Polished first stage of Context Menu
This commit is contained in:
parent
99886e8c62
commit
eb27fa42d1
10 changed files with 141 additions and 20 deletions
1
.clangd
1
.clangd
|
|
@ -1,5 +1,4 @@
|
|||
CompileFlags:
|
||||
CompilationDatabase: bin
|
||||
Add: ["--target=x86_64-w64-mingw32"]
|
||||
Diagnostics:
|
||||
MissingIncludes: None
|
||||
|
|
@ -258,7 +258,7 @@ const $accentColorDark = #6B0A1DFF
|
|||
|
||||
|
||||
|
||||
% ====== Slider ======
|
||||
% ====== ListView ======
|
||||
(list) {
|
||||
(item) {
|
||||
defaultTextColor = #202020FF
|
||||
|
|
@ -273,4 +273,21 @@ const $accentColorDark = #6B0A1DFF
|
|||
showSeparatorLine = true
|
||||
|
||||
}
|
||||
% ===================
|
||||
% ======================
|
||||
|
||||
|
||||
|
||||
% ====== Context Menu ======
|
||||
(context) {
|
||||
padding = rect(16, 0, 16, 0)
|
||||
itemSpacing = 6.0
|
||||
fontSize = 18
|
||||
backgroundColor = #CCAAAAFF
|
||||
selectionColor = $accentColor
|
||||
selectionTextColor = #FFFFFFFF
|
||||
separatorLineColor = #700000FF
|
||||
textColor = $textColor
|
||||
submenuIndicatorColor = $accentColorDark
|
||||
borderColor = #400000FF
|
||||
}
|
||||
% ==========================
|
||||
|
|
|
|||
|
|
@ -33,6 +33,7 @@ Add multi-selection to ListView
|
|||
Cache getStringDimensions() call in TabPanel::draw_tabs
|
||||
FIX: Optimize ListView
|
||||
FIX: Padding for ListView items
|
||||
Add icons to ListView
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@ namespace ogfx
|
|||
{
|
||||
auto s = gfx.getStringDimensions(entry.text, fontSize);
|
||||
if (s.x > size.x)
|
||||
size.x = s.x;
|
||||
size.x = s.x + (entry.submenus.size() > 0 ? 40 : 0);
|
||||
size.y += s.y;
|
||||
entry.update_size(gfx, fontSize);
|
||||
}
|
||||
|
|
@ -45,19 +45,53 @@ namespace ogfx
|
|||
return *this;
|
||||
}
|
||||
|
||||
void ContextMenu::applyTheme(const ostd::Stylesheet& theme)
|
||||
{
|
||||
setPadding(theme.get<Rectangle>("context.padding", getPadding(), {}, {}));
|
||||
setItemSpacing(theme.get<f32>("context.itemSpacing", getItemSpacing(), {}, {}));
|
||||
setFontSize(theme.get<i32>("context.fontSize", getFontSize(), {}, {}));
|
||||
setBackgroundColor(theme.get<Color>("context.backgroundColor", getBackgroundColor(), {}, {}));
|
||||
setSelectionColor(theme.get<Color>("context.selectionColor", getSelectionColor(), {}, {}));
|
||||
setSelectionTextColor(theme.get<Color>("context.selectionTextColor", getSelectionTextColor(), {}, {}));
|
||||
setSeparatorLineColor(theme.get<Color>("context.separatorLineColor", getSeparatorLineColor(), {}, {}));
|
||||
setTextColor(theme.get<Color>("context.textColor", getTextColor(), {}, {}));
|
||||
setSubmenuIndicatorColor(theme.get<Color>("context.submenuIndicatorColor", getSubmenuIndicatorColor(), {}, {}));
|
||||
setBorderColor(theme.get<Color>("context.borderColor", getBorderColor(), {}, {}));
|
||||
}
|
||||
|
||||
void ContextMenu::draw(BasicRenderer2D& gfx)
|
||||
{
|
||||
gfx.outlinedRect(*this, Colors::Crimson, Colors::Black, 2);
|
||||
gfx.fillRect(*this, getBackgroundColor());
|
||||
const f32 triPad = 14;
|
||||
f32 y = 0;
|
||||
i32 i = 0;
|
||||
for (auto& entry : m_data.entries)
|
||||
{
|
||||
Vec2 entryPos = getPosition() + Vec2 { m_padding.x, y + m_padding.y };
|
||||
Rectangle rect = { entryPos - Vec2 { m_padding.x, 0 }, getw(), m_entryHeight };
|
||||
if (rect.contains(m_mousePos, true))
|
||||
gfx.outlinedRect(rect, Colors::Chocolate, Colors::White, 1);
|
||||
gfx.drawString(entry.text, entryPos, Colors::Black, getFontSize());
|
||||
y += m_entryHeight;
|
||||
{
|
||||
gfx.outlinedRect(rect, getSelectionColor(), getSeparatorLineColor(), 1, false, false, i != m_data.entries.size() , false);
|
||||
gfx.drawVCenteredString(entry.text, { entryPos, getw(), m_entryHeight }, getSelectionTextColor(), getFontSize());
|
||||
}
|
||||
else
|
||||
{
|
||||
gfx.drawRect(rect, getSeparatorLineColor(), 1, false, false, i != m_data.entries.size() , false);
|
||||
gfx.drawVCenteredString(entry.text, { entryPos, getw(), m_entryHeight }, getTextColor(), getFontSize());
|
||||
}
|
||||
if (entry.submenus.size() > 0)
|
||||
{
|
||||
Triangle tri {
|
||||
{ rect.x + rect.w - m_entryHeight + triPad, rect.y + (triPad * 0.5f) },
|
||||
{ rect.x + rect.w - (triPad * 0.5f), rect.y + (rect.h * 0.5f) },
|
||||
{ rect.x + rect.w - m_entryHeight + triPad, rect.y + rect.h - (triPad * 0.5f) }
|
||||
};
|
||||
gfx.fillTriangle(tri, getSubmenuIndicatorColor());
|
||||
}
|
||||
y += m_entryHeight;
|
||||
i++;
|
||||
}
|
||||
gfx.drawRect(*this, getBorderColor(), 2);
|
||||
}
|
||||
|
||||
void ContextMenu::onMouseReleased(const Event& event)
|
||||
|
|
@ -84,6 +118,16 @@ namespace ogfx
|
|||
event.handle();
|
||||
}
|
||||
|
||||
void ContextMenu::onMousePressed(const Event& event)
|
||||
{
|
||||
event.handle();
|
||||
}
|
||||
|
||||
void ContextMenu::onMouseScrolled(const Event& event)
|
||||
{
|
||||
event.handle();
|
||||
}
|
||||
|
||||
void ContextMenu::show(void)
|
||||
{
|
||||
m_visible = true;
|
||||
|
|
@ -119,10 +163,11 @@ namespace ogfx
|
|||
for (auto& entry : m_data.entries)
|
||||
{
|
||||
auto s = gfx.getStringDimensions(entry.text, getFontSize());
|
||||
if (s.x > getw())
|
||||
setw(s.x);
|
||||
addh(s.y);
|
||||
m_entryHeight = s.y;
|
||||
f32 extra = (entry.submenus.size() > 0 ? s.y : 0);
|
||||
if (s.x + extra > getw())
|
||||
setw(s.x + extra);
|
||||
addh(s.y + m_spacing);
|
||||
m_entryHeight = s.y + m_spacing;
|
||||
entry.update_size(gfx, getFontSize());
|
||||
}
|
||||
addSize({ m_padding.x + m_padding.w, m_padding.y + m_padding.h });
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ namespace ogfx
|
|||
{
|
||||
public: struct Entry
|
||||
{
|
||||
inline Entry(const String& t, const stdvec<Entry>& sub = {}) { text = t; }
|
||||
inline Entry(const String& t, const stdvec<Entry>& sub = {}) { text = t; submenus = sub; }
|
||||
String text { "" };
|
||||
stdvec<Entry> submenus;
|
||||
|
||||
|
|
@ -47,9 +47,12 @@ namespace ogfx
|
|||
public:
|
||||
inline ContextMenu(WindowCore& window) : m_window(window) { create(); }
|
||||
ContextMenu& create(void);
|
||||
void applyTheme(const ostd::Stylesheet& theme);
|
||||
void draw(BasicRenderer2D& gfx);
|
||||
void onMouseReleased(const Event& event);
|
||||
void onMouseMoved(const Event& event);
|
||||
void onMousePressed(const Event& event);
|
||||
void onMouseScrolled(const Event& event);
|
||||
void show(void);
|
||||
void show(const Vec2& pos);
|
||||
void hide(void);
|
||||
|
|
@ -59,6 +62,16 @@ namespace ogfx
|
|||
inline bool isVisible(void) const { return m_visible; }
|
||||
inline i32 getFontSize(void) const { return m_fontSize; }
|
||||
|
||||
OSTD_PARAM_GETSET(Rectangle, Padding, m_padding);
|
||||
OSTD_PARAM_GETSET(f32, ItemSpacing, m_spacing);
|
||||
OSTD_PARAM_GETSET(Color, BackgroundColor, m_backgroundColor);
|
||||
OSTD_PARAM_GETSET(Color, SelectionColor, m_selectionColor);
|
||||
OSTD_PARAM_GETSET(Color, SelectionTextColor, m_selectionTextColor);
|
||||
OSTD_PARAM_GETSET(Color, SeparatorLineColor, m_separatorLineColor);
|
||||
OSTD_PARAM_GETSET(Color, TextColor, m_textColor);
|
||||
OSTD_PARAM_GETSET(Color, SubmenuIndicatorColor, m_submenuIndicatorColor);
|
||||
OSTD_PARAM_GETSET(Color, BorderColor, m_borderColor);
|
||||
|
||||
private:
|
||||
void update_size(void);
|
||||
|
||||
|
|
@ -67,10 +80,19 @@ namespace ogfx
|
|||
bool m_visible { false };
|
||||
Instance m_data;
|
||||
f32 m_entryHeight { 0 };
|
||||
Rectangle m_padding { 10, 10, 10, 10 };
|
||||
Vec2 m_mousePos;
|
||||
Vec2 m_mousePos { 0, 0 };
|
||||
|
||||
Rectangle m_padding { 16, 0, 16, 0 };
|
||||
f32 m_spacing { 8 };
|
||||
i32 m_fontSize { 18 };
|
||||
Color m_backgroundColor { "#6B0A1DFF" };
|
||||
Color m_selectionColor { "#DC143CFF" };
|
||||
Color m_selectionTextColor { "#F16A85FF" };
|
||||
Color m_separatorLineColor { "#700000FF" };
|
||||
Color m_textColor { "#F16A85FF" };
|
||||
Color m_submenuIndicatorColor { "#111111FF" };
|
||||
Color m_borderColor { "#400000FF" };
|
||||
|
||||
|
||||
friend class Instance;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -829,6 +829,7 @@ namespace ogfx
|
|||
m_guiTheme = &theme;
|
||||
m_rootWidget.__applyTheme(theme, true);
|
||||
m_rootWidget.reloadTheme(true);
|
||||
m_cmenu.applyTheme(theme);
|
||||
}
|
||||
|
||||
void Window::__on_window_init(i32 width, i32 height, const String& title)
|
||||
|
|
@ -871,9 +872,11 @@ namespace ogfx
|
|||
m_rootWidget.__draw(m_gfx);
|
||||
onRedraw(m_gfx);
|
||||
if (m_cmenu.isVisible())
|
||||
{
|
||||
stopTooltipTimer();
|
||||
m_cmenu.draw(m_gfx);
|
||||
|
||||
if (isTooltipShown())
|
||||
}
|
||||
else if (isTooltipShown())
|
||||
{
|
||||
auto textSize = m_gfx.getStringDimensions(getTooltipText(), m_rootWidget.getTooltipFontSize());
|
||||
Rectangle textBounds = { getMousePosition(), textSize };
|
||||
|
|
@ -902,6 +905,8 @@ namespace ogfx
|
|||
}
|
||||
else if (signal.ID == ostd::BuiltinSignals::WindowLostFocus)
|
||||
{
|
||||
if (m_cmenu.isVisible())
|
||||
m_cmenu.hide();
|
||||
evt.__original_signal_id = ostd::BuiltinSignals::WindowLostFocus;
|
||||
m_rootWidget.__onWindowFocusLost(evt);
|
||||
}
|
||||
|
|
@ -925,6 +930,8 @@ namespace ogfx
|
|||
}
|
||||
else if (signal.ID == ostd::BuiltinSignals::WindowResized)
|
||||
{
|
||||
if (m_cmenu.isVisible())
|
||||
m_cmenu.hide();
|
||||
evt.windowResized = &(ogfx::WindowResizedData&)signal.userData;
|
||||
evt.__original_signal_id = ostd::BuiltinSignals::WindowResized;
|
||||
m_rootWidget.__onWindowResized(evt);
|
||||
|
|
@ -941,12 +948,16 @@ namespace ogfx
|
|||
{
|
||||
evt.mouse = &(ogfx::MouseEventData&)signal.userData;
|
||||
evt.__original_signal_id = ostd::BuiltinSignals::MouseScrolled;
|
||||
if (m_cmenu.isVisible())
|
||||
m_cmenu.onMouseScrolled(evt);
|
||||
m_rootWidget.__onMouseScrolled(evt);
|
||||
}
|
||||
else if (signal.ID == ostd::BuiltinSignals::MousePressed)
|
||||
{
|
||||
evt.mouse = &(ogfx::MouseEventData&)signal.userData;
|
||||
evt.__original_signal_id = ostd::BuiltinSignals::MousePressed;
|
||||
if (m_cmenu.isVisible())
|
||||
m_cmenu.onMousePressed(evt);
|
||||
m_rootWidget.__onMousePressed(evt);
|
||||
}
|
||||
else if (signal.ID == ostd::BuiltinSignals::MouseReleased)
|
||||
|
|
|
|||
|
|
@ -272,6 +272,7 @@ namespace ogfx
|
|||
|
||||
void Widget::__onMousePressed(const Event& event)
|
||||
{
|
||||
if (event.isHandled()) return;
|
||||
setThemeQualifier("pressed");
|
||||
if (hasChildren())
|
||||
m_widgets.onMousePressed(event);
|
||||
|
|
@ -286,6 +287,7 @@ namespace ogfx
|
|||
|
||||
void Widget::__onMouseReleased(const Event& event)
|
||||
{
|
||||
if (event.isHandled()) return;
|
||||
setThemeQualifier("pressed", false);
|
||||
m_pressedButton = ogfx::MouseEventData::eButton::None;
|
||||
if (hasChildren())
|
||||
|
|
@ -312,6 +314,7 @@ namespace ogfx
|
|||
|
||||
void Widget::__onMouseMoved(const Event& event)
|
||||
{
|
||||
if (event.isHandled()) return;
|
||||
if (hasChildren())
|
||||
m_widgets.onMouseMoved(event);
|
||||
if (!event.isHandled())
|
||||
|
|
@ -326,6 +329,7 @@ namespace ogfx
|
|||
|
||||
void Widget::__onMouseScrolled(const Event& event)
|
||||
{
|
||||
if (event.isHandled()) return;
|
||||
if (hasChildren())
|
||||
m_widgets.onMouseScrolled(event);
|
||||
if (!event.isHandled())
|
||||
|
|
@ -338,6 +342,7 @@ namespace ogfx
|
|||
|
||||
void Widget::__onMouseEntered(const Event& event)
|
||||
{
|
||||
if (event.isHandled()) return;
|
||||
setThemeQualifier("hover");
|
||||
if (callback_onMouseEntered)
|
||||
callback_onMouseEntered(event);
|
||||
|
|
@ -348,6 +353,7 @@ namespace ogfx
|
|||
|
||||
void Widget::__onMouseExited(const Event& event)
|
||||
{
|
||||
if (event.isHandled()) return;
|
||||
setThemeQualifier("hover", false);
|
||||
if (callback_onMouseExited)
|
||||
callback_onMouseExited(event);
|
||||
|
|
@ -358,6 +364,7 @@ namespace ogfx
|
|||
|
||||
void Widget::__onMouseDragged(const Event& event)
|
||||
{
|
||||
if (event.isHandled()) return;
|
||||
if (hasChildren())
|
||||
m_widgets.onMouseDragged(event);
|
||||
if (!event.isHandled())
|
||||
|
|
@ -366,10 +373,13 @@ namespace ogfx
|
|||
callback_onMouseDragged(event);
|
||||
onMouseDragged(event);
|
||||
}
|
||||
if (isTooltipEnabled() && isMouseInside())
|
||||
getWindow().restartTooltipTimer();
|
||||
}
|
||||
|
||||
void Widget::__onKeyPressed(const Event& event)
|
||||
{
|
||||
if (event.isHandled()) return;
|
||||
if (hasChildren())
|
||||
m_widgets.onKeyPressed(event);
|
||||
if (!event.isHandled())
|
||||
|
|
@ -382,6 +392,7 @@ namespace ogfx
|
|||
|
||||
void Widget::__onKeyReleased(const Event& event)
|
||||
{
|
||||
if (event.isHandled()) return;
|
||||
m_pressedButton = ogfx::MouseEventData::eButton::None;
|
||||
if (hasChildren())
|
||||
m_widgets.onKeyReleased(event);
|
||||
|
|
@ -395,6 +406,7 @@ namespace ogfx
|
|||
|
||||
void Widget::__onTextEntered(const Event& event)
|
||||
{
|
||||
if (event.isHandled()) return;
|
||||
if (hasChildren())
|
||||
m_widgets.onTextEntered(event);
|
||||
if (!event.isHandled())
|
||||
|
|
|
|||
|
|
@ -436,13 +436,25 @@ namespace ogfx
|
|||
void BasicRenderer2D::drawCenteredString(const String& str, const Vec2& center, const Color& color, i32 fontSize, f32 scale)
|
||||
{
|
||||
auto dims = getStringDimensions(str, fontSize);
|
||||
drawString(str, { center.x - (dims.x * scale) * 0.5f, center.y - (dims.y * scale) * 0.5f }, color, fontSize, scale);
|
||||
drawString(str, { center.x - dims.x * 0.5f, center.y - dims.y * 0.5f }, color, fontSize, scale);
|
||||
}
|
||||
|
||||
void BasicRenderer2D::drawCenteredString(const String& str, const Rectangle& bounds, const Color& color, i32 fontSize, f32 scale)
|
||||
{
|
||||
drawCenteredString(str, Vec2 { bounds.x + bounds.w * 0.5f, bounds.y + bounds.h * 0.5f }, color, fontSize, scale);
|
||||
}
|
||||
|
||||
void BasicRenderer2D::drawVCenteredString(const String& str, const Rectangle& bounds, const Color& color, i32 fontSize, f32 scale)
|
||||
{
|
||||
auto dims = getStringDimensions(str, fontSize);
|
||||
drawString(str, { bounds.x, (bounds.y + bounds.h * 0.5f) - dims.y * 0.5f }, color, fontSize, scale);
|
||||
}
|
||||
|
||||
void BasicRenderer2D::drawHCenteredString(const String& str, const Rectangle& bounds, const Color& color, i32 fontSize, f32 scale)
|
||||
{
|
||||
auto dims = getStringDimensions(str, fontSize);
|
||||
drawString(str, { (bounds.x + bounds.w * 0.5f) - dims.x * 0.5f, bounds.y }, color, fontSize, scale);
|
||||
}
|
||||
// ===================================================== SPECIALIZED =====================================================
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -87,6 +87,8 @@ namespace ogfx
|
|||
void drawString(const String& str, const Vec2& position, const Color& color, i32 fontSize = 0, f32 scale = 1.0f);
|
||||
void drawCenteredString(const String& str, const Vec2& center, const Color& color, i32 fontSize = 0, f32 scale = 1.0f);
|
||||
void drawCenteredString(const String& str, const Rectangle& bounds, const Color& color, i32 fontSize = 0, f32 scale = 1.0f);
|
||||
void drawVCenteredString(const String& str, const Rectangle& bounds, const Color& color, i32 fontSize = 0, f32 scale = 1.0f);
|
||||
void drawHCenteredString(const String& str, const Rectangle& bounds, const Color& color, i32 fontSize = 0, f32 scale = 1.0f);
|
||||
|
||||
void drawLine(const FLine& line, const Color& color, i32 thickness = 1, bool rounded = true);
|
||||
void drawRect(const Rectangle& rect, const Color& color, i32 thickness = 1, bool topEdge = true, bool rightEdge = true, bool bottomEdge = true, bool leftEdge = true);
|
||||
|
|
|
|||
|
|
@ -152,7 +152,7 @@ class Window : public ogfx::gui::Window
|
|||
t1.addWidget(m_slide, { 30, 250 });
|
||||
t1.addWidget(m_slideLbl, { 340, 240 });
|
||||
t1.addWidget(m_list, { 30, 300 });
|
||||
t2.addWidget(m_panel2, { 500, 100 });
|
||||
t1.addWidget(m_panel2, { 500, 100 });
|
||||
|
||||
m_panel3.addWidget(m_label4);
|
||||
|
||||
|
|
@ -238,8 +238,8 @@ class Window : public ogfx::gui::Window
|
|||
{
|
||||
{ "Update" },
|
||||
{ "File" },
|
||||
{ "Open RAW" },
|
||||
{ "Mouse Settings" },
|
||||
{ "Open RAW", { { "Image" }, { "Text File" }, { "Audio" } } },
|
||||
{ "Mouse Settings", { { "Test" } } },
|
||||
{ "Terror" },
|
||||
{ "Properties" }
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue