elementary/map - map supports language,changed
[framework/uifw/elementary.git] / src / lib / elm_glview.c
1 #include <Elementary.h>
2 #include "elm_priv.h"
3 #include "elm_widget_glview.h"
4
5 EAPI const char ELM_GLVIEW_SMART_NAME[] = "elm_glview";
6
7 static const char SIG_FOCUSED[] = "focused";
8 static const char SIG_UNFOCUSED[] = "unfocused";
9 static const char SIG_LANG_CHANGED[] = "language,changed";
10
11 /* smart callbacks coming from elm glview objects: */
12 static const Evas_Smart_Cb_Description _smart_callbacks[] = {
13    {SIG_FOCUSED, ""},
14    {SIG_UNFOCUSED, ""},
15    {SIG_LANG_CHANGED, ""},
16    {NULL, NULL}
17 };
18
19 EVAS_SMART_SUBCLASS_NEW
20   (ELM_GLVIEW_SMART_NAME, _elm_glview, Elm_Glview_Smart_Class,
21   Elm_Widget_Smart_Class, elm_widget_smart_class_get, _smart_callbacks);
22
23 static Eina_Bool
24 _elm_glview_smart_translate(Evas_Object *obj)
25 {
26    evas_object_smart_callback_call(obj, SIG_LANG_CHANGED, NULL);
27    return EINA_TRUE;
28 }
29
30 static Eina_Bool
31 _elm_glview_smart_on_focus(Evas_Object *obj)
32 {
33    ELM_GLVIEW_DATA_GET(obj, sd);
34
35    if (elm_widget_focus_get(obj))
36      {
37         evas_object_focus_set(ELM_WIDGET_DATA(sd)->resize_obj, EINA_TRUE);
38         evas_object_smart_callback_call(obj, SIG_FOCUSED, NULL);
39      }
40    else
41      {
42         evas_object_focus_set(ELM_WIDGET_DATA(sd)->resize_obj, EINA_FALSE);
43         evas_object_smart_callback_call(obj, SIG_UNFOCUSED, NULL);
44      }
45
46    return EINA_TRUE;
47 }
48
49 static void
50 _glview_update_surface(Evas_Object *obj)
51 {
52    ELM_GLVIEW_DATA_GET(obj, sd);
53    if (!sd) return;
54
55    if (sd->surface)
56      {
57         evas_object_image_native_surface_set
58           (ELM_WIDGET_DATA(sd)->resize_obj, NULL);
59         evas_gl_surface_destroy(sd->evasgl, sd->surface);
60         sd->surface = NULL;
61      }
62
63    evas_object_image_size_set(ELM_WIDGET_DATA(sd)->resize_obj, sd->w, sd->h);
64
65    if (!sd->surface)
66      {
67         Evas_Native_Surface ns;
68
69         sd->surface = evas_gl_surface_create
70             (sd->evasgl, sd->config, sd->w, sd->h);
71         evas_gl_native_surface_get(sd->evasgl, sd->surface, &ns);
72         evas_object_image_native_surface_set
73           (ELM_WIDGET_DATA(sd)->resize_obj, &ns);
74         elm_glview_changed_set(obj);
75      }
76 }
77
78 static void
79 _elm_glview_smart_resize(Evas_Object *obj,
80                          Evas_Coord w,
81                          Evas_Coord h)
82 {
83    ELM_GLVIEW_DATA_GET(obj, sd);
84
85    _elm_glview_parent_sc->base.resize(obj, w, h);
86
87    sd->resized = EINA_TRUE;
88
89    if (sd->scale_policy == ELM_GLVIEW_RESIZE_POLICY_RECREATE)
90      {
91         if ((w == 0) || (h == 0))
92           {
93              w = 64;
94              h = 64;
95           }
96
97         if ((sd->w == w) && (sd->h == h)) return;
98
99         sd->w = w;
100         sd->h = h;
101
102         _glview_update_surface(obj);
103      }
104 }
105
106 static Eina_Bool
107 _render_cb(void *obj)
108 {
109    ELM_GLVIEW_DATA_GET(obj, sd);
110
111    // Do a make current
112    if (!evas_gl_make_current(sd->evasgl, sd->surface, sd->context))
113      {
114         sd->render_idle_enterer = NULL;
115         ERR("Failed doing make current.\n");
116         return EINA_FALSE;
117      }
118
119    // Call the init function if it hasn't been called already
120    if (!sd->initialized)
121      {
122         if (sd->init_func) sd->init_func(obj);
123         sd->initialized = EINA_TRUE;
124      }
125
126    if (sd->resized)
127      {
128         if (sd->resize_func) sd->resize_func(obj);
129         sd->resized = EINA_FALSE;
130      }
131
132    // Call the render function
133    if (sd->render_func) sd->render_func(obj);
134
135    // Depending on the policy return true or false
136    if (sd->render_policy == ELM_GLVIEW_RENDER_POLICY_ON_DEMAND)
137      return EINA_TRUE;
138    else if (sd->render_policy == ELM_GLVIEW_RENDER_POLICY_ALWAYS)
139      {
140         // Return false so it only runs once
141         sd->render_idle_enterer = NULL;
142         return EINA_FALSE;
143      }
144    else
145      {
146         ERR("Invalid Render Policy.\n");
147         sd->render_idle_enterer = NULL;
148         return EINA_FALSE;
149      }
150
151    return EINA_TRUE;
152 }
153
154 static void
155 _set_render_policy_callback(Evas_Object *obj)
156 {
157    ELM_GLVIEW_DATA_GET(obj, sd);
158
159    switch (sd->render_policy)
160      {
161       case ELM_GLVIEW_RENDER_POLICY_ON_DEMAND:
162         // Delete idle_enterer if it for some reason is around
163         if (sd->render_idle_enterer)
164           {
165              ecore_idle_enterer_del(sd->render_idle_enterer);
166              sd->render_idle_enterer = NULL;
167           }
168
169         // Set pixel getter callback
170         evas_object_image_pixels_get_callback_set
171           (ELM_WIDGET_DATA(sd)->resize_obj,
172           (Evas_Object_Image_Pixels_Get_Cb)_render_cb,
173           obj);
174         break;
175
176       case ELM_GLVIEW_RENDER_POLICY_ALWAYS:
177         // Unset the pixel getter callback if set already
178         evas_object_image_pixels_get_callback_set
179           (ELM_WIDGET_DATA(sd)->resize_obj, NULL, NULL);
180
181         break;
182
183       default:
184         ERR("Invalid Render Policy.\n");
185         return;
186      }
187 }
188
189 static void
190 _elm_glview_smart_add(Evas_Object *obj)
191 {
192    EVAS_SMART_DATA_ALLOC(obj, Elm_Glview_Smart_Data);
193
194    // Create image to render Evas_GL Surface
195    ELM_WIDGET_DATA(priv)->resize_obj =
196      evas_object_image_filled_add(evas_object_evas_get(obj));
197    evas_object_image_size_set(ELM_WIDGET_DATA(priv)->resize_obj, 1, 1);
198
199    _elm_glview_parent_sc->base.add(obj);
200
201    // Evas_GL
202    priv->evasgl = evas_gl_new(evas_object_evas_get(obj));
203    if (!priv->evasgl)
204      {
205         ERR("Failed Creating an Evas GL Object.\n");
206
207         return;
208      }
209
210    // Create a default config
211    priv->config = evas_gl_config_new();
212    if (!priv->config)
213      {
214         ERR("Failed Creating a Config Object.\n");
215         evas_object_del(obj);
216
217         evas_gl_free(priv->evasgl);
218         priv->evasgl = NULL;
219         return;
220      }
221    priv->config->color_format = EVAS_GL_RGB_888;
222
223    // Initialize variables
224    priv->mode = 0;
225    priv->scale_policy = ELM_GLVIEW_RESIZE_POLICY_RECREATE;
226    priv->render_policy = ELM_GLVIEW_RENDER_POLICY_ON_DEMAND;
227    priv->surface = NULL;
228
229    // Initialize it to (64,64)  (It's an arbitrary value)
230    priv->w = 64;
231    priv->h = 64;
232
233    // Initialize the rest of the values
234    priv->init_func = NULL;
235    priv->del_func = NULL;
236    priv->render_func = NULL;
237    priv->render_idle_enterer = NULL;
238    priv->initialized = EINA_FALSE;
239    priv->resized = EINA_FALSE;
240
241    // Create Context
242    priv->context = evas_gl_context_create(priv->evasgl, NULL);
243    if (!priv->context)
244      {
245         ERR("Error Creating an Evas_GL Context.\n");
246         evas_object_del(obj);
247
248         evas_gl_config_free(priv->config);
249         evas_gl_free(priv->evasgl);
250         priv->evasgl = NULL;
251         return;
252      }
253 }
254
255 static void
256 _elm_glview_smart_del(Evas_Object *obj)
257 {
258    ELM_GLVIEW_DATA_GET(obj, sd);
259
260    // Call delete func if it's registered
261    if (sd->del_func)
262      {
263         evas_gl_make_current(sd->evasgl, sd->surface, sd->context);
264         sd->del_func(obj);
265      }
266
267    if (sd->render_idle_enterer)
268      ecore_idle_enterer_del(sd->render_idle_enterer);
269
270    if (sd->surface) evas_gl_surface_destroy(sd->evasgl, sd->surface);
271    if (sd->context) evas_gl_context_destroy(sd->evasgl, sd->context);
272    if (sd->config) evas_gl_config_free(sd->config);
273    if (sd->evasgl) evas_gl_free(sd->evasgl);
274
275    _elm_glview_parent_sc->base.del(obj); /* handles freeing sd */
276 }
277
278 static void
279 _elm_glview_smart_set_user(Elm_Glview_Smart_Class *sc)
280 {
281    ELM_WIDGET_CLASS(sc)->base.add = _elm_glview_smart_add;
282    ELM_WIDGET_CLASS(sc)->base.del = _elm_glview_smart_del;
283    ELM_WIDGET_CLASS(sc)->base.resize = _elm_glview_smart_resize;
284
285    ELM_WIDGET_CLASS(sc)->on_focus = _elm_glview_smart_on_focus;
286    ELM_WIDGET_CLASS(sc)->translate = _elm_glview_smart_translate;
287 }
288
289 EAPI const Elm_Glview_Smart_Class *
290 elm_glview_smart_class_get(void)
291 {
292    static Elm_Glview_Smart_Class _sc =
293      ELM_GLVIEW_SMART_CLASS_INIT_NAME_VERSION(ELM_GLVIEW_SMART_NAME);
294    static const Elm_Glview_Smart_Class *class = NULL;
295    Evas_Smart_Class *esc = (Evas_Smart_Class *)&_sc;
296
297    if (class) return class;
298
299    _elm_glview_smart_set(&_sc);
300    esc->callbacks = _smart_callbacks;
301    class = &_sc;
302
303    return class;
304 }
305
306 EAPI Evas_Object *
307 elm_glview_add(Evas_Object *parent)
308 {
309    Evas_Object *obj;
310
311    EINA_SAFETY_ON_NULL_RETURN_VAL(parent, NULL);
312
313    obj = elm_widget_add(_elm_glview_smart_class_new(), parent);
314    if (!obj) return NULL;
315
316    ELM_GLVIEW_DATA_GET(obj, sd);
317
318    if (!sd->evasgl)
319      return NULL;
320
321    if (!elm_widget_sub_object_add(parent, obj))
322      ERR("could not add %p as sub object of %p", obj, parent);
323
324    return obj;
325 }
326
327 EAPI Evas_GL_API *
328 elm_glview_gl_api_get(const Evas_Object *obj)
329 {
330    ELM_GLVIEW_CHECK(obj) NULL;
331    ELM_GLVIEW_DATA_GET(obj, sd);
332
333    return evas_gl_api_get(sd->evasgl);
334 }
335
336 EAPI Eina_Bool
337 elm_glview_mode_set(Evas_Object *obj,
338                     Elm_GLView_Mode mode)
339 {
340    ELM_GLVIEW_CHECK(obj) EINA_FALSE;
341    ELM_GLVIEW_DATA_GET(obj, sd);
342
343    // Set the configs
344    if (mode & ELM_GLVIEW_ALPHA) sd->config->color_format = EVAS_GL_RGBA_8888;
345    else sd->config->color_format = EVAS_GL_RGB_888;
346
347    if (mode & ELM_GLVIEW_DEPTH) sd->config->depth_bits = EVAS_GL_DEPTH_BIT_24;
348    else sd->config->depth_bits = EVAS_GL_DEPTH_NONE;
349
350    if (mode & ELM_GLVIEW_STENCIL)
351      sd->config->stencil_bits = EVAS_GL_STENCIL_BIT_8;
352    else sd->config->stencil_bits = EVAS_GL_STENCIL_NONE;
353
354    if (mode & ELM_GLVIEW_DIRECT)
355      sd->config->options_bits = EVAS_GL_OPTIONS_DIRECT;
356    else sd->config->options_bits = EVAS_GL_OPTIONS_NONE;
357
358    // Check for Alpha Channel and enable it
359    if (mode & ELM_GLVIEW_ALPHA)
360      evas_object_image_alpha_set(ELM_WIDGET_DATA(sd)->resize_obj, EINA_TRUE);
361    else
362      evas_object_image_alpha_set(ELM_WIDGET_DATA(sd)->resize_obj, EINA_FALSE);
363
364    sd->mode = mode;
365
366    elm_glview_changed_set(obj);
367
368    return EINA_TRUE;
369 }
370
371 EAPI Eina_Bool
372 elm_glview_resize_policy_set(Evas_Object *obj,
373                              Elm_GLView_Resize_Policy policy)
374 {
375    ELM_GLVIEW_CHECK(obj) EINA_FALSE;
376    ELM_GLVIEW_DATA_GET(obj, sd);
377
378    if (policy == sd->scale_policy) return EINA_TRUE;
379    switch (policy)
380      {
381       case ELM_GLVIEW_RESIZE_POLICY_RECREATE:
382       case ELM_GLVIEW_RESIZE_POLICY_SCALE:
383         sd->scale_policy = policy;
384         _glview_update_surface(obj);
385         elm_glview_changed_set(obj);
386         return EINA_TRUE;
387
388       default:
389         ERR("Invalid Scale Policy.\n");
390         return EINA_FALSE;
391      }
392 }
393
394 EAPI Eina_Bool
395 elm_glview_render_policy_set(Evas_Object *obj,
396                              Elm_GLView_Render_Policy policy)
397 {
398    ELM_GLVIEW_CHECK(obj) EINA_FALSE;
399    ELM_GLVIEW_DATA_GET(obj, sd);
400
401    if ((policy != ELM_GLVIEW_RENDER_POLICY_ON_DEMAND) &&
402        (policy != ELM_GLVIEW_RENDER_POLICY_ALWAYS))
403      {
404         ERR("Invalid Render Policy.\n");
405         return EINA_FALSE;
406      }
407
408    if (sd->render_policy == policy) return EINA_TRUE;
409
410    sd->render_policy = policy;
411    _set_render_policy_callback(obj);
412    _glview_update_surface(obj);
413
414    return EINA_TRUE;
415 }
416
417 EAPI void
418 elm_glview_size_set(Evas_Object *obj,
419                     int w,
420                     int h)
421 {
422    ELM_GLVIEW_CHECK(obj);
423    ELM_GLVIEW_DATA_GET(obj, sd);
424
425    if ((w == sd->w) && (h == sd->h)) return;
426
427    sd->w = w;
428    sd->h = h;
429    _glview_update_surface(obj);
430
431    elm_glview_changed_set(obj);
432 }
433
434 EAPI void
435 elm_glview_size_get(const Evas_Object *obj,
436                     int *w,
437                     int *h)
438 {
439    ELM_GLVIEW_CHECK(obj);
440    ELM_GLVIEW_DATA_GET(obj, sd);
441
442    if (w) *w = sd->w;
443    if (h) *h = sd->h;
444 }
445
446 EAPI void
447 elm_glview_init_func_set(Evas_Object *obj,
448                          Elm_GLView_Func_Cb func)
449 {
450    ELM_GLVIEW_CHECK(obj);
451    ELM_GLVIEW_DATA_GET(obj, sd);
452
453    sd->initialized = EINA_FALSE;
454    sd->init_func = func;
455 }
456
457 EAPI void
458 elm_glview_del_func_set(Evas_Object *obj,
459                         Elm_GLView_Func_Cb func)
460 {
461    ELM_GLVIEW_CHECK(obj);
462    ELM_GLVIEW_DATA_GET(obj, sd);
463
464    sd->del_func = func;
465 }
466
467 EAPI void
468 elm_glview_resize_func_set(Evas_Object *obj,
469                            Elm_GLView_Func_Cb func)
470 {
471    ELM_GLVIEW_CHECK(obj);
472    ELM_GLVIEW_DATA_GET(obj, sd);
473
474    sd->resize_func = func;
475 }
476
477 EAPI void
478 elm_glview_render_func_set(Evas_Object *obj,
479                            Elm_GLView_Func_Cb func)
480 {
481    ELM_GLVIEW_CHECK(obj);
482    ELM_GLVIEW_DATA_GET(obj, sd);
483
484    sd->render_func = func;
485    _set_render_policy_callback(obj);
486 }
487
488 EAPI void
489 elm_glview_changed_set(Evas_Object *obj)
490 {
491    ELM_GLVIEW_CHECK(obj);
492    ELM_GLVIEW_DATA_GET(obj, sd);
493
494    evas_object_image_pixels_dirty_set
495      (ELM_WIDGET_DATA(sd)->resize_obj, EINA_TRUE);
496    if (sd->render_policy == ELM_GLVIEW_RENDER_POLICY_ALWAYS &&
497        !sd->render_idle_enterer)
498      sd->render_idle_enterer =
499        ecore_idle_enterer_before_add((Ecore_Task_Cb)_render_cb, obj);
500 }