1// Aseprite UI Library
2// Copyright (C) 2019 Igara Studio S.A.
3// Copyright (C) 2001-2016 David Capello
4//
5// This file is released under the terms of the MIT license.
6// Read LICENSE.txt for more information.
7
8#ifdef HAVE_CONFIG_H
9#include "config.h"
10#endif
11
12#include "ui/textbox.h"
13
14#include "gfx/size.h"
15#include "ui/intern.h"
16#include "ui/message.h"
17#include "ui/size_hint_event.h"
18#include "ui/system.h"
19#include "ui/theme.h"
20#include "ui/view.h"
21
22#include <algorithm>
23
24namespace ui {
25
26TextBox::TextBox(const std::string& text, int align)
27 : Widget(kTextBoxWidget)
28{
29 setFocusStop(true);
30 setAlign(align);
31 setText(text);
32 initTheme();
33}
34
35bool TextBox::onProcessMessage(Message* msg)
36{
37 switch (msg->type()) {
38
39 case kKeyDownMessage:
40 if (hasFocus()) {
41 View* view = View::getView(this);
42 if (view) {
43 gfx::Rect vp = view->viewportBounds();
44 gfx::Point scroll = view->viewScroll();
45 int textheight = textHeight();
46
47 switch (static_cast<KeyMessage*>(msg)->scancode()) {
48
49 case kKeyLeft:
50 scroll.x -= vp.w/2;
51 view->setViewScroll(scroll);
52 break;
53
54 case kKeyRight:
55 scroll.x += vp.w/2;
56 view->setViewScroll(scroll);
57 break;
58
59 case kKeyUp:
60 scroll.y -= vp.h/2;
61 view->setViewScroll(scroll);
62 break;
63
64 case kKeyDown:
65 scroll.y += vp.h/2;
66 view->setViewScroll(scroll);
67 break;
68
69 case kKeyPageUp:
70 scroll.y -= (vp.h-textheight);
71 view->setViewScroll(scroll);
72 break;
73
74 case kKeyPageDown:
75 scroll.y += (vp.h-textheight);
76 view->setViewScroll(scroll);
77 break;
78
79 case kKeyHome:
80 scroll.y = 0;
81 view->setViewScroll(scroll);
82 break;
83
84 case kKeyEnd:
85 scroll.y = bounds().h - vp.h;
86 view->setViewScroll(scroll);
87 break;
88
89 default:
90 return Widget::onProcessMessage(msg);
91 }
92 }
93 return true;
94 }
95 break;
96
97 case kMouseDownMessage: {
98 View* view = View::getView(this);
99 if (view) {
100 captureMouse();
101 m_oldPos = static_cast<MouseMessage*>(msg)->position();
102 set_mouse_cursor(kScrollCursor);
103 return true;
104 }
105 break;
106 }
107
108 case kMouseMoveMessage: {
109 View* view = View::getView(this);
110 if (view && hasCapture()) {
111 gfx::Point scroll = view->viewScroll();
112 gfx::Point newPos = static_cast<MouseMessage*>(msg)->position();
113
114 scroll += m_oldPos - newPos;
115 view->setViewScroll(scroll);
116
117 m_oldPos = newPos;
118 }
119 break;
120 }
121
122 case kMouseUpMessage: {
123 View* view = View::getView(this);
124 if (view && hasCapture()) {
125 releaseMouse();
126 set_mouse_cursor(kArrowCursor);
127 return true;
128 }
129 break;
130 }
131
132 case kMouseWheelMessage: {
133 View* view = View::getView(this);
134 if (view) {
135 auto mouseMsg = static_cast<MouseMessage*>(msg);
136 gfx::Point scroll = view->viewScroll();
137
138 if (mouseMsg->preciseWheel())
139 scroll += mouseMsg->wheelDelta();
140 else
141 scroll += mouseMsg->wheelDelta() * textHeight()*3;
142
143 view->setViewScroll(scroll);
144 }
145 break;
146 }
147 }
148
149 return Widget::onProcessMessage(msg);
150}
151
152void TextBox::onPaint(PaintEvent& ev)
153{
154 theme()->paintTextBox(ev);
155}
156
157void TextBox::onSizeHint(SizeHintEvent& ev)
158{
159 int w = 0;
160 int h = 0;
161
162 Theme::drawTextBox(nullptr, this, &w, &h, gfx::ColorNone, gfx::ColorNone);
163
164 if (this->align() & WORDWRAP) {
165 View* view = View::getView(this);
166 int width, min = w;
167
168 if (view) {
169 width = view->viewportBounds().w;
170 }
171 else {
172 width = bounds().w;
173 }
174
175 w = std::max(min, width);
176 Theme::drawTextBox(nullptr, this, &w, &h, gfx::ColorNone, gfx::ColorNone);
177
178 w = min;
179 }
180
181 ev.setSizeHint(gfx::Size(w, h));
182}
183
184void TextBox::onSetText()
185{
186 View* view = View::getView(this);
187 if (view)
188 view->updateView();
189
190 Widget::onSetText();
191}
192
193} // namespace ui
194