/* CDropDown by Gustav Larsson gee@pyro.nu */ #include "precompiled.h" #include "GUI.h" #include "CDropDown.h" #include "ogl.h" using namespace std; //------------------------------------------------------------------- // Constructor / Destructor //------------------------------------------------------------------- CDropDown::CDropDown() : m_Open(false), m_HideScrollBar(false), m_ElementHighlight(-1) { AddSetting(GUIST_float, "button_width"); AddSetting(GUIST_float, "dropdown_size"); AddSetting(GUIST_float, "dropdown_buffer"); // AddSetting(GUIST_CStr, "font"); // AddSetting(GUIST_CGUISpriteInstance, "sprite"); // Background that sits around the size AddSetting(GUIST_CGUISpriteInstance, "sprite_list"); // Background of the drop down list AddSetting(GUIST_CGUISpriteInstance, "sprite2"); // Button that sits to the right AddSetting(GUIST_CGUISpriteInstance, "sprite2_over"); AddSetting(GUIST_CGUISpriteInstance, "sprite2_pressed"); AddSetting(GUIST_CGUISpriteInstance, "sprite2_disabled"); AddSetting(GUIST_EVAlign, "text_valign"); // Add these in CList! And implement TODO //AddSetting(GUIST_CColor, "textcolor_over"); //AddSetting(GUIST_CColor, "textcolor_pressed"); //AddSetting(GUIST_CColor, "textcolor_disabled"); // Scrollbar is forced to be true. GUI::SetSetting(this, "scrollbar", true); } CDropDown::~CDropDown() { } void CDropDown::SetupText() { CList::SetupText(); SetupListRect(); } void CDropDown::HandleMessage(const SGUIMessage &Message) { // Important switch (Message.type) { case GUIM_SETTINGS_UPDATED: bool scrollbar; GUI::GetSetting(this, "scrollbar", scrollbar); // Update scroll-bar // TODO Gee: (2004-09-01) Is this really updated each time it should? if (scrollbar && (Message.value == CStr("dropdown_size")/* || Message.value == CStr("")*/)) { CRect rect = GetListRect(); GetScrollBar(0).SetX( rect.right ); GetScrollBar(0).SetY( rect.top ); GetScrollBar(0).SetZ( GetBufferedZ() ); GetScrollBar(0).SetLength( rect.bottom - rect.top ); } // Update cached list rect if (Message.value == CStr("size") || Message.value == CStr("absolute") || Message.value == CStr("dropdown_size") || Message.value == CStr("dropdown_buffer") || Message.value == CStr("scrollbar_style") || Message.value == CStr("button_width")) { SetupListRect(); } break; case GUIM_MOUSE_MOTION:{ if (m_Open) { CPos mouse = GetMousePos(); if (GetListRect().PointInside(mouse)) { bool scrollbar; CGUIList *pList; GUI::GetSetting(this, "scrollbar", scrollbar); GUI::GetSettingPointer(this, "list", pList); float scroll=0.f; if (scrollbar) { scroll = GetScrollBar(0).GetPos(); } CRect rect = GetListRect(); mouse.y += scroll; int set=-1; for (int i=0; i<(int)pList->m_Items.size(); ++i) { if (mouse.y >= rect.top + m_ItemsYPositions[i] && mouse.y < rect.top + m_ItemsYPositions[i+1] && // mouse is not over scroll-bar !(mouse.x >= GetScrollBar(0).GetOuterRect().left && mouse.x <= GetScrollBar(0).GetOuterRect().right)) { set = i; } } if (set != -1) { //GUI::SetSetting(this, "selected", set); m_ElementHighlight = set; //UpdateAutoScroll(); } } } }break; case GUIM_MOUSE_LEAVE:{ GUI::GetSetting(this, "selected", m_ElementHighlight); }break; // We can't inherent this routine from CList, because we need to include // a mouse click to open the dropdown, also the coordinates are changed. case GUIM_MOUSE_PRESS_LEFT: { if (!m_Open) { m_Open = true; GetScrollBar(0).SetPos(0.f); UpdateAutoScroll(); GUI::GetSetting(this, "selected", m_ElementHighlight); return; // overshadow } else { CPos mouse = GetMousePos(); // If the regular area is pressed, then abort, and close. if (m_CachedActualSize.PointInside(mouse)) { m_Open = false; return; // overshadow } if (!(mouse.x >= GetScrollBar(0).GetOuterRect().left && mouse.x <= GetScrollBar(0).GetOuterRect().right) && mouse.y >= GetListRect().top) { m_Open = false; } } } break; case GUIM_LOST_FOCUS: m_Open=false; break; case GUIM_LOAD: SetupListRect(); break; default: break; } // Important that this is after, so that overshadowed implementations aren't processed CList::HandleMessage(Message); } int CDropDown::ManuallyHandleEvent(const SDL_Event* ev) { int szChar = ev->key.keysym.sym; bool update_highlight = false; switch (szChar) { case '\r': m_Open=false; break; case SDLK_HOME: case SDLK_END: case SDLK_UP: case SDLK_DOWN: case SDLK_PAGEUP: case SDLK_PAGEDOWN: if (!m_Open) return EV_PASS; // Set current selected item to highlighted, before // then really processing these in CList::ManuallyHandleEvent() GUI::SetSetting(this, "selected", m_ElementHighlight); update_highlight = true; break; default: break; } CList::ManuallyHandleEvent(ev); if (update_highlight) GUI::GetSetting(this, "selected", m_ElementHighlight); return EV_HANDLED; } void CDropDown::SetupListRect() { float size, buffer, button_width; GUI::GetSetting(this, "dropdown_size", size); GUI::GetSetting(this, "dropdown_buffer", buffer); GUI::GetSetting(this, "button_width", button_width); if (m_ItemsYPositions.empty() || m_ItemsYPositions.back() >= size) { m_CachedListRect = CRect(m_CachedActualSize.left, m_CachedActualSize.bottom+buffer, m_CachedActualSize.right, m_CachedActualSize.bottom+buffer + size); m_HideScrollBar = false; } else { m_CachedListRect = CRect(m_CachedActualSize.left, m_CachedActualSize.bottom+buffer, m_CachedActualSize.right - GetScrollBar(0).GetStyle()->m_Width, m_CachedActualSize.bottom+buffer + m_ItemsYPositions.back()); // We also need to hide the scrollbar m_HideScrollBar = true; } } CRect CDropDown::GetListRect() const { return m_CachedListRect; } bool CDropDown::MouseOver() { if(!GetGUI()) throw PS_NEEDS_PGUI; if (m_Open) { CRect rect(m_CachedActualSize.left, m_CachedActualSize.top, m_CachedActualSize.right, GetListRect().bottom); return rect.PointInside(GetMousePos()); } else return m_CachedActualSize.PointInside(GetMousePos()); } void CDropDown::Draw() { if (!GetGUI()) return; float bz = GetBufferedZ(); float dropdown_size, button_width; GUI::GetSetting(this, "dropdown_size", dropdown_size); GUI::GetSetting(this, "button_width", button_width); CGUISpriteInstance *sprite, *sprite2, *sprite2_second; int cell_id, selected=0; CColor color; GUI::GetSettingPointer(this, "sprite", sprite); GUI::GetSettingPointer(this, "sprite2", sprite2); GUI::GetSetting(this, "cell_id", cell_id); GUI::GetSetting(this, "selected", selected); GUI::GetSetting(this, "textcolor", color); bool enabled; GUI::GetSetting(this, "enabled", enabled); GetGUI()->DrawSprite(*sprite, cell_id, bz, m_CachedActualSize); if (button_width > 0.f) { CRect rect(m_CachedActualSize.right-button_width, m_CachedActualSize.top, m_CachedActualSize.right, m_CachedActualSize.bottom); if (!enabled) { GUI::GetSettingPointer(this, "sprite2_disabled", sprite2_second); GetGUI()->DrawSprite(GUI<>::FallBackSprite(*sprite2_second, *sprite2), cell_id, bz+0.05f, rect); } else if (m_Open) { GUI::GetSettingPointer(this, "sprite2_pressed", sprite2_second); GetGUI()->DrawSprite(GUI<>::FallBackSprite(*sprite2_second, *sprite2), cell_id, bz+0.05f, rect); } else if (m_MouseHovering) { GUI::GetSettingPointer(this, "sprite2_over", sprite2_second); GetGUI()->DrawSprite(GUI<>::FallBackSprite(*sprite2_second, *sprite2), cell_id, bz+0.05f, rect); } else GetGUI()->DrawSprite(*sprite2, cell_id, bz+0.05f, rect); } if (selected != -1) // TODO: Maybe check validity completely? { // figure out clipping rectangle CRect cliparea(m_CachedActualSize.left, m_CachedActualSize.top, m_CachedActualSize.right-button_width, m_CachedActualSize.bottom); CPos pos(m_CachedActualSize.left, m_CachedActualSize.top); IGUITextOwner::Draw(selected, color, pos, bz+0.1f, cliparea); } bool *scrollbar=NULL, old; GUI::GetSettingPointer(this, "scrollbar", scrollbar); old = *scrollbar; if (m_Open) { if (m_HideScrollBar) *scrollbar = false; DrawList(m_ElementHighlight, "sprite_list", "sprite_selectarea", "textcolor"); if (m_HideScrollBar) *scrollbar = old; } }