c96fc24cfc353cd30583f758cd5dc4dada428d42
[platform/framework/web/wrt-commons.git] / modules / popup / src / popup_renderer.cpp
1 /*
2  * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved
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  * @file        popup_renderer.cpp
18  * @author      Lukasz Wrzosek (l.wrzosek@samsung.com)
19  * @version     1.0
20  * @brief       This is efl specific implementation for PopupRenderer
21  */
22
23 #include <dpl/popup/popup_manager.h>
24 #include <dpl/popup/popup_renderer.h>
25 #include <dpl/popup/popup_manager.h>
26 #include <dpl/popup/evas_object.h>
27 #include <dpl/shared_ptr.h>
28 #include <dpl/scoped_array.h>
29 #include <dpl/assert.h>
30 #include <dpl/log/log.h>
31 #include <dpl/foreach.h>
32 #include <dpl/framework_efl.h>
33 #include <dpl/lexical_cast.h>
34 #include <queue>
35
36 namespace DPL {
37
38 namespace {
39 using namespace Popup;
40 const char* EDJ_NAME = "/usr/share/edje/ace/generic_popup.edj";
41 const char* POPUP_LAYOUT1 = "popup_layout1";
42 const char* POPUP_LAYOUT2 = "popup_layout2";
43 const char* POPUP_PART_TITLE = "title,text";
44 const char* POPUP_PART_BUTTON1 = "button1";
45 const char* POPUP_PART_BUTTON2 = "button2";
46 const char* POPUP_PART_BUTTON3 = "button3";
47 const char* BUTTON_CLICKED_CALLBACK_NAME = "clicked";
48 const char* CHANGED_CALLBACK_NAME = "changed";
49 const unsigned int MAX_NUMBER_OF_VERTICAL = 2;
50
51 Evas_Object* create_layout_main(Evas_Object* parent, int totalV)
52 {
53     Evas_Object *layout = elm_layout_add(parent);
54
55     if (totalV == 1) {
56         elm_layout_file_set(layout, EDJ_NAME, POPUP_LAYOUT1);
57     } else if (totalV == 2) {
58         elm_layout_file_set(layout, EDJ_NAME, POPUP_LAYOUT2);
59     } else {
60         Assert("popup needs define new group in the edc");
61     }
62
63     evas_object_size_hint_weight_set(layout, EVAS_HINT_EXPAND,
64                                      EVAS_HINT_EXPAND);
65     return layout;
66 }
67 } //namespace
68
69 namespace Popup {
70 class PopupRenderer::Impl
71 {
72   public:
73     Impl() :
74         m_popupsToRender(),
75         m_current(),
76         m_initialized(false)
77     {
78     }
79
80     ~Impl()
81     {
82         if (m_initialized) {
83             LogError("Destroyed without Deinitialize");
84         }
85     }
86
87     void Initialize()
88     {
89         Assert(!m_initialized);
90         m_initialized = true;
91     }
92
93     void Deinitialize()
94     {
95         Assert(m_initialized);
96         m_current.Reset(NULL);
97         while (!m_popupsToRender.empty()) {
98             m_popupsToRender.pop();
99         }
100         m_initialized = false;
101     }
102
103     void ButtonCallback(EvasObject::IConnection* /*connection*/,
104             void* /*event_info*/,
105             void* data)
106     {
107         LogInfo("ButtonCallback");
108         Assert(m_initialized);
109         AnswerCallbackData answerData;
110
111         answerData.buttonAnswer = reinterpret_cast<int>(data);
112         answerData.chackState = m_checkState;
113         answerData.password = m_password;
114         m_current->ForwardAnswer(answerData);
115         m_current.Reset();
116
117         FOREACH(it, m_createdObjects)
118         {
119             if (it->IsValid()) {
120                 evas_object_del(*it);
121             }
122         }
123         m_createdObjects.clear();
124         m_checkState = false;
125         DoRender();
126     }
127
128     void CheckCallback(EvasObject::IConnection* connection,
129             void* /*event_info*/,
130             void* /* unused */)
131     {
132         m_checkState =
133             elm_check_state_get(connection->GetEvasObject());
134     }
135
136     void Render (PopupPtr popup)
137     {
138         Assert(m_initialized);
139         m_popupsToRender.push(popup);
140         DoRender();
141     }
142
143     void DoRender(const PopupObject::Label& object,
144             EvasObject& parent,
145             EvasObject& layout,
146             int themeIndex)
147     {
148         EvasObject label(elm_label_add(parent));
149
150         elm_object_style_set(label, "popup_description/default");
151         elm_label_line_wrap_set(label, ELM_WRAP_WORD);
152         elm_object_text_set(label, object.getLabel().c_str());
153         evas_object_size_hint_weight_set(label, EVAS_HINT_EXPAND, 0.0);
154         evas_object_size_hint_align_set(label, EVAS_HINT_FILL, EVAS_HINT_FILL);
155         evas_object_show(label);
156
157         elm_object_part_content_set(
158             layout,
159             DPL::lexical_cast<std::string>(themeIndex).c_str(),
160             label);
161         m_createdObjects.push_back(label);
162     }
163
164     void DoRender(const PopupObject::Check& object,
165             EvasObject& parent,
166             EvasObject& layout,
167             int themeIndex)
168     {
169         EvasObject check(elm_check_add(parent));
170
171         evas_object_size_hint_align_set(check, EVAS_HINT_FILL, EVAS_HINT_FILL);
172         evas_object_size_hint_weight_set(check, EVAS_HINT_EXPAND, 0.0);
173         elm_object_text_set(check,
174                             object.getCheckLabel().c_str());
175         elm_object_part_content_set(
176             layout,
177             DPL::lexical_cast<std::string>(themeIndex).c_str(),
178             check);
179
180         check.ConnectMemberSmartCallback(CHANGED_CALLBACK_NAME,
181                                          &Impl::CheckCallback,
182                                          this,
183                                          static_cast<void*>(NULL));
184         evas_object_show(check);
185         m_createdObjects.push_back(check);
186     }
187
188     void DoRender(const PopupObject::Button& object,
189             EvasObject &parent)
190     {
191         EvasObject btn(elm_button_add(parent));
192
193         elm_object_text_set(btn, object.getLabel().c_str());
194         elm_object_part_content_set(parent, POPUP_PART_BUTTON1, btn);
195         btn.ConnectMemberSmartCallback(BUTTON_CLICKED_CALLBACK_NAME,
196                                        &Impl::ButtonCallback,
197                                        this,
198                                        reinterpret_cast<void*>(object.getLabelId()));
199         m_createdObjects.push_back(btn);
200     }
201
202     void DoRender(const PopupObject::Button& object1,
203             const PopupObject::Button& object2,
204             EvasObject &parent)
205     {
206         EvasObject btn1(elm_button_add(parent));
207         EvasObject btn2(elm_button_add(parent));
208
209         elm_object_text_set(btn1, object1.getLabel().c_str());
210         elm_object_part_content_set(parent, POPUP_PART_BUTTON1, btn1);
211         btn1.ConnectMemberSmartCallback(BUTTON_CLICKED_CALLBACK_NAME,
212                                         &Impl::ButtonCallback,
213                                         this,
214                                         reinterpret_cast<void*>(object1.getLabelId()));
215
216         elm_object_text_set(btn2, object2.getLabel().c_str());
217         elm_object_part_content_set(parent, POPUP_PART_BUTTON2, btn2);
218         btn2.ConnectMemberSmartCallback(BUTTON_CLICKED_CALLBACK_NAME,
219                                         &Impl::ButtonCallback,
220                                         this,
221                                         reinterpret_cast<void*>(object2.getLabelId()));
222         m_createdObjects.push_back(btn1);
223         m_createdObjects.push_back(btn2);
224     }
225
226     void DoRender(const PopupObject::Button& object1,
227             const PopupObject::Button& object2,
228             const PopupObject::Button& object3,
229             EvasObject &parent)
230     {
231         EvasObject btn1(elm_button_add(parent));
232         EvasObject btn2(elm_button_add(parent));
233         EvasObject btn3(elm_button_add(parent));
234
235         elm_object_text_set(btn1, object1.getLabel().c_str());
236         elm_object_part_content_set(parent, POPUP_PART_BUTTON1, btn1);
237         btn1.ConnectMemberSmartCallback(BUTTON_CLICKED_CALLBACK_NAME,
238                                         &Impl::ButtonCallback,
239                                         this,
240                                         reinterpret_cast<void*>(object1.getLabelId()));
241
242         elm_object_text_set(btn2, object2.getLabel().c_str());
243         elm_object_part_content_set(parent, POPUP_PART_BUTTON2, btn2);
244         btn2.ConnectMemberSmartCallback(BUTTON_CLICKED_CALLBACK_NAME,
245                                         &Impl::ButtonCallback,
246                                         this,
247                                         reinterpret_cast<void*>(object2.getLabelId()));
248
249         elm_object_text_set(btn3, object3.getLabel().c_str());
250         elm_object_part_content_set(parent, POPUP_PART_BUTTON3, btn3);
251         btn3.ConnectMemberSmartCallback(BUTTON_CLICKED_CALLBACK_NAME,
252                                         &Impl::ButtonCallback,
253                                         this,
254                                         reinterpret_cast<void*>(object3.getLabelId()));
255         m_createdObjects.push_back(btn1);
256         m_createdObjects.push_back(btn2);
257         m_createdObjects.push_back(btn3);
258     }
259
260     EvasObject getBaseObject()
261     {
262         if (getExternalCanvas() == NULL) {
263             LogInfo("Create old style popup");
264             EvasObject win(elm_win_add(NULL, "Popup", ELM_WIN_DIALOG_BASIC));
265             elm_win_borderless_set(win, EINA_TRUE);
266             elm_win_alpha_set(win, EINA_TRUE);
267             elm_win_raise(win);
268             {
269                 int w, h, x, y;
270                 ecore_x_window_geometry_get(ecore_x_window_root_first_get(),
271                                             &x,
272                                             &y,
273                                             &w,
274                                             &h);
275                 evas_object_resize(win, w, h);
276                 evas_object_move(win, x, y);
277             }
278             m_createdObjects.push_back(win);
279             evas_object_show(win);
280             return win;
281         } else {
282             LogInfo("Create new style popup");
283             EvasObject win(getExternalCanvas());
284             evas_object_show(win);
285             return win;
286         }
287     }
288
289     void DoRender()
290     {
291         if (!m_current && !m_popupsToRender.empty()) {
292             m_current = m_popupsToRender.front();
293             m_popupsToRender.pop();
294
295             m_themeIndexV = 0;
296
297             // preprocessing
298             std::vector<int> countPopupObjects = {0 /* PopupObject::BUTTON */,
299                                                   0 /* PopupObject::LABEL */,
300                                                   0 /* PopupObject::CHECK */};
301             FOREACH(it, m_current->GetPopupObjects()) {
302                 Assert((*it)->getType() < countPopupObjects.size() &&
303                     "Wrong PopupObject assigned");
304                 countPopupObjects[(*it)->getType()]++;
305             }
306             int needsIndexV = countPopupObjects[PopupObject::LABEL] +
307                 countPopupObjects[PopupObject::CHECK];
308
309             EvasObject win = getBaseObject();
310             EvasObject main(elm_popup_add(win));
311
312             evas_object_size_hint_weight_set(main,
313                                              EVAS_HINT_EXPAND,
314                                              EVAS_HINT_EXPAND);
315             elm_object_part_text_set(main,
316                                      POPUP_PART_TITLE,
317                                      m_current->GetTitle().c_str());
318
319             m_createdObjects.push_back(main);
320             std::vector<PopupObject::Button> buttonObjectList;
321             EvasObject layout(create_layout_main(main, needsIndexV));
322             m_createdObjects.push_back(layout);
323
324             FOREACH(it, m_current->GetPopupObjects()) {
325                 switch ((*it)->getType()) {
326                 case PopupObject::BUTTON:
327                     buttonObjectList.push_back(*(*it)->asButton());
328                     break;
329                 case PopupObject::LABEL:
330                     DoRender(*(*it)->asLabel(),
331                              main,
332                              layout,
333                              m_themeIndexV++);
334                     break;
335                 case PopupObject::CHECK:
336                     DoRender(*(*it)->asCheck(),
337                              main,
338                              layout,
339                              m_themeIndexV++);
340                     break;
341                 default:
342                     Assert("incorrect type");
343                 }
344                 Assert(m_themeIndexV <= MAX_NUMBER_OF_VERTICAL);
345             }
346             elm_object_content_set(main,
347                                    layout);
348
349             // show buution
350             switch(buttonObjectList.size()) {
351             case 0:
352                 LogInfo("no button");
353                 break;
354             case 1:
355                 DoRender(buttonObjectList.at(0),
356                          main);
357                 break;
358             case 2:
359                 DoRender(buttonObjectList.at(0),
360                          buttonObjectList.at(1),
361                          main);
362                 break;
363             case 3:
364                 DoRender(buttonObjectList.at(0),
365                          buttonObjectList.at(1),
366                          buttonObjectList.at(2),
367                          main);
368                 break;
369             default:
370                 Assert("incorrect button number");
371                 break;
372             }
373
374             evas_object_show(main);
375         }
376     }
377
378     void setExternalCanvas(void* externalCanvas)
379     {
380         m_externalCanvas = static_cast<Evas_Object*>(externalCanvas);
381     }
382
383     Evas_Object* getExternalCanvas() const
384     {
385         return m_externalCanvas;
386     }
387
388     std::queue<PopupPtr> m_popupsToRender;
389     std::list<EvasObject> m_createdObjects;
390     PopupPtr m_current;
391     bool m_initialized;
392     bool m_checkState;
393     DPL::Optional<std::string> m_password;
394     unsigned int m_themeIndexV;
395
396   private:
397     Evas_Object* m_externalCanvas;
398 };
399
400 PopupRenderer::PopupRenderer()
401 {
402     m_impl = new PopupRenderer::Impl();
403 }
404
405 PopupRenderer::~PopupRenderer()
406 {
407     delete m_impl;
408 }
409
410 void PopupRenderer::Initialize()
411 {
412     Assert(m_impl);
413     m_impl->Initialize();
414 }
415
416 void PopupRenderer::Deinitialize()
417 {
418     Assert(m_impl);
419     m_impl->Deinitialize();
420 }
421
422 IPopupPtr PopupRenderer::CreatePopup()
423 {
424     return DPL::StaticPointerCast<IPopup>(IPopupPtr
425                                               (new Popup(SharedFromThis())));
426 }
427
428 void PopupRenderer::Render(PopupPtr popup)
429 {
430     m_impl->Render(popup);
431 }
432
433 void PopupRenderer::setExternalCanvas(void* externalCanvas)
434 {
435     m_impl->setExternalCanvas(externalCanvas);
436 }
437
438 } // namespace Popup
439 } // namespace DPL