gcsx_slider.cpp 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273
  1. /* GCSx
  2. ** SLIDER.CPP
  3. **
  4. ** Numerical slider widget
  5. */
  6. /*****************************************************************************
  7. ** Copyright (C) 2003-2006 Janson
  8. **
  9. ** This program is free software; you can redistribute it and/or modify
  10. ** it under the terms of the GNU General Public License as published by
  11. ** the Free Software Foundation; either version 2 of the License, or
  12. ** (at your option) any later version.
  13. **
  14. ** This program is distributed in the hope that it will be useful,
  15. ** but WITHOUT ANY WARRANTY; without even the implied warranty of
  16. ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  17. ** GNU General Public License for more details.
  18. **
  19. ** You should have received a copy of the GNU General Public License
  20. ** along with this program; if not, write to the Free Software
  21. ** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
  22. *****************************************************************************/
  23. #include "all.h"
  24. WSlider::WSlider(int sId, int sBegin, int sEnd, int* sSetting, int sLength) : Widget(sId, blankString, sSetting) { start_func
  25. assert(sBegin <= sEnd);
  26. assert(sSetting);
  27. assert((sLength > 0) || (sLength == -1));
  28. if (sLength == -1) pixelLength = GUI_SLIDER_TRACKLENGTH;
  29. else pixelLength = sLength;
  30. rangeBegin = sBegin;
  31. rangeEnd = sEnd;
  32. linkedTo = NULL;
  33. // Tab extends a certain amount past the end of the track
  34. resize(GUI_SLIDER_TABWIDTH + pixelLength, GUI_SLIDER_TABHEIGHT);
  35. load(); // Always keep a valid setting in it, due to linkTo
  36. }
  37. int WSlider::event(int hasFocus, const SDL_Event* event) { start_func
  38. assert(event);
  39. assert(parent);
  40. switch (event->type) {
  41. case SDL_INPUTFOCUS:
  42. if (event->user.code & 1) {
  43. if (!haveFocus) {
  44. haveFocus = 1;
  45. setDirty();
  46. }
  47. }
  48. else {
  49. if ((haveFocus) || (dragging)) {
  50. dragging = haveFocus = 0;
  51. setDirty();
  52. }
  53. }
  54. return 1;
  55. case SDL_KEYDOWN:
  56. switch (combineKey(event->key.keysym.sym, event->key.keysym.mod)) {
  57. case SDLK_LEFT:
  58. case SDLK_UP:
  59. statePixel(pixelValue - 1);
  60. return 1;
  61. case SDLK_RIGHT:
  62. case SDLK_DOWN:
  63. statePixel(pixelValue + 1);
  64. return 1;
  65. case SDLK_PAGEUP:
  66. statePixel(pixelValue - GUI_SLIDER_TABWIDTH);
  67. return 1;
  68. case SDLK_PAGEDOWN:
  69. statePixel(pixelValue + GUI_SLIDER_TABWIDTH);
  70. return 1;
  71. case SDLK_HOME:
  72. state(rangeBegin);
  73. return 1;
  74. case SDLK_END:
  75. state(rangeEnd);
  76. return 1;
  77. }
  78. break;
  79. case SDL_MOUSEBUTTONUP:
  80. if ((event->button.button == SDL_BUTTON_LEFT) && (dragging)) {
  81. dragging = 0;
  82. setDirty();
  83. }
  84. return 1;
  85. case SDL_MOUSEBUTTONDBL:
  86. case SDL_MOUSEBUTTONDOWN:
  87. if (event->button.button == SDL_BUTTON_LEFT) {
  88. if (event->button.x < pixelValue) {
  89. statePixel(pixelValue - GUI_SLIDER_TABWIDTH);
  90. }
  91. else if (event->button.x >= pixelValue + GUI_SLIDER_TABWIDTH) {
  92. statePixel(pixelValue + GUI_SLIDER_TABWIDTH);
  93. }
  94. else {
  95. dragging = 1;
  96. draggingX = event->button.x;
  97. draggingValue = pixelValue;
  98. setDirty();
  99. }
  100. return 1;
  101. }
  102. else if (event->button.button == SDL_BUTTON_WHEELUP) {
  103. statePixel(pixelValue - GUI_SLIDER_TABWIDTH);
  104. return 1;
  105. }
  106. else if (event->button.button == SDL_BUTTON_WHEELDOWN) {
  107. statePixel(pixelValue + GUI_SLIDER_TABWIDTH);
  108. return 1;
  109. }
  110. break;
  111. case SDL_MOUSEMOTION:
  112. if (dragging) {
  113. // Signed required in case negative
  114. statePixel(draggingValue + ((Sint16)event->motion.x) - draggingX);
  115. }
  116. return 1;
  117. }
  118. return 0;
  119. }
  120. void WSlider::linkTo(WNumberBox* linked) { start_func
  121. if (linked == NULL) {
  122. linkedTo = NULL;
  123. }
  124. else {
  125. linkedTo = linked;
  126. linkedTo->state(currentValue);
  127. }
  128. }
  129. void WSlider::siblingModified(Widget* modified) { start_func
  130. assert(modified);
  131. assert(modified != this);
  132. if (modified == linkedTo) stateFromLoad(linkedTo->state());
  133. }
  134. void WSlider::load() { start_func
  135. dragging = 0;
  136. stateFromLoad(*((int*)setting));
  137. setDirty();
  138. }
  139. void WSlider::apply() { start_func
  140. *((int*)setting) = state();
  141. }
  142. void WSlider::display(SDL_Surface* destSurface, Rect& toDisplay, const Rect& clipArea, int xOffset, int yOffset) { start_func
  143. assert(destSurface);
  144. if (visible) {
  145. // If dirty, redraw all
  146. if (dirty) {
  147. getRect(toDisplay);
  148. toDisplay.x += xOffset;
  149. toDisplay.y += yOffset;
  150. dirty = 0;
  151. intersectRects(toDisplay, clipArea);
  152. }
  153. // Anything to draw?
  154. if (toDisplay.w) {
  155. SDL_SetClipRect(destSurface, &toDisplay);
  156. xOffset += x;
  157. yOffset += y;
  158. // This widget makes no attempt at partial redraw other than the initial fill.
  159. SDL_FillRect(destSurface, &toDisplay, guiPacked[COLOR_FILL]);
  160. // The track is extended in total length by the tracksize, to make
  161. // the appearance balanced
  162. drawGuiBoxInvert(xOffset + GUI_SLIDER_TABWIDTH / 2 - GUI_SLIDER_TRACKSIZE / 2, yOffset + GUI_SLIDER_TABHEIGHT / 2 - GUI_SLIDER_TRACKSIZE / 2, pixelLength + GUI_SLIDER_TRACKSIZE, GUI_SLIDER_TRACKSIZE, 1, destSurface);
  163. // The tab is centered on it's pixel; 0 is actually one pixel off the tracksize,
  164. // lining up with the left center pixel of the tab (since the tab is an even
  165. // width) This creates a balanced appearance from 0 to pixelLength.
  166. // It is drawn inverted if currently depressed.
  167. if (dragging) {
  168. drawRect(xOffset + pixelValue, yOffset, GUI_SLIDER_TABWIDTH, GUI_SLIDER_TABHEIGHT, guiPacked[COLOR_FILL], destSurface);
  169. drawGuiBoxInvert(xOffset + pixelValue, yOffset, GUI_SLIDER_TABWIDTH, GUI_SLIDER_TABHEIGHT, 2, destSurface);
  170. }
  171. else {
  172. drawGuiBox(xOffset + pixelValue, yOffset, GUI_SLIDER_TABWIDTH, GUI_SLIDER_TABHEIGHT, 2, destSurface);
  173. }
  174. // Focus?
  175. if (haveFocus) drawFocusBox(xOffset, yOffset, width, height, destSurface);
  176. // This widget has no special disabled appearance.
  177. }
  178. }
  179. }
  180. int WSlider::state() const { start_func
  181. return currentValue;
  182. }
  183. int WSlider::state(int newValue) { start_func
  184. int markDirty = 0;
  185. if (newValue != currentValue) markDirty = 1;
  186. stateFromLoad(newValue);
  187. if ((markDirty) && (linkedTo)) linkedTo->state(newValue);
  188. // May not have a parent, as this is called during constructor
  189. if (parent) parent->childModified(this);
  190. return currentValue;
  191. }
  192. int WSlider::stateFromLoad(int newValue) { start_func
  193. if (newValue < rangeBegin) newValue = rangeBegin;
  194. else if (newValue > rangeEnd) newValue = rangeEnd;
  195. int markDirty = 0;
  196. if (newValue != currentValue) markDirty = 1;
  197. currentValue = newValue;
  198. if (rangeEnd == rangeBegin) {
  199. pixelValue = pixelLength;
  200. }
  201. else {
  202. // sBegin will always result in 0
  203. // sEnd will always result in pixelLength
  204. // values in between are equally spaced
  205. // *2, +1, /2 allows for rounding off
  206. pixelValue = ((newValue - rangeBegin) * pixelLength * 2 / (rangeEnd - rangeBegin) + 1) / 2;
  207. }
  208. if (markDirty) {
  209. setDirty();
  210. }
  211. return currentValue;
  212. }
  213. int WSlider::statePixel(int newPixel) { start_func
  214. if (newPixel < 0) newPixel = 0;
  215. else if (newPixel > pixelLength) newPixel = pixelLength;
  216. if (newPixel != pixelValue) {
  217. // *2, +1, /2 allows for rounding off
  218. return state(rangeBegin + (newPixel * (rangeEnd - rangeBegin) * 2 / pixelLength + 1) / 2);
  219. }
  220. return state();
  221. }