]> icculus.org git repositories - taylor/freespace2.git/blob - src/ui/slider.cpp
only use app name for IndexedDB path (easier to clear data later)
[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 #ifdef MAKE_FS1
226                 // hack to deal with some sliders that have ten
227                 // positions but eleven frames
228                 if (has_end_buttons && (num_pos == 11)) {
229                         ++pos;
230                 }
231 #endif
232
233                 if (pos < 0){
234                         pos = 0;
235                 }
236
237                 // if we have 10 positions, 0 - 9 are valid
238                 if ( pos >= num_pos ) {
239                         pos = num_pos - 1;
240                 }
241
242                 return;
243         }
244
245         if ( has_end_buttons ) {
246                 up_button.process(focus);
247                 if (up_button.pressed()) {
248                         if (pos < num_pos-1){
249                                 pos++;
250                         } else {
251                                 gamesnd_play_iface(SND_GENERAL_FAIL);
252                         }
253                 }
254
255                 down_button.process(focus);
256                 if (down_button.pressed()) {
257                         if(pos){
258                                 pos--;
259                         } else {
260                                 gamesnd_play_iface(SND_GENERAL_FAIL);
261                         }
262                 }
263         }
264 }
265
266 //
267 // OLD DOT SLIDER - TO BE PHASED OUT. IF YOU NEED TO USE A UI_DOT_SLIDER, use a UI_DOT_SLIDER_NEW -------------------
268 //
269
270 /// DOT_SLIDER class down here
271 void UI_DOT_SLIDER::create(UI_WINDOW *wnd, int _x, int _y, const char *bm, int id, int end_buttons, int _num_pos)
272 {
273         char    filename[MAX_FILENAME_LEN];
274         int     bx, by, bw, hotspot;
275
276         has_end_buttons = end_buttons;
277
278         if ( has_end_buttons ) {
279                 bx = _x + 24;
280                 by = _y + 1;
281                 bw = 190;
282                 hotspot = id + 1;
283         } else {
284                 bx = _x;
285                 by = _y;
286                 bw = 80;
287                 hotspot = id;
288         }
289
290         num_pos = _num_pos;
291
292         SDL_snprintf(filename, SDL_arraysize(filename), "%s%.2d", bm, hotspot);
293         first_frame = bm_load_animation(filename, &total_frames);
294         if (first_frame < 0) {
295                 Error(LOCATION, "Could not load %s.ani\n", filename);
296                 disable();
297                 hide();
298                 return;
299         }
300
301         base_create(wnd, UI_KIND_DOT_SLIDER, bx, by, bw, 20);
302         pos = 0;
303
304         // A DOT_SLIDER has up to 3 child buttons..
305
306         by = _y;
307
308         // First button is the region with the dots
309         button.create( wnd, "", bx, by, bw, 20, 0, 1 );
310         button.set_parent(this);
311         button.link_hotspot(hotspot);
312         button.hide();
313
314         if ( has_end_buttons ) {
315                 // Second button is the up (increase) button
316                 SDL_snprintf(filename, SDL_arraysize(filename), "%s%.2d", bm, id + 2);
317                 up_button.create( wnd, "", _x + 216, _y, 22, 24, 1, 1 );
318                 up_button.set_parent(this);
319                 up_button.set_highlight_action(common_play_highlight_sound);
320                 up_button.set_bmaps(filename);
321                 up_button.link_hotspot(id + 2);
322
323                 // Third button is the down (decrease) button
324                 SDL_snprintf(filename, SDL_arraysize(filename), "%s%.2d", bm, id);
325                 down_button.create( wnd, "", _x, _y, 22, 24, 1, 1 );
326                 down_button.set_parent(this);
327                 down_button.set_highlight_action(common_play_highlight_sound);
328                 down_button.set_bmaps(filename);
329                 down_button.link_hotspot(id);
330         }
331 }
332
333 void UI_DOT_SLIDER::destroy()
334 {
335         int i;
336
337         // release ani frames for the dots.
338         for (i=0; i<total_frames; i++){
339                 bm_release(first_frame + i);
340         }
341
342         UI_GADGET::destroy();
343 }
344
345 void UI_DOT_SLIDER::draw()
346 {
347         if ( has_end_buttons ) {
348                 up_button.draw();
349                 down_button.draw();
350         }
351         SDL_assert((pos >= 0) && (pos <= num_pos));
352         gr_set_bitmap(first_frame + pos, GR_ALPHABLEND_NONE, GR_BITBLT_MODE_NORMAL, 1.0f, -1, -1);  // draw the dot level
353         gr_bitmap(x, y);
354 }
355
356 void UI_DOT_SLIDER::process(int focus)
357 {
358         if (disabled_flag)
359                 return;
360
361         // check focus and derived focus with one variable
362         if (my_wnd->selected_gadget == this)
363                 focus = 1;
364
365         // first check the dot area
366         button.process(focus);
367         if (button.button_down() || button.pressed() || mouse_captured()) {
368                 capture_mouse();  // while we are changing level, ignore all other buttons
369
370                 if ( has_end_buttons ) {
371                         pos = (ui_mouse.x - x + 17) / 19;
372                 } else {
373                         pos = (ui_mouse.x - x) / 19;
374                 }
375
376                 if (pos < 0){
377                         pos = 0;
378                 }
379
380                 if ( pos > num_pos ){
381                         pos = num_pos;
382                 }
383
384                 return;
385         }
386
387         if ( has_end_buttons ) {
388                 up_button.process(focus);
389                 if (up_button.pressed()) {
390                         if (pos < num_pos){
391                                 pos++;
392                         } else {
393                                 gamesnd_play_iface(SND_GENERAL_FAIL);
394                         }
395                 }
396
397                 down_button.process(focus);
398                 if (down_button.pressed()) {
399                         if (pos){
400                                 pos--;
401                         } else {
402                                 gamesnd_play_iface(SND_GENERAL_FAIL);
403                         }
404                 }
405         }
406 }
407
408 /*
409 // --------------------------------------------------------------------
410 // UI_SLIDER::link_hotspot
411 //
412 //
413 void UI_SLIDER::link_hotspot(int left_button_num, int right_button_num)
414 {
415         left_button.link_hotspot(left_button_num);
416         right_button.link_hotspot(right_button_num);
417 }
418
419 // --------------------------------------------------------------------
420 // UI_SLIDER::set_bmaps
421 //
422 // Call the UI_GADGET::set_bmaps() function for the child components
423 // of a scroll bar (the up and down button).  Set up the bmaps for the
424 // line itself.
425 //
426 // We also need to get the dimensions of the bitmap button so we can update
427 // the dimensions of the scrollbar.
428 //
429 // returns:             -1 ==> error
430 //                                       0 ==> success
431 //
432 int UI_SLIDER::set_bmaps(char *left_button_fname, char *right_button_fname, char *bar_fname, char *marker_fname)
433 {
434         int m_w,m_h;
435
436         left_button.set_bmaps(left_button_fname);
437         right_button.set_bmaps(right_button_fname);
438         
439         // set the bitmaps for the rectangle that is the scrollbar itself
440         ((UI_GADGET*)this)->set_bmaps(bar_fname);
441         ((UI_GADGET*)this)->set_bmaps(marker_fname,2);  // skip the first two bitmaps 
442
443         bm_get_info( bmap_ids[SLIDER_MARKER_NORMAL], &m_w, &m_h, NULL );
444         // force the slider dimensions based on size of marker bitmap
445         w = n_positions * m_w;
446         marker_w = m_w;
447         marker_h = m_h;
448         pixel_range = w-marker_w;
449         increment = pixel_range / n_positions;
450
451         right_button.update_dimensions(x+w, y, -1, -1);
452
453         uses_bmaps = 1;
454
455         return 0;
456 }
457
458 void UI_SLIDER::hide()
459 {
460         hidden = 1;
461         left_button.hide();
462         right_button.hide();
463 }
464
465 void UI_SLIDER::unhide()
466 {
467         hidden = 0;
468         left_button.unhide();
469         right_button.unhide();
470 }
471
472 int UI_SLIDER::get_hidden()
473 {
474         return hidden;
475 }
476
477 void UI_SLIDER::create(UI_WINDOW *wnd, int _x, int _y, int _w, int _h, float _start, float _stop, float _current, int _n_positions )
478 {
479         char *up = "<";
480         char *down = ">";
481         int bw, bh, real_w;
482         bw=bh=_h;
483         real_w = _n_positions*bw;
484         base_create( wnd, UI_KIND_SLIDER, _x, _y, real_w, _h);
485
486         left_button.create( wnd, up, _x-bw, _y, _h, _h );
487         left_button.set_parent(this);
488
489         right_button.create( wnd, down, _x+real_w, _y, bh, bh );
490         right_button.set_parent(this);
491
492         horz = 0;
493         start = _start;
494         stop = _stop;
495         current = _current;
496
497         SDL_assert( _current >= _start );
498         SDL_assert( _current <= _stop );
499         SDL_assert( stop >= 0 );
500
501         n_positions = _n_positions;
502
503         dragging = 0;
504         last_scrolled = 0;
505         moved = 1;
506
507         marker_w = _h;
508         marker_h = _h;
509
510         pixel_range = w-marker_w;
511         marker_x = x + fl2i( ( (current - start)/(stop-start) * pixel_range ) );
512         increment = pixel_range / n_positions;
513         SDL_assert(increment >= 1);
514         mouse_locked = 0;
515 };
516
517 void UI_SLIDER::draw()
518 {
519         if ( uses_bmaps ) {
520                 gr_reset_clip();
521                 if ( disabled_flag ) {
522                         if ( bmap_ids[SLIDER_BAR_DISABLED] != -1 ) {
523                                 gr_set_bitmap(bmap_ids[SLIDER_BAR_DISABLED]);
524                                 gr_bitmap(x,y);
525                         }
526
527                         if ( bmap_ids[SLIDER_MARKER_DISABLED] != -1 ) {
528                                 gr_set_bitmap(bmap_ids[SLIDER_MARKER_DISABLED]);
529                                 gr_bitmap(marker_x,marker_y);
530                         }
531
532                 }
533                 else {
534                         if ( bmap_ids[SLIDER_BAR_NORMAL] != -1 ) {
535                                 gr_set_bitmap(bmap_ids[SLIDER_BAR_NORMAL]);
536                                 gr_bitmap(x,y);
537                         }
538
539                         if ( bmap_ids[SLIDER_MARKER_NORMAL] != -1 ) {
540                                 gr_set_bitmap(bmap_ids[SLIDER_MARKER_NORMAL]);
541                                 gr_bitmap(marker_x,marker_y);
542                         }
543                 }
544         }
545         else {
546                 gr_set_font(my_wnd->f_id);
547                 gr_set_clip( x, y, w, h );
548
549                 if (my_wnd->selected_gadget == this)
550                         gr_set_color_fast( &CBRIGHT_GREEN );
551                 else
552                         gr_set_color_fast( &CGRAY );
553
554                 ui_rect( 0, 0, w-1, h-1 );
555
556                 gr_set_clip( marker_x, marker_y, w, h );
557                 ui_draw_box_out(0, 0, marker_w, marker_h);
558         }
559 }
560
561 void UI_SLIDER::process(int focus)
562 {
563         int OnMe, OnMarker, keyfocus;
564         int oldpos, op;
565         float percent;
566         moved = 0;
567
568         if (disabled_flag) {
569                 return;
570         }
571
572         if (my_wnd->selected_gadget == this)
573                 keyfocus = 1;
574
575         left_button.process(focus);
576         right_button.process(focus);
577
578         marker_y = y;
579         keyfocus = 0;
580
581         if (start == stop) {
582                 marker_x = x;
583                 return;
584         }
585
586         op = marker_x;
587         oldpos = fake_position;
588
589         OnMarker = 0;
590         OnMe = is_mouse_on();
591         if ( OnMe ) {
592                 if ( ui_mouse.x >= (marker_x ) && ui_mouse.x <= (marker_x+marker_w) ) {
593                         OnMarker = 1;
594                         if ( B1_PRESSED )
595                                 mouse_locked = 1;
596                 }
597         }
598
599         if ( !B1_PRESSED) {
600                 mouse_locked = 0;
601         }
602
603         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 ) )  {
604                 if ( (timer_get_milliseconds() > last_scrolled+50) || left_button.just_pressed() || B1_JUST_PRESSED || mouse_locked || my_wnd->keypress == SDLK_LEFT)   {
605                         if ( left_button.just_pressed() || B1_JUST_PRESSED || mouse_locked || my_wnd->keypress == SDLK_LEFT )   {
606                                 last_scrolled = timer_get_milliseconds() + 300;
607                         } else
608                                 last_scrolled = timer_get_milliseconds();
609                         marker_x -= increment;
610                         if (marker_x < x )
611                                 marker_x = x;
612                 }
613         }
614
615         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) ) {
616                 if ( (timer_get_milliseconds() > last_scrolled+50) || right_button.just_pressed() || B1_JUST_PRESSED || mouse_locked || my_wnd->keypress == SDLK_RIGHT) {
617                         if ( right_button.just_pressed() || B1_JUST_PRESSED || mouse_locked || my_wnd->keypress == SDLK_RIGHT)
618                                 last_scrolled = timer_get_milliseconds() + 300;
619                         else
620                                 last_scrolled = timer_get_milliseconds();
621                         marker_x += increment;
622                         if (marker_x > (x+n_positions*increment) )
623                                 marker_x = x+n_positions*increment;
624                 }
625         }
626
627         percent = i2fl(marker_x - x)/i2fl(pixel_range);
628         current = percent * (stop - start);
629 }
630
631 int UI_SLIDER::getpos()
632 {
633         return marker_x;
634 }
635
636 float UI_SLIDER::getcurrent()
637 {
638         return current;
639 }
640
641 int UI_SLIDER::changed()
642 {
643         return moved;
644 }
645 */
646