From fac2262d233836d2d114503c8eb524be0387189c Mon Sep 17 00:00:00 2001 From: Magnus Norddahl Date: Fri, 12 Jan 2024 06:35:14 +0100 Subject: [PATCH] Add tab widget and event propagation --- CMakeLists.txt | 4 + include/zwidget/core/widget.h | 16 +- .../widgets/checkboxlabel/checkboxlabel.h | 4 +- include/zwidget/widgets/lineedit/lineedit.h | 6 +- include/zwidget/widgets/listview/listview.h | 6 +- .../zwidget/widgets/pushbutton/pushbutton.h | 4 +- include/zwidget/widgets/scrollbar/scrollbar.h | 4 +- include/zwidget/widgets/tabwidget/tabwidget.h | 124 ++++++ include/zwidget/widgets/textedit/textedit.h | 6 +- include/zwidget/widgets/textlabel/textlabel.h | 1 + src/core/widget.cpp | 82 +++- src/widgets/checkboxlabel/checkboxlabel.cpp | 6 +- src/widgets/lineedit/lineedit.cpp | 9 +- src/widgets/listview/listview.cpp | 9 +- src/widgets/pushbutton/pushbutton.cpp | 6 +- src/widgets/scrollbar/scrollbar.cpp | 6 +- src/widgets/tabwidget/tabwidget.cpp | 358 ++++++++++++++++++ src/widgets/textedit/textedit.cpp | 9 +- src/widgets/textlabel/textlabel.cpp | 6 + 19 files changed, 620 insertions(+), 46 deletions(-) create mode 100644 include/zwidget/widgets/tabwidget/tabwidget.h create mode 100644 src/widgets/tabwidget/tabwidget.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 42fea2e..dd836cd 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -30,6 +30,7 @@ set(ZWIDGET_SOURCES src/widgets/pushbutton/pushbutton.cpp src/widgets/checkboxlabel/checkboxlabel.cpp src/widgets/listview/listview.cpp + src/widgets/tabwidget/tabwidget.cpp src/window/window.cpp ) @@ -58,6 +59,7 @@ set(ZWIDGET_INCLUDES include/zwidget/widgets/pushbutton/pushbutton.h include/zwidget/widgets/checkboxlabel/checkboxlabel.h include/zwidget/widgets/listview/listview.h + include/zwidget/widgets/tabwidget/tabwidget.h include/zwidget/window/window.h ) @@ -91,6 +93,7 @@ source_group("src\\widgets\\textlabel" REGULAR_EXPRESSION "${CMAKE_CURRENT_SOURC source_group("src\\widgets\\pushbutton" REGULAR_EXPRESSION "${CMAKE_CURRENT_SOURCE_DIR}/src/widgets/pushbutton/.+") source_group("src\\widgets\\checkboxlabel" REGULAR_EXPRESSION "${CMAKE_CURRENT_SOURCE_DIR}/src/widgets/checkboxlabel/.+") source_group("src\\widgets\\listview" REGULAR_EXPRESSION "${CMAKE_CURRENT_SOURCE_DIR}/src/widgets/listview/.+") +source_group("src\\widgets\\tabwidget" REGULAR_EXPRESSION "${CMAKE_CURRENT_SOURCE_DIR}/src/widgets/tabwidget/.+") source_group("src\\window" REGULAR_EXPRESSION "${CMAKE_CURRENT_SOURCE_DIR}/src/window/.+") source_group("include" REGULAR_EXPRESSION "${CMAKE_CURRENT_SOURCE_DIR}/include/zwidget/.+") source_group("include\\core" REGULAR_EXPRESSION "${CMAKE_CURRENT_SOURCE_DIR}/include/zwidget/core/.+") @@ -107,6 +110,7 @@ source_group("include\\widgets\\textlabel" REGULAR_EXPRESSION "${CMAKE_CURRENT_S source_group("include\\widgets\\pushbutton" REGULAR_EXPRESSION "${CMAKE_CURRENT_SOURCE_DIR}/include/zwidget/widgets/pushbutton/.+") source_group("include\\widgets\\checkboxlabel" REGULAR_EXPRESSION "${CMAKE_CURRENT_SOURCE_DIR}/include/zwidget/widgets/checkboxlabel/.+") source_group("include\\widgets\\listview" REGULAR_EXPRESSION "${CMAKE_CURRENT_SOURCE_DIR}/include/zwidget/widgets/listview/.+") +source_group("include\\widgets\\tabwidget" REGULAR_EXPRESSION "${CMAKE_CURRENT_SOURCE_DIR}/include/zwidget/widgets/tabwidget/.+") source_group("include\\window" REGULAR_EXPRESSION "${CMAKE_CURRENT_SOURCE_DIR}/include/zwidget/window/.+") source_group("include\\window\\win32" REGULAR_EXPRESSION "${CMAKE_CURRENT_SOURCE_DIR}/include/zwidget/window/win32/.+") source_group("include\\window\\sdl2" REGULAR_EXPRESSION "${CMAKE_CURRENT_SOURCE_DIR}/include/zwidget/window/sdl2/.+") diff --git a/include/zwidget/core/widget.h b/include/zwidget/core/widget.h index 69862fd..34faa14 100644 --- a/include/zwidget/core/widget.h +++ b/include/zwidget/core/widget.h @@ -39,6 +39,10 @@ class Widget : DisplayWindowHost // Widget noncontent area void SetNoncontentSizes(double left, double top, double right, double bottom); + double GetNoncontentLeft() const { return Noncontent.Left; } + double GetNoncontentTop() const { return Noncontent.Top; } + double GetNoncontentRight() const { return Noncontent.Right; } + double GetNoncontentBottom() const { return Noncontent.Bottom; } // Widget frame box Rect GetFrameGeometry() const; @@ -68,6 +72,7 @@ class Widget : DisplayWindowHost bool HasFocus(); bool IsEnabled(); bool IsVisible(); + bool IsHidden(); void SetFocus(); void SetEnabled(bool value); @@ -86,7 +91,7 @@ class Widget : DisplayWindowHost void SetClipboardText(const std::string& text); Widget* Window(); - Canvas* GetCanvas(); + Canvas* GetCanvas() const; Widget* ChildAt(double x, double y) { return ChildAt(Point(x, y)); } Widget* ChildAt(const Point& pos); @@ -109,11 +114,11 @@ class Widget : DisplayWindowHost protected: virtual void OnPaintFrame(Canvas* canvas) { } virtual void OnPaint(Canvas* canvas) { } + virtual bool OnMouseDown(const Point& pos, int key) { return false; } + virtual bool OnMouseDoubleclick(const Point& pos, int key) { return false; } + virtual bool OnMouseUp(const Point& pos, int key) { return false; } + virtual bool OnMouseWheel(const Point& pos, EInputKey key) { return false; } virtual void OnMouseMove(const Point& pos) { } - virtual void OnMouseDown(const Point& pos, int key) { } - virtual void OnMouseDoubleclick(const Point& pos, int key) { } - virtual void OnMouseUp(const Point& pos, int key) { } - virtual void OnMouseWheel(const Point& pos, EInputKey key) { } virtual void OnMouseLeave() { } virtual void OnRawMouseMove(int dx, int dy) { } virtual void OnKeyChar(std::string chars) { } @@ -176,6 +181,7 @@ class Widget : DisplayWindowHost Widget* FocusWidget = nullptr; Widget* CaptureWidget = nullptr; Widget* HoverWidget = nullptr; + bool HiddenFlag = false; StandardCursor CurrentCursor = StandardCursor::arrow; diff --git a/include/zwidget/widgets/checkboxlabel/checkboxlabel.h b/include/zwidget/widgets/checkboxlabel/checkboxlabel.h index 0bd8abc..57025fe 100644 --- a/include/zwidget/widgets/checkboxlabel/checkboxlabel.h +++ b/include/zwidget/widgets/checkboxlabel/checkboxlabel.h @@ -21,8 +21,8 @@ class CheckboxLabel : public Widget protected: void OnPaint(Canvas* canvas) override; - void OnMouseDown(const Point& pos, int key) override; - void OnMouseUp(const Point& pos, int key) override; + bool OnMouseDown(const Point& pos, int key) override; + bool OnMouseUp(const Point& pos, int key) override; void OnMouseLeave() override; void OnKeyUp(EInputKey key) override; diff --git a/include/zwidget/widgets/lineedit/lineedit.h b/include/zwidget/widgets/lineedit/lineedit.h index c34ab11..526d9ee 100644 --- a/include/zwidget/widgets/lineedit/lineedit.h +++ b/include/zwidget/widgets/lineedit/lineedit.h @@ -72,9 +72,9 @@ class LineEdit : public Widget void OnPaintFrame(Canvas* canvas) override; void OnPaint(Canvas* canvas) override; void OnMouseMove(const Point& pos) override; - void OnMouseDown(const Point& pos, int key) override; - void OnMouseDoubleclick(const Point& pos, int key) override; - void OnMouseUp(const Point& pos, int key) override; + bool OnMouseDown(const Point& pos, int key) override; + bool OnMouseDoubleclick(const Point& pos, int key) override; + bool OnMouseUp(const Point& pos, int key) override; void OnKeyChar(std::string chars) override; void OnKeyDown(EInputKey key) override; void OnKeyUp(EInputKey key) override; diff --git a/include/zwidget/widgets/listview/listview.h b/include/zwidget/widgets/listview/listview.h index 879bda1..2b150ab 100644 --- a/include/zwidget/widgets/listview/listview.h +++ b/include/zwidget/widgets/listview/listview.h @@ -25,9 +25,9 @@ class ListView : public Widget protected: void OnPaint(Canvas* canvas) override; void OnPaintFrame(Canvas* canvas) override; - void OnMouseDown(const Point& pos, int key) override; - void OnMouseDoubleclick(const Point& pos, int key) override; - void OnMouseWheel(const Point& pos, EInputKey key) override; + bool OnMouseDown(const Point& pos, int key) override; + bool OnMouseDoubleclick(const Point& pos, int key) override; + bool OnMouseWheel(const Point& pos, EInputKey key) override; void OnKeyDown(EInputKey key) override; void OnGeometryChanged() override; void OnScrollbarScroll(); diff --git a/include/zwidget/widgets/pushbutton/pushbutton.h b/include/zwidget/widgets/pushbutton/pushbutton.h index 80d827d..b9b6c96 100644 --- a/include/zwidget/widgets/pushbutton/pushbutton.h +++ b/include/zwidget/widgets/pushbutton/pushbutton.h @@ -21,9 +21,9 @@ class PushButton : public Widget protected: void OnPaintFrame(Canvas* canvas) override; void OnPaint(Canvas* canvas) override; + bool OnMouseDown(const Point& pos, int key) override; + bool OnMouseUp(const Point& pos, int key) override; void OnMouseMove(const Point& pos) override; - void OnMouseDown(const Point& pos, int key) override; - void OnMouseUp(const Point& pos, int key) override; void OnMouseLeave() override; void OnKeyDown(EInputKey key) override; void OnKeyUp(EInputKey key) override; diff --git a/include/zwidget/widgets/scrollbar/scrollbar.h b/include/zwidget/widgets/scrollbar/scrollbar.h index 38afda3..5ec95c8 100644 --- a/include/zwidget/widgets/scrollbar/scrollbar.h +++ b/include/zwidget/widgets/scrollbar/scrollbar.h @@ -47,9 +47,9 @@ class Scrollbar : public Widget std::function FuncScrollEnd; protected: + bool OnMouseDown(const Point& pos, int key) override; + bool OnMouseUp(const Point& pos, int key) override; void OnMouseMove(const Point& pos) override; - void OnMouseDown(const Point& pos, int key) override; - void OnMouseUp(const Point& pos, int key) override; void OnMouseLeave() override; void OnPaint(Canvas* canvas) override; void OnEnableChanged() override; diff --git a/include/zwidget/widgets/tabwidget/tabwidget.h b/include/zwidget/widgets/tabwidget/tabwidget.h new file mode 100644 index 0000000..bd3fc20 --- /dev/null +++ b/include/zwidget/widgets/tabwidget/tabwidget.h @@ -0,0 +1,124 @@ + +#pragma once + +#include "../../core/widget.h" +#include +#include +#include + +class TabBar; +class TabBarTab; +class TabWidgetStack; +class TextLabel; +class ImageBox; +class Image; + +class TabWidget : public Widget +{ +public: + TabWidget(Widget* parent); + + int AddTab(Widget* page, const std::string& label); + int AddTab(Widget* page, const std::shared_ptr& icon, const std::string& label); + + void SetTabText(int index, const std::string& text); + void SetTabText(Widget* page, const std::string& text); + void SetTabIcon(int index, const std::shared_ptr& icon); + void SetTabIcon(Widget* page, const std::shared_ptr& icon); + + int GetCurrentIndex() const; + Widget* GetCurrentWidget() const; + + int GetPageIndex(Widget* pageWidget) const; + + void SetCurrentIndex(int pageIndex); + void SetCurrentWidget(Widget* pageWidget); + + std::function OnCurrentChanged; + +protected: + void OnPaintFrame(Canvas* canvas) override; + void OnGeometryChanged() override; + +private: + void OnBarCurrentChanged(); + + TabBar* Bar = nullptr; + TabWidgetStack* PageStack = nullptr; + std::vector Pages; +}; + +class TabBar : public Widget +{ +public: + TabBar(Widget* parent); + + int AddTab(const std::string& label); + int AddTab(const std::shared_ptr& icon, const std::string& label); + + void SetTabText(int index, const std::string& text); + void SetTabIcon(int index, const std::shared_ptr& icon); + + int GetCurrentIndex() const; + void SetCurrentIndex(int pageIndex); + + double GetPreferredHeight() const { return 30.0; } + + std::function OnCurrentChanged; + +protected: + void OnPaintFrame(Canvas* canvas) override; + void OnGeometryChanged() override; + +private: + void OnTabClicked(TabBarTab* tab); + int GetTabIndex(TabBarTab* tab); + + int CurrentIndex = -1; + std::vector Tabs; +}; + +class TabBarTab : public Widget +{ +public: + TabBarTab(Widget* parent); + + void SetText(const std::string& text); + void SetIcon(const std::shared_ptr& icon); + void SetCurrent(bool value); + + double GetPreferredWidth() const; + + std::function OnClick; + +protected: + void OnPaintFrame(Canvas* canvas) override; + void OnGeometryChanged() override; + bool OnMouseDown(const Point& pos, int key) override; + bool OnMouseUp(const Point& pos, int key) override; + void OnMouseMove(const Point& pos) override; + void OnMouseLeave() override; + +private: + bool IsCurrent = false; + + ImageBox* Icon = nullptr; + TextLabel* Label = nullptr; + bool hot = false; +}; + +class TabWidgetStack : public Widget +{ +public: + TabWidgetStack(Widget* parent); + + void SetCurrentWidget(Widget* widget); + Widget* GetCurrentWidget() const { return CurrentWidget; } + +protected: + void OnPaintFrame(Canvas* canvas) override; + void OnGeometryChanged() override; + +private: + Widget* CurrentWidget = nullptr; +}; diff --git a/include/zwidget/widgets/textedit/textedit.h b/include/zwidget/widgets/textedit/textedit.h index e2c6c76..ed80eec 100644 --- a/include/zwidget/widgets/textedit/textedit.h +++ b/include/zwidget/widgets/textedit/textedit.h @@ -56,9 +56,9 @@ class TextEdit : public Widget void OnPaintFrame(Canvas* canvas) override; void OnPaint(Canvas* canvas) override; void OnMouseMove(const Point& pos) override; - void OnMouseDown(const Point& pos, int key) override; - void OnMouseDoubleclick(const Point& pos, int key) override; - void OnMouseUp(const Point& pos, int key) override; + bool OnMouseDown(const Point& pos, int key) override; + bool OnMouseDoubleclick(const Point& pos, int key) override; + bool OnMouseUp(const Point& pos, int key) override; void OnKeyChar(std::string chars) override; void OnKeyDown(EInputKey key) override; void OnKeyUp(EInputKey key) override; diff --git a/include/zwidget/widgets/textlabel/textlabel.h b/include/zwidget/widgets/textlabel/textlabel.h index 32f250c..45515df 100644 --- a/include/zwidget/widgets/textlabel/textlabel.h +++ b/include/zwidget/widgets/textlabel/textlabel.h @@ -21,6 +21,7 @@ class TextLabel : public Widget void SetTextAlignment(TextLabelAlignment alignment); TextLabelAlignment GetTextAlignment() const; + double GetPreferredWidth() const; double GetPreferredHeight() const; protected: diff --git a/src/core/widget.cpp b/src/core/widget.cpp index 9c6dc63..7ddc1ca 100644 --- a/src/core/widget.cpp +++ b/src/core/widget.cpp @@ -172,6 +172,11 @@ void Widget::Show() { DispWindow->Show(); } + else if (HiddenFlag) + { + HiddenFlag = false; + Update(); + } } void Widget::ShowFullscreen() @@ -213,6 +218,11 @@ void Widget::Hide() if (DispWindow) DispWindow->Hide(); } + else if (!HiddenFlag) + { + HiddenFlag = true; + Update(); + } } void Widget::ActivateWindow() @@ -299,7 +309,7 @@ void Widget::Paint(Canvas* canvas) OnPaint(canvas); for (Widget* w = FirstChild(); w != nullptr; w = w->NextSibling()) { - if (w->Type == WidgetType::Child) + if (w->Type == WidgetType::Child && !w->HiddenFlag) w->Paint(canvas); } canvas->setOrigin(oldOrigin); @@ -323,9 +333,21 @@ bool Widget::IsEnabled() return true; } +bool Widget::IsHidden() +{ + return !IsVisible(); +} + bool Widget::IsVisible() { - return true; + if (Type != WidgetType::Child) + { + return true; // DispWindow->IsVisible(); + } + else + { + return !HiddenFlag; + } } void Widget::SetFocus() @@ -427,9 +449,9 @@ Widget* Widget::Window() return nullptr; } -Canvas* Widget::GetCanvas() +Canvas* Widget::GetCanvas() const { - for (Widget* w = this; w != nullptr; w = w->Parent()) + for (const Widget* w = this; w != nullptr; w = w->Parent()) { if (w->DispCanvas) return w->DispCanvas.get(); @@ -441,7 +463,7 @@ Widget* Widget::ChildAt(const Point& pos) { for (Widget* cur = LastChild(); cur != nullptr; cur = cur->PrevSibling()) { - if (cur->FrameGeometry.contains(pos)) + if (!cur->HiddenFlag && cur->FrameGeometry.contains(pos)) { Widget* cur2 = cur->ChildAt(pos - cur->ContentGeometry.topLeft()); return cur2 ? cur2 : cur; @@ -523,12 +545,26 @@ void Widget::OnWindowMouseMove(const Point& pos) if (HoverWidget != widget) { if (HoverWidget) - HoverWidget->OnMouseLeave(); + { + for (Widget* w = HoverWidget; w != widget && w != this; w = w->Parent()) + { + Widget* p = w->Parent(); + if (!w->FrameGeometry.contains(p->MapFrom(this, pos))) + { + w->OnMouseLeave(); + } + } + } HoverWidget = widget; } DispWindow->SetCursor(widget->CurrentCursor); - widget->OnMouseMove(widget->MapFrom(this, pos)); + + do + { + widget->OnMouseMove(widget->MapFrom(this, pos)); + widget = widget->Parent(); + } while (widget != this); } } @@ -543,7 +579,13 @@ void Widget::OnWindowMouseDown(const Point& pos, EInputKey key) Widget* widget = ChildAt(pos); if (!widget) widget = this; - widget->OnMouseDown(widget->MapFrom(this, pos), key); + while (widget) + { + bool stopPropagation = widget->OnMouseDown(widget->MapFrom(this, pos), key); + if (stopPropagation || widget == this) + break; + widget = widget->Parent(); + } } } @@ -558,7 +600,13 @@ void Widget::OnWindowMouseDoubleclick(const Point& pos, EInputKey key) Widget* widget = ChildAt(pos); if (!widget) widget = this; - widget->OnMouseDoubleclick(widget->MapFrom(this, pos), key); + while (widget) + { + bool stopPropagation = widget->OnMouseDoubleclick(widget->MapFrom(this, pos), key); + if (stopPropagation || widget == this) + break; + widget = widget->Parent(); + } } } @@ -573,7 +621,13 @@ void Widget::OnWindowMouseUp(const Point& pos, EInputKey key) Widget* widget = ChildAt(pos); if (!widget) widget = this; - widget->OnMouseUp(widget->MapFrom(this, pos), key); + while (widget) + { + bool stopPropagation = widget->OnMouseUp(widget->MapFrom(this, pos), key); + if (stopPropagation || widget == this) + break; + widget = widget->Parent(); + } } } @@ -588,7 +642,13 @@ void Widget::OnWindowMouseWheel(const Point& pos, EInputKey key) Widget* widget = ChildAt(pos); if (!widget) widget = this; - widget->OnMouseWheel(widget->MapFrom(this, pos), key); + while (widget) + { + bool stopPropagation = widget->OnMouseWheel(widget->MapFrom(this, pos), key); + if (stopPropagation || widget == this) + break; + widget = widget->Parent(); + } } } diff --git a/src/widgets/checkboxlabel/checkboxlabel.cpp b/src/widgets/checkboxlabel/checkboxlabel.cpp index d8f3026..7736101 100644 --- a/src/widgets/checkboxlabel/checkboxlabel.cpp +++ b/src/widgets/checkboxlabel/checkboxlabel.cpp @@ -55,19 +55,21 @@ void CheckboxLabel::OnPaint(Canvas* canvas) canvas->drawText(Point(14.0, GetHeight() - 5.0), Colorf::fromRgba8(255, 255, 255), text); } -void CheckboxLabel::OnMouseDown(const Point& pos, int key) +bool CheckboxLabel::OnMouseDown(const Point& pos, int key) { mouseDownActive = true; SetFocus(); + return true; } -void CheckboxLabel::OnMouseUp(const Point& pos, int key) +bool CheckboxLabel::OnMouseUp(const Point& pos, int key) { if (mouseDownActive) { Toggle(); } mouseDownActive = false; + return true; } void CheckboxLabel::OnMouseLeave() diff --git a/src/widgets/lineedit/lineedit.cpp b/src/widgets/lineedit/lineedit.cpp index 8a7af4e..34391fd 100644 --- a/src/widgets/lineedit/lineedit.cpp +++ b/src/widgets/lineedit/lineedit.cpp @@ -301,7 +301,7 @@ void LineEdit::OnMouseMove(const Point& pos) } } -void LineEdit::OnMouseDown(const Point& pos, int key) +bool LineEdit::OnMouseDown(const Point& pos, int key) { if (key == IK_LeftMouse) { @@ -318,13 +318,15 @@ void LineEdit::OnMouseDown(const Point& pos, int key) } Update(); } + return true; } -void LineEdit::OnMouseDoubleclick(const Point& pos, int key) +bool LineEdit::OnMouseDoubleclick(const Point& pos, int key) { + return true; } -void LineEdit::OnMouseUp(const Point& pos, int key) +bool LineEdit::OnMouseUp(const Point& pos, int key) { if (mouse_selecting && key == IK_LeftMouse) { @@ -346,6 +348,7 @@ void LineEdit::OnMouseUp(const Point& pos, int key) Update(); } } + return true; } void LineEdit::OnKeyChar(std::string chars) diff --git a/src/widgets/listview/listview.cpp b/src/widgets/listview/listview.cpp index 680b41d..717f958 100644 --- a/src/widgets/listview/listview.cpp +++ b/src/widgets/listview/listview.cpp @@ -96,7 +96,7 @@ void ListView::OnPaintFrame(Canvas* canvas) canvas->fillRect(Rect::xywh(w - 1.0, 0.0, 1.0, h - 0.0), bordercolor); } -void ListView::OnMouseDown(const Point& pos, int key) +bool ListView::OnMouseDown(const Point& pos, int key) { SetFocus(); @@ -109,17 +109,19 @@ void ListView::OnMouseDown(const Point& pos, int key) ScrollToItem(selectedItem); } } + return true; } -void ListView::OnMouseDoubleclick(const Point& pos, int key) +bool ListView::OnMouseDoubleclick(const Point& pos, int key) { if (key == IK_LeftMouse) { Activate(); } + return true; } -void ListView::OnMouseWheel(const Point& pos, EInputKey key) +bool ListView::OnMouseWheel(const Point& pos, EInputKey key) { if (key == IK_MouseWheelUp) { @@ -129,6 +131,7 @@ void ListView::OnMouseWheel(const Point& pos, EInputKey key) { scrollbar->SetPosition(std::min(scrollbar->GetPosition() + 20.0, scrollbar->GetMax())); } + return true; } void ListView::OnKeyDown(EInputKey key) diff --git a/src/widgets/pushbutton/pushbutton.cpp b/src/widgets/pushbutton/pushbutton.cpp index 2e2e348..d838fe4 100644 --- a/src/widgets/pushbutton/pushbutton.cpp +++ b/src/widgets/pushbutton/pushbutton.cpp @@ -57,14 +57,15 @@ void PushButton::OnMouseMove(const Point& pos) } } -void PushButton::OnMouseDown(const Point& pos, int key) +bool PushButton::OnMouseDown(const Point& pos, int key) { SetFocus(); buttonDown = true; Update(); + return true; } -void PushButton::OnMouseUp(const Point& pos, int key) +bool PushButton::OnMouseUp(const Point& pos, int key) { if (buttonDown) { @@ -73,6 +74,7 @@ void PushButton::OnMouseUp(const Point& pos, int key) Repaint(); Click(); } + return true; } void PushButton::OnMouseLeave() diff --git a/src/widgets/scrollbar/scrollbar.cpp b/src/widgets/scrollbar/scrollbar.cpp index 1462981..489a663 100644 --- a/src/widgets/scrollbar/scrollbar.cpp +++ b/src/widgets/scrollbar/scrollbar.cpp @@ -169,7 +169,7 @@ void Scrollbar::OnMouseMove(const Point& pos) Update(); } -void Scrollbar::OnMouseDown(const Point& pos, int key) +bool Scrollbar::OnMouseDown(const Point& pos, int key) { mouse_drag_start_pos = pos; @@ -254,9 +254,10 @@ void Scrollbar::OnMouseDown(const Point& pos, int key) Update(); CaptureMouse(); + return true; } -void Scrollbar::OnMouseUp(const Point& pos, int key) +bool Scrollbar::OnMouseUp(const Point& pos, int key) { if (mouse_down_mode == mouse_down_thumb_drag) { @@ -269,6 +270,7 @@ void Scrollbar::OnMouseUp(const Point& pos, int key) Update(); ReleaseMouseCapture(); + return true; } void Scrollbar::OnMouseLeave() diff --git a/src/widgets/tabwidget/tabwidget.cpp b/src/widgets/tabwidget/tabwidget.cpp new file mode 100644 index 0000000..cbac877 --- /dev/null +++ b/src/widgets/tabwidget/tabwidget.cpp @@ -0,0 +1,358 @@ + +#include "widgets/tabwidget/tabwidget.h" +#include "widgets/textlabel/textlabel.h" +#include "widgets/imagebox/imagebox.h" +#include + +TabWidget::TabWidget(Widget* parent) : Widget(parent) +{ + Bar = new TabBar(this); + PageStack = new TabWidgetStack(this); + + Bar->OnCurrentChanged = [=]() { OnBarCurrentChanged(); }; +} + +int TabWidget::AddTab(Widget* page, const std::string& label) +{ + return AddTab(page, nullptr, label); +} + +int TabWidget::AddTab(Widget* page, const std::shared_ptr& icon, const std::string& label) +{ + int pageIndex = Bar->AddTab(label); + page->SetParent(PageStack); + page->SetVisible(false); + Pages.push_back(page); + if (Pages.size() == 1) + { + PageStack->SetCurrentWidget(page); + } + return pageIndex; +} + +void TabWidget::SetTabText(int index, const std::string& text) +{ + Bar->SetTabText(index, text); +} + +void TabWidget::SetTabText(Widget* page, const std::string& text) +{ + int index = GetPageIndex(page); + if (index != -1) + SetTabText(index, text); +} + +void TabWidget::SetTabIcon(int index, const std::shared_ptr& icon) +{ + Bar->SetTabIcon(index, icon); +} + +void TabWidget::SetTabIcon(Widget* page, const std::shared_ptr& icon) +{ + int index = GetPageIndex(page); + if (index != -1) + SetTabIcon(index, icon); +} + +int TabWidget::GetCurrentIndex() const +{ + return Bar->GetCurrentIndex(); +} + +Widget* TabWidget::GetCurrentWidget() const +{ + return Pages[Bar->GetCurrentIndex()]; +} + +void TabWidget::SetCurrentIndex(int pageIndex) +{ + if (Bar->GetCurrentIndex() != pageIndex) + { + Bar->SetCurrentIndex(pageIndex); + PageStack->SetCurrentWidget(Pages[pageIndex]); + } +} + +void TabWidget::SetCurrentWidget(Widget* pageWidget) +{ + int pageIndex = GetPageIndex(pageWidget); + if (pageIndex != -1) + SetCurrentIndex(pageIndex); +} + +int TabWidget::GetPageIndex(Widget* pageWidget) const +{ + for (size_t i = 0; i < Pages.size(); i++) + { + if (Pages[i] == pageWidget) + return i; + } + return -1; +} + +void TabWidget::OnBarCurrentChanged() +{ + int pageIndex = Bar->GetCurrentIndex(); + PageStack->SetCurrentWidget(Pages[pageIndex]); + if (OnCurrentChanged) + OnCurrentChanged(); +} + +void TabWidget::OnPaintFrame(Canvas* canvas) +{ +} + +void TabWidget::OnGeometryChanged() +{ + double w = GetWidth(); + double h = GetHeight(); + double barHeight = Bar->GetPreferredHeight(); + Bar->SetFrameGeometry(Rect::xywh(0.0, 0.0, w, barHeight)); + PageStack->SetFrameGeometry(Rect::xywh(0.0, barHeight, w, std::max(h - barHeight, 0.0))); +} + +///////////////////////////////////////////////////////////////////////////// + +TabBar::TabBar(Widget* parent) : Widget(parent) +{ + SetNoncontentSizes(20.0, 0.0, 20.0, 0.0); +} + +int TabBar::AddTab(const std::string& label) +{ + return AddTab(nullptr, label); +} + +int TabBar::AddTab(const std::shared_ptr& icon, const std::string& label) +{ + TabBarTab* tab = new TabBarTab(this); + tab->SetIcon(icon); + tab->SetText(label); + tab->OnClick = [=]() { OnTabClicked(tab); }; + int pageIndex = Tabs.size(); + Tabs.push_back(tab); + if (CurrentIndex == -1) + SetCurrentIndex(pageIndex); + OnGeometryChanged(); + return pageIndex; +} + +void TabBar::SetTabText(int index, const std::string& text) +{ + Tabs[index]->SetText(text); + OnGeometryChanged(); +} + +void TabBar::SetTabIcon(int index, const std::shared_ptr& icon) +{ + Tabs[index]->SetIcon(icon); + OnGeometryChanged(); +} + +int TabBar::GetCurrentIndex() const +{ + return CurrentIndex; +} + +void TabBar::SetCurrentIndex(int pageIndex) +{ + if (CurrentIndex != pageIndex) + { + if (CurrentIndex != -1) + Tabs[CurrentIndex]->SetCurrent(false); + CurrentIndex = pageIndex; + if (CurrentIndex != -1) + Tabs[CurrentIndex]->SetCurrent(true); + } +} + +void TabBar::OnTabClicked(TabBarTab* tab) +{ + int pageIndex = GetTabIndex(tab); + if (CurrentIndex != pageIndex) + { + SetCurrentIndex(pageIndex); + if (OnCurrentChanged) + OnCurrentChanged(); + } +} + +int TabBar::GetTabIndex(TabBarTab* tab) +{ + for (size_t i = 0; i < Tabs.size(); i++) + { + if (Tabs[i] == tab) + return i; + } + return -1; +} + +void TabBar::OnPaintFrame(Canvas* canvas) +{ + double w = GetFrameGeometry().width; + double h = GetFrameGeometry().height; + canvas->fillRect(Rect::xywh(0.0, 0.0, w, h), Colorf::fromRgba8(38, 38, 38)); +} + +void TabBar::OnGeometryChanged() +{ + double w = GetWidth(); + double h = GetHeight(); + double x = 0.0; + for (TabBarTab* tab : Tabs) + { + double tabWidth = tab->GetNoncontentLeft() + tab->GetPreferredWidth() + tab->GetNoncontentRight(); + tab->SetFrameGeometry(Rect::xywh(x, 0.0, tabWidth, h)); + x += tabWidth; + } +} + +///////////////////////////////////////////////////////////////////////////// + +TabBarTab::TabBarTab(Widget* parent) : Widget(parent) +{ + SetNoncontentSizes(15.0, 0.0, 15.0, 0.0); +} + +void TabBarTab::SetText(const std::string& text) +{ + if (!text.empty()) + { + if (!Label) + { + Label = new TextLabel(this); + OnGeometryChanged(); + } + Label->SetText(text); + } + else + { + delete Label; + Label = nullptr; + OnGeometryChanged(); + } +} + +void TabBarTab::SetIcon(const std::shared_ptr& image) +{ + if (image) + { + if (!Icon) + { + Icon = new ImageBox(this); + OnGeometryChanged(); + } + Icon->SetImage(image); + } + else + { + delete Icon; + Icon = nullptr; + OnGeometryChanged(); + } +} + +void TabBarTab::SetCurrent(bool value) +{ + if (IsCurrent != value) + { + IsCurrent = value; + Update(); + } +} + +double TabBarTab::GetPreferredWidth() const +{ + double x = Icon ? 32.0 + 5.0 : 0.0; + if (Label) x += Label->GetPreferredWidth(); + return x; +} + +void TabBarTab::OnPaintFrame(Canvas* canvas) +{ + double w = GetFrameGeometry().width; + double h = GetFrameGeometry().height; + if (IsCurrent) + { + canvas->fillRect(Rect::xywh(0.0, 0.0, w, h), Colorf::fromRgba8(51, 51, 51)); + } + else if (hot) + { + canvas->fillRect(Rect::xywh(0.0, 0.0, w, h), Colorf::fromRgba8(45, 45, 45)); + } +} + +void TabBarTab::OnGeometryChanged() +{ + double x = 0.0; + double w = GetWidth(); + double h = GetHeight(); + if (Icon) + { + Icon->SetFrameGeometry(Rect::xywh(x, (h - 32.0) * 0.5, 32.0, 32.0)); + x = 32.0 + 5.0; + } + if (Label) + { + Label->SetFrameGeometry(Rect::xywh(x, (h - Label->GetPreferredHeight()) * 0.5, std::max(w - x, 0.0), Label->GetPreferredHeight())); + } +} + +void TabBarTab::OnMouseMove(const Point& pos) +{ + if (!hot) + { + hot = true; + Update(); + } +} + +bool TabBarTab::OnMouseDown(const Point& pos, int key) +{ + if (OnClick) + OnClick(); + return true; +} + +bool TabBarTab::OnMouseUp(const Point& pos, int key) +{ + return true; +} + +void TabBarTab::OnMouseLeave() +{ + hot = false; + Update(); +} + +///////////////////////////////////////////////////////////////////////////// + +TabWidgetStack::TabWidgetStack(Widget* parent) : Widget(parent) +{ + SetNoncontentSizes(20.0, 5.0, 20.0, 5.0); +} + +void TabWidgetStack::SetCurrentWidget(Widget* widget) +{ + if (widget != CurrentWidget) + { + if (CurrentWidget) + CurrentWidget->SetVisible(false); + CurrentWidget = widget; + if (CurrentWidget) + { + CurrentWidget->SetVisible(true); + OnGeometryChanged(); + } + } +} + +void TabWidgetStack::OnPaintFrame(Canvas* canvas) +{ +} + +void TabWidgetStack::OnGeometryChanged() +{ + if (CurrentWidget) + CurrentWidget->SetFrameGeometry(Rect::xywh(0.0, 0.0, GetWidth(), GetHeight())); +} diff --git a/src/widgets/textedit/textedit.cpp b/src/widgets/textedit/textedit.cpp index 9ddb5fb..dca840a 100644 --- a/src/widgets/textedit/textedit.cpp +++ b/src/widgets/textedit/textedit.cpp @@ -286,7 +286,7 @@ void TextEdit::OnMouseMove(const Point& pos) } } -void TextEdit::OnMouseDown(const Point& pos, int key) +bool TextEdit::OnMouseDown(const Point& pos, int key) { if (key == IK_LeftMouse) { @@ -298,13 +298,15 @@ void TextEdit::OnMouseDown(const Point& pos, int key) Update(); } + return true; } -void TextEdit::OnMouseDoubleclick(const Point& pos, int key) +bool TextEdit::OnMouseDoubleclick(const Point& pos, int key) { + return true; } -void TextEdit::OnMouseUp(const Point& pos, int key) +bool TextEdit::OnMouseUp(const Point& pos, int key) { if (mouse_selecting && key == IK_LeftMouse) { @@ -326,6 +328,7 @@ void TextEdit::OnMouseUp(const Point& pos, int key) Update(); } } + return true; } void TextEdit::OnKeyChar(std::string chars) diff --git a/src/widgets/textlabel/textlabel.cpp b/src/widgets/textlabel/textlabel.cpp index 3c034dd..55518f0 100644 --- a/src/widgets/textlabel/textlabel.cpp +++ b/src/widgets/textlabel/textlabel.cpp @@ -33,6 +33,12 @@ TextLabelAlignment TextLabel::GetTextAlignment() const return textAlignment; } +double TextLabel::GetPreferredWidth() const +{ + Canvas* canvas = GetCanvas(); + return canvas->measureText(text).width; +} + double TextLabel::GetPreferredHeight() const { return 20.0;