Merge "custom eail widget implementation" into tizen
[platform/core/uifw/eail.git] / eail / eail_naviframe.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_naviframe.c
22  * @brief EailNaviframe implementation
23  */
24
25 #include "eail_naviframe.h"
26 #include "eail_naviframe_page.h"
27 #include "eail_factory.h"
28 #include "eail_utils.h"
29 #include "eail_priv.h"
30
31 #define EAIL_NAVIFRAME_CLICK_ACTION "click" /**< @brief 'click' action name*/
32
33 /**
34  * @brief Define EailNaviframe GObject type
35  *
36  * It extends EAIL_TYPE_WIDGET and implements ATK_TYPE_SELECTION and
37  * ATK_TYPE_ACTION interfaces
38  */
39 G_DEFINE_TYPE(EailNaviframe, eail_naviframe, EAIL_TYPE_ACTION_WIDGET);
40
41 /**
42  * @brief Gets the number of accessible children of the accessible
43  *
44  * Implementation of AtkObject->get_n_children callback.
45  *
46  * @param obj AtkObject instance
47  *
48  * @returns integer representing the number of accessible children of
49  * the accessible
50  */
51 static gint
52 eail_naviframe_n_children_get(AtkObject *obj)
53 {
54    EailNaviframe *naviframe;
55    Evas_Object *widget;
56    Eina_List *list;
57    int list_count;
58
59    g_return_val_if_fail(EAIL_IS_NAVIFRAME(obj), -1);
60
61    naviframe = EAIL_NAVIFRAME(obj);
62    widget = eail_widget_get_widget(EAIL_WIDGET(naviframe));
63    list = elm_naviframe_items_get(widget);
64    list_count = eina_list_count(list);
65    eina_list_free(list);
66
67    return list_count;
68 }
69
70 /**
71  * @brief 'click' action callback
72  *
73  * @param action AtkAction instance
74  * @param data user data
75  * @return TRUE on success, FALSE otherwise
76  */
77 static gboolean
78 eail_naviframe_action_click(AtkAction *action, void *data)
79 {
80    EailNaviframe *naviframe;
81    Evas_Object *widget, *target;
82    Elm_Object_Item *it;
83
84    g_return_val_if_fail(EAIL_IS_NAVIFRAME(action), FALSE);
85
86    naviframe = EAIL_NAVIFRAME(action);
87
88    widget = eail_widget_get_widget(EAIL_WIDGET(naviframe));
89    it = elm_naviframe_top_item_get(widget);
90    if (!elm_naviframe_item_title_enabled_get(it)) return FALSE;
91
92    target = elm_object_item_widget_get(it);
93    if (!target) return FALSE;
94
95    evas_object_smart_callback_call(target, "title,clicked", it);
96
97    return TRUE;
98 }
99
100 /**
101  * @brief Initializes Action interface for Naviframe
102  *
103  * @param action_widget EailActionWidget instance
104  */
105 static void eail_naviframe_actions_init(EailActionWidget *action_widget)
106 {
107    eail_action_widget_action_append(action_widget,
108                                     EAIL_NAVIFRAME_CLICK_ACTION, NULL,
109                                     eail_naviframe_action_click);
110 }
111
112 /**
113  * @brief Initializer for GObject EailNaviframe instance
114  *
115  * @param naviframe EailNaviframe instance
116  */
117 static void
118 eail_naviframe_init(EailNaviframe *naviframe)
119 {
120 }
121
122 /**
123  * @brief Returns naviframe-page implementation for given object item
124  *
125  * @param naviframe AtkObject instance
126  * @param item Elm_Object_Item for naviframe-page
127  *
128  * @returns AtkObject representation of naviframe-page
129  */
130 static AtkObject *
131 _eail_naviframe_get_naviframe_page_for_item(AtkObject *naviframe,
132                                             Elm_Object_Item *item)
133 {
134    EailFactoryObj *factory_obj = NULL;
135    AtkObject *naviframe_page = NULL;
136
137    factory_obj = eail_factory_find_obj_for_item(item);
138    if (factory_obj)
139      {
140         if (!factory_obj->atk_obj)
141           ERR("No atk obj created for factory item object");
142
143         return factory_obj->atk_obj;
144      }
145
146    naviframe_page = eail_naviframe_page_new(naviframe, item);
147    atk_object_initialize(naviframe_page, item);
148    eail_factory_append_item_to_cache(ATK_OBJECT(naviframe_page), item);
149
150    return naviframe_page;
151 }
152
153 /**
154  * @brief Gets a reference to the specified accessible child of the object.
155  *
156  * The accessible children are 0-based so the first accessible child is at index 0,
157  * the second at index 1 and so on.
158  *
159  * Implementation of AtkObject->ref_child callback.
160  *
161  * @param obj AtkObject instance
162  * @param i child index
163  *
164  * @returns AtkObject representing the specified accessible child of the
165  * accessible
166  */
167 static AtkObject *
168 eail_naviframe_ref_child(AtkObject *obj, gint i)
169 {
170    Eina_List *list;
171    EailNaviframe *naviframe;
172    EailWidget *widget;
173    Evas_Object *e_object;
174
175    g_return_val_if_fail(EAIL_IS_NAVIFRAME(obj), NULL);
176
177    naviframe = EAIL_NAVIFRAME(obj);
178    widget = EAIL_WIDGET(naviframe);
179
180    e_object = eail_widget_get_widget(widget);
181
182    list = elm_naviframe_items_get(e_object);
183    int list_count = eina_list_count(list);
184    if (i >= list_count)
185      {
186         eina_list_free(list);
187         return NULL;
188      }
189
190    AtkObject *child = _eail_naviframe_get_naviframe_page_for_item
191                                                 (obj, eina_list_nth(list, i));
192    g_object_ref(child);
193    eina_list_free(list);
194
195    return child;
196 }
197
198 /**
199  * @brief Destructor of naviframe object
200  * @param obj GObject instance
201  */
202 static void
203 eail_naviframe_finalize(GObject *obj)
204 {
205    EailNaviframe *naviframe = EAIL_NAVIFRAME(obj);
206
207    if (naviframe->click_description)
208      free(naviframe->click_description);
209
210    G_OBJECT_CLASS(eail_naviframe_parent_class)->finalize(obj);
211 }
212
213 /**
214  * @brief Emits state-changed signals for naviframe child page if needed
215  *
216  * @param naviframe_page an AtkObject for naviframe page
217  */
218 static void
219 _eail_naviframe_page_emit_changed_signals(AtkObject *naviframe_page)
220 {
221    AtkStateSet *state_set = NULL;
222    gboolean visible = FALSE;
223
224    state_set = atk_object_ref_state_set(naviframe_page);
225    visible = atk_state_set_contains_state(state_set, ATK_STATE_VISIBLE);
226
227    atk_object_notify_state_change(naviframe_page, ATK_STATE_VISIBLE, visible);
228    atk_object_notify_state_change(naviframe_page, ATK_STATE_SHOWING, visible);
229    DBG("Emiting state_changed visible/showing: %d", visible);
230 }
231
232 /**
233  * @brief Handles signals changes for naviframe and its children pages
234  *
235  * @param naviframe an AtkObject for naviframe
236  */
237 static void
238 _eail_naviframe_emit_signals_changed(AtkObject *naviframe)
239 {
240    gint n_children = 0, i = 0;
241    AtkObject *navipage = NULL;
242
243    n_children = eail_naviframe_n_children_get(naviframe);
244
245    for (i = 0; i < n_children; ++i)
246      {
247         navipage = eail_naviframe_ref_child(naviframe, i);
248         if (navipage)
249           {
250               DBG("Emitting state-changed for child %d", i);
251
252               _eail_naviframe_page_emit_changed_signals(navipage);
253               g_object_unref(navipage);
254           }
255      }
256 }
257
258 /**
259  * @brief Handler for event which is raised when naviframe page is changed
260  * ("transition,finished" event)
261  *
262  * @param data data passed to callback
263  * @param obj Evas_Object that raised event
264  * @param event_info additional event info
265  */
266 void
267 _eail_naviframe_handle_page_changed_event(void *data,
268                                           Evas_Object *obj,
269                                           void *event_info)
270 {
271    EailNaviframe *naviframe_obj = NULL;
272    g_return_if_fail(EAIL_IS_NAVIFRAME(data));
273    gint n_children = 0;
274
275    eail_emit_atk_signal
276                   (ATK_OBJECT(data), "visible-data-changed", ATK_TYPE_OBJECT);
277
278    naviframe_obj = EAIL_NAVIFRAME(data);
279    if (!naviframe_obj) return;
280
281    _eail_naviframe_emit_signals_changed(ATK_OBJECT(naviframe_obj));
282
283    n_children = eail_naviframe_n_children_get(ATK_OBJECT(naviframe_obj));
284    DBG("N_CHILDREN: %d", n_children);
285
286    if (n_children && n_children > naviframe_obj->child_count_last)
287      {
288          eail_emit_children_changed(TRUE, ATK_OBJECT(data), n_children - 1);
289      }
290    else if(n_children < naviframe_obj->child_count_last)
291     {
292          eail_emit_children_changed(FALSE, ATK_OBJECT(data), n_children);
293     }
294
295    naviframe_obj->child_count_last = n_children;
296 }
297
298 /**
299  * @brief Initializer for AtkObjectClass
300  *
301  * @param obj AtkObject instance
302  * @param data initialization data
303  */
304 static void
305 eail_naviframe_initialize(AtkObject *obj, gpointer data)
306 {
307    Evas_Object *nested_widget = NULL;
308    EailNaviframe *naviframe_obj = NULL;
309    ATK_OBJECT_CLASS(eail_naviframe_parent_class)->initialize(obj, data);
310
311    obj->role = ATK_ROLE_PAGE_TAB_LIST;
312    g_return_if_fail(EAIL_IS_WIDGET(obj));
313
314    nested_widget = eail_widget_get_widget(EAIL_WIDGET(obj));
315    if (!nested_widget)
316      {
317         ERR("No evas object inside EailWidget was found");
318         return;
319      }
320
321    evas_object_smart_callback_add(nested_widget, "transition,finished",
322                                 _eail_naviframe_handle_page_changed_event, obj);
323
324    eail_naviframe_actions_init(EAIL_ACTION_WIDGET(obj));
325
326    naviframe_obj = EAIL_NAVIFRAME(obj);
327    /* storing last numbers of children to be for checking if children-changed
328     * signal has to be propagated */
329    naviframe_obj->child_count_last = eail_naviframe_n_children_get(obj);
330 }
331
332 /**
333  * @brief Initializer for GObject naviframe class
334  *
335  * Defines callbacks for base AtkObject.
336  *
337  * @param klass EailNaviframeClass instance
338  */
339 static void
340 eail_naviframe_class_init(EailNaviframeClass *klass)
341 {
342    AtkObjectClass *class = ATK_OBJECT_CLASS(klass);
343    GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
344
345    class->initialize = eail_naviframe_initialize;
346    class->get_n_children = eail_naviframe_n_children_get;
347    class->ref_child = eail_naviframe_ref_child;
348
349    gobject_class->finalize = eail_naviframe_finalize;
350 }
351