gcsx_wscroll.cpp 43 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943
  1. /* GCSx
  2. ** WSCROLL.H
  3. **
  4. ** Widget parent class to provide frame/scrollbars
  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. const string WidgetScroll::wtButtonUp("m");
  25. const string WidgetScroll::wtButtonDown("n");
  26. const string WidgetScroll::wtButtonLeft("l");
  27. const string WidgetScroll::wtButtonRight("k");
  28. WidgetScroll::WidgetScroll(FrameType type, Window* client, int cWidth, int cHeight, int cId) : Widget(cId, blankString, NULL) { start_func
  29. clientWidget = NULL;
  30. construct(type, client, cWidth, cHeight);
  31. }
  32. WidgetScroll::WidgetScroll(FrameType type, Widget* client, int cWidth, int cHeight) : Widget(client->getId(), blankString, NULL) { start_func
  33. clientWidget = client;
  34. construct(type, client, cWidth, cHeight);
  35. }
  36. void WidgetScroll::construct(FrameType type, Window* client, int cWidth, int cHeight) { start_func
  37. assert(cWidth >= -1);
  38. assert(cHeight >= -1);
  39. frameType = type;
  40. clientArea = client;
  41. dragMode = FRAME_DRAG_NONE;
  42. scrollX = scrollY = 0;
  43. hScrollLine = vScrollLine = fontHeight();
  44. scrollRepeatTicks = scrollRepeatDelay = 0;
  45. haveFocus = 0;
  46. whyDirty = FRAME_DIRTY_ALL;
  47. // Calculate our constants
  48. scrollbarButtonSize = fontHeight();
  49. scrollbarButtonXPad = (scrollbarButtonSize - fontWidth("f", FONT_WIDGET)) / 2;
  50. if ((frameType == FRAMETYPE_BEVEL) || (frameType == FRAMETYPE_BEVEL_BK)) {
  51. frameThickness = FRAME_BEVELTHICKNESS;
  52. }
  53. else if (frameType == FRAMETYPE_LINE) {
  54. frameThickness = FRAME_LINETHICKNESS;
  55. }
  56. else {
  57. frameThickness = 0;
  58. }
  59. if (client) {
  60. client->setParent(this);
  61. if (cWidth == -1) cWidth = client->getWidth();
  62. if (cHeight == -1) cHeight = client->getHeight();
  63. }
  64. else {
  65. if (cWidth == -1) cWidth = 0;
  66. if (cHeight == -1) cHeight = 0;
  67. }
  68. resize(cWidth + frameThickness * 2, cHeight + frameThickness * 2);
  69. }
  70. Widget* WidgetScroll::returnSelf() { start_func
  71. if (clientWidget) return clientWidget->returnSelf();
  72. return this;
  73. }
  74. void WidgetScroll::newClient(Window* fClient) { start_func
  75. assert(fClient);
  76. if (clientArea != NULL) {
  77. clientArea->setParent(NULL);
  78. }
  79. clientArea = fClient;
  80. clientWidget = NULL;
  81. clientArea->setParent(this);
  82. resize(width, height);
  83. }
  84. void WidgetScroll::newClient(Widget* fClient) { start_func
  85. assert(fClient);
  86. if (clientArea != NULL) {
  87. clientArea->setParent(NULL);
  88. }
  89. clientArea = clientWidget = fClient;
  90. clientArea->setParent(this);
  91. resize(width, height);
  92. }
  93. void WidgetScroll::newClient() { start_func
  94. if (clientArea != NULL) {
  95. clientArea->setParent(NULL);
  96. }
  97. clientArea = clientWidget = NULL;
  98. }
  99. void WidgetScroll::updateClientSize() { start_func
  100. resize(width, height);
  101. }
  102. void WidgetScroll::setScroll(int vLine, int hLine) { start_func
  103. assert(vLine > 0);
  104. assert(hLine > 0);
  105. vScrollLine = vLine;
  106. hScrollLine = hLine;
  107. // A page = full height/width, rounded down to a line multiple,
  108. // minus one line's worth
  109. vScrollPage = (clientHeightInner / vLine - 1) * vLine;
  110. if (vScrollPage < vLine) vScrollPage = vLine;
  111. hScrollPage = (clientWidthInner / hLine - 1) * hLine;
  112. if (hScrollPage < hLine) hScrollPage = hLine;
  113. }
  114. void WidgetScroll::resize(int newWidth, int newHeight, int newViewWidth, int newViewHeight, int fromParent) { start_func
  115. // (assert legal width/height)
  116. assert(newHeight >= 0);
  117. assert(newWidth >= 0);
  118. if (clientArea) {
  119. clientActualWidth = clientArea->getWidth();
  120. clientActualHeight = clientArea->getHeight();
  121. }
  122. else {
  123. clientActualWidth = clientActualHeight = 0;
  124. }
  125. // Our size (doesn't always set dirty, so we must)
  126. Window::resize(newWidth, newHeight, newViewWidth, newViewHeight, fromParent);
  127. setDirty();
  128. whyDirty = FRAME_DIRTY_ALL;
  129. // Determine client size
  130. newWidth -= frameThickness * 2;
  131. newHeight -= frameThickness * 2;
  132. clientX = frameThickness;
  133. clientY = frameThickness;
  134. // Scrollbars default to off
  135. vScrollbarX = vScrollbarY = vScrollbarWidth = vScrollbarHeight = vScrollbarTabSize = 0;
  136. hScrollbarX = hScrollbarY = hScrollbarWidth = hScrollbarHeight = hScrollbarTabSize = 0;
  137. // Must have room for at least 3 button sizes, or no scrollbars appear
  138. if ((clientArea) && (newWidth >= scrollbarButtonSize * 3) && (newHeight >= scrollbarButtonSize * 3)) {
  139. int needH = clientActualWidth > newWidth;
  140. int needV = clientActualHeight > newHeight;
  141. if (needV) needH = clientActualWidth > newWidth - scrollbarButtonSize;
  142. if (needH) needV = clientActualHeight > newHeight - scrollbarButtonSize;
  143. if (needV) {
  144. vScrollbarX = clientX + newWidth - scrollbarButtonSize;
  145. vScrollbarY = clientY;
  146. vScrollbarWidth = scrollbarButtonSize;
  147. vScrollbarHeight = newHeight;
  148. if (needH) vScrollbarHeight -= scrollbarButtonSize;
  149. }
  150. if (needH) {
  151. hScrollbarX = clientX;
  152. hScrollbarY = clientY + newHeight - scrollbarButtonSize;
  153. hScrollbarWidth = newWidth;
  154. hScrollbarHeight = scrollbarButtonSize;
  155. if (needV) hScrollbarWidth -= scrollbarButtonSize;
  156. }
  157. }
  158. // Assign client size
  159. clientWidth = newWidth;
  160. clientHeight = newHeight;
  161. clientWidthInner = newWidth - vScrollbarWidth;
  162. clientHeightInner = newHeight - hScrollbarHeight;
  163. // Now we can determine scrollbar tab sizes
  164. // Determine tab size as the percent the current view is of the total view
  165. // Tab position determined by scrollTo call later
  166. if (vScrollbarX) {
  167. vScrollbarTabSize = clientHeightInner * (vScrollbarHeight - scrollbarButtonSize * 2) / clientActualHeight;
  168. if (vScrollbarTabSize < FRAME_SCROLLTABMIN) vScrollbarTabSize = FRAME_SCROLLTABMIN;
  169. if (vScrollbarTabSize > (vScrollbarHeight - scrollbarButtonSize * 2)) vScrollbarTabSize = 0;
  170. }
  171. if (hScrollbarY) {
  172. hScrollbarTabSize = clientWidthInner * (hScrollbarWidth - scrollbarButtonSize * 2) / clientActualWidth;
  173. if (hScrollbarTabSize < FRAME_SCROLLTABMIN) hScrollbarTabSize = FRAME_SCROLLTABMIN;
  174. if (hScrollbarTabSize > (hScrollbarWidth - scrollbarButtonSize * 2)) hScrollbarTabSize = 0;
  175. }
  176. // Ensure we're scrolled properly and sizing is set right
  177. scrollTo(scrollX, scrollY);
  178. setScroll(vScrollLine, hScrollLine);
  179. // Resize (move) client?
  180. if (clientArea) {
  181. clientArea->move(clientX + scrollX, clientY + scrollY);
  182. clientArea->resize(clientActualWidth, clientActualHeight, clientWidthInner, clientHeightInner, 1);
  183. }
  184. }
  185. WidgetScroll::~WidgetScroll() { start_func
  186. if (clientArea != NULL) {
  187. if (clientArea->wantsToBeDeleted()) delete clientArea;
  188. else clientArea->setParent(NULL);
  189. }
  190. }
  191. void WidgetScroll::childMoved(int fromX, int fromY, int toX, int toY, Window* child) { start_func
  192. setChildDirty();
  193. }
  194. void WidgetScroll::childResized(int fromW, int fromH, int toW, int toH, Window* child) { start_func
  195. setChildDirty();
  196. }
  197. void WidgetScroll::display(SDL_Surface* destSurface, Rect& toDisplay, const Rect& clipArea, int xOffset, int yOffset) { start_func
  198. assert(destSurface);
  199. if (visible) {
  200. // This widget breaks redraw down into scrollbars, edge, client area
  201. // Redraw all?
  202. if ((whyDirty == FRAME_DIRTY_ALL) || (totalDirty)) {
  203. getRect(toDisplay);
  204. toDisplay.x += xOffset;
  205. toDisplay.y += yOffset;
  206. dirty = 0;
  207. intersectRects(toDisplay, clipArea);
  208. }
  209. xOffset += x;
  210. yOffset += y;
  211. // Anything to draw so far?
  212. if (toDisplay.w) {
  213. SDL_SetClipRect(destSurface, &toDisplay);
  214. if (disabled) SDL_FillRect(destSurface, &toDisplay, guiPacked[COLOR_FILL]);
  215. // Draw fill and border
  216. if (((frameType == FRAMETYPE_BEVEL) || (frameType == FRAMETYPE_BEVEL_BK)) && (clientWidth >= 0) && (clientHeight >= 0)) {
  217. drawGuiBoxInvert(xOffset, yOffset, width, height, FRAME_BEVELTHICKNESS, destSurface);
  218. }
  219. if ((frameType == FRAMETYPE_LINE) && (width > 0) && (height > 0)) {
  220. drawRect(xOffset, yOffset, width, height, guiPacked[COLOR_LINEBORDER], destSurface);
  221. }
  222. }
  223. // This will be the final displayed amount, we update it as we go but still work
  224. // off of the original dirtied area for efficiency
  225. Rect updatedArea = toDisplay;
  226. if (!disabled) {
  227. // (make sure vertical exists before doing more work)
  228. if (vScrollbarX) {
  229. // Determine clip area for vertical scrollbar
  230. Rect vertClip = { vScrollbarX + xOffset, vScrollbarY + yOffset, vScrollbarWidth, vScrollbarHeight };
  231. intersectRects(vertClip, clipArea);
  232. // If we need to update vertical scroll, OR it intersects with the dirty area,
  233. // redraw it; note that if the second conditional is tested, vertClip will be reduced
  234. // to whatever portion intersects with the dirty area, which is what we want
  235. if ((whyDirty & FRAME_DIRTY_SCROLLVERT) || (intersectRects(vertClip, toDisplay))) {
  236. // Add vertical rect into updated area
  237. boundRects(updatedArea, vertClip);
  238. // Draw vertical scrollbar
  239. SDL_SetClipRect(destSurface, &vertClip);
  240. SDL_FillRect(destSurface, &vertClip, guiPacked[COLOR_SCROLLTRACK]);
  241. if (vScrollbarTabSize) {
  242. // Invert if pressed
  243. if ((dragMode == FRAME_DRAG_SCROLLBAR_VERT) && (dragItem == FRAME_SCROLL_TAB)) {
  244. drawRect(xOffset + vScrollbarX, yOffset + vScrollbarY + scrollbarButtonSize + vScrollbarTab, scrollbarButtonSize, vScrollbarTabSize, guiPacked[COLOR_FILL], destSurface);
  245. drawGuiBoxInvert(xOffset + vScrollbarX, yOffset + vScrollbarY + scrollbarButtonSize + vScrollbarTab, scrollbarButtonSize, vScrollbarTabSize, 2, destSurface);
  246. }
  247. else {
  248. drawGuiBox(xOffset + vScrollbarX, yOffset + vScrollbarY + scrollbarButtonSize + vScrollbarTab, scrollbarButtonSize, vScrollbarTabSize, 2, destSurface);
  249. }
  250. }
  251. // if pressed
  252. if ((dragMode == FRAME_DRAG_SCROLLBAR_VERT) && (dragItem == FRAME_SCROLL_LESS)) {
  253. // Non-gradient: drawRect(xOffset + vScrollbarX, yOffset + vScrollbarY, scrollbarButtonSize, scrollbarButtonSize, guiPacked[COLOR_FILL], destSurface);
  254. drawGradient(xOffset + vScrollbarX, yOffset + vScrollbarY, scrollbarButtonSize, scrollbarButtonSize, guiRGB[COLOR_BUTTONDOWN1], guiRGB[COLOR_BUTTONDOWN2], destSurface);
  255. drawGuiBoxInvert(xOffset + vScrollbarX, yOffset + vScrollbarY, scrollbarButtonSize, scrollbarButtonSize, 2, destSurface);
  256. drawText(wtButtonUp, guiRGB[COLOR_TEXT], xOffset + vScrollbarX + scrollbarButtonXPad + 1, yOffset + vScrollbarY + scrollbarButtonXPad + 1, destSurface, FONT_WIDGET);
  257. }
  258. else {
  259. drawGuiBox(xOffset + vScrollbarX, yOffset + vScrollbarY, scrollbarButtonSize, scrollbarButtonSize, 2, destSurface);
  260. // Non-gradient: nothing
  261. drawGradient(xOffset + vScrollbarX + 2, yOffset + vScrollbarY + 2, scrollbarButtonSize - 4, scrollbarButtonSize - 4, guiRGB[COLOR_BUTTONFILL1], guiRGB[COLOR_BUTTONFILL2], destSurface);
  262. drawText(wtButtonUp, guiRGB[COLOR_TEXT], xOffset + vScrollbarX + scrollbarButtonXPad, yOffset + vScrollbarY + scrollbarButtonXPad, destSurface, FONT_WIDGET);
  263. }
  264. // if pressed
  265. if ((dragMode == FRAME_DRAG_SCROLLBAR_VERT) && (dragItem == FRAME_SCROLL_MORE)) {
  266. // Non-gradient: drawRect(xOffset + vScrollbarX, yOffset + vScrollbarY + vScrollbarHeight - scrollbarButtonSize, scrollbarButtonSize, scrollbarButtonSize, guiPacked[COLOR_FILL], destSurface);
  267. drawGradient(xOffset + vScrollbarX, yOffset + vScrollbarY + vScrollbarHeight - scrollbarButtonSize, scrollbarButtonSize, scrollbarButtonSize, guiRGB[COLOR_BUTTONDOWN1], guiRGB[COLOR_BUTTONDOWN2], destSurface);
  268. drawGuiBoxInvert(xOffset + vScrollbarX, yOffset + vScrollbarY + vScrollbarHeight - scrollbarButtonSize, scrollbarButtonSize, scrollbarButtonSize, 2, destSurface);
  269. drawText(wtButtonDown, guiRGB[COLOR_TEXT], xOffset + vScrollbarX + scrollbarButtonXPad + 1, yOffset + vScrollbarY + vScrollbarHeight - scrollbarButtonSize + scrollbarButtonXPad + 1, destSurface, FONT_WIDGET);
  270. }
  271. else {
  272. drawGuiBox(xOffset + vScrollbarX, yOffset + vScrollbarY + vScrollbarHeight - scrollbarButtonSize, scrollbarButtonSize, scrollbarButtonSize, 2, destSurface);
  273. // Non-gradient: nothing
  274. drawGradient(xOffset + vScrollbarX + 2, yOffset + vScrollbarY + vScrollbarHeight - scrollbarButtonSize + 2, scrollbarButtonSize - 4, scrollbarButtonSize - 4, guiRGB[COLOR_BUTTONFILL1], guiRGB[COLOR_BUTTONFILL2], destSurface);
  275. drawText(wtButtonDown, guiRGB[COLOR_TEXT], xOffset + vScrollbarX + scrollbarButtonXPad, yOffset + vScrollbarY + vScrollbarHeight - scrollbarButtonSize + scrollbarButtonXPad, destSurface, FONT_WIDGET);
  276. }
  277. }
  278. }
  279. // (make sure horizontal exists before doing more work)
  280. if (hScrollbarY) {
  281. // Determine clip area for horizontal scrollbar
  282. Rect horizClip = { hScrollbarX + xOffset, hScrollbarY + yOffset, hScrollbarWidth, hScrollbarHeight };
  283. intersectRects(horizClip, clipArea);
  284. // If we need to update horizontal scroll, OR it intersects with the dirty area,
  285. // redraw it; note that if the second conditional is tested, vertClip will be reduced
  286. // to whatever portion intersects with the dirty area, which is what we want
  287. if ((whyDirty & FRAME_DIRTY_SCROLLHORIZ) || (intersectRects(horizClip, toDisplay))) {
  288. // Add horizontal rect into updated area
  289. boundRects(updatedArea, horizClip);
  290. // Draw horizontal scrollbar
  291. SDL_SetClipRect(destSurface, &horizClip);
  292. SDL_FillRect(destSurface, &horizClip, guiPacked[COLOR_SCROLLTRACK]);
  293. if (hScrollbarTabSize) {
  294. // Invert if pressed
  295. if ((dragMode == FRAME_DRAG_SCROLLBAR_VERT) && (dragItem == FRAME_SCROLL_TAB)) {
  296. drawRect(xOffset + hScrollbarX + scrollbarButtonSize + hScrollbarTab, yOffset + hScrollbarY, hScrollbarTabSize, scrollbarButtonSize, guiPacked[COLOR_FILL], destSurface);
  297. drawGuiBoxInvert(xOffset + hScrollbarX + scrollbarButtonSize + hScrollbarTab, yOffset + hScrollbarY, hScrollbarTabSize, scrollbarButtonSize, 2, destSurface);
  298. }
  299. else {
  300. drawGuiBox(xOffset + hScrollbarX + scrollbarButtonSize + hScrollbarTab, yOffset + hScrollbarY, hScrollbarTabSize, scrollbarButtonSize, 2, destSurface);
  301. }
  302. }
  303. // if pressed
  304. if ((dragMode == FRAME_DRAG_SCROLLBAR_HORIZ) && (dragItem == FRAME_SCROLL_LESS)) {
  305. // Non-gradient: drawRect(xOffset + hScrollbarX, yOffset + hScrollbarY, scrollbarButtonSize, scrollbarButtonSize, guiPacked[COLOR_FILL], destSurface);
  306. drawGradient(xOffset + hScrollbarX, yOffset + hScrollbarY, scrollbarButtonSize, scrollbarButtonSize, guiRGB[COLOR_BUTTONDOWN1], guiRGB[COLOR_BUTTONDOWN2], destSurface);
  307. drawGuiBoxInvert(xOffset + hScrollbarX, yOffset + hScrollbarY, scrollbarButtonSize, scrollbarButtonSize, 2, destSurface);
  308. drawText(wtButtonLeft, guiRGB[COLOR_TEXT], xOffset + hScrollbarX + scrollbarButtonXPad + 1, yOffset + hScrollbarY + scrollbarButtonXPad + 1, destSurface, FONT_WIDGET);
  309. }
  310. else {
  311. drawGuiBox(xOffset + hScrollbarX, yOffset + hScrollbarY, scrollbarButtonSize, scrollbarButtonSize, 2, destSurface);
  312. // Non-gradient: nothing
  313. drawGradient(xOffset + hScrollbarX + 2, yOffset + hScrollbarY + 2, scrollbarButtonSize - 4, scrollbarButtonSize - 4, guiRGB[COLOR_BUTTONFILL1], guiRGB[COLOR_BUTTONFILL2], destSurface);
  314. drawText(wtButtonLeft, guiRGB[COLOR_TEXT], xOffset + hScrollbarX + scrollbarButtonXPad, yOffset + hScrollbarY + scrollbarButtonXPad, destSurface, FONT_WIDGET);
  315. }
  316. // if pressed
  317. if ((dragMode == FRAME_DRAG_SCROLLBAR_HORIZ) && (dragItem == FRAME_SCROLL_MORE)) {
  318. // Non-gradient: drawRect(xOffset + hScrollbarX + hScrollbarWidth - scrollbarButtonSize, yOffset + hScrollbarY, scrollbarButtonSize, scrollbarButtonSize, guiPacked[COLOR_FILL], destSurface);
  319. drawGradient(xOffset + hScrollbarX + hScrollbarWidth - scrollbarButtonSize, yOffset + hScrollbarY, scrollbarButtonSize, scrollbarButtonSize, guiRGB[COLOR_BUTTONDOWN1], guiRGB[COLOR_BUTTONDOWN2], destSurface);
  320. drawGuiBoxInvert(xOffset + hScrollbarX + hScrollbarWidth - scrollbarButtonSize, yOffset + hScrollbarY, scrollbarButtonSize, scrollbarButtonSize, 2, destSurface);
  321. drawText(wtButtonRight, guiRGB[COLOR_TEXT], xOffset + hScrollbarX + hScrollbarWidth - scrollbarButtonSize + scrollbarButtonXPad + 1, yOffset + hScrollbarY + scrollbarButtonXPad + 1, destSurface, FONT_WIDGET);
  322. }
  323. else {
  324. drawGuiBox(xOffset + hScrollbarX + hScrollbarWidth - scrollbarButtonSize, yOffset + hScrollbarY, scrollbarButtonSize, scrollbarButtonSize, 2, destSurface);
  325. // Non-gradient: nothing
  326. drawGradient(xOffset + hScrollbarX + hScrollbarWidth - scrollbarButtonSize + 2, yOffset + hScrollbarY + 2, scrollbarButtonSize - 4, scrollbarButtonSize - 4, guiRGB[COLOR_BUTTONFILL1], guiRGB[COLOR_BUTTONFILL2], destSurface);
  327. drawText(wtButtonRight, guiRGB[COLOR_TEXT], xOffset + hScrollbarX + hScrollbarWidth - scrollbarButtonSize + scrollbarButtonXPad, yOffset + hScrollbarY + scrollbarButtonXPad, destSurface, FONT_WIDGET);
  328. }
  329. }
  330. }
  331. // Fill in corner?
  332. if ((vScrollbarX) && (hScrollbarY)) {
  333. Rect cornerClip = { vScrollbarX + xOffset, hScrollbarY + yOffset, vScrollbarWidth, hScrollbarHeight };
  334. intersectRects(cornerClip, clipArea);
  335. // Only needed if area is dirty
  336. if (intersectRects(cornerClip, toDisplay)) {
  337. // We set clip because it may have been reset earlier
  338. SDL_SetClipRect(destSurface, &cornerClip);
  339. SDL_FillRect(destSurface, &cornerClip, guiPacked[COLOR_FILL]);
  340. }
  341. }
  342. // Client area exists?
  343. if ((clientWidthInner > 0) && (clientHeightInner > 0)) {
  344. // Client area that CAN be drawn
  345. Rect clientClip = { clientX + xOffset, clientY + yOffset, clientWidthInner, clientHeightInner };
  346. intersectRects(clientClip, clipArea);
  347. // Client area that MUST be drawn
  348. Rect clientDirty = clientClip;
  349. // If we need to update client, OR it intersects with the dirty area, redraw it
  350. int clientIsDirty = 0;
  351. if ((clientArea) && (clientArea->isDirty())) clientIsDirty = 1;
  352. // We test dirty first, because we always want the dirty area to be what
  353. // the client HAS to update, even if they're dirty...
  354. if ((intersectRects(clientDirty, toDisplay)) || (clientIsDirty)) {
  355. // ... but we clip to a wider area- the area the client CAN update
  356. SDL_SetClipRect(destSurface, &clientClip);
  357. // Background fill on dirty area
  358. SDL_FillRect(destSurface, &clientDirty, guiPacked[frameType == FRAMETYPE_BEVEL_BK ? COLOR_BKFILL : COLOR_TEXTBOX]);
  359. // Paint client area
  360. if (clientArea) {
  361. clientArea->display(destSurface, clientDirty, clientClip, xOffset, yOffset);
  362. // Add client rect into updated area
  363. boundRects(updatedArea, clientDirty);
  364. }
  365. }
  366. }
  367. }
  368. toDisplay = updatedArea;
  369. }
  370. dirty = 0;
  371. childDirty = 0;
  372. whyDirty = FRAME_DIRTY_NONE;
  373. }
  374. void WidgetScroll::scrollToView(int sX, int sY, int sWidth, int sHeight) { start_func
  375. int cX = -scrollX;
  376. int cY = -scrollY;
  377. // Don't adjust left-right if target encompasses entire view
  378. if ((sX > cX) || (sX + sWidth < cX + clientWidthInner)) {
  379. // If right-most edge of target is to the right of us, scroll to see it
  380. if (sX + sWidth > cX + clientWidthInner) cX = sX + sWidth - clientWidthInner;
  381. // Same for left
  382. if (sX < cX) cX = sX;
  383. }
  384. // Don't adjust up-down if target encompasses entire view
  385. if ((sY > cY) || (sY + sHeight < cY + clientHeightInner)) {
  386. // Same for bottom, top
  387. if (sY + sHeight > cY + clientHeightInner) cY = sY + sHeight - clientHeightInner;
  388. if (sY < cY) cY = sY;
  389. }
  390. // Complete scroll
  391. scrollTo(-cX, -cY);
  392. }
  393. void WidgetScroll::scrollBy(int sX, int sY) { start_func
  394. scrollTo(scrollX + sX, scrollY + sY);
  395. }
  396. void WidgetScroll::scrollTo(int sX, int sY, int tabX, int tabY) { start_func
  397. if (clientArea) {
  398. // Not too far in either direction
  399. if (clientActualWidth + sX < clientWidthInner) sX = clientWidthInner - clientActualWidth;
  400. if (clientActualHeight + sY < clientHeightInner) sY = clientHeightInner - clientActualHeight;
  401. // Check this direction last in case window is too large overall
  402. if (sX > 0) sX = 0;
  403. if (sY > 0) sY = 0;
  404. // Tab positions
  405. // Tab positions
  406. if ((vScrollbarTabSize) && (clientHeightInner < clientActualHeight)) {
  407. int newTab;
  408. if (tabY >= 0) newTab = tabY;
  409. else newTab = (vScrollbarHeight - (scrollbarButtonSize * 2) - vScrollbarTabSize) * sY / (clientHeightInner - clientActualHeight);
  410. if (newTab != vScrollbarTab) {
  411. setDirty();
  412. whyDirty |= FRAME_DIRTY_SCROLLVERT;
  413. }
  414. vScrollbarTab = newTab;
  415. }
  416. else {
  417. if (vScrollbarTab != 0) {
  418. setDirty();
  419. whyDirty |= FRAME_DIRTY_SCROLLVERT;
  420. }
  421. vScrollbarTab = 0;
  422. }
  423. if ((hScrollbarTabSize) && (clientWidthInner < clientActualWidth)) {
  424. int newTab;
  425. if (tabX >= 0) newTab = tabX;
  426. else newTab = (hScrollbarWidth - (scrollbarButtonSize * 2) - hScrollbarTabSize) * sX / (clientWidthInner - clientActualWidth);
  427. if (newTab != hScrollbarTab) {
  428. setDirty();
  429. whyDirty |= FRAME_DIRTY_SCROLLHORIZ;
  430. }
  431. hScrollbarTab = newTab;
  432. }
  433. else {
  434. if (hScrollbarTab != 0) {
  435. setDirty();
  436. whyDirty |= FRAME_DIRTY_SCROLLHORIZ;
  437. }
  438. hScrollbarTab = 0;
  439. }
  440. if ((scrollX != sX) || (scrollY != sY)) {
  441. scrollX = sX;
  442. scrollY = sY;
  443. clientArea->move(clientX + scrollX, clientY + scrollY);
  444. }
  445. }
  446. else {
  447. // No client, no scrollbars- reset to zero- dirty if wasn't already at zero
  448. if ((scrollX) || (scrollY)) {
  449. setDirty();
  450. whyDirty = FRAME_DIRTY_ALL;
  451. if (clientArea) clientArea->move(clientX, clientY);
  452. }
  453. scrollX = scrollY = 0;
  454. }
  455. }
  456. void WidgetScroll::whereCoords(int x, int y, DragType* dragType, DragSubType* dragItem) const { start_func
  457. assert(dragType);
  458. assert(dragItem);
  459. *dragType = FRAME_DRAG_NONE;
  460. *dragItem = FRAME_SCROLL_NONE;
  461. // Client area? Client *can* receive clicks outside it's actual area
  462. if ((clientArea) &&
  463. (x >= clientX) &&
  464. (y >= clientY) &&
  465. (x < clientX + clientWidthInner) &&
  466. (y < clientY + clientHeightInner)) {
  467. *dragType = FRAME_DRAG_CLIENT;
  468. }
  469. // Vertical scrollbar?
  470. else if ((x >= vScrollbarX) &&
  471. (x < vScrollbarX + vScrollbarWidth) &&
  472. (y >= vScrollbarY) &&
  473. (y < vScrollbarY + vScrollbarHeight)) {
  474. *dragType = FRAME_DRAG_SCROLLBAR_VERT;
  475. if (y < vScrollbarY + scrollbarButtonSize) *dragItem = FRAME_SCROLL_LESS;
  476. else if (y >= vScrollbarY + vScrollbarHeight - scrollbarButtonSize) *dragItem = FRAME_SCROLL_MORE;
  477. else if (y < vScrollbarY + scrollbarButtonSize + vScrollbarTab) *dragItem = FRAME_SCROLL_PAGELESS;
  478. else if (y >= vScrollbarY + scrollbarButtonSize + vScrollbarTab + vScrollbarTabSize) *dragItem = FRAME_SCROLL_PAGEMORE;
  479. else *dragItem = FRAME_SCROLL_TAB;
  480. }
  481. // Horizontal scrollbar?
  482. else if ((x >= hScrollbarX) &&
  483. (x < hScrollbarX + hScrollbarWidth) &&
  484. (y >= hScrollbarY) &&
  485. (y < hScrollbarY + hScrollbarHeight)) {
  486. *dragType = FRAME_DRAG_SCROLLBAR_HORIZ;
  487. if (x < hScrollbarX + scrollbarButtonSize) *dragItem = FRAME_SCROLL_LESS;
  488. else if (x >= hScrollbarX + hScrollbarWidth - scrollbarButtonSize) *dragItem = FRAME_SCROLL_MORE;
  489. else if (x < hScrollbarX + scrollbarButtonSize + hScrollbarTab) *dragItem = FRAME_SCROLL_PAGELESS;
  490. else if (x >= hScrollbarX + scrollbarButtonSize + hScrollbarTab + hScrollbarTabSize) *dragItem = FRAME_SCROLL_PAGEMORE;
  491. else *dragItem = FRAME_SCROLL_TAB;
  492. }
  493. }
  494. int WidgetScroll::event(int hasFocus, const SDL_Event* event) { start_func
  495. assert(event);
  496. DragType newDragMode;
  497. DragSubType newDragItem;
  498. int idleUsed = 0;
  499. Uint32 ticks;
  500. int mX, mY;
  501. int done = 0;
  502. Window* exempt = NULL;
  503. // We need to copy the event if we expect to change it to send a copy to client
  504. SDL_Event clientEvent = *event;
  505. switch (event->type) {
  506. case SDL_CLOSE:
  507. // Close client, then us
  508. if (clientArea) {
  509. int deleteClient = clientArea->wantsToBeDeleted();
  510. clientArea->event(hasFocus, &clientEvent);
  511. if (deleteClient) delete clientArea;
  512. else clientArea->setParent(NULL);
  513. clientArea = NULL;
  514. }
  515. return 1;
  516. case SDL_MOUSEBUTTONUP:
  517. if (dragMode == FRAME_DRAG_CLIENT) {
  518. // Adjust coordinates to 0-based for client
  519. if (clientArea) {
  520. clientEvent.button.x -= clientX + scrollX;
  521. clientEvent.button.y -= clientY + scrollY;
  522. // Propogate to client
  523. clientArea->event(hasFocus, &clientEvent);
  524. }
  525. if ((SDL_GetMouseState(NULL, NULL) & (SDL_BUTTON_LMASK | SDL_BUTTON_RMASK)) == 0) done = 1;
  526. }
  527. else if (event->button.button == SDL_BUTTON_LEFT) {
  528. if (dragMode == FRAME_DRAG_SCROLLBAR_HORIZ) {
  529. setDirty();
  530. whyDirty |= FRAME_DIRTY_SCROLLHORIZ;
  531. }
  532. else if (dragMode == FRAME_DRAG_SCROLLBAR_VERT) {
  533. setDirty();
  534. whyDirty |= FRAME_DIRTY_SCROLLVERT;
  535. }
  536. done = 1;
  537. }
  538. if (done) {
  539. whereCoords(event->motion.x, event->motion.y, &newDragMode, &newDragItem);
  540. if (newDragMode != dragMode) selectMouse(MOUSE_NORMAL);
  541. dragMode = FRAME_DRAG_NONE;
  542. scrollRepeatTicks = scrollRepeatDelay = 0;
  543. }
  544. break;
  545. case SDL_MOUSEBUTTONDBL:
  546. case SDL_MOUSEBUTTONDOWN:
  547. // Dragging/clicking what?
  548. whereCoords(event->button.x, event->button.y, &newDragMode, &newDragItem);
  549. if (newDragMode == FRAME_DRAG_CLIENT) {
  550. // No drag on wheels
  551. if ((event->button.button != SDL_BUTTON_WHEELUP) &&
  552. (event->button.button != SDL_BUTTON_WHEELDOWN)) {
  553. dragMode = newDragMode;
  554. dragItem = newDragItem;
  555. }
  556. // Adjust coordinates to 0-based for client
  557. if (clientArea) {
  558. clientEvent.button.x -= clientX + scrollX;
  559. clientEvent.button.y -= clientY + scrollY;
  560. // Propogate to client
  561. if (!clientArea->event(hasFocus, &clientEvent)) {
  562. // If not used, handle mouse wheel ourselves
  563. if (event->button.button == SDL_BUTTON_WHEELUP) {
  564. scrollTo(scrollX, scrollY + vScrollPage);
  565. }
  566. else if (event->button.button == SDL_BUTTON_WHEELDOWN) {
  567. scrollTo(scrollX, scrollY - vScrollPage);
  568. }
  569. }
  570. }
  571. }
  572. else if (((event->button.button == SDL_BUTTON_WHEELUP) || (event->button.button == SDL_BUTTON_WHEELDOWN)) &&
  573. ((newDragMode == FRAME_DRAG_SCROLLBAR_VERT) || (newDragMode == FRAME_DRAG_SCROLLBAR_HORIZ))) {
  574. if (newDragMode == FRAME_DRAG_SCROLLBAR_VERT) {
  575. setDirty();
  576. whyDirty |= FRAME_DIRTY_SCROLLVERT;
  577. if (event->button.button == SDL_BUTTON_WHEELUP) scrollTo(scrollX, scrollY + vScrollPage);
  578. else if (event->button.button == SDL_BUTTON_WHEELDOWN) scrollTo(scrollX, scrollY - vScrollPage);
  579. }
  580. if (newDragMode == FRAME_DRAG_SCROLLBAR_HORIZ) {
  581. setDirty();
  582. whyDirty |= FRAME_DIRTY_SCROLLHORIZ;
  583. if (event->button.button == SDL_BUTTON_WHEELUP) scrollTo(scrollX + hScrollPage, scrollY);
  584. else if (event->button.button == SDL_BUTTON_WHEELDOWN) scrollTo(scrollX - hScrollPage, scrollY);
  585. }
  586. }
  587. else if (event->button.button == SDL_BUTTON_LEFT) {
  588. if (newDragMode == FRAME_DRAG_SCROLLBAR_VERT) {
  589. setDirty();
  590. whyDirty |= FRAME_DIRTY_SCROLLVERT;
  591. scrollRepeatTicks = SDL_GetTicks();
  592. scrollRepeatDelay = DELAY_SCROLLBAR_REPEATSTART;
  593. if (newDragItem == FRAME_SCROLL_LESS) scrollTo(scrollX, scrollY + vScrollLine);
  594. else if (newDragItem == FRAME_SCROLL_MORE) scrollTo(scrollX, scrollY - vScrollLine);
  595. else if (newDragItem == FRAME_SCROLL_PAGELESS) scrollTo(scrollX, scrollY + vScrollPage);
  596. else if (newDragItem == FRAME_SCROLL_PAGEMORE) scrollTo(scrollX, scrollY - vScrollPage);
  597. // Force mouse motion to determine new drag mode
  598. SDL_GetMouseState(&mX, &mY);
  599. SDL_WarpMouse(mX, mY);
  600. }
  601. if (newDragMode == FRAME_DRAG_SCROLLBAR_HORIZ) {
  602. setDirty();
  603. whyDirty |= FRAME_DIRTY_SCROLLHORIZ;
  604. scrollRepeatTicks = SDL_GetTicks();
  605. scrollRepeatDelay = DELAY_SCROLLBAR_REPEATSTART;
  606. if (newDragItem == FRAME_SCROLL_LESS) scrollTo(scrollX + hScrollLine, scrollY);
  607. else if (newDragItem == FRAME_SCROLL_MORE) scrollTo(scrollX - hScrollLine, scrollY);
  608. else if (newDragItem == FRAME_SCROLL_PAGELESS) scrollTo(scrollX + hScrollPage, scrollY);
  609. else if (newDragItem == FRAME_SCROLL_PAGEMORE) scrollTo(scrollX - hScrollPage, scrollY);
  610. // Force mouse motion to determine new drag mode
  611. SDL_GetMouseState(&mX, &mY);
  612. SDL_WarpMouse(mX, mY);
  613. }
  614. dragMode = newDragMode;
  615. dragItem = newDragItem;
  616. dragX = event->button.x;
  617. dragY = event->button.y;
  618. dragItemOverflowX = 0;
  619. dragItemOverflowY = 0;
  620. }
  621. break;
  622. case SDL_MOUSEMOTION:
  623. if (dragMode == FRAME_DRAG_CLIENT) {
  624. // Adjust coordinates to 0-based for client
  625. if (clientArea) {
  626. clientEvent.motion.x -= clientX + scrollX;
  627. clientEvent.motion.y -= clientY + scrollY;
  628. // Propogate to client
  629. clientArea->event(hasFocus, &clientEvent);
  630. }
  631. }
  632. else if (event->motion.state & SDL_BUTTON_LMASK) {
  633. // Tab?
  634. if ((dragMode == FRAME_DRAG_SCROLLBAR_HORIZ) &&
  635. (dragItem == FRAME_SCROLL_TAB)) {
  636. int newX = hScrollbarTab + event->motion.xrel;
  637. // Overflow
  638. if (dragItemOverflowX) {
  639. newX += dragItemOverflowX;
  640. dragItemOverflowX = 0;
  641. }
  642. if (newX + hScrollbarTabSize > (hScrollbarWidth - scrollbarButtonSize * 2)) {
  643. dragItemOverflowX = newX + hScrollbarTabSize - (hScrollbarWidth - scrollbarButtonSize * 2);
  644. newX -= dragItemOverflowX;
  645. }
  646. if (newX < 0) {
  647. dragItemOverflowX = newX;
  648. newX = 0;
  649. }
  650. // Scroll to right spot
  651. scrollTo(newX * (clientWidthInner - clientActualWidth) / (hScrollbarWidth - (scrollbarButtonSize * 2) - hScrollbarTabSize), scrollY, newX, -1);
  652. }
  653. else if ((dragMode == FRAME_DRAG_SCROLLBAR_VERT) &&
  654. (dragItem == FRAME_SCROLL_TAB)) {
  655. int newY = vScrollbarTab + event->motion.yrel;
  656. // Overflow
  657. if (dragItemOverflowY) {
  658. newY += dragItemOverflowY;
  659. dragItemOverflowY = 0;
  660. }
  661. if (newY + vScrollbarTabSize > (vScrollbarHeight - scrollbarButtonSize * 2)) {
  662. dragItemOverflowY = newY + vScrollbarTabSize - (vScrollbarHeight - scrollbarButtonSize * 2);
  663. newY -= dragItemOverflowY;
  664. }
  665. if (newY < 0) {
  666. dragItemOverflowY = newY;
  667. newY = 0;
  668. }
  669. // Scroll to right spot
  670. scrollTo(scrollX, newY * (clientHeightInner - clientActualHeight) / (vScrollbarHeight - (scrollbarButtonSize * 2) - vScrollbarTabSize), -1, newY);
  671. }
  672. // Scrollbar?
  673. else if ((dragMode == FRAME_DRAG_SCROLLBAR_HORIZ) ||
  674. (dragMode == FRAME_DRAG_SCROLLBAR_VERT)) {
  675. whereCoords(event->motion.x, event->motion.y, &newDragMode, &newDragItem);
  676. if (dragMode == newDragMode) {
  677. if (dragItem != newDragItem) {
  678. dragItem = newDragItem;
  679. setDirty();
  680. if (dragMode == FRAME_DRAG_SCROLLBAR_HORIZ) whyDirty |= FRAME_DIRTY_SCROLLHORIZ;
  681. else whyDirty |= FRAME_DIRTY_SCROLLVERT;
  682. }
  683. }
  684. else {
  685. if (dragItem != FRAME_SCROLL_NONE) {
  686. dragItem = FRAME_SCROLL_NONE;
  687. setDirty();
  688. if (dragMode == FRAME_DRAG_SCROLLBAR_HORIZ) whyDirty |= FRAME_DIRTY_SCROLLHORIZ;
  689. else whyDirty |= FRAME_DIRTY_SCROLLVERT;
  690. }
  691. }
  692. }
  693. }
  694. // Just hover?
  695. else {
  696. whereCoords(event->motion.x, event->motion.y, &newDragMode, &newDragItem);
  697. if (newDragMode == FRAME_DRAG_CLIENT) {
  698. // Adjust coordinates to 0-based for client
  699. if (clientArea) {
  700. clientEvent.motion.x -= clientX + scrollX;
  701. clientEvent.motion.y -= clientY + scrollY;
  702. // Propogate to client
  703. clientArea->event(hasFocus, &clientEvent);
  704. }
  705. }
  706. else selectMouse(MOUSE_NORMAL);
  707. }
  708. break;
  709. case SDL_INPUTFOCUS:
  710. if ((event->user.code & 1) && (!haveFocus)) {
  711. haveFocus = 1;
  712. // Propogate to client
  713. if (clientArea) {
  714. clientArea->event(hasFocus, &clientEvent);
  715. }
  716. }
  717. else if (!(event->user.code & 1) && (haveFocus)) {
  718. haveFocus = 0;
  719. // Propogate to client
  720. if (clientArea) {
  721. clientArea->event(hasFocus, &clientEvent);
  722. }
  723. }
  724. break;
  725. case SDL_SPECIAL:
  726. // Scrollbar repeat?
  727. if ((event->user.code & SDL_IDLE) && (scrollRepeatDelay)) {
  728. ticks = SDL_GetTicks();
  729. // (catch wraparound)
  730. if (ticks < scrollRepeatTicks) scrollRepeatTicks = SDL_GetTicks();
  731. else if (ticks - scrollRepeatTicks > scrollRepeatDelay) {
  732. scrollRepeatTicks = SDL_GetTicks();
  733. scrollRepeatDelay = DELAY_SCROLLBAR_REPEATAGAIN;
  734. if (dragMode == FRAME_DRAG_SCROLLBAR_VERT) {
  735. if (dragItem == FRAME_SCROLL_LESS) scrollTo(scrollX, scrollY + vScrollLine);
  736. else if (dragItem == FRAME_SCROLL_MORE) scrollTo(scrollX, scrollY - vScrollLine);
  737. else if (dragItem == FRAME_SCROLL_PAGELESS) scrollTo(scrollX, scrollY + vScrollPage);
  738. else if (dragItem == FRAME_SCROLL_PAGEMORE) scrollTo(scrollX, scrollY - vScrollPage);
  739. }
  740. if (dragMode == FRAME_DRAG_SCROLLBAR_HORIZ) {
  741. if (dragItem == FRAME_SCROLL_LESS) scrollTo(scrollX + hScrollLine, scrollY);
  742. else if (dragItem == FRAME_SCROLL_MORE) scrollTo(scrollX - hScrollLine, scrollY);
  743. else if (dragItem == FRAME_SCROLL_PAGELESS) scrollTo(scrollX + hScrollPage, scrollY);
  744. else if (dragItem == FRAME_SCROLL_PAGEMORE) scrollTo(scrollX - hScrollPage, scrollY);
  745. }
  746. // Force mouse motion to determine new drag mode
  747. SDL_GetMouseState(&mX, &mY);
  748. SDL_WarpMouse(mX, mY);
  749. idleUsed = 1;
  750. }
  751. }
  752. // (continue on, to propogate to client)
  753. case SDL_MOUSEFOCUS:
  754. // (we can just propogate MOUSEFOCUS, since we are virtually equal
  755. // to our child window in size anyways)
  756. case SDL_COMMAND:
  757. case SDL_QUIT:
  758. case SDL_SYSKEY:
  759. case SDL_OBJECTCHANGE:
  760. // (exempt window may exist)
  761. exempt = (Window*)clientEvent.user.data2;
  762. default:
  763. // Propogate to client
  764. if ((clientArea) && (clientArea != exempt)) {
  765. return (clientArea->event(hasFocus, &clientEvent) || idleUsed);
  766. }
  767. return idleUsed;
  768. }
  769. // All mouse and focus events, we use.
  770. return 1;
  771. }
  772. int WidgetScroll::stateTabId() const { start_func
  773. if (clientWidget) return clientWidget->stateTabId();
  774. return Widget::stateTabId();
  775. }
  776. int WidgetScroll::stateTabId(int wTabId) { start_func
  777. if (clientWidget) return clientWidget->stateTabId(wTabId);
  778. return Widget::stateTabId(wTabId);
  779. }
  780. int WidgetScroll::refuseAll() const { start_func
  781. if (clientWidget) return clientWidget->refuseAll();
  782. if (clientArea) return Widget::refuseAll();
  783. return 1;
  784. }
  785. void WidgetScroll::doAction() { start_func
  786. if (clientWidget) clientWidget->doAction();
  787. return;
  788. }
  789. char WidgetScroll::getShortcut() const { start_func
  790. if (clientWidget) return clientWidget->getShortcut();
  791. return 0;
  792. }
  793. int WidgetScroll::getId() const { start_func
  794. if (clientWidget) return clientWidget->getId();
  795. return Widget::getId();
  796. }
  797. void WidgetScroll::disable() { start_func
  798. if (clientWidget) clientWidget->disable();
  799. Widget::disable();
  800. }
  801. void WidgetScroll::enable() { start_func
  802. if (clientWidget) clientWidget->enable();
  803. Widget::enable();
  804. }
  805. void WidgetScroll::load() { start_func
  806. if (clientWidget) clientWidget->load();
  807. }
  808. void WidgetScroll::apply() { start_func
  809. if (clientWidget) clientWidget->apply();
  810. }
  811. void WidgetScroll::resolutionChange(int fromW, int fromH, int fromBpp, int toW, int toH, int toBpp) { start_func
  812. Window::resolutionChange(fromW, fromH, fromBpp, toW, toH, toBpp);
  813. if (clientArea != NULL) clientArea->resolutionChange(fromW, fromH, fromBpp, toW, toH, toBpp);
  814. }
  815. const char* WidgetScroll::tooltip(int xPos, int yPos) const { start_func
  816. if (clientWidget) {
  817. xPos -= clientX + scrollX;
  818. yPos -= clientY + scrollY;
  819. return clientWidget->tooltip(xPos, yPos);
  820. }
  821. return Widget::tooltip(xPos, yPos);
  822. }