Clean up the menu setup code a little and show/hide selection-bsaed menu items as...
[milk] / src / milk-main-window.c
1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License as
4  * published by the Free Software Foundation; either version 2 of the
5  * License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
10  * General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public
13  * License along with this program; if not, write to the
14  * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
15  * Boston, MA  02110-1301  USA
16  *
17  * Authors: Travis Reitter <treitter@gmail.com>
18  */
19
20 #include <config.h>
21
22 #include <glib.h>
23 #include <glib/gi18n.h>
24 #include <gtk/gtk.h>
25 #include <hildon/hildon.h>
26
27 #include "milk-main-window.h"
28 #include "milk-task-model.h"
29
30 G_DEFINE_TYPE (MilkMainWindow, milk_main_window, HILDON_TYPE_WINDOW)
31
32 /* less expensive than G_TYPE_INSTANCE_GET_PRIVATE */
33 #define MILK_MAIN_WINDOW_PRIVATE(o) ((MILK_MAIN_WINDOW ((o)))->priv)
34
35 struct _MilkMainWindowPrivate
36 {
37         GtkWidget *app_menu;
38
39         GtkWidget *main_vbox;
40
41         GtkWidget *new_task_entry;
42         GtkWidget *task_view;
43         GtkWidget *task_selector;
44 };
45
46 enum {
47         TASK_VIEW_COLUMN_TITLE,
48         N_VIEW_COLUMNS
49 };
50
51 typedef struct {
52         const char *display_name;
53         const char *id;
54         gpointer    callback;
55 } MenuItem;
56
57 static void
58 milk_main_window_get_property (GObject    *object,
59                                guint       property_id,
60                                GValue     *value,
61                                GParamSpec *pspec)
62 {
63         switch (property_id)
64         {
65                 default:
66                         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id,
67                                         pspec);
68         }
69 }
70
71 static void
72 milk_main_window_set_property (GObject      *object,
73                                guint         property_id,
74                                const GValue *value,
75                                GParamSpec   *pspec)
76 {
77         switch (property_id)
78         {
79                 default:
80                         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id,
81                                         pspec);
82         }
83 }
84
85 static void
86 milk_main_window_dispose (GObject *object)
87 {
88         G_OBJECT_CLASS (milk_main_window_parent_class)->dispose (object);
89 }
90
91 static void
92 new_task_clicked_cb (GtkButton      *button,
93                      MilkMainWindow *window)
94 {
95         g_debug ("FIXME: implement 'new task' action");
96 }
97
98 static void
99 complete_clicked_cb (GtkButton      *button,
100                      MilkMainWindow *window)
101 {
102         g_debug ("FIXME: implement 'complete' action");
103 }
104
105 static void
106 delete_clicked_cb (GtkButton      *button,
107                    MilkMainWindow *window)
108 {
109         g_debug ("FIXME: implement 'delete' action");
110 }
111
112 static void
113 priority_plus_clicked_cb (GtkButton      *button,
114                           MilkMainWindow *window)
115 {
116         g_debug ("FIXME: implement 'priority plus' action");
117 }
118
119 static void
120 priority_minus_clicked_cb (GtkButton      *button,
121                            MilkMainWindow *window)
122 {
123         g_debug ("FIXME: implement 'priority minus' action");
124 }
125
126 static void
127 edit_clicked_cb (GtkButton      *button,
128                  MilkMainWindow *window)
129 {
130         g_debug ("FIXME: implement 'edit' action");
131 }
132
133 static MenuItem menu_items_always_shown[] = {
134         {"New Task",   "menu-item-new-task",       new_task_clicked_cb},
135 };
136
137 static MenuItem menu_items_selection_required[] = {
138         {"Edit",       "menu-item-edit",           edit_clicked_cb},
139         {"Priority +", "menu-item-priority_plus",  priority_plus_clicked_cb},
140         {"Priority -", "menu-item-priority_minus", priority_minus_clicked_cb},
141         {"Complete",   "menu-item-complete",       complete_clicked_cb},
142         {"Delete",     "menu-item-delete",         delete_clicked_cb},
143 };
144
145 static void
146 task_view_selection_changed_cb (HildonTouchSelector *view,
147                                 gint                 column,
148                                 MilkMainWindow      *window)
149 {
150         MilkMainWindowPrivate *priv;
151         GList *rows;
152         gboolean show = FALSE;
153         gint i;
154
155         priv = MILK_MAIN_WINDOW_PRIVATE (window);
156
157         rows = hildon_touch_selector_get_selected_rows (view, column);
158         show = (g_list_length (rows) > 0);
159
160         for (i = 0; i < G_N_ELEMENTS (menu_items_selection_required); i++) {
161                 GtkWidget *w;
162
163                 w = g_object_get_data (
164                                 G_OBJECT (priv->app_menu),
165                                 menu_items_selection_required[i].id);
166
167                 if (show)
168                         gtk_widget_show (w);
169                 else
170                         gtk_widget_hide (w);
171         }
172 }
173
174 static GtkWidget*
175 create_menu (gpointer user_data)
176 {
177         HildonAppMenu *menu;
178         MenuItem *menu_array;
179         gint i, length;
180         GtkWidget *w;
181
182         menu = HILDON_APP_MENU (hildon_app_menu_new ());
183
184         menu_array = menu_items_always_shown;
185         length = G_N_ELEMENTS (menu_items_always_shown);
186         for (i = 0; i < length; i++) {
187                 w = hildon_button_new_with_text (
188                                 HILDON_SIZE_FINGER_HEIGHT | HILDON_SIZE_AUTO_WIDTH,
189                                 HILDON_BUTTON_ARRANGEMENT_VERTICAL,
190                                 _(menu_array[i].display_name), "");
191                 g_signal_connect (w, "clicked",
192                                 G_CALLBACK (menu_array[i].callback), user_data);
193                 g_object_set_data (G_OBJECT (menu), menu_array[i].id, w);
194                 hildon_app_menu_append (menu, GTK_BUTTON (w));
195                 gtk_widget_show (w);
196         }
197
198         menu_array = menu_items_selection_required;
199         length = G_N_ELEMENTS (menu_items_selection_required);
200         for (i = 0; i < length; i++) {
201                 w = hildon_button_new_with_text (
202                                 HILDON_SIZE_FINGER_HEIGHT | HILDON_SIZE_AUTO_WIDTH,
203                                 HILDON_BUTTON_ARRANGEMENT_VERTICAL,
204                                 menu_array[i].display_name, "");
205                 g_signal_connect (w, "clicked",
206                                 G_CALLBACK (menu_array[i].callback), user_data);
207                 g_object_set_data (G_OBJECT (menu), menu_array[i].id, w);
208                 hildon_app_menu_append (menu, GTK_BUTTON (w));
209                 gtk_widget_hide (w);
210         }
211
212         gtk_widget_show (GTK_WIDGET (menu));
213
214         return GTK_WIDGET (menu);
215 }
216
217 static MenuItem menu_items_always_shown[] = {
218         {"New Task",   "menu-item-new-task",       new_task_clicked_cb},
219 };
220
221 static MenuItem menu_items_selection_required[] = {
222         {"Edit",       "menu-item-edit",           edit_clicked_cb},
223         {"Priority +", "menu-item-priority_plus",  priority_plus_clicked_cb},
224         {"Priority -", "menu-item-priority_minus", priority_minus_clicked_cb},
225         {"Complete",   "menu-item-complete",       complete_clicked_cb},
226         {"Delete",     "menu-item-delete",         delete_clicked_cb},
227 };
228
229 static void
230 task_view_selection_changed_cb (HildonTouchSelector *view,
231                                 gint                 column,
232                                 MilkMainWindow      *window)
233 {
234         MilkMainWindowPrivate *priv;
235         GList *rows;
236         gboolean show = FALSE;
237         gint i;
238
239         priv = MILK_MAIN_WINDOW_PRIVATE (window);
240
241         rows = hildon_touch_selector_get_selected_rows (view, column);
242         show = (g_list_length (rows) > 0);
243
244         for (i = 0; i < G_N_ELEMENTS (menu_items_selection_required); i++) {
245                 GtkWidget *w;
246
247                 w = g_object_get_data (
248                                 G_OBJECT (priv->app_menu),
249                                 menu_items_selection_required[i].id);
250
251                 if (show)
252                         gtk_widget_show (w);
253                 else
254                         gtk_widget_hide (w);
255         }
256 }
257
258 static GtkWidget*
259 create_menu (gpointer user_data)
260 {
261         HildonAppMenu *menu;
262         MenuItem *menu_array;
263         gint i, length;
264         GtkWidget *w;
265
266         menu = HILDON_APP_MENU (hildon_app_menu_new ());
267
268         menu_array = menu_items_always_shown;
269         length = G_N_ELEMENTS (menu_items_always_shown);
270         for (i = 0; i < length; i++) {
271                 w = hildon_button_new_with_text (
272                                 HILDON_SIZE_FINGER_HEIGHT | HILDON_SIZE_AUTO_WIDTH,
273                                 HILDON_BUTTON_ARRANGEMENT_VERTICAL,
274                                 _(menu_array[i].display_name), "");
275                 g_signal_connect (w, "clicked",
276                                 G_CALLBACK (menu_array[i].callback), user_data);
277                 g_object_set_data (G_OBJECT (menu), menu_array[i].id, w);
278                 hildon_app_menu_append (menu, GTK_BUTTON (w));
279                 gtk_widget_show (w);
280         }
281
282         menu_array = menu_items_selection_required;
283         length = G_N_ELEMENTS (menu_items_selection_required);
284         for (i = 0; i < length; i++) {
285                 w = hildon_button_new_with_text (
286                                 HILDON_SIZE_FINGER_HEIGHT | HILDON_SIZE_AUTO_WIDTH,
287                                 HILDON_BUTTON_ARRANGEMENT_VERTICAL,
288                                 menu_array[i].display_name, "");
289                 g_signal_connect (w, "clicked",
290                                 G_CALLBACK (menu_array[i].callback), user_data);
291                 g_object_set_data (G_OBJECT (menu), menu_array[i].id, w);
292                 hildon_app_menu_append (menu, GTK_BUTTON (w));
293                 gtk_widget_hide (w);
294         }
295
296         gtk_widget_show (GTK_WIDGET (menu));
297
298         return GTK_WIDGET (menu);
299 }
300
301 static void
302 contact_column_render_func (GtkCellLayout   *cell_layout,
303                             GtkCellRenderer *renderer,
304                             GtkTreeModel    *model,
305                             GtkTreeIter     *iter,
306                             gpointer         user_data)
307 {
308         MilkTask *task;
309         char *title;
310
311         gtk_tree_model_get (
312                         model, iter, MILK_TASK_MODEL_COLUMN_TASK, &task, -1);
313
314         g_object_get (task, "title", &title, NULL);
315         g_object_set (renderer, "text", title, NULL);
316
317         g_free (title);
318         g_object_unref (task);
319 }
320
321 static MenuItem menu_items_always_shown[] = {
322         {"New Task",   "menu-item-new-task",       new_task_clicked_cb},
323 };
324
325 static MenuItem menu_items_selection_required[] = {
326         {"Edit",       "menu-item-edit",           edit_clicked_cb},
327         {"Priority +", "menu-item-priority_plus",  priority_plus_clicked_cb},
328         {"Priority -", "menu-item-priority_minus", priority_minus_clicked_cb},
329         {"Complete",   "menu-item-complete",       complete_clicked_cb},
330         {"Delete",     "menu-item-delete",         delete_clicked_cb},
331 };
332
333 static void
334 task_view_selection_changed_cb (HildonTouchSelector *view,
335                                 gint                 column,
336                                 MilkMainWindow      *window)
337 {
338         MilkMainWindowPrivate *priv;
339         GList *rows;
340         gboolean show = FALSE;
341         gint i;
342
343         priv = MILK_MAIN_WINDOW_PRIVATE (window);
344
345         rows = hildon_touch_selector_get_selected_rows (view, column);
346         show = (g_list_length (rows) > 0);
347
348         for (i = 0; i < G_N_ELEMENTS (menu_items_selection_required); i++) {
349                 GtkWidget *w;
350
351                 w = g_object_get_data (
352                                 G_OBJECT (priv->app_menu),
353                                 menu_items_selection_required[i].id);
354
355                 if (show)
356                         gtk_widget_show (w);
357                 else
358                         gtk_widget_hide (w);
359         }
360 }
361
362 static GtkWidget*
363 create_menu (gpointer user_data)
364 {
365         HildonAppMenu *menu;
366         MenuItem *menu_array;
367         gint i, length;
368         GtkWidget *w;
369
370         menu = HILDON_APP_MENU (hildon_app_menu_new ());
371
372         menu_array = menu_items_always_shown;
373         length = G_N_ELEMENTS (menu_items_always_shown);
374         for (i = 0; i < length; i++) {
375                 w = hildon_button_new_with_text (
376                                 HILDON_SIZE_FINGER_HEIGHT | HILDON_SIZE_AUTO_WIDTH,
377                                 HILDON_BUTTON_ARRANGEMENT_VERTICAL,
378                                 _(menu_array[i].display_name), "");
379                 g_signal_connect (w, "clicked",
380                                 G_CALLBACK (menu_array[i].callback), user_data);
381                 g_object_set_data (G_OBJECT (menu), menu_array[i].id, w);
382                 hildon_app_menu_append (menu, GTK_BUTTON (w));
383                 gtk_widget_show (w);
384         }
385
386         menu_array = menu_items_selection_required;
387         length = G_N_ELEMENTS (menu_items_selection_required);
388         for (i = 0; i < length; i++) {
389                 w = hildon_button_new_with_text (
390                                 HILDON_SIZE_FINGER_HEIGHT | HILDON_SIZE_AUTO_WIDTH,
391                                 HILDON_BUTTON_ARRANGEMENT_VERTICAL,
392                                 menu_array[i].display_name, "");
393                 g_signal_connect (w, "clicked",
394                                 G_CALLBACK (menu_array[i].callback), user_data);
395                 g_object_set_data (G_OBJECT (menu), menu_array[i].id, w);
396                 hildon_app_menu_append (menu, GTK_BUTTON (w));
397                 gtk_widget_hide (w);
398         }
399
400         gtk_widget_show (GTK_WIDGET (menu));
401
402         return GTK_WIDGET (menu);
403 }
404
405 static void
406 milk_main_window_constructed (GObject* object)
407 {
408         MilkMainWindow *self = MILK_MAIN_WINDOW (object);
409         MilkMainWindowPrivate *priv = MILK_MAIN_WINDOW_PRIVATE (object);
410         GtkWidget *w;
411         GtkTreeModel *model;
412         GtkCellRenderer *renderer;
413         HildonTouchSelectorColumn *col;
414
415         w = gtk_vbox_new (FALSE, HILDON_MARGIN_DEFAULT);
416         gtk_container_add (GTK_CONTAINER (self), w);
417         priv->main_vbox = w;
418
419         /*
420          * New Task entry
421          */
422         w = hildon_entry_new (HILDON_SIZE_FINGER_HEIGHT);
423         gtk_box_pack_start (GTK_BOX (priv->main_vbox), w, FALSE, FALSE, 0);
424
425         /* FIXME: change this to hildon_gtk_entry_set_placeholder_text() is
426          * fixed, since this is deprecated */
427         hildon_entry_set_placeholder (HILDON_ENTRY (w),
428                         _("Enter a new task..."));
429         priv->new_task_entry = w;
430
431         /*
432          * Task List
433          */
434         model = GTK_TREE_MODEL (milk_task_model_new ());
435         w = hildon_touch_selector_new ();
436
437         renderer = gtk_cell_renderer_text_new ();
438         g_object_set (renderer,
439                         "ellipsize", PANGO_ELLIPSIZE_END,
440                         NULL);
441         col = hildon_touch_selector_append_column (HILDON_TOUCH_SELECTOR (w),
442                         model, renderer,
443                         "text", MILK_TASK_MODEL_COLUMN_TITLE,
444                         NULL);
445         g_object_unref (model);
446
447         hildon_touch_selector_column_set_text_column (
448                         col, MILK_TASK_MODEL_COLUMN_TITLE);
449         hildon_touch_selector_set_column_selection_mode (
450                         HILDON_TOUCH_SELECTOR (w),
451                         HILDON_TOUCH_SELECTOR_SELECTION_MODE_MULTIPLE);
452         hildon_touch_selector_set_hildon_ui_mode (
453                         HILDON_TOUCH_SELECTOR (w), HILDON_UI_MODE_EDIT);
454         hildon_touch_selector_unselect_all (
455                         HILDON_TOUCH_SELECTOR (w), TASK_VIEW_COLUMN_TITLE);
456
457         gtk_box_pack_start (GTK_BOX (priv->main_vbox), w, TRUE, TRUE, 0);
458         g_object_set (w, "can-focus", TRUE, NULL);
459         gtk_widget_grab_focus (w);
460
461         g_signal_connect (
462                         G_OBJECT (w), "changed",
463                         G_CALLBACK (task_view_selection_changed_cb), self);
464         priv->task_view = w;
465
466         priv->app_menu = create_menu (self);
467         hildon_window_set_app_menu (
468                         HILDON_WINDOW (self), HILDON_APP_MENU (priv->app_menu));
469 }
470
471 static void
472 milk_main_window_class_init (MilkMainWindowClass *klass)
473 {
474         GObjectClass *object_class = G_OBJECT_CLASS (klass);
475
476         g_type_class_add_private (klass, sizeof (MilkMainWindowPrivate));
477
478         object_class->get_property = milk_main_window_get_property;
479         object_class->set_property = milk_main_window_set_property;
480         object_class->constructed = milk_main_window_constructed;
481         object_class->dispose = milk_main_window_dispose;
482 }
483
484 static void
485 milk_main_window_init (MilkMainWindow *self)
486 {
487         self->priv = G_TYPE_INSTANCE_GET_PRIVATE (
488                         self, MILK_TYPE_MAIN_WINDOW, MilkMainWindowPrivate);
489 }
490
491 GtkWidget*
492 milk_main_window_new ()
493 {
494         return g_object_new (MILK_TYPE_MAIN_WINDOW,
495                              NULL);
496 }