1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711 |
- /* GCSx
- ** GUI.CPP
- **
- ** Base gui classes and code
- */
- /*****************************************************************************
- ** 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"
- SDLKey Desktop::keypadConvert[10] = {
- SDLK_INSERT,
- SDLK_END,
- SDLK_DOWN,
- SDLK_PAGEDOWN,
- SDLK_LEFT,
- SDLK_KP5,
- SDLK_RIGHT,
- SDLK_HOME,
- SDLK_UP,
- SDLK_PAGEUP,
- };
-
- int Window::nextId = 1;
- Desktop* desktop = NULL;
- WindowParent::~WindowParent() { start_func
- }
- WindowCollection::WindowCollection() : windowDataDisplay(), windowDataFocus() { start_func
- handleEvents = NULL;
- currentFocus = NULL;
- previousFocus = NULL;
- lastFocus = NULL;
- currentMouseFocus = NULL;
- lastMouseX = -1;
- lastMouseY = -1;
- modalPos = NULL;
- allowDesktopClick = 0;
-
- overallWidth = 0;
- overallHeight = 0;
- canvasX = 0;
- canvasY = 0;
- canvasWidth = 0;
- canvasHeight = 0;
-
- updateRect.w = 0;
- }
- WindowCollection::~WindowCollection() { start_func
- }
- void WindowCollection::addToUpdateRect(const Rect& add) { start_func
- boundRects(updateRect, add);
- }
- void WindowCollection::setEventHandler(int (*eventHandler)(const SDL_Event* event)) { start_func
- handleEvents = eventHandler;
- }
- // (verify that a window is still part of the collection)
- int WindowCollection::verifyWindow(const Window* target) const { start_func
- if (target == NULL) return 0;
- list<Window*>::const_iterator end = windowDataDisplay.end();
- for (list<Window*>::const_iterator pos = windowDataDisplay.begin(); pos != end; ++pos) {
- assert(*pos);
- if (*pos == target) return 1;
- }
- return 0;
- }
- Window* WindowCollection::verifyWindow(int targetId) { start_func
- if (targetId == 0) return NULL;
- list<Window*>::iterator end = windowDataDisplay.end();
- for (list<Window*>::iterator pos = windowDataDisplay.begin(); pos != end; ++pos) {
- assert(*pos);
- if ((*pos)->getId() == targetId) return *pos;
- }
- return NULL;
- }
- // Run an event
- // (after running an SDL_CLOSE event, any window pointers other than 'target' we have can't be trusted)
- int WindowCollection::windowRunEvent(Window* target, const SDL_Event* event) { start_func
- assert(target);
- assert(event);
- return target->event(currentFocus == target, event);
- }
- // (internal- find top window by coordinates)
- const Window* WindowCollection::findWindowByCoords(int x, int y) const { start_func
- list<Window*>::const_reverse_iterator end = windowDataDisplay.rend();
- for (list<Window*>::const_reverse_iterator pos = windowDataDisplay.rbegin(); pos != end; ++pos) {
- assert(*pos);
- if ((*pos)->isCoords(x, y)) return *pos;
- }
- return NULL;
- }
- Window* WindowCollection::findWindowByCoords(int x, int y) { start_func
- list<Window*>::reverse_iterator end = windowDataDisplay.rend();
- for (list<Window*>::reverse_iterator pos = windowDataDisplay.rbegin(); pos != end; ++pos) {
- assert(*pos);
- if ((*pos)->isCoords(x, y)) return *pos;
- }
- return NULL;
- }
- // (internal- tell new window it has mouse focus, if applicable; revert to normal mouse pointer)
- Window* WindowCollection::recheckMouseFocus(int sendMoveEvent) { start_func
- Window* window = findWindowByCoords(lastMouseX, lastMouseY);
-
- // Refusing?
- if (window) {
- if (window->refuseAll()) window = NULL;
- }
-
- // Disallow mouse focus on anything but the current modal window OR a window
- // sorted above it (if not on modal window, go to NULL)
- if (modalPos) {
- if (!window) {
- window = NULL;
- }
- else if ((window->windowSort() <= Window::WINDOWSORT_MODAL) && (window != modalPos)) {
- window = NULL;
- }
- }
-
- if (window != currentMouseFocus) {
- desktop->focusEvent(SDL_MOUSEFOCUS, 0, currentMouseFocus);
- desktop->focusEvent(SDL_MOUSEFOCUS, 1, window);
- currentMouseFocus = window;
- selectMouse(MOUSE_NORMAL);
- if (sendMoveEvent) {
- SDL_Event customEvent;
- customEvent.type = SDL_MOUSEMOTION;
- customEvent.motion.x = lastMouseX;
- customEvent.motion.y = lastMouseY;
- customEvent.motion.state = SDL_GetMouseState(NULL, NULL);
- customEvent.motion.xrel = 0;
- customEvent.motion.yrel = 0;
- insertEvent(&customEvent);
- }
- }
-
- return window;
- }
- // (internal- tell new window it has input focus)
- int WindowCollection::changeInputFocus(Window* window, int toTop) { start_func
- if (window != currentFocus) {
- // Refusing?
- if (window) {
- if (window->refuseAll()) return 0;
- }
- if ((window) && (toTop)) {
- // Bring to top of focus stack first
- bringToTop(window);
-
- // bringToTop called us, so we're done
- return 1;
- }
-
- // Always announce desktop losing focus
- if ((!currentFocus) && (allowDesktopClick) && (this == desktop)) desktop->broadcastEvent(SDL_SPECIAL, SDL_DESKTOPINACTIVE);
-
- // Possibilities-
- // tempFocus to tempFocus- normal focus change
- // normal/blank to normal/blank- normal focus change, kill previousfocus
-
- // normal/blank to tempFocus- old focus doesn't "lose" it
- // tempFocus to normal/blank- both temp and previous focus lose it, even if changing
- // back to the previous, it still must lose it temp.
- int from = 0;
- int to = 0;
- if (currentFocus) {
- if (currentFocus->tempFocus()) from = 1;
- }
- if (window) {
- if (window->tempFocus()) to = 1;
- }
-
- if (from == to) {
- desktop->focusEvent(SDL_INPUTFOCUS, 0, currentFocus);
- // From normal to normal, if we STILL have a previous focus...
- if (!to) {
- // Kill it. If it's the new focus window, tho, don't send an event.
- if ((previousFocus != window) && (previousFocus)) desktop->focusEvent(SDL_INPUTFOCUS, 0, previousFocus);
- previousFocus = NULL;
- }
- }
- else if (from == 0) {
- previousFocus = currentFocus;
- }
- else {
- desktop->focusEvent(SDL_INPUTFOCUS, 0, previousFocus);
- desktop->focusEvent(SDL_INPUTFOCUS, 0, currentFocus);
- previousFocus = NULL;
- }
- desktop->focusEvent(SDL_INPUTFOCUS, 1, window);
- currentFocus = window;
- // Always announce desktop gaining focus
- if ((!currentFocus) && (allowDesktopClick) && (this == desktop)) desktop->broadcastEvent(SDL_SPECIAL, SDL_DESKTOPACTIVE);
- return 1;
- }
- return 0;
- }
- void WindowCollection::resolutionChange(int fromW, int fromH, int fromBpp, int toW, int toH, int toBpp) { start_func
- list<Window*>::iterator end = windowDataDisplay.end();
- for (list<Window*>::iterator pos = windowDataDisplay.begin(); pos != end; ++pos) {
- assert(*pos);
- (*pos)->resolutionChange(fromW, fromH, fromBpp, toW, toH, toBpp);
- }
-
- // Call AFTER resizing windows, as the docked ones have now rearranged themselves
- adjustCanvas();
- }
- // (internal- adjust our canvas size/pos to match any currently docked windows)
- void WindowCollection::adjustCanvas() { start_func
- // (skip if we aren't using this feature)
- if ((overallWidth) && (overallHeight)) {
- canvasX = 0;
- canvasY = 0;
- int canvasRight = overallWidth;
- int canvasBottom = overallHeight;
-
- // Scan all windows for docked ones
- list<Window*>::iterator end = windowDataDisplay.end();
- for (list<Window*>::iterator pos = windowDataDisplay.begin(); pos != end; ++pos) {
- Window* wpos = *pos;
- assert(wpos);
- if (wpos->isDocked()) {
- // Determine what edge it is docked at based on what screen edges it touches
- // If a window touches two opposite edges, neither is the docking edge
- // (for example, menubar touches left/right but is docked at the top)
- if ((wpos->getX() <= 0) && (wpos->getX() + wpos->getWidth() < overallWidth)) {
- // Left edge- increase canvasX if needed
- int size = wpos->getWidth() + wpos->getX();
- if (size > canvasX) canvasX = size;
- }
- if ((wpos->getX() + wpos->getWidth() >= overallWidth) && (wpos->getX() > 0)) {
- // Right edge- decrease canvasRight if needed
- if (wpos->getX() < canvasRight) canvasRight = wpos->getX();
- }
- if ((wpos->getY() <= 0) && (wpos->getY() + wpos->getHeight() < overallHeight)) {
- // Top edge- increase canvasY if needed
- int size = wpos->getHeight() + wpos->getY();
- if (size > canvasY) canvasY = size;
- }
- if ((wpos->getY() + wpos->getHeight() >= overallHeight) && (wpos->getY() > 0)) {
- // Bottom edge- decrease canvasBottom if needed
- if (wpos->getY() < canvasBottom) canvasBottom = wpos->getY();
- }
- }
- }
- canvasWidth = canvasRight - canvasX;
- canvasHeight = canvasBottom - canvasY;
- // Here, we "force" any frame windows to be within our confines
- for (list<Window*>::iterator pos = windowDataDisplay.begin(); pos != end; ++pos) {
- Window* wpos = *pos;
- assert(wpos);
- if (typeid(*wpos) == typeid(FrameWindow)) {
- dynamic_cast<FrameWindow*>(wpos)->redoSize();
- }
- }
- }
- }
- void Window::move(int xPos, int yPos) { start_func
- int prevX = x;
- int prevY = y;
- x = xPos;
- y = yPos;
- // @TODO: At some point we might be able to scroll data and just redraw
- // partial or not at all
- setDirty(1);
- if (parent) parent->childMoved(prevX, prevY, x, y, this);
- }
- void Window::resize(int newWidth, int newHeight, int newViewWidth, int newViewHeight, int fromParent) { start_func
- int updateParent = 0;
- int oldWidth = width;
- int oldHeight = height;
- if (newViewWidth < 0) newViewWidth = viewWidth;
- if (newViewHeight < 0) newViewHeight = viewHeight;
-
- // Compare so we don't resize if not needed and to prevent unneeded recursion
- if ((newWidth != width) || (newHeight != height) ||
- (newViewWidth != viewWidth) || (newViewHeight != viewHeight)) {
- if ((newWidth != width) || (newHeight != height)) updateParent = 1;
-
- viewWidth = newViewWidth;
- viewHeight = newViewHeight;
- width = newWidth;
- height = newHeight;
- setDirty(1);
-
- // Update parent, including FrameWindow or WidgetScroll if there is one
- if ((parent) && (!fromParent) && (updateParent)) {
- parent->childResized(oldWidth, oldHeight, width, height, this);
- if (typeid(*parent) == typeid(FrameWindow)) {
- dynamic_cast<FrameWindow*>(parent)->updateClientSize();
- }
- else if (typeid(*parent) == typeid(WidgetScroll)) {
- dynamic_cast<WidgetScroll*>(parent)->updateClientSize();
- }
- }
- }
-
- if ((width > 0) && (height > 0) && (parent) && (viewWidth != 0) && (viewHeight != 0)) visible = 1;
- else visible = 0;
- }
- int Window::attemptClose() { start_func
- return 1;
- }
- /* Not currently used or supported
- int Window::usesAlpha() const { start_func
- return 0;
- }
- */
- int Window::isDocked() const { start_func
- return 0;
- }
- int Window::tempFocus() const { start_func
- return 0;
- }
- int Window::refuseAll() const { start_func
- return 0;
- }
- Window::CommandSupport Window::supportsCommand(int code) const { start_func
- return COMMAND_HIDE;
- }
- Window::WindowType Window::windowType() const { start_func
- return WINDOW_UNKNOWN;
- }
- int Window::wantsToBeDeleted() const { start_func
- return 1;
- }
- Window::WindowSort Window::windowSort() const { start_func
- return WINDOWSORT_NORMAL;
- }
- int Window::isOnDesktop() const { start_func
- if (parent) {
- if (parent == desktop) return desktop->verifyWindow(this);
- else return dynamic_cast<Window*>(parent)->isOnDesktop();
- }
- return 0;
- }
-
- void Window::closeWindow(int skipAttempt) { start_func
- if (isOnDesktop()) {
- if ((parent) && (parent != desktop)) {
- dynamic_cast<FrameWindow*>(parent)->closeWindow(skipAttempt);
- }
- else {
- if (!skipAttempt) {
- if (!attemptClose()) return;
- }
- desktop->focusEvent(SDL_CLOSE, 0, this);
- }
- }
- }
- const char* Window::tooltip(int xPos, int yPos) const { start_func
- return NULL;
- }
- int Window::isCoords(int xPos, int yPos) const { start_func
- if ((xPos >= x) && (yPos >= y) && (xPos < x + width) && (yPos < y + height)) return 1;
- return 0;
- }
- int Window::getId() const { start_func
- return id;
- }
- int Window::getX() const { start_func
- return x;
- }
- int Window::getY() const { start_func
- return y;
- }
- int Window::getScreenX() const { start_func
- if (parent) return parent->getScreenX() + x;
- return x;
- }
- int Window::getScreenY() const { start_func
- if (parent) return parent->getScreenY() + y;
- return y;
- }
- int Window::getWidth() const { start_func
- return width;
- }
- int Window::getHeight() const { start_func
- return height;
- }
- void Window::getRect(Rect& rect) const { start_func
- rect.x = x;
- rect.y = y;
- rect.w = width;
- rect.h = height;
- }
- void Window::undoNotify(int undoType, int undoItemId, int undoItemSubId, int uX, int uY, int uW, int uH) { start_func
- }
- Window::Window() { start_func
- parent = NULL;
- parentNotify = NULL;
- visible = 0;
- id = nextId++;
-
- width = height = -1;
- viewWidth = viewHeight = -1;
-
- dirty = 1;
- totalDirty = 1;
- childDirty = 0;
- }
- Window::~Window() { start_func
- if (parent) parent->childDeleted(this);
- if ((parentNotify) && (parentNotify != parent)) parentNotify->childDeleted(this);
- cleanEvents(this);
- }
- #ifndef NDEBUG
- const char* Window::debugDump() const { start_func
- return "(untyped window)";
- }
- #endif
- void Window::setDirty(int total) { start_func
- if (total) totalDirty = 1;
- if (!dirty) {
- dirty = 1;
- if (parent) parent->setChildDirty();
- }
- }
- void Window::childMoved(int fromX, int fromY, int toX, int toY, Window* child) { start_func
- assert(child);
- }
- void Window::childResized(int fromW, int fromH, int toW, int toH, Window* child) { start_func
- assert(child);
- }
- void Window::childDeleted(Window* child) { start_func
- assert(child);
- }
- void Window::childModified(Window* child) { start_func
- assert(child);
- if (parent) parent->childModified(child);
- }
- void Window::siblingModified(Window* sibling) { start_func
- assert(sibling);
- }
- void Window::setChildDirty() { start_func
- childDirty = 1;
- if (parent) parent->setChildDirty();
- }
- int Window::isDirty() const { start_func
- // Don't check totalDirty, it's never set if dirty isn't set
- return dirty || childDirty;
- }
- void Window::setParent(WindowParent* wParent) { start_func
- parent = wParent;
- if ((width > 0) && (height > 0) && (parent) && (viewWidth != 0) && (viewHeight != 0)) visible = 1;
- else visible = 0;
- if ((dirty) && (parent)) parent->setChildDirty();
- }
- void Window::setParentNotify(WindowParent* wParentNotify) { start_func
- parentNotify = wParentNotify;
- }
- void Window::resolutionChange(int fromW, int fromH, int fromBpp, int toW, int toH, int toBpp) { start_func
- // Default does nothing
- }
- void WindowCollection::addWindow(Window* item, int giveFocus) { start_func
- assert(item);
-
- // Abort if already part of our collection
- if (verifyWindow(item)) return;
- Window::WindowSort sortType = item->windowSort();
- // Scan through windows until we find one of equal/lower sort value
- // (can't use reverse iterator)
- list<Window*>::iterator pos = windowDataDisplay.end();
- list<Window*>::iterator begin = windowDataDisplay.begin();
- while (pos != begin) {
- --pos;
- assert(*pos);
- if ((*pos)->windowSort() <= sortType) {
- // Insert after this one
- ++pos; // Move one element back towards the end of the list
- windowDataDisplay.insert(pos, item);
- break;
- }
- }
-
- if (pos == windowDataDisplay.begin()) {
- // Insert at beginning
- windowDataDisplay.push_front(item);
- }
-
- // Add to focus stack at beginning or end
- if ((giveFocus) || (sortType == Window::WINDOWSORT_MODAL)) {
- windowDataFocus.push_back(item);
- }
- else {
- windowDataFocus.push_front(item);
- }
- item->setParent(this);
- Rect toUpdate;
- item->getRect(toUpdate);
- addToUpdateRect(toUpdate);
- if (item->isDocked()) adjustCanvas();
- recheckMouseFocus(1);
- if ((giveFocus) || (sortType == Window::WINDOWSORT_MODAL)) changeInputFocus(item);
- if (sortType == Window::WINDOWSORT_MODAL) modalPos = item;
- }
- void WindowCollection::removeWindow(Window* item) { start_func
- assert(item);
- Window* highestModal = NULL;
-
- // Main list of windows
- // (can't use reverse iterators)
- // Note that we purposely use windowDataDisplay here
- // and windowDataFocus in deleteAllWindows
- list<Window*>::iterator pos = windowDataDisplay.end();
- list<Window*>::iterator found = windowDataDisplay.end();
- list<Window*>::iterator begin = windowDataDisplay.begin();
- while (pos != begin) {
- --pos;
- assert(*pos);
- if (*pos == item) {
- found = pos;
- }
- else if (!highestModal) {
- if ((*pos)->windowSort() == Window::WINDOWSORT_MODAL) highestModal = *pos;
- }
- }
-
- if (found != windowDataDisplay.end()) {
- // Found- remove
- item->setParent(NULL);
- if (previousFocus == item) previousFocus = NULL;
- Rect toUpdate;
- item->getRect(toUpdate);
- addToUpdateRect(toUpdate);
- windowDataDisplay.erase(found);
- cleanEvents(item);
-
- // Also remove from focus stack
- for (pos = windowDataFocus.begin(); pos != windowDataFocus.end(); ++pos) {
- assert(*pos);
- if (*pos == item) {
- windowDataFocus.erase(pos);
- break;
- }
- }
-
- if (item->isDocked()) adjustCanvas();
-
- if (currentMouseFocus == item) {
- currentMouseFocus = NULL;
- recheckMouseFocus(1);
- }
- if (modalPos == item) {
- modalPos = highestModal;
- }
- if (currentFocus == item) {
- // (remove before swapping, to prevent it from showing up in previousFocus)
- currentFocus = NULL;
- if (previousFocus) changeInputFocus(previousFocus);
- else if (!windowDataFocus.empty()) changeInputFocus(*(--windowDataFocus.end()));
- else changeInputFocus(NULL);
- }
- }
-
- assert(item != currentFocus);
- assert(item != previousFocus);
- assert(item != currentMouseFocus);
- }
- // pos = 0 for first, 1 for second, etc.
- Window* WindowCollection::findWindow(Window::WindowType type, int pos) { start_func
- assert(pos >= 0);
- assert(type > Window::WINDOW_UNKNOWN);
- assert(type <= Window::WINDOW_LASTTYPE);
- // This function by definition searches focus stack (see header)
- list<Window*>::iterator iend = windowDataFocus.end();
- for (list<Window*>::iterator ipos = windowDataFocus.begin(); ipos != iend; ++ipos) {
- assert(*ipos);
- if ((*ipos)->windowType() == type) {
- if (pos == 0) return *ipos;
- --pos;
- }
- }
- return NULL;
- }
- Window* WindowCollection::findFocusWindow() { start_func
- return currentFocus;
- }
- Window* WindowCollection::findPreviousFocusWindow() { start_func
- if (previousFocus) return previousFocus;
- return currentFocus;
- }
- void WindowCollection::bringToTop(Window* item, int giveFocus) { start_func
- if (!item) {
- if ((allowDesktopClick) && (!modalPos)) changeInputFocus(NULL, 0);
- return;
- }
-
- int found = 0;
-
- // First, find and remove...
- list<Window*>::iterator end = windowDataDisplay.end();
- for (list<Window*>::iterator pos = windowDataDisplay.begin(); pos != end; ++pos) {
- assert(*pos);
- if (*pos == item) {
- windowDataDisplay.erase(pos);
- found = 1;
- break;
- }
- }
-
- // Then, insert
- if (found) {
- int sortType = item->windowSort();
- // (can't use reverse iterator)
- list<Window*>::iterator pos = windowDataDisplay.end();
- list<Window*>::iterator begin = windowDataDisplay.begin();
- while (pos != begin) {
- --pos;
- assert(*pos);
- if ((*pos)->windowSort() <= sortType) {
- // Insert after this one
- ++pos; // Move one element back towards the end of the list
- windowDataDisplay.insert(pos, item);
- break;
- }
- }
- if (pos == windowDataDisplay.begin()) {
- // Insert at beginning
- windowDataDisplay.push_front(item);
- }
-
- // Find and move in focus stack too?
- if (giveFocus) {
- for (pos = windowDataFocus.begin(); pos != windowDataFocus.end(); ++pos) {
- assert(*pos);
- if (*pos == item) {
- windowDataFocus.erase(pos);
- windowDataFocus.push_back(item);
- break;
- }
- }
-
- changeInputFocus(item, 0); // Don't recurse to bringToTop again
- }
- Rect toUpdate;
- item->getRect(toUpdate);
- addToUpdateRect(toUpdate);
- recheckMouseFocus(1);
- }
- }
- void WindowCollection::sendToBottom(Window* item) { start_func
- assert(item);
- int found = 0;
-
- // First, find and remove...
- list<Window*>::iterator end = windowDataDisplay.end();
- for (list<Window*>::iterator pos = windowDataDisplay.begin(); pos != end; ++pos) {
- assert(*pos);
- if (*pos == item) {
- windowDataDisplay.erase(pos);
- found = 1;
- break;
- }
- }
-
- // Then, insert
- if (found) {
- Window::WindowSort sortType = item->windowSort();
- list<Window*>::iterator end = windowDataDisplay.end();
- list<Window*>::iterator pos;
- for (pos = windowDataDisplay.begin(); pos != end; ++pos) {
- assert(*pos);
- if ((*pos)->windowSort() >= sortType) {
- // Insert before this one
- windowDataDisplay.insert(pos, item);
- break;
- }
- }
- if (pos == windowDataDisplay.end()) {
- // Insert at end
- windowDataDisplay.push_back(item);
- }
-
- // Now, find in focus stack, move to bottom
- end = windowDataFocus.end();
- for (pos = windowDataFocus.begin(); pos != end; ++pos) {
- assert(*pos);
- if (*pos == item) {
- windowDataFocus.erase(pos);
- windowDataFocus.push_front(item);
- break;
- }
- }
- if (currentFocus == item) {
- if (previousFocus) changeInputFocus(previousFocus);
- else changeInputFocus(*(--windowDataFocus.end()));
- }
- Rect toUpdate;
- item->getRect(toUpdate);
- addToUpdateRect(toUpdate);
- }
- }
- int WindowCollection::handleEvent(const SDL_Event* event) { start_func
- Window* window = NULL;
- Window* exempt = NULL;
- int broadcast = 0;
-
- assert(event);
- SDL_Event eventCopy = *event;
- // Select appropriate window
- switch (eventCopy.type) {
- case SDL_NOEVENT:
- return 0;
-
- case SDL_QUIT:
- case SDL_SYSKEY:
- case SDL_SPECIAL:
- case SDL_OBJECTCHANGE:
- // (exempt window may exist)
- exempt = (Window*)eventCopy.user.data2;
- case SDL_ACTIVEEVENT:
- case SDL_VIDEORESIZE:
- case SDL_VIDEOEXPOSE:
- broadcast = 1;
- break;
-
- case SDL_CLOSE:
- case SDL_INPUTFOCUS:
- case SDL_MOUSEFOCUS:
- // Window is defined as part of the event
- window = (Window*)eventCopy.user.data1;
- // (global SDL_CLOSE events not currently used, but can be supported)
- // if (window == NULL) broadcast = 1;
- // This will catch it if it recurses/loops back to us by mistake
- assert(window);
- eventCopy.user.data1 = NULL;
- break;
- case SDL_COMMAND:
- case SDL_KEYDOWN:
- case SDL_KEYUP:
- window = currentFocus;
- if (!window) {
- // @TODO: don't break if we ever start broadcasting keyups/commandreleases
- if (eventCopy.type == SDL_KEYUP) break;
- if (eventCopy.type == SDL_KEYDOWN) eventCopy.type = SDL_SYSKEY;
- broadcast = 1;
- }
- break;
- case SDL_MOUSEMOTION:
- lastMouseX = eventCopy.motion.x;
- lastMouseY = eventCopy.motion.y;
- // If a button is pressed, we keep the previous focus indefinitely
- if ((eventCopy.motion.state & SDL_BUTTON_LMASK) || (eventCopy.motion.state & SDL_BUTTON_RMASK)) {
- window = currentMouseFocus;
- }
- else {
- window = recheckMouseFocus();
- }
-
- // Adjust coordinates to 0-based for window
- if (window) {
- eventCopy.motion.x -= window->getX();
- eventCopy.motion.y -= window->getY();
- }
- break;
- case SDL_MOUSEBUTTONUP:
- // Mouse release also retains previous window focus
- lastMouseX = eventCopy.button.x;
- lastMouseY = eventCopy.button.y;
- window = currentMouseFocus;
- // Adjust coordinates to 0-based for window
- if (window) {
- eventCopy.button.x -= window->getX();
- eventCopy.button.y -= window->getY();
- }
- break;
- case SDL_MOUSEBUTTONDBL:
- case SDL_MOUSEBUTTONDOWN:
- lastMouseX = eventCopy.button.x;
- lastMouseY = eventCopy.button.y;
- window = recheckMouseFocus();
- // Adjust coordinates to 0-based for window
- if ((window) || ((allowDesktopClick) && (!modalPos))) {
- // No focus on wheels
- if ((event->button.button != SDL_BUTTON_WHEELUP) &&
- (event->button.button != SDL_BUTTON_WHEELDOWN)) {
- changeInputFocus(window);
- }
- if (window) {
- eventCopy.button.x -= window->getX();
- eventCopy.button.y -= window->getY();
- }
- }
- else if (currentFocus) {
- // NULL focus will take away focus from a tempfocus window (popup)
- if ((currentFocus->tempFocus()) &&
- (event->button.button != SDL_BUTTON_WHEELUP) &&
- (event->button.button != SDL_BUTTON_WHEELDOWN)) {
- if (previousFocus) changeInputFocus(previousFocus);
- else changeInputFocus(NULL);
- }
- }
- break;
-
- default:
- return 0;
- }
- // Propogate event
- if (window) {
- // Don't recurse (never broadcast in this case, either)
- if ((void*)window == (void*)this) return 0;
-
- // Refusing?
- if (!window->refuseAll()) {
- // single window event, is allowed to close
- if (windowRunEvent(window, &eventCopy)) {
- if ((eventCopy.type == SDL_CLOSE) && (window->wantsToBeDeleted())) {
- delete window;
- }
- return 1;
- }
- }
-
- // If window is a floating panel of another window, attempt key/cmd there
- if ((typeid(*window) == typeid(FrameWindow)) && (!modalPos)) {
- if (dynamic_cast<FrameWindow*>(window)->getFramePanel()) {
- if ((eventCopy.type == SDL_KEYDOWN) || (eventCopy.type == SDL_KEYUP) || (eventCopy.type == SDL_COMMAND)) {
- if (windowRunEvent(dynamic_cast<FrameWindow*>(window)->getFramePanel(), &eventCopy)) return 1;
- }
- }
- }
- // Keypresses now broadcast unless modal window open
- if ((eventCopy.type == SDL_KEYDOWN) && (!modalPos)) {
- eventCopy.type = SDL_SYSKEY;
- broadcast = 1;
- }
- // If modal window, run as shortcut
- else if ((eventCopy.type == SDL_KEYDOWN) && (this == desktop)) {
- int count = config->readShortcut(eventCopy.key.keysym.sym, eventCopy.key.keysym.mod, 0);
- if (count) {
- // Recurse through all potential shortcuts
- for (int pos = 1; pos <= count; ++pos) {
- int cmd = config->readShortcut(eventCopy.key.keysym.sym, eventCopy.key.keysym.mod, pos);
- // Stop when one works
- if (desktop->broadcastEvent(SDL_COMMAND, cmd, NULL, NULL, 1)) {
- desktop->lastShortcutKey = eventCopy.key.keysym.sym;
- return 1;
- }
- }
- }
- return 0;
- }
- // SDL_COMMAND goes to global event unless modal window open
- else if ((handleEvents) && (eventCopy.type == SDL_COMMAND) && (!modalPos) && (this == desktop)) {
- return handleEvents(&eventCopy);
- }
- // (anything else is just plain done)
- else return 0;
- }
-
- if (broadcast) {
- int result = 0;
- list<Window*>::reverse_iterator pos;
- list<Window*>::reverse_iterator next;
- list<Window*>::reverse_iterator end = windowDataDisplay.rend();
-
- // Reverse order, because if a window moves, it should be towards the end
- for (pos = windowDataDisplay.rbegin(); pos != end; pos = next) {
- assert(*pos);
- if ((eventCopy.type == SDL_SPECIAL) && (eventCopy.user.code == SDL_PREQUIT) && (desktop->cancelQuitState())) break;
-
- // Note the next element in sequence now, before we run event
- next = pos;
- ++next;
-
- // Don't recurse
- if ((void*)(*pos) == (void*)this) return 0;
- // Refusing?
- if ((*pos)->refuseAll()) continue;
-
- // Exempt?
- if (*pos == exempt) continue;
- // Run event- if window closes or moves to top, we already have next item
- if (windowRunEvent(*pos, &eventCopy)) result = 1;
-
- // If a SDL_SYSKEY event that was used, we're done
- if ((eventCopy.type == SDL_SYSKEY) && (result)) break;
- }
-
- // Unused SDL_SYSKEY events attempts to run as shortcut now
- if ((eventCopy.type == SDL_SYSKEY) && (!result) && (this == desktop)) {
- int count = config->readShortcut(eventCopy.key.keysym.sym, eventCopy.key.keysym.mod, 0);
- if (count) {
- // Close all popup menus at any level
- PopupMenu* menu = dynamic_cast<PopupMenu*>(desktop->findWindow(Window::WINDOW_MENUBAR, 0));
- if (menu) menu->closeAllSubmenus(0);
- // Recurse through all potential shortcuts
- for (int pos = 1; pos <= count; ++pos) {
- int cmd = config->readShortcut(eventCopy.key.keysym.sym, eventCopy.key.keysym.mod, pos);
- // Stop when one works
- if (desktop->broadcastEvent(SDL_COMMAND, cmd, NULL, NULL, 1)) {
- desktop->lastShortcutKey = eventCopy.key.keysym.sym;
- result = 1;
- break;
- }
- }
- }
- }
-
- // Goes to event handler, unless-
- // SDL_COMMAND or SDL_SYSKEY that was used, or
- // SDL_CLOSE
- // (global SDL_CLOSE events not currently used, but can be supported)
- if ((handleEvents) &&
- // (eventCopy.type != SDL_CLOSE) &&
- (((eventCopy.type != SDL_COMMAND) && (eventCopy.type != SDL_SYSKEY)) || (!result))) {
-
- if (handleEvents(&eventCopy)) result = 1;
- }
-
- return result;
- }
- return 0;
- }
- void Desktop::setGameLoop(void (*gameLoop)(int)) { start_func
- gameLoopH = gameLoop;
- allowDesktopClick = gameLoop ? 1 : 0;
- }
- void Desktop::setSupportsHandler(Window::CommandSupport (*supportsHandler)(int code)) { start_func
- supportsCommandH = supportsHandler;
- }
- Window::CommandSupport Desktop::supportsCommand(int code, Window::CommandSupport prior) const { start_func
- if (supportsCommandH) {
- Window::CommandSupport sc = supportsCommandH(code);
- if ((prior == Window::COMMAND_HIDE) || (sc & Window::COMMAND_ENABLE)) return sc;
- }
- return prior;
- }
- void Desktop::preventDoubleClick() { start_func
- dclickTicks = 0;
- }
- void Desktop::updateScreen() { start_func
- // Restore mouse (screen should have NULL clip right now)
- unblitMouse();
-
- // Screen clip
- Rect screenClip = { 0, 0, overallWidth, overallHeight };
- // Start with updateRect at it's current status
- if (updateRect.w) {
- // Ensure clipped to screen size
- intersectRects(updateRect, screenClip);
- // Fill with background (screen should have NULL clip right now)
- SDL_FillRect(getScreen(), &updateRect, convertRGB(guiRGB[backgroundColorIndex], backgroundAlpha));
- if (backgroundImage) {
- Rect imageClip = { bkDestX, bkDestY, bkSrcW, bkSrcH };
- if (intersectRects(imageClip, updateRect)) {
- blit(bkSrcX + imageClip.x - bkDestX, bkSrcY + imageClip.y - bkDestY,
- backgroundImage, imageClip.x, imageClip.y, getScreen(), imageClip.w, imageClip.h);
- }
- }
- }
-
- SDL_Surface* screen = getScreen();
- if ((childDirty) || (updateRect.w)) {
- list<Window*>::iterator end = windowDataDisplay.end();
- for (list<Window*>::iterator pos = windowDataDisplay.begin(); pos != end; ++pos) {
- assert(*pos);
- // Start with clip area of entire window
- Rect clipDirty;
- (*pos)->getRect(clipDirty);
- // Actual clip to within screen size
- Rect clipTotal = clipDirty;
- // If this intersects with our current update area OR window is dirty
- if ((intersectRects(clipDirty, updateRect)) || ((*pos)->isDirty())) {
- // ...then display window (we only request area that matches our update)
- (*pos)->display(screen, clipDirty, clipTotal, 0, 0);
- // and add in anything it did update to our update area
- boundRects(updateRect, clipDirty);
- }
- }
- }
-
- childDirty = 0;
- SDL_SetClipRect(screen, (SDL_Rect*)NULL);
- blitMouse();
- intersectRects(updateRect, screenClip);
-
- // Call game loop, if any
- if (gameLoopH) {
- // If desktop can be clicked AND is active, pass keys to game
- gameLoopH((allowDesktopClick) && (currentFocus == NULL));
- }
- // Update our screen now
- screenFlip(&updateRect);
- postGLScreenFlip();
-
- // Clear updateRect for next time
- updateRect.w = 0;
- }
- int Desktop::eventLoop() { start_func
- Window* modalLoopPos = NULL;
- SDL_Event event;
- SDL_Event customEvent;
- customEvent.type = SDL_SPECIAL;
- customEvent.user.data1 = NULL;
- customEvent.user.data2 = NULL;
-
- // A modal loop? Remember what window is "ours"
- if (modalPos) modalLoopPos = modalPos;
- modalReturn = 0;
- ++eventLoopCount;
- while (!quit) {
- if (grabEvent(&event)) {
- int gameMode = (gameLoopH) && (allowDesktopClick) && (currentFocus == NULL);
- int storeToGame = 0;
- idleTimeout = 0;
- didShortTimeout = 0;
-
- // Tooltip? Remove
- if ((tooltip) && (event.type != SDL_MOUSEFOCUS)) {
- removeWindow(tooltip);
- delete tooltip;
- tooltip = NULL;
- tooltipMs = 0;
- }
-
- // Skip user-generated input events EXCEPT key ups/button ups
- // (to avoid stuck keys)
- // Mouse movement is OK too
- if (eventCleanup) {
- if ((event.type == SDL_KEYDOWN) ||
- (event.type == SDL_MOUSEBUTTONDOWN) ||
- (event.type == SDL_MOUSEBUTTONDBL))
- continue;
- }
- // Adjust key modifiers
- if ((event.type == SDL_KEYDOWN) || (event.type == SDL_KEYUP)) {
- if (gameMode)
- // All keys go to game
- storeToGame = 1;
- else {
- // Adjust numeric keypad
- if ((event.key.keysym.sym >= SDLK_KP0) && (event.key.keysym.sym <= SDLK_KP9)) {
- if (event.key.keysym.mod & KMOD_NUM) {
- event.key.keysym.sym = (SDLKey)(event.key.keysym.sym - SDLK_KP0 + SDLK_0);
- event.key.keysym.unicode = event.key.keysym.sym;
- }
- else {
- event.key.keysym.sym = keypadConvert[event.key.keysym.sym - SDLK_KP0];
- }
- }
- else if (event.key.keysym.sym == SDLK_KP_PERIOD) {
- if (event.key.keysym.mod & KMOD_NUM) {
- event.key.keysym.sym = SDLK_PERIOD;
- event.key.keysym.unicode = '.';
- }
- else {
- event.key.keysym.sym = SDLK_DELETE;
- }
- }
- SDLMod mod = KMOD_NONE;
- if (event.key.keysym.mod & KMOD_ALT) mod = (SDLMod)(mod | KMOD_ALT);
- if (event.key.keysym.mod & KMOD_CTRL) mod = (SDLMod)(mod | KMOD_CTRL);
- if (event.key.keysym.mod & KMOD_SHIFT) mod = (SDLMod)(mod | KMOD_SHIFT);
- event.key.keysym.mod = mod;
- // Do "command release"
- if ((event.type == SDL_KEYUP) && (event.key.keysym.sym == lastShortcutKey) && (lastShortcutKey)) {
- lastShortcutKey = 0;
- customEvent.type = SDL_COMMAND;
- customEvent.user.code = CMD_RELEASE;
- handleEvent(&customEvent);
- customEvent.type = SDL_SPECIAL;
- }
- }
- }
-
- // Adjust for double-click
- else if (event.type == SDL_MOUSEBUTTONDOWN) {
- if (event.button.button == SDL_BUTTON_LEFT) {
- if ((dclickTicks) &&
- ((SDL_GetTicks() - dclickTicks) < DOUBLECLICK_TIME) &&
- (abs(dclickX - event.button.x) <= DOUBLECLICK_DIST) &&
- (abs(dclickY - event.button.y) <= DOUBLECLICK_DIST)) {
- event.type = SDL_MOUSEBUTTONDBL;
- dclickTicks = 0;
- }
- else {
- dclickX = event.button.x;
- dclickY = event.button.y;
- dclickTicks = SDL_GetTicks();
- }
- }
- else {
- // (cancel upon any non-left click)
- dclickTicks = 0;
- }
- }
- // Special handling for QUIT
- else if ((event.type == SDL_QUIT) || ((event.type == SDL_SPECIAL) && (event.user.code & SDL_SPECIALQUIT))) {
- // Can't quit with modal dialogs open
- if (modalPos) continue;
-
- // Skip if we're already doing a prequit- that means we have
- // a modal "save" dialog or something open already; this should be
- // covered by the above condition, but "just in case"
- if (preQuit) continue;
-
- // First, run a pre-quit event
- customEvent.user.code = SDL_PREQUIT;
-
- preQuit = 1;
- handleEvent(&customEvent);
- preQuit = 0;
-
- // Cancel the quit?
- if (cancelPreQuit) {
- cancelPreQuit = 0;
- continue;
- }
-
- if (event.type == SDL_QUIT) quit = 1;
- else quit = event.user.code;
- }
-
- // Turn resize events into a resolution change
- else if (event.type == SDL_VIDEORESIZE) {
- // Catch non-fatal video errors
- try {
- selectVideoMode(event.resize.w, event.resize.h, -1, 0, 1);
- }
- catch (const VideoException& e) {
- guiErrorBox(string(e.details), errorTitleVideo);
- }
- continue;
- }
- // Turn active events into gain/lose mouse/input focus
- else if (event.type == SDL_ACTIVEEVENT) {
- if ((event.active.state & SDL_APPMOUSEFOCUS) && (event.active.gain == 0) && (currentMouseFocus)) {
- focusEvent(SDL_MOUSEFOCUS, 0, currentMouseFocus);
- currentMouseFocus = NULL;
- selectMouse(MOUSE_NORMAL);
- }
- if ((event.active.state & SDL_APPINPUTFOCUS) && (event.active.gain == 0)) {
- if (!lastFocus) {
- if (previousFocus) lastFocus = previousFocus;
- else lastFocus = currentFocus;
- changeInputFocus(NULL);
- }
- }
- if ((event.active.state & SDL_APPINPUTFOCUS) && (event.active.gain == 1)) {
- // Fixes "stuck ALT" etc
- // @TODO: SDL_ResetKeyboard();
- changeInputFocus(lastFocus);
- lastFocus = NULL;
- // Ignore the mouse click that generated this (hopefully)
- initEventCleanup();
- }
- }
-
- if (!storeToGame) handleEvent(&event);
-
- // Tooltips- record time so idle can make them appear
- // Also, COPY all mouse events to game
- if ((event.type == SDL_MOUSEBUTTONDOWN) ||
- (event.type == SDL_MOUSEBUTTONDBL) ||
- (event.type == SDL_MOUSEBUTTONUP) ||
- (event.type == SDL_MOUSEMOTION)) {
- tooltipMs = SDL_GetTicks();
- storeToGame = 1;
- }
- else if ((event.type == SDL_KEYDOWN) ||
- (event.type == SDL_KEYUP) ||
- (event.type == SDL_ACTIVEEVENT)) {
- tooltipMs = 0;
- }
-
- // Also copy all ACTIVE and QUIT events to game
- if ((event.type == SDL_ACTIVEEVENT) ||
- (event.type == SDL_QUIT)) {
- storeToGame = 1;
- }
-
- /* SDL_OBJECTCHANGE events no longer use the queue
- **
- // Object change events- delete structure
- else if (event.type == SDL_OBJECTCHANGE) {
- delete (ObjChange*)event.user.data1;
- }
- **
- */
- if ((storeToGame) && (gameMode)) storeEventGame(&event);
- }
- else {
- int phaseChange = 0;
- eventCleanup = 0;
- // Update selection rectangle phase
- Uint32 ticks = SDL_GetTicks();
- // (catch wraparound)
- if (ticks < selectionPhaseMs) selectionPhaseMs = SDL_GetTicks();
- else if (ticks - selectionPhaseMs > DELAY_PHASE_ROTATE) {
- cursorPhase = (cursorPhase + 1) % 64;
- int grey = abs(32 - cursorPhase) << 3;
- if (grey > 255) grey = 255;
- guiRGB[COLOR_TILECURSOR].r = grey;
- guiRGB[COLOR_TILECURSOR].g = grey;
- guiRGB[COLOR_TILECURSOR].b = grey;
- cursorAlpha = abs(16 - cursorPhase % 32) << 4;
- if (cursorAlpha < 64) cursorAlpha = 64;
- if (cursorAlpha > 255) cursorAlpha = 255;
- guiPacked[COLOR_TILECURSOR] = convertRGB(guiRGB[COLOR_TILECURSOR]);
- phaseChange = 1;
-
- if (cursorPhase % 4 == 0) {
- selectionPhase = (selectionPhase + 1) % NUM_PHASES;
- phaseChange = 2;
- }
- selectionPhaseMs = SDL_GetTicks();
- }
- // Display tooltip?
- if ((tooltipMs) && (!tooltip) && (currentMouseFocus) &&
- ((SDL_GetMouseState(NULL, NULL) & (SDL_BUTTON_LMASK | SDL_BUTTON_RMASK)) == 0)) {
- // (catch wraparound)
- if (ticks < tooltipMs) tooltipMs = SDL_GetTicks();
- else if (ticks - tooltipMs > DELAY_TOOLTIP_SHOW) {
- tooltipMs = 0;
- const char* tiptext = currentMouseFocus->tooltip(lastMouseX - currentMouseFocus->getX(), lastMouseY - currentMouseFocus->getY());
- if (tiptext) {
- tooltip = new ToolTip(tiptext);
- tooltip->popup(lastMouseX, lastMouseY + mouseTooltipYOffset());
- }
- }
- }
- // Idle event
- customEvent.user.code = phaseChange == 2 ? SDL_IDLEPHASE : phaseChange ? SDL_IDLECURSOR : SDL_IDLE;
- // Longer idle timeouts
- ++idleTimeout;
- if (idleTimeout > DELAY_IDLE_LONG) {
- customEvent.user.code = SDL_IDLETIMEOUTLONG;
- idleTimeout = 0;
- }
- else if ((!didShortTimeout) && (idleTimeout > DELAY_IDLE_SHORT)) {
- customEvent.user.code = SDL_IDLETIMEOUTSHORT;
- didShortTimeout = 1;
- }
- handleEvent(&customEvent);
- // @TODO: skip if calling game loop, have game loop delay as usual?
- SDL_Delay(1);
- }
- // Skip screen update if focus/close events waiting
- if (eventsWaiting()) continue;
-
- updateScreen();
-
- // If a modal loop, check if our modal dialog has closed- that means we're done
- if (modalLoopPos) {
- if (!verifyWindow(modalLoopPos)) break;
- // Check that our modal window is on top, or a window allowed to sort above it
- // ("no window" is also allowed, because that occurs when you switch to another app)
- if ((modalLoopPos != currentFocus) && (currentFocus) && (currentFocus->windowSort() <= Window::WINDOWSORT_MODAL)) {
- changeInputFocus(modalLoopPos);
- }
- }
- }
-
- --eventLoopCount;
-
- // Return value
- int returnValue = 0;
- // End quit state if all loops have ended
- if (eventLoopCount == 0) {
- returnValue = quit;
- quit = 0;
- }
-
- // Return modal value?
- if (modalReturn) {
- // (We do have to reset it to zero again)
- returnValue = modalReturn;
- modalReturn = 0;
- }
-
- return returnValue;
- }
- void Desktop::closeAllWindows() { start_func
- SDL_Event customEvent;
- customEvent.type = SDL_CLOSE;
- customEvent.user.code = 0;
- customEvent.user.data1 = NULL;
- customEvent.user.data2 = NULL;
- list<Window*>::iterator pos;
- // Reverse order
- for (pos = windowDataFocus.begin(); pos != windowDataFocus.end(); pos = windowDataFocus.begin()) {
- assert(*pos);
- Window* ptr = *pos;
- windowRunEvent(ptr, &customEvent);
- // In case it hasn't removed itself
- removeWindow(ptr);
- if (ptr->wantsToBeDeleted()) {
- ptr->setParent(NULL);
- delete ptr;
- }
- }
- }
- void Desktop::deleteAllWindows() { start_func
- currentFocus = NULL;
- previousFocus = NULL;
- lastFocus = NULL;
- currentMouseFocus = NULL;
- modalPos = NULL;
- // Note that we purposely use windowDataFocus here
- // and windowDataDisplay in removeWindow
- windowDataDisplay.clear();
- list<Window*>::reverse_iterator pos;
- list<Window*>::reverse_iterator next;
- list<Window*>::reverse_iterator end = windowDataFocus.rend();
- // Reverse order
- for (pos = windowDataFocus.rbegin(); pos != end; pos = next) {
- assert(*pos);
- // Note the next element in sequence now, before we delete
- next = pos;
- ++next;
- // Delete- removeWindow, if called, shouldn't do anything
- (*pos)->setParent(NULL);
- if ((*pos)->wantsToBeDeleted()) delete *pos;
- }
-
- windowDataFocus.clear();
- }
- void Desktop::broadcastObjChange(int code, void* object, int data1, int data2, Window* exempt) { start_func
- ObjChange obj;
- obj.obj = object;
- obj.info1 = data1;
- obj.info2 = data2;
- SDL_Event customEvent;
- customEvent.type = SDL_OBJECTCHANGE;
- customEvent.user.code = code;
- customEvent.user.data1 = &obj;
- customEvent.user.data2 = exempt;
- /* SDL_OBJECTCHANGE events no longer use the queue
- **
- // In order to use this, obj (above) needs to be dynamically allocated again
- // combinatoryEvent(&customEvent);
- **
- */
- handleEvent(&customEvent);
- }
- int Desktop::broadcastEvent(int type, int code, void* data, Window* exempt, int runImmediate) { start_func
- assert((type == SDL_COMMAND) || (type == SDL_SPECIAL) || (type == SDL_SYSKEY) ||
- (type == SDL_QUIT));
- assert(type < SDL_NUMEVENTS);
- SDL_Event customEvent;
- customEvent.type = type;
- customEvent.user.code = code;
- customEvent.user.data1 = data;
- customEvent.user.data2 = exempt;
- if (runImmediate) {
- return handleEvent(&customEvent);
- }
- else if (SDL_PushEvent(&customEvent)) {
- fatalCrash(0, "SDL_PushEvent failure");
- }
- return 0;
- }
- void Desktop::focusEvent(int type, int code, Window* window) { start_func
- if (!window) return;
-
- assert((type == SDL_MOUSEFOCUS) || (type == SDL_CLOSE) || (type == SDL_INPUTFOCUS));
- assert((code == 0) || (code == 1));
- SDL_Event customEvent;
- customEvent.type = type;
- customEvent.user.code = code;
- customEvent.user.data1 = window;
- customEvent.user.data2 = NULL;
- if (type == SDL_CLOSE) preemptEvent(&customEvent);
- else insertEvent(&customEvent);
- }
- void Desktop::setModalReturn(int returnValue) { start_func
- if (modalPos) modalReturn = returnValue;
- }
- void Desktop::cancelQuit() { start_func
- if (preQuit) cancelPreQuit = 1;
- }
- int Desktop::cancelQuitState() { start_func
- return cancelPreQuit;
- }
- void Desktop::resolutionChange(int fromW, int fromH, int fromBpp, int toW, int toH, int toBpp) { start_func
- overallWidth = screenWidth;
- overallHeight = screenHeight;
- setBackground(backgroundImage, backgroundColorIndex);
- WindowCollection::resolutionChange(fromW, fromH, fromBpp, toW, toH, toBpp);
- }
- void Desktop::setChildDirty() { start_func
- childDirty = 1;
- }
- void Desktop::setBackgroundAlpha(int alpha) { start_func
- if (alpha > 255) alpha = 255;
- if (alpha < 0) alpha = 0;
- backgroundAlpha = alpha;
- updateRect.x = 0;
- updateRect.y = 0;
- updateRect.w = overallWidth;
- updateRect.h = overallHeight;
- }
- void Desktop::setBackground(SDL_Surface* image, int colorIndex) { start_func
- assert(colorIndex >= 0);
- assert(colorIndex < COLOR_COUNT);
- backgroundColorIndex = colorIndex;
-
- if (image) {
- // Calculate position (centered)
- bkSrcW = image->w;
- bkSrcH = image->h;
- bkSrcX = 0;
- bkSrcY = 0;
- bkDestX = (overallWidth - bkSrcW) / 2;
- bkDestY = (overallHeight - bkSrcH) / 2;
- if (bkDestX < 0) {
- bkSrcW = overallWidth;
- bkSrcX = -bkDestX;
- bkDestX = 0;
- }
- if (bkDestY < 0) {
- bkSrcH = overallHeight;
- bkSrcY = -bkDestY;
- bkDestY = 0;
- }
- SDL_Surface* convertedBk = SDL_ConvertSurface(image, getScreen()->format, getScreen()->flags);
- if (backgroundImage) SDL_FreeSurface(backgroundImage);
- backgroundImage = convertedBk;
- }
- else {
- if (backgroundImage) SDL_FreeSurface(backgroundImage);
- backgroundImage = NULL;
- }
- updateRect.x = 0;
- updateRect.y = 0;
- updateRect.w = overallWidth;
- updateRect.h = overallHeight;
- }
- void Desktop::initEventCleanup() { start_func
- eventCleanup = 1;
- }
- Desktop::Desktop() : WindowCollection() { start_func
- gameLoopH = NULL;
- supportsCommandH = NULL;
- backgroundImage = NULL;
- backgroundColorIndex = COLOR_FRONTDESKTOP;
- backgroundAlpha = 255;
- quit = 0;
- preQuit = 0;
- cancelPreQuit = 0;
- eventLoopCount = 0;
- modalReturn = 0;
- eventCleanup = 0;
- overallWidth = screenWidth;
- overallHeight = screenHeight;
- canvasWidth = screenWidth;
- canvasHeight = screenHeight;
-
- updateRect.x = 0;
- updateRect.y = 0;
- updateRect.w = overallWidth;
- updateRect.h = overallHeight;
- childDirty = 0;
- dclickTicks = 0;
- selectionPhase = 0;
- selectionPhaseMs = SDL_GetTicks();
- cursorPhase = 0;
- cursorAlpha = 128;
- tooltip = NULL;
- tooltipMs = 0;
- lastShortcutKey = 0;
- }
- Desktop::~Desktop() { start_func
- if (backgroundImage) SDL_FreeSurface(backgroundImage);
- }
- int Desktop::getScreenX() const { start_func
- return 0;
- }
- int Desktop::getScreenY() const { start_func
- return 0;
- }
- int Desktop::desktopX() const { start_func
- return canvasX;
- }
- int Desktop::desktopY() const { start_func
- return canvasY;
- }
- int Desktop::desktopWidth() const { start_func
- return canvasWidth;
- }
- int Desktop::desktopHeight() const { start_func
- return canvasHeight;
- }
- void Desktop::childMoved(int fromX, int fromY, int toX, int toY, Window* child) { start_func
- assert(child);
-
- Rect moved;
- child->getRect(moved);
- addToUpdateRect(moved);
- moved.x = fromX;
- moved.y = fromY;
- addToUpdateRect(moved);
- }
- void Desktop::childResized(int fromW, int fromH, int toW, int toH, Window* child) { start_func
- assert(child);
-
- Rect moved;
- child->getRect(moved);
- if (fromW > toW) moved.w = fromW;
- if (fromH > toH) moved.h = fromH;
- addToUpdateRect(moved);
- }
- void Desktop::childDeleted(Window* child) { start_func
- assert(child);
- // (just in case the window forgot to remove itself from the desktop)
- removeWindow(child);
- }
- void Desktop::childModified(Window* child) { start_func
- assert(child);
- }
- void Desktop::siblingModified(Window* sibling) { start_func
- assert(sibling);
- }
|