Exiting from Screen zoom by pressing "Escape" or "Backspace" key.
[profile/tv/apps/web/browser.git] / services / ZoomUI / ZoomUI.cpp
1 /*
2  * Copyright (c) 2015 Samsung Electronics Co., Ltd.
3  *
4  * Licensed under the Apache License, Version 2.0 (the License);
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an AS IS BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17
18 #include <Elementary.h>
19 #include <boost/concept_check.hpp>
20 #include <vector>
21 #include <AbstractMainWindow.h>
22
23 #include "ZoomUI.h"
24 #include "BrowserLogger.h"
25 #include "ServiceManager.h"
26
27 #define DX 50
28 #define iDX -50
29
30 namespace tizen_browser{
31 namespace base_ui{
32
33 EXPORT_SERVICE(ZoomUI, "org.tizen.browser.zoomui")
34
35 ZoomUI::ZoomUI()
36     : m_layout(nullptr)
37     , m_zoom_slider(nullptr)
38     , m_nav_layout(nullptr)
39     , m_current_translation_x(0)
40     , m_current_translation_y(0)
41 {
42     BROWSER_LOGD("[%s:%d] ", __PRETTY_FUNCTION__, __LINE__);
43     m_edjFilePath = EDJE_DIR;
44     m_edjFilePath.append("ZoomUI/ZoomUI.edj");
45     elm_theme_extension_add(nullptr, m_edjFilePath.c_str());
46 }
47
48 ZoomUI::~ZoomUI() {}
49
50 void ZoomUI::init(Evas_Object* parent)
51 {
52     BROWSER_LOGD("[%s:%d] ", __PRETTY_FUNCTION__, __LINE__);
53     M_ASSERT(parent);
54     m_parent = parent;
55 }
56
57 Evas_Object* ZoomUI::getContent()
58 {
59     BROWSER_LOGD("[%s:%d] ", __PRETTY_FUNCTION__, __LINE__);
60     M_ASSERT(m_parent);
61     if(!m_layout)
62         createLayout(m_parent);
63     return m_layout;
64 }
65
66 void ZoomUI::showUI()
67 {
68     evas_object_show(m_layout);
69     evas_object_show(m_zoom_menu);
70     evas_object_show(m_zoom_slider);
71     m_keyDownHandler = ecore_event_handler_add(ECORE_EVENT_KEY_DOWN, _key_down_cb, this);
72     m_keyUpHandler = ecore_event_handler_add(ECORE_EVENT_KEY_UP, _key_up_cb, this);
73     int zoomFactor = *(getZoom());
74     elm_slider_value_set(m_zoom_slider, calculateSliderValue(zoomFactor));
75 }
76
77 void ZoomUI::hideUI()
78 {
79     evas_object_hide(m_zoom_slider);
80     evas_object_hide(m_nav_layout);
81     evas_object_hide(m_zoom_menu);
82     evas_object_hide(m_layout);
83     ecore_event_handler_del(m_keyDownHandler);
84     ecore_event_handler_del(m_keyUpHandler);
85 }
86
87 void ZoomUI::show(Evas_Object* parent)
88 {
89     BROWSER_LOGD("[%s:%d] ", __PRETTY_FUNCTION__, __LINE__);
90     init(parent);
91     if (!m_layout)
92         createLayout(parent);
93     showUI();
94     elm_object_focus_set(m_zoom_slider, EINA_TRUE);
95 }
96
97 void ZoomUI::showNavigation()
98 {
99     BROWSER_LOGD("[%s:%d] ", __PRETTY_FUNCTION__, __LINE__);
100     M_ASSERT(m_nav_layout);
101     int zoomFactor = *(getZoom());
102     if (zoomFactor > ZOOM_DEFAULT)
103         evas_object_show(m_nav_layout);
104 }
105
106 bool ZoomUI::isVisible()
107 {
108     BROWSER_LOGD("[%s:%d] ", __PRETTY_FUNCTION__, __LINE__);
109     if (evas_object_visible_get(m_layout) || (*(getZoom()) != ZOOM_DEFAULT))
110         return true;
111     else
112         return false;
113 }
114
115 void ZoomUI::createLayout(Evas_Object *parent)
116 {
117     BROWSER_LOGD("[%s:%d] ", __PRETTY_FUNCTION__, __LINE__);
118
119     m_layout = elm_layout_add(parent);
120     elm_layout_file_set(m_layout, m_edjFilePath.c_str(), "zoom-layout");
121     evas_object_size_hint_weight_set(m_layout, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
122     evas_object_size_hint_align_set(m_layout, EVAS_HINT_FILL, EVAS_HINT_FILL);
123     createZoomSlider();
124     createNavigationButtons();
125 }
126
127 void ZoomUI::createZoomSlider()
128 {
129     m_zoom_menu = elm_layout_add(m_layout);
130     elm_layout_file_set(m_zoom_menu, m_edjFilePath.c_str(), "zoom-menu");
131     evas_object_size_hint_weight_set(m_zoom_menu, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
132     evas_object_size_hint_align_set(m_zoom_menu, EVAS_HINT_FILL, EVAS_HINT_FILL);
133
134     m_zoom_slider = elm_slider_add(m_zoom_menu);
135     evas_object_size_hint_weight_set(m_zoom_slider, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
136     evas_object_size_hint_align_set(m_zoom_slider, EVAS_HINT_FILL, EVAS_HINT_FILL);
137     evas_object_smart_callback_add(m_zoom_slider, "changed", _zoom_slider_changed, this);
138     elm_object_style_set(m_zoom_slider, "default");
139     elm_slider_horizontal_set(m_zoom_slider, EINA_TRUE);
140     elm_slider_min_max_set(m_zoom_slider, 1, 6);
141     elm_slider_step_set(m_zoom_slider, 0.2);
142     int zoomFactor = *(getZoom());
143     elm_slider_value_set(m_zoom_slider, calculateSliderValue(zoomFactor));
144     elm_slider_indicator_show_set(m_zoom_slider, EINA_FALSE);
145
146     elm_object_part_content_set(m_zoom_menu, "slider_swallow", m_zoom_slider);
147     evas_object_event_callback_add(m_zoom_slider, EVAS_CALLBACK_KEY_DOWN, _zoom_value_confirmed, this);
148 }
149
150 void ZoomUI::createNavigationButtons()
151 {
152     m_nav_layout = elm_layout_add(m_layout);
153     elm_layout_file_set(m_nav_layout, m_edjFilePath.c_str(), "nav-layout");
154     evas_object_size_hint_weight_set(m_nav_layout, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
155     evas_object_size_hint_align_set(m_nav_layout, EVAS_HINT_FILL, EVAS_HINT_FILL);
156
157     m_leftArrow = elm_icon_add(m_nav_layout);
158     setImageFile(m_leftArrow, LEFT, false);
159     evas_object_smart_callback_add(m_leftArrow, "clicked", _left_button_clicked, this);
160     evas_object_event_callback_add(m_leftArrow, EVAS_CALLBACK_MOUSE_IN, _cb_focus_in_left_button, this);
161     evas_object_event_callback_add(m_leftArrow, EVAS_CALLBACK_MOUSE_OUT, _cb_focus_out_left_button, this);
162     elm_object_part_content_set(m_nav_layout, "left_button", m_leftArrow);
163
164     m_rightArrow = elm_icon_add(m_nav_layout);
165     setImageFile(m_rightArrow, RIGHT, false);
166     evas_object_smart_callback_add(m_rightArrow, "clicked", _right_button_clicked, this);
167     evas_object_event_callback_add(m_rightArrow, EVAS_CALLBACK_MOUSE_IN, _cb_focus_in_right_button, this);
168     evas_object_event_callback_add(m_rightArrow, EVAS_CALLBACK_MOUSE_OUT, _cb_focus_out_right_button, this);
169     elm_object_part_content_set(m_nav_layout, "right_button", m_rightArrow);
170
171     m_downArrow = elm_icon_add(m_nav_layout);
172     setImageFile(m_downArrow, DOWN, false);
173     evas_object_smart_callback_add(m_downArrow, "clicked", _down_button_clicked, this);
174     evas_object_event_callback_add(m_downArrow, EVAS_CALLBACK_MOUSE_IN, _cb_focus_in_down_button, this);
175     evas_object_event_callback_add(m_downArrow, EVAS_CALLBACK_MOUSE_OUT, _cb_focus_out_down_button, this);
176     elm_object_part_content_set(m_nav_layout, "down_button", m_downArrow);
177
178     m_upArrow = elm_icon_add(m_nav_layout);
179     setImageFile(m_upArrow, UP, false);
180     evas_object_smart_callback_add(m_upArrow, "clicked", _up_button_clicked, this);
181     evas_object_event_callback_add(m_upArrow, EVAS_CALLBACK_MOUSE_IN, _cb_focus_in_up_button, this);
182     evas_object_event_callback_add(m_upArrow, EVAS_CALLBACK_MOUSE_OUT, _cb_focus_out_up_button, this);
183     elm_object_part_content_set(m_nav_layout, "up_button", m_upArrow);
184 }
185
186 void ZoomUI::clearItems()
187 {
188     evas_object_del(m_layout);
189     setZoom(ZOOM_DEFAULT);
190 }
191
192 void ZoomUI::setImageFile(Evas_Object* obj, int direction, bool focused)
193 {
194     BROWSER_LOGD("[%s:%d] ", __PRETTY_FUNCTION__, __LINE__);
195     switch (direction) {
196         case LEFT:  elm_image_file_set(obj, m_edjFilePath.c_str(), focused ? "ic_zoom_indicator_left_foc.png" : "ic_zoom_indicator_left_nor.png");
197                     break;
198         case RIGHT: elm_image_file_set(obj, m_edjFilePath.c_str(), focused ? "ic_zoom_indicator_right_foc.png" : "ic_zoom_indicator_right_nor.png");
199                     break;
200         case DOWN:  elm_image_file_set(obj, m_edjFilePath.c_str(), focused ? "ic_zoom_indicator_down_foc.png" : "ic_zoom_indicator_down_nor.png");
201                     break;
202         case UP:    elm_image_file_set(obj, m_edjFilePath.c_str(), focused ? "ic_zoom_indicator_up_foc.png" : "ic_zoom_indicator_up_nor.png");
203                     break;
204         default:    BROWSER_LOGD("[%s:%d] Warning: Unhandled button", __PRETTY_FUNCTION__, __LINE__);
205                     break;
206     }
207 }
208
209 void ZoomUI::_zoom_slider_changed(void *data, Evas_Object *obj, void*)
210 {
211     BROWSER_LOGD("[%s:%d] ", __PRETTY_FUNCTION__, __LINE__);
212     if(data && obj) {
213         int val = elm_slider_value_get(obj);
214         int zoomLevel = ZOOM_DEFAULT;    
215         ZoomUI *zoomUI = static_cast<ZoomUI*>(data);
216
217         switch (val) {
218             case 1: zoomLevel = ZOOM_50;
219                     break;
220             case 2: zoomLevel = ZOOM_75;
221                     break;
222             case 3: zoomLevel = ZOOM_DEFAULT;
223                     break;
224             case 4: zoomLevel = ZOOM_150;
225                     break;
226             case 5: zoomLevel = ZOOM_200;
227                     break;
228             case 6: zoomLevel = ZOOM_300;
229                     break;
230             default:BROWSER_LOGD("[%s:%d] Warning: Unhandled zoom level", __PRETTY_FUNCTION__, __LINE__);
231                     break;
232         }
233         zoomUI->setZoom(zoomLevel);
234     }
235 }
236
237 void ZoomUI::_zoom_value_confirmed(void* data, Evas*, Evas_Object*, void* event_info)
238 {
239     BROWSER_LOGD("[%s:%d] ", __PRETTY_FUNCTION__, __LINE__);
240     Evas_Event_Key_Down* ev = static_cast<Evas_Event_Key_Down*>(event_info);
241
242     if (!data || !ev || !ev->keyname)
243         return;
244
245     ZoomUI* self = static_cast<ZoomUI*>(data);
246     if (std::string(ev->keyname) == "Return") {
247         int val = (int)elm_slider_value_get(self->m_zoom_slider);
248         BROWSER_LOGD("[%s:%d] val: %d", __PRETTY_FUNCTION__, __LINE__, val);
249         if (val > 3) {
250             BROWSER_LOGD("[%s:%d] value is greater than 3", __PRETTY_FUNCTION__, __LINE__);
251             evas_object_show(self->m_nav_layout);
252         } else {
253             BROWSER_LOGD("[%s:%d] value is smaller or equal to 3", __PRETTY_FUNCTION__, __LINE__);
254             evas_object_hide(self->m_nav_layout);
255         }
256         evas_object_hide(self->m_zoom_menu);
257     }
258 }
259
260 void ZoomUI::escapeZoom()
261 {
262     BROWSER_LOGD("[%s:%d] ", __PRETTY_FUNCTION__, __LINE__);
263     if (isVisible()) {
264         setZoom(ZoomUI::ZOOM_DEFAULT);
265         hideUI();
266     }
267 }
268
269 Eina_Bool ZoomUI::_key_down_cb(void* data, int, void* event_info)
270 {
271     BROWSER_LOGD("[%s:%d] ", __PRETTY_FUNCTION__, __LINE__);
272     Ecore_Event_Key* ev = static_cast<Ecore_Event_Key*>(event_info);
273
274     if (!data || !ev || !ev->keyname)
275         return EINA_FALSE;
276
277     ZoomUI* self = static_cast<ZoomUI*>(data);
278     if (std::string(ev->keyname) == "Left") {
279         _left_button_clicked(data, self->m_leftArrow, event_info);
280         _cb_focus_in_left_button(data, nullptr, self->m_leftArrow, event_info);
281     } else if (std::string(ev->keyname) == "Right") {
282         _right_button_clicked(data, self->m_rightArrow, event_info);
283         _cb_focus_in_right_button(data, nullptr, self->m_rightArrow, event_info);
284     } else if (std::string(ev->keyname) == "Up") {
285         _up_button_clicked(data, self->m_upArrow, event_info);
286         _cb_focus_in_up_button(data, nullptr, self->m_upArrow, event_info);
287     } else if (std::string(ev->keyname) == "Down") {
288         _down_button_clicked(data, self->m_downArrow, event_info);
289         _cb_focus_in_down_button(data, nullptr, self->m_downArrow, event_info);
290     } else
291         return EINA_FALSE;
292
293     return EINA_TRUE;
294 }
295
296 Eina_Bool ZoomUI::_key_up_cb(void* data, int, void* event_info)
297 {
298     BROWSER_LOGD("[%s:%d] ", __PRETTY_FUNCTION__, __LINE__);
299     Ecore_Event_Key* ev = static_cast<Ecore_Event_Key*>(event_info);
300
301     if (!data || !ev || !ev->keyname)
302         return EINA_FALSE;
303
304     ZoomUI* self = static_cast<ZoomUI*>(data);
305     if (std::string(ev->keyname) == "Left") {
306         _cb_focus_out_left_button(data, nullptr, self->m_leftArrow, event_info);
307     } else if (std::string(ev->keyname) == "Right") {
308         _cb_focus_out_right_button(data, nullptr, self->m_rightArrow, event_info);
309     } else if (std::string(ev->keyname) == "Up") {
310         _cb_focus_out_up_button(data, nullptr, self->m_upArrow, event_info);
311     } else if (std::string(ev->keyname) == "Down") {
312         _cb_focus_out_down_button(data, nullptr, self->m_downArrow, event_info);
313     } else
314         return EINA_FALSE;
315
316     return EINA_TRUE;
317 }
318
319 void ZoomUI::_left_button_clicked(void * data, Evas_Object * obj, void*)
320 {
321     BROWSER_LOGD("[%s:%d] ", __PRETTY_FUNCTION__, __LINE__);
322     if (data && obj) {
323         ZoomUI *zoomUI = static_cast<ZoomUI*>(data);
324         zoomUI->scrollView(iDX, 0);
325     }
326 }
327
328 void ZoomUI::_right_button_clicked(void * data, Evas_Object * obj, void*)
329 {
330     BROWSER_LOGD("[%s:%d] ", __PRETTY_FUNCTION__, __LINE__);
331     if (data && obj) {
332         ZoomUI *zoomUI = static_cast<ZoomUI*>(data);
333         zoomUI->scrollView(DX, 0);
334     }
335 }
336
337 void ZoomUI::_up_button_clicked(void * data, Evas_Object * obj, void*)
338 {
339     BROWSER_LOGD("[%s:%d] ", __PRETTY_FUNCTION__, __LINE__);
340     if (data && obj) {
341         ZoomUI *zoomUI = static_cast<ZoomUI*>(data);
342         zoomUI->scrollView(0, iDX);
343     }
344 }
345
346 void ZoomUI::_down_button_clicked(void * data, Evas_Object * obj, void*)
347 {
348     BROWSER_LOGD("[%s:%d] ", __PRETTY_FUNCTION__, __LINE__);
349     if (data && obj) {
350         ZoomUI *zoomUI = static_cast<ZoomUI*>(data);
351         zoomUI->scrollView(0, DX);
352     }
353 }
354
355 void ZoomUI::_cb_focus_in_left_button(void * data, Evas *, Evas_Object *obj, void *)
356 {
357     BROWSER_LOGD("[%s:%d] ", __PRETTY_FUNCTION__, __LINE__);
358     if (data && obj) {
359         elm_object_focus_set(obj, EINA_TRUE);
360         ZoomUI *zoomUI = static_cast<ZoomUI*>(data);
361         zoomUI->setImageFile(obj, LEFT, true);
362     }
363 }
364
365 void ZoomUI::_cb_focus_out_left_button(void * data, Evas *, Evas_Object *obj, void *)
366 {
367     BROWSER_LOGD("[%s:%d] ", __PRETTY_FUNCTION__, __LINE__);
368     if (data && obj) {
369         elm_object_focus_set(obj, EINA_FALSE);
370         ZoomUI *zoomUI = static_cast<ZoomUI*>(data);
371         zoomUI->setImageFile(obj, LEFT, false);
372     }
373 }
374
375 void ZoomUI::_cb_focus_in_right_button(void * data, Evas *, Evas_Object *obj, void *)
376 {
377     BROWSER_LOGD("[%s:%d] ", __PRETTY_FUNCTION__, __LINE__);
378     if (data && obj) {
379         elm_object_focus_set(obj, EINA_TRUE);
380         ZoomUI *zoomUI = static_cast<ZoomUI*>(data);
381         zoomUI->setImageFile(obj, RIGHT, true);
382     }
383 }
384
385 void ZoomUI::_cb_focus_out_right_button(void * data, Evas *, Evas_Object *obj, void *)
386 {
387     BROWSER_LOGD("[%s:%d] ", __PRETTY_FUNCTION__, __LINE__);
388     if (data && obj) {
389         elm_object_focus_set(obj, EINA_FALSE);
390         ZoomUI *zoomUI = static_cast<ZoomUI*>(data);
391         zoomUI->setImageFile(obj, RIGHT, false);
392     }
393 }
394
395 void ZoomUI::_cb_focus_in_up_button(void * data, Evas *, Evas_Object *obj, void *)
396 {
397     BROWSER_LOGD("[%s:%d] ", __PRETTY_FUNCTION__, __LINE__);
398     if (data && obj) {
399         elm_object_focus_set(obj, EINA_TRUE);
400         ZoomUI *zoomUI = static_cast<ZoomUI*>(data);
401         zoomUI->setImageFile(obj, UP, true);
402     }
403 }
404
405 void ZoomUI::_cb_focus_out_up_button(void * data, Evas *, Evas_Object *obj, void *)
406 {
407     BROWSER_LOGD("[%s:%d] ", __PRETTY_FUNCTION__, __LINE__);
408     if (data && obj) {
409         elm_object_focus_set(obj, EINA_FALSE);
410         ZoomUI *zoomUI = static_cast<ZoomUI*>(data);
411         zoomUI->setImageFile(obj, UP, false);
412     }
413 }
414
415 void ZoomUI::_cb_focus_in_down_button(void * data, Evas *, Evas_Object *obj, void *)
416 {
417     BROWSER_LOGD("[%s:%d] ", __PRETTY_FUNCTION__, __LINE__);
418     if (data && obj) {
419         elm_object_focus_set(obj, EINA_TRUE);
420         ZoomUI *zoomUI = static_cast<ZoomUI*>(data);
421         zoomUI->setImageFile(obj, DOWN, true);
422     }
423 }
424
425 void ZoomUI::_cb_focus_out_down_button(void * data, Evas *, Evas_Object *obj, void *)
426 {
427     BROWSER_LOGD("[%s:%d] ", __PRETTY_FUNCTION__, __LINE__);
428     if (data && obj) {
429         elm_object_focus_set(obj, EINA_FALSE);
430         ZoomUI *zoomUI = static_cast<ZoomUI*>(data);
431         zoomUI->setImageFile(obj, DOWN, false);
432     }
433 }
434
435 int ZoomUI::calculateSliderValue(int zoom)
436 {
437     BROWSER_LOGD("[%s:%d] zoom factor: %d", __PRETTY_FUNCTION__, __LINE__, zoom);
438     int rv = 1; //for zoom < ZOOM_75
439     if (zoom >= ZOOM_300)
440         rv = 6;
441     else if (zoom >= ZOOM_200)
442         rv = 5;
443     else if (zoom >= ZOOM_150)
444         rv = 4;
445     else if (zoom >= ZOOM_100)
446         rv = 3;
447     else if (zoom >= ZOOM_75)
448         rv = 2;
449
450     return rv;
451 }
452
453
454 }
455 }