2 * Copyright (C) Volition, Inc. 1999. All rights reserved.
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
10 * $Logfile: /Freespace2/code/Ui/slider.cpp $
15 * C++ file for controlling and displaying a horizontal slider
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)
22 * Revision 1.5 2004/09/20 01:31:45 theoddone33
25 * Revision 1.4 2002/07/13 19:47:02 theoddone33
26 * Fix some more warnings
28 * Change demo building, edit Makefile if you want the demo.
30 * Revision 1.3 2002/06/09 04:41:29 relnev
31 * added copyright header
33 * Revision 1.2 2002/05/07 03:16:53 theoddone33
34 * The Great Newline Fix
36 * Revision 1.1.1.1 2002/05/03 03:28:11 root
40 * 8 8/10/99 6:54p Dave
41 * Mad optimizations. Added paging to the nebula effect.
43 * 7 8/02/99 6:04p Jefff
44 * use_hack_to_get_around_stupid_problem_flag extended to sliders
46 * 6 5/03/99 8:33p Dave
47 * New version of multi host options screen.
49 * 5 2/11/99 3:08p Dave
50 * PXO refresh button. Very preliminary squad war support.
52 * 4 12/02/98 5:47p Dave
53 * Put in interface xstr code. Converted barracks screen to new format.
55 * 3 10/13/98 9:29a Dave
56 * Started neatening up freespace.h. Many variables renamed and
57 * reorganized. Added AlphaColors.[h,cpp]
59 * 2 10/07/98 10:54a Dave
62 * 1 10/07/98 10:51a Dave
64 * 12 4/17/98 10:34a Hoffoss
65 * Fixed dot slider positionings.
67 * 11 3/22/98 10:50p Lawrance
68 * Allow sliders to not have end-buttons.
70 * 10 2/03/98 4:21p Hoffoss
71 * Made UI controls draw white text when disabled.
73 * 9 1/30/98 11:59a Hoffoss
74 * changed offset of slider child button.
76 * 8 1/27/98 7:02p Lawrance
77 * Don't play the "mouse over" sound for the volume circles.
79 * 7 1/15/98 12:00p Hoffoss
80 * Embelished file with nifty comments.
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.
87 * 5 8/24/97 5:25p Lawrance
88 * improve drawing of buttons
90 * 4 6/12/97 12:39p John
91 * made ui use freespace colors
93 * 3 6/11/97 1:13p John
94 * Started fixing all the text colors in the game.
96 * 2 5/26/97 10:26a Lawrance
97 * get slider control working 100%
107 #include "missionscreencommon.h"
110 #include "alphacolors.h"
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,
118 // no end buttons yet
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)){
128 // now we know we have end buttons
134 base_create(wnd, UI_KIND_DOT_SLIDER_NEW, _x, _y, 0, 20);
136 dot_width = _dot_width;
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
145 button.set_bmaps(bm_slider, num_pos, 0);
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);
152 button.link_hotspot(slider_mask);
153 button.set_bmaps(bm_slider, num_pos, 0);
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);
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);
175 void UI_DOT_SLIDER_NEW::draw()
178 if ( has_end_buttons ) {
183 // draw the proper dot
184 SDL_assert((pos >= 0) && (pos <= num_pos));
186 // for position -1, we don't draw (no dots)
189 button.draw_forced(pos);
194 void UI_DOT_SLIDER_NEW::process(int focus)
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);
205 if ( (hotkey >= 0) && (my_wnd->keypress == hotkey) ){
206 gamesnd_play_iface(SND_GENERAL_FAIL);
213 // check focus and derived focus with one variable
214 if (my_wnd->selected_gadget == this){
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
223 pos = (ui_mouse.x - x) / dot_width;
226 // hack to deal with some sliders that have ten
227 // positions but eleven frames
228 if (has_end_buttons && (num_pos == 11)) {
237 // if we have 10 positions, 0 - 9 are valid
238 if ( pos >= num_pos ) {
245 if ( has_end_buttons ) {
246 up_button.process(focus);
247 if (up_button.pressed()) {
248 if (pos < num_pos-1){
251 gamesnd_play_iface(SND_GENERAL_FAIL);
255 down_button.process(focus);
256 if (down_button.pressed()) {
260 gamesnd_play_iface(SND_GENERAL_FAIL);
267 // OLD DOT SLIDER - TO BE PHASED OUT. IF YOU NEED TO USE A UI_DOT_SLIDER, use a UI_DOT_SLIDER_NEW -------------------
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)
273 char filename[MAX_FILENAME_LEN];
274 int bx, by, bw, hotspot;
276 has_end_buttons = end_buttons;
278 if ( has_end_buttons ) {
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);
301 base_create(wnd, UI_KIND_DOT_SLIDER, bx, by, bw, 20);
304 // A DOT_SLIDER has up to 3 child buttons..
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);
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);
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);
333 void UI_DOT_SLIDER::destroy()
337 // release ani frames for the dots.
338 for (i=0; i<total_frames; i++){
339 bm_release(first_frame + i);
342 UI_GADGET::destroy();
345 void UI_DOT_SLIDER::draw()
347 if ( has_end_buttons ) {
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
356 void UI_DOT_SLIDER::process(int focus)
361 // check focus and derived focus with one variable
362 if (my_wnd->selected_gadget == this)
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
370 if ( has_end_buttons ) {
371 pos = (ui_mouse.x - x + 17) / 19;
373 pos = (ui_mouse.x - x) / 19;
380 if ( pos > num_pos ){
387 if ( has_end_buttons ) {
388 up_button.process(focus);
389 if (up_button.pressed()) {
393 gamesnd_play_iface(SND_GENERAL_FAIL);
397 down_button.process(focus);
398 if (down_button.pressed()) {
402 gamesnd_play_iface(SND_GENERAL_FAIL);
409 // --------------------------------------------------------------------
410 // UI_SLIDER::link_hotspot
413 void UI_SLIDER::link_hotspot(int left_button_num, int right_button_num)
415 left_button.link_hotspot(left_button_num);
416 right_button.link_hotspot(right_button_num);
419 // --------------------------------------------------------------------
420 // UI_SLIDER::set_bmaps
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
426 // We also need to get the dimensions of the bitmap button so we can update
427 // the dimensions of the scrollbar.
429 // returns: -1 ==> error
432 int UI_SLIDER::set_bmaps(char *left_button_fname, char *right_button_fname, char *bar_fname, char *marker_fname)
436 left_button.set_bmaps(left_button_fname);
437 right_button.set_bmaps(right_button_fname);
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
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;
448 pixel_range = w-marker_w;
449 increment = pixel_range / n_positions;
451 right_button.update_dimensions(x+w, y, -1, -1);
458 void UI_SLIDER::hide()
465 void UI_SLIDER::unhide()
468 left_button.unhide();
469 right_button.unhide();
472 int UI_SLIDER::get_hidden()
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 )
483 real_w = _n_positions*bw;
484 base_create( wnd, UI_KIND_SLIDER, _x, _y, real_w, _h);
486 left_button.create( wnd, up, _x-bw, _y, _h, _h );
487 left_button.set_parent(this);
489 right_button.create( wnd, down, _x+real_w, _y, bh, bh );
490 right_button.set_parent(this);
497 SDL_assert( _current >= _start );
498 SDL_assert( _current <= _stop );
499 SDL_assert( stop >= 0 );
501 n_positions = _n_positions;
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);
517 void UI_SLIDER::draw()
521 if ( disabled_flag ) {
522 if ( bmap_ids[SLIDER_BAR_DISABLED] != -1 ) {
523 gr_set_bitmap(bmap_ids[SLIDER_BAR_DISABLED]);
527 if ( bmap_ids[SLIDER_MARKER_DISABLED] != -1 ) {
528 gr_set_bitmap(bmap_ids[SLIDER_MARKER_DISABLED]);
529 gr_bitmap(marker_x,marker_y);
534 if ( bmap_ids[SLIDER_BAR_NORMAL] != -1 ) {
535 gr_set_bitmap(bmap_ids[SLIDER_BAR_NORMAL]);
539 if ( bmap_ids[SLIDER_MARKER_NORMAL] != -1 ) {
540 gr_set_bitmap(bmap_ids[SLIDER_MARKER_NORMAL]);
541 gr_bitmap(marker_x,marker_y);
546 gr_set_font(my_wnd->f_id);
547 gr_set_clip( x, y, w, h );
549 if (my_wnd->selected_gadget == this)
550 gr_set_color_fast( &CBRIGHT_GREEN );
552 gr_set_color_fast( &CGRAY );
554 ui_rect( 0, 0, w-1, h-1 );
556 gr_set_clip( marker_x, marker_y, w, h );
557 ui_draw_box_out(0, 0, marker_w, marker_h);
561 void UI_SLIDER::process(int focus)
563 int OnMe, OnMarker, keyfocus;
572 if (my_wnd->selected_gadget == this)
575 left_button.process(focus);
576 right_button.process(focus);
587 oldpos = fake_position;
590 OnMe = is_mouse_on();
592 if ( ui_mouse.x >= (marker_x ) && ui_mouse.x <= (marker_x+marker_w) ) {
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;
608 last_scrolled = timer_get_milliseconds();
609 marker_x -= increment;
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;
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;
627 percent = i2fl(marker_x - x)/i2fl(pixel_range);
628 current = percent * (stop - start);
631 int UI_SLIDER::getpos()
636 float UI_SLIDER::getcurrent()
641 int UI_SLIDER::changed()