OSDN Git Service

51cb937b4eef735e521f025ee4a5f637bfd7b652
[mmo/main.git] / client / ui / InputBox.cpp
1 //
2 // InputBox.cpp
3 //
4
5 #include "InputBox.hpp"
6 #include "../CardManager.hpp"
7 #include "../../common/Logger.hpp"
8 #include "../../common/unicode.hpp"
9
10 const size_t InputBox::HISTORY_MAX_SIZE = 50;
11
12 const int InputBox::DEFAULT_MAX_WIDTH = 600;
13
14 const int InputBox::TAB_TOP_MARGIN = 7;
15 const int InputBox::TAB_SIDE_MARGIN = 30;
16 const int InputBox::TAB_X_MARGIN = 15;
17 const int InputBox::MESSAGE_TOP_MARGIN = 30;
18
19 const int InputBox::BOX_MIN_WIDTH = 200;
20 const int InputBox::BOX_TOP_MARGIN = 36;
21 const int InputBox::BOX_BOTTOM_MARGIN = 16;
22 const int InputBox::BOX_SIDE_MARGIN = 6;
23
24 const int InputBox::KEY_REPEAT_FRAME = 6;
25
26 const int InputBox::INPUT_MARGIN_X = 8;
27 const int InputBox::INPUT_MARGIN_Y = 6;
28
29 const int InputBox::IME_BLOCK_SIZE = 32;
30 const int InputBox::IME_MARGIN_BASE = 12;
31 const int InputBox::IME_MARGIN_Y = 16;
32 const int InputBox::IME_MAX_PAGE_SIZE = 6;
33 const int InputBox::IME_MIN_WIDTH = 120;
34
35 InputBox::InputBox(const ManagerAccessorPtr& manager_accessor) :
36                 multiline_(true),
37                 font_height_(ResourceManager::default_font_size()),
38                 drag_offset_x_(-1),
39                 drag_offset_y_(-1),
40                 drag_resize_offset_x_(-1),
41                 drag_resize_offset_y_(-1),
42                 min_input_height_(font_height_ + INPUT_MARGIN_Y * 2),
43                 selecting_tab_index_(0),
44                 manager_accessor_(manager_accessor),
45                 card_(std::make_shared<Card>(manager_accessor_, "", "immo", "", "",
46                             std::vector<std::string>())),
47                                 input_()
48
49 {
50         absolute_rect_ = Rect(100, 100, 800, 100);
51
52     font_handle_ = ResourceManager::default_font_handle();
53     bg_image_handle_ = ResourceManager::LoadCachedDivGraph<4>(
54             _T("system/images/gui/gui_inputbox_bg.png"), 2, 2, 24, 24);
55     tab_bg_image_handle_ = ResourceManager::LoadCachedDivGraph<4>(
56             _T("system/images/gui/gui_inputbox_tab_bg.png"), 2, 2, 12, 12);
57     tab_bg_inactive_image_handle_ = ResourceManager::LoadCachedDivGraph<4>(
58             _T("system/images/gui/gui_inputbox_tab_inactive_bg.png"), 2, 2, 12, 12);
59     ime_image_handle_ = ResourceManager::LoadCachedDivGraph<4>(
60             _T("system/images/gui/gui_inputbox_ime_bg.png"), 2, 2, 12, 12);
61
62     script_icon_image_handle_ = ResourceManager::LoadCachedGraph(_T("system/images/gui/gui_inputbox_tab_script_icon.png"));
63
64     int screen_width, screen_height;
65     GetScreenState(&screen_width, &screen_height, nullptr);
66     absolute_rect_.width = std::min(DEFAULT_MAX_WIDTH + 0, (int)(screen_width * 0.4));
67     absolute_rect_.height = input_.height() + BOX_TOP_MARGIN + BOX_BOTTOM_MARGIN;
68     absolute_rect_.x = (screen_width - absolute_rect_.width) / 2;
69     absolute_rect_.y = screen_height - absolute_rect_.height - BOX_BOTTOM_MARGIN;
70
71     selecting_tab_index_ = 0;
72
73     Activate();
74     if (auto card_manager = manager_accessor_->card_manager().lock()) {
75         card_manager->AddCard(card_);
76     }
77
78     input_.set_on_enter([this](const std::string& text) -> bool{
79
80         if (input_.text().empty()) {
81             input_.set_active(false);
82         } else {
83             if (selecting_tab_index_ == -1) {
84                 card_->Execute(unicode::ToString(input_.text()), "mmo",
85                         [&](const v8::Handle<v8::Value>& result, const std::string& error){
86                     if (error.size() > 0) {
87                         script_tab_.message = unicode::ToTString(error);
88                     } else if (!result.IsEmpty()) {
89                         script_tab_.message = _T("=> ") +
90                             unicode::ToTString(std::string(*String::Utf8Value(result->ToString())));
91                     } else {
92                         script_tab_.message = _T("");
93                     }
94                     input_.set_message(script_tab_.message);
95                 });
96             } else if (!tabs_.empty()) {
97                 if (auto card =
98                         tabs_.at(selecting_tab_index_).card.lock()) {
99                     card->onEnter(unicode::ToString(input_.text()));
100                 }
101             }
102         }
103
104         return true;
105     });
106 }
107
108 InputBox::~InputBox()
109 {
110
111 }
112
113 void InputBox::DrawTabs()
114 {
115
116     {
117         int tab_index = 0;
118         SetDrawArea(absolute_rect_.x, script_tab_.y, script_tab_.x, script_tab_.y + script_tab_.height);
119         BOOST_FOREACH(auto& tab, tabs_) {
120
121             std::array<ImageHandlePtr, 4>* image_handle;
122             if (selecting_tab_index_ == tab_index) {
123                 image_handle = &tab_bg_image_handle_;
124             } else {
125                 image_handle = &tab_bg_inactive_image_handle_;
126             }
127             int tab_x = tab.x;
128             int tab_y = tab.y;
129             int tab_width = tab.width;
130             int tab_height = tab.height;
131
132             DrawGraph(tab_x, tab_y, *(*image_handle)[0], TRUE);
133             DrawGraph(tab_x + tab_width - 12, tab_y, *(*image_handle)[1], TRUE);
134             DrawGraph(tab_x, tab_y + tab_height - 12, *(*image_handle)[2], TRUE);
135             DrawGraph(tab_x + tab_width - 12, tab_y + tab_height - 12,
136                     *(*image_handle)[3], TRUE);
137
138             DrawRectExtendGraphF(tab_x + 12, tab_y, tab_x + tab_width - 12,
139                     tab_y + 12, 0, 0, 1, 12, *(*image_handle)[1], TRUE);
140
141             DrawRectExtendGraphF(tab_x + 12, tab_y + tab_height - 12,
142                     tab_x + tab_width - 12, tab_y + tab_height, 0, 0, 1, 12,
143                     *(*image_handle)[3], TRUE);
144
145             DrawRectExtendGraphF(tab_x, tab_y + 12, tab_x + 12,
146                     tab_y + tab_height - 12, 0, 0, 12, 1, *(*image_handle)[2],
147                     TRUE);
148
149             DrawRectExtendGraphF(tab_x + tab_width - 12, tab_y + 12,
150                     tab_x + tab_width, tab_y + tab_height - 12, 0, 0, 12, 1,
151                     *(*image_handle)[3], TRUE);
152
153             DrawRectExtendGraphF(tab_x + 12, tab_y + 12, tab_x + tab_width - 12,
154                     tab_y + tab_height - 12, 0, 0, 1, 1, *(*image_handle)[3],
155                     TRUE);
156
157             SetDrawBlendMode(DX_BLENDMODE_ALPHA, 100);
158             DrawStringToHandle(tab_x + 9, absolute_rect_.y + TAB_TOP_MARGIN + 1, unicode::ToTString(tab.name).c_str(),
159                     GetColor(255, 255, 255), font_handle_);
160             SetDrawBlendMode(DX_BLENDMODE_NOBLEND, 0);
161
162             DrawStringToHandle(tab_x + 9, absolute_rect_.y + TAB_TOP_MARGIN, unicode::ToTString(tab.name).c_str(),
163                     GetColor(0, 0, 0), font_handle_);
164
165             tab_index++;
166         }
167         SetDrawAreaFull();
168     }
169
170     {
171         SetDrawBright(210, 47, 47);
172         // スクリプトタブ
173         int tab_x = script_tab_.x;
174         int tab_y = script_tab_.y;
175         int tab_width = script_tab_.width;
176         int tab_height = script_tab_.height;
177
178         std::array<ImageHandlePtr, 4>* image_handle;
179         if (IsScriptMode()) {
180             image_handle = &tab_bg_image_handle_;
181         } else {
182             image_handle = &tab_bg_inactive_image_handle_;
183         }
184
185         DrawGraph(tab_x, tab_y, *(*image_handle)[0], TRUE);
186         DrawGraph(tab_x + tab_width - 12, tab_y, *(*image_handle)[1], TRUE);
187         DrawGraph(tab_x, tab_y + tab_height - 12, *(*image_handle)[2], TRUE);
188         DrawGraph(tab_x + tab_width - 12, tab_y + tab_height - 12,
189                 *(*image_handle)[3], TRUE);
190
191         DrawRectExtendGraphF(tab_x + 12, tab_y, tab_x + tab_width - 12,
192                 tab_y + 12, 0, 0, 1, 12, *(*image_handle)[1], TRUE);
193
194         DrawRectExtendGraphF(tab_x + 12, tab_y + tab_height - 12,
195                 tab_x + tab_width - 12, tab_y + tab_height, 0, 0, 1, 12,
196                 *(*image_handle)[3], TRUE);
197
198         DrawRectExtendGraphF(tab_x, tab_y + 12, tab_x + 12,
199                 tab_y + tab_height - 12, 0, 0, 12, 1, *(*image_handle)[2], TRUE);
200
201         DrawRectExtendGraphF(tab_x + tab_width - 12, tab_y + 12,
202                 tab_x + tab_width, tab_y + tab_height - 12, 0, 0, 12, 1,
203                 *(*image_handle)[3], TRUE);
204
205         DrawRectExtendGraphF(tab_x + 12, tab_y + 12, tab_x + tab_width - 12,
206                 tab_y + tab_height - 12, 0, 0, 1, 1, *(*image_handle)[3], TRUE);
207
208         SetDrawBright(255, 255, 255);
209
210         DrawGraph(absolute_rect_.x + absolute_rect_.width - TAB_SIDE_MARGIN - 16, absolute_rect_.y + TAB_TOP_MARGIN,
211                 *script_icon_image_handle_, TRUE);
212     }
213 }
214
215 void InputBox::DrawBase()
216 {
217     if (IsActive()) {
218         SetDrawBlendMode(DX_BLENDMODE_ADD, 255);
219     } else {
220         SetDrawBlendMode(DX_BLENDMODE_ADD, 150);
221     }
222
223     DrawGraph(absolute_rect_.x, absolute_rect_.y, *bg_image_handle_[0], TRUE);
224     DrawGraph(absolute_rect_.x + absolute_rect_.width - 24, absolute_rect_.y, *bg_image_handle_[1], TRUE);
225     DrawGraph(absolute_rect_.x, absolute_rect_.y + absolute_rect_.height - 24, *bg_image_handle_[2], TRUE);
226     DrawGraph(absolute_rect_.x + absolute_rect_.width - 24, absolute_rect_.y + absolute_rect_.height - 24, *bg_image_handle_[3], TRUE);
227
228     DrawRectExtendGraphF(absolute_rect_.x + 24, absolute_rect_.y,
229                          absolute_rect_.x + absolute_rect_.width - 24, absolute_rect_.y + 24,
230                          0, 0, 1, 24, *bg_image_handle_[1], TRUE);
231
232     DrawRectExtendGraphF(absolute_rect_.x + 24, absolute_rect_.y + absolute_rect_.height - 24,
233                          absolute_rect_.x + absolute_rect_.width - 24, absolute_rect_.y + absolute_rect_.height,
234                          0, 0, 1, 24, *bg_image_handle_[3], TRUE);
235
236     DrawRectExtendGraphF(absolute_rect_.x, absolute_rect_.y + 24,
237                          absolute_rect_.x + 24, absolute_rect_.y + absolute_rect_.height - 24,
238                          0, 0, 24, 1, *bg_image_handle_[2], TRUE);
239
240     DrawRectExtendGraphF(absolute_rect_.x + absolute_rect_.width - 24, absolute_rect_.y + 24,
241                          absolute_rect_.x + absolute_rect_.width, absolute_rect_.y + absolute_rect_.height - 24,
242                          0, 0, 24, 1, *bg_image_handle_[3], TRUE);
243
244     DrawRectExtendGraphF(absolute_rect_.x +  24, absolute_rect_.y + 24,
245                          absolute_rect_.x + absolute_rect_.width - 24, absolute_rect_.y + absolute_rect_.height - 24,
246                          0, 0, 1, 1, *bg_image_handle_[3], TRUE);
247
248     SetDrawBlendMode(DX_BLENDMODE_NOBLEND, 0);
249 }
250
251 void InputBox::Draw()
252 {
253     DrawBase();
254     DrawTabs();
255     input_.Draw();
256 }
257
258 int InputBox::multiline() const
259 {
260     return multiline_;
261 }
262
263 void InputBox::set_multiline(int multiline)
264 {
265     multiline_ = multiline;
266 }
267
268 void InputBox::CancelSelect()
269 {
270     input_.CancelSelect();
271 }
272
273 bool InputBox::IsScriptMode()
274 {
275     return selecting_tab_index_ == -1;
276 }
277
278 void InputBox::SetScriptMode()
279 {
280     SwitchTab(-1);
281 }
282
283 void InputBox::SwitchTab(int index)
284 {
285     if (selecting_tab_index_ == -1) {
286         script_tab_.text = GetInputString();
287     } else if (!tabs_.empty()) {
288         tabs_.at(selecting_tab_index_).text = GetInputString();
289     }
290
291     selecting_tab_index_ = index;
292
293     if (selecting_tab_index_ == -1) {
294         SetInputString(script_tab_.text);
295         input_.set_message(script_tab_.message);
296         input_.set_reverse_color(true);
297     } else if (!tabs_.empty()) {
298         SetInputString(tabs_.at(selecting_tab_index_).text);
299         input_.set_message(tabs_.at(selecting_tab_index_).message);
300         input_.set_reverse_color(false);
301     }
302 }
303
304 tstring InputBox::GetInputString() const {
305     return input_.text();
306 }
307
308 void InputBox::SetInputString(const tstring& text)
309 {
310     input_.set_text(text);
311 }
312
313 void InputBox::ProcessInput(InputManager* input)
314 {
315     if (!input) {
316         return;
317     }
318
319     bool push_mouse_left = (input->GetMouseLeftCount() > 0);
320
321     bool first_key_shift = (input->GetKeyCount(KEY_INPUT_RSHIFT) == 1
322             || input->GetKeyCount(KEY_INPUT_LSHIFT) == 1);
323         
324     bool push_key_esc = input->GetKeyCount(KEY_INPUT_ESCAPE) > 0;
325
326     bool push_key_shift = (input->GetKeyCount(KEY_INPUT_RSHIFT) > 0
327             || input->GetKeyCount(KEY_INPUT_LSHIFT) > 0);
328
329     bool push_key_v = (input->GetKeyCount(KEY_INPUT_V) > 0);
330     bool push_key_ctrl = (input->GetKeyCount(KEY_INPUT_LCONTROL) > 0
331             || input->GetKeyCount(KEY_INPUT_RCONTROL) > 0);
332
333     bool first_key_return = (input->GetKeyCount(KEY_INPUT_RETURN) == 1);
334
335     bool push_repeat_key_return = (input->GetKeyCount(KEY_INPUT_RETURN)
336             + KEY_REPEAT_FRAME) % (KEY_REPEAT_FRAME + 1) == 0;
337     bool push_repeat_key_up = (input->GetKeyCount(KEY_INPUT_UP)
338             + KEY_REPEAT_FRAME) % (KEY_REPEAT_FRAME + 1) == 0;
339     bool push_repeat_key_down = (input->GetKeyCount(KEY_INPUT_DOWN)
340             + KEY_REPEAT_FRAME) % (KEY_REPEAT_FRAME + 1) == 0;
341     bool push_long_backspace = (input->GetKeyCount(KEY_INPUT_BACK) > 60 * 1.5);
342
343     bool empty = input_.text().empty();
344     input_.ProcessInput(input);
345
346     if (IsActive() && ((first_key_return && !push_key_shift && empty) || push_key_esc)) {
347         Inactivate();
348     } else if (!IsActive() && first_key_return) {
349         Activate();
350     } else if (!IsActive() && push_key_v && push_key_ctrl) {
351         Activate();
352     }
353         
354     ProcessInputTabs(input);
355     UpdateBase(input);
356     UpdateTabs();
357
358
359     int new_height = input_.height() + BOX_TOP_MARGIN + BOX_BOTTOM_MARGIN;
360
361     int screen_height;
362     GetScreenState(nullptr, &screen_height, nullptr);
363     if (absolute_rect_.y + absolute_rect_.height > screen_height - BOX_TOP_MARGIN) {
364         absolute_rect_.y -= new_height - absolute_rect_.height;
365         // input_.set_y(y_ + BOX_TOP_MARGIN);
366     }
367
368     absolute_rect_.height = new_height;
369         
370     input_.set_y(absolute_rect_.y + BOX_TOP_MARGIN);
371     input_.set_x(absolute_rect_.x + INPUT_MARGIN_X);
372     input_.set_width(absolute_rect_.width - INPUT_MARGIN_X * 2);
373
374         //line_buffer.clear();
375         //line_width = 0;
376
377         //if (push_key_shift && (push_repeat_key_up || push_repeat_key_down)) {
378         //    SetKeyInputSelectArea(GetKeyInputCursorPosition(input_handle_),
379         //            prev_cursor_pos_, input_handle_);
380         //}
381
382     //}
383
384     if (IsActive()) {
385         input->CancelKeyCountAll();
386     }
387 }
388
389 void InputBox::Update()
390 {
391     input_.Update();
392 }
393
394 void InputBox::ReloadTabs()
395 {
396     tabs_.clear();
397     if (auto card_manager = manager_accessor_->card_manager().lock()) {
398         auto card_list = card_manager->cards();
399         int tab_offset_x = 0;
400         for (auto it = card_list.begin(); it != card_list.end(); ++it) {
401             auto card = *it;
402             if (card->HasInputEvent()) {
403                 InputBox::Tab tab;
404                 tab.card = card;
405                 tab.name = unicode::ToTString(card->name());
406
407                 tab.x = absolute_rect_.x + TAB_SIDE_MARGIN + tab_offset_x - 9;
408                 tab.y = absolute_rect_.y - 3;
409                 tab.height = font_height_ + TAB_TOP_MARGIN * 2 + 3 * 2;
410
411                 auto name = unicode::ToTString(tab.name);
412                 tab.width = GetDrawStringWidthToHandle(name.c_str(), name.size(),
413                         font_handle_) + 18;
414
415                 tab_offset_x += tab.width + TAB_X_MARGIN;
416
417                 tabs_.push_back(tab);
418             }
419         }
420     }
421 }
422
423 void InputBox::ProcessInputTabs(InputManager* input)
424 {
425     if (input->GetMouseLeftCount() == 1) {
426         int tab_index = 0;
427
428         for (auto it = tabs_.begin(); it != tabs_.end(); ++it) {
429             auto tab = *it;
430
431             bool tab_hover = (tab.x <= input->GetMouseX()
432                     && input->GetMouseX() <= tab.x + tab.width
433                     && tab.y <= input->GetMouseY()
434                     && input->GetMouseY() <= tab.y + tab.height);
435
436             if (tab_hover) {
437                 SwitchTab(tab_index);
438             }
439
440             tab_index++;
441         }
442
443         {
444             bool tab_hover = (script_tab_.x <= input->GetMouseX()
445                     && input->GetMouseX() <= script_tab_.x + script_tab_.width
446                     && script_tab_.y <= input->GetMouseY()
447                     && input->GetMouseY() <= script_tab_.y + script_tab_.height);
448
449             if (tab_hover) {
450                 SetScriptMode();
451             }
452         }
453     }
454 }
455
456 void InputBox::UpdateTabs()
457 {
458     // スクリプトモードショートカット
459     // if (input->GetKeyCount(InputManager::KEYBIND_SCRIPT_MODE) == 1) {
460     //    SetScriptMode();
461     // }
462
463     // タブ選択
464     int tab_offset_x = 0;
465     BOOST_FOREACH(auto& tab, tabs_) {
466         tab.x = absolute_rect_.x + TAB_SIDE_MARGIN + tab_offset_x - 9;
467         tab.y = absolute_rect_.y - 3;
468         tab.height = font_height_ + TAB_TOP_MARGIN * 2 + 3 * 2;
469
470         auto name = unicode::ToTString(tab.name);
471         tab.width = GetDrawStringWidthToHandle(name.c_str(), name.size(),
472                 font_handle_) + 18;
473
474         tab_offset_x += tab.width - 3;
475     }
476
477     script_tab_.x = absolute_rect_.x + absolute_rect_.width - TAB_SIDE_MARGIN - 16 - 9;
478     script_tab_.y = absolute_rect_.y - 3;
479     script_tab_.width = 16 + 18;
480     script_tab_.height = font_height_ + TAB_TOP_MARGIN * 2 + 3 * 2;
481 }
482
483
484 void InputBox::UpdateBase(InputManager* input)
485 {
486     int screen_width, screen_height;
487     GetScreenState(&screen_width, &screen_height, nullptr);
488
489     bool hover = (absolute_rect_.x <= input->GetMouseX() && input->GetMouseX() <= absolute_rect_.x + absolute_rect_.width
490             && absolute_rect_.y <= input->GetMouseY() && input->GetMouseY() <= absolute_rect_.y + absolute_rect_.height);
491
492     //bool input_hover = (input_x_ <= input->GetMouseX()
493     //        && input->GetMouseX() <= input_x_ + input_width_
494     //        && input_y_ <= input->GetMouseY()
495     //        && input->GetMouseY() <= input_y_ + input_height_);
496
497     bool corner_hover = (absolute_rect_.x + absolute_rect_.width - 18 <= input->GetMouseX()
498             && input->GetMouseX() <= absolute_rect_.x + absolute_rect_.width
499             && absolute_rect_.y + absolute_rect_.height - 18 <= input->GetMouseY()
500             && input->GetMouseY() <= absolute_rect_.y + absolute_rect_.height);
501
502     // ドラッグ処理
503     if (input->GetMouseLeft()) {
504         if (input->GetPrevMouseLeft() == 0 && drag_offset_x_ < 0 && hover
505                  && !corner_hover) {
506             drag_offset_x_ = input->GetMouseX() - absolute_rect_.x;
507             drag_offset_y_ = input->GetMouseY() - absolute_rect_.y;
508         }
509         if (input->GetPrevMouseLeft() == 0 && drag_resize_offset_x_ < 0
510                 && corner_hover) {
511             drag_resize_offset_x_ = absolute_rect_.x + absolute_rect_.width - input->GetMouseX();
512             drag_resize_offset_y_ = absolute_rect_.y + absolute_rect_.height - input->GetMouseY();
513         }
514         if (hover && !IsActive()) {
515             Activate();
516         } else if (!hover && IsActive()
517                 && (drag_offset_x_ < 0 && drag_resize_offset_x_ < 0)) {
518             Inactivate();
519         }
520     } else {
521         drag_offset_x_ = -1;
522         drag_offset_y_ = -1;
523         drag_resize_offset_x_ = -1;
524         drag_resize_offset_y_ = -1;
525     }
526
527     if (drag_offset_x_ >= 0) {
528         absolute_rect_.x = input->GetMouseX() - drag_offset_x_;
529         absolute_rect_.y = input->GetMouseY() - drag_offset_y_;
530         absolute_rect_.x = std::max(0, absolute_rect_.x); absolute_rect_.x = std::min(screen_width - absolute_rect_.width, absolute_rect_.x);
531         absolute_rect_.y = std::max(0, absolute_rect_.y); absolute_rect_.y = std::min(screen_height - absolute_rect_.height, absolute_rect_.y);
532         input->CancelMouseLeft();
533     } else if (drag_resize_offset_x_ >= 0) {
534         int new_width = input->GetMouseX() - absolute_rect_.x + drag_resize_offset_x_;
535         new_width = std::max(new_width, (BOX_MIN_WIDTH + 0));
536         new_width = std::min(new_width, screen_width - absolute_rect_.x);
537         absolute_rect_.width = new_width;
538         input->CancelMouseLeft();
539     }
540 }
541
542
543 bool InputBox::IsActive()
544 {
545     return input_.active();
546 }
547
548 void InputBox::Activate()
549 {
550     input_.set_active(true);
551 }
552
553 void InputBox::Inactivate()
554 {
555     input_.set_active(false);
556 }