Make sure dropdowns fit in the screen by allowing the list to be above when there is not enough space

Reviewed By: Vladislav
Differential Revision: D1061
fixes #4857

This was SVN commit r21379.
This commit is contained in:
bb 2018-02-25 22:26:31 +00:00
parent a1ddf6114a
commit 3698c134b5
7 changed files with 91 additions and 11 deletions

View file

@ -77,6 +77,7 @@
sprite2_pressed="ModernDropDownArrowHighlight"
buffer_zone="8"
dropdown_size="225"
minimum_visible_items="3"
sprite_list="BlackBorderOnGray"
sprite_selectarea="ModernDarkBoxWhite"
textcolor_selected="white"

View file

@ -55,6 +55,7 @@ ex_settings =
attribute clip { bool }?&
attribute dropdown_size { xsd:decimal }?&
attribute dropdown_buffer { xsd:decimal }?&
attribute minimum_visible_items { xsd:nonNegativeInteger }?&
attribute enabled { bool }?&
attribute font { text }?&
attribute fov_wedge_color { ccolor }?&

View file

@ -214,6 +214,11 @@
<data type="decimal"/>
</attribute>
</optional>
<optional>
<attribute name="minimum_visible_items">
<data type="nonNegativeInteger"/>
</attribute>
</optional>
<optional>
<attribute name="enabled">
<ref name="bool"/>

View file

@ -31,6 +31,7 @@ CDropDown::CDropDown()
AddSetting(GUIST_float, "button_width");
AddSetting(GUIST_float, "dropdown_size");
AddSetting(GUIST_float, "dropdown_buffer");
AddSetting(GUIST_uint, "minimum_visible_items");
// AddSetting(GUIST_CStrW, "font");
AddSetting(GUIST_CStrW, "sound_closed");
AddSetting(GUIST_CStrW, "sound_disabled");
@ -85,6 +86,7 @@ void CDropDown::HandleMessage(SGUIMessage& Message)
Message.value == "absolute" ||
Message.value == "dropdown_size" ||
Message.value == "dropdown_buffer" ||
Message.value == "minimum_visible_items" ||
Message.value == "scrollbar_style" ||
Message.value == "button_width")
{
@ -389,23 +391,63 @@ InReaction CDropDown::ManuallyHandleEvent(const SDL_Event_* ev)
void CDropDown::SetupListRect()
{
float size, buffer;
extern int g_yres;
extern float g_GuiScale;
float size, buffer, yres;
yres = g_yres / g_GuiScale;
u32 minimumVisibleItems;
GUI<float>::GetSetting(this, "dropdown_size", size);
GUI<float>::GetSetting(this, "dropdown_buffer", buffer);
GUI<u32>::GetSetting(this, "minimum_visible_items", minimumVisibleItems);
if (m_ItemsYPositions.empty() || m_ItemsYPositions.back() > size)
if (m_ItemsYPositions.empty())
{
m_CachedListRect = CRect(m_CachedActualSize.left, m_CachedActualSize.bottom+buffer,
m_CachedActualSize.right, m_CachedActualSize.bottom+buffer + size);
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);
m_HideScrollBar = false;
}
else
{
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, 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;
}
}
}
@ -421,9 +463,8 @@ bool CDropDown::MouseOver()
if (m_Open)
{
CRect rect(m_CachedActualSize.left, m_CachedActualSize.top,
m_CachedActualSize.right, GetListRect().bottom);
CRect rect(m_CachedActualSize.left, std::min(m_CachedActualSize.top, GetListRect().top),
m_CachedActualSize.right, std::max(m_CachedActualSize.bottom, GetListRect().bottom));
return rect.PointInside(GetMousePos());
}
else

View file

@ -27,6 +27,7 @@ to handle every possible type.
TYPE(bool)
TYPE(int)
TYPE(uint)
TYPE(float)
TYPE(CColor)
TYPE(CClientArea)

View file

@ -46,6 +46,13 @@ bool __ParseString<int>(const CStrW& Value, int& Output)
return true;
}
template <>
bool __ParseString<u32>(const CStrW& Value, u32& Output)
{
Output = Value.ToUInt();
return true;
}
template <>
bool __ParseString<float>(const CStrW& Value, float& Output)
{

View file

@ -156,6 +156,17 @@ bool JSI_IGUIObject::getProperty(JSContext* cx, JS::HandleObject obj, JS::Handle
break;
}
case GUIST_uint:
{
u32 value;
GUI<u32>::GetSetting(e, propName, value);
if (value >= std::numeric_limits<u32>::max())
LOGERROR("Integer overflow on converting to GUIST_uint");
else
vp.set(JS::Int32Value(value));
break;
}
case GUIST_float:
{
float value;
@ -452,6 +463,19 @@ bool JSI_IGUIObject::setProperty(JSContext* cx, JS::HandleObject obj, JS::Handle
break;
}
case GUIST_uint:
{
u32 value;
if (ScriptInterface::FromJSVal(cx, vp, value))
GUI<u32>::SetSetting(e, propName, value);
else
{
JS_ReportError(cx, "Cannot convert value to u32");
return false;
}
break;
}
case GUIST_float:
{
double value;