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 // slider.cpp
21 ////////////////////////////////////////////////////////////////////////
22
23 #include "slider.h"
24 #include "misc.h"
25
26 ////////////////////////////////////////////////////////////////////////
27 // NAME : SliderWidget::SliderWidget
28 // DESCRIPTION: Create a new slider widget.
29 // PARAMETERS : id - widget identifier
30 // x - left edge of widget
31 // y - top edge of widget
32 // w - widget width
33 // h - widget height
34 // vmin - lowest slider level allowed
35 // vmax - highest slider level allowed
36 // start - default level
37 // ksize - size of the slider knob in items (if the slider
38 // has 10 possible positions and ksize is 2, the
39 // size will be claculated as if there were 12
40 // levels and two of them were represented by one
41 // slider position, so the knob would take up
42 // 2/12th of the widget size)
43 // flags - widget flags (see widget.h for details)
44 // title - widget title (currently unused)
45 // window - window to add this widget to
46 // RETURNS : -
47 ////////////////////////////////////////////////////////////////////////
48
SliderWidget(short id,short x,short y,unsigned short w,unsigned short h,short vmin,short vmax,short start,short ksize,unsigned short flags,const char * title,Window * window)49 SliderWidget::SliderWidget( short id, short x, short y, unsigned short w,
50 unsigned short h, short vmin, short vmax, short start, short ksize,
51 unsigned short flags, const char *title, Window *window ) :
52 Widget( id, x, y, w, h, flags, title, window ) {
53 mousehit = false;
54 current = start;
55 keystep = 1;
56
57 Adjust( vmin, vmax, ksize );
58 }
59
60 ////////////////////////////////////////////////////////////////////////
61 // NAME : SliderWidget::Adjust
62 // DESCRIPTION: Set new minimum and maximum slider values.
63 // PARAMETERS : newmin - new minimum level
64 // newmax - new maximum level
65 // newsize - new knob size
66 // RETURNS : -
67 ////////////////////////////////////////////////////////////////////////
68
Adjust(short newmin,short newmax,short newsize)69 void SliderWidget::Adjust( short newmin, short newmax, short newsize ) {
70 min_level = newmin;
71 max_level = newmax;
72 size = MAX( newsize, 1 );
73
74 if ( current < min_level ) current = min_level;
75 else if ( current > max_level ) current = max_level;
76
77 short num = max_level - min_level;
78 if ( flags & WIDGET_HSCROLL ) {
79 knob.w = MAX( 2, (w - 2) * size / (size + num) );
80 knob.h = h - 2;
81 if ( max_level > min_level ) step = (float)(w - 2 - knob.w) / num;
82 else step = 0;
83 knob.x = (short)(x + 1 + (current - min_level) * step + 0.5);
84 knob.y = y + 1;
85 } else {
86 knob.w = w - 2;
87 knob.h = MAX( 2, (h - 2) * size / (size + num) );
88 if ( max_level > min_level ) step = (float)(h - 2 - knob.h) / num;
89 else step = 0;
90 knob.x = x + 1;
91 knob.y = (short)(y + 1 + (current - min_level) * step + 0.5);
92 }
93 }
94
95 ////////////////////////////////////////////////////////////////////////
96 // NAME : SliderWidget::Draw
97 // DESCRIPTION: Draw slider widget and knob.
98 // PARAMETERS : -
99 // RETURNS : -
100 ////////////////////////////////////////////////////////////////////////
101
Draw(void)102 void SliderWidget::Draw( void ) {
103 surface->DrawBack( *this );
104 surface->DrawBox( *this, BOX_RECESSED );
105
106 // draw knob
107 surface->DrawBox( knob, Clicked() ? BOX_RECESSED : BOX_RAISED );
108 if ( Clicked() )
109 surface->FillRectAlpha( knob.x+1, knob.y+1, knob.w-2, knob.h-2, Color(CF_COLOR_SHADOW) );
110
111 PrintTitle( surface->GetFGPen() );
112 }
113
114 ////////////////////////////////////////////////////////////////////////
115 // NAME : SliderWidget::ScrollTo
116 // DESCRIPTION: Set the slider to a new level.
117 // PARAMETERS : level - new slider position
118 // RETURNS : -
119 ////////////////////////////////////////////////////////////////////////
120
ScrollTo(short level)121 void SliderWidget::ScrollTo( short level ) {
122 current = level;
123 if ( current < min_level ) current = min_level;
124 else if ( current > max_level ) current = max_level;
125
126 if ( flags & WIDGET_HSCROLL )
127 knob.x = (short)(x + 1 + (current - min_level) * step + 0.5);
128 else knob.y = (short)(y + 1 + (current - min_level) * step + 0.5);
129
130 if ( hook ) hook->WidgetActivated( this, surface );
131 Draw();
132 Show();
133 }
134
135 ////////////////////////////////////////////////////////////////////////
136 // NAME : SliderWidget::MouseDown
137 // DESCRIPTION: Depress the slider or move the knob towards the mouse.
138 // PARAMETERS : button - SDL_MouseButtonEvent received from the event
139 // handler
140 // RETURNS : GUI status
141 ////////////////////////////////////////////////////////////////////////
142
MouseDown(const SDL_MouseButtonEvent & button)143 GUI_Status SliderWidget::MouseDown( const SDL_MouseButtonEvent &button ) {
144 short mx = button.x - surface->LeftEdge();
145 short my = button.y - surface->TopEdge();
146
147 if ( Contains( mx, my ) ) {
148 if ( button.button == SDL_BUTTON_LEFT ) {
149 if ( knob.Contains( mx, my ) ) {
150 Push();
151 mousehit = true;
152 } else {
153 short diff = MAX( 1, size/2 );
154 if ( flags & WIDGET_HSCROLL ) {
155 if ( mx < knob.x ) ScrollTo( current - diff );
156 else if ( mx >= (knob.x + knob.w) ) ScrollTo( current + diff );
157 } else {
158 if ( my < knob.y ) ScrollTo( current - diff );
159 else if ( my >= (knob.y + knob.h) ) ScrollTo( current + diff );
160 }
161 }
162 } else if ( button.button == SDL_BUTTON_WHEELUP ) {
163 ScrollTo( current - MAX(1, size/4) );
164 } else if ( button.button == SDL_BUTTON_WHEELDOWN ) {
165 ScrollTo( current + MAX(1, size/4) );
166 }
167 }
168
169 return GUI_OK;
170 }
171
172 ////////////////////////////////////////////////////////////////////////
173 // NAME : SliderWidget::MouseUp
174 // DESCRIPTION: Release the knob.
175 // PARAMETERS : button - SDL_MouseButtonEvent received from the event
176 // handler
177 // RETURNS : GUI_OK
178 ////////////////////////////////////////////////////////////////////////
179
MouseUp(const SDL_MouseButtonEvent & button)180 GUI_Status SliderWidget::MouseUp( const SDL_MouseButtonEvent &button ) {
181 if ( Clicked() && (button.button == SDL_BUTTON_LEFT) ) {
182 Release();
183 mousehit = false;
184 }
185 return GUI_OK;
186 }
187
188 ////////////////////////////////////////////////////////////////////////
189 // NAME : SliderWidget::KeyDown
190 // DESCRIPTION: Depress knob and move slider if correct key was hit.
191 // PARAMETERS : key - SDL_keysym received from the event handler
192 // RETURNS : GUI_OK
193 ////////////////////////////////////////////////////////////////////////
194
KeyDown(const SDL_keysym & key)195 GUI_Status SliderWidget::KeyDown( const SDL_keysym &key ) {
196 if ( key.sym == this->key ) {
197 Push();
198 if ( key.mod & (KMOD_LSHIFT|KMOD_RSHIFT) ) {
199 if ( current > min_level ) ScrollTo( current - keystep );
200 } else if ( current < max_level ) ScrollTo( current + keystep );
201 } else if ( flags & (WIDGET_HSCROLLKEY|WIDGET_VSCROLLKEY) ) {
202 switch( key.sym ) {
203 case SDLK_UP:
204 if ( (flags & WIDGET_VSCROLLKEY) && (current > min_level) ) {
205 Push();
206 ScrollTo( current - keystep );
207 }
208 break;
209 case SDLK_DOWN:
210 if ( (flags & WIDGET_VSCROLLKEY) && (current < max_level) ) {
211 Push();
212 ScrollTo( current + keystep );
213 }
214 break;
215
216 case SDLK_LEFT:
217 if ( (flags & WIDGET_HSCROLLKEY) && (current > min_level) ) {
218 Push();
219 ScrollTo( current - keystep );
220 }
221 break;
222 case SDLK_RIGHT:
223 if ( (flags & WIDGET_HSCROLLKEY) && (current < max_level) ) {
224 Push();
225 ScrollTo( current + keystep );
226 }
227 break;
228 default:
229 break;
230 }
231 }
232
233 return GUI_OK;
234 }
235
236 ////////////////////////////////////////////////////////////////////////
237 // NAME : SliderWidget::KeyUp
238 // DESCRIPTION: Release the knob if necessary.
239 // PARAMETERS : key - SDL_keysym received from the event handler
240 // RETURNS : GUI_OK
241 ////////////////////////////////////////////////////////////////////////
242
KeyUp(const SDL_keysym & key)243 GUI_Status SliderWidget::KeyUp( const SDL_keysym &key ) {
244 if ( Clicked() ) Release();
245 return GUI_OK;
246 }
247
248 ////////////////////////////////////////////////////////////////////////
249 // NAME : SliderWidget::MouseMove
250 // DESCRIPTION: Drag the knob after the mouse.
251 // PARAMETERS : motion - SDL_MouseMotionEvent from the event handler
252 // RETURNS : GUI_OK
253 ////////////////////////////////////////////////////////////////////////
254
MouseMove(const SDL_MouseMotionEvent & motion)255 GUI_Status SliderWidget::MouseMove( const SDL_MouseMotionEvent &motion ) {
256 if ( mousehit ) {
257
258 if ( max_level != min_level ) {
259 short val;
260
261 if ( flags & WIDGET_HSCROLL ) {
262 short dx = knob.x + motion.xrel;
263 knob.x = MIN( MAX( x + 1, dx ), x + w - 1 - knob.w );
264 val = (short)((knob.x - 1 - x + step/2) / step) + min_level;
265 } else {
266 short dy = knob.y + motion.yrel;
267 knob.y = MIN( MAX( y + 1, dy ), y + h - 1 - knob.h );
268 val = (short)((knob.y - 1 - y + step/2) / step) + min_level;
269 }
270
271 Draw();
272 Show();
273 if ( val != current ) {
274 current = MAX( min_level, MIN( val, max_level ) );
275 if ( hook ) hook->WidgetActivated( this, surface );
276 }
277 }
278 }
279 return GUI_OK;
280 }
281
282
283 ////////////////////////////////////////////////////////////////////////
284 // NAME : ProgressWidget::ProgressWidget
285 // DESCRIPTION: Create a new progress bar. Initially, the new progress
286 // bar will be empty.
287 // PARAMETERS : id - widget identifier
288 // x - left edge of widget
289 // y - top edge of widget
290 // w - widget width
291 // h - widget height
292 // vmin - value mapped to an empty bar
293 // vmax - value mapped to a completely filled bar
294 // flags - widget flags (see widget.h for details)
295 // title - widget title
296 // window - window to add this widget to
297 // RETURNS : -
298 ////////////////////////////////////////////////////////////////////////
299
ProgressWidget(short id,short x,short y,unsigned short w,unsigned short h,short vmin,short vmax,unsigned short flags,const char * title,Window * window)300 ProgressWidget::ProgressWidget( short id, short x, short y, unsigned short w,
301 unsigned short h, short vmin, short vmax, unsigned short flags,
302 const char *title, Window *window ) :
303 Widget( id, x, y, w, h, flags, title, window ),
304 level(0), min_level(vmin), max_level(vmax), col(CF_COLOR_HIGHLIGHT),
305 title_x(0), title_y(0) {
306 if ( title ) {
307 title_x = x + (w - font->TextWidth( title )) / 2;
308 title_y = y + (h - font->Height()) / 2;
309 }
310 }
311
312 ////////////////////////////////////////////////////////////////////////
313 // NAME : ProgressWidget::SetLevel
314 // DESCRIPTION: Fill the progress bar.
315 // PARAMETERS : lev - level up to which the bar should be filled. Must
316 // be between min and max. min will clear the bar,
317 // max will fill it completely.
318 // RETURNS : -
319 ////////////////////////////////////////////////////////////////////////
320
SetLevel(short lev)321 void ProgressWidget::SetLevel( short lev ) {
322 if ( lev < min_level ) lev = min_level;
323 else if ( lev > max_level ) lev = max_level;
324
325 level = lev - min_level;
326 Draw();
327 Show();
328 }
329
330 ////////////////////////////////////////////////////////////////////////
331 // NAME : ProgressWidget::Draw
332 // DESCRIPTION: Draw the progress bar.
333 // PARAMETERS : -
334 // RETURNS : -
335 ////////////////////////////////////////////////////////////////////////
336
Draw(void)337 void ProgressWidget::Draw( void ) {
338 surface->DrawBack( *this );
339 surface->DrawBox( *this, BOX_RECESSED );
340
341 if ( !Disabled() && (level > 0) ) {
342 unsigned short levsize = level * (Width() - 2) / (max_level - min_level);
343 surface->FillRectAlpha( x + 1, y + 1, levsize, h - 2, col );
344 }
345
346 PrintTitle( title_x, title_y, col );
347 }
348