From 43c338928a98f6a765e95011d3808c26cc6597ce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Nusser?= Date: Fri, 7 Apr 2017 00:17:17 +0200 Subject: Implement GridLayout --- plugingui/layout.cc | 115 +++++++++++++++++++++++++++++++++++++++++++++++++++ plugingui/layout.h | 60 +++++++++++++++++++++++---- plugingui/maintab.cc | 5 ++- plugingui/maintab.h | 2 +- 4 files changed, 172 insertions(+), 10 deletions(-) (limited to 'plugingui') diff --git a/plugingui/layout.cc b/plugingui/layout.cc index 7e3c6e8..551611c 100644 --- a/plugingui/layout.cc +++ b/plugingui/layout.cc @@ -233,4 +233,119 @@ void HBoxLayout::setVAlignment(VAlignment alignment) align = alignment; } +// +// GridLayout +// + +GridLayout::GridLayout(LayoutItem* parent, std::size_t number_of_columns, + std::size_t number_of_rows) + : BoxLayout(parent) + , number_of_columns(number_of_columns) + , number_of_rows(number_of_rows) +{ +} + +void GridLayout::removeItem(LayoutItem* item) +{ + Layout::removeItem(item); + + // manually remove from grid_ranges as remove_if doesn't work on an + // unordered_map + for(auto it = grid_ranges.begin(); it != grid_ranges.end(); ++it) + { + if(it->first == item) + { + it = grid_ranges.erase(it); + } + else + { + ++it; + } + } +} + +void GridLayout::layout() +{ + if(grid_ranges.empty()) + { + return; + } + + // Calculate cell sizes + auto cell_size = calculateCellSize(); + + for(auto const& pair : grid_ranges) + { + auto& item = *pair.first; + auto const& range = pair.second; + + moveAndResize(item, range, cell_size); + } +} + +void GridLayout::setPosition(LayoutItem* item, GridRange const& range) +{ + grid_ranges[item] = range; +} + +auto GridLayout::calculateCellSize() const -> CellSize +{ + auto empty_width = (number_of_columns - 1) * spacing; + auto available_width = parent->width(); + auto empty_height = (number_of_rows - 1) * spacing; + auto available_height = parent->height(); + + CellSize cell_size; + if(available_width > empty_width && available_height > empty_height) + { + cell_size.width = (available_width - empty_width) / number_of_columns; + cell_size.height = (available_height - empty_height) / number_of_rows; + } + else + { + cell_size.width = 0; + cell_size.height = 0; + } + + return cell_size; +} + +void GridLayout::moveAndResize( + LayoutItem& item, GridRange const& range, CellSize cell_size) const +{ + std::size_t x = range.column_begin * (cell_size.width + spacing); + std::size_t y = range.row_begin * (cell_size.height + spacing); + + std::size_t column_count = (range.column_end - range.column_begin); + std::size_t row_count = (range.row_end - range.row_begin); + std::size_t width = column_count * (cell_size.width + spacing) - spacing; + std::size_t height = row_count * (cell_size.height + spacing) - spacing; + + if(resizeChildren) + { + item.move(x, y); + + if(cell_size.width * cell_size.height != 0) + { + item.resize(width, height); + } + else + { + item.resize(0, 0); + } + } + else + { + if(item.width() <= width && item.height() <= height) + { + item.move(x + (width - item.width()) / 2, + y + (height - item.height()) / 2); + } + else + { + item.move(x, y); + } + } +} + } // GUI:: diff --git a/plugingui/layout.h b/plugingui/layout.h index 37a7d6d..763f616 100644 --- a/plugingui/layout.h +++ b/plugingui/layout.h @@ -28,6 +28,7 @@ #include #include +#include #include @@ -56,8 +57,7 @@ private: }; //! \brief Abtract Layout class. -class Layout - : public Listener +class Layout : public Listener { public: Layout(LayoutItem* parent); @@ -80,8 +80,7 @@ protected: }; //! \brief Abstract box layout -class BoxLayout - : public Layout +class BoxLayout : public Layout { public: BoxLayout(LayoutItem* parent); @@ -107,8 +106,7 @@ enum class HAlignment }; //! \brief A Layout that lays out its elements vertically. -class VBoxLayout - : public BoxLayout +class VBoxLayout : public BoxLayout { public: VBoxLayout(LayoutItem* parent); @@ -130,8 +128,7 @@ enum class VAlignment }; //! \brief A Layout that lays out its elements vertically. -class HBoxLayout - : public BoxLayout +class HBoxLayout : public BoxLayout { public: HBoxLayout(LayoutItem* parent); @@ -145,4 +142,51 @@ protected: VAlignment align; }; +//! \brief A Layout class which places the items in a regular grid. An item can +//! span multiple rows/columns. +class GridLayout : public BoxLayout +{ +public: + // The range is open, i.e. end is one past the last one. + struct GridRange + { + int column_begin; + int column_end; + int row_begin; + int row_end; + }; + + GridLayout(LayoutItem* parent, std::size_t number_of_columns, + std::size_t number_of_rows); + + virtual ~GridLayout() + { + } + + // From Layout: + virtual void removeItem(LayoutItem* item); + virtual void layout(); + + void setPosition(LayoutItem* item, GridRange const& range); + +protected: + std::size_t number_of_columns; + std::size_t number_of_rows; + + // Note: Yes, this is somewhat redundant to the LayoutItemList of the Layout + // class. However, this was the best idea I had such that I could still + // derive from Layout. If you find this ugly, feel free to fix it. + std::unordered_map grid_ranges; + +private: + struct CellSize { + std::size_t width; + std::size_t height; + }; + + CellSize calculateCellSize() const; + void moveAndResize( + LayoutItem& item, GridRange const& range, CellSize cell_size) const; +}; + } // GUI:: diff --git a/plugingui/maintab.cc b/plugingui/maintab.cc index f450bc0..498660e 100644 --- a/plugingui/maintab.cc +++ b/plugingui/maintab.cc @@ -33,12 +33,15 @@ MainTab::MainTab(Widget* parent) : Widget(parent) { layout.setSpacing(10); layout.setResizeChildren(true); - layout.setHAlignment(GUI::HAlignment::center); layout.addItem(&drumkit_frame); layout.addItem(&status_frame); layout.addItem(&humanizer_frame); layout.addItem(&diskstreaming_frame); + layout.setPosition(&drumkit_frame, GridLayout::GridRange{0, 1, 0, 4}); + layout.setPosition(&status_frame, GridLayout::GridRange{0, 1, 4, 7}); + layout.setPosition(&humanizer_frame, GridLayout::GridRange{1, 2, 0, 3}); + layout.setPosition(&diskstreaming_frame, GridLayout::GridRange{1, 2, 3, 5}); drumkit_frame.setTitle("Drumkit"); status_frame.setTitle("Status"); diff --git a/plugingui/maintab.h b/plugingui/maintab.h index 1ab30d7..ac39daf 100644 --- a/plugingui/maintab.h +++ b/plugingui/maintab.h @@ -42,7 +42,7 @@ public: MainTab(Widget* parent); private: - VBoxLayout layout{this}; + GridLayout layout{this, 2, 9}; FrameWidget drumkit_frame{this, false}; FrameWidget status_frame{this, false}; -- cgit v1.2.3