123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943 |
- /* GCSx
- ** WSCROLL.H
- **
- ** Widget parent class to provide frame/scrollbars
- */
- /*****************************************************************************
- ** Copyright (C) 2003-2006 Janson
- **
- ** This program is free software; you can redistribute it and/or modify
- ** it under the terms of the GNU General Public License as published by
- ** the Free Software Foundation; either version 2 of the License, or
- ** (at your option) any later version.
- **
- ** This program is distributed in the hope that it will be useful,
- ** but WITHOUT ANY WARRANTY; without even the implied warranty of
- ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- ** GNU General Public License for more details.
- **
- ** You should have received a copy of the GNU General Public License
- ** along with this program; if not, write to the Free Software
- ** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
- *****************************************************************************/
- #include "all.h"
- const string WidgetScroll::wtButtonUp("m");
- const string WidgetScroll::wtButtonDown("n");
- const string WidgetScroll::wtButtonLeft("l");
- const string WidgetScroll::wtButtonRight("k");
- WidgetScroll::WidgetScroll(FrameType type, Window* client, int cWidth, int cHeight, int cId) : Widget(cId, blankString, NULL) { start_func
- clientWidget = NULL;
- construct(type, client, cWidth, cHeight);
- }
- WidgetScroll::WidgetScroll(FrameType type, Widget* client, int cWidth, int cHeight) : Widget(client->getId(), blankString, NULL) { start_func
- clientWidget = client;
- construct(type, client, cWidth, cHeight);
- }
- void WidgetScroll::construct(FrameType type, Window* client, int cWidth, int cHeight) { start_func
- assert(cWidth >= -1);
- assert(cHeight >= -1);
- frameType = type;
- clientArea = client;
- dragMode = FRAME_DRAG_NONE;
- scrollX = scrollY = 0;
- hScrollLine = vScrollLine = fontHeight();
- scrollRepeatTicks = scrollRepeatDelay = 0;
- haveFocus = 0;
- whyDirty = FRAME_DIRTY_ALL;
- // Calculate our constants
- scrollbarButtonSize = fontHeight();
- scrollbarButtonXPad = (scrollbarButtonSize - fontWidth("f", FONT_WIDGET)) / 2;
- if ((frameType == FRAMETYPE_BEVEL) || (frameType == FRAMETYPE_BEVEL_BK)) {
- frameThickness = FRAME_BEVELTHICKNESS;
- }
- else if (frameType == FRAMETYPE_LINE) {
- frameThickness = FRAME_LINETHICKNESS;
- }
- else {
- frameThickness = 0;
- }
- if (client) {
- client->setParent(this);
- if (cWidth == -1) cWidth = client->getWidth();
- if (cHeight == -1) cHeight = client->getHeight();
- }
- else {
- if (cWidth == -1) cWidth = 0;
- if (cHeight == -1) cHeight = 0;
- }
-
- resize(cWidth + frameThickness * 2, cHeight + frameThickness * 2);
- }
- Widget* WidgetScroll::returnSelf() { start_func
- if (clientWidget) return clientWidget->returnSelf();
- return this;
- }
- void WidgetScroll::newClient(Window* fClient) { start_func
- assert(fClient);
- if (clientArea != NULL) {
- clientArea->setParent(NULL);
- }
-
- clientArea = fClient;
- clientWidget = NULL;
- clientArea->setParent(this);
- resize(width, height);
- }
- void WidgetScroll::newClient(Widget* fClient) { start_func
- assert(fClient);
- if (clientArea != NULL) {
- clientArea->setParent(NULL);
- }
-
- clientArea = clientWidget = fClient;
- clientArea->setParent(this);
- resize(width, height);
- }
- void WidgetScroll::newClient() { start_func
- if (clientArea != NULL) {
- clientArea->setParent(NULL);
- }
-
- clientArea = clientWidget = NULL;
- }
- void WidgetScroll::updateClientSize() { start_func
- resize(width, height);
- }
- void WidgetScroll::setScroll(int vLine, int hLine) { start_func
- assert(vLine > 0);
- assert(hLine > 0);
-
- vScrollLine = vLine;
- hScrollLine = hLine;
-
- // A page = full height/width, rounded down to a line multiple,
- // minus one line's worth
- vScrollPage = (clientHeightInner / vLine - 1) * vLine;
- if (vScrollPage < vLine) vScrollPage = vLine;
- hScrollPage = (clientWidthInner / hLine - 1) * hLine;
- if (hScrollPage < hLine) hScrollPage = hLine;
- }
- void WidgetScroll::resize(int newWidth, int newHeight, int newViewWidth, int newViewHeight, int fromParent) { start_func
- // (assert legal width/height)
- assert(newHeight >= 0);
- assert(newWidth >= 0);
- if (clientArea) {
- clientActualWidth = clientArea->getWidth();
- clientActualHeight = clientArea->getHeight();
- }
- else {
- clientActualWidth = clientActualHeight = 0;
- }
- // Our size (doesn't always set dirty, so we must)
- Window::resize(newWidth, newHeight, newViewWidth, newViewHeight, fromParent);
- setDirty();
- whyDirty = FRAME_DIRTY_ALL;
- // Determine client size
- newWidth -= frameThickness * 2;
- newHeight -= frameThickness * 2;
- clientX = frameThickness;
- clientY = frameThickness;
- // Scrollbars default to off
- vScrollbarX = vScrollbarY = vScrollbarWidth = vScrollbarHeight = vScrollbarTabSize = 0;
- hScrollbarX = hScrollbarY = hScrollbarWidth = hScrollbarHeight = hScrollbarTabSize = 0;
- // Must have room for at least 3 button sizes, or no scrollbars appear
- if ((clientArea) && (newWidth >= scrollbarButtonSize * 3) && (newHeight >= scrollbarButtonSize * 3)) {
- int needH = clientActualWidth > newWidth;
- int needV = clientActualHeight > newHeight;
- if (needV) needH = clientActualWidth > newWidth - scrollbarButtonSize;
- if (needH) needV = clientActualHeight > newHeight - scrollbarButtonSize;
-
- if (needV) {
- vScrollbarX = clientX + newWidth - scrollbarButtonSize;
- vScrollbarY = clientY;
- vScrollbarWidth = scrollbarButtonSize;
- vScrollbarHeight = newHeight;
- if (needH) vScrollbarHeight -= scrollbarButtonSize;
- }
-
- if (needH) {
- hScrollbarX = clientX;
- hScrollbarY = clientY + newHeight - scrollbarButtonSize;
- hScrollbarWidth = newWidth;
- hScrollbarHeight = scrollbarButtonSize;
- if (needV) hScrollbarWidth -= scrollbarButtonSize;
- }
- }
-
- // Assign client size
- clientWidth = newWidth;
- clientHeight = newHeight;
- clientWidthInner = newWidth - vScrollbarWidth;
- clientHeightInner = newHeight - hScrollbarHeight;
-
- // Now we can determine scrollbar tab sizes
- // Determine tab size as the percent the current view is of the total view
- // Tab position determined by scrollTo call later
- if (vScrollbarX) {
- vScrollbarTabSize = clientHeightInner * (vScrollbarHeight - scrollbarButtonSize * 2) / clientActualHeight;
- if (vScrollbarTabSize < FRAME_SCROLLTABMIN) vScrollbarTabSize = FRAME_SCROLLTABMIN;
- if (vScrollbarTabSize > (vScrollbarHeight - scrollbarButtonSize * 2)) vScrollbarTabSize = 0;
- }
- if (hScrollbarY) {
- hScrollbarTabSize = clientWidthInner * (hScrollbarWidth - scrollbarButtonSize * 2) / clientActualWidth;
- if (hScrollbarTabSize < FRAME_SCROLLTABMIN) hScrollbarTabSize = FRAME_SCROLLTABMIN;
- if (hScrollbarTabSize > (hScrollbarWidth - scrollbarButtonSize * 2)) hScrollbarTabSize = 0;
- }
- // Ensure we're scrolled properly and sizing is set right
- scrollTo(scrollX, scrollY);
- setScroll(vScrollLine, hScrollLine);
- // Resize (move) client?
- if (clientArea) {
- clientArea->move(clientX + scrollX, clientY + scrollY);
- clientArea->resize(clientActualWidth, clientActualHeight, clientWidthInner, clientHeightInner, 1);
- }
- }
- WidgetScroll::~WidgetScroll() { start_func
- if (clientArea != NULL) {
- if (clientArea->wantsToBeDeleted()) delete clientArea;
- else clientArea->setParent(NULL);
- }
- }
- void WidgetScroll::childMoved(int fromX, int fromY, int toX, int toY, Window* child) { start_func
- setChildDirty();
- }
- void WidgetScroll::childResized(int fromW, int fromH, int toW, int toH, Window* child) { start_func
- setChildDirty();
- }
- void WidgetScroll::display(SDL_Surface* destSurface, Rect& toDisplay, const Rect& clipArea, int xOffset, int yOffset) { start_func
- assert(destSurface);
- if (visible) {
- // This widget breaks redraw down into scrollbars, edge, client area
- // Redraw all?
- if ((whyDirty == FRAME_DIRTY_ALL) || (totalDirty)) {
- getRect(toDisplay);
- toDisplay.x += xOffset;
- toDisplay.y += yOffset;
- dirty = 0;
- intersectRects(toDisplay, clipArea);
- }
-
- xOffset += x;
- yOffset += y;
-
- // Anything to draw so far?
- if (toDisplay.w) {
- SDL_SetClipRect(destSurface, &toDisplay);
-
- if (disabled) SDL_FillRect(destSurface, &toDisplay, guiPacked[COLOR_FILL]);
-
- // Draw fill and border
- if (((frameType == FRAMETYPE_BEVEL) || (frameType == FRAMETYPE_BEVEL_BK)) && (clientWidth >= 0) && (clientHeight >= 0)) {
- drawGuiBoxInvert(xOffset, yOffset, width, height, FRAME_BEVELTHICKNESS, destSurface);
- }
- if ((frameType == FRAMETYPE_LINE) && (width > 0) && (height > 0)) {
- drawRect(xOffset, yOffset, width, height, guiPacked[COLOR_LINEBORDER], destSurface);
- }
- }
-
- // This will be the final displayed amount, we update it as we go but still work
- // off of the original dirtied area for efficiency
- Rect updatedArea = toDisplay;
-
- if (!disabled) {
- // (make sure vertical exists before doing more work)
- if (vScrollbarX) {
- // Determine clip area for vertical scrollbar
- Rect vertClip = { vScrollbarX + xOffset, vScrollbarY + yOffset, vScrollbarWidth, vScrollbarHeight };
- intersectRects(vertClip, clipArea);
-
- // If we need to update vertical scroll, OR it intersects with the dirty area,
- // redraw it; note that if the second conditional is tested, vertClip will be reduced
- // to whatever portion intersects with the dirty area, which is what we want
- if ((whyDirty & FRAME_DIRTY_SCROLLVERT) || (intersectRects(vertClip, toDisplay))) {
- // Add vertical rect into updated area
- boundRects(updatedArea, vertClip);
-
- // Draw vertical scrollbar
- SDL_SetClipRect(destSurface, &vertClip);
- SDL_FillRect(destSurface, &vertClip, guiPacked[COLOR_SCROLLTRACK]);
- if (vScrollbarTabSize) {
- // Invert if pressed
- if ((dragMode == FRAME_DRAG_SCROLLBAR_VERT) && (dragItem == FRAME_SCROLL_TAB)) {
- drawRect(xOffset + vScrollbarX, yOffset + vScrollbarY + scrollbarButtonSize + vScrollbarTab, scrollbarButtonSize, vScrollbarTabSize, guiPacked[COLOR_FILL], destSurface);
- drawGuiBoxInvert(xOffset + vScrollbarX, yOffset + vScrollbarY + scrollbarButtonSize + vScrollbarTab, scrollbarButtonSize, vScrollbarTabSize, 2, destSurface);
- }
- else {
- drawGuiBox(xOffset + vScrollbarX, yOffset + vScrollbarY + scrollbarButtonSize + vScrollbarTab, scrollbarButtonSize, vScrollbarTabSize, 2, destSurface);
- }
- }
- // if pressed
- if ((dragMode == FRAME_DRAG_SCROLLBAR_VERT) && (dragItem == FRAME_SCROLL_LESS)) {
- // Non-gradient: drawRect(xOffset + vScrollbarX, yOffset + vScrollbarY, scrollbarButtonSize, scrollbarButtonSize, guiPacked[COLOR_FILL], destSurface);
- drawGradient(xOffset + vScrollbarX, yOffset + vScrollbarY, scrollbarButtonSize, scrollbarButtonSize, guiRGB[COLOR_BUTTONDOWN1], guiRGB[COLOR_BUTTONDOWN2], destSurface);
- drawGuiBoxInvert(xOffset + vScrollbarX, yOffset + vScrollbarY, scrollbarButtonSize, scrollbarButtonSize, 2, destSurface);
- drawText(wtButtonUp, guiRGB[COLOR_TEXT], xOffset + vScrollbarX + scrollbarButtonXPad + 1, yOffset + vScrollbarY + scrollbarButtonXPad + 1, destSurface, FONT_WIDGET);
- }
- else {
- drawGuiBox(xOffset + vScrollbarX, yOffset + vScrollbarY, scrollbarButtonSize, scrollbarButtonSize, 2, destSurface);
- // Non-gradient: nothing
- drawGradient(xOffset + vScrollbarX + 2, yOffset + vScrollbarY + 2, scrollbarButtonSize - 4, scrollbarButtonSize - 4, guiRGB[COLOR_BUTTONFILL1], guiRGB[COLOR_BUTTONFILL2], destSurface);
- drawText(wtButtonUp, guiRGB[COLOR_TEXT], xOffset + vScrollbarX + scrollbarButtonXPad, yOffset + vScrollbarY + scrollbarButtonXPad, destSurface, FONT_WIDGET);
- }
- // if pressed
- if ((dragMode == FRAME_DRAG_SCROLLBAR_VERT) && (dragItem == FRAME_SCROLL_MORE)) {
- // Non-gradient: drawRect(xOffset + vScrollbarX, yOffset + vScrollbarY + vScrollbarHeight - scrollbarButtonSize, scrollbarButtonSize, scrollbarButtonSize, guiPacked[COLOR_FILL], destSurface);
- drawGradient(xOffset + vScrollbarX, yOffset + vScrollbarY + vScrollbarHeight - scrollbarButtonSize, scrollbarButtonSize, scrollbarButtonSize, guiRGB[COLOR_BUTTONDOWN1], guiRGB[COLOR_BUTTONDOWN2], destSurface);
- drawGuiBoxInvert(xOffset + vScrollbarX, yOffset + vScrollbarY + vScrollbarHeight - scrollbarButtonSize, scrollbarButtonSize, scrollbarButtonSize, 2, destSurface);
- drawText(wtButtonDown, guiRGB[COLOR_TEXT], xOffset + vScrollbarX + scrollbarButtonXPad + 1, yOffset + vScrollbarY + vScrollbarHeight - scrollbarButtonSize + scrollbarButtonXPad + 1, destSurface, FONT_WIDGET);
- }
- else {
- drawGuiBox(xOffset + vScrollbarX, yOffset + vScrollbarY + vScrollbarHeight - scrollbarButtonSize, scrollbarButtonSize, scrollbarButtonSize, 2, destSurface);
- // Non-gradient: nothing
- drawGradient(xOffset + vScrollbarX + 2, yOffset + vScrollbarY + vScrollbarHeight - scrollbarButtonSize + 2, scrollbarButtonSize - 4, scrollbarButtonSize - 4, guiRGB[COLOR_BUTTONFILL1], guiRGB[COLOR_BUTTONFILL2], destSurface);
- drawText(wtButtonDown, guiRGB[COLOR_TEXT], xOffset + vScrollbarX + scrollbarButtonXPad, yOffset + vScrollbarY + vScrollbarHeight - scrollbarButtonSize + scrollbarButtonXPad, destSurface, FONT_WIDGET);
- }
- }
- }
-
- // (make sure horizontal exists before doing more work)
- if (hScrollbarY) {
- // Determine clip area for horizontal scrollbar
- Rect horizClip = { hScrollbarX + xOffset, hScrollbarY + yOffset, hScrollbarWidth, hScrollbarHeight };
- intersectRects(horizClip, clipArea);
-
- // If we need to update horizontal scroll, OR it intersects with the dirty area,
- // redraw it; note that if the second conditional is tested, vertClip will be reduced
- // to whatever portion intersects with the dirty area, which is what we want
- if ((whyDirty & FRAME_DIRTY_SCROLLHORIZ) || (intersectRects(horizClip, toDisplay))) {
- // Add horizontal rect into updated area
- boundRects(updatedArea, horizClip);
-
- // Draw horizontal scrollbar
- SDL_SetClipRect(destSurface, &horizClip);
- SDL_FillRect(destSurface, &horizClip, guiPacked[COLOR_SCROLLTRACK]);
- if (hScrollbarTabSize) {
- // Invert if pressed
- if ((dragMode == FRAME_DRAG_SCROLLBAR_VERT) && (dragItem == FRAME_SCROLL_TAB)) {
- drawRect(xOffset + hScrollbarX + scrollbarButtonSize + hScrollbarTab, yOffset + hScrollbarY, hScrollbarTabSize, scrollbarButtonSize, guiPacked[COLOR_FILL], destSurface);
- drawGuiBoxInvert(xOffset + hScrollbarX + scrollbarButtonSize + hScrollbarTab, yOffset + hScrollbarY, hScrollbarTabSize, scrollbarButtonSize, 2, destSurface);
- }
- else {
- drawGuiBox(xOffset + hScrollbarX + scrollbarButtonSize + hScrollbarTab, yOffset + hScrollbarY, hScrollbarTabSize, scrollbarButtonSize, 2, destSurface);
- }
- }
- // if pressed
- if ((dragMode == FRAME_DRAG_SCROLLBAR_HORIZ) && (dragItem == FRAME_SCROLL_LESS)) {
- // Non-gradient: drawRect(xOffset + hScrollbarX, yOffset + hScrollbarY, scrollbarButtonSize, scrollbarButtonSize, guiPacked[COLOR_FILL], destSurface);
- drawGradient(xOffset + hScrollbarX, yOffset + hScrollbarY, scrollbarButtonSize, scrollbarButtonSize, guiRGB[COLOR_BUTTONDOWN1], guiRGB[COLOR_BUTTONDOWN2], destSurface);
- drawGuiBoxInvert(xOffset + hScrollbarX, yOffset + hScrollbarY, scrollbarButtonSize, scrollbarButtonSize, 2, destSurface);
- drawText(wtButtonLeft, guiRGB[COLOR_TEXT], xOffset + hScrollbarX + scrollbarButtonXPad + 1, yOffset + hScrollbarY + scrollbarButtonXPad + 1, destSurface, FONT_WIDGET);
- }
- else {
- drawGuiBox(xOffset + hScrollbarX, yOffset + hScrollbarY, scrollbarButtonSize, scrollbarButtonSize, 2, destSurface);
- // Non-gradient: nothing
- drawGradient(xOffset + hScrollbarX + 2, yOffset + hScrollbarY + 2, scrollbarButtonSize - 4, scrollbarButtonSize - 4, guiRGB[COLOR_BUTTONFILL1], guiRGB[COLOR_BUTTONFILL2], destSurface);
- drawText(wtButtonLeft, guiRGB[COLOR_TEXT], xOffset + hScrollbarX + scrollbarButtonXPad, yOffset + hScrollbarY + scrollbarButtonXPad, destSurface, FONT_WIDGET);
- }
- // if pressed
- if ((dragMode == FRAME_DRAG_SCROLLBAR_HORIZ) && (dragItem == FRAME_SCROLL_MORE)) {
- // Non-gradient: drawRect(xOffset + hScrollbarX + hScrollbarWidth - scrollbarButtonSize, yOffset + hScrollbarY, scrollbarButtonSize, scrollbarButtonSize, guiPacked[COLOR_FILL], destSurface);
- drawGradient(xOffset + hScrollbarX + hScrollbarWidth - scrollbarButtonSize, yOffset + hScrollbarY, scrollbarButtonSize, scrollbarButtonSize, guiRGB[COLOR_BUTTONDOWN1], guiRGB[COLOR_BUTTONDOWN2], destSurface);
- drawGuiBoxInvert(xOffset + hScrollbarX + hScrollbarWidth - scrollbarButtonSize, yOffset + hScrollbarY, scrollbarButtonSize, scrollbarButtonSize, 2, destSurface);
- drawText(wtButtonRight, guiRGB[COLOR_TEXT], xOffset + hScrollbarX + hScrollbarWidth - scrollbarButtonSize + scrollbarButtonXPad + 1, yOffset + hScrollbarY + scrollbarButtonXPad + 1, destSurface, FONT_WIDGET);
- }
- else {
- drawGuiBox(xOffset + hScrollbarX + hScrollbarWidth - scrollbarButtonSize, yOffset + hScrollbarY, scrollbarButtonSize, scrollbarButtonSize, 2, destSurface);
- // Non-gradient: nothing
- drawGradient(xOffset + hScrollbarX + hScrollbarWidth - scrollbarButtonSize + 2, yOffset + hScrollbarY + 2, scrollbarButtonSize - 4, scrollbarButtonSize - 4, guiRGB[COLOR_BUTTONFILL1], guiRGB[COLOR_BUTTONFILL2], destSurface);
- drawText(wtButtonRight, guiRGB[COLOR_TEXT], xOffset + hScrollbarX + hScrollbarWidth - scrollbarButtonSize + scrollbarButtonXPad, yOffset + hScrollbarY + scrollbarButtonXPad, destSurface, FONT_WIDGET);
- }
- }
- }
-
- // Fill in corner?
- if ((vScrollbarX) && (hScrollbarY)) {
- Rect cornerClip = { vScrollbarX + xOffset, hScrollbarY + yOffset, vScrollbarWidth, hScrollbarHeight };
- intersectRects(cornerClip, clipArea);
-
- // Only needed if area is dirty
- if (intersectRects(cornerClip, toDisplay)) {
- // We set clip because it may have been reset earlier
- SDL_SetClipRect(destSurface, &cornerClip);
- SDL_FillRect(destSurface, &cornerClip, guiPacked[COLOR_FILL]);
- }
- }
-
- // Client area exists?
- if ((clientWidthInner > 0) && (clientHeightInner > 0)) {
- // Client area that CAN be drawn
- Rect clientClip = { clientX + xOffset, clientY + yOffset, clientWidthInner, clientHeightInner };
- intersectRects(clientClip, clipArea);
-
- // Client area that MUST be drawn
- Rect clientDirty = clientClip;
-
- // If we need to update client, OR it intersects with the dirty area, redraw it
- int clientIsDirty = 0;
- if ((clientArea) && (clientArea->isDirty())) clientIsDirty = 1;
- // We test dirty first, because we always want the dirty area to be what
- // the client HAS to update, even if they're dirty...
- if ((intersectRects(clientDirty, toDisplay)) || (clientIsDirty)) {
- // ... but we clip to a wider area- the area the client CAN update
- SDL_SetClipRect(destSurface, &clientClip);
-
- // Background fill on dirty area
- SDL_FillRect(destSurface, &clientDirty, guiPacked[frameType == FRAMETYPE_BEVEL_BK ? COLOR_BKFILL : COLOR_TEXTBOX]);
-
- // Paint client area
- if (clientArea) {
- clientArea->display(destSurface, clientDirty, clientClip, xOffset, yOffset);
- // Add client rect into updated area
- boundRects(updatedArea, clientDirty);
- }
- }
- }
- }
-
- toDisplay = updatedArea;
- }
- dirty = 0;
- childDirty = 0;
- whyDirty = FRAME_DIRTY_NONE;
- }
- void WidgetScroll::scrollToView(int sX, int sY, int sWidth, int sHeight) { start_func
- int cX = -scrollX;
- int cY = -scrollY;
- // Don't adjust left-right if target encompasses entire view
- if ((sX > cX) || (sX + sWidth < cX + clientWidthInner)) {
- // If right-most edge of target is to the right of us, scroll to see it
- if (sX + sWidth > cX + clientWidthInner) cX = sX + sWidth - clientWidthInner;
-
- // Same for left
- if (sX < cX) cX = sX;
- }
- // Don't adjust up-down if target encompasses entire view
- if ((sY > cY) || (sY + sHeight < cY + clientHeightInner)) {
- // Same for bottom, top
- if (sY + sHeight > cY + clientHeightInner) cY = sY + sHeight - clientHeightInner;
- if (sY < cY) cY = sY;
- }
-
- // Complete scroll
- scrollTo(-cX, -cY);
- }
- void WidgetScroll::scrollBy(int sX, int sY) { start_func
- scrollTo(scrollX + sX, scrollY + sY);
- }
- void WidgetScroll::scrollTo(int sX, int sY, int tabX, int tabY) { start_func
- if (clientArea) {
- // Not too far in either direction
- if (clientActualWidth + sX < clientWidthInner) sX = clientWidthInner - clientActualWidth;
- if (clientActualHeight + sY < clientHeightInner) sY = clientHeightInner - clientActualHeight;
- // Check this direction last in case window is too large overall
- if (sX > 0) sX = 0;
- if (sY > 0) sY = 0;
-
- // Tab positions
- // Tab positions
- if ((vScrollbarTabSize) && (clientHeightInner < clientActualHeight)) {
- int newTab;
- if (tabY >= 0) newTab = tabY;
- else newTab = (vScrollbarHeight - (scrollbarButtonSize * 2) - vScrollbarTabSize) * sY / (clientHeightInner - clientActualHeight);
- if (newTab != vScrollbarTab) {
- setDirty();
- whyDirty |= FRAME_DIRTY_SCROLLVERT;
- }
- vScrollbarTab = newTab;
- }
- else {
- if (vScrollbarTab != 0) {
- setDirty();
- whyDirty |= FRAME_DIRTY_SCROLLVERT;
- }
- vScrollbarTab = 0;
- }
- if ((hScrollbarTabSize) && (clientWidthInner < clientActualWidth)) {
- int newTab;
- if (tabX >= 0) newTab = tabX;
- else newTab = (hScrollbarWidth - (scrollbarButtonSize * 2) - hScrollbarTabSize) * sX / (clientWidthInner - clientActualWidth);
- if (newTab != hScrollbarTab) {
- setDirty();
- whyDirty |= FRAME_DIRTY_SCROLLHORIZ;
- }
- hScrollbarTab = newTab;
- }
- else {
- if (hScrollbarTab != 0) {
- setDirty();
- whyDirty |= FRAME_DIRTY_SCROLLHORIZ;
- }
- hScrollbarTab = 0;
- }
-
- if ((scrollX != sX) || (scrollY != sY)) {
- scrollX = sX;
- scrollY = sY;
- clientArea->move(clientX + scrollX, clientY + scrollY);
- }
- }
- else {
- // No client, no scrollbars- reset to zero- dirty if wasn't already at zero
- if ((scrollX) || (scrollY)) {
- setDirty();
- whyDirty = FRAME_DIRTY_ALL;
- if (clientArea) clientArea->move(clientX, clientY);
- }
- scrollX = scrollY = 0;
- }
- }
- void WidgetScroll::whereCoords(int x, int y, DragType* dragType, DragSubType* dragItem) const { start_func
- assert(dragType);
- assert(dragItem);
- *dragType = FRAME_DRAG_NONE;
- *dragItem = FRAME_SCROLL_NONE;
- // Client area? Client *can* receive clicks outside it's actual area
- if ((clientArea) &&
- (x >= clientX) &&
- (y >= clientY) &&
- (x < clientX + clientWidthInner) &&
- (y < clientY + clientHeightInner)) {
- *dragType = FRAME_DRAG_CLIENT;
- }
- // Vertical scrollbar?
- else if ((x >= vScrollbarX) &&
- (x < vScrollbarX + vScrollbarWidth) &&
- (y >= vScrollbarY) &&
- (y < vScrollbarY + vScrollbarHeight)) {
- *dragType = FRAME_DRAG_SCROLLBAR_VERT;
-
- if (y < vScrollbarY + scrollbarButtonSize) *dragItem = FRAME_SCROLL_LESS;
- else if (y >= vScrollbarY + vScrollbarHeight - scrollbarButtonSize) *dragItem = FRAME_SCROLL_MORE;
- else if (y < vScrollbarY + scrollbarButtonSize + vScrollbarTab) *dragItem = FRAME_SCROLL_PAGELESS;
- else if (y >= vScrollbarY + scrollbarButtonSize + vScrollbarTab + vScrollbarTabSize) *dragItem = FRAME_SCROLL_PAGEMORE;
- else *dragItem = FRAME_SCROLL_TAB;
- }
- // Horizontal scrollbar?
- else if ((x >= hScrollbarX) &&
- (x < hScrollbarX + hScrollbarWidth) &&
- (y >= hScrollbarY) &&
- (y < hScrollbarY + hScrollbarHeight)) {
- *dragType = FRAME_DRAG_SCROLLBAR_HORIZ;
- if (x < hScrollbarX + scrollbarButtonSize) *dragItem = FRAME_SCROLL_LESS;
- else if (x >= hScrollbarX + hScrollbarWidth - scrollbarButtonSize) *dragItem = FRAME_SCROLL_MORE;
- else if (x < hScrollbarX + scrollbarButtonSize + hScrollbarTab) *dragItem = FRAME_SCROLL_PAGELESS;
- else if (x >= hScrollbarX + scrollbarButtonSize + hScrollbarTab + hScrollbarTabSize) *dragItem = FRAME_SCROLL_PAGEMORE;
- else *dragItem = FRAME_SCROLL_TAB;
- }
- }
- int WidgetScroll::event(int hasFocus, const SDL_Event* event) { start_func
- assert(event);
- DragType newDragMode;
- DragSubType newDragItem;
- int idleUsed = 0;
- Uint32 ticks;
- int mX, mY;
- int done = 0;
- Window* exempt = NULL;
-
- // We need to copy the event if we expect to change it to send a copy to client
- SDL_Event clientEvent = *event;
- switch (event->type) {
- case SDL_CLOSE:
- // Close client, then us
- if (clientArea) {
- int deleteClient = clientArea->wantsToBeDeleted();
- clientArea->event(hasFocus, &clientEvent);
- if (deleteClient) delete clientArea;
- else clientArea->setParent(NULL);
- clientArea = NULL;
- }
- return 1;
-
- case SDL_MOUSEBUTTONUP:
- if (dragMode == FRAME_DRAG_CLIENT) {
- // Adjust coordinates to 0-based for client
- if (clientArea) {
- clientEvent.button.x -= clientX + scrollX;
- clientEvent.button.y -= clientY + scrollY;
- // Propogate to client
- clientArea->event(hasFocus, &clientEvent);
- }
- if ((SDL_GetMouseState(NULL, NULL) & (SDL_BUTTON_LMASK | SDL_BUTTON_RMASK)) == 0) done = 1;
- }
- else if (event->button.button == SDL_BUTTON_LEFT) {
- if (dragMode == FRAME_DRAG_SCROLLBAR_HORIZ) {
- setDirty();
- whyDirty |= FRAME_DIRTY_SCROLLHORIZ;
- }
- else if (dragMode == FRAME_DRAG_SCROLLBAR_VERT) {
- setDirty();
- whyDirty |= FRAME_DIRTY_SCROLLVERT;
- }
- done = 1;
- }
-
- if (done) {
- whereCoords(event->motion.x, event->motion.y, &newDragMode, &newDragItem);
- if (newDragMode != dragMode) selectMouse(MOUSE_NORMAL);
- dragMode = FRAME_DRAG_NONE;
- scrollRepeatTicks = scrollRepeatDelay = 0;
- }
- break;
-
- case SDL_MOUSEBUTTONDBL:
- case SDL_MOUSEBUTTONDOWN:
- // Dragging/clicking what?
- whereCoords(event->button.x, event->button.y, &newDragMode, &newDragItem);
-
- if (newDragMode == FRAME_DRAG_CLIENT) {
- // No drag on wheels
- if ((event->button.button != SDL_BUTTON_WHEELUP) &&
- (event->button.button != SDL_BUTTON_WHEELDOWN)) {
- dragMode = newDragMode;
- dragItem = newDragItem;
- }
- // Adjust coordinates to 0-based for client
- if (clientArea) {
- clientEvent.button.x -= clientX + scrollX;
- clientEvent.button.y -= clientY + scrollY;
- // Propogate to client
- if (!clientArea->event(hasFocus, &clientEvent)) {
- // If not used, handle mouse wheel ourselves
- if (event->button.button == SDL_BUTTON_WHEELUP) {
- scrollTo(scrollX, scrollY + vScrollPage);
- }
- else if (event->button.button == SDL_BUTTON_WHEELDOWN) {
- scrollTo(scrollX, scrollY - vScrollPage);
- }
- }
- }
- }
- else if (((event->button.button == SDL_BUTTON_WHEELUP) || (event->button.button == SDL_BUTTON_WHEELDOWN)) &&
- ((newDragMode == FRAME_DRAG_SCROLLBAR_VERT) || (newDragMode == FRAME_DRAG_SCROLLBAR_HORIZ))) {
- if (newDragMode == FRAME_DRAG_SCROLLBAR_VERT) {
- setDirty();
- whyDirty |= FRAME_DIRTY_SCROLLVERT;
- if (event->button.button == SDL_BUTTON_WHEELUP) scrollTo(scrollX, scrollY + vScrollPage);
- else if (event->button.button == SDL_BUTTON_WHEELDOWN) scrollTo(scrollX, scrollY - vScrollPage);
- }
- if (newDragMode == FRAME_DRAG_SCROLLBAR_HORIZ) {
- setDirty();
- whyDirty |= FRAME_DIRTY_SCROLLHORIZ;
- if (event->button.button == SDL_BUTTON_WHEELUP) scrollTo(scrollX + hScrollPage, scrollY);
- else if (event->button.button == SDL_BUTTON_WHEELDOWN) scrollTo(scrollX - hScrollPage, scrollY);
- }
- }
- else if (event->button.button == SDL_BUTTON_LEFT) {
- if (newDragMode == FRAME_DRAG_SCROLLBAR_VERT) {
- setDirty();
- whyDirty |= FRAME_DIRTY_SCROLLVERT;
- scrollRepeatTicks = SDL_GetTicks();
- scrollRepeatDelay = DELAY_SCROLLBAR_REPEATSTART;
- if (newDragItem == FRAME_SCROLL_LESS) scrollTo(scrollX, scrollY + vScrollLine);
- else if (newDragItem == FRAME_SCROLL_MORE) scrollTo(scrollX, scrollY - vScrollLine);
- else if (newDragItem == FRAME_SCROLL_PAGELESS) scrollTo(scrollX, scrollY + vScrollPage);
- else if (newDragItem == FRAME_SCROLL_PAGEMORE) scrollTo(scrollX, scrollY - vScrollPage);
- // Force mouse motion to determine new drag mode
- SDL_GetMouseState(&mX, &mY);
- SDL_WarpMouse(mX, mY);
- }
- if (newDragMode == FRAME_DRAG_SCROLLBAR_HORIZ) {
- setDirty();
- whyDirty |= FRAME_DIRTY_SCROLLHORIZ;
- scrollRepeatTicks = SDL_GetTicks();
- scrollRepeatDelay = DELAY_SCROLLBAR_REPEATSTART;
- if (newDragItem == FRAME_SCROLL_LESS) scrollTo(scrollX + hScrollLine, scrollY);
- else if (newDragItem == FRAME_SCROLL_MORE) scrollTo(scrollX - hScrollLine, scrollY);
- else if (newDragItem == FRAME_SCROLL_PAGELESS) scrollTo(scrollX + hScrollPage, scrollY);
- else if (newDragItem == FRAME_SCROLL_PAGEMORE) scrollTo(scrollX - hScrollPage, scrollY);
- // Force mouse motion to determine new drag mode
- SDL_GetMouseState(&mX, &mY);
- SDL_WarpMouse(mX, mY);
- }
- dragMode = newDragMode;
- dragItem = newDragItem;
- dragX = event->button.x;
- dragY = event->button.y;
- dragItemOverflowX = 0;
- dragItemOverflowY = 0;
- }
- break;
- case SDL_MOUSEMOTION:
- if (dragMode == FRAME_DRAG_CLIENT) {
- // Adjust coordinates to 0-based for client
- if (clientArea) {
- clientEvent.motion.x -= clientX + scrollX;
- clientEvent.motion.y -= clientY + scrollY;
- // Propogate to client
- clientArea->event(hasFocus, &clientEvent);
- }
- }
- else if (event->motion.state & SDL_BUTTON_LMASK) {
- // Tab?
- if ((dragMode == FRAME_DRAG_SCROLLBAR_HORIZ) &&
- (dragItem == FRAME_SCROLL_TAB)) {
- int newX = hScrollbarTab + event->motion.xrel;
- // Overflow
- if (dragItemOverflowX) {
- newX += dragItemOverflowX;
- dragItemOverflowX = 0;
- }
- if (newX + hScrollbarTabSize > (hScrollbarWidth - scrollbarButtonSize * 2)) {
- dragItemOverflowX = newX + hScrollbarTabSize - (hScrollbarWidth - scrollbarButtonSize * 2);
- newX -= dragItemOverflowX;
- }
- if (newX < 0) {
- dragItemOverflowX = newX;
- newX = 0;
- }
-
- // Scroll to right spot
- scrollTo(newX * (clientWidthInner - clientActualWidth) / (hScrollbarWidth - (scrollbarButtonSize * 2) - hScrollbarTabSize), scrollY, newX, -1);
- }
- else if ((dragMode == FRAME_DRAG_SCROLLBAR_VERT) &&
- (dragItem == FRAME_SCROLL_TAB)) {
- int newY = vScrollbarTab + event->motion.yrel;
- // Overflow
- if (dragItemOverflowY) {
- newY += dragItemOverflowY;
- dragItemOverflowY = 0;
- }
- if (newY + vScrollbarTabSize > (vScrollbarHeight - scrollbarButtonSize * 2)) {
- dragItemOverflowY = newY + vScrollbarTabSize - (vScrollbarHeight - scrollbarButtonSize * 2);
- newY -= dragItemOverflowY;
- }
- if (newY < 0) {
- dragItemOverflowY = newY;
- newY = 0;
- }
-
- // Scroll to right spot
- scrollTo(scrollX, newY * (clientHeightInner - clientActualHeight) / (vScrollbarHeight - (scrollbarButtonSize * 2) - vScrollbarTabSize), -1, newY);
- }
- // Scrollbar?
- else if ((dragMode == FRAME_DRAG_SCROLLBAR_HORIZ) ||
- (dragMode == FRAME_DRAG_SCROLLBAR_VERT)) {
- whereCoords(event->motion.x, event->motion.y, &newDragMode, &newDragItem);
- if (dragMode == newDragMode) {
- if (dragItem != newDragItem) {
- dragItem = newDragItem;
- setDirty();
- if (dragMode == FRAME_DRAG_SCROLLBAR_HORIZ) whyDirty |= FRAME_DIRTY_SCROLLHORIZ;
- else whyDirty |= FRAME_DIRTY_SCROLLVERT;
- }
- }
- else {
- if (dragItem != FRAME_SCROLL_NONE) {
- dragItem = FRAME_SCROLL_NONE;
- setDirty();
- if (dragMode == FRAME_DRAG_SCROLLBAR_HORIZ) whyDirty |= FRAME_DIRTY_SCROLLHORIZ;
- else whyDirty |= FRAME_DIRTY_SCROLLVERT;
- }
- }
- }
- }
- // Just hover?
- else {
- whereCoords(event->motion.x, event->motion.y, &newDragMode, &newDragItem);
- if (newDragMode == FRAME_DRAG_CLIENT) {
- // Adjust coordinates to 0-based for client
- if (clientArea) {
- clientEvent.motion.x -= clientX + scrollX;
- clientEvent.motion.y -= clientY + scrollY;
-
- // Propogate to client
- clientArea->event(hasFocus, &clientEvent);
- }
- }
- else selectMouse(MOUSE_NORMAL);
- }
- break;
-
- case SDL_INPUTFOCUS:
- if ((event->user.code & 1) && (!haveFocus)) {
- haveFocus = 1;
-
- // Propogate to client
- if (clientArea) {
- clientArea->event(hasFocus, &clientEvent);
- }
- }
- else if (!(event->user.code & 1) && (haveFocus)) {
- haveFocus = 0;
- // Propogate to client
- if (clientArea) {
- clientArea->event(hasFocus, &clientEvent);
- }
- }
- break;
-
- case SDL_SPECIAL:
- // Scrollbar repeat?
- if ((event->user.code & SDL_IDLE) && (scrollRepeatDelay)) {
- ticks = SDL_GetTicks();
- // (catch wraparound)
- if (ticks < scrollRepeatTicks) scrollRepeatTicks = SDL_GetTicks();
- else if (ticks - scrollRepeatTicks > scrollRepeatDelay) {
- scrollRepeatTicks = SDL_GetTicks();
- scrollRepeatDelay = DELAY_SCROLLBAR_REPEATAGAIN;
- if (dragMode == FRAME_DRAG_SCROLLBAR_VERT) {
- if (dragItem == FRAME_SCROLL_LESS) scrollTo(scrollX, scrollY + vScrollLine);
- else if (dragItem == FRAME_SCROLL_MORE) scrollTo(scrollX, scrollY - vScrollLine);
- else if (dragItem == FRAME_SCROLL_PAGELESS) scrollTo(scrollX, scrollY + vScrollPage);
- else if (dragItem == FRAME_SCROLL_PAGEMORE) scrollTo(scrollX, scrollY - vScrollPage);
- }
- if (dragMode == FRAME_DRAG_SCROLLBAR_HORIZ) {
- if (dragItem == FRAME_SCROLL_LESS) scrollTo(scrollX + hScrollLine, scrollY);
- else if (dragItem == FRAME_SCROLL_MORE) scrollTo(scrollX - hScrollLine, scrollY);
- else if (dragItem == FRAME_SCROLL_PAGELESS) scrollTo(scrollX + hScrollPage, scrollY);
- else if (dragItem == FRAME_SCROLL_PAGEMORE) scrollTo(scrollX - hScrollPage, scrollY);
- }
- // Force mouse motion to determine new drag mode
- SDL_GetMouseState(&mX, &mY);
- SDL_WarpMouse(mX, mY);
- idleUsed = 1;
- }
- }
- // (continue on, to propogate to client)
-
- case SDL_MOUSEFOCUS:
- // (we can just propogate MOUSEFOCUS, since we are virtually equal
- // to our child window in size anyways)
- case SDL_COMMAND:
- case SDL_QUIT:
- case SDL_SYSKEY:
- case SDL_OBJECTCHANGE:
- // (exempt window may exist)
- exempt = (Window*)clientEvent.user.data2;
- default:
- // Propogate to client
- if ((clientArea) && (clientArea != exempt)) {
- return (clientArea->event(hasFocus, &clientEvent) || idleUsed);
- }
- return idleUsed;
- }
- // All mouse and focus events, we use.
- return 1;
- }
- int WidgetScroll::stateTabId() const { start_func
- if (clientWidget) return clientWidget->stateTabId();
- return Widget::stateTabId();
- }
- int WidgetScroll::stateTabId(int wTabId) { start_func
- if (clientWidget) return clientWidget->stateTabId(wTabId);
- return Widget::stateTabId(wTabId);
- }
- int WidgetScroll::refuseAll() const { start_func
- if (clientWidget) return clientWidget->refuseAll();
- if (clientArea) return Widget::refuseAll();
- return 1;
- }
-
- void WidgetScroll::doAction() { start_func
- if (clientWidget) clientWidget->doAction();
- return;
- }
- char WidgetScroll::getShortcut() const { start_func
- if (clientWidget) return clientWidget->getShortcut();
- return 0;
- }
- int WidgetScroll::getId() const { start_func
- if (clientWidget) return clientWidget->getId();
- return Widget::getId();
- }
- void WidgetScroll::disable() { start_func
- if (clientWidget) clientWidget->disable();
- Widget::disable();
- }
- void WidgetScroll::enable() { start_func
- if (clientWidget) clientWidget->enable();
- Widget::enable();
- }
- void WidgetScroll::load() { start_func
- if (clientWidget) clientWidget->load();
- }
- void WidgetScroll::apply() { start_func
- if (clientWidget) clientWidget->apply();
- }
- void WidgetScroll::resolutionChange(int fromW, int fromH, int fromBpp, int toW, int toH, int toBpp) { start_func
- Window::resolutionChange(fromW, fromH, fromBpp, toW, toH, toBpp);
- if (clientArea != NULL) clientArea->resolutionChange(fromW, fromH, fromBpp, toW, toH, toBpp);
- }
- const char* WidgetScroll::tooltip(int xPos, int yPos) const { start_func
- if (clientWidget) {
- xPos -= clientX + scrollX;
- yPos -= clientY + scrollY;
- return clientWidget->tooltip(xPos, yPos);
- }
- return Widget::tooltip(xPos, yPos);
- }
|