Merge "custom eail widget implementation" into tizen
[platform/core/uifw/eail.git] / eail / eail_menu.c
1 /*
2  * Copyright (c) 2013 Samsung Electronics Co., Ltd.
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public License
15  * along with this library; see the file COPYING.LIB.  If not, write to
16  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17  * Boston, MA 02110-1301, USA.
18  */
19
20 /**
21  * @file eail_menu.c
22  * @brief EailMenu implementation
23  */
24
25 #include <Elementary.h>
26
27 #include "eail_menu.h"
28 #include "eail_item_parent.h"
29 #include "eail_factory.h"
30 #include "eail_priv.h"
31
32 static void eail_item_parent_interface_init(EailItemParentIface *iface);
33
34 /**
35  * @brief Definition of EailMenu as GObject
36  *
37  * EailList is extended Widget with EAIL_TYPE_ITEM_PARENT implemented
38  */
39 G_DEFINE_TYPE_WITH_CODE(EailMenu,
40                         eail_menu,
41                         EAIL_TYPE_WIDGET,
42                         G_IMPLEMENT_INTERFACE(EAIL_TYPE_ITEM_PARENT,
43                                               eail_item_parent_interface_init));
44
45 /*
46  * Implementation of the *AtkObject* interface
47  */
48
49 /**
50  * @brief Initializer for AtkObjectClass
51  */
52 static void
53 eail_menu_initialize(AtkObject *obj, gpointer data)
54 {
55    ATK_OBJECT_CLASS(eail_menu_parent_class)->initialize(obj, data);
56
57    obj->role = ATK_ROLE_MENU;
58 }
59
60 /**
61  * @brief Prepares Eina_List filled with Elm_Object_Item* objects
62  * representing items in menu
63  *
64  * Call eina_list_free on the returned list when results processing has been finished.
65  *
66  * @param list EailMenu instance
67  *
68  * @return Eina_List representing the list of list's items
69  */
70 static Eina_List *
71 eail_menu_get_items(EailMenu *list)
72 {
73    Eina_List *items = NULL;
74    Elm_Object_Item *item;
75    Evas_Object *widget = eail_widget_get_widget(EAIL_WIDGET(list));
76
77    item = elm_menu_first_item_get(widget);
78    while (item)
79      {
80         items = eina_list_append(items, item);
81         item = elm_menu_item_next_get(item);
82      }
83
84    return items;
85 }
86
87 /**
88  * @brief Gets the number of accessible children of the accessible
89  *
90  * Implementation of AtkObject->get_n_children callback.
91  *
92  * @param obj AtkObject instance
93  *
94  * @returns integer representing the number of accessible children of
95  * the accessible
96  */
97 static gint
98 eail_menu_get_n_children(AtkObject *obj)
99 {
100    gint n_items;
101    Eina_List *items;
102
103    items = eail_menu_get_items(EAIL_MENU(obj));
104    n_items = eina_list_count(items);
105
106    eina_list_free(items);
107
108    return n_items;
109 }
110
111 /**
112  * @brief Gets a reference to the specified accessible child of the object.
113  *
114  * The accessible children are 0-based so the first accessible child is at index 0,
115  * the second at index 1 and so on.
116  *
117  * Implementation of AtkObject->ref_child callback.
118  *
119  * @param obj AtkObject instance
120  * @param i child index
121  *
122  * @returns AtkObject representing the specified accessible child of the
123  * accessible
124  */
125 static AtkObject *
126 eail_menu_ref_child(AtkObject *obj, gint i)
127 {
128    Eina_List *items;
129    AtkObject *child = NULL;
130
131    items = eail_menu_get_items(EAIL_MENU(obj));
132    if (eina_list_count(items) > i)
133      {
134         child = eail_factory_get_item_atk_obj
135                  (eina_list_nth(items, i), ATK_ROLE_MENU_ITEM, obj);
136
137         g_object_ref(child);
138      }
139
140    eina_list_free(items);
141
142    return child;
143 }
144
145
146 /**
147  * @brief Gets the accessible name of the accessible
148  *
149  * Implementation of AtkObject->get_name callback.
150  *
151  * @param obj AtkObject instance
152  *
153  * @returns character string representing the accessible name of
154  * the accessible
155  */
156 static const gchar *
157 eail_menu_get_name(AtkObject *obj)
158 {
159    AtkObject *parent = NULL;
160    const gchar *atk_name = NULL;
161
162    /* returning name from ATK default implementation if available */
163    atk_name = ATK_OBJECT_CLASS(eail_menu_parent_class)->get_name(obj);
164    if (atk_name)
165      return atk_name;
166
167    parent = atk_object_get_parent(obj);
168    if (!parent) return NULL;
169
170    return parent->name;
171 }
172
173 /**
174  * @brief Initializer for GObject EailMenu instance
175  *
176  * @param menu EailMenu instance
177  */
178 static void
179 eail_menu_init(EailMenu *menu)
180 {
181 }
182
183 /**
184  * @brief Initializer for GObject class
185  *
186  * Defines callbacks for base AtkObject.
187  *
188  * @param klass EailMenuClass instance
189  */
190 static void
191 eail_menu_class_init(EailMenuClass *klass)
192 {
193    AtkObjectClass *atk_class = ATK_OBJECT_CLASS(klass);
194
195    atk_class->initialize = eail_menu_initialize;
196    atk_class->get_n_children = eail_menu_get_n_children;
197    atk_class->ref_child = eail_menu_ref_child;
198    atk_class->get_name = eail_menu_get_name;
199 }
200
201 /* Child MenuItem handling  - implementation of EailItemParent interface*/
202
203 /**
204  * @brief Gets the name of a list's child
205  *
206  * @param parent EailItemParent instance
207  * @param item EailItem child instance
208  *
209  * @returns string representing the name of the child
210  */
211 static const gchar *
212 eail_menu_item_name_get(EailItemParent *parent, EailItem *item)
213 {
214    Elm_Object_Item *it = eail_item_get_item(item);
215    if (!it) return NULL;
216
217    return elm_object_item_part_text_get(it, NULL);
218 }
219
220 /**
221  * @brief Gets nested Evas_Object of given EailItem
222  *
223  * Implementation of EailItemParent->get_evas_obj callback.
224  *
225  * @param parent EailItemParent instance
226  * @param item EailItem instance
227  * @returns Evas_Object representing the menu item
228  */
229 Evas_Object *
230 eail_menu_item_get_evas_obj(EailItemParent   *parent,
231                        EailItem         *item)
232 {
233    Elm_Object_Item *it = eail_item_get_item(item);
234
235    if (!it)
236      {
237         ERR("Error. Could not get Elm_Object_item from EailItem");
238         return NULL;
239      }
240
241    return elm_menu_item_object_get(it);
242 }
243
244 /**
245  * @brief Gets supported actions
246  *
247  * Implementation of EailItemParent->get_actions_supported callback.
248  *
249  * @param parent EailItemParent instance
250  * @param item EailItem instance
251  * @returns integer representing supported actions
252  */
253 static gint
254 eail_menu_get_actions_supported(EailItemParent   *parent,
255                                    EailItem         *item)
256 {
257    return EAIL_ACTION_SUPPORTED_CLICK;
258 }
259
260 /**
261  * @brief Prepares Eina_List filled with Elm_Object_Item* objects
262  * representing items in the list
263  *
264  * Call eina_list_free on the returned list when results processing has been finished.
265  *
266  * @param menu_item_obj child of menu widget
267  *
268  * @return Eina_List representing the list of menu items
269  */
270 static const Eina_List *
271 eail_menu_item_get_items(EailItem *menu_item_obj)
272 {
273    const Eina_List *items = NULL;
274    EailItem *eail_item = EAIL_ITEM(menu_item_obj);
275    Elm_Object_Item *it = eail_item_get_item(eail_item);
276
277    items = elm_menu_item_subitems_get(it);
278
279    return items;
280 }
281
282 /**
283  * @brief Gets the number of accessible children of the accessible
284  *
285  * Implementation of AtkObject->get_n_children callback.
286  *
287  * @param parent EAIL representation of menu widget
288  * @param eail_item child of menu widget
289  *
290  * @returns integer representing the number of accessible children of
291  * the accessible
292  */
293 static gint
294 eail_menu_item_get_n_children(EailItemParent *parent, EailItem *eail_item)
295 {
296    gint n_items;
297    const Eina_List *items;
298    Evas_Object *inside_widget = NULL;
299
300    items = eail_menu_item_get_items(eail_item);
301    n_items = eina_list_count(items);
302
303    /* increasing child items count for widgets that are stored inside
304     * menu item (eg. icon or button). They will be appended at the end
305     * of the children list in eail_menu_item_ref_child func*/
306    inside_widget = elm_object_item_content_get(eail_item_get_item(eail_item));
307    if (inside_widget)
308      n_items++;
309
310    return n_items;
311 }
312
313 /**
314  * @brief Creates content widgets from given menu_item AtkObject
315  *
316  * @param menu_item_obj AtkObject menu item
317  * @returns AtkObject representing the nested content of menu item
318  */
319 static AtkObject *
320 _eail_menu_item_create_content_atk_obj(AtkObject *menu_item_obj)
321 {
322    EailItem *eail_item = EAIL_ITEM(menu_item_obj);
323    Evas_Object *content_widget = NULL;
324    AtkObject *content_atk_obj = NULL;
325
326    content_widget = elm_object_item_content_get(eail_item_get_item(eail_item));
327
328    if (!content_widget)
329      {
330         ERR("Content widget could not be found in menu_item.");
331         return NULL;
332      }
333
334    content_atk_obj = eail_factory_get_accessible(content_widget);
335
336    return content_atk_obj;
337 }
338
339 /**
340  * @brief Gets a reference to the specified accessible child of the object.
341  *
342  * The accessible children are 0-based so the first accessible child is at index 0,
343  * the second at index 1 and so on.
344  *
345  * Implementation of AtkObject->ref_child callback.
346  *
347  * @param parent EailItemParent instance
348  * @param item EailItem instance
349  * @param i child index
350  *
351  * @returns AtkObject representing the specified accessible child of the
352  * accessible
353  */
354 static AtkObject *
355 eail_menu_item_ref_child(EailItemParent   *parent,
356                          EailItem         *item,
357                          gint             i)
358 {
359    const Eina_List *items;
360    AtkObject *child = NULL;
361    Elm_Object_Item *elm_obj_item = NULL;
362
363    items = eail_menu_item_get_items(item);
364    if (eina_list_count(items) > i)
365      {
366         elm_obj_item = eina_list_nth(items, i);
367
368         /* creating new menu item from Elm_Object_Item */
369         child = eail_factory_get_item_atk_obj
370                          (elm_obj_item, ATK_ROLE_MENU_ITEM, ATK_OBJECT(parent));
371      }
372    else if (eina_list_count(items) == i)
373      {
374         /* ref to widget inside menu item has to be referenced */
375         child = _eail_menu_item_create_content_atk_obj(ATK_OBJECT(item));
376      }
377
378    if (child)
379      g_object_ref(child);
380    else
381      ERR("Could not ref menu item child for index %d", i);
382
383    return child;
384 }
385
386 /**
387  * @brief Checks if content get is supported
388  *
389  * Implementation of EailItemParent->is_content_get_supported callback.
390  *
391  * @param parent EailItemParent instance
392  * @param item EailItem instance
393  * @returns always FALSE
394  */
395 gboolean
396 eail_menu_item_content_get_support(EailItemParent   *parent,
397                                    EailItem         *item)
398 {
399    return FALSE;
400 }
401
402 /**
403  * @brief Gets index in parent
404  *
405  * @param parent EailItemParent instance
406  * @param item EailItem child instance
407  *
408  * @returns int representing the index in parent
409  */
410 static gint
411 eail_menu_get_item_index_in_parent(EailItemParent *parent, EailItem *item)
412 {
413    Elm_Object_Item *it = eail_item_get_item(item);
414    if (!it) return -1;
415
416    return elm_menu_item_index_get(it);
417 }
418
419 /**
420  * @brief Initializes EailItemParentIface callbacks
421  *
422  * @param iface EailItemParentIface instance
423  */
424 static void
425 eail_item_parent_interface_init(EailItemParentIface *iface)
426 {
427    iface->get_evas_obj = eail_menu_item_get_evas_obj;
428    iface->get_item_name = eail_menu_item_name_get;
429    iface->get_n_children = eail_menu_item_get_n_children;
430    iface->ref_n_child = eail_menu_item_ref_child;
431    iface->get_actions_supported = eail_menu_get_actions_supported;
432    iface->is_content_get_supported = eail_menu_item_content_get_support;
433    iface->get_item_index_in_parent = eail_menu_get_item_index_in_parent;
434 }