From dce19b0d3b6ea02fb1063b4e9553b5d840c0d9cd Mon Sep 17 00:00:00 2001 From: bb Date: Sun, 25 Feb 2018 22:26:31 +0000 Subject: [PATCH] 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 git-svn-id: https://svn.wildfiregames.com/public/ps/trunk@21379 3db68df2-c116-0410-a063-a993310a9797 --- .../data/mods/mod/gui/common/modern/styles.xml | 1 + binaries/data/mods/mod/gui/gui.rnc | 1 + binaries/data/mods/mod/gui/gui.rng | 5 ++ source/gui/CDropDown.cpp | 63 ++++++++++++++++++---- source/gui/GUItypes.h | 1 + source/gui/GUIutil.cpp | 7 +++ source/gui/scripting/JSInterface_IGUIObject.cpp | 24 +++++++++ 7 files changed, 91 insertions(+), 11 deletions(-) diff --git a/binaries/data/mods/mod/gui/common/modern/styles.xml b/binaries/data/mods/mod/gui/common/modern/styles.xml index f9c318fcdb..3dc7f760a1 100644 --- a/binaries/data/mods/mod/gui/common/modern/styles.xml +++ b/binaries/data/mods/mod/gui/common/modern/styles.xml @@ -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" diff --git a/binaries/data/mods/mod/gui/gui.rnc b/binaries/data/mods/mod/gui/gui.rnc index 55e182ad86..ab93ef6638 100644 --- a/binaries/data/mods/mod/gui/gui.rnc +++ b/binaries/data/mods/mod/gui/gui.rnc @@ -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 }?& diff --git a/binaries/data/mods/mod/gui/gui.rng b/binaries/data/mods/mod/gui/gui.rng index c1c8338a7e..5e28fefc71 100644 --- a/binaries/data/mods/mod/gui/gui.rng +++ b/binaries/data/mods/mod/gui/gui.rng @@ -215,6 +215,11 @@ + + + + + diff --git a/source/gui/CDropDown.cpp b/source/gui/CDropDown.cpp index c767ac0a31..e233160e5a 100644 --- a/source/gui/CDropDown.cpp +++ b/source/gui/CDropDown.cpp @@ -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::GetSetting(this, "dropdown_size", size); GUI::GetSetting(this, "dropdown_buffer", buffer); + GUI::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 diff --git a/source/gui/GUItypes.h b/source/gui/GUItypes.h index 0daab15795..5eb5322e8f 100644 --- a/source/gui/GUItypes.h +++ b/source/gui/GUItypes.h @@ -27,6 +27,7 @@ to handle every possible type. TYPE(bool) TYPE(int) +TYPE(uint) TYPE(float) TYPE(CColor) TYPE(CClientArea) diff --git a/source/gui/GUIutil.cpp b/source/gui/GUIutil.cpp index 6e3d9db25b..703298d0a7 100644 --- a/source/gui/GUIutil.cpp +++ b/source/gui/GUIutil.cpp @@ -47,6 +47,13 @@ bool __ParseString(const CStrW& Value, int& Output) } template <> +bool __ParseString(const CStrW& Value, u32& Output) +{ + Output = Value.ToUInt(); + return true; +} + +template <> bool __ParseString(const CStrW& Value, float& Output) { Output = Value.ToFloat(); diff --git a/source/gui/scripting/JSInterface_IGUIObject.cpp b/source/gui/scripting/JSInterface_IGUIObject.cpp index a6d31590b8..b0ee5fb45b 100644 --- a/source/gui/scripting/JSInterface_IGUIObject.cpp +++ b/source/gui/scripting/JSInterface_IGUIObject.cpp @@ -156,6 +156,17 @@ bool JSI_IGUIObject::getProperty(JSContext* cx, JS::HandleObject obj, JS::Handle break; } + case GUIST_uint: + { + u32 value; + GUI::GetSetting(e, propName, value); + if (value >= std::numeric_limits::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::SetSetting(e, propName, value); + else + { + JS_ReportError(cx, "Cannot convert value to u32"); + return false; + } + break; + } + case GUIST_float: { double value; -- 2.11.4.GIT