Vegastrike 0.5.1 rc1  1.0
Original sources for Vegastrike Evolved
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
slider.cpp
Go to the documentation of this file.
1 /*
2  * Vega Strike
3  * Copyright (C) 2003 Mike Byron
4  *
5  * http://vegastrike.sourceforge.net/
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 2
10  * of the License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
20  */
21 
22 #include "vegastrike.h"
23 
24 #include "slider.h"
25 
26 #include "eventmanager.h"
27 
28 #include "vs_globals.h"
29 #include "config_xml.h"
30 #include "xml_support.h"
31 
32 //The Slider class controls the setting for a simple integer range.
33 
34 //These limits are in thumb length units -- 0.0 -> 1.0.
35 static const float MAX_THUMB_LENGTH = 1.0; //Can't have a thumb this long.
36 static const float MIN_THUMB_LENGTH = .05; //Make the thumb at least this thick.
37 static const float NO_THUMB_LENGTH = 1.0; //If we don't have a thumb, this is the length.
38 
39 //This is absolute -- thumbs must be at least this big in coordinates.
40 static const float ABSOLUTE_MIN_THUMB_LENGTH = .05;
41 
42 //Margins for cancelling a thumb drag operation.
43 //That is, if you drag the mouse out of this area, the slider position goes back
44 //to it's original position before the drag aperation started.
45 //These are margins outside the slider rectangle. They are negative because they are used to
46 //"inset" the rectangle.
47 //NOTE: This is used for both vertical and horizontal. Margins should be the same.
48 static const Size THUMB_DRAG_CANCEL_MARGINS = Size( -.3, -.3 );
49 
50 //Set the position of this scroller.
51 void Slider::setPosition( int pos )
52 {
53  int newPosition = pos;
54  if (pos > m_maxValue)
55  newPosition = m_maxValue;
56  else if (pos < m_minValue)
57  newPosition = m_minValue;
58  if (m_position != newPosition) {
59  m_position = newPosition;
60  sendCommand( "Slider::PositionChanged", this );
61  }
62 }
63 
64 //Range represented by the slider.
65 void Slider::setMaxMin( int max, int min )
66 {
67  m_maxValue = max;
68  m_minValue = min;
69 
70  //Set default page size
71  const int pageSize = float_to_int( (max-min)/10.0+0.5 );
72  setPageSize( pageSize );
73 }
74 
75 //"Thumb" length. 1.0 = Entire range.
76 void Slider::setThumbLength( float len )
77 {
78  float realLen = m_originalThumbLength = len;
79  if (realLen > MAX_THUMB_LENGTH || realLen < 0.0)
80  realLen = NO_THUMB_LENGTH;
81  else if (realLen < MIN_THUMB_LENGTH)
82  realLen = MIN_THUMB_LENGTH;
83  //Make sure the thumb is at least an absolute size.
84  if (m_vertical) {
87  } else if (realLen*m_rect.size.width < ABSOLUTE_MIN_THUMB_LENGTH && m_rect.size.height > 0) {
89  }
90  m_thumbLength = realLen;
91 }
92 
93 //The outside boundaries of the control.
94 void Slider::setRect( const Rect &r )
95 {
96  Control::setRect( r );
97 
98  //Calculate other things based on new rect.
101 }
102 
103 //Whether color is light or dark.
104 static bool isColorLight( const GFXColor &c )
105 {
106  return c.r > .6 || c.g > .6 || c.b > .6;
107 }
108 
109 //Make a color somewhat darker.
110 static GFXColor darkenColor( const GFXColor &c, const float factor )
111 {
112  GFXColor result;
113  result.r = guiMax( 0, c.r-factor );
114  result.g = guiMax( 0, c.g-factor );
115  result.b = guiMax( 0, c.b-factor );
116  result.a = c.a;
117 
118  return result;
119 }
120 
121 //Make a color somewhat darker.
122 static GFXColor lightenColor( const GFXColor &c, const float factor )
123 {
124  GFXColor result;
125  result.r = guiMin( 1.0, c.r+factor );
126  result.g = guiMin( 1.0, c.g+factor );
127  result.b = guiMin( 1.0, c.b+factor );
128  result.a = c.a;
129 
130  return result;
131 }
132 
133 //Calculate the thumb colors based on the specified background color.
135 {
136  if ( !isClear( c ) ) {
137  if ( isColorLight( c ) )
138  //Light color. Make thumb darker.
140  else
141  //Dark Color.
143  }
144 }
145 
146 //Set the background color.
148 {
149  //Calculate a reasonable thumb color.
151 
152  Control::setColor( c );
153 }
154 
155 //Draw the control.
156 void Slider::draw( void )
157 {
158  //Draw the background.
159  drawBackground();
160  //Draw the thumb.
161  if ( !( isClear( m_thumbColor ) && isClear( m_thumbOutlineColor ) ) ) {
162  float relativePosition = 0.0;
163  if (m_maxValue != m_minValue)
164  relativePosition = ( (float) (m_position-m_minValue) )/(m_maxValue-m_minValue);
165  Rect thumbRect = m_rect;
166  if (m_vertical) {
167  //Vertical thumb.
169  thumbRect.origin.y += (1.0-relativePosition)*(m_rect.size.height-thumbRect.size.height);
170  } else {
171  //Horizontal thumb.
172  thumbRect.size.width = m_thumbLength*m_rect.size.width;
173  thumbRect.origin.x += relativePosition*(m_rect.size.width-thumbRect.size.width);
174  }
175  m_thumbRect = thumbRect; //Want to save away the bigger version for mouse hits.
176  thumbRect.inset( Size( .01, .01 ) );
177  drawRect( thumbRect, m_thumbColor );
178  drawRectOutline( thumbRect, m_thumbOutlineColor, 1.0 );
179  }
180 }
181 
183 {
184  static int zoominc = XMLSupport::parse_int( vs_config->getVariable( "general", "wheel_increment_lines", "3" ) );
185  if ( event.code == LEFT_MOUSE_BUTTON && m_thumbLength != NO_THUMB_LENGTH && hitTest( event.loc ) ) {
186  if (m_vertical) {
187  if (event.loc.y < m_thumbRect.origin.y) {
189  } else if ( event.loc.y > m_thumbRect.top() ) {
191  } else {
193  m_buttonDownMouse = event.loc.y;
195  }
196  } else {
197  if (event.loc.x < m_thumbRect.origin.x) {
199  } else if ( event.loc.x > m_thumbRect.right() ) {
201  } else {
203  m_buttonDownMouse = event.loc.x;
205  }
206  }
207  setModal( true ); //Make sure we don't miss anything.
208  //Make sure we see mouse events *first* until we get a mouse-up.
210  return true;
211  } else if (event.code == WHEELUP_MOUSE_BUTTON) {
212  if ( hitTest( event.loc ) )
213  setPosition( position()-zoominc );
214  } else if (event.code == WHEELDOWN_MOUSE_BUTTON) {
215  if ( hitTest( event.loc ) )
216  setPosition( position()+zoominc );
217  }
218  return Control::processMouseDown( event );
219 }
220 
222 {
223  //The interface for mouse dragging is a little weird. There is no button information. All
224  //we know is that some button is down. This is enough, since we don't get into a specific
225  //mouse state in this control unless we know which mouse button was pressed...
227  if (m_thumbLength == NO_THUMB_LENGTH) return true;
228  const Rect cancelRect = m_rect.copyAndInset( THUMB_DRAG_CANCEL_MARGINS );
229  if ( !cancelRect.inside( event.loc ) ) {
230  //We are outside the cancel rect. Go back to original position.
232  return true;
233  } else {
234  //We are dragging the thumb -- get a new scroll position.
235  if (m_vertical) {
236  //Calculate the factor to convert a change in mouse coords to a change in slider position.
237  //This is derived from the ratio of the non-thumb length in the slider to the
238  //total range.
239  const float totalMouseLength = (1.0-m_thumbLength)*m_rect.size.height;
240  const int totalRange = m_maxValue-m_minValue;
241  const int positionChange = float_to_int( (m_buttonDownMouse-event.loc.y)*totalRange/totalMouseLength+0.5 );
242  setPosition( m_buttonDownPosition+positionChange );
243  return true;
244  } else {
245  const float totalMouseLength = (1.0-m_thumbLength)*m_rect.size.width;
246  const int totalRange = m_maxValue-m_minValue;
247  const int positionChange = float_to_int( (event.loc.x-m_buttonDownMouse)*totalRange/totalMouseLength+0.5 );
248  setPosition( m_buttonDownPosition+positionChange );
249  return true;
250  }
251  }
252  return Control::processMouseDrag( event );
253  }
254  return false;
255 }
256 
257 bool Slider::processMouseUp( const InputEvent &event )
258 {
259  if (m_mouseState != MOUSE_NONE && event.code == LEFT_MOUSE_BUTTON) {
260  //We are now done with the modal mouse loop.
261  switch (m_mouseState)
262  {
263  case MOUSE_PAGE_UP:
264  if ( hitTest( event.loc ) )
266  break;
267  case MOUSE_PAGE_DOWN:
268  if ( hitTest( event.loc ) )
270  break;
271  case MOUSE_THUMB_DRAG:
272  //Whatever position we have is the correct one.
273  //Do nothing.
274  break;
275  default:
276  assert( false ); //Forgot an enum case.
277  }
278  //Make sure we get off the event chain.
279  globalEventManager().removeResponder( this, true );
280  setModal( false );
282 
283  return Control::processMouseUp( event );
284  }
285  return false;
286 }
287 
288 //CONSTRUCTION
289 Slider::Slider( void ) :
290  m_minValue( 0 )
291  , m_maxValue( 100 )
292  , m_thumbLength( .15 )
293  , m_originalThumbLength( m_thumbLength )
294  , m_pageSize( 10 )
295  , m_thumbColor( m_color )
296  , m_thumbOutlineColor( GUI_OPAQUE_BLACK() )
297  , m_position( m_minValue )
298  , m_vertical( true )
299  , m_mouseState( MOUSE_NONE )
300  , m_buttonDownMouse( 0.0 )
301  , m_buttonDownPosition( 0 )
302  , m_thumbRect()
303 {}
304