2019-07-26 20:57:28 +02:00
|
|
|
/* Copyright (C) 2019 Wildfire Games.
|
2009-04-18 19:00:33 +02:00
|
|
|
* This file is part of 0 A.D.
|
|
|
|
*
|
|
|
|
* 0 A.D. 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.
|
|
|
|
*
|
|
|
|
* 0 A.D. 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 0 A.D. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
*/
|
|
|
|
|
2006-04-24 01:14:18 +02:00
|
|
|
#include "precompiled.h"
|
2013-07-01 06:15:09 +02:00
|
|
|
|
2006-04-24 01:14:18 +02:00
|
|
|
#include "CDropDown.h"
|
|
|
|
|
2019-07-26 20:57:28 +02:00
|
|
|
#include "gui/CGUIColor.h"
|
2012-01-13 00:32:27 +01:00
|
|
|
#include "lib/external_libraries/libsdl.h"
|
2013-07-01 06:15:09 +02:00
|
|
|
#include "lib/ogl.h"
|
2013-07-14 14:17:07 +02:00
|
|
|
#include "lib/timer.h"
|
2015-08-21 19:08:41 +02:00
|
|
|
#include "ps/CLogger.h"
|
2013-07-01 06:15:09 +02:00
|
|
|
#include "soundmanager/ISoundManager.h"
|
2006-04-24 01:14:18 +02:00
|
|
|
|
2019-08-01 22:20:24 +02:00
|
|
|
CDropDown::CDropDown(CGUI* pGUI)
|
|
|
|
: CList(pGUI), IGUIObject(pGUI),
|
|
|
|
m_Open(false), m_HideScrollBar(false), m_ElementHighlight(-1)
|
2006-04-24 01:14:18 +02:00
|
|
|
{
|
2019-08-04 04:20:08 +02:00
|
|
|
AddSetting<float>("button_width");
|
|
|
|
AddSetting<float>("dropdown_size");
|
|
|
|
AddSetting<float>("dropdown_buffer");
|
|
|
|
AddSetting<uint>("minimum_visible_items");
|
|
|
|
// AddSetting<CStrW, "font");
|
|
|
|
AddSetting<CStrW>("sound_closed");
|
|
|
|
AddSetting<CStrW>("sound_disabled");
|
|
|
|
AddSetting<CStrW>("sound_enter");
|
|
|
|
AddSetting<CStrW>("sound_leave");
|
|
|
|
AddSetting<CStrW>("sound_opened");
|
|
|
|
AddSetting<CGUISpriteInstance>("sprite"); // Background that sits around the size
|
|
|
|
AddSetting<CGUISpriteInstance>("sprite_disabled");
|
|
|
|
AddSetting<CGUISpriteInstance>("sprite_list"); // Background of the drop down list
|
|
|
|
AddSetting<CGUISpriteInstance>("sprite2"); // Button that sits to the right
|
|
|
|
AddSetting<CGUISpriteInstance>("sprite2_over");
|
|
|
|
AddSetting<CGUISpriteInstance>("sprite2_pressed");
|
|
|
|
AddSetting<CGUISpriteInstance>("sprite2_disabled");
|
|
|
|
AddSetting<EVAlign>("text_valign");
|
2015-08-21 19:08:41 +02:00
|
|
|
|
2006-04-24 01:14:18 +02:00
|
|
|
// Add these in CList! And implement TODO
|
2019-08-04 04:20:08 +02:00
|
|
|
//AddSetting<CGUIColor>("textcolor_over");
|
|
|
|
//AddSetting<CGUIColor>("textcolor_pressed");
|
|
|
|
AddSetting<CGUIColor>("textcolor_selected");
|
|
|
|
AddSetting<CGUIColor>("textcolor_disabled");
|
2006-04-24 01:14:18 +02:00
|
|
|
|
|
|
|
// Scrollbar is forced to be true.
|
|
|
|
GUI<bool>::SetSetting(this, "scrollbar", true);
|
|
|
|
}
|
|
|
|
|
|
|
|
CDropDown::~CDropDown()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
void CDropDown::SetupText()
|
|
|
|
{
|
|
|
|
SetupListRect();
|
2010-06-30 23:20:08 +02:00
|
|
|
CList::SetupText();
|
2006-04-24 01:14:18 +02:00
|
|
|
}
|
|
|
|
|
2017-06-30 01:39:12 +02:00
|
|
|
void CDropDown::UpdateCachedSize()
|
|
|
|
{
|
|
|
|
CList::UpdateCachedSize();
|
|
|
|
SetupText();
|
|
|
|
}
|
|
|
|
|
2015-08-21 19:08:41 +02:00
|
|
|
void CDropDown::HandleMessage(SGUIMessage& Message)
|
2006-04-24 01:14:18 +02:00
|
|
|
{
|
|
|
|
// Important
|
|
|
|
|
|
|
|
switch (Message.type)
|
|
|
|
{
|
|
|
|
case GUIM_SETTINGS_UPDATED:
|
2010-06-30 23:20:08 +02:00
|
|
|
{
|
2006-04-24 01:14:18 +02:00
|
|
|
// Update cached list rect
|
2010-06-30 23:20:08 +02:00
|
|
|
if (Message.value == "size" ||
|
|
|
|
Message.value == "absolute" ||
|
|
|
|
Message.value == "dropdown_size" ||
|
|
|
|
Message.value == "dropdown_buffer" ||
|
2018-02-25 23:26:31 +01:00
|
|
|
Message.value == "minimum_visible_items" ||
|
2010-06-30 23:20:08 +02:00
|
|
|
Message.value == "scrollbar_style" ||
|
|
|
|
Message.value == "button_width")
|
2006-04-24 01:14:18 +02:00
|
|
|
{
|
|
|
|
SetupListRect();
|
2015-08-21 19:08:41 +02:00
|
|
|
}
|
2006-04-24 01:14:18 +02:00
|
|
|
|
|
|
|
break;
|
2010-06-30 23:20:08 +02:00
|
|
|
}
|
2006-04-24 01:14:18 +02:00
|
|
|
|
2010-06-30 23:20:08 +02:00
|
|
|
case GUIM_MOUSE_MOTION:
|
|
|
|
{
|
2015-08-21 19:08:41 +02:00
|
|
|
if (!m_Open)
|
|
|
|
break;
|
2006-04-24 01:14:18 +02:00
|
|
|
|
2019-08-10 14:51:27 +02:00
|
|
|
CPos mouse = m_pGUI->GetMousePos();
|
2006-04-24 01:14:18 +02:00
|
|
|
|
2015-08-21 19:08:41 +02:00
|
|
|
if (!GetListRect().PointInside(mouse))
|
|
|
|
break;
|
|
|
|
|
|
|
|
bool scrollbar;
|
|
|
|
CGUIList* pList;
|
|
|
|
GUI<bool>::GetSetting(this, "scrollbar", scrollbar);
|
|
|
|
GUI<CGUIList>::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
|
2015-10-31 06:40:43 +01:00
|
|
|
(m_HideScrollBar ||
|
|
|
|
mouse.x < GetScrollBar(0).GetOuterRect().left ||
|
|
|
|
mouse.x > GetScrollBar(0).GetOuterRect().right))
|
2015-08-21 19:08:41 +02:00
|
|
|
{
|
|
|
|
set = i;
|
2006-04-24 01:14:18 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-08-21 19:08:41 +02:00
|
|
|
if (set != -1)
|
|
|
|
{
|
|
|
|
m_ElementHighlight = set;
|
|
|
|
//UpdateAutoScroll();
|
|
|
|
}
|
|
|
|
|
2010-06-30 23:20:08 +02:00
|
|
|
break;
|
|
|
|
}
|
2006-04-24 01:14:18 +02:00
|
|
|
|
2013-07-01 06:15:09 +02:00
|
|
|
case GUIM_MOUSE_ENTER:
|
|
|
|
{
|
|
|
|
bool enabled;
|
|
|
|
GUI<bool>::GetSetting(this, "enabled", enabled);
|
2015-08-21 19:08:41 +02:00
|
|
|
if (!enabled)
|
|
|
|
break;
|
|
|
|
|
|
|
|
CStrW soundPath;
|
|
|
|
if (g_SoundManager && GUI<CStrW>::GetSetting(this, "sound_enter", soundPath) == PSRETURN_OK && !soundPath.empty())
|
|
|
|
g_SoundManager->PlayAsUI(soundPath.c_str(), false);
|
2013-07-01 06:15:09 +02:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2010-06-30 23:20:08 +02:00
|
|
|
case GUIM_MOUSE_LEAVE:
|
|
|
|
{
|
2006-04-24 01:14:18 +02:00
|
|
|
GUI<int>::GetSetting(this, "selected", m_ElementHighlight);
|
|
|
|
|
2013-07-01 06:15:09 +02:00
|
|
|
bool enabled;
|
|
|
|
GUI<bool>::GetSetting(this, "enabled", enabled);
|
2015-08-21 19:08:41 +02:00
|
|
|
if (!enabled)
|
|
|
|
break;
|
|
|
|
|
|
|
|
CStrW soundPath;
|
|
|
|
if (g_SoundManager && GUI<CStrW>::GetSetting(this, "sound_leave", soundPath) == PSRETURN_OK && !soundPath.empty())
|
|
|
|
g_SoundManager->PlayAsUI(soundPath.c_str(), false);
|
2010-06-30 23:20:08 +02:00
|
|
|
break;
|
|
|
|
}
|
2006-04-24 01:14:18 +02:00
|
|
|
|
2010-06-30 23:20:08 +02:00
|
|
|
// 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.
|
2006-04-24 01:14:18 +02:00
|
|
|
case GUIM_MOUSE_PRESS_LEFT:
|
|
|
|
{
|
2010-06-30 23:20:08 +02:00
|
|
|
bool enabled;
|
|
|
|
GUI<bool>::GetSetting(this, "enabled", enabled);
|
|
|
|
if (!enabled)
|
2013-07-01 06:15:09 +02:00
|
|
|
{
|
|
|
|
CStrW soundPath;
|
|
|
|
if (g_SoundManager && GUI<CStrW>::GetSetting(this, "sound_disabled", soundPath) == PSRETURN_OK && !soundPath.empty())
|
|
|
|
g_SoundManager->PlayAsUI(soundPath.c_str(), false);
|
2010-06-30 23:20:08 +02:00
|
|
|
break;
|
2013-07-01 06:15:09 +02:00
|
|
|
}
|
2010-06-30 23:20:08 +02:00
|
|
|
|
2006-04-24 01:14:18 +02:00
|
|
|
if (!m_Open)
|
|
|
|
{
|
2015-08-21 19:08:41 +02:00
|
|
|
CGUIList* pList;
|
2013-10-04 02:31:36 +02:00
|
|
|
GUI<CGUIList>::GetSettingPointer(this, "list", pList);
|
|
|
|
if (pList->m_Items.empty())
|
|
|
|
return;
|
|
|
|
|
2006-04-24 01:14:18 +02:00
|
|
|
m_Open = true;
|
2010-06-30 23:20:08 +02:00
|
|
|
GetScrollBar(0).SetZ(GetBufferedZ());
|
2006-04-24 01:14:18 +02:00
|
|
|
GUI<int>::GetSetting(this, "selected", m_ElementHighlight);
|
2012-08-08 19:22:52 +02:00
|
|
|
|
|
|
|
// Start at the position of the selected item, if possible.
|
2015-08-21 19:08:41 +02:00
|
|
|
GetScrollBar(0).SetPos(m_ItemsYPositions.empty() ? 0 : m_ItemsYPositions[m_ElementHighlight] - 60);
|
2013-07-01 06:15:09 +02:00
|
|
|
|
|
|
|
CStrW soundPath;
|
|
|
|
if (g_SoundManager && GUI<CStrW>::GetSetting(this, "sound_opened", soundPath) == PSRETURN_OK && !soundPath.empty())
|
|
|
|
g_SoundManager->PlayAsUI(soundPath.c_str(), false);
|
|
|
|
|
2006-04-24 01:14:18 +02:00
|
|
|
return; // overshadow
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2019-08-10 14:51:27 +02:00
|
|
|
const CPos& mouse = m_pGUI->GetMousePos();
|
2006-04-24 01:14:18 +02:00
|
|
|
|
|
|
|
// If the regular area is pressed, then abort, and close.
|
|
|
|
if (m_CachedActualSize.PointInside(mouse))
|
|
|
|
{
|
|
|
|
m_Open = false;
|
2010-06-30 23:20:08 +02:00
|
|
|
GetScrollBar(0).SetZ(GetBufferedZ());
|
2013-07-01 06:15:09 +02:00
|
|
|
|
|
|
|
CStrW soundPath;
|
|
|
|
if (g_SoundManager && GUI<CStrW>::GetSetting(this, "sound_closed", soundPath) == PSRETURN_OK && !soundPath.empty())
|
|
|
|
g_SoundManager->PlayAsUI(soundPath.c_str(), false);
|
|
|
|
|
2006-04-24 01:14:18 +02:00
|
|
|
return; // overshadow
|
|
|
|
}
|
|
|
|
|
2015-10-31 06:40:43 +01:00
|
|
|
if (m_HideScrollBar ||
|
|
|
|
mouse.x < GetScrollBar(0).GetOuterRect().left ||
|
|
|
|
mouse.x > GetScrollBar(0).GetOuterRect().right ||
|
|
|
|
mouse.y < GetListRect().top)
|
2006-04-24 01:14:18 +02:00
|
|
|
{
|
|
|
|
m_Open = false;
|
2010-06-30 23:20:08 +02:00
|
|
|
GetScrollBar(0).SetZ(GetBufferedZ());
|
2006-04-24 01:14:18 +02:00
|
|
|
}
|
|
|
|
}
|
2010-06-30 23:20:08 +02:00
|
|
|
break;
|
|
|
|
}
|
2006-04-24 01:14:18 +02:00
|
|
|
|
2013-12-31 05:54:16 +01:00
|
|
|
case GUIM_MOUSE_WHEEL_DOWN:
|
|
|
|
{
|
2014-06-21 02:25:12 +02:00
|
|
|
bool enabled;
|
|
|
|
GUI<bool>::GetSetting(this, "enabled", enabled);
|
|
|
|
|
2013-12-31 12:06:00 +01:00
|
|
|
// Don't switch elements by scrolling when open, causes a confusing interaction between this and the scrollbar.
|
2014-06-21 02:25:12 +02:00
|
|
|
if (m_Open || !enabled)
|
2013-12-31 05:54:16 +01:00
|
|
|
break;
|
|
|
|
|
|
|
|
GUI<int>::GetSetting(this, "selected", m_ElementHighlight);
|
|
|
|
if (m_ElementHighlight + 1 >= (int)m_ItemsYPositions.size() - 1)
|
|
|
|
break;
|
|
|
|
|
2015-08-21 19:08:41 +02:00
|
|
|
++m_ElementHighlight;
|
2013-12-31 05:54:16 +01:00
|
|
|
GUI<int>::SetSetting(this, "selected", m_ElementHighlight);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case GUIM_MOUSE_WHEEL_UP:
|
|
|
|
{
|
2014-06-21 02:25:12 +02:00
|
|
|
bool enabled;
|
|
|
|
GUI<bool>::GetSetting(this, "enabled", enabled);
|
|
|
|
|
2013-12-31 05:54:16 +01:00
|
|
|
// Don't switch elements by scrolling when open, causes a confusing interaction between this and the scrollbar.
|
2014-06-21 02:25:12 +02:00
|
|
|
if (m_Open || !enabled)
|
2013-12-31 05:54:16 +01:00
|
|
|
break;
|
|
|
|
|
|
|
|
GUI<int>::GetSetting(this, "selected", m_ElementHighlight);
|
|
|
|
if (m_ElementHighlight - 1 < 0)
|
|
|
|
break;
|
|
|
|
|
|
|
|
m_ElementHighlight--;
|
|
|
|
GUI<int>::SetSetting(this, "selected", m_ElementHighlight);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2006-04-24 01:14:18 +02:00
|
|
|
case GUIM_LOST_FOCUS:
|
2013-07-01 06:15:09 +02:00
|
|
|
{
|
|
|
|
if (m_Open)
|
|
|
|
{
|
|
|
|
CStrW soundPath;
|
|
|
|
if (g_SoundManager && GUI<CStrW>::GetSetting(this, "sound_closed", soundPath) == PSRETURN_OK && !soundPath.empty())
|
|
|
|
g_SoundManager->PlayAsUI(soundPath.c_str(), false);
|
|
|
|
}
|
2010-06-30 23:20:08 +02:00
|
|
|
m_Open = false;
|
2006-04-24 01:14:18 +02:00
|
|
|
break;
|
2013-07-01 06:15:09 +02:00
|
|
|
}
|
2006-04-24 01:14:18 +02:00
|
|
|
|
|
|
|
case GUIM_LOAD:
|
|
|
|
SetupListRect();
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Important that this is after, so that overshadowed implementations aren't processed
|
|
|
|
CList::HandleMessage(Message);
|
2012-07-31 05:34:09 +02:00
|
|
|
|
|
|
|
// As HandleMessage functions return void, we need to manually verify
|
|
|
|
// whether the child list's items were modified.
|
|
|
|
if (CList::GetModified())
|
|
|
|
SetupText();
|
2006-04-24 01:14:18 +02:00
|
|
|
}
|
|
|
|
|
2006-08-26 23:52:18 +02:00
|
|
|
InReaction CDropDown::ManuallyHandleEvent(const SDL_Event_* ev)
|
2006-04-24 01:14:18 +02:00
|
|
|
{
|
2014-10-27 05:37:06 +01:00
|
|
|
InReaction result = IN_PASS;
|
2006-04-24 01:14:18 +02:00
|
|
|
bool update_highlight = false;
|
|
|
|
|
2014-10-27 05:37:06 +01:00
|
|
|
if (ev->ev.type == SDL_KEYDOWN)
|
2006-04-24 01:14:18 +02:00
|
|
|
{
|
2014-10-27 05:37:06 +01:00
|
|
|
int szChar = ev->ev.key.keysym.sym;
|
2015-08-21 19:08:41 +02:00
|
|
|
|
2014-10-27 05:37:06 +01:00
|
|
|
switch (szChar)
|
|
|
|
{
|
|
|
|
case '\r':
|
|
|
|
m_Open = false;
|
|
|
|
result = IN_HANDLED;
|
|
|
|
break;
|
2006-04-24 01:14:18 +02:00
|
|
|
|
2014-10-27 05:37:06 +01:00
|
|
|
case SDLK_HOME:
|
|
|
|
case SDLK_END:
|
|
|
|
case SDLK_UP:
|
|
|
|
case SDLK_DOWN:
|
|
|
|
case SDLK_PAGEUP:
|
|
|
|
case SDLK_PAGEDOWN:
|
|
|
|
if (!m_Open)
|
|
|
|
return IN_PASS;
|
|
|
|
// Set current selected item to highlighted, before
|
|
|
|
// then really processing these in CList::ManuallyHandleEvent()
|
|
|
|
GUI<int>::SetSetting(this, "selected", m_ElementHighlight);
|
|
|
|
update_highlight = true;
|
|
|
|
break;
|
2006-04-24 01:14:18 +02:00
|
|
|
|
2014-10-27 05:37:06 +01:00
|
|
|
default:
|
|
|
|
// If we have inputed a character try to get the closest element to it.
|
|
|
|
// TODO: not too nice and doesn't deal with dashes.
|
|
|
|
if (m_Open && ((szChar >= SDLK_a && szChar <= SDLK_z) || szChar == SDLK_SPACE
|
|
|
|
|| (szChar >= SDLK_0 && szChar <= SDLK_9)
|
|
|
|
|| (szChar >= SDLK_KP_0 && szChar <= SDLK_KP_9)))
|
|
|
|
{
|
|
|
|
// arbitrary 1 second limit to add to string or start fresh.
|
|
|
|
// maximal amount of characters is 100, which imo is far more than enough.
|
|
|
|
if (timer_Time() - m_TimeOfLastInput > 1.0 || m_InputBuffer.length() >= 100)
|
|
|
|
m_InputBuffer = szChar;
|
|
|
|
else
|
|
|
|
m_InputBuffer += szChar;
|
2015-08-21 19:08:41 +02:00
|
|
|
|
2014-10-27 05:37:06 +01:00
|
|
|
m_TimeOfLastInput = timer_Time();
|
2015-08-21 19:08:41 +02:00
|
|
|
|
|
|
|
CGUIList* pList;
|
2014-10-27 05:37:06 +01:00
|
|
|
GUI<CGUIList>::GetSettingPointer(this, "list", pList);
|
|
|
|
// let's look for the closest element
|
|
|
|
// basically it's alphabetic order and "as many letters as we can get".
|
|
|
|
int closest = -1;
|
|
|
|
int bestIndex = -1;
|
|
|
|
int difference = 1250;
|
2015-08-21 19:08:41 +02:00
|
|
|
for (int i = 0; i < (int)pList->m_Items.size(); ++i)
|
2013-07-14 14:17:07 +02:00
|
|
|
{
|
2014-10-27 05:37:06 +01:00
|
|
|
int indexOfDifference = 0;
|
|
|
|
int diff = 0;
|
2015-08-21 19:08:41 +02:00
|
|
|
for (size_t j = 0; j < m_InputBuffer.length(); ++j)
|
2014-10-27 05:37:06 +01:00
|
|
|
{
|
2018-01-14 22:18:37 +01:00
|
|
|
diff = std::abs((int)(pList->m_Items[i].GetRawString().LowerCase()[j]) - (int)m_InputBuffer[j]);
|
2014-10-27 05:37:06 +01:00
|
|
|
if (diff == 0)
|
|
|
|
indexOfDifference = j+1;
|
|
|
|
else
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (indexOfDifference > bestIndex || (indexOfDifference >= bestIndex && diff < difference))
|
|
|
|
{
|
|
|
|
bestIndex = indexOfDifference;
|
|
|
|
closest = i;
|
|
|
|
difference = diff;
|
|
|
|
}
|
2013-07-14 14:17:07 +02:00
|
|
|
}
|
2014-10-27 05:37:06 +01:00
|
|
|
// let's select the closest element. There should basically always be one.
|
|
|
|
if (closest != -1)
|
2013-07-14 14:17:07 +02:00
|
|
|
{
|
2014-10-27 05:37:06 +01:00
|
|
|
GUI<int>::SetSetting(this, "selected", closest);
|
|
|
|
update_highlight = true;
|
|
|
|
GetScrollBar(0).SetPos(m_ItemsYPositions[closest] - 60);
|
2013-07-14 14:17:07 +02:00
|
|
|
}
|
2014-10-27 05:37:06 +01:00
|
|
|
result = IN_HANDLED;
|
2013-07-14 14:17:07 +02:00
|
|
|
}
|
2014-10-27 05:37:06 +01:00
|
|
|
break;
|
2013-07-14 14:17:07 +02:00
|
|
|
}
|
2006-04-24 01:14:18 +02:00
|
|
|
}
|
|
|
|
|
2014-10-27 05:37:06 +01:00
|
|
|
if (CList::ManuallyHandleEvent(ev) == IN_HANDLED)
|
|
|
|
result = IN_HANDLED;
|
2006-04-24 01:14:18 +02:00
|
|
|
|
|
|
|
if (update_highlight)
|
|
|
|
GUI<int>::GetSetting(this, "selected", m_ElementHighlight);
|
|
|
|
|
2014-10-27 05:37:06 +01:00
|
|
|
return result;
|
2006-04-24 01:14:18 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void CDropDown::SetupListRect()
|
|
|
|
{
|
2018-02-25 23:26:31 +01:00
|
|
|
extern int g_yres;
|
|
|
|
extern float g_GuiScale;
|
|
|
|
float size, buffer, yres;
|
|
|
|
yres = g_yres / g_GuiScale;
|
|
|
|
u32 minimumVisibleItems;
|
2006-04-24 01:14:18 +02:00
|
|
|
GUI<float>::GetSetting(this, "dropdown_size", size);
|
|
|
|
GUI<float>::GetSetting(this, "dropdown_buffer", buffer);
|
2018-02-25 23:26:31 +01:00
|
|
|
GUI<u32>::GetSetting(this, "minimum_visible_items", minimumVisibleItems);
|
2006-04-24 01:14:18 +02:00
|
|
|
|
2018-02-25 23:26:31 +01:00
|
|
|
if (m_ItemsYPositions.empty())
|
2006-04-24 01:14:18 +02:00
|
|
|
{
|
2018-02-25 23:26:31 +01:00
|
|
|
m_CachedListRect = CRect(m_CachedActualSize.left, m_CachedActualSize.bottom + buffer,
|
|
|
|
m_CachedActualSize.right, m_CachedActualSize.bottom + buffer + size);
|
|
|
|
m_HideScrollBar = false;
|
|
|
|
}
|
|
|
|
// Too many items so use a scrollbar
|
|
|
|
else if (m_ItemsYPositions.back() > size)
|
|
|
|
{
|
|
|
|
// Place items below if at least some items can be placed below
|
|
|
|
if (m_CachedActualSize.bottom + buffer + size <= yres)
|
|
|
|
m_CachedListRect = CRect(m_CachedActualSize.left, m_CachedActualSize.bottom + buffer,
|
|
|
|
m_CachedActualSize.right, m_CachedActualSize.bottom + buffer + size);
|
|
|
|
else if ((m_ItemsYPositions.size() > minimumVisibleItems && yres - m_CachedActualSize.bottom - buffer >= m_ItemsYPositions[minimumVisibleItems]) ||
|
|
|
|
m_CachedActualSize.top < yres - m_CachedActualSize.bottom)
|
|
|
|
m_CachedListRect = CRect(m_CachedActualSize.left, m_CachedActualSize.bottom + buffer,
|
|
|
|
m_CachedActualSize.right, yres);
|
|
|
|
// Not enough space below, thus place items above
|
|
|
|
else
|
|
|
|
m_CachedListRect = CRect(m_CachedActualSize.left, std::max(0.f, m_CachedActualSize.top - buffer - size),
|
|
|
|
m_CachedActualSize.right, m_CachedActualSize.top - buffer);
|
2006-04-24 01:14:18 +02:00
|
|
|
|
|
|
|
m_HideScrollBar = false;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2018-02-25 23:26:31 +01:00
|
|
|
// Enough space below, no scrollbar needed
|
|
|
|
if (m_CachedActualSize.bottom + buffer + m_ItemsYPositions.back() <= yres)
|
|
|
|
{
|
|
|
|
m_CachedListRect = CRect(m_CachedActualSize.left, m_CachedActualSize.bottom + buffer,
|
|
|
|
m_CachedActualSize.right, m_CachedActualSize.bottom + buffer + m_ItemsYPositions.back());
|
|
|
|
m_HideScrollBar = true;
|
|
|
|
}
|
|
|
|
// Enough space below for some items, but not all, so place items below and use a scrollbar
|
|
|
|
else if ((m_ItemsYPositions.size() > minimumVisibleItems && yres - m_CachedActualSize.bottom - buffer >= m_ItemsYPositions[minimumVisibleItems]) ||
|
|
|
|
m_CachedActualSize.top < yres - m_CachedActualSize.bottom)
|
|
|
|
{
|
|
|
|
m_CachedListRect = CRect(m_CachedActualSize.left, m_CachedActualSize.bottom + buffer,
|
|
|
|
m_CachedActualSize.right, yres);
|
|
|
|
m_HideScrollBar = false;
|
|
|
|
}
|
|
|
|
// Not enough space below, thus place items above. Hide the scrollbar accordingly
|
|
|
|
else
|
|
|
|
{
|
|
|
|
m_CachedListRect = CRect(m_CachedActualSize.left, std::max(0.f, m_CachedActualSize.top - buffer - m_ItemsYPositions.back()),
|
|
|
|
m_CachedActualSize.right, m_CachedActualSize.top - buffer);
|
|
|
|
m_HideScrollBar = m_CachedActualSize.top > m_ItemsYPositions.back() + buffer;
|
|
|
|
}
|
2006-04-24 01:14:18 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
CRect CDropDown::GetListRect() const
|
|
|
|
{
|
|
|
|
return m_CachedListRect;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool CDropDown::MouseOver()
|
|
|
|
{
|
|
|
|
if (m_Open)
|
|
|
|
{
|
2018-02-25 23:26:31 +01:00
|
|
|
CRect rect(m_CachedActualSize.left, std::min(m_CachedActualSize.top, GetListRect().top),
|
|
|
|
m_CachedActualSize.right, std::max(m_CachedActualSize.bottom, GetListRect().bottom));
|
2019-08-10 14:51:27 +02:00
|
|
|
return rect.PointInside(m_pGUI->GetMousePos());
|
2006-04-24 01:14:18 +02:00
|
|
|
}
|
|
|
|
else
|
2019-08-10 14:51:27 +02:00
|
|
|
return m_CachedActualSize.PointInside(m_pGUI->GetMousePos());
|
2006-04-24 01:14:18 +02:00
|
|
|
}
|
|
|
|
|
2015-08-21 19:08:41 +02:00
|
|
|
void CDropDown::Draw()
|
2006-04-24 01:14:18 +02:00
|
|
|
{
|
|
|
|
float bz = GetBufferedZ();
|
|
|
|
|
|
|
|
float dropdown_size, button_width;
|
|
|
|
GUI<float>::GetSetting(this, "dropdown_size", dropdown_size);
|
|
|
|
GUI<float>::GetSetting(this, "button_width", button_width);
|
|
|
|
|
2015-08-21 19:08:41 +02:00
|
|
|
CGUISpriteInstance* sprite;
|
|
|
|
CGUISpriteInstance* sprite2;
|
|
|
|
CGUISpriteInstance* sprite2_second;
|
|
|
|
int cell_id, selected = 0;
|
2019-07-26 20:57:28 +02:00
|
|
|
CGUIColor color;
|
2006-04-24 01:14:18 +02:00
|
|
|
|
2016-12-05 18:21:51 +01:00
|
|
|
bool enabled;
|
|
|
|
GUI<bool>::GetSetting(this, "enabled", enabled);
|
|
|
|
|
2006-04-24 01:14:18 +02:00
|
|
|
GUI<CGUISpriteInstance>::GetSettingPointer(this, "sprite2", sprite2);
|
|
|
|
GUI<int>::GetSetting(this, "cell_id", cell_id);
|
|
|
|
GUI<int>::GetSetting(this, "selected", selected);
|
2019-07-26 20:57:28 +02:00
|
|
|
GUI<CGUIColor>::GetSetting(this, enabled ? "textcolor_selected" : "textcolor_disabled", color);
|
2006-04-24 01:14:18 +02:00
|
|
|
|
2016-12-05 18:21:51 +01:00
|
|
|
GUI<CGUISpriteInstance>::GetSettingPointer(this, enabled ? "sprite" : "sprite_disabled", sprite);
|
2006-04-24 01:14:18 +02:00
|
|
|
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<CGUISpriteInstance>::GetSettingPointer(this, "sprite2_disabled", sprite2_second);
|
|
|
|
GetGUI()->DrawSprite(GUI<>::FallBackSprite(*sprite2_second, *sprite2), cell_id, bz+0.05f, rect);
|
|
|
|
}
|
2015-08-21 19:08:41 +02:00
|
|
|
else if (m_Open)
|
2006-04-24 01:14:18 +02:00
|
|
|
{
|
|
|
|
GUI<CGUISpriteInstance>::GetSettingPointer(this, "sprite2_pressed", sprite2_second);
|
|
|
|
GetGUI()->DrawSprite(GUI<>::FallBackSprite(*sprite2_second, *sprite2), cell_id, bz+0.05f, rect);
|
|
|
|
}
|
2015-08-21 19:08:41 +02:00
|
|
|
else if (m_MouseHovering)
|
2006-04-24 01:14:18 +02:00
|
|
|
{
|
|
|
|
GUI<CGUISpriteInstance>::GetSettingPointer(this, "sprite2_over", sprite2_second);
|
|
|
|
GetGUI()->DrawSprite(GUI<>::FallBackSprite(*sprite2_second, *sprite2), cell_id, bz+0.05f, rect);
|
|
|
|
}
|
2015-08-21 19:08:41 +02:00
|
|
|
else
|
2006-04-24 01:14:18 +02:00
|
|
|
GetGUI()->DrawSprite(*sprite2, cell_id, bz+0.05f, rect);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (selected != -1) // TODO: Maybe check validity completely?
|
|
|
|
{
|
|
|
|
CRect cliparea(m_CachedActualSize.left, m_CachedActualSize.top,
|
|
|
|
m_CachedActualSize.right-button_width, m_CachedActualSize.bottom);
|
|
|
|
|
|
|
|
CPos pos(m_CachedActualSize.left, m_CachedActualSize.top);
|
2011-07-17 19:30:07 +02:00
|
|
|
DrawText(selected, color, pos, bz+0.1f, cliparea);
|
2006-04-24 01:14:18 +02:00
|
|
|
}
|
|
|
|
|
2015-08-21 19:08:41 +02:00
|
|
|
bool* scrollbar = NULL;
|
|
|
|
bool old;
|
2006-04-24 01:14:18 +02:00
|
|
|
GUI<bool>::GetSettingPointer(this, "scrollbar", scrollbar);
|
|
|
|
|
|
|
|
old = *scrollbar;
|
|
|
|
|
|
|
|
if (m_Open)
|
|
|
|
{
|
|
|
|
if (m_HideScrollBar)
|
2015-08-21 19:08:41 +02:00
|
|
|
*scrollbar = false;
|
2006-04-24 01:14:18 +02:00
|
|
|
|
|
|
|
DrawList(m_ElementHighlight, "sprite_list", "sprite_selectarea", "textcolor");
|
2015-08-21 19:08:41 +02:00
|
|
|
|
2006-04-24 01:14:18 +02:00
|
|
|
if (m_HideScrollBar)
|
|
|
|
*scrollbar = old;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// When a dropdown list is opened, it needs to be visible above all the other
|
|
|
|
// controls on the page. The only way I can think of to do this is to increase
|
|
|
|
// its z value when opened, so that it's probably on top.
|
|
|
|
float CDropDown::GetBufferedZ() const
|
|
|
|
{
|
|
|
|
float bz = CList::GetBufferedZ();
|
|
|
|
if (m_Open)
|
2008-07-13 23:22:03 +02:00
|
|
|
return std::min(bz + 500.f, 1000.f); // TODO - don't use magic number for max z value
|
2006-04-24 01:14:18 +02:00
|
|
|
else
|
|
|
|
return bz;
|
|
|
|
}
|