X-Git-Url: https://git.dogcows.com/gitweb?p=chaz%2Fhomebank;a=blobdiff_plain;f=src%2Fgtk-dateentry.c;h=5702cfa8c3d49e566fde30b37705d9c8c17174dd;hp=6e55a394f9cd615105babae7ae275b4f97481886;hb=cd13d9691c46c2b2d6d459e9e6a76bed1c21b7a6;hpb=b84403141a4c3a32a594800eb3fcabdc856461f8 diff --git a/src/gtk-dateentry.c b/src/gtk-dateentry.c index 6e55a39..5702cfa 100644 --- a/src/gtk-dateentry.c +++ b/src/gtk-dateentry.c @@ -1,5 +1,5 @@ /* HomeBank -- Free, easy, personal accounting for everyone. - * Copyright (C) 1995-2017 Maxime DOYEN + * Copyright (C) 1995-2018 Maxime DOYEN * * This file is part of HomeBank. * @@ -34,360 +34,228 @@ #define DB(x); #endif + enum { CHANGED, LAST_SIGNAL }; + enum { PROPERTY_DATE = 5, }; -static void gtk_date_entry_dispose (GObject *gobject); -static void gtk_date_entry_finalize (GObject *gobject); -static void gtk_date_entry_destroy (GtkWidget *dateentry); - -static void gtk_date_entry_entry_activate(GtkWidget * calendar, gpointer user_data); -static gint gtk_date_entry_entry_key_pressed (GtkWidget *widget, GdkEventKey *event, gpointer user_data); -static void gtk_date_entry_button_clicked (GtkWidget * widget, GtkDateEntry * dateentry); - -static void -gtk_date_entry_popup(GtkDateEntry * dateentry, GdkEvent *event); - -static gint gtk_date_entry_popup_key_event (GtkWidget *widget, GdkEventKey *event, gpointer user_data); -static gint gtk_date_entry_popup_button_press (GtkWidget * widget, GdkEvent * event, gpointer data); - -static void gtk_date_entry_calendar_year(GtkWidget * calendar, GtkDateEntry * dateentry); -static void gtk_date_entry_calendar_getfrom(GtkWidget * calendar, GtkDateEntry * dateentry); -static gint gtk_date_entry_calendar_select(GtkWidget * calendar, gpointer user_data); - - -static void gtk_date_entry_entry_set_text(GtkDateEntry * dateentry); -static void gtk_date_entry_popdown(GtkDateEntry *dateentry); - - static guint dateentry_signals[LAST_SIGNAL] = {0,}; -// todo:finish this -// this is to be able to seizure d or d/m or m/d in the gtkdateentry - -/* order of these in the current locale */ -static GDateDMY dmy_order[3] = -{ - G_DATE_DAY, G_DATE_MONTH, G_DATE_YEAR -}; +G_DEFINE_TYPE(GtkDateEntry, gtk_date_entry, GTK_TYPE_BOX) -struct _GDateParseTokens { - gint num_ints; - gint n[3]; - guint month; -}; -typedef struct _GDateParseTokens GDateParseTokens; -#define NUM_LEN 10 static void -hb_date_fill_parse_tokens (const gchar *str, GDateParseTokens *pt) +update_text(GtkDateEntry *self) { - gchar num[4][NUM_LEN+1]; - gint i; - const guchar *s; - - DB( g_print("\n[dateentry] fill parse token\n") ); - - /* We count 4, but store 3; so we can give an error - * if there are 4. - */ - num[0][0] = num[1][0] = num[2][0] = num[3][0] = '\0'; - - s = (const guchar *) str; - pt->num_ints = 0; - while (*s && pt->num_ints < 4) - { - - i = 0; - while (*s && g_ascii_isdigit (*s) && i < NUM_LEN) - { - num[pt->num_ints][i] = *s; - ++s; - ++i; - } - - if (i > 0) - { - num[pt->num_ints][i] = '\0'; - ++(pt->num_ints); - } - - if (*s == '\0') break; - - ++s; - } - - pt->n[0] = pt->num_ints > 0 ? atoi (num[0]) : 0; - pt->n[1] = pt->num_ints > 1 ? atoi (num[1]) : 0; - pt->n[2] = pt->num_ints > 2 ? atoi (num[2]) : 0; +GtkDateEntryPrivate *priv = self->priv; +gchar label[24]; + + DB( g_print("\n[dateentry] update text\n") ); + g_date_strftime (label, 17 - 1, "%x", priv->date); + gtk_entry_set_text (GTK_ENTRY (priv->entry), label); + DB( g_print(" = %s\n", label) ); } -/* -static void hb_date_determine_dmy(void) +static void +eval_date(GtkDateEntry *self) { -GDate d; -gchar buf[128]; -GDateParseTokens testpt; -gint i; +GtkDateEntryPrivate *priv = self->priv; - DB( g_print("\n[dateentry] determine dmy\n") ); - - g_date_clear (&d, 1); // clear for scratch use - - // had to pick a random day - don't change this, some strftimes - // are broken on some days, and this one is good so far. - g_date_set_dmy (&d, 4, 7, 1976); - g_date_strftime (buf, 127, "%x", &d); - - hb_date_fill_parse_tokens (buf, &testpt); - - i = 0; - while (i < testpt.num_ints) + g_date_clamp(priv->date, &priv->mindate, &priv->maxdate); + + update_text(self); + + if(priv->lastdate != g_date_get_julian(priv->date)) { - switch (testpt.n[i]) - { - case 7: - dmy_order[i] = G_DATE_MONTH; - break; - case 4: - dmy_order[i] = G_DATE_DAY; - break; - case 1976: - dmy_order[2] = G_DATE_YEAR; - break; - } - ++i; + DB( g_print(" **emit 'changed' signal**\n") ); + g_signal_emit_by_name (self, "changed", NULL, NULL); } - DB( g_print(" dmy legend: 0=day, 1=month, 2=year\n") ); - DB( g_print(" dmy is: %d %d %d\n", dmy_order[0], dmy_order[1], dmy_order[2]) ); -}*/ - + priv->lastdate = g_date_get_julian(priv->date); +} -static void hb_date_parse_tokens(GtkWidget *gtkentry, gpointer user_data) +static void +parse_date(GtkDateEntry *self) { -GtkDateEntry *dateentry = user_data; -GtkDateEntryPrivate *priv = dateentry->priv; -const gchar *str; -GDateParseTokens pt; +GtkDateEntryPrivate *priv = self->priv; - str = gtk_entry_get_text (GTK_ENTRY (priv->entry)); + DB( g_print("\n[dateentry] parse date\n") ); - hb_date_fill_parse_tokens(str, &pt); - DB( g_print(" -> parsetoken return is %d values :%d %d %d\n", pt.num_ints, pt.n[0], pt.n[1], pt.n[2]) ); - - // initialize with today's date - g_date_set_time_t(priv->date, time(NULL)); - - switch( pt.num_ints ) + g_date_set_parse (priv->date, gtk_entry_get_text (GTK_ENTRY (priv->entry))); + if(!g_date_valid(priv->date)) { - case 1: - DB( g_print(" -> seizured 1 number\n") ); - if(g_date_valid_day(pt.n[0])) - g_date_set_day(priv->date, pt.n[0]); - break; - case 2: - DB( g_print(" -> seizured 2 numbers\n") ); - if( dmy_order[0] != G_DATE_YEAR ) - { - if( dmy_order[0] == G_DATE_DAY ) - { - if(g_date_valid_day(pt.n[0])) - g_date_set_day(priv->date, pt.n[0]); - if(g_date_valid_month(pt.n[1])) - g_date_set_month(priv->date, pt.n[1]); - } - else - { - if(g_date_valid_day(pt.n[1])) - g_date_set_day(priv->date, pt.n[1]); - if(g_date_valid_month(pt.n[0])) - g_date_set_month(priv->date, pt.n[0]); - } - } - break; + g_date_set_time_t(priv->date, time(NULL)); } - - - + eval_date(self); } - - - -//end - - -G_DEFINE_TYPE(GtkDateEntry, gtk_date_entry, GTK_TYPE_BOX) - - - static void -gtk_date_entry_class_init (GtkDateEntryClass *class) +gtk_date_entry_cb_calendar_day_selected(GtkWidget * calendar, GtkDateEntry * dateentry) { -GObjectClass *object_class; -GtkWidgetClass *widget_class; - - object_class = G_OBJECT_CLASS (class); - widget_class = GTK_WIDGET_CLASS (class); - - DB( g_print("\n[dateentry] class_init\n") ); - - //object_class->constructor = gtk_date_entry_constructor; - //object_class->set_property = gtk_date_entry_set_property; - //object_class->get_property = gtk_date_entry_get_property; - object_class->dispose = gtk_date_entry_dispose; - object_class->finalize = gtk_date_entry_finalize; +GtkDateEntryPrivate *priv = dateentry->priv; +guint year, month, day; - widget_class->destroy = gtk_date_entry_destroy; - - dateentry_signals[CHANGED] = - g_signal_new ("changed", - G_TYPE_FROM_CLASS (class), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (GtkDateEntryClass, changed), - NULL, NULL, - g_cclosure_marshal_VOID__VOID, - G_TYPE_NONE, 0); + DB( g_print("\n[dateentry] calendar_day_selected\n") ); - g_type_class_add_private (object_class, sizeof (GtkDateEntryPrivate)); - + gtk_calendar_get_date (GTK_CALENDAR (priv->calendar), &year, &month, &day); + g_date_set_dmy (priv->date, day, month + 1, year); + eval_date(dateentry); } -static gboolean -gtk_date_entry_entry_focus_out(GtkWidget *widget, GdkEventFocus *event, gpointer user_data) +static gint +gtk_date_entry_cb_calendar_day_select_double_click(GtkWidget * calendar, gpointer user_data) { GtkDateEntry *dateentry = user_data; +GtkDateEntryPrivate *priv = dateentry->priv; - DB( g_print("\n[dateentry] entry focus-out-event %d\n", gtk_widget_is_focus(GTK_WIDGET(dateentry))) ); + DB( g_print("\n[dateentry] calendar_day_select_double_click\n") ); - gtk_date_entry_entry_activate(GTK_WIDGET(dateentry), dateentry); + gtk_widget_hide (priv->popover); return FALSE; } -static void -gtk_date_entry_init (GtkDateEntry *dateentry) -{ -GtkDateEntryPrivate *priv; - - DB( g_print("\n[dateentry] init\n") ); - - /* yes, also priv, need to keep the code readable */ - dateentry->priv = G_TYPE_INSTANCE_GET_PRIVATE (dateentry, - GTK_TYPE_DATE_ENTRY, - GtkDateEntryPrivate); - priv = dateentry->priv; - - - /* initialize datas */ - priv->date = g_date_new(); - priv->device = NULL; - priv->popup_in_progress = FALSE; - priv->has_grab = FALSE; - - g_date_set_time_t(priv->date, time(NULL)); - g_date_set_dmy(&priv->mindate, 1, 1, 1900); - g_date_set_dmy(&priv->maxdate, 31, 12, 2200); +static void +gtk_date_entry_cb_calendar_monthyear(GtkWidget *calendar, GtkDateEntry *dateentry) +{ +GtkDateEntryPrivate *priv = dateentry->priv; +guint year, month, day; + DB( g_print("\n[dateentry] cb_calendar_monthyear\n") ); - gtk_style_context_add_class (gtk_widget_get_style_context (GTK_WIDGET(dateentry)), GTK_STYLE_CLASS_LINKED); + gtk_calendar_get_date (GTK_CALENDAR (priv->calendar), &year, &month, &day); + if( year < 1900) + g_object_set(calendar, "year", 1900, NULL); - //widget=GTK_WIDGET(dateentry); - - priv->entry = gtk_entry_new (); - - //gtk_entry_set_width_chars(GTK_ENTRY(priv->entry), 10); - //gtk_entry_set_max_width_chars(GTK_ENTRY(priv->entry), 4); - + if( year > 2200) + g_object_set(calendar, "year", 2200, NULL); - gtk_box_pack_start (GTK_BOX (dateentry), priv->entry, TRUE, TRUE, 0); - - g_signal_connect (priv->entry, "key-press-event", - G_CALLBACK (gtk_date_entry_entry_key_pressed), dateentry); - - g_signal_connect_after (priv->entry, "focus-out-event", - G_CALLBACK (gtk_date_entry_entry_focus_out), dateentry); +} - g_signal_connect (priv->entry, "activate", - G_CALLBACK (gtk_date_entry_entry_activate), dateentry); - - priv->button = gtk_button_new (); - priv->arrow = gtk_image_new_from_icon_name ("pan-down-symbolic", GTK_ICON_SIZE_BUTTON); - gtk_container_add (GTK_CONTAINER (priv->button), priv->arrow); - gtk_box_pack_end (GTK_BOX (dateentry), priv->button, FALSE, FALSE, 0); - gtk_widget_show_all (priv->button); +static gint +gtk_date_entry_cb_entry_key_pressed (GtkWidget *widget, GdkEventKey *event, gpointer user_data) +{ +GtkDateEntry *dateentry = user_data; +GtkDateEntryPrivate *priv = dateentry->priv; - g_signal_connect (priv->button, "clicked", - G_CALLBACK (gtk_date_entry_button_clicked), dateentry); + DB( g_print("\n[dateentry] entry key pressed: state=%04x, keyval=%04x\n", event->state, event->keyval) ); + if( event->keyval == GDK_KEY_Up ) + { + if( !(event->state & (GDK_SHIFT_MASK | GDK_CONTROL_MASK)) ) + { + g_date_add_days (priv->date, 1); + eval_date(dateentry); + } + else + if( event->state & GDK_SHIFT_MASK ) + { + g_date_add_months (priv->date, 1); + eval_date(dateentry); + } + else + if( event->state & GDK_CONTROL_MASK ) + { + g_date_add_years (priv->date, 1); + eval_date(dateentry); + } + return TRUE; + } + else + if( event->keyval == GDK_KEY_Down ) + { + if( !(event->state & (GDK_SHIFT_MASK | GDK_CONTROL_MASK)) ) + { + g_date_subtract_days (priv->date, 1); + eval_date(dateentry); + } + else + if( event->state & GDK_SHIFT_MASK ) + { + g_date_subtract_months (priv->date, 1); + eval_date(dateentry); + } + else + if( event->state & GDK_CONTROL_MASK ) + { + g_date_subtract_years (priv->date, 1); + eval_date(dateentry); + } + return TRUE; + } - priv->popup_window = gtk_window_new (GTK_WINDOW_POPUP); - gtk_window_set_type_hint ( - GTK_WINDOW (priv->popup_window), GDK_WINDOW_TYPE_HINT_COMBO); - gtk_widget_set_events (priv->popup_window, - gtk_widget_get_events(priv->popup_window) | GDK_KEY_PRESS_MASK); + return FALSE; +} - priv->frame = gtk_frame_new (NULL); - gtk_container_add (GTK_CONTAINER (priv->popup_window), priv->frame); - gtk_frame_set_shadow_type (GTK_FRAME (priv->frame), GTK_SHADOW_ETCHED_IN); - gtk_widget_show (priv->frame); - g_signal_connect (priv->popup_window, "key-press-event", - G_CALLBACK (gtk_date_entry_popup_key_event), dateentry); +static void +gtk_date_entry_cb_entry_activate(GtkWidget *gtkentry, gpointer user_data) +{ +GtkDateEntry *dateentry = user_data; - g_signal_connect (priv->popup_window, "button-press-event", - G_CALLBACK (gtk_date_entry_popup_button_press), dateentry); + DB( g_print("\n[dateentry] entry_activate\n") ); - - priv->calendar = gtk_calendar_new (); - gtk_container_add (GTK_CONTAINER (priv->frame), priv->calendar); - gtk_widget_show (priv->calendar); + parse_date(dateentry); + eval_date(dateentry); +} - g_signal_connect (priv->calendar, "prev-year", - G_CALLBACK (gtk_date_entry_calendar_year), dateentry); - g_signal_connect (priv->calendar, "next-year", - G_CALLBACK (gtk_date_entry_calendar_year), dateentry); - g_signal_connect (priv->calendar, "prev-month", - G_CALLBACK (gtk_date_entry_calendar_year), dateentry); - g_signal_connect (priv->calendar, "next-month", - G_CALLBACK (gtk_date_entry_calendar_year), dateentry); - g_signal_connect (priv->calendar, "day-selected", - G_CALLBACK (gtk_date_entry_calendar_getfrom), dateentry); +static gboolean +gtk_date_entry_cb_entry_focus_out(GtkWidget *widget, GdkEventFocus *event, gpointer user_data) +{ +GtkDateEntry *dateentry = user_data; - g_signal_connect (priv->calendar, "day-selected-double-click", - G_CALLBACK (gtk_date_entry_calendar_select), dateentry); + DB( g_print("\n[dateentry] entry focus-out-event %d\n", gtk_widget_is_focus(GTK_WIDGET(dateentry))) ); + parse_date(dateentry); + eval_date(dateentry); + return FALSE; } -GtkWidget * -gtk_date_entry_new () +static void +gtk_date_entry_cb_button_clicked (GtkWidget * widget, GtkDateEntry * dateentry) { -GtkDateEntry *dateentry; - - DB( g_print("\n[dateentry] new\n") ); +GtkDateEntryPrivate *priv = dateentry->priv; +//GdkRectangle rect; +int month; - dateentry = g_object_new (GTK_TYPE_DATE_ENTRY, NULL); + DB( g_print("\n[dateentry] button_clicked\n") ); - return GTK_WIDGET(dateentry); + /* GtkCalendar expects month to be in 0-11 range (inclusive) */ + month = g_date_get_month (priv->date) - 1; + + g_signal_handler_block(priv->calendar, priv->hid_dayselect); + + gtk_calendar_select_month (GTK_CALENDAR (priv->calendar), + CLAMP (month, 0, 11), + g_date_get_year (priv->date)); + gtk_calendar_select_day (GTK_CALENDAR (priv->calendar), + g_date_get_day (priv->date)); + + g_signal_handler_unblock(priv->calendar, priv->hid_dayselect); + + gtk_popover_set_relative_to (GTK_POPOVER (priv->popover), GTK_WIDGET (priv->entry)); + //gtk_widget_get_clip(priv->arrow, &rect); + //gtk_popover_set_pointing_to (GTK_POPOVER (priv->popover), &rect); + + gtk_widget_show_all (priv->popover); } @@ -400,18 +268,13 @@ GtkDateEntryPrivate *priv = dateentry->priv; g_return_if_fail(object != NULL); g_return_if_fail(GTK_IS_DATE_ENTRY(object)); - DB( g_print(" \n[dateentry] destroy\n") ); + DB( g_print("\n[dateentry] destroy\n") ); DB( g_print(" free gtkentry: %p\n", priv->entry) ); DB( g_print(" free arrow: %p\n", priv->button) ); - DB( g_print(" free popup_window: %p\n", priv->popup_window) ); DB( g_print(" free dateentry: %p\n", dateentry) ); - if(priv->popup_window) - gtk_widget_destroy (priv->popup_window); - priv->popup_window = NULL; - if(priv->date) g_date_free(priv->date); priv->date = NULL; @@ -426,7 +289,7 @@ gtk_date_entry_dispose (GObject *gobject) { //GtkDateEntry *self = GTK_DATE_ENTRY (gobject); - DB( g_print(" \n[dateentry] dispose\n") ); + DB( g_print("\n[dateentry] dispose\n") ); //g_clear_object (&self->priv->an_object); @@ -442,7 +305,7 @@ gtk_date_entry_finalize (GObject *gobject) { //GtkDateEntry *self = GTK_DATE_ENTRY (gobject); - DB( g_print(" \n[dateentry] finalize\n") ); + DB( g_print("\n[dateentry] finalize\n") ); //g_date_free(self->date); @@ -455,478 +318,199 @@ gtk_date_entry_finalize (GObject *gobject) } -/* -** -*/ -void gtk_date_entry_set_date(GtkDateEntry *dateentry, guint32 julian_days) -{ -GtkDateEntryPrivate *priv = dateentry->priv; - - DB( g_print(" \n[dateentry] set date\n") ); - - g_return_if_fail (GTK_IS_DATE_ENTRY (dateentry)); - - if(g_date_valid_julian(julian_days)) - { - g_date_set_julian (priv->date, julian_days); - } - else - { - g_date_set_time_t(priv->date, time(NULL)); - } - gtk_date_entry_entry_set_text(dateentry); -} -/* -** -*/ -void gtk_date_entry_set_mindate(GtkDateEntry *dateentry, guint32 julian_days) +static void +gtk_date_entry_class_init (GtkDateEntryClass *class) { -GtkDateEntryPrivate *priv = dateentry->priv; - - DB( g_print(" \n[dateentry] set mindate\n") ); +GObjectClass *object_class; +GtkWidgetClass *widget_class; - g_return_if_fail (GTK_IS_DATE_ENTRY (dateentry)); + object_class = G_OBJECT_CLASS (class); + widget_class = GTK_WIDGET_CLASS (class); - if(g_date_valid_julian(julian_days)) - { - g_date_set_julian (&priv->mindate, julian_days); - } -} + DB( g_print("\n[dateentry] class_init\n") ); + //object_class->constructor = gtk_date_entry_constructor; + //object_class->set_property = gtk_date_entry_set_property; + //object_class->get_property = gtk_date_entry_get_property; + object_class->dispose = gtk_date_entry_dispose; + object_class->finalize = gtk_date_entry_finalize; -/* -** -*/ -void gtk_date_entry_set_maxdate(GtkDateEntry *dateentry, guint32 julian_days) -{ -GtkDateEntryPrivate *priv = dateentry->priv; + widget_class->destroy = gtk_date_entry_destroy; - DB( g_print(" \n[dateentry] set maxdate\n") ); - - g_return_if_fail (GTK_IS_DATE_ENTRY (dateentry)); - - if(g_date_valid_julian(julian_days)) - { - g_date_set_julian (&priv->maxdate, julian_days); - } -} - + dateentry_signals[CHANGED] = + g_signal_new ("changed", + G_TYPE_FROM_CLASS (class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (GtkDateEntryClass, changed), + NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); -guint32 gtk_date_entry_get_date(GtkDateEntry * dateentry) -{ -GtkDateEntryPrivate *priv = dateentry->priv; + g_type_class_add_private (object_class, sizeof (GtkDateEntryPrivate)); - DB( g_print(" \n[dateentry] get date\n") ); - - g_return_val_if_fail (GTK_IS_DATE_ENTRY (dateentry), 0); - - return(g_date_get_julian(priv->date)); } - -static void -gtk_date_entry_entry_set_text(GtkDateEntry * dateentry) +static void +gtk_date_entry_init (GtkDateEntry *dateentry) { -GtkDateEntryPrivate *priv = dateentry->priv; -gchar buffer[256]; - - DB( g_print("\n[dateentry] entry set text\n") ); +GtkDateEntryPrivate *priv; - g_date_clamp(priv->date, &priv->mindate, &priv->maxdate); + DB( g_print("\n[dateentry] init\n") ); + /* yes, also priv, need to keep the code readable */ + dateentry->priv = G_TYPE_INSTANCE_GET_PRIVATE (dateentry, + GTK_TYPE_DATE_ENTRY, + GtkDateEntryPrivate); + priv = dateentry->priv; - if(g_date_valid(priv->date) == TRUE) - { - g_date_strftime (buffer, 256 - 1, "%x", priv->date); - gtk_entry_set_text (GTK_ENTRY (priv->entry), buffer); - - DB( g_print(" = %s\n", buffer) ); - } - else - gtk_entry_set_text (GTK_ENTRY (priv->entry), "??"); - - - /* emit the signal */ - if(priv->lastdate != g_date_get_julian(priv->date)) - { - DB( g_print(" **emit 'changed' signal**\n") ); + gtk_style_context_add_class (gtk_widget_get_style_context (GTK_WIDGET(dateentry)), GTK_STYLE_CLASS_LINKED); - g_signal_emit_by_name (dateentry, "changed", NULL, NULL); - } + priv->entry = gtk_entry_new (); + gtk_entry_set_width_chars(GTK_ENTRY(priv->entry), 16); + gtk_entry_set_max_width_chars(GTK_ENTRY(priv->entry), 16); + gtk_box_pack_start (GTK_BOX (dateentry), priv->entry, TRUE, TRUE, 0); - priv->lastdate = g_date_get_julian(priv->date); + priv->button = gtk_button_new (); + priv->arrow = gtk_image_new_from_icon_name ("pan-down-symbolic", GTK_ICON_SIZE_BUTTON); + gtk_container_add (GTK_CONTAINER (priv->button), priv->arrow); + gtk_box_pack_end (GTK_BOX (dateentry), priv->button, FALSE, FALSE, 0); -} + priv->popover = gtk_popover_new (priv->button); + gtk_popover_set_position(GTK_POPOVER(priv->popover), GTK_POS_BOTTOM); + gtk_container_set_border_width (GTK_CONTAINER (priv->popover), 6); + priv->calendar = gtk_calendar_new (); + gtk_container_add (GTK_CONTAINER (priv->popover), priv->calendar); + gtk_widget_show_all (GTK_WIDGET(dateentry)); -static void -gtk_date_entry_entry_activate(GtkWidget *gtkentry, gpointer user_data) -{ -GtkDateEntry *dateentry = user_data; -GtkDateEntryPrivate *priv = dateentry->priv; -const gchar *str; + /* initialize datas */ + priv->date = g_date_new(); + g_date_set_time_t(priv->date, time(NULL)); + g_date_set_dmy(&priv->mindate, 1, 1, 1900); //693596 + g_date_set_dmy(&priv->maxdate, 31, 12, 2200); //803533 + update_text(dateentry); - DB( g_print("\n[dateentry] entry_activate\n") ); - str = gtk_entry_get_text (GTK_ENTRY (priv->entry)); + g_signal_connect (priv->entry, "key-press-event", + G_CALLBACK (gtk_date_entry_cb_entry_key_pressed), dateentry); - //1) we parse the string according to the locale - g_date_set_parse (priv->date, str); - if(g_date_valid(priv->date) == FALSE) - { - //2) give a try to tokens: day, day/month, month/day - hb_date_parse_tokens(gtkentry, user_data); - } + g_signal_connect_after (priv->entry, "focus-out-event", + G_CALLBACK (gtk_date_entry_cb_entry_focus_out), dateentry); - //3) at last if date still invalid, put today's dateentry_signals - // we should consider just warn the user here - if(g_date_valid(priv->date) == FALSE) - { - /* today's date */ - g_date_set_time_t(priv->date, time(NULL)); - } + g_signal_connect (priv->entry, "activate", + G_CALLBACK (gtk_date_entry_cb_entry_activate), dateentry); - gtk_date_entry_entry_set_text(dateentry); -} + g_signal_connect (priv->button, "clicked", + G_CALLBACK (gtk_date_entry_cb_button_clicked), dateentry); -static void -gtk_date_entry_calendar_year(GtkWidget *calendar, GtkDateEntry *dateentry) -{ -GtkDateEntryPrivate *priv = dateentry->priv; -guint year, month, day; + g_signal_connect (priv->calendar, "prev-year", + G_CALLBACK (gtk_date_entry_cb_calendar_monthyear), dateentry); + g_signal_connect (priv->calendar, "next-year", + G_CALLBACK (gtk_date_entry_cb_calendar_monthyear), dateentry); + g_signal_connect (priv->calendar, "prev-month", + G_CALLBACK (gtk_date_entry_cb_calendar_monthyear), dateentry); + g_signal_connect (priv->calendar, "next-month", + G_CALLBACK (gtk_date_entry_cb_calendar_monthyear), dateentry); - DB( g_print(" (dateentry) year changed\n") ); + priv->hid_dayselect = g_signal_connect (priv->calendar, "day-selected", + G_CALLBACK (gtk_date_entry_cb_calendar_day_selected), dateentry); - gtk_calendar_get_date (GTK_CALENDAR (priv->calendar), &year, &month, &day); - if( year < 1900) - g_object_set(calendar, "year", 1900, NULL); + g_signal_connect (priv->calendar, "day-selected-double-click", + G_CALLBACK (gtk_date_entry_cb_calendar_day_select_double_click), dateentry); - if( year > 2200) - g_object_set(calendar, "year", 2200, NULL); - } -static void -gtk_date_entry_calendar_getfrom(GtkWidget * calendar, GtkDateEntry * dateentry) +GtkWidget * +gtk_date_entry_new () { -GtkDateEntryPrivate *priv = dateentry->priv; -guint year, month, day; - - DB( g_print(" (dateentry) calendar_getfrom\n") ); - - gtk_calendar_get_date (GTK_CALENDAR (priv->calendar), &year, &month, &day); - g_date_set_dmy (priv->date, day, month + 1, year); - gtk_date_entry_entry_set_text(dateentry); -} - +GtkDateEntry *dateentry; -static gint -gtk_date_entry_calendar_select(GtkWidget * calendar, gpointer user_data) -{ -GtkDateEntry *dateentry = user_data; + DB( g_print("\n[dateentry] new\n") ); - DB( g_print(" (dateentry) calendar_select\n") ); + dateentry = g_object_new (GTK_TYPE_DATE_ENTRY, NULL); - gtk_date_entry_calendar_getfrom(NULL, dateentry); - - gtk_date_entry_popdown(dateentry); - return FALSE; + return GTK_WIDGET(dateentry); } -static gint -gtk_date_entry_entry_key_pressed (GtkWidget *widget, GdkEventKey *event, gpointer user_data) +/* +** +*/ +void +gtk_date_entry_set_mindate(GtkDateEntry *dateentry, guint32 julian_days) { -GtkDateEntry *dateentry = user_data; GtkDateEntryPrivate *priv = dateentry->priv; + + DB( g_print("\n[dateentry] set mindate\n") ); - DB( g_print("\n[dateentry] entry key pressed: state=%04x, keyval=%04x\n", event->state, event->keyval) ); + g_return_if_fail (GTK_IS_DATE_ENTRY (dateentry)); - if( event->keyval == GDK_KEY_Up ) - { - if( !(event->state & (GDK_SHIFT_MASK | GDK_CONTROL_MASK)) ) - { - g_date_add_days (priv->date, 1); - gtk_date_entry_entry_set_text(dateentry); - } - else - if( event->state & GDK_SHIFT_MASK ) - { - g_date_add_months (priv->date, 1); - gtk_date_entry_entry_set_text(dateentry); - } - else - if( event->state & GDK_CONTROL_MASK ) - { - g_date_add_years (priv->date, 1); - gtk_date_entry_entry_set_text(dateentry); - } - return TRUE; - } - else - if( event->keyval == GDK_KEY_Down ) + if(g_date_valid_julian(julian_days)) { - if( !(event->state & (GDK_SHIFT_MASK | GDK_CONTROL_MASK)) ) - { - g_date_subtract_days (priv->date, 1); - gtk_date_entry_entry_set_text(dateentry); - } - else - if( event->state & GDK_SHIFT_MASK ) - { - g_date_subtract_months (priv->date, 1); - gtk_date_entry_entry_set_text(dateentry); - } - else - if( event->state & GDK_CONTROL_MASK ) - { - g_date_subtract_years (priv->date, 1); - gtk_date_entry_entry_set_text(dateentry); - } - return TRUE; + g_date_set_julian (&priv->mindate, julian_days); } - - return FALSE; } -static void -gtk_date_entry_popup_position (GtkDateEntry * dateentry) +/* +** +*/ +void +gtk_date_entry_set_maxdate(GtkDateEntry *dateentry, guint32 julian_days) { GtkDateEntryPrivate *priv = dateentry->priv; -gint x, y; -gint bwidth, bheight; -GtkRequisition req; -GdkWindow *gdkwindow; -GtkAllocation allocation; - - DB( g_print("\n[dateentry] position popup\n") ); - - gtk_widget_get_preferred_size (priv->popup_window, NULL, &req); - - gdkwindow = gtk_widget_get_window(priv->button); - gdk_window_get_origin (gdkwindow, &x, &y); - - gtk_widget_get_allocation(priv->button, &allocation); - x += allocation.x; - y += allocation.y; - bwidth = allocation.width; - bheight = allocation.height; - - x += bwidth - req.width; - y += bheight; - - if (x < 0) - x = 0; - - if (y < 0) - y = 0; - - gtk_window_move (GTK_WINDOW (priv->popup_window), x, y); -} - - -static void -gtk_date_entry_button_clicked (GtkWidget * widget, GtkDateEntry * dateentry) -{ -GdkEvent *event; - - DB( g_print("\n[dateentry] button_clicked\n") ); - -/* Obtain the GdkEvent that triggered - * the date button's "clicked" signal. */ - event = gtk_get_current_event (); - gtk_date_entry_popup(dateentry, event); - -} - - -static void -gtk_date_entry_popup(GtkDateEntry * dateentry, GdkEvent *event) -{ -GtkDateEntryPrivate *priv = dateentry->priv; -const char *str; -int month; -GdkDevice *event_device; -GdkDevice *assoc_device; -GdkDevice *keyboard_device; -GdkDevice *pointer_device; -GdkWindow *window; -GdkGrabStatus grab_status; -guint event_time; - - - DB( g_print("\n[dateentry] popup_display\n****\n\n") ); + DB( g_print("\n[dateentry] set maxdate\n") ); -/* update */ - str = gtk_entry_get_text (GTK_ENTRY (priv->entry)); - g_date_set_parse (priv->date, str); + g_return_if_fail (GTK_IS_DATE_ENTRY (dateentry)); - if(g_date_valid(priv->date) == TRUE) + if(g_date_valid_julian(julian_days)) { - /* GtkCalendar expects month to be in 0-11 range (inclusive) */ - month = g_date_get_month (priv->date) - 1; - gtk_calendar_select_month (GTK_CALENDAR (priv->calendar), - CLAMP (month, 0, 11), - g_date_get_year (priv->date)); - gtk_calendar_select_day (GTK_CALENDAR (priv->calendar), - g_date_get_day (priv->date)); - } - - - /* popup */ - gtk_date_entry_popup_position(dateentry); - gtk_widget_show (priv->popup_window); - gtk_widget_grab_focus (priv->popup_window); - gtk_grab_add (priv->popup_window); - - window = gtk_widget_get_window (priv->popup_window); - - g_return_if_fail (priv->grab_keyboard == NULL); - g_return_if_fail (priv->grab_pointer == NULL); - - event_device = gdk_event_get_device (event); - assoc_device = gdk_device_get_associated_device (event_device); - - event_time = gdk_event_get_time (event); - - if (gdk_device_get_source (event_device) == GDK_SOURCE_KEYBOARD) { - keyboard_device = event_device; - pointer_device = assoc_device; - } else { - keyboard_device = assoc_device; - pointer_device = event_device; - } - - if (keyboard_device != NULL) { - grab_status = gdk_device_grab ( - keyboard_device, - window, - GDK_OWNERSHIP_WINDOW, - TRUE, - GDK_KEY_PRESS_MASK | - GDK_KEY_RELEASE_MASK, - NULL, - event_time); - if (grab_status == GDK_GRAB_SUCCESS) { - priv->grab_keyboard = - g_object_ref (keyboard_device); - } - } - - if (pointer_device != NULL) { - grab_status = gdk_device_grab ( - pointer_device, - window, - GDK_OWNERSHIP_WINDOW, - TRUE, - GDK_BUTTON_PRESS_MASK | - GDK_BUTTON_RELEASE_MASK | - GDK_POINTER_MOTION_MASK, - NULL, - event_time); - if (grab_status == GDK_GRAB_SUCCESS) { - priv->grab_pointer = - g_object_ref (pointer_device); - } else if (priv->grab_keyboard != NULL) { - gdk_device_ungrab ( - priv->grab_keyboard, - event_time); - g_object_unref (priv->grab_keyboard); - priv->grab_keyboard = NULL; - } + g_date_set_julian (&priv->maxdate, julian_days); } - - gdk_window_focus (window, event_time); - } -static void -gtk_date_entry_popdown(GtkDateEntry *dateentry) +/* +** +*/ +void +gtk_date_entry_set_date(GtkDateEntry *dateentry, guint32 julian_days) { GtkDateEntryPrivate *priv = dateentry->priv; - DB( g_print("\n[dateentry] popdown\n") ); + DB( g_print("\n[dateentry] set date\n") ); - gtk_widget_hide (priv->popup_window); - gtk_grab_remove (priv->popup_window); + g_return_if_fail (GTK_IS_DATE_ENTRY (dateentry)); - if (priv->grab_keyboard != NULL) { - gdk_device_ungrab ( - priv->grab_keyboard, - GDK_CURRENT_TIME); - g_object_unref (priv->grab_keyboard); - priv->grab_keyboard = NULL; + if(g_date_valid_julian(julian_days)) + { + g_date_set_julian (priv->date, julian_days); } - - if (priv->grab_pointer != NULL) { - gdk_device_ungrab ( - priv->grab_pointer, - GDK_CURRENT_TIME); - g_object_unref (priv->grab_pointer); - priv->grab_pointer = NULL; + else + { + g_date_set_time_t(priv->date, time(NULL)); } - + eval_date(dateentry); } - - - -static gint -gtk_date_entry_popup_key_event (GtkWidget *widget, GdkEventKey *event, gpointer user_data) -{ -GtkDateEntry *dateentry = user_data; - - DB( g_print("\n[dateentry] popup_key_event%d\n", event->keyval) ); - - DB( g_print(" -> key=%d\n", event->keyval) ); - - if (event->keyval != GDK_KEY_Escape && event->keyval != GDK_KEY_Return) - return FALSE; - - g_signal_stop_emission_by_name (widget, "key-press-event"); - - gtk_date_entry_popdown(dateentry); - - return TRUE; -} - - -static gint -gtk_date_entry_popup_button_press (GtkWidget * widget, GdkEvent * event, gpointer user_data) +/* +** +*/ +guint32 +gtk_date_entry_get_date(GtkDateEntry *dateentry) { -GtkDateEntry *dateentry = user_data; -//GtkDateEntryPrivate *priv = dateentry->priv; -GtkWidget *child; - - DB( g_print("\n[dateentry] popup_button_press\n") ); - - child = gtk_get_event_widget (event); - - /* We don't ask for button press events on the grab widget, so - * if an event is reported directly to the grab widget, it must - * be on a window outside the application (and thus we remove - * the popup window). Otherwise, we check if the widget is a child - * of the grab widget, and only remove the popup window if it - * is not. - */ - if (child != widget) { - while (child) { - if (child == widget) - return FALSE; - child = gtk_widget_get_parent (child); - } - } +GtkDateEntryPrivate *priv = dateentry->priv; + + DB( g_print("\n[dateentry] get date\n") ); - gtk_date_entry_popdown(dateentry); + g_return_val_if_fail (GTK_IS_DATE_ENTRY (dateentry), 0); - return TRUE; + return(g_date_get_julian(priv->date)); }