add gitignore
[chaz/homebank] / src / gtk-dateentry.c
1 /* HomeBank -- Free, easy, personal accounting for everyone.
2 * Copyright (C) 1995-2014 Maxime DOYEN
3 *
4 * This file is part of HomeBank.
5 *
6 * HomeBank is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * HomeBank is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20 #include <stdlib.h>
21 #include <string.h>
22 #include <time.h>
23
24 #include <gtk/gtk.h>
25 #include <gdk/gdkkeysyms.h>
26
27 #include "gtk-dateentry.h"
28
29 #define MYDEBUG 0
30
31 #if MYDEBUG
32 #define DB(x) (x);
33 #else
34 #define DB(x);
35 #endif
36
37 enum {
38 CHANGED,
39 LAST_SIGNAL
40 };
41
42 enum {
43 PROPERTY_DATE = 5,
44 };
45
46 static void gtk_dateentry_class_init (GtkDateEntryClass *klass);
47 static void gtk_dateentry_init (GtkDateEntry *dateentry);
48 static void gtk_dateentry_destroy (GtkObject *dateentry);
49 static void gtk_dateentry_popup_display (GtkDateEntry *dateentry);
50 static gint gtk_dateentry_arrow_press (GtkWidget * widget,
51 GtkDateEntry * dateentry);
52 static gint gtk_dateentry_button_press (GtkWidget *widget,
53 GdkEvent *event,
54 gpointer data);
55
56 static void gtk_dateentry_entry_parse(GtkWidget * calendar, gpointer user_data);
57 static gint gtk_dateentry_entry_key (GtkWidget *widget, GdkEventKey *event, gpointer user_data);
58 static void gtk_dateentry_calendar_getfrom(GtkWidget * calendar, GtkDateEntry * dateentry);
59 static gint gtk_dateentry_calendar_select(GtkWidget * calendar, gpointer user_data);
60 static void gtk_dateentry_calendar_year(GtkWidget * calendar, GtkDateEntry * dateentry);
61 static void gtk_dateentry_hide_popdown_window(GtkDateEntry *dateentry);
62 static gint gtk_dateentry_arrow_press (GtkWidget * widget, GtkDateEntry * dateentry);
63 static gint key_press_popup (GtkWidget *widget, GdkEventKey *event, gpointer user_data);
64 static gint gtk_dateentry_button_press (GtkWidget * widget, GdkEvent * event, gpointer data);
65
66 static void gtk_dateentry_entry_set_text(GtkDateEntry * dateentry);
67
68 /*
69 static void
70 gtk_dateentry_set_property (GObject *object,
71 guint prop_id,
72 const GValue *value,
73 GParamSpec *pspec);
74
75 static void
76 gtk_dateentry_get_property (GObject *object,
77 guint prop_id,
78 GValue *value,
79 GParamSpec *pspec);
80 */
81
82 static GtkHBoxClass *parent_class = NULL;
83 static guint dateentry_signals[LAST_SIGNAL] = {0,};
84
85
86 // todo:finish this
87 // this is to be able to seizure d or d/m or m/d in the gtkdateentry
88
89 /* order of these in the current locale */
90 static GDateDMY dmy_order[3] =
91 {
92 G_DATE_DAY, G_DATE_MONTH, G_DATE_YEAR
93 };
94
95 struct _GDateParseTokens {
96 gint num_ints;
97 gint n[3];
98 guint month;
99 };
100
101 typedef struct _GDateParseTokens GDateParseTokens;
102
103 #define NUM_LEN 10
104
105 static void
106 g_date_fill_parse_tokens (const gchar *str, GDateParseTokens *pt)
107 {
108 gchar num[4][NUM_LEN+1];
109 gint i;
110 const guchar *s;
111
112 DB( g_print("\n[dateentry] fill parse token\n") );
113
114 /* We count 4, but store 3; so we can give an error
115 * if there are 4.
116 */
117 num[0][0] = num[1][0] = num[2][0] = num[3][0] = '\0';
118
119 s = (const guchar *) str;
120 pt->num_ints = 0;
121 while (*s && pt->num_ints < 4)
122 {
123
124 i = 0;
125 while (*s && g_ascii_isdigit (*s) && i < NUM_LEN)
126 {
127 num[pt->num_ints][i] = *s;
128 ++s;
129 ++i;
130 }
131
132 if (i > 0)
133 {
134 num[pt->num_ints][i] = '\0';
135 ++(pt->num_ints);
136 }
137
138 if (*s == '\0') break;
139
140 ++s;
141 }
142
143 pt->n[0] = pt->num_ints > 0 ? atoi (num[0]) : 0;
144 pt->n[1] = pt->num_ints > 1 ? atoi (num[1]) : 0;
145 pt->n[2] = pt->num_ints > 2 ? atoi (num[2]) : 0;
146
147 }
148
149 static void g_date_determine_dmy(void)
150 {
151 GDate d;
152 gchar buf[128];
153 GDateParseTokens testpt;
154 gint i;
155
156 DB( g_print("\n[dateentry] determine dmy\n") );
157
158
159 g_date_clear (&d, 1); /* clear for scratch use */
160
161
162 /* had to pick a random day - don't change this, some strftimes
163 * are broken on some days, and this one is good so far. */
164 g_date_set_dmy (&d, 4, 7, 1976);
165
166 g_date_strftime (buf, 127, "%x", &d);
167
168 g_date_fill_parse_tokens (buf, &testpt);
169
170 i = 0;
171 while (i < testpt.num_ints)
172 {
173 switch (testpt.n[i])
174 {
175 case 7:
176 dmy_order[i] = G_DATE_MONTH;
177 break;
178 case 4:
179 dmy_order[i] = G_DATE_DAY;
180 break;
181 //case 76:
182 //using_twodigit_years = TRUE; /* FALL THRU */
183 case 1976:
184 dmy_order[2] = G_DATE_YEAR;
185 break;
186 }
187 ++i;
188 }
189
190 DB( g_print(" dmy legend: 0=day, 1=month, 2=year\n") );
191 DB( g_print(" dmy is: %d %d %d\n", dmy_order[0], dmy_order[1], dmy_order[2]) );
192 }
193
194
195 //end
196
197
198 GType
199 gtk_dateentry_get_type ()
200 {
201 static GType dateentry_type = 0;
202
203 //DB( g_print("\n[dateentry] get_type\n") );
204
205 if (!dateentry_type)
206 {
207 static const GTypeInfo dateentry_info =
208 {
209 sizeof (GtkDateEntryClass),
210 NULL, /* base_init */
211 NULL, /* base_finalize */
212 (GClassInitFunc) gtk_dateentry_class_init,
213 NULL, /* class_finalize */
214 NULL, /* class_data */
215 sizeof (GtkDateEntry),
216 0, /* n_preallocs */
217 (GInstanceInitFunc) gtk_dateentry_init,
218 NULL
219 };
220
221 //dateentry_type = gtk_type_unique (gtk_hbox_get_type (), &dateentry_info);
222
223 dateentry_type = g_type_register_static (GTK_TYPE_HBOX, "GtkDateEntry",
224 &dateentry_info, 0);
225
226
227 }
228 return dateentry_type;
229 }
230
231 static void
232 gtk_dateentry_class_init (GtkDateEntryClass * klass)
233 {
234 //GObjectClass *gobject_class;
235 GtkObjectClass *object_class;
236 //GtkWidgetClass *widget_class;
237
238 //gobject_class = (GObjectClass*) klass;
239 object_class = (GtkObjectClass*) klass;
240 //widget_class = (GtkWidgetClass*) klass;
241
242 parent_class = g_type_class_peek_parent (klass);
243
244 DB( g_print("\n[dateentry] class_init\n") );
245
246
247 object_class->destroy = gtk_dateentry_destroy;
248
249 dateentry_signals[CHANGED] =
250 g_signal_new ("changed",
251 G_OBJECT_CLASS_TYPE (klass),
252 G_SIGNAL_RUN_LAST,
253 G_STRUCT_OFFSET (GtkDateEntryClass, changed),
254 NULL, NULL,
255 g_cclosure_marshal_VOID__VOID,
256 G_TYPE_NONE, 0);
257
258 g_date_determine_dmy();
259
260 /*
261 gobject_class->set_property = gtk_dateentry_set_property;
262 gobject_class->get_property = gtk_dateentry_get_property;
263
264 g_object_class_install_property (gobject_class,
265 PROPERTY_DATE,
266 g_param_spec_uint( "date",
267 "Date",
268 "The date currently selected",
269 0, G_MAXUINT,
270 0,
271 (G_PARAM_READABLE | G_PARAM_WRITABLE)
272 )
273 );
274 */
275 }
276
277 static gboolean gtk_dateentry_focus(GtkWidget *widget,
278 GdkEventFocus *event,
279 gpointer user_data)
280 {
281 GtkDateEntry *dateentry = user_data;
282
283 DB( g_print("\n[dateentry] focus-out-event %d\n", gtk_widget_is_focus(GTK_WIDGET(dateentry))) );
284
285 gtk_dateentry_entry_parse(GTK_WIDGET(dateentry), dateentry);
286
287 return FALSE;
288 }
289
290 static void
291 gtk_dateentry_init (GtkDateEntry *dateentry)
292 {
293 GtkWidget *widget;
294 GtkWidget *arrow;
295
296 DB( g_print("\n[dateentry] init\n") );
297
298 /* initialize datas */
299 dateentry->date = g_date_new();
300
301 g_date_set_time_t(dateentry->date, time(NULL));
302
303 g_date_set_dmy(&dateentry->mindate, 1, 1, 1900);
304 g_date_set_dmy(&dateentry->maxdate, 31, 12, 2200);
305
306
307 widget=GTK_WIDGET(dateentry);
308 gtk_box_set_homogeneous(GTK_BOX(widget), FALSE);
309
310 dateentry->entry = gtk_entry_new ();
311 gtk_widget_set_size_request(dateentry->entry, 90, -1);
312 gtk_box_pack_start (GTK_BOX (dateentry), dateentry->entry, TRUE, TRUE, 0);
313
314 dateentry->arrow = gtk_toggle_button_new ();
315 arrow = gtk_arrow_new (GTK_ARROW_DOWN, GTK_SHADOW_IN);
316 gtk_container_add (GTK_CONTAINER (dateentry->arrow), arrow);
317 gtk_box_pack_end (GTK_BOX (dateentry), dateentry->arrow, FALSE, FALSE, 0);
318
319 gtk_widget_show (dateentry->entry);
320 gtk_widget_show (dateentry->arrow);
321
322
323 /* our popup window */
324 dateentry->popwin = gtk_window_new (GTK_WINDOW_POPUP);
325 gtk_widget_set_events (dateentry->popwin,
326 gtk_widget_get_events(dateentry->popwin) | GDK_KEY_PRESS_MASK);
327
328 dateentry->frame = gtk_frame_new (NULL);
329 gtk_container_add (GTK_CONTAINER (dateentry->popwin), dateentry->frame);
330 gtk_frame_set_shadow_type (GTK_FRAME (dateentry->frame), GTK_SHADOW_OUT);
331 gtk_widget_show (dateentry->frame);
332
333 dateentry->calendar = gtk_calendar_new ();
334 gtk_container_add (GTK_CONTAINER (dateentry->frame), dateentry->calendar);
335 gtk_widget_show (dateentry->calendar);
336
337 // dateentry signals
338 g_signal_connect (GTK_OBJECT (dateentry->entry), "activate",
339 G_CALLBACK (gtk_dateentry_entry_parse), dateentry);
340
341 g_signal_connect (GTK_OBJECT (dateentry->entry), "focus-out-event",
342 G_CALLBACK (gtk_dateentry_focus), dateentry);
343
344
345 g_signal_connect (GTK_OBJECT (dateentry->entry), "key_press_event",
346 G_CALLBACK (gtk_dateentry_entry_key), dateentry);
347
348 // arrow/popwin signals
349 g_signal_connect (GTK_OBJECT (dateentry->arrow), "toggled",
350 G_CALLBACK (gtk_dateentry_arrow_press), dateentry);
351
352 g_signal_connect (GTK_OBJECT (dateentry->popwin), "key_press_event",
353 G_CALLBACK (key_press_popup), dateentry);
354
355 g_signal_connect (GTK_OBJECT (dateentry->popwin), "button_press_event",
356 G_CALLBACK (gtk_dateentry_button_press), dateentry);
357
358 // calendar signals
359 g_signal_connect (GTK_OBJECT (dateentry->calendar), "prev-year",
360 G_CALLBACK (gtk_dateentry_calendar_year), dateentry);
361 g_signal_connect (GTK_OBJECT (dateentry->calendar), "next-year",
362 G_CALLBACK (gtk_dateentry_calendar_year), dateentry);
363 g_signal_connect (GTK_OBJECT (dateentry->calendar), "prev-month",
364 G_CALLBACK (gtk_dateentry_calendar_year), dateentry);
365 g_signal_connect (GTK_OBJECT (dateentry->calendar), "next-month",
366 G_CALLBACK (gtk_dateentry_calendar_year), dateentry);
367
368 g_signal_connect (GTK_OBJECT (dateentry->calendar), "day-selected",
369 G_CALLBACK (gtk_dateentry_calendar_getfrom), dateentry);
370
371 g_signal_connect (GTK_OBJECT (dateentry->calendar), "day-selected-double-click",
372 G_CALLBACK (gtk_dateentry_calendar_select), dateentry);
373
374 //gtk_dateentry_calendar_getfrom(NULL, dateentry);
375 }
376
377
378 GtkWidget *gtk_dateentry_new ()
379 {
380 GtkDateEntry *dateentry;
381
382 DB( g_print("\n[dateentry] new\n") );
383
384 dateentry = g_object_new (GTK_TYPE_DATE_ENTRY, NULL);
385
386 return GTK_WIDGET(dateentry);
387 }
388
389
390 static void gtk_dateentry_destroy (GtkObject * object)
391 {
392 GtkDateEntry *dateentry;
393
394 DB( g_print(" \n[dateentry] destroy\n") );
395
396 g_return_if_fail (GTK_IS_DATE_ENTRY (object));
397
398 dateentry = GTK_DATE_ENTRY (object);
399
400 DB( g_print(" free gtkentry: %p\n", dateentry->entry) );
401 DB( g_print(" free arrow: %p\n", dateentry->arrow) );
402 DB( g_print(" free popwin: %p\n", dateentry->popwin) );
403
404 DB( g_print(" free dateentry: %p\n", dateentry) );
405
406 if(dateentry->popwin)
407 gtk_widget_destroy (dateentry->popwin);
408 dateentry->popwin = NULL;
409
410 if(dateentry->date)
411 g_date_free(dateentry->date);
412 dateentry->date = NULL;
413
414 GTK_OBJECT_CLASS (parent_class)->destroy (object);
415 }
416
417 /*
418 **
419 */
420 void gtk_dateentry_set_date(GtkDateEntry *dateentry, guint32 julian_days)
421 {
422 DB( g_print(" \n[dateentry] set date\n") );
423
424 g_return_if_fail (GTK_IS_DATE_ENTRY (dateentry));
425
426 if(g_date_valid_julian(julian_days))
427 {
428 g_date_set_julian (dateentry->date, julian_days);
429 }
430 else
431 {
432 g_date_set_time_t(dateentry->date, time(NULL));
433 }
434 gtk_dateentry_entry_set_text(dateentry);
435 }
436
437 /*
438 **
439 */
440 void gtk_dateentry_set_mindate(GtkDateEntry *dateentry, guint32 julian_days)
441 {
442 DB( g_print(" \n[dateentry] set date\n") );
443
444 g_return_if_fail (GTK_IS_DATE_ENTRY (dateentry));
445
446 if(g_date_valid_julian(julian_days))
447 {
448 g_date_set_julian (&dateentry->mindate, julian_days);
449 }
450 }
451
452
453 /*
454 **
455 */
456 void gtk_dateentry_set_maxdate(GtkDateEntry *dateentry, guint32 julian_days)
457 {
458 DB( g_print(" \n[dateentry] set date\n") );
459
460 g_return_if_fail (GTK_IS_DATE_ENTRY (dateentry));
461
462 if(g_date_valid_julian(julian_days))
463 {
464 g_date_set_julian (&dateentry->maxdate, julian_days);
465 }
466 }
467
468
469 /*
470 **
471 */
472 guint32 gtk_dateentry_get_date(GtkDateEntry * dateentry)
473 {
474 DB( g_print(" \n[dateentry] get date\n") );
475
476 g_return_val_if_fail (GTK_IS_DATE_ENTRY (dateentry), 0);
477
478 return(g_date_get_julian(dateentry->date));
479 }
480
481
482 /*
483 static void
484 gtk_dateentry_set_property (GObject *object,
485 guint prop_id,
486 const GValue *value,
487 GParamSpec *pspec)
488 {
489 GtkDateEntry *dateentry = GTK_DATE_ENTRY (object);
490
491 DB( g_print("\n[dateentry] set %d\n", prop_id) );
492
493
494 switch (prop_id)
495 {
496 case PROPERTY_DATE:
497 DB( g_print(" -> date to %d\n", g_value_get_uint (value)) );
498
499 g_date_set_julian (dateentry->date, g_value_get_uint (value));
500 gtk_dateentry_entry_set_text(dateentry);
501 break;
502
503
504 default:
505 //G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
506 break;
507 }
508 }
509
510
511
512 static void
513 gtk_dateentry_get_property (GObject *object,
514 guint prop_id,
515 GValue *value,
516 GParamSpec *pspec)
517 {
518 GtkDateEntry *dateentry = GTK_DATE_ENTRY (object);
519
520 DB( g_print("\n[dateentry] get\n") );
521
522 switch (prop_id)
523 {
524 case PROPERTY_DATE:
525 DB( g_print(" -> date is %d\n", 0) );
526 g_value_set_uint (value, g_date_get_julian(dateentry->date));
527 break;
528
529 default:
530 //G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
531 break;
532 }
533 }
534 */
535
536
537 /*
538 ** fill in our gtkentry from our GDate
539 */
540 static void gtk_dateentry_entry_set_text(GtkDateEntry * dateentry)
541 {
542 gchar buffer[256];
543
544 DB( g_print("\n[dateentry] date2entry\n") );
545
546 g_date_clamp(dateentry->date, &dateentry->mindate, &dateentry->maxdate);
547
548
549 if(g_date_valid(dateentry->date) == TRUE)
550 {
551 g_date_strftime (buffer, 256 - 1, "%x", dateentry->date);
552 gtk_entry_set_text (GTK_ENTRY (dateentry->entry), buffer);
553
554 DB( g_print(" = %s\n", buffer) );
555 }
556 else
557 gtk_entry_set_text (GTK_ENTRY (dateentry->entry), "??");
558
559
560 /* emit the signal */
561 if(dateentry->lastdate != g_date_get_julian(dateentry->date))
562 {
563 DB( g_print(" **emit 'changed' signal**\n") );
564
565 g_signal_emit_by_name (dateentry, "changed", NULL, NULL);
566 }
567
568 dateentry->lastdate = g_date_get_julian(dateentry->date);
569
570 }
571
572
573 static void gtk_dateentry_tokens(GtkWidget *gtkentry, gpointer user_data)
574 {
575 GtkDateEntry *dateentry = user_data;
576 const gchar *str;
577 GDateParseTokens pt;
578
579 str = gtk_entry_get_text (GTK_ENTRY (dateentry->entry));
580
581 g_date_fill_parse_tokens(str, &pt);
582 DB( g_print(" -> parsetoken return is %d values :%d %d %d\n", pt.num_ints, pt.n[0], pt.n[1], pt.n[2]) );
583
584 // initialize with today's date
585 g_date_set_time_t(dateentry->date, time(NULL));
586
587 switch( pt.num_ints )
588 {
589 case 1:
590 DB( g_print(" -> seizured 1 number\n") );
591 if(g_date_valid_day(pt.n[0]))
592 g_date_set_day(dateentry->date, pt.n[0]);
593 break;
594 case 2:
595 DB( g_print(" -> seizured 2 numbers\n") );
596 if( dmy_order[0] != G_DATE_YEAR )
597 {
598 if( dmy_order[0] == G_DATE_DAY )
599 {
600 if(g_date_valid_day(pt.n[0]))
601 g_date_set_day(dateentry->date, pt.n[0]);
602 if(g_date_valid_month(pt.n[1]))
603 g_date_set_month(dateentry->date, pt.n[1]);
604 }
605 else
606 {
607 if(g_date_valid_day(pt.n[1]))
608 g_date_set_day(dateentry->date, pt.n[1]);
609 if(g_date_valid_month(pt.n[0]))
610 g_date_set_month(dateentry->date, pt.n[0]);
611 }
612 }
613 break;
614 }
615
616
617
618 }
619
620
621
622
623
624 /*
625 ** parse the gtkentry and store the GDate
626 */
627 static void gtk_dateentry_entry_parse(GtkWidget *gtkentry, gpointer user_data)
628 {
629 GtkDateEntry *dateentry = user_data;
630 const gchar *str;
631
632 DB( g_print("\n[dateentry] entry_parse\n") );
633
634 str = gtk_entry_get_text (GTK_ENTRY (dateentry->entry));
635
636 //1) we parse the string according to the locale
637 g_date_set_parse (dateentry->date, str);
638 if(g_date_valid(dateentry->date) == FALSE)
639 {
640 //2) give a try to tokens: day, day/month, month/day
641 gtk_dateentry_tokens(gtkentry, user_data);
642 }
643
644 //3) at last if date still invalid, put today's dateentry_signals
645 // we should consider just warn the user here
646 if(g_date_valid(dateentry->date) == FALSE)
647 {
648 /* today's date */
649 g_date_set_time_t(dateentry->date, time(NULL));
650 }
651
652 gtk_dateentry_entry_set_text(dateentry);
653
654 }
655
656 static void gtk_dateentry_calendar_year(GtkWidget *calendar, GtkDateEntry *dateentry)
657 {
658 guint year, month, day;
659
660 DB( g_print(" (dateentry) year changed\n") );
661
662 gtk_calendar_get_date (GTK_CALENDAR (dateentry->calendar), &year, &month, &day);
663 if( year < 1900)
664 g_object_set(calendar, "year", 1900, NULL);
665
666 if( year > 2200)
667 g_object_set(calendar, "year", 2200, NULL);
668
669 }
670
671 /*
672 ** store the calendar date to GDate, update our gtkentry
673 */
674 static void gtk_dateentry_calendar_getfrom(GtkWidget * calendar, GtkDateEntry * dateentry)
675 {
676 guint year, month, day;
677
678 DB( g_print(" (dateentry) get from calendar\n") );
679
680 gtk_calendar_get_date (GTK_CALENDAR (dateentry->calendar), &year, &month, &day);
681 g_date_set_dmy (dateentry->date, day, month + 1, year);
682 gtk_dateentry_entry_set_text(dateentry);
683 }
684
685
686 static gint gtk_dateentry_calendar_select(GtkWidget * calendar, gpointer user_data)
687 {
688 GtkDateEntry *dateentry = user_data;
689
690 DB( g_print(" (dateentry) calendar_select\n") );
691
692 gtk_dateentry_hide_popdown_window(dateentry);
693 gtk_dateentry_calendar_getfrom(NULL, dateentry);
694 return FALSE;
695 }
696
697
698 static gint
699 gtk_dateentry_entry_key (GtkWidget *widget, GdkEventKey *event, gpointer user_data)
700 {
701 GtkDateEntry *dateentry = user_data;
702
703 DB( g_print("\n[dateentry] entry key pressed: state=%04x, keyval=%04x\n", event->state, event->keyval) );
704
705 if( event->keyval == GDK_KEY_Up )
706 {
707 if( !(event->state & (GDK_SHIFT_MASK | GDK_CONTROL_MASK)) )
708 {
709 g_date_add_days (dateentry->date, 1);
710 gtk_dateentry_entry_set_text(dateentry);
711 }
712 else
713 if( event->state & GDK_SHIFT_MASK )
714 {
715 g_date_add_months (dateentry->date, 1);
716 gtk_dateentry_entry_set_text(dateentry);
717 }
718 else
719 if( event->state & GDK_CONTROL_MASK )
720 {
721 g_date_add_years (dateentry->date, 1);
722 gtk_dateentry_entry_set_text(dateentry);
723 }
724 return TRUE;
725 }
726 else
727 if( event->keyval == GDK_KEY_Down )
728 {
729 if( !(event->state & (GDK_SHIFT_MASK | GDK_CONTROL_MASK)) )
730 {
731 g_date_subtract_days (dateentry->date, 1);
732 gtk_dateentry_entry_set_text(dateentry);
733 }
734 else
735 if( event->state & GDK_SHIFT_MASK )
736 {
737 g_date_subtract_months (dateentry->date, 1);
738 gtk_dateentry_entry_set_text(dateentry);
739 }
740 else
741 if( event->state & GDK_CONTROL_MASK )
742 {
743 g_date_subtract_years (dateentry->date, 1);
744 gtk_dateentry_entry_set_text(dateentry);
745 }
746 return TRUE;
747 }
748
749 return FALSE;
750 }
751
752
753 static void
754 position_popup (GtkDateEntry * dateentry)
755 {
756 gint x, y;
757 gint bwidth, bheight;
758 GtkRequisition req;
759 GdkWindow *gdkwindow;
760 GtkAllocation allocation;
761
762 DB( g_print("\n[dateentry] position popup\n") );
763
764 gtk_widget_size_request (dateentry->popwin, &req);
765
766 gdkwindow = gtk_widget_get_window(dateentry->arrow);
767 gdk_window_get_origin (gdkwindow, &x, &y);
768
769 gtk_widget_get_allocation(dateentry->arrow, &allocation);
770 x += allocation.x;
771 y += allocation.y;
772 bwidth = allocation.width;
773 bheight = allocation.height;
774
775 x += bwidth - req.width;
776 y += bheight;
777
778 if (x < 0)
779 x = 0;
780
781 if (y < 0)
782 y = 0;
783
784 gtk_window_move (GTK_WINDOW (dateentry->popwin), x, y);
785 }
786
787
788
789 static void
790 gtk_dateentry_popup_display (GtkDateEntry * dateentry)
791 {
792 const char *str;
793 int month;
794
795 //gint height, width, x, y;
796 //gint old_width, old_height;
797
798 DB( g_print("\n[dateentry] popup_display\n****\n\n") );
799
800 //old_width = dateentry->popwin->allocation.width;
801 //old_height = dateentry->popwin->allocation.height;
802
803
804 /* update */
805 str = gtk_entry_get_text (GTK_ENTRY (dateentry->entry));
806 g_date_set_parse (dateentry->date, str);
807
808 if(g_date_valid(dateentry->date) == TRUE)
809 {
810 /* GtkCalendar expects month to be in 0-11 range (inclusive) */
811 month = g_date_get_month (dateentry->date) - 1;
812 gtk_calendar_select_month (GTK_CALENDAR (dateentry->calendar),
813 CLAMP (month, 0, 11),
814 g_date_get_year (dateentry->date));
815 gtk_calendar_select_day (GTK_CALENDAR (dateentry->calendar),
816 g_date_get_day (dateentry->date));
817 }
818
819 position_popup(dateentry);
820
821 gtk_widget_show (dateentry->popwin);
822
823 gtk_grab_add (dateentry->popwin);
824
825 // this close the popup */
826 GdkWindow *gdkwindow;
827 gdkwindow = gtk_widget_get_window(dateentry->popwin);
828
829 gdk_pointer_grab (gdkwindow, TRUE,
830 GDK_BUTTON_PRESS_MASK |
831 GDK_BUTTON_RELEASE_MASK |
832 GDK_POINTER_MOTION_MASK,
833 NULL, NULL, GDK_CURRENT_TIME);
834
835 }
836
837 static void
838 gtk_dateentry_hide_popdown_window(GtkDateEntry *dateentry)
839 {
840 DB( g_print("\n[dateentry] hide_popdown_window\n") );
841
842 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(dateentry->arrow), FALSE);
843
844 gtk_grab_remove(dateentry->popwin);
845 gdk_pointer_ungrab(GDK_CURRENT_TIME);
846 gtk_widget_hide(dateentry->popwin);
847 }
848
849 static gint
850 gtk_dateentry_arrow_press (GtkWidget * widget, GtkDateEntry * dateentry)
851 {
852 GtkToggleButton *button;
853
854 DB( g_print("\n[dateentry] arrow_press\n") );
855
856 button = GTK_TOGGLE_BUTTON(widget);
857
858 if(!gtk_toggle_button_get_active(button)){
859 gtk_widget_hide (dateentry->popwin);
860 gtk_grab_remove (dateentry->popwin);
861 gdk_pointer_ungrab (GDK_CURRENT_TIME);
862
863 gtk_dateentry_calendar_getfrom(NULL, dateentry);
864 return TRUE;
865 }
866
867 gtk_dateentry_popup_display(dateentry);
868 return TRUE;
869 }
870
871 static gint
872 key_press_popup (GtkWidget *widget, GdkEventKey *event, gpointer user_data)
873 {
874 GtkDateEntry *dateentry = user_data;
875
876
877 DB( g_print("\n[dateentry] key pressed%d\n", event->keyval) );
878
879 if (event->keyval != GDK_KEY_Escape)
880 return FALSE;
881
882 g_signal_stop_emission_by_name (widget, "key_press_event");
883
884 gtk_dateentry_hide_popdown_window(dateentry);
885
886
887 return TRUE;
888 }
889
890
891 static gint
892 gtk_dateentry_button_press (GtkWidget * widget, GdkEvent * event, gpointer user_data)
893 {
894 GtkWidget *child;
895
896 DB( g_print("\n[dateentry] button_press\n") );
897
898 child = gtk_get_event_widget (event);
899
900 if (child != widget)
901 {
902 while (child)
903 {
904 if (child == widget)
905 return FALSE;
906 child = gtk_widget_get_parent(child);
907 }
908 }
909
910 gtk_widget_hide (widget);
911 gtk_grab_remove (widget);
912 gdk_pointer_ungrab (GDK_CURRENT_TIME);
913 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(GTK_DATE_ENTRY(user_data)->arrow), FALSE);
914
915 return TRUE;
916 }
917
This page took 0.0861769999999999 seconds and 4 git commands to generate.