diff --git a/example/example.cpp b/example/example.cpp index f366b82..5efbea1 100644 --- a/example/example.cpp +++ b/example/example.cpp @@ -225,6 +225,9 @@ LauncherWindowTab2::LauncherWindowTab2(Widget parent): Widget(nullptr) GamesList->AddItem("The Doom"); GamesList->AddItem("Doom 2"); + GamesList->ShowHeaders(true); + GamesList->SetHeaderText(0, "Game"); + GeneralLabel->SetText("General"); ExtrasLabel->SetText("Extra Graphics"); FullscreenCheckbox->SetText("Fullscreen"); diff --git a/example/stylesheet.h b/example/stylesheet.h index cc43531..035d7d1 100644 --- a/example/stylesheet.h +++ b/example/stylesheet.h @@ -129,6 +129,8 @@ listview { border-right-color: var(--border); border-bottom-color: var(--border); selection-color: var(--bgHover); + header-background-color: var(--bgLight); + header-text-color: var(--fgLight); } dropdown { diff --git a/include/zwidget/widgets/listview/listview.h b/include/zwidget/widgets/listview/listview.h index caa0c24..0ea0e52 100644 --- a/include/zwidget/widgets/listview/listview.h +++ b/include/zwidget/widgets/listview/listview.h @@ -14,6 +14,8 @@ class ListView : public Widget ListView(Widget* parent = nullptr); void SetColumnWidths(const std::vector& widths); + void SetHeaderText(int index, const std::string& headerText); + void ShowHeaders(bool value) { m_ShowHeaders = value; } void AddItem(const std::string& text, int index = -1, int column = 0); void UpdateItem(const std::string& text, int index, int column = 0); void RemoveItem(int index = -1); @@ -45,9 +47,13 @@ class ListView : public Widget Scrollbar* scrollbar = nullptr; + std::vector m_HeaderTexts = {""}; std::vector> items; std::vector columnwidths; int selectedItem = 0; friend Dropdown; + +private: + bool m_ShowHeaders = false; }; diff --git a/src/core/theme.cpp b/src/core/theme.cpp index af312b0..8bec571 100644 --- a/src/core/theme.cpp +++ b/src/core/theme.cpp @@ -194,20 +194,20 @@ WidgetTheme* WidgetTheme::GetTheme() ///////////////////////////////////////////////////////////////////////////// -SimpleTheme::SimpleTheme(const ThemeColors& theme) +SimpleTheme::SimpleTheme(const ThemeColors& colors) { - auto bgMain = theme.bgMain; // background - auto fgMain = theme.fgMain; // - auto bgLight = theme.bgLight; // headers / inputs - auto fgLight = theme.fgLight; // - auto bgAction = theme.bgAction; // interactive elements - auto fgAction = theme.fgAction; // - auto bgHover = theme.bgHover; // hover / highlight - auto fgHover = theme.fgHover; // - auto bgActive = theme.bgActive; // click - auto fgActive = theme.fgActive; // - auto border = theme.border; // around elements - auto divider = theme.divider; // between elements + auto bgMain = colors.bgMain; // background + auto fgMain = colors.fgMain; // + auto bgLight = colors.bgLight; // headers / inputs + auto fgLight = colors.fgLight; // + auto bgAction = colors.bgAction; // interactive elements + auto fgAction = colors.fgAction; // + auto bgHover = colors.bgHover; // hover / highlight + auto fgHover = colors.fgHover; // + auto bgActive = colors.bgActive; // click + auto fgActive = colors.fgActive; // + auto border = colors.border; // around elements + auto divider = colors.divider; // between elements auto none = Colorf::transparent(); @@ -311,6 +311,8 @@ SimpleTheme::SimpleTheme(const ThemeColors& theme) listview->SetColor("border-right-color", border); listview->SetColor("border-bottom-color", border); listview->SetColor("selection-color", bgHover); + listview->SetColor("header-background-color", bgLight); + listview->SetColor("header-text-color", fgLight); dropdown->SetDouble("noncontent-left", 5.0); dropdown->SetDouble("noncontent-top", 5.0); diff --git a/src/widgets/listview/listview.cpp b/src/widgets/listview/listview.cpp index bb74f58..93784b6 100644 --- a/src/widgets/listview/listview.cpp +++ b/src/widgets/listview/listview.cpp @@ -24,11 +24,13 @@ void ListView::SetColumnWidths(const std::vector& widths) { updated = true; column.push_back(""); + m_HeaderTexts.push_back(""); } while (column.size() > newWidth) { updated = true; column.pop_back(); + m_HeaderTexts.pop_back(); } } @@ -36,6 +38,14 @@ void ListView::SetColumnWidths(const std::vector& widths) Update(); } +void ListView::SetHeaderText(const int index, const std::string& headerText) +{ + if (index < 0 || index >= m_HeaderTexts.size()) + return; + + m_HeaderTexts[index] = headerText; +} + void ListView::AddItem(const std::string& text, int index, int column) { if (column < 0 || column >= (int)columnwidths.size()) @@ -158,6 +168,27 @@ void ListView::OnPaint(Canvas* canvas) // Make sure the text doesn't enter the scrollbar's area. canvas->pushClip({ 0.0, 0.0, w, GetHeight() }); + if (m_ShowHeaders) + { + // Draw the header rectangles and header texts + // This is drawn last so that the elements don't appear on top of the header + Colorf headerColor = GetStyleColor("header-background-color"); + Colorf headerTextColor = GetStyleColor("header-text-color"); + double cx = x; + + for (size_t idx = 0 ; idx < columnwidths.size() ; idx++) + { + canvas->fillRect(Rect::xywh(x, 0, columnwidths[idx], h), headerColor); + canvas->drawText(GetFont(), Point(cx, h / 2), m_HeaderTexts[idx], headerTextColor); + cx += columnwidths[idx]; + } + + y += h; + + // So that the elements don't overlap with the header area + canvas->pushClip({ 0.0, h, w, GetHeight() }); + } + int index = 0; for (const std::vector& item : items) { @@ -179,6 +210,12 @@ void ListView::OnPaint(Canvas* canvas) index++; } + if (m_ShowHeaders) + { + // Delete the header clip + canvas->popClip(); + } + canvas->popClip(); } @@ -188,7 +225,13 @@ bool ListView::OnMouseDown(const Point& pos, InputKey key) if (key == InputKey::LeftMouse) { - int index = (int)((pos.y - 5.0 + scrollbar->GetPosition()) / getItemHeight()); + auto y = pos.y; + + // If the headers are shown, push the y position a bit. + if (m_ShowHeaders) + y -= getItemHeight(); + + int index = (int)((y - 5.0 + scrollbar->GetPosition()) / getItemHeight()); if (index >= 0 && (size_t)index < items.size()) { ScrollToItem(index);