summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndré Nusser <andre.nusser@googlemail.com>2017-04-07 00:17:17 +0200
committerAndré Nusser <andre.nusser@googlemail.com>2017-04-07 21:48:01 +0200
commit43c338928a98f6a765e95011d3808c26cc6597ce (patch)
tree5a51677d6463f6cc8fa322ec2cb7eab2c553530b
parent42d7b7245566fd6e598f7031638370808abc13af (diff)
Implement GridLayout
-rw-r--r--plugingui/layout.cc115
-rw-r--r--plugingui/layout.h60
-rw-r--r--plugingui/maintab.cc5
-rw-r--r--plugingui/maintab.h2
4 files changed, 172 insertions, 10 deletions
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 <cstdlib>
#include <list>
+#include <unordered_map>
#include <notifier.h>
@@ -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<LayoutItem*, GridRange> 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};