[WRTjs] Refactor popup
[platform/framework/web/chromium-efl.git] / wrt / src / browser / popup.cc
1 /*
2  * Copyright (c) 2019 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 #include "wrt/src/browser/popup.h"
18
19 #include <vector>
20
21 #include "base/logging.h"
22 #include "tizen_src/chromium_impl/tizen/system_info.h"
23 #include "wrt/src/browser/popup_string.h"
24 #include "wrt/src/common/constants.h"
25
26 #if BUILDFLAG(IS_TIZEN_TV)
27 #include "wrt/src/browser/tv/popup_tv.h"
28 #endif
29
30 namespace wrt {
31
32 namespace {
33
34 const char* kContentButton1 = "button1";
35 const char* kContentButton2 = "button2";
36 const char* kContentText = nullptr;
37 const char* kContentTitle = "title,text";
38 const char* kStateActivated = "activated";
39 const char* kStateClicked = "clicked";
40 const char* kSignalEdit = "elm,action,hide,search_icon";
41 const char* kStyleButton = "popup";
42 const char* kStyleButtonLeft = "popup";
43 const char* kStyleButtonRight = "popup";
44 const char* kStyleCheck = "multiline";
45 const char* kStyleEditPw = "editfield/password/popup";
46 const char* kStyleLabel = "popup/default";
47 const char* kStylePopup = "default";
48 const char* kWRTEdjePath = "/usr/share/edje/wrtjs/wrtjs_tizen.edj";
49
50 static Evas_Object* AddCheckBox(Evas_Object* parent, const std::string& style) {
51   Evas_Object* check = elm_check_add(parent);
52   elm_object_style_set(check, style.c_str());
53   evas_object_size_hint_align_set(check, EVAS_HINT_FILL, EVAS_HINT_FILL);
54   elm_check_state_set(check, EINA_FALSE);
55   return check;
56 }
57
58 }  // namespace
59
60 // static
61 std::vector<std::unique_ptr<Popup>> Popup::opened_popups_;
62
63 // static
64 std::unique_ptr<Popup> Popup::CreatePopup(Evas_Object* window) {
65 #if BUILDFLAG(IS_TIZEN_TV)
66   return PopupTV::CreatePopup(window);
67 #endif
68
69   Evas_Object* popup = elm_popup_add(window);
70
71   elm_popup_align_set(popup, ELM_NOTIFY_ALIGN_FILL, 1.0);
72   evas_object_size_hint_weight_set(popup, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
73   elm_object_style_set(popup, kStylePopup);
74
75   Evas_Object* box = elm_box_add(popup);
76   elm_box_padding_set(box, 0, 10);
77   evas_object_size_hint_weight_set(box, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
78   evas_object_size_hint_align_set(box, EVAS_HINT_FILL, EVAS_HINT_FILL);
79   elm_object_part_content_set(popup, "default", box);
80   evas_object_show(box);
81
82   evas_object_event_callback_add(
83       popup, EVAS_CALLBACK_RESIZE, nullptr, nullptr);
84
85   auto* instance = new Popup(popup, box);
86   return std::unique_ptr<Popup>(instance);
87 }
88
89 // static
90 void Popup::Show(std::unique_ptr<Popup> popup) {
91   if (popup)
92     popup->ShowInternal(std::move(popup));
93 }
94
95 // static
96 void Popup::ForceCloseAllPopup() {
97   for (auto& popup : opened_popups_) {
98     // will cause modification of opened_popups_
99     popup->Hide();
100   }
101   opened_popups_.clear();
102 }
103
104 Popup::Popup(Evas_Object* popup, Evas_Object* box) : popup_(popup), box_(box) {}
105
106 Popup::~Popup() {
107   if (popup_) {
108     evas_object_del(popup_);
109     popup_ = nullptr;
110   }
111 }
112
113 void Popup::ShowInternal(std::unique_ptr<Popup> popup) {
114   evas_object_show(popup->popup_);
115   opened_popups_.push_back(std::move(popup));
116 }
117
118 void Popup::SetButtonType(ButtonType type) {
119   switch (type) {
120     case ButtonType::OkButton:
121       button1_ = AddButton(popup_string::kPopupButtonOk,
122                            kContentButton1, kStyleButton);
123       break;
124     case ButtonType::OkCancelButton:
125       button1_ = AddButton(popup_string::kPopupButtonCancel,
126                            kContentButton1, kStyleButtonLeft);
127       button2_ = AddButton(popup_string::kPopupButtonOk,
128                            kContentButton2, kStyleButtonRight);
129       break;
130     case ButtonType::LoginCancelButton:
131       button1_ = AddButton(popup_string::kPopupButtonCancel,
132                            kContentButton1, kStyleButtonLeft);
133       button2_ = AddButton(popup_string::kPopupButtonLogin,
134                            kContentButton2, kStyleButtonRight);
135       break;
136     case ButtonType::AllowDenyButton:
137       button1_ = AddButton(popup_string::kPopupButtonDeny,
138                            kContentButton1, kStyleButtonLeft);
139       button2_ = AddButton(popup_string::kPopupButtonAllow,
140                            kContentButton2, kStyleButtonRight);
141       break;
142   }
143 }
144
145 Evas_Object* Popup::AddButton(const char* id, const char* content,
146                               const char* button_style) {
147   Evas_Object* button = elm_button_add(popup_);
148   elm_object_style_set(button, button_style);
149   elm_object_domain_translatable_part_text_set(
150       button, 0, kTextDomainRuntime, id);
151   elm_object_part_content_set(popup_, content, button);
152
153   auto callback = [](void* data, Evas_Object* button, void* /*eventInfo*/) {
154     for (auto iterator = opened_popups_.begin();
155          iterator != opened_popups_.end(); ++iterator) {
156       if (iterator->get() == data) {
157         std::unique_ptr<Popup> popup(iterator->release());
158         opened_popups_.erase(iterator);
159         popup->HandleButtonClickEvent(button);
160         return;
161       }
162     }
163     LOG(ERROR) << "Fail to get Popup instance";
164   };
165   evas_object_smart_callback_add(button, kStateClicked, callback, this);
166   return button;
167 }
168
169 void Popup::SetFirstEntry(const std::string& id, EntryType type) {
170   entry1_ = AddEntry(id.c_str(), type);
171 }
172
173 void Popup::SetSecondEntry(const std::string& id, EntryType type) {
174   if (!entry1_) {
175     LOG(ERROR) << "SetFirstEntry() is not called yet";
176     return;
177   }
178   entry2_ = AddEntry(id.c_str(), type);
179 }
180
181 Evas_Object* Popup::AddEntry(const char* id, Popup::EntryType type) {
182   Evas_Object* entry = elm_entry_add(box_);
183   elm_object_style_set(entry, kStyleEditPw);
184   elm_entry_single_line_set(entry, EINA_TRUE);
185   elm_entry_scrollable_set(entry, EINA_TRUE);
186   evas_object_size_hint_weight_set(entry, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
187   evas_object_size_hint_align_set(entry, EVAS_HINT_FILL, EVAS_HINT_FILL);
188   elm_entry_prediction_allow_set(entry, EINA_FALSE);
189   elm_object_signal_emit(entry, kSignalEdit, "");
190   elm_entry_autocapital_type_set(entry, ELM_AUTOCAPITAL_TYPE_NONE);
191
192   if (type == Popup::EntryType::Edit) {
193     evas_object_smart_callback_add(entry, kStateActivated,
194                                    [](void*, Evas_Object* obj, void*) {
195                                      elm_object_focus_set(obj, EINA_TRUE);
196                                    }, nullptr);
197   } else {
198     elm_entry_password_set(entry, EINA_TRUE);
199     elm_entry_input_panel_layout_set(entry, ELM_INPUT_PANEL_LAYOUT_PASSWORD);
200   }
201   evas_object_show(entry);
202
203   Evas_Object* layout = elm_layout_add(box_);
204   if (edjeFilePath_.empty())
205     edjeFilePath_ = kWRTEdjePath;
206   elm_layout_file_set(layout, edjeFilePath_.c_str(), "PopupTextEntrySet");
207
208   Evas_Object* rectangle = evas_object_rectangle_add(
209                                evas_object_evas_get(layout));
210   evas_object_color_set(rectangle, 0, 0, 0, 0);
211   evas_object_resize(rectangle, 100, 100);
212   evas_object_size_hint_min_set(rectangle, 100, 100);
213   evas_object_show(rectangle);
214   elm_object_part_content_set(layout, "entry.rectangle", rectangle);
215   evas_object_size_hint_weight_set(layout, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
216   evas_object_size_hint_align_set(layout, EVAS_HINT_FILL, EVAS_HINT_FILL);
217   elm_object_domain_translatable_part_text_set(
218       layout, "entry.text", kTextDomainRuntime, id);
219   elm_layout_content_set(layout, "entry.swallow", entry);
220
221   evas_object_show(layout);
222   elm_box_pack_end(box_, layout);
223
224   return entry;
225 }
226
227 void Popup::SetCheckBox(const std::string& id) {
228   if (checkStyle_.empty())
229     checkStyle_ = kStyleCheck;
230   check_box_ = AddCheckBox(box_, checkStyle_);
231   if (!id.empty()) {
232     elm_object_domain_translatable_part_text_set(
233         check_box_, kContentText,
234         kTextDomainRuntime,
235         id.c_str());
236   }
237   evas_object_size_hint_padding_set(check_box_, 20, 20, 0, 10);
238   elm_box_pack_end(box_, check_box_);
239   evas_object_show(check_box_);
240 }
241
242 void Popup::SetTitle(const std::string& id) {
243   elm_object_domain_translatable_part_text_set(
244       popup_, kContentTitle, kTextDomainRuntime, id.c_str());
245 }
246
247 void Popup::SetBody(const std::string& id) {
248   Evas_Object* label = elm_label_add(box_);
249   elm_object_style_set(label, kStyleLabel);
250   elm_label_line_wrap_set(label, ELM_WRAP_MIXED);
251   elm_object_domain_translatable_part_text_set(
252                                    label, kContentText, kTextDomainRuntime,
253                                    elm_entry_utf8_to_markup(id.c_str()));
254   evas_object_size_hint_weight_set(label, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
255   evas_object_size_hint_align_set(label, EVAS_HINT_FILL, EVAS_HINT_FILL);
256 #if BUILDFLAG(IS_TIZEN_TV)
257   evas_object_color_set(label, 255, 255, 255, 255);
258 #else
259   evas_object_color_set(label, 0, 0, 0, 255);
260 #endif
261   elm_box_pack_end(box_, label);
262   evas_object_show(label);
263 }
264
265 void Popup::SetResultHandler(ResultHandler handler) {
266   handler_ = std::move(handler);
267 }
268
269 void Popup::Hide() {
270   evas_object_hide(popup_);
271 }
272
273 void Popup::HandleButtonClickEvent(Evas_Object* button) {
274   Hide();
275
276   bool is_positive = false;
277   if (button1_)
278     is_positive = (button && (!button2_ || button == button2_));
279
280   std::string entry1;
281   std::string entry2;
282   if (entry1_) {
283     const char* text = elm_entry_entry_get(entry1_);
284     if (text)
285       entry1 = text;
286     if (entry2_) {
287       text = elm_entry_entry_get(entry2_);
288       if (text)
289         entry2 = text;
290     }
291   }
292
293   bool is_checked = false;
294   if (check_box_)
295     is_checked = elm_check_state_get(check_box_);
296
297   std::move(handler_).Run(is_positive, is_checked, entry1, entry2);
298 }
299
300 }  // namespace wrt