0
|
1 /*
|
|
2 * Copyright (c) 2004-2006 Kazunori "jagarl" Ueno
|
|
3 * All rights reserved.
|
|
4 *
|
|
5 * Redistribution and use in source and binary forms, with or without
|
|
6 * modification, are permitted provided that the following conditions
|
|
7 * are met:
|
|
8 * 1. Redistributions of source code must retain the above copyright
|
|
9 * notice, this list of conditions and the following disclaimer.
|
|
10 * 2. Redistributions in binary form must reproduce the above copyright
|
|
11 * notice, this list of conditions and the following disclaimer in the
|
|
12 * documentation and/or other materials provided with the distribution.
|
|
13 * 3. The name of the author may not be used to endorse or promote products
|
|
14 * derived from this software without specific prior written permission.
|
|
15 *
|
|
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
|
17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
|
18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
|
19 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
|
20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
|
21 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
22 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
23 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
|
25 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
26 */
|
|
27
|
|
28 #include"widget.h"
|
|
29 #include<algorithm>
|
|
30 #include<map>
|
|
31 #include<string>
|
|
32
|
|
33 Rect DSurfaceRenderText(TextGlyphStream::iterator start, TextGlyphStream::iterator end, const Rect& srcrect,
|
|
34 Surface* dst, const Rect& dstrect);
|
|
35 void DSurfaceFill(Surface* src, const Rect& rect, int r, int g, int b, int a = 0xff);
|
|
36 void DSurfaceMove(Surface* src, const Rect& srcrect, Surface* dst_o, const Rect& dstrect);
|
|
37
|
|
38 //static char* wdefault_font_orig = "msgothic.ttc;times.ttf;";
|
|
39 static std::map<int, XKFont::HorizLayout*> size_to_layout;
|
|
40 static char* wdefault_font_orig = "times.ttf;msgothic.ttc";
|
|
41 static std::string wdefault_font = wdefault_font_orig;
|
|
42
|
|
43 void SetFont(const char* font) {
|
|
44 if (font == 0) return;
|
|
45 std::map<int,XKFont::HorizLayout*>::iterator it;
|
|
46 for (it=size_to_layout.begin(); it != size_to_layout.end(); it++) {
|
|
47 delete it->second;
|
|
48 }
|
|
49 size_to_layout.clear();
|
|
50 wdefault_font = font;
|
|
51 }
|
|
52 // namespace Widget {
|
|
53 #define TimeCursor WidTimeCursor
|
|
54 #define MouseCursor WidMouseCursor
|
|
55 #define Button WidButton
|
|
56 #define Scale WidScale
|
|
57 #define TextButton WidTextButton
|
|
58 #define Text WidText
|
|
59 #define AnmTime WidAnmTime
|
|
60 #define AnmMove WidAnmMove
|
|
61 #define AnmAlpha WidAnmAlpha
|
|
62 #define AnmPtnSolid WidAnmPtnSolid
|
|
63 #define AnmPtnAlpha WidAnmPtnAlpha
|
|
64
|
|
65 XKFont::HorizLayout* DefaultLayout(int text_size) {
|
|
66 if (size_to_layout.find(text_size) == size_to_layout.end()) {
|
|
67 size_to_layout[text_size] = new XKFont::HorizLayout(wdefault_font.c_str(), text_size);
|
|
68 }
|
|
69 return size_to_layout[text_size];
|
|
70 }
|
|
71
|
|
72 void PicWidget::activate(void) {
|
|
73 }
|
|
74 void PicWidget::deactivate(void) {
|
|
75 }
|
|
76 void PicWidget::SetRegion(const Rect& apos) {
|
|
77 }
|
|
78 void PicWidget::show(void) {
|
|
79 Pic()->show();
|
|
80 }
|
|
81 void PicWidget::hide(void) {
|
|
82 Pic()->hide();
|
|
83 }
|
|
84 void PicWidget::show_all(void) {
|
|
85 Pic()->show_all();
|
|
86 }
|
|
87
|
|
88 TimeCursor::TimeCursor(Event::Container& container, int _interval, PicContainer* parent, const char* s, int _sx, int _sy, int _sdx, int _sdy, int _nptn, const Rect& r) :
|
|
89 Time(container) {
|
|
90 interval = _interval;
|
|
91 if (interval < 0) interval = 100;
|
|
92 nptn = _nptn;
|
|
93 if (nptn < 0) nptn = 1;
|
|
94 count = 0; old_time = 0;
|
|
95
|
|
96 x = _sx; y = _sy; dx = _sdx; dy = _sdy;
|
|
97 SetPic(parent->create_leaf(r, PicBase::CACHE_BACK));
|
|
98 Pic()->SetSurface(s, _sx, _sy);
|
|
99 };
|
|
100 void TimeCursor::Elapsed(unsigned int current_time) {
|
|
101 int move = (current_time-old_time)/interval;
|
|
102 if (move) {
|
|
103 old_time += move*interval;
|
|
104 count += move;
|
|
105 count %= nptn;
|
|
106 Pic()->SetSurfacePos(x + count*dx, y + count*dy);
|
|
107 }
|
|
108 if (current_time > old_time+interval) SetWakeup(current_time);
|
|
109 else SetWakeup(old_time+interval);
|
|
110 }
|
|
111
|
|
112 MouseCursor::MouseCursor(Event::Container& _container, PicContainer* parent, const char* s, int x, int y, int w, int h) :
|
|
113 Event::Video(_container), container(_container) {
|
|
114 int sx, sy;
|
|
115 _container.MousePos(sx, sy);
|
|
116 SetPic(parent->create_leaf(Rect(sx, sy, sx+w, sy+h), 0));
|
|
117 Pic()->SetSurface(s, x, y);
|
|
118 x = 0; y = 0;
|
|
119 container.RegisterGlobalMotionFunc(&Motionfunc, (void*)this);
|
|
120 }
|
|
121 MouseCursor::MouseCursor(Event::Container& _container, PicContainer* parent, Surface* s, int x, int y, int w, int h) :
|
|
122 Event::Video(_container), container(_container) {
|
|
123 int sx, sy;
|
|
124 _container.MousePos(sx, sy);
|
|
125 SetPic(parent->create_leaf(Rect(sx, sy, sx+w, sy+h), 0));
|
|
126 Pic()->SetSurface(s, x, y);
|
|
127 x = 0; y = 0;
|
|
128 container.RegisterGlobalMotionFunc(&Motionfunc, (void*)this);
|
|
129 }
|
|
130
|
|
131 MouseCursor::~MouseCursor() {
|
|
132 container.DeleteGlobalMotionFunc(&Motionfunc, (void*)this);
|
|
133 }
|
|
134
|
|
135 bool MouseCursor::Motionfunc(int x, int y, void* pointer) {
|
|
136 MouseCursor* _this = (MouseCursor*)pointer;
|
|
137 // 左上がカーソルポイントの場合
|
|
138 // _this->Pic()->Move(x,y);
|
|
139 // 左下がカーソルポイントの場合
|
|
140 _this->Pic()->Move(x,y-_this->Pic()->Height());
|
|
141 return true;
|
|
142 }
|
|
143
|
|
144 Button::Button(Event::Container& container, PicContainer* parent, const char* s, int _sx, int _sy, int _sdx, int _sdy, int _nptn, const Rect& r, int _z) : sx(_sx), sy(_sy), sdx(_sdx), sdy(_sdy), nptn(_nptn) ,Event::Video(container,r, _z) {
|
|
145 SetPic(parent->create_leaf(r, 0));
|
|
146 Pic()->SetSurface(s, _sx, _sy);
|
|
147 show();
|
|
148 is_in = false;
|
|
149 is_toggled = false;
|
|
150 press_func = 0;
|
|
151 press_pointer = 0;
|
|
152 drag_func = 0;
|
|
153 drag_pointer = 0;
|
|
154 is_toggle_switch = false;
|
|
155 }
|
|
156 Button::Button(Event::Container& container, PicContainer* parent, Surface* s, int _sx, int _sy, int _sdx, int _sdy, int _nptn, const Rect& r, int _z) : sx(_sx), sy(_sy), sdx(_sdx), sdy(_sdy), nptn(_nptn) ,Event::Video(container,r, _z) {
|
|
157 SetPic(parent->create_leaf(r, 0));
|
|
158 Pic()->SetSurface(s, _sx, _sy);
|
|
159 show();
|
|
160 is_in = false;
|
|
161 is_toggled = false;
|
|
162 press_func = 0;
|
|
163 press_pointer = 0;
|
|
164 drag_func = 0;
|
|
165 drag_pointer = 0;
|
|
166 is_toggle_switch = false;
|
|
167 }
|
|
168 Button::~Button() {
|
|
169 }
|
|
170 void Button::In(void) {
|
|
171 is_in = true;
|
|
172 if (nptn > 1)
|
|
173 if (! is_toggled)
|
|
174 Pic()->SetSurfacePos(sx+sdx, sy+sdy);
|
|
175 }
|
|
176 void Button::Out(void) {
|
|
177 is_in = false;
|
|
178 if (!is_toggled)
|
|
179 Pic()->SetSurfacePos(sx, sy);
|
|
180 }
|
|
181 void Button::Toggle(bool new_toggle) {
|
|
182 if (is_toggled == new_toggle) {
|
|
183 return;
|
|
184 }
|
|
185 is_toggled = new_toggle;
|
|
186 // if (is_in) return; // is_in に関わらずウィジットの表示を変更することにする
|
|
187 if (is_toggled) {
|
|
188 if (nptn > 2)
|
|
189 Pic()->SetSurfacePos(sx+sdx*2, sy+sdy*2);
|
|
190 else if (nptn > 1)
|
|
191 Pic()->SetSurfacePos(sx+sdx, sy+sdy);
|
|
192 else
|
|
193 Pic()->SetSurfacePos(sx, sy);
|
|
194 } else {
|
|
195 Pic()->SetSurfacePos(sx, sy);
|
|
196 }
|
|
197 }
|
|
198 void Button::Press(void) {
|
|
199 is_in = true;
|
|
200 if (is_toggled) ;
|
|
201 else if (nptn > 2)
|
|
202 Pic()->SetSurfacePos(sx+sdx*2, sy+sdy*2);
|
|
203 else if (nptn > 1)
|
|
204 Pic()->SetSurfacePos(sx+sdx, sy+sdy);
|
|
205 if (press_func) press_func(press_pointer, this);
|
|
206 if (is_toggle_switch) Toggle(!is_toggled);
|
|
207 }
|
|
208 void Button::Release(void) {
|
|
209 if (is_toggled) ;
|
|
210 else if (nptn > 1 && is_in)
|
|
211 Pic()->SetSurfacePos(sx+sdx, sy+sdy);
|
|
212 else if (nptn > 1)
|
|
213 Pic()->SetSurfacePos(sx, sy);
|
|
214 }
|
|
215 void Button::Drag(int x_from, int y_from, int x_to, int y_to) {
|
|
216 if (drag_func) drag_func(x_from,y_from,x_to, y_to,drag_pointer, this);
|
|
217 }
|
|
218
|
|
219 Scale::Scale(Event::Container& _container, PicContainer* _parent, const Rect& r_orig, const Color& _color, bool _is_vertical) :
|
|
220 Event::Video(_container,Rect(0,0), 1),
|
|
221 container(_container), parent(_parent), cursor_color(_color),
|
|
222 mouse_x(0), mouse_y(0), max(0), min(0),
|
|
223 value(0), value_add(0), value_dragstart(0), is_vertical(_is_vertical),
|
|
224 change_func(0), change_pointer(0) {
|
|
225
|
|
226 arrow_down = 0;
|
|
227 arrow_up = 0;
|
|
228 cursor = 0;
|
|
229 panel = 0;
|
|
230
|
|
231 Init(r_orig);
|
|
232 }
|
|
233
|
|
234 extern char* create_button(int number, int& width, int& height, int r, int g, int b);
|
|
235 extern char* create_box(int& width, int& height, int r, int g, int b);
|
|
236 void Scale::Init(Rect r_orig) {
|
|
237 int r=cursor_color.r, g=cursor_color.g, b=cursor_color.b;
|
|
238 // 矢印
|
|
239 int arrow_width = -1;
|
|
240 cursor_width = -1;
|
|
241 char* button1;
|
|
242 char* button2;
|
|
243 if (is_vertical) {
|
|
244 // 矢印に必要な領域確保
|
|
245 int arrow_height = r_orig.width();
|
|
246 button1 = create_button(2, arrow_height, arrow_width, r, g, b);
|
|
247 button2 = create_button(3, arrow_height, arrow_width, r, g, b);
|
|
248 if (r_orig.height() < arrow_width*4) {
|
|
249 if (r_orig.height() < 8) r_orig.by = r_orig.ty + 8; // 小さすぎる場合は強制変更
|
|
250 free( (void*)button1);
|
|
251 free( (void*)button2);
|
|
252 arrow_width = r_orig.height()/4;
|
|
253 // 再割り当て
|
|
254 button1 = create_button(2, arrow_height, arrow_width, r, g, b);
|
|
255 button2 = create_button(3, arrow_height, arrow_width, r, g, b);
|
|
256 }
|
|
257 // 矢印ボタンの作成
|
|
258 Surface* a1s = parent->Root().NewSurfaceFromRGBAData(arrow_height, arrow_width*3, button1, ALPHA_MASK);
|
|
259 int x = r_orig.lx; int y = r_orig.ty;
|
|
260 arrow_up = new Button(container, parent, a1s, 0, 0, 0, arrow_width, 3, Rect(x,y,x+arrow_height,y+arrow_width),1);
|
|
261 arrow_up->Pic()->SetSurfaceFreeFlag();
|
|
262 Surface* a2s = parent->Root().NewSurfaceFromRGBAData(arrow_height, arrow_width*3, button2, ALPHA_MASK);
|
|
263 x = r_orig.rx - arrow_height; y = r_orig.by - arrow_width;
|
|
264 arrow_down = new Button(container, parent, a2s, 0, 0, 0, arrow_width, 3, Rect(x,y,x+arrow_height,y+arrow_width),1);
|
|
265 arrow_down->Pic()->SetSurfaceFreeFlag();
|
|
266 // picture作成(ボタンの動く領域)
|
|
267 Rect r = r_orig;
|
|
268 r.ty += arrow_width;
|
|
269 r.by -= arrow_width;
|
|
270 panel = parent->create_node(r, 0);
|
|
271 SetPic(panel);
|
|
272 // ボタンの中心線を描画、設定
|
|
273 Surface* s = parent->Root().NewSurface(r.width()/2, r.height(), ALPHA_MASK);
|
|
274 DSurfaceFill(s, Rect(0,0,r.width()/2,r.height()), 0, 0, 0, 0xff);
|
|
275 Pic()->SetSurface(s, -r.width()/4, 0, 0);
|
|
276 Pic()->SetSurfaceFreeFlag();
|
|
277 } else {
|
|
278 // 矢印に必要な領域確保
|
|
279 int arrow_height = r_orig.height();
|
|
280 button1 = create_button(0, arrow_width, arrow_height, r, g, b);
|
|
281 button2 = create_button(1, arrow_width, arrow_height, r, g, b);
|
|
282 if (r_orig.width() < arrow_width*4) {
|
|
283 if (r_orig.width() < 8) r_orig.rx = r_orig.lx + 8; // 小さすぎる場合は強制変更
|
|
284 free( (void*)button1);
|
|
285 free( (void*)button2);
|
|
286 arrow_width = r_orig.width()/4;
|
|
287 // 再割り当て
|
|
288 button1 = create_button(2, arrow_width, arrow_height, r, g, b);
|
|
289 button2 = create_button(3, arrow_width, arrow_height, r, g, b);
|
|
290 }
|
|
291 // 矢印ボタンの作成
|
|
292 Surface* a1s = parent->Root().NewSurfaceFromRGBAData(arrow_width, arrow_height*3, button1, ALPHA_MASK);
|
|
293 int x = r_orig.lx; int y = r_orig.ty;
|
|
294 arrow_up = new Button(container, parent, a1s, 0, 0, 0, arrow_height, 3, Rect(x,y,x+arrow_width,y+arrow_height),1);
|
|
295 arrow_up->Pic()->SetSurfaceFreeFlag();
|
|
296 Surface* a2s = parent->Root().NewSurfaceFromRGBAData(arrow_width, arrow_height*3, button2, ALPHA_MASK);
|
|
297 x = r_orig.rx - arrow_width; y = r_orig.by - arrow_height;
|
|
298 arrow_down = new Button(container, parent, a2s, 0, 0, 0, arrow_height, 3, Rect(x,y,x+arrow_width,y+arrow_height),1);
|
|
299 arrow_down->Pic()->SetSurfaceFreeFlag();
|
|
300 // picture作成(ボタンの動く領域)
|
|
301 Rect r = r_orig;
|
|
302 r.lx += arrow_width;
|
|
303 r.rx -= arrow_width;
|
|
304 panel = parent->create_node(r, 0);
|
|
305 SetPic(panel);
|
|
306 // ボタンの中心線を描画、設定
|
|
307 Surface* s = parent->Root().NewSurface(r.width(), r.height()/2, ALPHA_MASK);
|
|
308 DSurfaceFill(s, Rect(0,0,r.width(),r.height()/2), 0, 0, 0, 0xff);
|
|
309 Pic()->SetSurface(s, 0, -r.height()/4, 0);
|
|
310 Pic()->SetSurfaceFreeFlag();
|
|
311 }
|
|
312 arrow_up->press_func = &Scale::PressArrowUp;
|
|
313 arrow_up->press_pointer = (void*)this;
|
|
314 arrow_down->press_func = &Scale::PressArrowDown;
|
|
315 arrow_down->press_pointer = (void*)this;
|
|
316 arrow_up->show();
|
|
317 arrow_down->show();
|
|
318 panel->show();
|
|
319 InitCursor(0);
|
|
320 }
|
|
321
|
|
322 void Scale::InitCursor(int width_ratio) {
|
|
323 int r=cursor_color.r, g=cursor_color.g, b=cursor_color.b;
|
|
324 if (cursor) delete cursor;
|
|
325 cursor = 0;
|
|
326 Rect region(0,0);
|
|
327 if (width_ratio < 0) width_ratio = 0;
|
|
328 else if (width_ratio > 1024) width_ratio = 1024;
|
|
329 if (is_vertical) {
|
|
330 if (width_ratio == 0) cursor_width = Pic()->Width() * 3 / 2; // 幅の1.5倍
|
|
331 else cursor_width = Pic()->Height()*width_ratio/1024;
|
|
332 if (cursor_width <= 0) return; // カーソルなし(いいのか?)
|
|
333 region = Rect(0, 0, Pic()->Width(), cursor_width);
|
|
334 } else { // horizontal
|
|
335 if (width_ratio == 0) cursor_width = Pic()->Height() * 3 / 2; // 高さの1.5倍
|
|
336 else cursor_width = Pic()->Width()*width_ratio/1024;
|
|
337 if (cursor_width <= 0) return; // カーソルなし(いいのか?)
|
|
338 region = Rect(0, 0, cursor_width, Pic()->Height());
|
|
339 }
|
|
340
|
|
341 int height = region.height();
|
|
342 int width = region.width();
|
|
343 char* box = create_box(width, height, r, g, b);
|
|
344 Surface* boxs = parent->Root().NewSurfaceFromRGBAData(width, height*3, box, ALPHA_MASK);
|
|
345 cursor = new Button(container, panel, boxs, 0, 0, 0, height, 3, region, 2);
|
|
346 cursor->Pic()->SetSurfaceFreeFlag();
|
|
347
|
|
348 cursor->press_func = &Scale::PressCursor;
|
|
349 cursor->press_pointer = (void*)this;
|
|
350 cursor->drag_func = &Scale::DragCursor;
|
|
351 cursor->drag_pointer = (void*)this;
|
|
352 cursor->show();
|
|
353
|
|
354 // 矢印等をクリックしたときの移動量計算
|
|
355 int bar_width;
|
|
356 if (is_vertical) bar_width = Pic()->Height();
|
|
357 else bar_width = Pic()->Width();
|
|
358 if (bar_width <= 0) value_add = max-min;
|
|
359 else if (cursor_width == 0) value_add = 2;
|
|
360 else value_add = scale_max*cursor_width/bar_width;
|
|
361
|
|
362 return;
|
|
363 }
|
|
364
|
|
365 void Scale::PressArrowDown(void* pointer, Button* from) {
|
|
366 Scale* self = (Scale*)pointer;
|
|
367 self->SetScaleValue(self->value + self->value_add);
|
|
368 }
|
|
369 void Scale::PressArrowUp(void* pointer, Button* from){
|
|
370 Scale* self = (Scale*)pointer;
|
|
371 self->SetScaleValue(self->value - self->value_add);
|
|
372 }
|
|
373 void Scale::PressCursor(void* pointer, Button* from){
|
|
374 Scale* self = (Scale*)pointer;
|
|
375 self->value_dragstart = self->value;
|
|
376 }
|
|
377 void Scale::DragCursor(int x_from, int y_from,int x, int y, void* pointer, Button* from){
|
|
378 Scale* self = (Scale*)pointer;
|
|
379 int dx, w;
|
|
380 if (self->is_vertical) {
|
|
381 dx = y-y_from;
|
|
382 w = self->Event::Video::Region().height();
|
|
383 } else {
|
|
384 dx = x-x_from;
|
|
385 w = self->Event::Video::Region().width();
|
|
386 }
|
|
387 if (w == 0) return;
|
|
388 self->SetScaleValue(self->value_dragstart + dx*scale_max/w);
|
|
389 }
|
|
390 int Scale::CalcValue(void) {
|
|
391 Rect own_region = Event::Video::Region();
|
|
392 int x, w;
|
|
393 if (is_vertical) {
|
|
394 w = own_region.height();
|
|
395 x = mouse_y - own_region.ty;
|
|
396 } else {
|
|
397 w = own_region.width();
|
|
398 x = mouse_x - own_region.lx;
|
|
399 }
|
|
400 if (w == 0) return 0;
|
|
401 if (x < 0) x = 0;
|
|
402 else if (x > w) x = w;
|
|
403 return x*scale_max/w;
|
|
404 }
|
|
405 void Scale::Press(void){
|
|
406 int v = CalcValue();
|
|
407 if (v < value) SetScaleValue(value-value_add);
|
|
408 else SetScaleValue(value+value_add);
|
|
409 return;
|
|
410 }
|
|
411 void Scale::Motion(int x, int y){
|
|
412 mouse_x = x;
|
|
413 mouse_y = y;
|
|
414 }
|
|
415
|
|
416 void Scale::SetRange(int new_min, int new_max) {
|
|
417 min = new_min;
|
|
418 max = new_max;
|
|
419 SetValue(value);
|
|
420 return;
|
|
421 }
|
|
422 void Scale::SetValue(int new_value) {
|
|
423 if (min == max) {
|
|
424 value = min;
|
|
425 SetScaleValue(0);
|
|
426 return;
|
|
427 }
|
|
428 int scale_value = (new_value-min) * scale_max / (max-min);
|
|
429 SetScaleValue(scale_value);
|
|
430 }
|
|
431 int Scale::GetValue(void) const{
|
|
432 return min + value * (max-min) / scale_max;
|
|
433 }
|
|
434 void Scale::SetScaleValue(int new_value) {
|
|
435 if (new_value < 0) value = 0;
|
|
436 else if (new_value > scale_max) value = scale_max;
|
|
437 else value = new_value;
|
|
438 if (is_vertical) {
|
|
439 int h = Pic()->Height();
|
|
440 int y = (h-cursor_width) * value / scale_max;
|
|
441 if (y < 0) y = 0;
|
|
442 cursor->Pic()->Move(0, y);
|
|
443 } else { // horizontal
|
|
444 int w = Pic()->Width();
|
|
445 int x = (w-cursor_width) * value / scale_max;
|
|
446 if (x < 0) x = 0;
|
|
447 cursor->Pic()->Move(x, 0);
|
|
448 }
|
|
449 if (change_func) {
|
|
450 (*change_func)(change_pointer, this);
|
|
451 }
|
|
452 return;
|
|
453 }
|
|
454
|
|
455 TextButton::TextButton(Event::Container& container, PicContainer* parent, const char* text, int _text_size, Attribute attr, const Rect& r_orig, int _z, const Color& _fore, const Color& _pressed, const Color& _back) :
|
|
456 Button(container, parent, (Surface*)0, 0, 0, 0, 0, 0, r_orig, _z),
|
|
457 root(parent->Root()), surface(0), attribute(attr), text_size(_text_size),
|
|
458 fore(_fore), pressed(_pressed), back(_back)
|
|
459 {
|
|
460 bool rect_changed = false;
|
|
461 // まず、テキスト領域の広さを得る
|
|
462 Rect r(r_orig);
|
|
463
|
|
464 if (text == 0) text = "";
|
|
465 int width = r.width(); int height = r.height();
|
|
466 if (width == 0) width = parent->Width() - r.lx;
|
|
467
|
|
468 TextGlyphStream gs = DefaultLayout(text_size)->Layout(text, width);
|
|
469
|
|
470 if (r.width() == 0) { // 文字に合わせてウィジット作成
|
|
471 rect_changed = true;
|
|
472 width = gs.width() + text_size;
|
|
473 r.rx = r.lx + gs.width();
|
|
474 attribute = Attribute(attribute | CENTER);
|
|
475 }
|
|
476 if (r.height() == 0) {
|
|
477 rect_changed = true;
|
|
478 if (attribute & NOPADDING) r.by = r.ty + gs.height();
|
|
479 else r.by = r.ty + gs.height() + text_size/2;
|
|
480 }
|
|
481
|
|
482 if (rect_changed) {
|
|
483 // 大きさ変更
|
|
484 Pic()->SetSurfaceRect(r);
|
|
485 }
|
|
486
|
|
487 sx = 0; sy = 0; sdx = 0; sdy = r.height(); nptn = 3;
|
|
488 int x = 0, y = 0;
|
|
489 if (attribute & CENTER)
|
|
490 x = (Pic()->Width() - gs.width()) / 2;
|
|
491 y = (Pic()->Height() - gs.height()) / 2;
|
|
492
|
|
493 if (back.a == 0) { // 背景なし、もしくはボタン押の状態のみ背景あり
|
|
494 surface = root.NewSurface(r.width(), r.height()*2, ALPHA_MASK);
|
|
495 DSurfaceFill(surface, Rect(*surface), 0, 0, 0, 0);
|
|
496 if (attribute & REVERSE) {
|
|
497 DSurfaceFill(surface, Rect(0,r.height(),r.width(),r.height()*2), pressed.r, pressed.g, pressed.b, 0xff);
|
|
498 }
|
|
499 gs.SetColor(fore.r, fore.g, fore.b);
|
|
500 DSurfaceRenderText(gs.begin(), gs.end(), Rect(0,0,gs.width(),gs.height()), surface, Rect(x,y));
|
|
501 gs.SetColor(pressed.r, pressed.g, pressed.b);
|
|
502 if (attribute & REVERSE) {
|
|
503 gs.SetReverse(true);
|
|
504 DSurfaceRenderText(gs.begin(), gs.end(), Rect(0,0,gs.width(),gs.height()), surface, Rect(x,y+r.height()));
|
|
505 gs.SetReverse(false);
|
|
506 } else {
|
|
507 DSurfaceRenderText(gs.begin(), gs.end(), Rect(0,0,gs.width(),gs.height()), surface, Rect(x,y+r.height()));
|
|
508 }
|
|
509 nptn = 2;
|
|
510 } else { // ボタン型の背景あり
|
|
511 /* ラベル用の Surface を作る */
|
|
512 width = r.width(); height = r.height();
|
|
513 char* box = create_box(width, height, back.r, back.g, back.b);
|
|
514 surface = root.NewSurfaceFromRGBAData(r.width(), r.height()*3, box, ALPHA_MASK);
|
|
515
|
|
516 Surface* text_surface = root.NewSurface(r.width(), r.height(), ALPHA_MASK);
|
|
517 DSurfaceFill(text_surface, Rect(*text_surface), 0, 0, 0, 0);
|
|
518
|
|
519 gs.SetColor(fore.r, fore.g, fore.b);
|
|
520 DSurfaceRenderText(gs.begin(), gs.end(), Rect(0,0,gs.width(),gs.height()), text_surface, Rect(x,y));
|
|
521 root.BlitSurface(text_surface, Rect(0,0,width,height), surface, Rect(0,0));
|
|
522 gs.SetColor(pressed.r, pressed.g, pressed.b);
|
|
523 DSurfaceRenderText(gs.begin(), gs.end(), Rect(0,0,gs.width(),gs.height()), text_surface, Rect(x,y));
|
|
524 root.BlitSurface(text_surface, Rect(0,0,width,height), surface, Rect(0,height));
|
|
525 root.BlitSurface(text_surface, Rect(0,0,width,height), surface, Rect(0,height*2));
|
|
526 root.DeleteSurface(text_surface);
|
|
527 }
|
|
528
|
|
529 Pic()->SetSurface(surface, 0, 0);
|
|
530 show();
|
|
531 }
|
|
532 void TextButton::SetText(const char* text, const Color& _fore, const Color& _pressed, const Color& _back)
|
|
533 {
|
|
534 int width = Pic()->Width(); int height = Pic()->Height();
|
|
535 // まず、テキスト領域の広さを得る
|
|
536 if (text == 0) text = "";
|
|
537
|
|
538 TextGlyphStream gs = DefaultLayout(text_size)->Layout(text, width);
|
|
539
|
|
540 int x = 0, y = 0;
|
|
541 if (attribute & CENTER) {
|
|
542 x = (width - gs.width()) / 2;
|
|
543 y = (height - gs.height()) / 2;
|
|
544 }
|
|
545 int surf_x = Pic()->SurfacePosX();
|
|
546 int surf_y = Pic()->SurfacePosY();
|
|
547 Pic()->SetSurface( (Surface*)0,0,0);
|
|
548 root.DeleteSurface(surface);
|
|
549 surface = 0;
|
|
550
|
|
551 if (back.a == 0) { // 背景なし
|
|
552 surface = root.NewSurface(width, height*2, ALPHA_MASK);
|
|
553 DSurfaceFill(surface, Rect(*surface), 0, 0, 0, 0);
|
|
554 if (attribute & REVERSE) {
|
|
555 DSurfaceFill(surface, Rect(0,height,width,height*2), pressed.r, pressed.g, pressed.b, 0xff);
|
|
556 }
|
|
557 gs.SetColor(_fore.r, _fore.g, _fore.b);
|
|
558 DSurfaceRenderText(gs.begin(), gs.end(), Rect(0,0,gs.width(),gs.height()), surface, Rect(x,y));
|
|
559 gs.SetColor(_pressed.r, _pressed.g, _pressed.b);
|
|
560 gs.SetReverse(true);
|
|
561 DSurfaceRenderText(gs.begin(), gs.end(), Rect(0,0,gs.width(),gs.height()), surface, Rect(x,y+height));
|
|
562 gs.SetReverse(false);
|
|
563 nptn = 2;
|
|
564 } else {
|
|
565 /* ラベル用の Surface を作る */
|
|
566 char* box = create_box(width, height, _back.r, _back.g, _back.b);
|
|
567 surface = root.NewSurfaceFromRGBAData(width, height*3, box, ALPHA_MASK);
|
|
568
|
|
569 Surface* text_surface = root.NewSurface(width, height, ALPHA_MASK);
|
|
570 DSurfaceFill(text_surface, Rect(*text_surface), 0, 0, 0, 0);
|
|
571
|
|
572 gs.SetColor(_fore.r, _fore.g, _fore.b);
|
|
573 DSurfaceRenderText(gs.begin(), gs.end(), Rect(0,0,gs.width(),gs.height()), text_surface, Rect(x,y));
|
|
574 root.BlitSurface(text_surface, Rect(0,0,width,height), surface, Rect(0,0));
|
|
575 gs.SetColor(_pressed.r, _pressed.g, _pressed.b);
|
|
576 DSurfaceRenderText(gs.begin(), gs.end(), Rect(0,0,gs.width(),gs.height()), text_surface, Rect(x,y));
|
|
577 root.BlitSurface(text_surface, Rect(0,0,width,height), surface, Rect(0,height));
|
|
578 root.BlitSurface(text_surface, Rect(0,0,width,height), surface, Rect(0,height*2));
|
|
579 root.DeleteSurface(text_surface);
|
|
580 }
|
|
581
|
|
582 Pic()->SetSurface(surface, surf_x, surf_y);
|
|
583 show();
|
|
584 }
|
|
585
|
|
586 TextButton::~TextButton() {
|
|
587 if (surface) root.DeleteSurface(surface);
|
|
588 surface = 0;
|
|
589 return;
|
|
590 }
|
|
591
|
|
592 Text::Text(Event::Container& container, PicContainer* parent, const Rect& r, const Rect& text_r, int _fontsize) :
|
|
593 Event::Video(container),
|
|
594 Event::Time(container),
|
|
595 event(container),
|
|
596 srcrect(0,0,0,0),
|
|
597 layout(wdefault_font.c_str(), _fontsize), fontsize(_fontsize) {
|
|
598
|
|
599 SetPic(parent->create_node(r, 0));
|
|
600 surface = parent->Root().NewSurface(text_r.width(), text_r.height(), ALPHA_MASK);
|
|
601 pictext = PicNode()->create_leaf(text_r, PicBase::CACHE_BACK);
|
|
602 pictext->SetSurface(surface, 0, 0);
|
|
603 pictext->show();
|
|
604 cursor = 0;
|
|
605 cursor_activated = false;
|
|
606 window_activated = false;
|
|
607
|
|
608 event.RegisterGlobalPressFunc(&Pressed, (void*)this);
|
|
609
|
|
610 speed = 10;
|
|
611 wait_delay = -1;
|
|
612 status = PREPARE;
|
|
613 old_time = wait_starttime = 0;
|
|
614 }
|
|
615
|
|
616 Text::~Text() {
|
|
617 event.DeleteGlobalPressFunc(&Pressed, (void*)this);
|
|
618 PicNode()->Root().DeleteSurface(surface);
|
|
619 }
|
|
620
|
|
621 void Text::SetSpeed(int new_speed) {
|
|
622 speed = new_speed;
|
|
623 }
|
|
624 void Text::SetWait(int new_wait) {
|
|
625 if (new_wait < 0) new_wait = 100000000;
|
|
626 wait_delay = new_wait;
|
|
627 }
|
|
628
|
|
629 int Text::CalcScrollHeight(void) {
|
|
630 int i;
|
|
631 int len = bottom_pos.size();
|
|
632 int y0 = bottom_pos[line_number];
|
|
633 int height = Rect(*surface).height();
|
|
634 for (i=line_number; i<len; i++)
|
|
635 if (bottom_pos[i] - y0 > height) break;
|
|
636 if (i == line_number) i = line_number + 1;
|
|
637 return i - line_number - 1;
|
|
638 }
|
|
639 void Text::Elapsed(unsigned int current_time) {
|
|
640 SetWakeup(current_time + 50);
|
|
641 if (status == PREPARE) {
|
|
642 old_time = current_time;
|
|
643 return;
|
|
644 }
|
|
645 int nChar = speed * (current_time - old_time) / 1000;
|
|
646 if (speed == -1 || press_count) nChar = -1;
|
|
647 if (nChar == 0) return;
|
|
648 if (speed == -1) old_time = current_time;
|
|
649 else old_time += nChar * 1000 / speed;
|
|
650
|
|
651 switch(status) {
|
|
652 case WAIT: goto label_wait;
|
|
653 case SCROLL: goto label_scroll;
|
|
654 case DRAW2: goto label_draw2;
|
|
655 case WAIT2: goto label_wait2;
|
|
656 }
|
|
657
|
|
658 status = DRAW;
|
|
659 if (press_count) {
|
|
660 nChar = -1;
|
|
661 press_count = 0;
|
|
662 }
|
|
663 DrawText(nChar);
|
|
664 if (nChar == 0) return;
|
|
665 status = WAIT;
|
|
666 cursor_activated = true;
|
|
667 if (cursor_activated && window_activated && cursor) cursor->show();
|
|
668 wait_starttime = current_time;
|
|
669 label_wait:
|
|
670 if (current_time < wait_starttime + wait_delay && press_count == 0) return;
|
|
671 press_count = 0;
|
|
672 nChar = 0;
|
|
673 cursor_activated = false;
|
|
674 if (cursor) cursor->hide();
|
|
675 while(cur_pos != gstream.end()) {
|
|
676 // スクロールしては次行描画、を繰り返す
|
|
677 for (scroll_height = CalcScrollHeight(); scroll_height > 0; scroll_height--) {
|
|
678 status = SCROLL;
|
|
679 label_scroll:
|
|
680 if (press_count) break;
|
|
681 Scrollup(nChar);
|
|
682 if (nChar == 0) return;
|
|
683 status = DRAW2;
|
|
684 label_draw2:
|
|
685 if (press_count) break;
|
|
686 DrawText(nChar);
|
|
687 if (nChar == 0) return;
|
|
688 }
|
|
689 if (nChar != 0 && scroll_height) {
|
|
690 nChar = 100000;
|
|
691 if (status == SCROLL) Scrollup(nChar);
|
|
692 DrawText(nChar);
|
|
693 scroll_height--;
|
|
694 for (; scroll_height > 0; scroll_height--) {
|
|
695 Scrollup(nChar);
|
|
696 DrawText(nChar);
|
|
697 }
|
|
698 }
|
|
699 press_count = 0;
|
|
700 status = WAIT2;
|
|
701 cursor_activated = true;
|
|
702 if (cursor_activated && window_activated && cursor) cursor->show();
|
|
703 wait_starttime = current_time;
|
|
704 label_wait2:
|
|
705 if (current_time < wait_starttime + wait_delay && press_count == 0) return;
|
|
706 press_count = 0;
|
|
707 nChar = 0;
|
|
708 cursor_activated = false;
|
|
709 if (cursor) cursor->hide();
|
|
710 }
|
|
711 status = PREPARE;
|
|
712 return;
|
|
713 }
|
|
714
|
|
715 bool Text::Pressed(int x, int y, void* pointer) {
|
|
716 Text* wid = (Text*)pointer;
|
|
717 if (wid->Pic()->IsHidden()) return true;
|
|
718 wid->press_count++;
|
|
719 return true;
|
|
720 }
|
|
721
|
|
722 void Text::Clear(void) {
|
|
723 stream.container.clear();
|
|
724 DSurfaceFill(surface, Rect(*surface), 0, 0, 0, 0);
|
|
725 pictext->ReBlit();
|
|
726 status = PREPARE;
|
|
727 }
|
|
728
|
|
729 void Text::Flush(void) {
|
|
730 int nChar = -1;
|
|
731 DrawText(nChar);
|
|
732 }
|
|
733
|
|
734 void Text::Start(void) {
|
|
735 gstream.clear();
|
|
736 bottom_pos.clear();
|
|
737 layout.Layout(stream, gstream, bottom_pos, pictext->Width()-fontsize/2);
|
|
738
|
|
739 // height の積算値として bottom_pos を計算
|
|
740 std::vector<int>::iterator it;
|
|
741 int pos = 0;
|
|
742 for (it = bottom_pos.begin(); it != bottom_pos.end(); it++) {
|
|
743 pos += *it;
|
|
744 *it = pos;
|
|
745 }
|
|
746
|
|
747 cur_pos = gstream.begin();
|
|
748 line_number = 0;
|
|
749 scrolled_count = 0;
|
|
750 srcrect = Rect(0, 0, pictext->Width(), pictext->Height());
|
|
751 press_count = 0;
|
|
752
|
|
753 status = DRAW;
|
|
754 cursor_activated = false;
|
|
755 if (cursor) cursor->hide();
|
|
756 }
|
|
757
|
|
758 void Text::DrawText(int& nChar) {
|
|
759 // 描画範囲を得る
|
|
760 iterator end = gstream.end();
|
|
761 iterator it = cur_pos;
|
|
762 while(nChar && it != end) { // nChar < 0 なら出来るだけの文字を描画
|
|
763 if (! (it->flag & TextGlyph::Group)) nChar--;
|
|
764 if (it->flag & TextGlyph::LineEnd) {
|
|
765 if (bottom_pos[line_number+1] > srcrect.by) { //改行すると画面から出てしまう
|
|
766 it++;
|
|
767 if (nChar == 0) nChar = 1;
|
|
768 break;
|
|
769 }
|
|
770 line_number++;
|
|
771 }
|
|
772 it++;
|
|
773 }
|
|
774 // 描画する
|
|
775 Rect r = DSurfaceRenderText(cur_pos, it, srcrect, surface, Rect(0,0,0,0));
|
|
776 pictext->ReBlit(r);
|
|
777 cur_pos = it;
|
|
778 return;
|
|
779 }
|
|
780
|
|
781 void Text::Scrollup(int& nChar) {
|
|
782 if (nChar < 0) { // 一画面分スクロールする
|
|
783 DSurfaceFill(surface, Rect(*surface), 0, 0, 0, 0);
|
|
784 pictext->ReBlit();
|
|
785 srcrect = Rect(*surface);
|
|
786 srcrect.rmove(0, bottom_pos[line_number]);
|
|
787 line_number++;
|
|
788 scrolled_count = 0;
|
|
789 return;
|
|
790 }
|
|
791 // スクロール幅を求める
|
|
792 const int max_scroll_count = 8;
|
|
793 int dy = bottom_pos[line_number+1] - bottom_pos[line_number];
|
|
794 int cur_dy;
|
|
795 if (scrolled_count+nChar >= max_scroll_count) {
|
|
796 cur_dy = dy - (scrolled_count*dy/max_scroll_count);
|
|
797 nChar -= max_scroll_count-scrolled_count;
|
|
798 nChar++;
|
|
799 scrolled_count = 0;
|
|
800 line_number++;
|
|
801 srcrect.rmove(0, dy);
|
|
802 } else {
|
|
803 cur_dy = (scrolled_count+nChar)*dy/max_scroll_count;
|
|
804 cur_dy -=(scrolled_count*dy/max_scroll_count);
|
|
805 scrolled_count += nChar;
|
|
806 nChar = 0;
|
|
807 }
|
|
808 Rect r(*surface);
|
|
809 DSurfaceMove(surface, r, surface, Rect(0, -cur_dy, 0, 0));
|
|
810 r.ty = r.by-cur_dy;
|
|
811 DSurfaceFill(surface, r, 0, 0, 0, 0);
|
|
812 pictext->ReBlit();
|
|
813 return;
|
|
814 }
|
|
815
|
|
816 void Text::activate(void) {
|
|
817 event.RegisterGlobalPressFunc(&Pressed, (void*)this);
|
|
818 Event::Video::activate();
|
|
819 window_activated = true;
|
|
820 if (cursor_activated && window_activated && cursor) cursor->show();
|
|
821 }
|
|
822 void Text::deactivate(void) {
|
|
823 event.DeleteGlobalPressFunc(&Pressed, (void*)this);
|
|
824 Event::Video::deactivate();
|
|
825 window_activated = false;
|
|
826 if (cursor) cursor->hide();
|
|
827 }
|
|
828 void Text::SetCursor(TimeCursor* c) {
|
|
829 cursor = c;
|
|
830 if (c) {
|
|
831 if (cursor_activated && window_activated) c->show();
|
|
832 else c->hide();
|
|
833 }
|
|
834 }
|
|
835
|
|
836 Label::Label(PicContainer* parent, const Rect& r_orig, bool _is_center, const char* text, int _text_size) :
|
|
837 is_center(_is_center),
|
|
838 root(parent->Root()),
|
|
839 text_size(_text_size) {
|
|
840 Rect r(r_orig);
|
|
841
|
|
842 if (text == 0) text = "";
|
|
843 int width = r.width(); int height = r.height();
|
|
844 if (width == 0) width = parent->Width() - r.lx;
|
|
845
|
|
846 TextGlyphStream gs = DefaultLayout(text_size)->Layout(text, width);
|
|
847
|
|
848 if (r.width() == 0) { // 文字に合わせてウィジット作成
|
|
849 width = gs.width();
|
|
850 r.rx = r.lx + gs.width();
|
|
851 }
|
|
852 if (r.height() == 0) {
|
|
853 r.by = r.ty + gs.height();
|
|
854 }
|
|
855
|
|
856 SetPic(parent->create_leaf(r, 0));
|
|
857
|
|
858 /* ラベル用の Surface を作る */
|
|
859 surface = parent->Root().NewSurface(r.width(), r.height(), ALPHA_MASK);
|
|
860
|
|
861 DSurfaceFill(surface, Rect(*surface), 0, 0, 0, 0);
|
|
862 int x = 0, y = 0;
|
|
863 if (is_center) {
|
|
864 x = (Pic()->Width() - gs.width()) / 2;
|
|
865 y = (Pic()->Height() - gs.height()) / 2;
|
|
866 }
|
|
867
|
|
868 DSurfaceRenderText(gs.begin(), gs.end(), Rect(*surface), surface, Rect(x,y));
|
|
869
|
|
870 Pic()->SetSurface(surface, 0, 0);
|
|
871 show();
|
|
872 }
|
|
873 Label::~Label() {
|
|
874 root.DeleteSurface(surface);
|
|
875 }
|
|
876 void Label::SetText(const char* text) {
|
|
877 if (text == 0) text = "";
|
|
878 TextGlyphStream gs = DefaultLayout(text_size)->Layout(text, Pic()->Width());
|
|
879 DSurfaceFill(surface, Rect(*surface), 0, 0, 0, 0);
|
|
880 int x = 0, y = 0;
|
|
881 if (is_center) {
|
|
882 x = (Pic()->Width() - gs.width()) / 2;
|
|
883 y = (Pic()->Height() - gs.height()) / 2;
|
|
884 }
|
|
885
|
|
886 DSurfaceRenderText(gs.begin(), gs.end(), Rect(*surface), surface, Rect(x,y));
|
|
887 Pic()->ReBlit();
|
|
888 }
|
|
889
|
|
890 Dialog::Dialog(Event::Container& container, PicContainer* parent, const char* text, bool with_cancel) :
|
|
891 Event::Video(container) {
|
|
892
|
|
893 int x,y;
|
|
894 status = WAIT;
|
|
895 set_func = 0;
|
|
896 set_pointer = 0;
|
|
897
|
|
898 XKFont::HorizLayout& layout = *DefaultLayout(26);
|
|
899 int dialog_width = parent->Width() / 2;
|
|
900 TextGlyphStream s_ok = layout.Layout("OK", dialog_width);
|
|
901 TextGlyphStream s_cancel = layout.Layout("取消", dialog_width);
|
|
902 TextGlyphStream s_text = layout.Layout(text, dialog_width);
|
|
903
|
|
904 Rect r_text(0, 0, s_text.width(), s_text.height());
|
|
905 Rect r_ok(0, 0, s_ok.width(), s_ok.height());
|
|
906 Rect r_cancel(0, 0, s_cancel.width(), s_cancel.height());
|
|
907
|
|
908 /* ダイアログボックスの Surface を作る */
|
|
909 int dwidth = r_text.width() + (r_text.width()/10)*2 + 6;
|
|
910 int dheight = r_text.height() + r_ok.height() + r_cancel.height()*3 + 4;
|
|
911 surface_diag = parent->Root().NewSurface(dwidth, dheight, NO_MASK); // alpha なし
|
|
912 DSurfaceFill(surface_diag, Rect(*surface_diag), 0xf0, 0xd0, 0xa0);
|
|
913 DrawBox(surface_diag, Rect(0,0,dwidth,dheight));
|
|
914
|
|
915 Surface* surface_text = parent->Root().NewSurface(r_text.width(), r_text.height(), ALPHA_MASK);
|
|
916 s_text.SetColor(0x38, 0x20, 0x18);
|
|
917 DSurfaceRenderText(s_text.begin(), s_text.end(), r_text, surface_text, Rect(0, 0, 0, 0));
|
|
918 x = r_text.width()/10 + 3;
|
|
919 y = r_cancel.height()+2;
|
|
920 parent->Root().BlitSurface(surface_text, r_text, surface_diag, Rect(x, y, x+r_text.width(), y+r_text.height()));
|
|
921 parent->Root().DeleteSurface(surface_text);
|
|
922
|
|
923 /* panel をつくる */
|
|
924 x = (parent->Width()-dwidth)/2;
|
|
925 y = (parent->Height()-dheight)/2;
|
|
926 SetPic(parent->create_node(Rect(x, y, x+dwidth, y+dheight), 0));
|
|
927
|
|
928 /* ボタンを作成する */
|
|
929 /* f8d8c8 背景(明)*/
|
|
930 /* f0d0a0 背景*/
|
|
931 /* b08040 枠(明)*/
|
|
932 /* 805010 枠*/
|
|
933 /* 382018 黒*/
|
|
934 /* 9890f8 青*/
|
|
935 /* dc6448 赤*/
|
|
936 /* 各ボタンは左右にボタン幅の 1/4, 上下にボタン幅の 1/4 のマージンを持つ */
|
|
937 Rect r_btn(r_ok); r_btn.join(r_cancel);
|
|
938 int btn_width = r_btn.width() * 3 / 2;
|
|
939 int btn_height = r_btn.height() * 3 / 2;
|
|
940 surface_btn = parent->Root().NewSurface(btn_width, btn_height*4, ALPHA_MASK);
|
|
941 DSurfaceFill(surface_btn, Rect(*surface_btn), 0, 0, 0, 0);
|
|
942 s_ok.SetColor(0x38, 0x20, 0x18);
|
|
943 DSurfaceRenderText(s_ok.begin(), s_ok.end(), r_ok, surface_btn, Rect( (btn_width-r_ok.width())/2,(btn_height-r_ok.height())/2));
|
|
944 s_ok.SetColor(0x98, 0x90, 0xf8);
|
|
945 DSurfaceRenderText(s_ok.begin(), s_ok.end(), r_ok, surface_btn, Rect( (btn_width-r_ok.width())/2,(btn_height-r_ok.height())/2 + btn_height));
|
|
946 s_cancel.SetColor(0x38, 0x20, 0x18);
|
|
947 DSurfaceRenderText(s_cancel.begin(), s_cancel.end(), r_cancel, surface_btn, Rect( (btn_width-r_cancel.width())/2,(btn_height-r_cancel.height())/2 + btn_height*2));
|
|
948 s_cancel.SetColor(0xdc, 0x64, 0x48);
|
|
949 DSurfaceRenderText(s_cancel.begin(), s_cancel.end(), r_cancel, surface_btn, Rect( (btn_width-r_cancel.width())/2,(btn_height-r_cancel.height())/2 + btn_height*3));
|
|
950
|
|
951 x = (dwidth - btn_width*2) / 3;;
|
|
952 y = r_cancel.height()*3/2 + r_text.height() + 2;
|
|
953 if (!with_cancel) x = (dwidth - btn_width) / 2;
|
|
954 Button* b_ok = new Button(container, PicNode(), surface_btn, 0, 0, 0, btn_height, 2, Rect(x, y, x+btn_width, y+btn_height), 1);
|
|
955 DrawBox(surface_diag, Rect(x-3,y-2,x+btn_width+3,y+btn_height+2));
|
|
956 b_ok->press_pointer = (void*)this;
|
|
957 b_ok->press_func = &press_ok;
|
|
958 if (with_cancel) {
|
|
959 x += x + btn_width;
|
|
960 Button* b_cancel = new Button(container, PicNode(), surface_btn, 0, btn_height*2, 0, btn_height, 2, Rect(x, y, x+btn_width, y+btn_height), 1);
|
|
961 DrawBox(surface_diag, Rect(x-3,y-2,x+btn_width+3,y+btn_height+2));
|
|
962 b_cancel->press_pointer = (void*)this;
|
|
963 b_cancel->press_func = &press_cancel;
|
|
964 }
|
|
965
|
|
966 Pic()->SetSurface(surface_diag, 0, 0);
|
|
967 Pic()->ZMove(ZMOVE_TOP);
|
|
968
|
|
969 show_all();
|
|
970 }
|
|
971 Dialog::~Dialog() {
|
|
972 PicRoot& root = PicNode()->Root();
|
|
973 SetPic(0);
|
|
974 root.DeleteSurface(surface_btn);
|
|
975 root.DeleteSurface(surface_diag);
|
|
976 return;
|
|
977 }
|
|
978
|
|
979 void Dialog::press_ok(void* pointer, Button* btn) {
|
|
980 if (pointer) {
|
|
981 Dialog* wid = (Dialog*)pointer;
|
|
982 wid->status = OK;
|
|
983 if (wid->set_func) {
|
|
984 (*wid->set_func)(wid->set_pointer, wid);
|
|
985 }
|
|
986 }
|
|
987 }
|
|
988 void Dialog::press_cancel(void* pointer, Button* btn) {
|
|
989 if (pointer) {
|
|
990 Dialog* wid = (Dialog*)pointer;
|
|
991 wid->status = CANCEL;
|
|
992 if (wid->set_func) {
|
|
993 (*wid->set_func)(wid->set_pointer, wid);
|
|
994 }
|
|
995 }
|
|
996 }
|
|
997
|
|
998 void Dialog::DrawBox(Surface* s, const Rect& r) {
|
|
999 DSurfaceFill(s, Rect(r.lx, r.ty, r.rx, r.ty+1), 0x80, 0x50, 0x10);
|
|
1000 DSurfaceFill(s, Rect(r.lx, r.ty+1, r.rx, r.ty+2), 0x38, 0x20, 0x18);
|
|
1001 DSurfaceFill(s, Rect(r.lx, r.by-2, r.rx, r.by-1), 0x80, 0x50, 0x10);
|
|
1002 DSurfaceFill(s, Rect(r.lx, r.by-1, r.rx, r.by), 0x38, 0x20, 0x18);
|
|
1003
|
|
1004 DSurfaceFill(s, Rect(r.lx, r.ty, r.lx+1, r.by), 0xb0, 0x80, 0x40);
|
|
1005 DSurfaceFill(s, Rect(r.lx+1, r.ty+1, r.lx+2, r.by-1), 0x80, 0x50, 0x10);
|
|
1006 DSurfaceFill(s, Rect(r.lx+1, r.ty+2, r.lx+2, r.by-2), 0x38, 0x20, 0x18);
|
|
1007 DSurfaceFill(s, Rect(r.rx-3, r.ty+2, r.rx-2, r.by-2), 0xb0, 0x80, 0x40);
|
|
1008 DSurfaceFill(s, Rect(r.rx-2, r.ty+1, r.rx-1, r.by-1), 0x80, 0x50, 0x10);
|
|
1009 DSurfaceFill(s, Rect(r.rx-1, r.ty, r.rx, r.by), 0x38, 0x20, 0x18);
|
|
1010 }
|
|
1011
|
|
1012 AnmTime::AnmTime(Event::Container& container, PicBase* _pic, int _total_time, int _all_count) :
|
|
1013 Event::Time(container),
|
|
1014 PicAnm(_pic), start_time(0), total_time(_total_time), all_count(_all_count) {
|
|
1015 status = FINISHED;
|
|
1016 if (total_time == 0) total_time = 1;
|
|
1017 }
|
|
1018 AnmTime::AnmTime(Event::Container& container, std::vector<PicBase*> _pic, int _total_time, int _all_count) :
|
|
1019 Event::Time(container),
|
|
1020 PicAnm(_pic), start_time(0), total_time(_total_time), all_count(_all_count) {
|
|
1021 status = FINISHED;
|
|
1022 if (total_time == 0) total_time = 1;
|
|
1023 }
|
|
1024 void AnmTime::Elapsed(unsigned int current_time) {
|
|
1025 if (total_time == 0) return;
|
|
1026 if (status == FINISHED || current_time == 0) {SetWakeup(current_time+1); return;}
|
|
1027 if (start_time == 0) {
|
|
1028 start_time = current_time;
|
|
1029 Start();
|
|
1030 }
|
|
1031 unsigned int time_elapsed = current_time - start_time;
|
|
1032 if (time_elapsed < total_time) {
|
|
1033 int count = time_elapsed * all_count / total_time;
|
|
1034 Exec(count);
|
|
1035 int next_time = start_time + (count+1) * total_time / all_count;
|
|
1036 SetWakeup(next_time);
|
|
1037 } else {
|
|
1038 Exec(all_count);
|
|
1039 Finish();
|
|
1040 status = FINISHED;
|
|
1041 }
|
|
1042 return;
|
|
1043 }
|
|
1044 void AnmTime::Abort(void) {
|
|
1045 if (status == FINISHED) return;
|
|
1046 if (start_time == 0) {
|
|
1047 Start();
|
|
1048 Exec(all_count);
|
|
1049 }
|
|
1050 if (total_time) {
|
|
1051 Finish();
|
|
1052 }
|
|
1053 status = FINISHED;
|
|
1054 }
|
|
1055 bool AnmTime::IsEnd(void) {
|
|
1056 return status == FINISHED;
|
|
1057 }
|
|
1058 AnmMove::AnmMove(Event::Container& container, PicBase* _pic, const Rect& _to, int total_time) :
|
|
1059 AnmTime(container, _pic, total_time),
|
|
1060 from(0,0), to(_to) {
|
|
1061 from.lx = _pic->PosX();
|
|
1062 from.ty = _pic->PosY();
|
|
1063 from.rx = from.lx + _pic->Width();
|
|
1064 from.by = from.ty + _pic->Height();
|
|
1065
|
|
1066 int dx = to.lx - from.lx;
|
|
1067 int dy = to.ty - from.ty;
|
|
1068 if (dx < 0) dx = -dx;
|
|
1069 if (dy < 0) dy = -dy;
|
|
1070 if (dx < dy) dx = dy;
|
|
1071 if (dx == 0) dx = 1;
|
|
1072 SetAllCount(dx);
|
|
1073 }
|
|
1074 void AnmMove::Exec(int count) {
|
|
1075 Rect r(from);
|
|
1076 int dx = to.lx - from.lx;
|
|
1077 int dy = to.ty - from.ty;
|
|
1078 r.rmove(dx*count/all_count, dy*count/all_count);
|
|
1079 iterator it;
|
|
1080 for (it=pic.begin(); it!=pic.end(); it++) (*it)->Move(r.lx, r.ty);
|
|
1081 }
|
|
1082 AnmAlpha::AnmAlpha(Event::Container& container, PicBase* _pic, int alpha_from, int alpha_to, int total_time) :
|
|
1083 AnmTime(container, _pic, total_time),
|
|
1084 from(alpha_from), to(alpha_to), alpha_r(0,0,1,1) {
|
|
1085 if (from < 0) from = 0;
|
|
1086 if (from >= ALPHA_MAX) from = ALPHA_MAX;
|
|
1087 if (to < 0) to = 0;
|
|
1088 if (to >= ALPHA_MAX) to = ALPHA_MAX;
|
|
1089 int c = from - to;
|
|
1090 if (c < 0) c = -c;
|
|
1091 if (c == 0) c = 1;
|
|
1092 SetAllCount(c);
|
|
1093 }
|
|
1094 AnmAlpha::AnmAlpha(Event::Container& container, std::vector<PicBase*> _pic, int alpha_from, int alpha_to, int total_time) :
|
|
1095 AnmTime(container, _pic, total_time),
|
|
1096 from(alpha_from), to(alpha_to), alpha_r(0,0,1,1) {
|
|
1097 if (from < 0) from = 0;
|
|
1098 if (from >= ALPHA_MAX) from = ALPHA_MAX;
|
|
1099 if (to < 0) to = 0;
|
|
1100 if (to >= ALPHA_MAX) to = ALPHA_MAX;
|
|
1101 int c = from - to;
|
|
1102 if (c < 0) c = -c;
|
|
1103 if (c == 0) c = 1;
|
|
1104 SetAllCount(c);
|
|
1105 }
|
|
1106 void AnmAlpha::Start(void) {
|
|
1107 iterator it;
|
|
1108 for (it=pic.begin(); it!=pic.end(); it++) (*it)->show();
|
|
1109 }
|
|
1110 void AnmAlpha::Exec(int count) {
|
|
1111 alpha = (from * (all_count-count) + (to-from) * count) / all_count;
|
|
1112 iterator it;
|
|
1113 for (it=pic.begin(); it!=pic.end(); it++) (*it)->SetSurfaceAlpha(&alpha, alpha_r);
|
|
1114 }
|
|
1115 void AnmAlpha::Finish(void) {
|
|
1116 iterator it;
|
|
1117 for (it=pic.begin(); it!=pic.end(); it++) {
|
|
1118 if (to == 0) (*it)->hide();
|
|
1119 else if (to != ALPHA_MAX) fprintf(stderr,"Warning in AnmAlpha::Finish: alpha value suddenly changed.\n");
|
|
1120 (*it)->SetSurfaceAlpha(0,Rect(0,0));
|
|
1121 }
|
|
1122 }
|
|
1123 AnmAlphaMove::AnmAlphaMove(Event::Container& container, PicBase* _pic) :
|
|
1124 AnmTime(container, _pic, 0) {
|
|
1125 }
|
|
1126 void AnmAlphaMove::SetPtn(void) {
|
|
1127 int total = 0;
|
|
1128 std::vector<Ptn>::iterator it;
|
|
1129 for (it=ptns.begin(); it!=ptns.end(); it++) {
|
|
1130 if (total < it->next_tick) total = it->next_tick;
|
|
1131 }
|
|
1132 SetAllCount(total);
|
|
1133 SetTotalTime(total);
|
|
1134 cur_count = 0;
|
|
1135 }
|
|
1136 void AnmAlphaMove::Exec(int count) {
|
|
1137 if (ptns.empty()) return;
|
|
1138 if (cur_count != 0 && ptns[cur_count].next_tick > count) return;
|
|
1139 if (cur_count >= ptns.size()) return;
|
|
1140 // 次のパターンを探す
|
|
1141 // count <= it->next_tick なる条件を満たす最後の it を探す
|
|
1142 std::vector<Ptn>::iterator it;
|
|
1143 for (it=ptns.begin()+cur_count; it != ptns.end(); it++) {
|
|
1144 if (count <= it->next_tick) break;
|
|
1145 }
|
|
1146 if (it == ptns.end()) {
|
|
1147 fprintf(stderr,"end\n");
|
|
1148 it = ptns.end() - 1;
|
|
1149 }
|
|
1150 cur_count = it - ptns.begin();
|
|
1151
|
|
1152 iterator p;
|
|
1153 for (p=pic.begin(); p!=pic.end(); p++) {
|
|
1154 // move
|
|
1155 (*p)->Move(it->pos.lx, it->pos.ty);
|
|
1156 (*p)->SetSurfacePos(it->surface_pos.lx, it->surface_pos.ty);
|
|
1157 // alpha set
|
|
1158 if (it->alpha == 0) (*p)->hide();
|
|
1159 else if (it->alpha == ALPHA_MAX) { (*p)->show(); (*p)->SetSurfaceAlpha(0, Rect(0,0)); }
|
|
1160 else { (*p)->show(); (*p)->SetSurfaceAlpha( &(it->alpha), Rect(0,0,1,1)); }
|
|
1161 }
|
|
1162 }
|
|
1163 void AnmAlphaMove::Finish(void) {
|
|
1164 if (ptns.empty()) return;
|
|
1165 if (cur_count >= ptns.size() - 1) return;
|
|
1166 cur_count = ptns.size() - 1;
|
|
1167 Exec(ptns[cur_count].next_tick); // 最後の pattern の状態にする
|
|
1168 }
|
|
1169
|
|
1170 AnmPtnSolid::AnmPtnSolid(Event::Container& container, PicBase* _pic, const unsigned char* _ptn, const Rect& _alpha_r, int total_time) :
|
|
1171 AnmTime(container, _pic, total_time),
|
|
1172 ptn(_ptn), alpha_r(_alpha_r)
|
|
1173 {
|
|
1174 ptn_len = alpha_r.width() * alpha_r.height();
|
|
1175 alpha = new unsigned char[ptn_len];
|
|
1176 int max_a = 0;
|
|
1177 for (int i=0; i<ptn_len; i++) {
|
|
1178 if (ptn[i] > max_a) max_a = ptn[i];
|
|
1179 }
|
|
1180 if (max_a == 0) max_a = 1;
|
|
1181 SetAllCount(max_a);
|
|
1182 }
|
|
1183
|
|
1184 AnmPtnAlpha::AnmPtnAlpha(Event::Container& container, PicBase* _pic, const unsigned char* _ptn, const Rect& _alpha_r, int _band_width, int total_time) :
|
|
1185 AnmTime(container, _pic, total_time),
|
|
1186 ptn(_ptn), band(_band_width), alpha_r(_alpha_r)
|
|
1187 {
|
|
1188 ptn_len = alpha_r.width() * alpha_r.height();
|
|
1189 alpha = new unsigned char[ptn_len];
|
|
1190 if (band <= 0) band = 1;
|
|
1191 SetAllCount(ALPHA_MAX+band);
|
|
1192 }
|
|
1193
|
|
1194 void AnmPtnSolid::Exec(int count) {
|
|
1195 int i;
|
|
1196 for (i=0; i<ptn_len; i++) {
|
|
1197 if (ptn[i] <= count) alpha[i] = ALPHA_MAX;
|
|
1198 else alpha[i] = 0;
|
|
1199 }
|
|
1200 iterator it;
|
|
1201 for (it=pic.begin(); it!=pic.end(); it++) (*it)->SetSurfaceAlpha(alpha, alpha_r);
|
|
1202 }
|
|
1203 void AnmPtnAlpha::Exec(int count) {
|
|
1204 int i;
|
|
1205 int ptn_zero = count;
|
|
1206 int ptn_max = count - band;
|
|
1207 for (i=0; i<ptn_len; i++) {
|
|
1208 if (ptn[i] >= ptn_zero) alpha[i] = 0;
|
|
1209 else if (ptn[i] < ptn_max) alpha[i] = ALPHA_MAX;
|
|
1210 else alpha[i] = (ptn_zero-ptn[i])*ALPHA_MAX/band;
|
|
1211 }
|
|
1212 iterator it;
|
|
1213 for (it=pic.begin(); it!=pic.end(); it++) (*it)->SetSurfaceAlpha(alpha, alpha_r);
|
|
1214 }
|
|
1215
|
|
1216 void AnmPtnSolid::Start(void) {
|
|
1217 iterator it;
|
|
1218 for (it=pic.begin(); it!=pic.end(); it++) (*it)->show();
|
|
1219 }
|
|
1220 void AnmPtnSolid::Finish(void) {
|
|
1221 iterator it;
|
|
1222 for (it=pic.begin(); it!=pic.end(); it++) (*it)->SetSurfaceAlpha(0, Rect(0,0));
|
|
1223 }
|
|
1224 void AnmPtnAlpha::Start(void) {
|
|
1225 iterator it;
|
|
1226 for (it=pic.begin(); it!=pic.end(); it++) (*it)->show();
|
|
1227 }
|
|
1228 void AnmPtnAlpha::Finish(void) {
|
|
1229 iterator it;
|
|
1230 for (it=pic.begin(); it!=pic.end(); it++) (*it)->SetSurfaceAlpha(0, Rect(0,0));
|
|
1231 }
|
|
1232
|
|
1233 /*
|
|
1234
|
|
1235 Widget の種類
|
|
1236 Mouse: マウス位置に連動する。Surface と origin が必須
|
|
1237 Panel : なにも存在しないところに張りつけていく
|
|
1238 背景張りつけも可能
|
|
1239 ButtonPanel : 無効化可能。Group の Button がカーソルに入ったら、全Button / Label が「カーソル下」状態になる
|
|
1240 同一変数を扱うボタンは原則、同一ButtonPanel の下に入ること(同期する。高速化可能)
|
|
1241 そうでない場合、ボタンの GlobalVariable フラグを立てる必要がある
|
|
1242 背景種類:Window
|
|
1243 内部の透明度と枠形を別々に指定可能。枠形は全枠、部分枠どちらの形でも可能
|
|
1244 (部分枠なら、内部的には上枠、下枠、左右枠と別 Surface で管理する)
|
|
1245 DragButton
|
|
1246 Panel 全体をドラッグし、場所変更できるボタン。
|
|
1247 Button: 無効化>通常>カーソル下>ボタン押下 のpicture / animation
|
|
1248 Toggle Button にできる(Group化すればRadioButtonにもできる)
|
|
1249 Label : 無効化>通常>カーソル下 のanimation
|
|
1250 animation は
|
|
1251 ・上への変化
|
|
1252 ・下への変化
|
|
1253 ・常時変形
|
|
1254 の3つの形式をもつ。
|
|
1255 形式は
|
|
1256 ・x / y increment による(全領域と x,y の大きさを指定すると左上から右上、左下、という方へ勝手に領域を変更していく)
|
|
1257 ・色変化(明度変化)。色テーブルを指定する。Surface は alpha のみとする
|
|
1258 どちらも、一つのラベルに使う時間の長さを指定する
|
|
1259 ・callback による。指定した一定時間以上が立つとCallBack が呼び出され、新たなSurface , origin を指定する。
|
|
1260
|
|
1261 ・Surface は
|
|
1262 普通の画像
|
|
1263 文字列(適当に仮想化)
|
|
1264 画像数値列
|
|
1265 のいずれか
|
|
1266 Cursor
|
|
1267 リターンカーソル。Label の一種。
|
|
1268 Number
|
|
1269 数字を表示する。フォントの大きさ、もしくは画像数値列
|
|
1270 Text
|
|
1271 テキストを表示する
|
|
1272 パネルの大きさだけ指定すると適当にやってくれる
|
|
1273 カーソルの位置(文字の次/最終)を指定すること
|
|
1274 機能:文字送り速度設定、読み飛ばし設定(常に最高速で押しっぱなし)
|
|
1275 ProgressBar など
|
|
1276 バーの長さ、あるいは位置で変数の大きさを示す。
|
|
1277 Tick, Max を指定、変数の変化には適当に対応できるようにする
|
|
1278 バーの方向として縦/横。Surface は繰り返しで使う(速度上、32pixel くらいあったほうがいいかも?)
|
|
1279 バーの代わりにボタンも使える。Surface 指定のメソッドが違うだけ。
|
|
1280 オプション:バーのどこかをクリックされたとき、そこに移動するかそこに向かって移動するか
|
|
1281 オプション?:矢印ボタン(いらないか)
|
|
1282 ScrollBar
|
|
1283 横/縦。Panel と連動する(専用, ProgressBar の一種として実装)
|
|
1284 (Panel 側で「見えない部分はdelete, 見える部分は自動で作成」機能をつける?:バックログ)
|
|
1285
|
|
1286
|
|
1287
|
|
1288 メニューの出し方
|
|
1289 右クリック
|
|
1290 ボタンを押す
|
|
1291 上の方、右の方など領域に行くとヌっと出てくる
|
|
1292 メニューモード内
|
|
1293 ボタンを押して終了
|
|
1294 マップを作っておき、各メニューに名前を割り振ると二次元に広がったメニューになる
|
|
1295 名前を割り振ると上に名前リストがでてくる
|
|
1296 名前を割り振ると横に名前リストが出てくる
|
|
1297
|
|
1298 */
|
|
1299 // }
|