void CGUI::TickObjects() { CStr action = "tick"; GUI<CStr>::RecurseObject(0, m_BaseObject, &IGUIObject::ScriptEvent, action); m_Tooltip.Update(FindObjectUnderMouse(), m_MousePos, this); }
InReaction CGUI::HandleEvent(const SDL_Event_* ev) { InReaction ret = IN_PASS; if (ev->ev.type == SDL_HOTKEYDOWN) { const char* hotkey = static_cast<const char*>(ev->ev.user.data1); std::map<CStr, std::vector<IGUIObject*> >::iterator it = m_HotkeyObjects.find(hotkey); if (it != m_HotkeyObjects.end()) { for (size_t i = 0; i < it->second.size(); ++i) { it->second[i]->SendEvent(GUIM_PRESSED, "press"); } } } else if (ev->ev.type == SDL_MOUSEMOTION) { // Yes the mouse position is stored as float to avoid // constant conversions when operating in a // float-based environment. m_MousePos = CPos((float)ev->ev.motion.x, (float)ev->ev.motion.y); SGUIMessage msg(GUIM_MOUSE_MOTION); GUI<SGUIMessage>::RecurseObject(GUIRR_HIDDEN | GUIRR_GHOST, m_BaseObject, &IGUIObject::HandleMessage, msg); } // Update m_MouseButtons. (BUTTONUP is handled later.) else if (ev->ev.type == SDL_MOUSEBUTTONDOWN) { switch (ev->ev.button.button) { case SDL_BUTTON_LEFT: case SDL_BUTTON_RIGHT: case SDL_BUTTON_MIDDLE: m_MouseButtons |= Bit<unsigned int>(ev->ev.button.button); break; default: break; } } // Update m_MousePos (for delayed mouse button events) CPos oldMousePos = m_MousePos; if (ev->ev.type == SDL_MOUSEBUTTONDOWN || ev->ev.type == SDL_MOUSEBUTTONUP) { m_MousePos = CPos((float)ev->ev.button.x, (float)ev->ev.button.y); } // Only one object can be hovered IGUIObject *pNearest = NULL; // TODO Gee: (2004-09-08) Big TODO, don't do the below if the SDL_Event is something like a keypress! try { PROFILE( "mouse events" ); // TODO Gee: Optimizations needed! // these two recursive function are quite overhead heavy. // pNearest will after this point at the hovered object, possibly NULL pNearest = FindObjectUnderMouse(); // Is placed in the UpdateMouseOver function //if (ev->ev.type == SDL_MOUSEMOTION && pNearest) // pNearest->ScriptEvent("mousemove"); // Now we'll call UpdateMouseOver on *all* objects, // we'll input the one hovered, and they will each // update their own data and send messages accordingly GUI<IGUIObject*>::RecurseObject(GUIRR_HIDDEN | GUIRR_GHOST, m_BaseObject, &IGUIObject::UpdateMouseOver, pNearest); if (ev->ev.type == SDL_MOUSEBUTTONDOWN) { switch (ev->ev.button.button) { case SDL_BUTTON_LEFT: // Focus the clicked object (or focus none if nothing clicked on) SetFocusedObject(pNearest); if (pNearest) ret = pNearest->SendEvent(GUIM_MOUSE_PRESS_LEFT, "mouseleftpress"); break; case SDL_BUTTON_RIGHT: if (pNearest) ret = pNearest->SendEvent(GUIM_MOUSE_PRESS_RIGHT, "mouserightpress"); break; #if !SDL_VERSION_ATLEAST(2, 0, 0) case SDL_BUTTON_WHEELDOWN: // wheel down if (pNearest) ret = pNearest->SendEvent(GUIM_MOUSE_WHEEL_DOWN, "mousewheeldown"); break; case SDL_BUTTON_WHEELUP: // wheel up if (pNearest) ret = pNearest->SendEvent(GUIM_MOUSE_WHEEL_UP, "mousewheelup"); break; #endif default: break; } } #if SDL_VERSION_ATLEAST(2, 0, 0) else if (ev->ev.type == SDL_MOUSEWHEEL) { if (ev->ev.wheel.y < 0) { if (pNearest) ret = pNearest->SendEvent(GUIM_MOUSE_WHEEL_DOWN, "mousewheeldown"); } else if (ev->ev.wheel.y > 0) { if (pNearest) ret = pNearest->SendEvent(GUIM_MOUSE_WHEEL_UP, "mousewheelup"); } } #endif else if (ev->ev.type == SDL_MOUSEBUTTONUP) { switch (ev->ev.button.button) { case SDL_BUTTON_LEFT: if (pNearest) { double timeElapsed = timer_Time() - pNearest->m_LastClickTime[SDL_BUTTON_LEFT]; pNearest->m_LastClickTime[SDL_BUTTON_LEFT] = timer_Time(); //Double click? if (timeElapsed < SELECT_DBLCLICK_RATE) { ret = pNearest->SendEvent(GUIM_MOUSE_DBLCLICK_LEFT, "mouseleftdoubleclick"); } else { ret = pNearest->SendEvent(GUIM_MOUSE_RELEASE_LEFT, "mouseleftrelease"); } } break; case SDL_BUTTON_RIGHT: if (pNearest) { double timeElapsed = timer_Time() - pNearest->m_LastClickTime[SDL_BUTTON_RIGHT]; pNearest->m_LastClickTime[SDL_BUTTON_RIGHT] = timer_Time(); //Double click? if (timeElapsed < SELECT_DBLCLICK_RATE) { ret = pNearest->SendEvent(GUIM_MOUSE_DBLCLICK_RIGHT, "mouserightdoubleclick"); } else { ret = pNearest->SendEvent(GUIM_MOUSE_RELEASE_RIGHT, "mouserightrelease"); } } break; } // Reset all states on all visible objects GUI<>::RecurseObject(GUIRR_HIDDEN, m_BaseObject, &IGUIObject::ResetStates); // It will have reset the mouse over of the current hovered, so we'll // have to restore that if (pNearest) pNearest->m_MouseHovering = true; } } catch (PSERROR_GUI& e) { UNUSED2(e); debug_warn(L"CGUI::HandleEvent error"); // TODO Gee: Handle } // BUTTONUP's effect on m_MouseButtons is handled after // everything else, so that e.g. 'press' handlers (activated // on button up) see which mouse button had been pressed. if (ev->ev.type == SDL_MOUSEBUTTONUP) { switch (ev->ev.button.button) { case SDL_BUTTON_LEFT: case SDL_BUTTON_RIGHT: case SDL_BUTTON_MIDDLE: m_MouseButtons &= ~Bit<unsigned int>(ev->ev.button.button); break; default: break; } } // Restore m_MousePos (for delayed mouse button events) if (ev->ev.type == SDL_MOUSEBUTTONDOWN || ev->ev.type == SDL_MOUSEBUTTONUP) { m_MousePos = oldMousePos; } // Handle keys for input boxes if (GetFocusedObject()) { if ( (ev->ev.type == SDL_KEYDOWN && ev->ev.key.keysym.sym != SDLK_ESCAPE && !g_keys[SDLK_LCTRL] && !g_keys[SDLK_RCTRL] && !g_keys[SDLK_LALT] && !g_keys[SDLK_RALT]) || ev->ev.type == SDL_HOTKEYDOWN ) { ret = GetFocusedObject()->ManuallyHandleEvent(ev); } // else will return IN_PASS because we never used the button. } return ret; }