Added TabPanel widget
This commit is contained in:
parent
5491e5d4b3
commit
cda204aec9
8 changed files with 153 additions and 48 deletions
|
|
@ -21,7 +21,7 @@ window.backgroundColor = rgba(160, 160, 160, 255)
|
|||
titlebarColor = #999999FF
|
||||
titlebarBorderColor = #909090FF
|
||||
borderColor = #909090FF
|
||||
borderRadius = 10
|
||||
borderRadius = 0
|
||||
borderWidth = 2
|
||||
titlebarBorderWidth = 2
|
||||
showBorder = true
|
||||
|
|
@ -39,30 +39,29 @@ window.backgroundColor = rgba(160, 160, 160, 255)
|
|||
|
||||
|
||||
|
||||
% ====== Panel ======
|
||||
% ====== TabPanel ======
|
||||
(tabPanel) {
|
||||
backgroundColor = #AAAAAAFF
|
||||
borderColor = #909090FF
|
||||
borderColor = #666666FF
|
||||
borderRadius = 0
|
||||
borderWidth = 2
|
||||
showBorder = true
|
||||
showBackground = true
|
||||
padding = rect(0, 0, 0, 0)
|
||||
margin = rect(0, 0, 0, 0)
|
||||
textColor = $textColor
|
||||
fontSize = 18
|
||||
|
||||
(tabBar) {
|
||||
height = 35.0
|
||||
fontSize = 18
|
||||
backgroundColor = #999999FF
|
||||
backgroundColor = #888888FF
|
||||
borderColor = #909090FF
|
||||
borderWidth = 2
|
||||
borderWidth = 1
|
||||
sidePadding = 20.0
|
||||
}
|
||||
}
|
||||
(@panel_tab panel) {
|
||||
backgroundColor = color_crimson
|
||||
}
|
||||
% ===================
|
||||
% ======================
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -55,3 +55,4 @@ Implement following widgets:
|
|||
Vertical
|
||||
Horizontal
|
||||
Grid
|
||||
Tooltips
|
||||
|
|
|
|||
|
|
@ -146,23 +146,51 @@ namespace ogfx
|
|||
void TabPanel::applyTheme(const ostd::Stylesheet& theme)
|
||||
{
|
||||
setTabBarHeight(getThemeValue<f32>(theme, "tabBar.height", m_tabBarHeight));
|
||||
setTabBarBackgroundColor(getThemeValue<Color>(theme, "tabBar.backgroundColor", m_tabBarBackgroundColor));
|
||||
setTabBarBorderColor(getThemeValue<Color>(theme, "tabBar.borderColor", m_tabBarBorderColor));
|
||||
setTabBarBorderColor(getThemeValue<i32>(theme, "tabBar.borderWidth", m_tabBarBorderWidth));
|
||||
setTabBarSidePadding(getThemeValue<f32>(theme, "tabBar.sidePadding", m_tabSidePadding));
|
||||
}
|
||||
|
||||
for (auto& tab : m_tabs)
|
||||
void TabPanel::onMousePressed(const Event& event)
|
||||
{
|
||||
if (!isMouseInsideTabBar({ event.mouse->position_x, event.mouse->position_y }))
|
||||
return;
|
||||
const f32 extra_offset = 5;
|
||||
i32 index = 0;
|
||||
for (auto& b : m_tabBoundsList)
|
||||
{
|
||||
if (tab == nullptr)
|
||||
continue;
|
||||
tab->setBackgroundColor(getBackgroundColor());
|
||||
if (b.contains(event.mouse->position_x, event.mouse->position_y))
|
||||
{
|
||||
setCurrentTab(*m_tabs[index]);
|
||||
Rectangle tabBounds = m_tabBoundsList[index];
|
||||
f32 tabLocalLeft = tabBounds.x - getGlobalPosition().x;
|
||||
f32 tabLocalRight = tabLocalLeft + tabBounds.w;
|
||||
|
||||
if (tabLocalLeft < 0)
|
||||
m_tabScrollOffset += tabLocalLeft - extra_offset;
|
||||
else if (tabLocalRight > getw())
|
||||
m_tabScrollOffset += (tabLocalRight - getw()) + extra_offset;
|
||||
break;
|
||||
}
|
||||
index++;
|
||||
}
|
||||
}
|
||||
|
||||
void TabPanel::onMouseReleased(const Event& event)
|
||||
void TabPanel::onMouseScrolled(const Event& event)
|
||||
{
|
||||
|
||||
if (!isMouseInsideTabBar({ event.mouse->position_x, event.mouse->position_y }))
|
||||
return;
|
||||
if (m_tabs.size() == 0)
|
||||
return;
|
||||
const f32 extra_offset = 5;
|
||||
m_tabScrollOffset += (event.mouse->scrollAmount.y * -40.0f);
|
||||
m_tabScrollOffset = std::clamp(m_tabScrollOffset, -extra_offset, m_totalTabWidth - getw() + extra_offset);
|
||||
}
|
||||
|
||||
void TabPanel::onDraw(ogfx::BasicRenderer2D& gfx)
|
||||
{
|
||||
gfx.outlinedRoundRect({ getGlobalPosition(), { getw(), m_tabBarHeight } }, m_tabBarBackgroundColor, m_tabBarBorderColor, m_tabBarBorderRadii, getBorderWidth());
|
||||
gfx.outlinedRect({ getGlobalPosition(), { getw(), getTabBarHeight() } }, getTabBarBackgroundColor(), getTabBarBorderColor(), getTabBarBorderWidth(), false, false, true, false);
|
||||
draw_tabs(gfx);
|
||||
}
|
||||
|
||||
|
|
@ -172,10 +200,13 @@ namespace ogfx
|
|||
auto& tab = *m_tabs.back();
|
||||
tab.setTitle(title);
|
||||
tab.setTitlebarType(Panel::TitleBarTypes::None);
|
||||
if (m_currentTab == nullptr && m_tabs.size() == 2)
|
||||
tab.addThemeOverride("@panel_tab.panel.titlebarType", "none");
|
||||
tab.addThemeOverride("@panel_tab.panel.showBorder", false);
|
||||
tab.addThemeOverride("@panel_tab.panel.borderRadius", 0);
|
||||
tab.setBackgroundColor(getBackgroundColor());
|
||||
if (m_currentTab == nullptr && m_tabs.size() == 1)
|
||||
setCurrentTab(tab);
|
||||
tab.addThemeID("panel_tab");
|
||||
// Initialization code here
|
||||
return tab;
|
||||
}
|
||||
|
||||
|
|
@ -215,27 +246,42 @@ namespace ogfx
|
|||
auto it = std::find_if(m_tabs.begin(), m_tabs.end(), [&](const std::unique_ptr<Panel>& p) { return p.get() == &tab; });
|
||||
if (it == m_tabs.end())
|
||||
return false;
|
||||
m_currentTab = it->get();
|
||||
return true;
|
||||
i32 index = it - m_tabs.begin();
|
||||
return setCurrentTab(index);
|
||||
}
|
||||
|
||||
bool TabPanel::setCurrentTab(i32 index)
|
||||
{
|
||||
if (index < 0 || index >= (i32)m_tabs.size())
|
||||
return false;
|
||||
m_currentTab = m_tabs[index].get();
|
||||
return true;
|
||||
|
||||
auto curr = m_tabs[index].get();
|
||||
if (curr == m_currentTab && m_currentTab != nullptr)
|
||||
return false;
|
||||
removeWidget(*m_currentTab);
|
||||
m_currentTabIndex = index;
|
||||
m_currentTab = curr;
|
||||
m_currentTab->setMargin({ 0, 0, 0, 0 });
|
||||
m_currentTab->setSize(getPureContentBounds().getSize());
|
||||
m_currentTab->setPosition({ 0, 0 });
|
||||
m_currentTab->reloadTheme(true);
|
||||
m_currentTab->resetScroll();
|
||||
return addWidget(*m_currentTab);
|
||||
}
|
||||
|
||||
void TabPanel::setTabBarHeight(f32 height)
|
||||
{
|
||||
if (height == m_tabBarHeight)
|
||||
return;
|
||||
m_tabBarHeight = height;
|
||||
m_tabBarBorderRadii = { cast<f32>(getBorderRadius()), cast<f32>(getBorderRadius()), 0, 0 };
|
||||
setContentOffset({ 0, m_tabBarHeight });
|
||||
}
|
||||
|
||||
bool TabPanel::isMouseInsideTabBar(const Vec2& mousePos)
|
||||
{
|
||||
Rectangle bounds { getGlobalPosition(), { getw(), getTabBarHeight() } };
|
||||
return bounds.contains(mousePos, true);
|
||||
}
|
||||
|
||||
void TabPanel::prepare_for_current_tab_removal(void)
|
||||
{
|
||||
if (m_currentTab == nullptr)
|
||||
|
|
@ -258,34 +304,31 @@ namespace ogfx
|
|||
|
||||
void TabPanel::draw_tabs(ogfx::BasicRenderer2D& gfx)
|
||||
{
|
||||
f32 nextTabX = 2;
|
||||
f32 nextTabX = 1 - m_tabScrollOffset;
|
||||
m_tabBoundsList.clear();
|
||||
i32 index = -1;
|
||||
for (const auto& _tab : m_tabs)
|
||||
{
|
||||
index++;
|
||||
if (_tab == nullptr) continue;
|
||||
const auto& tab = *_tab;
|
||||
auto titleBounds = gfx.getStringDimensions(tab.getTitle(), getFontSize());
|
||||
auto glob = getGlobalPosition();
|
||||
Rectangle tabBounds { glob + Vec2 { nextTabX, 2}, { titleBounds.x + (m_tabSidePadding * 2), m_tabBarHeight - 3 } };
|
||||
Rectangle tabBounds { glob + Vec2 { nextTabX, 2}, { titleBounds.x + (m_tabSidePadding * 2), m_tabBarHeight } };
|
||||
if (m_currentTab == _tab.get())
|
||||
{
|
||||
gfx.outlinedRect(tabBounds, tab.getBackgroundColor(), Colors::Black, 1, true, true, false, true);
|
||||
gfx.outlinedRect(tabBounds, tab.getBackgroundColor(), getTabBarBorderColor(), getTabBarBorderWidth(), true, true, true, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
gfx.drawRect(tabBounds, Colors::Black, 1, true, true, false, true);
|
||||
bool draw_right_edge = !(m_currentTabIndex == (index + 1));
|
||||
gfx.drawRect(tabBounds - Rectangle { 0, 0, 0, 2 }, getTabBarBorderColor(), getTabBarBorderWidth(), false, draw_right_edge, true, false);
|
||||
}
|
||||
gfx.drawCenteredString(tab.getTitle(), tabBounds, getTextColor(), getFontSize());
|
||||
nextTabX += titleBounds.x + (m_tabSidePadding * 2);
|
||||
|
||||
// f32 titleY = (m_tabBarHeight / 2.0f) - (titleBounds.y / 2.0f);
|
||||
// if (m_currentTab == _tab.get())
|
||||
// {
|
||||
// gfx.fillRect({ getGlobalPosition() + Vec2 { nextTabX, 0 }, { (titleBounds.x * 2), m_tabBarHeight } }, tab.getBackgroundColor());
|
||||
// }
|
||||
// gfx.drawString(tab.getTitle(), getGlobalPosition() + Vec2 { nextTabX + m_tabSidePadding, titleY }, getTextColor(), getFontSize());
|
||||
// nextTabX += titleBounds.x + (m_tabSidePadding * 2);
|
||||
// gfx.drawLine({ getGlobalPosition() + Vec2 { nextTabX, 0 }, getGlobalPosition() + Vec2 { nextTabX, m_tabBarHeight - 3 } }, Colors::Black, 2);
|
||||
m_tabBoundsList.push_back(tabBounds);
|
||||
}
|
||||
m_totalTabWidth = nextTabX + m_tabScrollOffset - 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -74,7 +74,8 @@ namespace ogfx
|
|||
inline TabPanel(WindowCore& window) : Widget({ 0, 0, 0, 0 }, window) { create(); }
|
||||
TabPanel& create(void);
|
||||
void applyTheme(const ostd::Stylesheet& theme) override;
|
||||
void onMouseReleased(const Event& event) override;
|
||||
void onMousePressed(const Event& event) override;
|
||||
void onMouseScrolled(const Event& event) override;
|
||||
void onDraw(ogfx::BasicRenderer2D& gfx) override;
|
||||
Panel& addTab(const String& title);
|
||||
bool removeTab(Panel& tab);
|
||||
|
|
@ -83,6 +84,13 @@ namespace ogfx
|
|||
bool setCurrentTab(Panel& tab);
|
||||
bool setCurrentTab(i32 index);
|
||||
void setTabBarHeight(f32 height);
|
||||
bool isMouseInsideTabBar(const Vec2& mousePos);
|
||||
|
||||
inline f32 getTabBarHeight(void) const { return m_tabBarHeight; }
|
||||
OSTD_PARAM_GETSET(Color, TabBarBackgroundColor, m_tabBarBackgroundColor);
|
||||
OSTD_PARAM_GETSET(Color, TabBarBorderColor, m_tabBarBorderColor);
|
||||
OSTD_PARAM_GETSET(f32, TabBarSidePadding, m_tabSidePadding);
|
||||
OSTD_PARAM_GETSET(i32, TabBarBorderWidth, m_tabBarBorderWidth);
|
||||
|
||||
private:
|
||||
void prepare_for_current_tab_removal(void);
|
||||
|
|
@ -90,13 +98,18 @@ namespace ogfx
|
|||
|
||||
private:
|
||||
stdvec<std::unique_ptr<Panel>> m_tabs;
|
||||
stdvec<Rectangle> m_tabBoundsList;
|
||||
Panel* m_currentTab { nullptr };
|
||||
i32 m_currentTabIndex { -1 };
|
||||
f32 m_tabScrollOffset { 0.0f };
|
||||
f32 m_totalTabWidth { 0.0f };
|
||||
Rectangle m_tabBarBorderRadii { 0, 0, 0, 0 };
|
||||
|
||||
f32 m_tabBarHeight { 35 };
|
||||
Color m_tabBarBackgroundColor { 120, 120, 120 };
|
||||
Color m_tabBarBorderColor { 170, 170, 170 };
|
||||
f32 m_tabSidePadding { 20 };
|
||||
i32 m_tabBarBorderWidth { 2 };
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -306,6 +306,26 @@ namespace ogfx
|
|||
void ScrollableWidget::onUpdate(void)
|
||||
{
|
||||
m_smoothScrollTimer.update();
|
||||
if (!needsVScroll() && m_vScrollbarAdded)
|
||||
{
|
||||
removeWidget(m_vScrollbar);
|
||||
m_vScrollbarAdded = false;
|
||||
}
|
||||
else if (!m_vScrollbarAdded)
|
||||
{
|
||||
addWidget(m_vScrollbar);
|
||||
m_vScrollbarAdded = true;
|
||||
}
|
||||
if (!needsHScroll() && m_hScrollbarAdded)
|
||||
{
|
||||
removeWidget(m_hScrollbar);
|
||||
m_hScrollbarAdded = false;
|
||||
}
|
||||
else if (!m_hScrollbarAdded)
|
||||
{
|
||||
addWidget(m_hScrollbar);
|
||||
m_hScrollbarAdded = true;
|
||||
}
|
||||
}
|
||||
|
||||
void ScrollableWidget::drawScrollbars(ogfx::BasicRenderer2D& gfx)
|
||||
|
|
@ -319,6 +339,22 @@ namespace ogfx
|
|||
m_vScrollbar.setMargin({ 0, getPureContentBounds().y, 0, 0 });
|
||||
}
|
||||
|
||||
void ScrollableWidget::resetScroll(bool horizontal, bool vertical, bool propagate)
|
||||
{
|
||||
if (vertical)
|
||||
m_scrollOffset.y = 0;
|
||||
if (horizontal)
|
||||
m_scrollOffset.x = 0;
|
||||
if (propagate)
|
||||
{
|
||||
for (auto& w : getChildren().getWidgets())
|
||||
{
|
||||
if (w == nullptr) continue;
|
||||
w->resetScroll(horizontal, vertical, propagate);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ScrollableWidget::onMouseScrolled(const Event& event)
|
||||
{
|
||||
if (isVScrollEnabled())
|
||||
|
|
|
|||
|
|
@ -60,7 +60,7 @@ namespace ogfx
|
|||
f32 m_dragGrabOffset { 0 };
|
||||
Rectangle m_correctionOffset { 1, 1, 0, 0 };
|
||||
|
||||
Rectangle m_trackBorderRadii { 0, 0, 10, 0 };
|
||||
Rectangle m_trackBorderRadii { 0, 0, 0, 0 };
|
||||
f32 m_thumbBorderRadius { 16 };
|
||||
Color m_trackColor { 70, 70, 70 };
|
||||
Color m_thumbColor { 120, 120, 120 };
|
||||
|
|
@ -98,7 +98,7 @@ namespace ogfx
|
|||
f32 m_dragGrabOffset { 0 };
|
||||
Rectangle m_correctionOffset { 0, 0, 0, 0 };
|
||||
|
||||
Rectangle m_trackBorderRadii { 0, 0, 0, 10 };
|
||||
Rectangle m_trackBorderRadii { 0, 0, 0, 0 };
|
||||
f32 m_thumbBorderRadius { 16 };
|
||||
Color m_trackColor { 70, 70, 70 };
|
||||
Color m_thumbColor { 120, 120, 120 };
|
||||
|
|
@ -113,6 +113,7 @@ namespace ogfx
|
|||
virtual void onUpdate(void) override;
|
||||
void drawScrollbars(ogfx::BasicRenderer2D& gfx);
|
||||
void updateScrollbarsSize(void);
|
||||
void resetScroll(bool horizontal = true, bool vertical = true, bool propagate = true) override;
|
||||
virtual void onMouseScrolled(const Event& event) override;
|
||||
virtual void setScrollOffset(const Vec2& offset) override;
|
||||
virtual void addScrollOffset(const Vec2& offset) override;
|
||||
|
|
@ -137,6 +138,8 @@ namespace ogfx
|
|||
Vec2 m_scrollVelocity { 0.0f, 0.0f };
|
||||
f32 m_scrollSmoothFactor { 0.7f };
|
||||
f32 m_scrollSpeedMultiplier { 15.0f };
|
||||
bool m_hScrollbarAdded { false };
|
||||
bool m_vScrollbarAdded { false };
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -129,6 +129,7 @@ namespace ogfx
|
|||
inline const stdvec<String>& getThemeIDList(void) const { return m_themeIDList; }
|
||||
inline const ostd::Stylesheet::QualifierList& getThemeQualifierList(void) const { return m_qualifierList; }
|
||||
inline String getStylesheetCategoryName(void) const { return m_stylesheetCategoryName; }
|
||||
inline WidgetManager& getChildren(void) { return m_widgets; }
|
||||
OSTD_PARAM_GETSET(Color, TextColor, m_textColor);
|
||||
OSTD_PARAM_GETSET(Color, BackgroundColor, m_backgroundColor);
|
||||
OSTD_PARAM_GETSET(Color, BorderColor, m_borderColor);
|
||||
|
|
@ -274,6 +275,7 @@ namespace ogfx
|
|||
inline virtual void addScrollOffset(const Vec2& offset) { }
|
||||
inline virtual bool needsVScroll(void) const { return false; }
|
||||
inline virtual bool needsHScroll(void) const { return false; }
|
||||
inline virtual void resetScroll(bool horizontal = true, bool vertical = true, bool propagate = true) { }
|
||||
inline virtual f32 getVScrollbarSize(void) const { return 0; }
|
||||
inline virtual f32 getHScrollbarSize(void) const { return 0; }
|
||||
// =====================================================
|
||||
|
|
|
|||
|
|
@ -90,10 +90,18 @@ class Window : public ogfx::gui::Window
|
|||
m_panel2.setSize(600, 400);
|
||||
m_panel2.setTitle("Panel 2");
|
||||
|
||||
m_tabs.setSize(400, 400);
|
||||
m_tabs.addTab("Tab1");
|
||||
m_tabs.addTab("Tab2 Test");
|
||||
m_tabs.addTab("Long Tab Test");
|
||||
m_tabs.setSize(900, 700);
|
||||
auto& t1 = m_tabs.addTab("Tab1");
|
||||
auto& t2 = m_tabs.addTab("Tab2 Test");
|
||||
auto& t3 = m_tabs.addTab("Long Tab Test");
|
||||
for (i32 i = 3; i < 15; i++)
|
||||
m_tabs.addTab(String("Tab").add(i));
|
||||
|
||||
t2.addThemeOverride("@panel_tab.panel.backgroundColor", Colors::SkyBlue);
|
||||
t3.addThemeOverride("@panel_tab.panel.backgroundColor", Colors::Orange);
|
||||
|
||||
t1.addWidget(m_check1, { 30, 30 });
|
||||
t2.addWidget(m_panel2, { 500, 100 });
|
||||
|
||||
m_panel3.addWidget(m_label4);
|
||||
|
||||
|
|
@ -107,9 +115,9 @@ class Window : public ogfx::gui::Window
|
|||
m_panel2.addWidget(m_btn1, { 0, 300 });
|
||||
m_panel2.addWidget(m_img, { 20, 50 });
|
||||
|
||||
addWidget(m_check1, { 30, 30 });
|
||||
addWidget(m_panel2, { 500, 100 });
|
||||
addWidget(m_tabs, { 20, 120 });
|
||||
|
||||
|
||||
addWidget(m_tabs, { 0, 0 });
|
||||
|
||||
m_theme.loadFromFile("./DefaultTheme.oss", true, getDefaultStylesheetVariableList());
|
||||
setTheme(m_theme);
|
||||
|
|
@ -127,7 +135,7 @@ class Window : public ogfx::gui::Window
|
|||
|
||||
void onRedraw(ogfx::BasicRenderer2D& gfx) override
|
||||
{
|
||||
gfx.fillRect(m_tabs.getGlobalPureContentBounds(), { 0, 255, 0, 100 });
|
||||
// gfx.fillRect(m_tabs.getGlobalPureContentBounds(), { 0, 255, 0, 100 });
|
||||
}
|
||||
|
||||
void onFixedUpdate(void) override
|
||||
|
|
|
|||
Loading…
Reference in a new issue