]> icculus.org git repositories - taylor/freespace2.git/blob - src/ui/slider.cpp
use a better multi_sw_ok_to_commit() check
[taylor/freespace2.git] / src / ui / slider.cpp
1 /*
2  * Copyright (C) Volition, Inc. 1999.  All rights reserved.
3  *
4  * All source code herein is the property of Volition, Inc. You may not sell 
5  * or otherwise commercially exploit the source or things you created based on
6  * the source.
7  */
8
9 /*
10  * $Logfile: /Freespace2/code/Ui/slider.cpp $
11  * $Revision$
12  * $Date$
13  * $Author$
14  *
15  * C++ file for controlling and displaying a horizontal slider
16  *
17  * $Log$
18  * Revision 1.6  2005/10/01 21:55:00  taylor
19  * fix a small bug in UI_GADGET that could leave a control animation loaded in memory without a way to unload it
20  * allow a slider with no defined hotspot to function properly (fixes the FS1 skill slider mask problem)
21  *
22  * Revision 1.5  2004/09/20 01:31:45  theoddone33
23  * GCC 3.4 fixes.
24  *
25  * Revision 1.4  2002/07/13 19:47:02  theoddone33
26  * Fix some more warnings
27  *
28  * Change demo building, edit Makefile if you want the demo.
29  *
30  * Revision 1.3  2002/06/09 04:41:29  relnev
31  * added copyright header
32  *
33  * Revision 1.2  2002/05/07 03:16:53  theoddone33
34  * The Great Newline Fix
35  *
36  * Revision 1.1.1.1  2002/05/03 03:28:11  root
37  * Initial import.
38  *
39  * 
40  * 8     8/10/99 6:54p Dave
41  * Mad optimizations. Added paging to the nebula effect.
42  * 
43  * 7     8/02/99 6:04p Jefff
44  * use_hack_to_get_around_stupid_problem_flag extended to sliders
45  * 
46  * 6     5/03/99 8:33p Dave
47  * New version of multi host options screen.
48  * 
49  * 5     2/11/99 3:08p Dave
50  * PXO refresh button. Very preliminary squad war support.
51  * 
52  * 4     12/02/98 5:47p Dave
53  * Put in interface xstr code. Converted barracks screen to new format.
54  * 
55  * 3     10/13/98 9:29a Dave
56  * Started neatening up freespace.h. Many variables renamed and
57  * reorganized. Added AlphaColors.[h,cpp]
58  * 
59  * 2     10/07/98 10:54a Dave
60  * Initial checkin.
61  * 
62  * 1     10/07/98 10:51a Dave
63  * 
64  * 12    4/17/98 10:34a Hoffoss
65  * Fixed dot slider positionings.
66  * 
67  * 11    3/22/98 10:50p Lawrance
68  * Allow sliders to not have end-buttons.
69  * 
70  * 10    2/03/98 4:21p Hoffoss
71  * Made UI controls draw white text when disabled.
72  * 
73  * 9     1/30/98 11:59a Hoffoss
74  * changed offset of slider child button.
75  * 
76  * 8     1/27/98 7:02p Lawrance
77  * Don't play the "mouse over" sound for the volume circles.
78  * 
79  * 7     1/15/98 12:00p Hoffoss
80  * Embelished file with nifty comments.
81  * 
82  * 6     1/14/98 6:44p Hoffoss
83  * Massive changes to UI code.  A lot cleaner and better now.  Did all
84  * this to get the new UI_DOT_SLIDER to work properly, which the old code
85  * wasn't flexible enough to handle.
86  * 
87  * 5     8/24/97 5:25p Lawrance
88  * improve drawing of buttons 
89  * 
90  * 4     6/12/97 12:39p John
91  * made ui use freespace colors
92  * 
93  * 3     6/11/97 1:13p John
94  * Started fixing all the text colors in the game.
95  * 
96  * 2     5/26/97 10:26a Lawrance
97  * get slider control working 100%
98  *
99  * $NoKeywords: $
100  */
101
102
103 #include "uidefs.h"
104 #include "ui.h"
105 #include "timer.h"
106
107 #include "missionscreencommon.h"
108 #include "bmpman.h"
109 #include "gamesnd.h"
110 #include "alphacolors.h"
111
112 /// DOT_SLIDER class down here
113 void UI_DOT_SLIDER_NEW::create(UI_WINDOW *wnd, int _x, int _y, int _num_pos, const char *bm_slider, int slider_mask,
114                                                                                                                                                                         const char *bm_left, int left_mask, int left_x, int left_y,
115                                                                                                                                                                         const char *bm_right, int right_mask, int right_x, int right_y,
116                                                                                                                                                                         int _dot_width)
117 {
118         // no end buttons yet
119         has_end_buttons = 0;
120
121         // if any of the left/right arrow information is specified, make sure its _all_ specified
122         if((bm_left != NULL) || (left_mask != -1) || (bm_right != NULL) || (right_mask != -1)){
123                 SDL_assert((bm_left != NULL) && (left_mask >= 0) && (bm_right != NULL) && (right_mask >= 0));
124                 if((bm_left == NULL) || (left_mask < 0) || (bm_right == NULL) || (right_mask < 0)){
125                         return;
126                 }
127
128                 // now we know we have end buttons
129                 has_end_buttons = 1;
130         }
131
132         // internal stuff
133         num_pos = _num_pos;
134         base_create(wnd, UI_KIND_DOT_SLIDER_NEW, _x, _y, 0, 20);
135         pos = 0;                
136         dot_width = _dot_width; 
137
138         // set bitmaps for the slider itself    
139         button.create( wnd, "", _x, _y, 0, 0, 0, 1 );
140         button.set_parent(this);
141         if (slider_mask == -1) {
142                 // this lets us take advantage of the fact that UI_GADGET allows for no mask hotspot
143                 // and for FS1 that's needed for the freaky skill slider in the options screen - taylor
144                 int _bw, _bh;
145                 button.set_bmaps(bm_slider, num_pos, 0);
146
147                 if (button.bmap_ids[0] >= 0) {
148                         bm_get_info(button.bmap_ids[0], &_bw, &_bh);
149                         button.update_dimensions(_x, _y, _bw, _bh);
150                 }
151         } else {
152                 button.link_hotspot(slider_mask);
153                 button.set_bmaps(bm_slider, num_pos, 0);
154         }
155         button.hide();
156                 
157         // maybe setup buttons for the arrows
158         if ( has_end_buttons ) {
159                 // Second button is the up (increase) button            
160                 up_button.create( wnd, "", right_x, right_y, 0, 0, 1, 1 );
161                 up_button.set_parent(this);
162                 up_button.set_highlight_action(common_play_highlight_sound);
163                 up_button.link_hotspot(right_mask);
164                 up_button.set_bmaps(bm_right);          
165
166                 // Third button is the down (decrease) button           
167                 down_button.create( wnd, "", left_x, left_y, 0, 0, 1, 1 );
168                 down_button.set_parent(this);
169                 down_button.set_highlight_action(common_play_highlight_sound);
170                 down_button.link_hotspot(left_mask);
171                 down_button.set_bmaps(bm_left);         
172         }
173 }
174
175 void UI_DOT_SLIDER_NEW::draw()
176 {
177         // draw end buttons
178         if ( has_end_buttons ) {
179                 up_button.draw();
180                 down_button.draw();
181         }
182         
183         // draw the proper dot
184         SDL_assert((pos >= 0) && (pos <= num_pos));     
185         
186         // for position -1, we don't draw (no dots)     
187         if(pos >= 0){
188                 button.unhide();        
189                 button.draw_forced(pos);
190                 button.hide();          
191         }
192 }
193
194 void UI_DOT_SLIDER_NEW::process(int focus)
195 {
196         if (disabled_flag) {
197                 if (!hidden && !my_wnd->use_hack_to_get_around_stupid_problem_flag) {
198                         if (button.is_mouse_on() && B1_JUST_PRESSED) {
199                                 gamesnd_play_iface(SND_GENERAL_FAIL);
200                         } else if (has_end_buttons && (up_button.is_mouse_on() || down_button.is_mouse_on())) {
201                                 gamesnd_play_iface(SND_GENERAL_FAIL);
202                         }
203                         
204
205                         if ( (hotkey >= 0) && (my_wnd->keypress == hotkey) ){
206                                 gamesnd_play_iface(SND_GENERAL_FAIL);
207                         }
208                 }
209
210                 return;
211         }
212
213         // check focus and derived focus with one variable
214         if (my_wnd->selected_gadget == this){
215                 focus = 1;
216         }
217
218         // first check the dot area
219         button.process(focus);
220         if (button.button_down() || button.pressed() || mouse_captured()) {
221                 capture_mouse();  // while we are changing level, ignore all other buttons
222                 
223                 pos = (ui_mouse.x - x) / dot_width;             
224
225                 if (pos < 0){
226                         pos = 0;
227                 }
228
229                 // if we have 10 positions, 0 - 9 are valid
230                 if ( pos >= num_pos ) {
231                         pos = num_pos - 1;
232                 }
233
234                 return;
235         }
236
237         if ( has_end_buttons ) {
238                 up_button.process(focus);
239                 if (up_button.pressed()) {
240                         if (pos < num_pos-1){
241                                 pos++;
242                         } else {
243                                 gamesnd_play_iface(SND_GENERAL_FAIL);
244                         }
245                 }
246
247                 down_button.process(focus);
248                 if (down_button.pressed()) {
249                         if(pos){
250                                 pos--;
251                         } else {
252                                 gamesnd_play_iface(SND_GENERAL_FAIL);
253                         }
254                 }
255         }
256 }
257
258 //
259 // OLD DOT SLIDER - TO BE PHASED OUT. IF YOU NEED TO USE A UI_DOT_SLIDER, use a UI_DOT_SLIDER_NEW -------------------
260 //
261
262 /// DOT_SLIDER class down here
263 void UI_DOT_SLIDER::create(UI_WINDOW *wnd, int _x, int _y, const char *bm, int id, int end_buttons, int _num_pos)
264 {
265         char    filename[MAX_FILENAME_LEN];
266         int     bx, by, bw, hotspot;
267
268         has_end_buttons = end_buttons;
269
270         if ( has_end_buttons ) {
271                 bx = _x + 24;
272                 by = _y + 1;
273                 bw = 190;
274                 hotspot = id + 1;
275         } else {
276                 bx = _x;
277                 by = _y;
278                 bw = 80;
279                 hotspot = id;
280         }
281
282         num_pos = _num_pos;
283
284         SDL_snprintf(filename, SDL_arraysize(filename), "%s%.2d", bm, hotspot);
285         first_frame = bm_load_animation(filename, &total_frames);
286         if (first_frame < 0) {
287                 Error(LOCATION, "Could not load %s.ani\n", filename);
288                 disable();
289                 hide();
290                 return;
291         }
292
293         base_create(wnd, UI_KIND_DOT_SLIDER, bx, by, bw, 20);
294         pos = 0;
295
296         // A DOT_SLIDER has up to 3 child buttons..
297
298         by = _y;
299
300         // First button is the region with the dots
301         button.create( wnd, "", bx, by, bw, 20, 0, 1 );
302         button.set_parent(this);
303         button.link_hotspot(hotspot);
304         button.hide();
305
306         if ( has_end_buttons ) {
307                 // Second button is the up (increase) button
308                 SDL_snprintf(filename, SDL_arraysize(filename), "%s%.2d", bm, id + 2);
309                 up_button.create( wnd, "", _x + 216, _y, 22, 24, 1, 1 );
310                 up_button.set_parent(this);
311                 up_button.set_highlight_action(common_play_highlight_sound);
312                 up_button.set_bmaps(filename);
313                 up_button.link_hotspot(id + 2);
314
315                 // Third button is the down (decrease) button
316                 SDL_snprintf(filename, SDL_arraysize(filename), "%s%.2d", bm, id);
317                 down_button.create( wnd, "", _x, _y, 22, 24, 1, 1 );
318                 down_button.set_parent(this);
319                 down_button.set_highlight_action(common_play_highlight_sound);
320                 down_button.set_bmaps(filename);
321                 down_button.link_hotspot(id);
322         }
323 }
324
325 void UI_DOT_SLIDER::destroy()
326 {
327         int i;
328
329         // release ani frames for the dots.
330         for (i=0; i<total_frames; i++){
331                 bm_release(first_frame + i);
332         }
333
334         UI_GADGET::destroy();
335 }
336
337 void UI_DOT_SLIDER::draw()
338 {
339         if ( has_end_buttons ) {
340                 up_button.draw();
341                 down_button.draw();
342         }
343         SDL_assert((pos >= 0) && (pos <= num_pos));
344         gr_set_bitmap(first_frame + pos, GR_ALPHABLEND_NONE, GR_BITBLT_MODE_NORMAL, 1.0f, -1, -1);  // draw the dot level
345         gr_bitmap(x, y);
346 }
347
348 void UI_DOT_SLIDER::process(int focus)
349 {
350         if (disabled_flag)
351                 return;
352
353         // check focus and derived focus with one variable
354         if (my_wnd->selected_gadget == this)
355                 focus = 1;
356
357         // first check the dot area
358         button.process(focus);
359         if (button.button_down() || button.pressed() || mouse_captured()) {
360                 capture_mouse();  // while we are changing level, ignore all other buttons
361
362                 if ( has_end_buttons ) {
363                         pos = (ui_mouse.x - x + 17) / 19;
364                 } else {
365                         pos = (ui_mouse.x - x) / 19;
366                 }
367
368                 if (pos < 0){
369                         pos = 0;
370                 }
371
372                 if ( pos > num_pos ){
373                         pos = num_pos;
374                 }
375
376                 return;
377         }
378
379         if ( has_end_buttons ) {
380                 up_button.process(focus);
381                 if (up_button.pressed()) {
382                         if (pos < num_pos){
383                                 pos++;
384                         } else {
385                                 gamesnd_play_iface(SND_GENERAL_FAIL);
386                         }
387                 }
388
389                 down_button.process(focus);
390                 if (down_button.pressed()) {
391                         if (pos){
392                                 pos--;
393                         } else {
394                                 gamesnd_play_iface(SND_GENERAL_FAIL);
395                         }
396                 }
397         }
398 }
399
400 /*
401 // --------------------------------------------------------------------
402 // UI_SLIDER::link_hotspot
403 //
404 //
405 void UI_SLIDER::link_hotspot(int left_button_num, int right_button_num)
406 {
407         left_button.link_hotspot(left_button_num);
408         right_button.link_hotspot(right_button_num);
409 }
410
411 // --------------------------------------------------------------------
412 // UI_SLIDER::set_bmaps
413 //
414 // Call the UI_GADGET::set_bmaps() function for the child components
415 // of a scroll bar (the up and down button).  Set up the bmaps for the
416 // line itself.
417 //
418 // We also need to get the dimensions of the bitmap button so we can update
419 // the dimensions of the scrollbar.
420 //
421 // returns:             -1 ==> error
422 //                                       0 ==> success
423 //
424 int UI_SLIDER::set_bmaps(char *left_button_fname, char *right_button_fname, char *bar_fname, char *marker_fname)
425 {
426         int m_w,m_h;
427
428         left_button.set_bmaps(left_button_fname);
429         right_button.set_bmaps(right_button_fname);
430         
431         // set the bitmaps for the rectangle that is the scrollbar itself
432         ((UI_GADGET*)this)->set_bmaps(bar_fname);
433         ((UI_GADGET*)this)->set_bmaps(marker_fname,2);  // skip the first two bitmaps 
434
435         bm_get_info( bmap_ids[SLIDER_MARKER_NORMAL], &m_w, &m_h, NULL );
436         // force the slider dimensions based on size of marker bitmap
437         w = n_positions * m_w;
438         marker_w = m_w;
439         marker_h = m_h;
440         pixel_range = w-marker_w;
441         increment = pixel_range / n_positions;
442
443         right_button.update_dimensions(x+w, y, -1, -1);
444
445         uses_bmaps = 1;
446
447         return 0;
448 }
449
450 void UI_SLIDER::hide()
451 {
452         hidden = 1;
453         left_button.hide();
454         right_button.hide();
455 }
456
457 void UI_SLIDER::unhide()
458 {
459         hidden = 0;
460         left_button.unhide();
461         right_button.unhide();
462 }
463
464 int UI_SLIDER::get_hidden()
465 {
466         return hidden;
467 }
468
469 void UI_SLIDER::create(UI_WINDOW *wnd, int _x, int _y, int _w, int _h, float _start, float _stop, float _current, int _n_positions )
470 {
471         char *up = "<";
472         char *down = ">";
473         int bw, bh, real_w;
474         bw=bh=_h;
475         real_w = _n_positions*bw;
476         base_create( wnd, UI_KIND_SLIDER, _x, _y, real_w, _h);
477
478         left_button.create( wnd, up, _x-bw, _y, _h, _h );
479         left_button.set_parent(this);
480
481         right_button.create( wnd, down, _x+real_w, _y, bh, bh );
482         right_button.set_parent(this);
483
484         horz = 0;
485         start = _start;
486         stop = _stop;
487         current = _current;
488
489         SDL_assert( _current >= _start );
490         SDL_assert( _current <= _stop );
491         SDL_assert( stop >= 0 );
492
493         n_positions = _n_positions;
494
495         dragging = 0;
496         last_scrolled = 0;
497         moved = 1;
498
499         marker_w = _h;
500         marker_h = _h;
501
502         pixel_range = w-marker_w;
503         marker_x = x + fl2i( ( (current - start)/(stop-start) * pixel_range ) );
504         increment = pixel_range / n_positions;
505         SDL_assert(increment >= 1);
506         mouse_locked = 0;
507 };
508
509 void UI_SLIDER::draw()
510 {
511         if ( uses_bmaps ) {
512                 gr_reset_clip();
513                 if ( disabled_flag ) {
514                         if ( bmap_ids[SLIDER_BAR_DISABLED] != -1 ) {
515                                 gr_set_bitmap(bmap_ids[SLIDER_BAR_DISABLED]);
516                                 gr_bitmap(x,y);
517                         }
518
519                         if ( bmap_ids[SLIDER_MARKER_DISABLED] != -1 ) {
520                                 gr_set_bitmap(bmap_ids[SLIDER_MARKER_DISABLED]);
521                                 gr_bitmap(marker_x,marker_y);
522                         }
523
524                 }
525                 else {
526                         if ( bmap_ids[SLIDER_BAR_NORMAL] != -1 ) {
527                                 gr_set_bitmap(bmap_ids[SLIDER_BAR_NORMAL]);
528                                 gr_bitmap(x,y);
529                         }
530
531                         if ( bmap_ids[SLIDER_MARKER_NORMAL] != -1 ) {
532                                 gr_set_bitmap(bmap_ids[SLIDER_MARKER_NORMAL]);
533                                 gr_bitmap(marker_x,marker_y);
534                         }
535                 }
536         }
537         else {
538                 gr_set_font(my_wnd->f_id);
539                 gr_set_clip( x, y, w, h );
540
541                 if (my_wnd->selected_gadget == this)
542                         gr_set_color_fast( &CBRIGHT_GREEN );
543                 else
544                         gr_set_color_fast( &CGRAY );
545
546                 ui_rect( 0, 0, w-1, h-1 );
547
548                 gr_set_clip( marker_x, marker_y, w, h );
549                 ui_draw_box_out(0, 0, marker_w, marker_h);
550         }
551 }
552
553 void UI_SLIDER::process(int focus)
554 {
555         int OnMe, OnMarker, keyfocus;
556         int oldpos, op;
557         float percent;
558         moved = 0;
559
560         if (disabled_flag) {
561                 return;
562         }
563
564         if (my_wnd->selected_gadget == this)
565                 keyfocus = 1;
566
567         left_button.process(focus);
568         right_button.process(focus);
569
570         marker_y = y;
571         keyfocus = 0;
572
573         if (start == stop) {
574                 marker_x = x;
575                 return;
576         }
577
578         op = marker_x;
579         oldpos = fake_position;
580
581         OnMarker = 0;
582         OnMe = is_mouse_on();
583         if ( OnMe ) {
584                 if ( ui_mouse.x >= (marker_x ) && ui_mouse.x <= (marker_x+marker_w) ) {
585                         OnMarker = 1;
586                         if ( B1_PRESSED )
587                                 mouse_locked = 1;
588                 }
589         }
590
591         if ( !B1_PRESSED) {
592                 mouse_locked = 0;
593         }
594
595         if ( (left_button.position!=0) || (keyfocus && key_pressed(SDLK_LEFT)) || ( OnMe && B1_PRESSED && ui_mouse.x < marker_x) || (mouse_locked && ui_mouse.x < marker_x ) )  {
596                 if ( (timer_get_milliseconds() > last_scrolled+50) || left_button.just_pressed() || B1_JUST_PRESSED || mouse_locked || my_wnd->keypress == SDLK_LEFT)   {
597                         if ( left_button.just_pressed() || B1_JUST_PRESSED || mouse_locked || my_wnd->keypress == SDLK_LEFT )   {
598                                 last_scrolled = timer_get_milliseconds() + 300;
599                         } else
600                                 last_scrolled = timer_get_milliseconds();
601                         marker_x -= increment;
602                         if (marker_x < x )
603                                 marker_x = x;
604                 }
605         }
606
607         if ( (right_button.position!=0) || (keyfocus && key_pressed(SDLK_RIGHT)) || ( OnMe && B1_PRESSED && ui_mouse.x > (marker_x+marker_w)) || (mouse_locked && ui_mouse.x > marker_x+marker_w) ) {
608                 if ( (timer_get_milliseconds() > last_scrolled+50) || right_button.just_pressed() || B1_JUST_PRESSED || mouse_locked || my_wnd->keypress == SDLK_RIGHT) {
609                         if ( right_button.just_pressed() || B1_JUST_PRESSED || mouse_locked || my_wnd->keypress == SDLK_RIGHT)
610                                 last_scrolled = timer_get_milliseconds() + 300;
611                         else
612                                 last_scrolled = timer_get_milliseconds();
613                         marker_x += increment;
614                         if (marker_x > (x+n_positions*increment) )
615                                 marker_x = x+n_positions*increment;
616                 }
617         }
618
619         percent = i2fl(marker_x - x)/i2fl(pixel_range);
620         current = percent * (stop - start);
621 }
622
623 int UI_SLIDER::getpos()
624 {
625         return marker_x;
626 }
627
628 float UI_SLIDER::getcurrent()
629 {
630         return current;
631 }
632
633 int UI_SLIDER::changed()
634 {
635         return moved;
636 }
637 */
638