mirror of
https://github.com/ZDoom/gzdoom.git
synced 2024-11-10 06:42:08 +00:00
Add a tab widget
This commit is contained in:
parent
c7778b9332
commit
762ce6f14c
7 changed files with 438 additions and 3 deletions
|
@ -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/.+")
|
||||
|
|
|
@ -86,7 +86,7 @@ public:
|
|||
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);
|
||||
|
||||
|
|
116
libraries/ZWidget/include/zwidget/widgets/tabwidget/tabwidget.h
Normal file
116
libraries/ZWidget/include/zwidget/widgets/tabwidget/tabwidget.h
Normal file
|
@ -0,0 +1,116 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "../../core/widget.h"
|
||||
#include <functional>
|
||||
#include <string>
|
||||
|
||||
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<Image>& icon, const std::string& label);
|
||||
|
||||
int GetCurrentIndex() const;
|
||||
Widget* GetCurrentWidget() const;
|
||||
|
||||
int GetPageIndex(Widget* pageWidget) const;
|
||||
|
||||
void SetCurrentIndex(int pageIndex);
|
||||
void SetCurrentWidget(Widget* pageWidget);
|
||||
|
||||
std::function<void()> OnCurrentChanged;
|
||||
|
||||
protected:
|
||||
void OnPaintFrame(Canvas* canvas) override;
|
||||
void OnGeometryChanged() override;
|
||||
|
||||
private:
|
||||
void OnBarCurrentChanged();
|
||||
|
||||
TabBar* Bar = nullptr;
|
||||
TabWidgetStack* PageStack = nullptr;
|
||||
std::vector<Widget*> Pages;
|
||||
};
|
||||
|
||||
class TabBar : public Widget
|
||||
{
|
||||
public:
|
||||
TabBar(Widget* parent);
|
||||
|
||||
int AddTab(const std::string& label);
|
||||
int AddTab(const std::shared_ptr<Image>& icon, const std::string& label);
|
||||
|
||||
int GetCurrentIndex() const;
|
||||
void SetCurrentIndex(int pageIndex);
|
||||
|
||||
double GetPreferredHeight() const { return 30.0; }
|
||||
|
||||
std::function<void()> OnCurrentChanged;
|
||||
|
||||
protected:
|
||||
void OnPaintFrame(Canvas* canvas) override;
|
||||
void OnGeometryChanged() override;
|
||||
|
||||
private:
|
||||
void OnTabClicked(TabBarTab* tab);
|
||||
int GetTabIndex(TabBarTab* tab);
|
||||
|
||||
int CurrentIndex = -1;
|
||||
std::vector<TabBarTab*> Tabs;
|
||||
};
|
||||
|
||||
class TabBarTab : public Widget
|
||||
{
|
||||
public:
|
||||
TabBarTab(Widget* parent);
|
||||
|
||||
void SetText(const std::string& text);
|
||||
void SetIcon(const std::shared_ptr<Image>& icon);
|
||||
void SetCurrent(bool value);
|
||||
|
||||
double GetPreferredWidth() const;
|
||||
|
||||
std::function<void()> OnClick;
|
||||
|
||||
protected:
|
||||
void OnPaintFrame(Canvas* canvas) override;
|
||||
void OnGeometryChanged() 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;
|
||||
|
||||
private:
|
||||
bool IsCurrent = false;
|
||||
|
||||
ImageBox* Icon = nullptr;
|
||||
TextLabel* Label = nullptr;
|
||||
bool mouseDown = false;
|
||||
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;
|
||||
};
|
|
@ -21,6 +21,7 @@ public:
|
|||
void SetTextAlignment(TextLabelAlignment alignment);
|
||||
TextLabelAlignment GetTextAlignment() const;
|
||||
|
||||
double GetPreferredWidth() const;
|
||||
double GetPreferredHeight() const;
|
||||
|
||||
protected:
|
||||
|
|
|
@ -427,9 +427,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();
|
||||
|
|
308
libraries/ZWidget/src/widgets/tabwidget/tabwidget.cpp
Normal file
308
libraries/ZWidget/src/widgets/tabwidget/tabwidget.cpp
Normal file
|
@ -0,0 +1,308 @@
|
|||
|
||||
#include "widgets/tabwidget/tabwidget.h"
|
||||
#include "widgets/textlabel/textlabel.h"
|
||||
#include "widgets/imagebox/imagebox.h"
|
||||
#include <algorithm>
|
||||
|
||||
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<Image>& 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;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
}
|
||||
|
||||
int TabBar::AddTab(const std::string& label)
|
||||
{
|
||||
return AddTab(nullptr, label);
|
||||
}
|
||||
|
||||
int TabBar::AddTab(const std::shared_ptr<Image>& icon, const std::string& label)
|
||||
{
|
||||
TabBarTab* tab = new TabBarTab(this);
|
||||
tab->SetIcon(icon);
|
||||
tab->SetText(label);
|
||||
int pageIndex = Tabs.size();
|
||||
Tabs.push_back(tab);
|
||||
if (CurrentIndex == -1)
|
||||
SetCurrentIndex(pageIndex);
|
||||
OnGeometryChanged();
|
||||
return pageIndex;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
}
|
||||
|
||||
void TabBar::OnGeometryChanged()
|
||||
{
|
||||
double w = GetWidth();
|
||||
double h = GetHeight();
|
||||
double x = 0.0;
|
||||
for (TabBarTab* tab : Tabs)
|
||||
{
|
||||
double tabWidth = tab->GetPreferredWidth();
|
||||
tab->SetFrameGeometry(Rect::xywh(x, 0.0, tabWidth, h));
|
||||
x += tabWidth;
|
||||
}
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
TabBarTab::TabBarTab(Widget* parent) : Widget(parent)
|
||||
{
|
||||
}
|
||||
|
||||
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>& 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)
|
||||
{
|
||||
}
|
||||
|
||||
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, 0.0, std::max(w - x, 0.0), h));
|
||||
}
|
||||
}
|
||||
|
||||
void TabBarTab::OnMouseMove(const Point& pos)
|
||||
{
|
||||
if (!hot)
|
||||
{
|
||||
hot = true;
|
||||
Update();
|
||||
}
|
||||
}
|
||||
|
||||
void TabBarTab::OnMouseDown(const Point& pos, int key)
|
||||
{
|
||||
mouseDown = true;
|
||||
Update();
|
||||
}
|
||||
|
||||
void TabBarTab::OnMouseUp(const Point& pos, int key)
|
||||
{
|
||||
if (mouseDown)
|
||||
{
|
||||
mouseDown = false;
|
||||
Repaint();
|
||||
if (OnClick)
|
||||
OnClick();
|
||||
}
|
||||
}
|
||||
|
||||
void TabBarTab::OnMouseLeave()
|
||||
{
|
||||
hot = false;
|
||||
mouseDown = false;
|
||||
Update();
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
TabWidgetStack::TabWidgetStack(Widget* parent) : Widget(parent)
|
||||
{
|
||||
}
|
||||
|
||||
void TabWidgetStack::SetCurrentWidget(Widget* widget)
|
||||
{
|
||||
if (widget != CurrentWidget)
|
||||
{
|
||||
if (CurrentWidget)
|
||||
CurrentWidget->SetVisible(false);
|
||||
CurrentWidget = widget;
|
||||
if (CurrentWidget)
|
||||
CurrentWidget->SetVisible(true);
|
||||
}
|
||||
}
|
||||
|
||||
void TabWidgetStack::OnPaintFrame(Canvas* canvas)
|
||||
{
|
||||
}
|
||||
|
||||
void TabWidgetStack::OnGeometryChanged()
|
||||
{
|
||||
if (CurrentWidget)
|
||||
CurrentWidget->SetFrameGeometry(Rect::xywh(0.0, 0.0, GetWidth(), GetHeight()));
|
||||
}
|
|
@ -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;
|
||||
|
|
Loading…
Reference in a new issue