1 // Crimson Fields -- a game of tactical warfare
2 // Copyright (C) 2000-2007 Jens Granseuer
3 //
4 // This program is free software; you can redistribute it and/or modify
5 // it under the terms of the GNU General Public License as published by
6 // the Free Software Foundation; either version 2 of the License, or
7 // (at your option) any later version.
8 //
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU General Public License for more details.
13 //
14 // You should have received a copy of the GNU General Public License
15 // along with this program; if not, write to the Free Software
16 // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17 //
18
19 ////////////////////////////////////////////////////////////////////////
20 // button.cpp
21 ////////////////////////////////////////////////////////////////////////
22
23 #include "button.h"
24 #include "misc.h"
25 #include "sound.h"
26
27 ////////////////////////////////////////////////////////////////////////
28 // NAME : ButtonWidget::ButtonWidget
29 // DESCRIPTION: Create a button widget.
30 // PARAMETERS : id - widget identifier
31 // x - left edge of widget relative to window border
32 // y - top edge of widget
33 // w - widget width
34 // h - widget height
35 // flags - see widget.h for details
36 // title - widget title (may be NULL)
37 // window - widget parent window
38 // RETURNS : -
39 ////////////////////////////////////////////////////////////////////////
40
ButtonWidget(short id,short x,short y,unsigned short w,unsigned short h,unsigned short flags,const char * title,Window * window)41 ButtonWidget::ButtonWidget( short id, short x, short y, unsigned short w,
42 unsigned short h, unsigned short flags,
43 const char *title, Window *window ) :
44 Widget( id, x, y, w, h, flags, title, window ) {
45 if ( !(this->flags & (WIDGET_ALIGN_CENTER|WIDGET_ALIGN_LEFT|
46 WIDGET_ALIGN_RIGHT|WIDGET_ALIGN_TOP)) )
47 this->flags |= WIDGET_ALIGN_CENTER;
48 }
49
50 ////////////////////////////////////////////////////////////////////////
51 // NAME : ButtonWidget::Draw
52 // DESCRIPTION: Draw the button widget.
53 // PARAMETERS : -
54 // RETURNS : -
55 ////////////////////////////////////////////////////////////////////////
56
Draw(void)57 void ButtonWidget::Draw( void ) {
58 surface->DrawBack( *this );
59
60 if ( (flags & WIDGET_STYLE_MENU) && Clicked() ) {
61 surface->DrawBox( *this, BOX_RECESSED );
62 surface->FillRectAlpha( x+1, y+1, w-2, h-2, Color(CF_COLOR_SHADOW) );
63 } else if ( flags & WIDGET_STYLE_HIGHLIGHT ) {
64 surface->FillRectAlpha( *this, surface->GetFGPen() );
65 } else if ( !(flags & WIDGET_STYLE_NOBORDER) ) {
66 surface->DrawBox( *this, BOX_RECESSED );
67 surface->DrawBox( Rect(x+1,y+1,w-2,h-2), Clicked() ? BOX_RECESSED : BOX_RAISED );
68 if ( Clicked() )
69 surface->FillRectAlpha( x+2, y+2, w-4, h-4, Color(CF_COLOR_SHADOW) );
70 }
71
72 if ( flags & WIDGET_STYLE_GFX ) {
73 Image &img = image[Clicked()];
74
75 // the flags designate the label alignment; image alignment is opposite
76 int xoff;
77 if ( (flags & (WIDGET_ALIGN_LEFT|WIDGET_ALIGN_WITHIN)) ==
78 (WIDGET_ALIGN_LEFT|WIDGET_ALIGN_WITHIN) ) {
79 xoff = x + (w - img.Width()) - 2;
80 } else if ( (flags & (WIDGET_ALIGN_RIGHT|WIDGET_ALIGN_WITHIN)) ==
81 (WIDGET_ALIGN_RIGHT|WIDGET_ALIGN_WITHIN) ) {
82 xoff = x + 2;
83 } else {
84 xoff = x + (w - img.Width()) / 2;
85 }
86 img.Draw( surface, xoff, y + (h - img.Height()) / 2 );
87 }
88
89 PrintTitle( ((flags & WIDGET_STYLE_HIGHLIGHT) && !Clicked()) ?
90 surface->GetBGPen() : surface->GetFGPen() );
91 if ( flags & WIDGET_STYLE_SUBMENU )
92 image[0].Draw( surface, x + w - 3 - image[0].Width(),
93 y + (h - image[0].Height())/2 + (Clicked() ? 1 : 0) );
94 }
95
96 ////////////////////////////////////////////////////////////////////////
97 // NAME : ButtonWidget::SetImage
98 // DESCRIPTION: For widgets which have the WIDGET_STYLE_GFX flag set,
99 // define the images to use for displaying them.
100 // PARAMETERS : image - the surface containing the images
101 // state1 - rectangle containing the position of the image
102 // to show when the widget is not selected
103 // state2 - rectangle containing the position of the image
104 // to show when the widget is selected
105 // RETURNS : -
106 ////////////////////////////////////////////////////////////////////////
107
SetImage(Surface * image,const Rect & state1,const Rect & state2)108 void ButtonWidget::SetImage( Surface *image,
109 const Rect &state1, const Rect &state2 ) {
110 this->image[0] = Image( image, state1.x, state1.y, state1.w, state1.h );
111 this->image[1] = Image( image, state2.x, state2.y, state2.w, state2.h );
112 }
113
114 ////////////////////////////////////////////////////////////////////////
115 // NAME : ButtonWidget::MouseDown
116 // DESCRIPTION: Show the widget in depressed state if it was selected.
117 // PARAMETERS : button - SDL_MouseButtonEvent received from the event
118 // handler
119 // RETURNS : GUI_OK
120 ////////////////////////////////////////////////////////////////////////
121
MouseDown(const SDL_MouseButtonEvent & button)122 GUI_Status ButtonWidget::MouseDown( const SDL_MouseButtonEvent &button ) {
123 if ( (button.button == SDL_BUTTON_LEFT) &&
124 Contains( button.x - surface->LeftEdge(),
125 button.y - surface->TopEdge() ) ) Push();
126 else if ( Clicked() ) Release();
127 return GUI_OK;
128 }
129
130 ////////////////////////////////////////////////////////////////////////
131 // NAME : ButtonWidget::MouseUp
132 // DESCRIPTION: Release the button and activate it if the mouse pointer
133 // is still over it.
134 // PARAMETERS : button - SDL_MouseButtonEvent received from the event
135 // handler
136 // RETURNS : GUI status
137 ////////////////////////////////////////////////////////////////////////
138
MouseUp(const SDL_MouseButtonEvent & button)139 GUI_Status ButtonWidget::MouseUp( const SDL_MouseButtonEvent &button ) {
140 if ( Clicked() && (button.button == SDL_BUTTON_LEFT) ) {
141 Release();
142 if ( Contains( button.x - surface->LeftEdge(),
143 button.y - surface->TopEdge() ) ) return Activate();
144 }
145 return GUI_OK;
146 }
147
148 ////////////////////////////////////////////////////////////////////////
149 // NAME : ButtonWidget::KeyDown
150 // DESCRIPTION: Depress button if the correct key was hit.
151 // PARAMETERS : key - SDL_keysym received from the event handler
152 // RETURNS : GUI_OK
153 ////////////////////////////////////////////////////////////////////////
154
KeyDown(const SDL_keysym & key)155 GUI_Status ButtonWidget::KeyDown( const SDL_keysym &key ) {
156 if ( (key.sym == this->key) ||
157 ((flags & WIDGET_DEFAULT) && (key.sym == SDLK_RETURN)) ) Push();
158 else if ( Clicked() ) Release();
159 return GUI_OK;
160 }
161
162 ////////////////////////////////////////////////////////////////////////
163 // NAME : ButtonWidget::KeyUp
164 // DESCRIPTION: Activate widget if correct key was released.
165 // PARAMETERS : key - SDL_keysym received from the event handler
166 // RETURNS : GUI status
167 ////////////////////////////////////////////////////////////////////////
168
KeyUp(const SDL_keysym & key)169 GUI_Status ButtonWidget::KeyUp( const SDL_keysym &key ) {
170 if ( Clicked() && ((key.sym == this->key) ||
171 ((flags & WIDGET_DEFAULT) && (key.sym == SDLK_RETURN))) ) {
172 Release();
173 return Activate();
174 }
175 return GUI_OK;
176 }
177
178 ////////////////////////////////////////////////////////////////////////
179 // NAME : ButtonWidget::Push
180 // DESCRIPTION: Change the widget state to 'clicked', redraw, and play
181 // a sound effect.
182 // PARAMETERS : -
183 // RETURNS : -
184 ////////////////////////////////////////////////////////////////////////
185
Push(void)186 void ButtonWidget::Push( void ) {
187 if ( !clicked ) {
188 Audio::PlaySfx( Audio::SND_GUI_PRESSED, 0 );
189 Widget::Push();
190 }
191 }
192
193 ////////////////////////////////////////////////////////////////////////
194 // NAME : ButtonWidget::Activate
195 // DESCRIPTION: Activate widget, i.e. call the activation function of
196 // the hook class.
197 // PARAMETERS : -
198 // RETURNS : return code of the activation function
199 ////////////////////////////////////////////////////////////////////////
200
Activate(void)201 GUI_Status ButtonWidget::Activate( void ) {
202 if ( hook ) return hook->WidgetActivated( this, surface );
203 return (GUI_Status)id;
204 }
205
206
207 ////////////////////////////////////////////////////////////////////////
208 // NAME : CheckboxWidget::CheckboxWidget
209 // DESCRIPTION: Create a checkbox widget.
210 // PARAMETERS : id - widget identifier
211 // x - left edge of widget relative to window border
212 // y - top edge of widget
213 // w - widget width
214 // h - widget height
215 // state - initial state (checked or unchecked)
216 // flags - see widget.h for details
217 // title - widget title (may be NULL)
218 // window - widget parent window
219 // RETURNS : -
220 ////////////////////////////////////////////////////////////////////////
221
222 #define GFX_CHECK_SIZE 15
223 #define GFX_CHECK_OFF_X 64
224 #define GFX_CHECK_OFF_Y 46
225 #define GFX_CHECK_ON_X 79
226 #define GFX_CHECK_ON_Y 46
227
CheckboxWidget(short id,short x,short y,unsigned short w,unsigned short h,bool state,unsigned short flags,const char * title,Window * window)228 CheckboxWidget::CheckboxWidget( short id, short x, short y, unsigned short w,
229 unsigned short h, bool state, unsigned short flags,
230 const char *title, Window *window ) :
231 ButtonWidget( id, x, y, w, h, flags, title, window ) {
232 clicked = state;
233
234 // set default graphics
235 if ( flags & WIDGET_STYLE_GFX ) {
236 Surface *icons = surface->GetView()->GetSystemIcons();
237 image[0] = Image( icons, GFX_CHECK_OFF_X, GFX_CHECK_OFF_Y,
238 GFX_CHECK_SIZE, GFX_CHECK_SIZE );
239 image[1] = Image( icons, GFX_CHECK_ON_X, GFX_CHECK_ON_Y,
240 GFX_CHECK_SIZE, GFX_CHECK_SIZE );
241 }
242 }
243
244 ////////////////////////////////////////////////////////////////////////
245 // NAME : CheckboxWidget::MouseDown
246 // DESCRIPTION: Check or uncheck the widget, depending on its current
247 // state.
248 // PARAMETERS : button - SDL_MouseButtonEvent received from the event
249 // handler
250 // RETURNS : GUI status
251 ////////////////////////////////////////////////////////////////////////
252
MouseDown(const SDL_MouseButtonEvent & button)253 GUI_Status CheckboxWidget::MouseDown( const SDL_MouseButtonEvent &button ) {
254 if ( (button.button == SDL_BUTTON_LEFT) &&
255 Contains( button.x - surface->LeftEdge(),
256 button.y - surface->TopEdge() ) ) {
257 if ( Clicked() ) {
258 Audio::PlaySfx( Audio::SND_GUI_PRESSED, 0 );
259 Release();
260 } else Push();
261 return Activate();
262 }
263 return GUI_OK;
264 }
265
266 ////////////////////////////////////////////////////////////////////////
267 // NAME : CheckboxWidget::KeyDown
268 // DESCRIPTION: Toggle the widget status when the corresponding key was
269 // hit.
270 // PARAMETERS : key - SDL_keysym received from the event handler
271 // RETURNS : GUI status
272 ////////////////////////////////////////////////////////////////////////
273
KeyDown(const SDL_keysym & key)274 GUI_Status CheckboxWidget::KeyDown( const SDL_keysym &key ) {
275 if ( (key.sym == this->key) ||
276 ((flags & WIDGET_DEFAULT) && (key.sym == SDLK_RETURN)) ) {
277 if ( Clicked() ) {
278 Audio::PlaySfx( Audio::SND_GUI_PRESSED, 0 );
279 Release();
280 } else Push();
281 return Activate();
282 }
283 return GUI_OK;
284 }
285
286
287 ////////////////////////////////////////////////////////////////////////
288 // NAME : MenuButtonWidget::MenuButtonWidget
289 // DESCRIPTION: Create a button widget for a MenuWindow.
290 // PARAMETERS : id - widget identifier
291 // x - left edge of widget relative to window border
292 // y - top edge of widget
293 // w - widget width
294 // h - widget height
295 // flags - see widget.h for details
296 // title - widget title (may be NULL)
297 // window - widget parent window
298 // RETURNS : -
299 ////////////////////////////////////////////////////////////////////////
300
MenuButtonWidget(short id,short x,short y,unsigned short w,unsigned short h,unsigned short flags,const char * title,Window * window)301 MenuButtonWidget::MenuButtonWidget( short id, short x, short y, unsigned short w,
302 unsigned short h, unsigned short flags,
303 const char *title, Window *window ) :
304 ButtonWidget( id, x, y, w, h, flags, title, window ) {
305 image[0] = Image( window->GetView()->GetSystemIcons(), 175, 46, 7, 11 );
306 }
307
308 ////////////////////////////////////////////////////////////////////////
309 // NAME : MenuButtonWidget::MouseMove
310 // DESCRIPTION: When the mouse is moved over the button, highlight it.
311 // PARAMETERS : motion - SDL_MouseMotionEvent received from the event
312 // handler
313 // RETURNS : GUI_OK
314 ////////////////////////////////////////////////////////////////////////
315
MouseMove(const SDL_MouseMotionEvent & motion)316 GUI_Status MenuButtonWidget::MouseMove( const SDL_MouseMotionEvent &motion ) {
317 bool contain = Contains( motion.x - surface->LeftEdge(), motion.y - surface->TopEdge() );
318
319 if ( ((flags & WIDGET_STYLE_HIGHLIGHT) && !contain) ||
320 (!(flags & WIDGET_STYLE_HIGHLIGHT) && contain) ) {
321 ToggleCurrent();
322 Draw();
323 Show();
324 }
325
326 return GUI_OK;
327 }
328
329
330 #define GFX_CYCLE_W 7
331 #define GFX_CYCLE_H 12
332 #define GFX_CYCLE_X 138
333 #define GFX_CYCLE_Y 46
334
335 ////////////////////////////////////////////////////////////////////////
336 // NAME : CycleWidget::CycleWidget
337 // DESCRIPTION: Create a new cycle widget.
338 // PARAMETERS : id - widget identifier
339 // x - left edge of widget relative to window border
340 // y - top edge of widget
341 // w - widget width
342 // h - widget height
343 // flags - see widget.h for details (default title
344 // placement is WIDGET_ALIGN_LEFT)
345 // title - widget title (may be NULL)
346 // defval - default value, starting with 0
347 // labels - array of available choices, terminated by a
348 // NULL-string
349 // window - widget parent window
350 // RETURNS : -
351 ////////////////////////////////////////////////////////////////////////
352
CycleWidget(short id,short x,short y,unsigned short w,unsigned short h,unsigned short flags,const char * title,unsigned short defval,const char * labels[],Window * window)353 CycleWidget::CycleWidget( short id, short x, short y, unsigned short w,
354 unsigned short h, unsigned short flags, const char *title,
355 unsigned short defval, const char *labels[], Window *window ) :
356 ButtonWidget( id, x, y, w, h, flags, title, window ),
357 maxval(0) {
358
359 if ( !(flags & (WIDGET_ALIGN_CENTER|WIDGET_ALIGN_LEFT|
360 WIDGET_ALIGN_RIGHT|WIDGET_ALIGN_TOP)) )
361 // button widget defaults to center which we must revert
362 this->flags ^= WIDGET_ALIGN_LEFT|WIDGET_ALIGN_CENTER;
363
364 image[0] = Image( window->GetView()->GetSystemIcons(),
365 GFX_CYCLE_X, GFX_CYCLE_Y,
366 GFX_CYCLE_W, GFX_CYCLE_H );
367
368 int i;
369 for ( i = 1; labels[i]; ++i ) ++maxval;
370 choices = new string[maxval+1];
371 for ( i = 0; i <= maxval; ++i ) choices[i].assign( labels[i] );
372
373 val = MIN( defval, maxval );
374 }
375
376 ////////////////////////////////////////////////////////////////////////
377 // NAME : CycleWidget::Draw
378 // DESCRIPTION: Draw the cycle widget.
379 // PARAMETERS : -
380 // RETURNS : -
381 ////////////////////////////////////////////////////////////////////////
382
Draw(void)383 void CycleWidget::Draw( void ) {
384 ButtonWidget::Draw();
385
386 short off = (Clicked() ? 1 : 0);
387 Color fcol;
388
389 surface->FillRect( x + w - image[0].Width() - 8 + off, y + 4 + off, 1, h - 8, Color(CF_COLOR_SHADOW) );
390 surface->FillRect( x + w - image[0].Width() - 7 + off, y + 4 + off, 1, h - 8, Color(CF_COLOR_HIGHLIGHT) );
391
392 image[0].Draw( surface, x + w - image[0].Width() - 4 + off, y + (h - image[0].Height())/2 + off );
393
394 if ( Disabled() ) {
395 fcol = font->GetColor();
396 font->SetColor( Color(CF_COLOR_GHOSTED) );
397 }
398
399 // draw current label
400 font->Write( choices[val].c_str(), surface,
401 x + (w - image[0].Width() - 10 - font->TextWidth(choices[val].c_str()))/2 + off,
402 y + (h - font->Height()) / 2 + off, *this );
403
404 if ( Disabled() ) font->SetColor( fcol );
405 }
406
407 ////////////////////////////////////////////////////////////////////////
408 // NAME : CycleWidget::MouseDown
409 // DESCRIPTION: Show the widget in depressed state if it was selected.
410 // PARAMETERS : button - SDL_MouseButtonEvent received from the event
411 // handler
412 // RETURNS : GUI_OK
413 ////////////////////////////////////////////////////////////////////////
414
MouseDown(const SDL_MouseButtonEvent & button)415 GUI_Status CycleWidget::MouseDown( const SDL_MouseButtonEvent &button ) {
416 if ( ((button.button == SDL_BUTTON_LEFT) ||
417 (button.button == SDL_BUTTON_RIGHT)) &&
418 Contains( button.x - surface->LeftEdge(),
419 button.y - surface->TopEdge() ) ) {
420 up = (button.button == SDL_BUTTON_LEFT);
421 Push();
422 } else if ( Clicked() ) Release();
423 return GUI_OK;
424 }
425
426 ////////////////////////////////////////////////////////////////////////
427 // NAME : CycleWidget::MouseUp
428 // DESCRIPTION: Release the button and activate it if the mouse pointer
429 // is still over it.
430 // PARAMETERS : button - SDL_MouseButtonEvent received from the event
431 // handler
432 // RETURNS : GUI status
433 ////////////////////////////////////////////////////////////////////////
434
MouseUp(const SDL_MouseButtonEvent & button)435 GUI_Status CycleWidget::MouseUp( const SDL_MouseButtonEvent &button ) {
436 if ( Clicked() &&
437 ((button.button == SDL_BUTTON_LEFT) ||
438 (button.button == SDL_BUTTON_RIGHT)) ) {
439 bool hit = Contains( button.x - surface->LeftEdge(),
440 button.y - surface->TopEdge() );
441 if ( hit ) CycleValue();
442 Release();
443 if ( hit ) return Activate();
444 }
445 return GUI_OK;
446 }
447
448 ////////////////////////////////////////////////////////////////////////
449 // NAME : CycleWidget::KeyUp
450 // DESCRIPTION: Activate widget if correct key was released.
451 // PARAMETERS : key - SDL_keysym received from the event handler
452 // RETURNS : GUI status
453 ////////////////////////////////////////////////////////////////////////
454
KeyUp(const SDL_keysym & key)455 GUI_Status CycleWidget::KeyUp( const SDL_keysym &key ) {
456 if ( Clicked() && ((key.sym == this->key) ||
457 ((flags & WIDGET_DEFAULT) && (key.sym == SDLK_RETURN))) ) {
458 up = ((key.mod & (KMOD_LSHIFT|KMOD_RSHIFT)) == 0);
459 CycleValue();
460 Release();
461 return Activate();
462 }
463 return GUI_OK;
464 }
465
466 ////////////////////////////////////////////////////////////////////////
467 // NAME : CycleWidget::CycleValue
468 // DESCRIPTION: Update the widget value according to the button pressed.
469 // PARAMETERS : -
470 // RETURNS : -
471 ////////////////////////////////////////////////////////////////////////
472
CycleValue(void)473 void CycleWidget::CycleValue( void ) {
474 if (up) val = (val + 1) % (maxval + 1);
475 else if ( val == 0 ) val = maxval;
476 else --val;
477 }
478
479 ////////////////////////////////////////////////////////////////////////
480 // NAME : CycleWidget::SetValue
481 // DESCRIPTION: Set the cycle value.
482 // PARAMETERS : value - new value
483 // RETURNS : -
484 ////////////////////////////////////////////////////////////////////////
485
SetValue(unsigned short value)486 void CycleWidget::SetValue( unsigned short value ) {
487 val = value % (maxval + 1);
488 Draw();
489 Show();
490 }
491
492 ////////////////////////////////////////////////////////////////////////
493 // NAME : DropWidget::DropWidget
494 // DESCRIPTION: Create a dropd-own widget, which is a ButtonWidget with
495 // a small arrow image.
496 // PARAMETERS : id - widget identifier
497 // x - left edge of widget relative to window border
498 // y - top edge of widget
499 // w - widget width
500 // h - widget height
501 // flags - see widget.h for details
502 // title - widget title (may be NULL)
503 // window - widget parent window
504 // RETURNS : -
505 ////////////////////////////////////////////////////////////////////////
506
DropWidget(short id,short x,short y,unsigned short w,unsigned short h,unsigned short flags,const char * title,Window * window)507 DropWidget::DropWidget( short id, short x, short y, unsigned short w,
508 unsigned short h, unsigned short flags, const char *title,
509 Window *window ) :
510 ButtonWidget( id, x, y, w, h, flags, title, window ) {
511 image[0] = Image( window->GetView()->GetSystemIcons(), 157, 53, 11, 7 );
512 }
513
514 ////////////////////////////////////////////////////////////////////////
515 // NAME : DropWidget::Draw
516 // DESCRIPTION: Draw the drop-down widget.
517 // PARAMETERS : -
518 // RETURNS : -
519 ////////////////////////////////////////////////////////////////////////
520
Draw(void)521 void DropWidget::Draw( void ) {
522 surface->DrawBack( *this );
523
524 surface->DrawBox( *this, BOX_RECESSED );
525 surface->DrawBox( Rect(x+1,y+1,w-2,h-2), Clicked() ? BOX_RECESSED : BOX_RAISED );
526 if ( Clicked() )
527 surface->FillRectAlpha( x+2, y+2, w-4, h-4, Color(CF_COLOR_SHADOW) );
528
529 short off = (Clicked() ? 1 : 0);
530 short xoff = x + (w - font->TextWidth(title.c_str()) - image[0].Width() - 8) / 2;
531 short yoff = y + (h - font->Height()) / 2;
532 PrintTitle( xoff + off, yoff + off, surface->GetFGPen() );
533
534 surface->FillRect( x + w - image[0].Width() - 8 + off, y + 4 + off, 1, h - 8, Color(CF_COLOR_SHADOW) );
535 surface->FillRect( x + w - image[0].Width() - 7 + off, y + 4 + off, 1, h - 8, Color(CF_COLOR_HIGHLIGHT) );
536
537 image[0].Draw( surface, x + w - image[0].Width() - 4 + off, y + (h - image[0].Height())/2 + off );
538 }
539
540