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