--- a/src/intro_gui.cpp Sun Apr 15 14:17:40 2007 +0000
+++ b/src/intro_gui.cpp Sun Apr 15 14:20:35 2007 +0000
@@ -167,6 +167,8 @@
CCountedPtr<gui::Panel> m_panel2;
CCountedPtr<gui::Panel> m_panel3;
CCountedPtr<gui::Panel> m_panel4;
+ CCountedPtr<gui::Table> m_table1;
+ CCountedPtr<gui::Table> m_table2;
gui::WidgetPtr m_label1;
gui::WidgetPtr m_button1;
@@ -178,7 +180,7 @@
WindowT()
: BaseWindow(WC_TEST1, STR_015B_OPENTTD, COLOUR_BROWN, gui::FF_NO_RESIZE_BOX)
- , m_num_dyn_buttons(5)
+ , m_num_dyn_buttons(2)
{
}
@@ -207,6 +209,32 @@
AddWidget(m_panel1, gui::Panel::BOTTOM);
+
+
+ m_table2 = new gui::Table(this, gui::FF_NO_FRAME | gui::FF_IGNORE_PARENT_FRAME | gui::FF_SAME_SIZE, 0, COLOUR_TRANSPARENT);
+
+ m_button_add = new gui::TextButton(m_table2, STR_NULL, /*gui::FF_MIN_SIZE |*/ gui::FF_ALIGN_HCENTER | gui::FF_ALIGN_VCENTER, STR_0305_QUIT_OPENTTD, COLOUR_YELLOW);
+ m_button_add->m_text = "Add";
+ m_button_add->AddReflectHandlerT(&WindowT::ButtonAdd_OnClick);
+ m_table2->AddWidget(m_button_add, 0, 0);
+
+ m_button_remove = new gui::TextButton(m_table2, STR_NULL, /*gui::FF_MIN_SIZE |*/ gui::FF_ALIGN_HCENTER | gui::FF_ALIGN_VCENTER, STR_0305_QUIT_OPENTTD, COLOUR_YELLOW);
+ m_button_remove->m_text = "Del";
+ m_button_remove->AddReflectHandlerT(&WindowT::ButtonRemove_OnClick);
+ m_table2->AddWidget(m_button_remove, 1, 0);
+
+ m_button1 = new gui::TextButton(m_table2, STR_0304_QUIT, /*gui::FF_MIN_SIZE |*/ gui::FF_ALIGN_HCENTER | gui::FF_ALIGN_VCENTER, STR_0305_QUIT_OPENTTD, COLOUR_YELLOW);
+ m_button1->AddReflectHandlerT(&WindowT::Button1_OnClick);
+ m_table2->AddWidget(m_button1, 2, 0);
+
+ AddWidget(m_table2, gui::Panel::BOTTOM);
+
+
+
+
+
+
+
m_panel2 = new gui::Panel(this, gui::FF_NONE, 0, COLOUR_GREY);
for (int i = 0; i < m_num_dyn_buttons; i++) {
CCountedPtr<gui::TextButton> bu = new gui::TextButton(m_panel2, STR_000F_PASSENGERS + i, gui::FF_MIN_SIZE | gui::FF_ALIGN_HCENTER | gui::FF_ALIGN_VCENTER, STR_00D0_NOTHING + i, COLOUR_PARENT);
@@ -230,6 +258,59 @@
}
AddWidget(m_panel4, gui::Panel::RIGHT);
+ //m_table1 = new gui::Table(this, gui::FF_NONE, 0, COLOUR_GREY);
+ //for (int16 i = 1; i <= 9; i++) {
+ // CCountedPtr<gui::TextButton> bu = new gui::TextButton(m_table1, STR_NULL, gui::FF_MIN_SIZE | gui::FF_ALIGN_LEFT | gui::FF_ALIGN_TOP, STR_00D0_NOTHING + i, COLOUR_PARENT);
+ // char num_str[16];
+ // sprintf(num_str, "%d", i);
+ // bu->m_text = num_str;
+ // int16 x_pos = (i - 1) % 3;
+ // int16 y_pos = 2 - (i - 1) / 3;
+ // m_table1->AddWidget(bu, x_pos, y_pos);
+ //}
+ static const char *but_text[] = {
+ "C", "/", "*", "-",
+ "7", "8", "9", "+",
+ "4", "5", "6",
+ "1", "2", "3", "=",
+ "0", "."
+ };
+ static const int16 but_x_pos[] = {
+ 0, 1, 2, 3,
+ 0, 1, 2, 3,
+ 0, 1, 2,
+ 0, 1, 2, 3,
+ 0, 2
+ };
+ static const int16 but_y_pos[] = {
+ 0, 0, 0, 0,
+ 1, 1, 1, 1,
+ 2, 2, 2,
+ 3, 3, 3, 3,
+ 4, 4
+ };
+ static const int16 but_x_span[] = {
+ 1, 1, 1, 1,
+ 1, 1, 1, 1,
+ 1, 1, 1,
+ 1, 1, 1, 1,
+ 2, 1
+ };
+ static const int16 but_y_span[] = {
+ 1, 1, 1, 1,
+ 1, 1, 1, 2,
+ 1, 1, 1,
+ 1, 1, 1, 2,
+ 1, 1
+ };
+ m_table1 = new gui::Table(this, gui::FF_NONE | gui::FF_SAME_SIZE, 0, COLOUR_GREY);
+ for (int i = 0; i < (int)lengthof(but_text); i++) {
+ CCountedPtr<gui::TextButton> bu = new gui::TextButton(m_table1, STR_NULL, /*gui::FF_MIN_SIZE |*/ gui::FF_ALIGN_LEFT | gui::FF_ALIGN_TOP, STR_00D0_NOTHING + i, COLOUR_PARENT);
+ bu->m_text = but_text[i];
+ m_table1->AddWidget(bu, but_x_pos[i], but_y_pos[i], but_x_span[i], but_y_span[i]);
+ }
+ AddWidget(m_table1, gui::Panel::CENTER);
+
///* add controls */
//m_label1 = new gui::Label(this, 22, gui::FF_NONE, Rect16(104, 155, 231, 166), STR_0305_QUIT_OPENTTD, STR_0305_QUIT_OPENTTD, COLOUR_BROWN);
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/widget/widget_table.cpp Sun Apr 15 14:20:35 2007 +0000
@@ -0,0 +1,650 @@
+/* $Id: widget_panel.cpp 9484 2007-03-26 21:00:16Z KUDr $ */
+
+#include "../stdafx.h"
+#include <stdarg.h>
+#include "../openttd.h"
+#include "../debug.h"
+#include "../functions.h"
+#include "../map.h"
+#include "../player.h"
+#include "../window.h"
+#include "../gfx.h"
+#include "../viewport.h"
+#include "../console.h"
+#include "../variables.h"
+#include "../table/sprites.h"
+#include "../genworld.h"
+#include "../helpers.hpp"
+#include "../misc/blob.hpp"
+#include "window_events.hpp"
+#include "widget_types.h"
+
+namespace gui {
+
+struct TableSizeData;
+struct DoLayoutData;
+
+struct TableSlot;
+typedef CCountedPtr<TableSlot> TableSlotPtr;
+
+/**
+ * Table Slot class. Each table child widget is assigned to the slot. Slot describes
+ * which cells are occupied by widget, what is the real slot position and size, etc.
+ */
+struct TableSlot : CompositeWidget::Slot {
+ typedef CompositeWidget::Slot super;
+
+ Rect16 m_placement; ///< Slot row/col index and span
+ Rect16 m_rc_slot; ///< Bounding rectangle of the widget slot
+ bool m_edge_left : 1; ///< widget is on left edge
+ bool m_edge_top : 1; ///< widget is on top edge
+ bool m_edge_right : 1; ///< widget is on right edge
+ bool m_edge_bottom : 1; ///< widget is on bottom edge
+
+ TableSlot(Widget *wi, const Rect16 &placement)
+ : super(wi)
+ , m_placement(placement)
+ , m_edge_left(false)
+ , m_edge_top(false)
+ , m_edge_right(false)
+ , m_edge_bottom(false)
+ {}
+
+ /*virtual*/ ~TableSlot() {};
+};
+
+/**
+ * Tells if RowOrColPosT and RowOrColPosArrayT hold row or column sizes.
+ */
+enum RowOrCol {
+ COL,
+ ROW,
+};
+
+/**
+ * Row/column size info. Used to calculate cell layout on the Table widget
+ * (as item of ColPosArray or RowPosArray).
+ */
+template <RowOrCol Trow_or_col> struct RowOrColPosT {
+ int16 m_pos; ///< x/y position of the cell inside Table widget
+
+ RowOrColPosT()
+ : m_pos(0)
+ {}
+};
+
+typedef RowOrColPosT<COL> ColPos;
+typedef RowOrColPosT<ROW> RowPos;
+
+/**
+ * One dimensional array of row/column info. Used to calculate cell layout on the Table widget
+ * (as TableSizeData::m_rows/m_cols).
+ */
+template <RowOrCol Trow_or_col> struct RowOrColPosArrayT {
+ typedef RowOrColPosT<Trow_or_col> RowOrColPos;
+ typedef CBlobT<RowOrColPos> Array;
+
+ Array m_array; ///< zero based array of ColPos/RowPos
+ int16 m_min; ///< index base (for [] operator)
+
+ RowOrColPosArrayT()
+ : m_array()
+ , m_min(0)
+ {}
+
+ void Create(const Rect16 &area);
+
+ RowOrColPos& operator[] (int16 pos);
+ RowOrColPos& operator[] (Point16 pos);
+};
+
+typedef RowOrColPosArrayT<COL> ColPosArray;
+typedef RowOrColPosArrayT<ROW> RowPosArray;
+
+/**
+ * Allocate and initialize ColPos array to contain cell position data indexed from area.Left() to area.Right()+1.
+ */
+template <>
+void ColPosArray::Create(const Rect16 &area)
+{
+ m_min = area.Left();
+ m_array.Free();
+ /* Allocate one item more, then rows/cols to see whole table size */
+ m_array.GrowSizeC(area.Width() + 1);
+}
+
+/**
+ * Allocate and initialize RowPos array to contain cell position data indexed from area.Left() to area.Right()+1.
+ */
+template <>
+void RowPosArray::Create(const Rect16 &area)
+{
+ m_min = area.Top();
+ m_array.Free();
+ /* Allocate one item more, then rows/cols to see whole table size */
+ m_array.GrowSizeC(area.Height() + 1);
+}
+
+/**
+ * RowPos or ColPos indexing operator.
+ */
+template <RowOrCol Trow_or_col>
+RowOrColPosT<Trow_or_col>& RowOrColPosArrayT<Trow_or_col>::operator[] (int16 pos)
+{
+ return *m_array.Data(pos - m_min);
+}
+
+/**
+ * RowPos or ColPos indexing operator (specialization for column).
+ */
+template <>
+ColPos& ColPosArray::operator[] (Point16 pos)
+{
+ return *m_array.Data(pos.x - m_min);
+}
+
+/**
+ * RowPos or ColPos indexing operator (specialization for row).
+ */
+template <>
+RowPos& RowPosArray::operator[] (Point16 pos)
+{
+ return *m_array.Data(pos.y - m_min);
+}
+
+/**
+ * Two-dimensional array of table slots. Used as m_matrix member of TableSizeData.
+ */
+struct SlotMatrix {
+ typedef CBlobT<TableSlotPtr> Array;
+
+ Rect16 m_placement_area;
+ Array m_slots;
+
+ /**
+ * Create 2-dim array of slots so it can be indexed by col/row placement.
+ */
+ void Create(const Rect16 &area)
+ {
+ m_placement_area = area;
+ m_slots.Free();
+ m_slots.GrowSizeC(m_placement_area.Height() * m_placement_area.Width());
+ }
+
+ /**
+ * Get slot by its col/row indices.
+ */
+ TableSlotPtr* operator[] (Point16 pos)
+ {
+ assert(m_placement_area.PtInRect(pos));
+ pos -= m_placement_area.TopLeft();
+ int idx = ((int)pos.y) * m_placement_area.Width() + pos.x;
+ TableSlotPtr *ret = (idx < m_slots.Size()) ? m_slots.Data(idx) : NULL;
+ return ret;
+ }
+};
+
+/**
+ * Table cell size calculator. Used by Table::QuerySizes() and Table::DoLayout() routines.
+ * Smart pointer to this class is stored in the Table widget (Table::m_size_data).
+ * Its life-time is between begin of Table::QuerySizes() and end of Table::DoLayout().
+ */
+struct TableSizeData : SimpleCountedObject {
+ typedef TableSlot Slot;
+ typedef TableSlotPtr SlotPtr;
+
+ Table *m_table; ///< table widget for which we are calculating cell pos/sizes
+ Rect16 m_placement_area; ///< cell index rectangle used by slots (min col/row to max col/row)
+ Size16 m_int_border; ///< internal table frame border (reserved space at the table edges)
+ SlotMatrix m_matrix; ///< 2-dim array of slots
+ ColPosArray m_cols; ///< 1-dim array of column position/width info
+ RowPosArray m_rows; ///< 1-dim array of row position/height info
+
+ TableSizeData(Table *p)
+ : m_table(p)
+ , m_int_border(p->CalcInternalBorder())
+ {}
+
+ void UpdatePlacementArea();
+ void UpdatePlacementArea_EnumProc(TableSlot &slot, int slot_idx);
+
+ void UpdateEdges();
+ void UpdateEdges_EnumProc(TableSlot &slot, int slot_idx);
+
+ void FillMatrix();
+ void FillMatrix_EnumProc(TableSlot &slot, int slot_idx);
+
+ void UpdateColMinSizes_VarSizes();
+ void UpdateColMinSizes_SameSizes();
+
+ void UpdateRowMinSizes_VarSizes();
+ void UpdateRowMinSizes_SameSizes();
+
+ void DoLayout();
+ void DoLayout_EnumProc(TableSlot &slot, int slot_idx);
+
+ void EnlargeWidth_VarSizes(int16 add_size);
+ void EnlargeWidth_SameSizes(int16 add_size);
+ void EnlargeHeight_VarSizes(int16 add_size);
+ void EnlargeHeight_SameSizes(int16 add_size);
+};
+
+/**
+ * Enumerate all table slots and make union rectangle of the area occupied by table slots.
+ * For example if lowest column index is 3 and highest is 5 then table will have 3 columns.
+ * The same can happen to rows.
+ */
+void TableSizeData::UpdatePlacementArea()
+{
+ m_table->EnumSlotsT<TableSizeData, &TableSizeData::UpdatePlacementArea_EnumProc>(this);
+}
+
+/**
+ * Extend m_placement_area rectangle by placement rectangle of given slot. For first slot use just
+ * rectangle assignment (copy), for subsequent slots make rectangle union.
+ */
+void TableSizeData::UpdatePlacementArea_EnumProc(TableSlot &slot, int slot_idx)
+{
+ if (slot_idx > 0) {
+ m_placement_area.DoUnion(slot.m_placement);
+ } else {
+ m_placement_area = slot.m_placement;
+ }
+}
+
+/**
+ * Scan for all table slots and fill their TableSlot::m_edge_xxx flags.
+ */
+void TableSizeData::UpdateEdges()
+{
+ m_table->EnumSlotsT<TableSizeData, &TableSizeData::UpdateEdges_EnumProc>(this);
+}
+
+/**
+ * Fill one slot TableSlot::m_edge_xxx flags - callback of Table::EnumSlotsT.
+ */
+void TableSizeData::UpdateEdges_EnumProc(TableSlot &slot, int slot_idx)
+{
+ slot.m_edge_left = slot.m_placement.Left() == m_placement_area.Left();
+ slot.m_edge_top = slot.m_placement.Top() == m_placement_area.Top();
+ slot.m_edge_right = slot.m_placement.Right() == m_placement_area.Right();
+ slot.m_edge_bottom = slot.m_placement.Bottom() == m_placement_area.Bottom();
+}
+
+/**
+ * Fill table slot matrix with TableSlot.
+ */
+void TableSizeData::FillMatrix()
+{
+ m_matrix.Create(m_placement_area);
+ m_table->EnumSlotsT<TableSizeData, &TableSizeData::FillMatrix_EnumProc>(this);
+ m_cols.Create(m_placement_area);
+ m_rows.Create(m_placement_area);
+}
+
+/**
+ * Fill one matrix slot - callback of Table::EnumSlotsT method called from
+ * TableSizeData::FillMatrix.
+ */
+void TableSizeData::FillMatrix_EnumProc(TableSlot &slot, int slot_idx)
+{
+ TableSlotPtr *slot_ptr = m_matrix[slot.m_placement.TopLeft()];
+ assert(slot_ptr != NULL);
+ *slot_ptr = &slot;
+}
+
+/**
+ * Scan table slots by columns (left/right) and move column's horizontal positions down to
+ * satisfy min widths of widgets inside. Update TableSizeData::ColPosArray::m_pos.
+ */
+void TableSizeData::UpdateColMinSizes_VarSizes()
+{
+ /* Position the first cell. */
+ ColPos &pos_begin_first = m_cols[m_placement_area.Left()];
+ pos_begin_first.m_pos = m_int_border.x;
+
+ for (int16 y = m_placement_area.Top(); y <= m_placement_area.Bottom(); y++) {
+ for (int16 x = m_placement_area.Left(); x <= m_placement_area.Right(); x++) {
+ /* Locate slot at this position (if any) */
+ TableSlot *slot = *m_matrix[Point16(x, y)];
+ if (slot == NULL) continue;
+
+ /* Find appropriate begin/end position data for the slot. */
+ ColPos &pos_begin = m_cols[slot->m_placement.Left()];
+ ColPos &pos_end = m_cols[slot->m_placement.Right() + 1];
+
+ /* Where this slot will begin. */
+ int16 min_begin_pos = pos_begin.m_pos;
+ int16 min_slot_width = slot->m_wi->m_min_size.x;
+
+ /* Slot can overlap the left edge. Move it to the left by border width. */
+ bool ignore_parent_frame = (slot->m_wi->m_feature_flags & FF_IGNORE_PARENT_FRAME) != 0;
+ if (ignore_parent_frame && slot->m_edge_left) min_begin_pos -= m_int_border.x;
+
+ /* Set minimal slot begin position. */
+ for (int16 sx = slot->m_placement.Left() + 1; sx <= slot->m_placement.Right(); sx++) {
+ ColPos &pos = m_cols[sx];
+ if (pos.m_pos < min_begin_pos) pos.m_pos = min_begin_pos;
+ }
+
+ /* Set slot end position. */
+ int16 min_end_pos = min_begin_pos + min_slot_width;
+
+ /* Slot can overlap the right edge. Move it to the left by border width. */
+ if (ignore_parent_frame && slot->m_edge_right) min_end_pos -= m_int_border.x;
+
+ /* Table cell can't end before it begins. */
+ if (min_end_pos < min_begin_pos) min_end_pos = min_begin_pos;
+
+ /* Adjust the slot end position to ensure that the slot will fit there. */
+ if (pos_end.m_pos < min_end_pos) pos_end.m_pos = min_end_pos;
+
+ /* Set minimal positions of remaining table cells. */
+ for (int16 sx = slot->m_placement.Right() + 2; sx <= m_placement_area.Right(); sx++) {
+ ColPos &pos = m_cols[sx];
+ if (pos.m_pos < min_end_pos) pos.m_pos = min_end_pos;
+ }
+ }
+ }
+}
+
+/**
+ * Scan table slots by columns (left/right) and move column's horizontal positions down to
+ * satisfy min widths of widgets inside. Update TableSizeData::ColPosArray::m_pos.
+ */
+void TableSizeData::UpdateColMinSizes_SameSizes()
+{
+ int16 accu_min_cell_width = 0;
+
+ for (int16 y = m_placement_area.Top(); y <= m_placement_area.Bottom(); y++) {
+ for (int16 x = m_placement_area.Left(); x <= m_placement_area.Right(); x++) {
+ /* Locate slot at this position (if any) */
+ TableSlot *slot = *m_matrix[Point16(x, y)];
+ if (slot == NULL) continue;
+
+ /* Fetch minimum slot width and span. */
+ int16 min_slot_width = slot->m_wi->m_min_size.x;
+ int16 span = slot->m_placement.Width();
+ assert(span > 0);
+
+ /* Slot can overlap the left/right edge. Move it to the left by border width. */
+ if ((slot->m_wi->m_feature_flags & FF_IGNORE_PARENT_FRAME) != 0) {
+ if (slot->m_edge_left) min_slot_width -= m_int_border.x;
+ if (slot->m_edge_right) min_slot_width -= m_int_border.x;
+ }
+
+ /* Widget slot width -> table cell width. */
+ int16 min_cell_width = min_slot_width / span;
+
+ /* Accumulate minimal cell width. */
+ if (accu_min_cell_width < min_cell_width) accu_min_cell_width = min_slot_width;
+ }
+ }
+
+ /* Position the first cell. */
+ ColPos &pos_begin_first = m_cols[m_placement_area.Left()];
+ pos_begin_first.m_pos = m_int_border.x;
+
+ /* Position other cells. */
+ for (int16 x = m_placement_area.Left(); x <= m_placement_area.Right(); x++) {
+ ColPos &pos_cur = m_cols[x];
+ ColPos &pos_next = m_cols[x + 1];
+ pos_next.m_pos = pos_cur.m_pos + accu_min_cell_width;
+ }
+}
+
+/**
+ * Scan table slots by rows (top/down) and move row vertical positions down to
+ * satisfy min heights of widgets inside. Update TableSizeData::RowPosArray::m_pos.
+ */
+void TableSizeData::UpdateRowMinSizes_VarSizes()
+{
+ /* Position the first cell. */
+ RowPos &pos_begin_first = m_rows[m_placement_area.Top()];
+ pos_begin_first.m_pos = m_int_border.y;
+
+ for (int16 x = m_placement_area.Left(); x <= m_placement_area.Right(); x++) {
+ for (int16 y = m_placement_area.Top(); y <= m_placement_area.Bottom(); y++) {
+ /* Locate slot at this position (if any) */
+ TableSlot *slot = *m_matrix[Point16(x, y)];
+ if (slot == NULL) continue;
+
+ /* Find appropriate begin/end position data for the slot. */
+ RowPos &pos_begin = m_rows[slot->m_placement.Top()];
+ RowPos &pos_end = m_rows[slot->m_placement.Bottom() + 1];
+
+ /* Where this slot will begin. */
+ int16 min_begin_pos = pos_begin.m_pos;
+ int16 min_slot_height = slot->m_wi->m_min_size.y;
+
+ /* Slot can overlap the left edge. Move it to the left by border width. */
+ bool ignore_parent_frame = (slot->m_wi->m_feature_flags & FF_IGNORE_PARENT_FRAME) != 0;
+ if (ignore_parent_frame && slot->m_edge_top) min_begin_pos -= m_int_border.y;
+
+ /* Set minimal slot begin position. */
+ for (int16 sy = slot->m_placement.Top() + 1; sy <= slot->m_placement.Bottom(); sy++) {
+ RowPos &pos = m_rows[sy];
+ if (pos.m_pos < min_begin_pos) pos.m_pos = min_begin_pos;
+ }
+
+ /* Set slot end position. */
+ int16 min_end_pos = min_begin_pos + min_slot_height;
+
+ /* Slot can overlap the right edge. Move it to the left by border width. */
+ if (ignore_parent_frame && slot->m_edge_bottom) min_end_pos -= m_int_border.y;
+
+ /* Table cell can't end before it begins. */
+ if (min_end_pos < min_begin_pos) min_end_pos = min_begin_pos;
+
+ /* Adjust the slot end position to ensure that the slot will fit there. */
+ if (pos_end.m_pos < min_end_pos) pos_end.m_pos = min_end_pos;
+
+ /* Set minimal positions of remaining table cells. */
+ for (int16 sy = slot->m_placement.Bottom() + 2; sy <= m_placement_area.Bottom(); sy++) {
+ RowPos &pos = m_rows[sy];
+ if (pos.m_pos < min_end_pos) pos.m_pos = min_end_pos;
+ }
+ }
+ }
+}
+
+/**
+ * Scan table slots by rows (top/down) and move row vertical positions down to
+ * satisfy min heights of widgets inside. Update TableSizeData::RowPosArray::m_pos.
+ */
+void TableSizeData::UpdateRowMinSizes_SameSizes()
+{
+ int16 accu_min_cell_height = 0;
+
+ for (int16 x = m_placement_area.Left(); x <= m_placement_area.Right(); x++) {
+ for (int16 y = m_placement_area.Top(); y <= m_placement_area.Bottom(); y++) {
+ /* Locate slot at this position (if any) */
+ TableSlot *slot = *m_matrix[Point16(x, y)];
+ if (slot == NULL) continue;
+
+ /* Fetch minimum slot width and span. */
+ int16 min_slot_height = slot->m_wi->m_min_size.y;
+ int16 span = slot->m_placement.Height();
+ assert(span > 0);
+
+ /* Slot can overlap the left/right edge. Move it to the left by border width. */
+ if ((slot->m_wi->m_feature_flags & FF_IGNORE_PARENT_FRAME) != 0) {
+ if (slot->m_edge_left) min_slot_height -= m_int_border.y;
+ if (slot->m_edge_right) min_slot_height -= m_int_border.y;
+ }
+
+ /* Widget slot width -> table cell width. */
+ int16 min_cell_height = min_slot_height / span;
+
+ /* Accumulate minimal cell width. */
+ if (accu_min_cell_height < min_cell_height) accu_min_cell_height = min_cell_height;
+ }
+ }
+
+ /* Position the first cell. */
+ RowPos &pos_begin_first = m_rows[m_placement_area.Top()];
+ pos_begin_first.m_pos = m_int_border.y;
+
+ /* Position other cells. */
+ for (int16 y = m_placement_area.Top(); y <= m_placement_area.Bottom(); y++) {
+ RowPos &pos_cur = m_rows[y];
+ RowPos &pos_next = m_rows[y + 1];
+ pos_next.m_pos = pos_cur.m_pos + accu_min_cell_height;
+ }
+}
+
+/**
+ * Called from Table::DoLayout to assign each table slot its rectangle.
+ */
+void TableSizeData::DoLayout()
+{
+ // current placement area size is minimal one
+ int16 W = m_cols[m_placement_area.Right() + 1].m_pos - m_cols[m_placement_area.Left()].m_pos + m_int_border.x * 2;
+ int16 H = m_rows[m_placement_area.Bottom() + 1].m_pos - m_rows[m_placement_area.Top() ].m_pos + m_int_border.y * 2;
+
+ // enlarge width if needed
+ if (W < m_table->Width()) {
+ if ((m_table->m_feature_flags & FF_SAME_WIDTH) == 0) {
+ EnlargeWidth_VarSizes(m_table->Width() - W);
+ } else {
+ EnlargeWidth_SameSizes(m_table->Width() - W);
+ }
+ }
+
+ // enlarge height if needed
+ if (H < m_table->Height()) {
+ if ((m_table->m_feature_flags & FF_SAME_HEIGHT) == 0) {
+ EnlargeHeight_VarSizes(m_table->Height() - H);
+ } else {
+ EnlargeHeight_SameSizes(m_table->Height() - H);
+ }
+ }
+
+ m_table->EnumSlotsT<TableSizeData, &TableSizeData::DoLayout_EnumProc>(this);
+}
+
+/**
+ * Called from TableSizeData::DoLayout as slot enumeration callback. Its purpose is to find
+ * the proper column width and row height of each table slot.
+ */
+void TableSizeData::DoLayout_EnumProc(TableSlot &slot, int slot_idx)
+{
+ int16 L = m_cols[slot.m_placement.Left()].m_pos;
+ int16 T = m_rows[slot.m_placement.Top()].m_pos;
+ int16 R = m_cols[slot.m_placement.Right() + 1].m_pos - 1;
+ int16 B = m_rows[slot.m_placement.Bottom() + 1].m_pos - 1;
+ Rect16 rc = Rect16(L, T, R, B);
+ slot.m_wi->SetSlotRect(rc);
+}
+
+/**
+ * Called from TableSizeData::DoLayout when 'variable cell widths' table needs to enlarge horizontally from
+ * its minimal width to the real width by incrementing width of its cells.
+ */
+void TableSizeData::EnlargeWidth_VarSizes(int16 add_size)
+{
+ // Do we need different distribution scheme for var-size tables? If yes, do it here...
+ EnlargeWidth_SameSizes(add_size);
+}
+
+/**
+ * Called from TableSizeData::DoLayout when 'variable cell widths' table needs to enlarge horizontally from
+ * its minimal width to the real width by incrementing width of its cells.
+ */
+void TableSizeData::EnlargeWidth_SameSizes(int16 add_size)
+{
+ int16 num_slots = m_placement_area.Width();
+ for (int32 i = m_placement_area.Left(); i <= m_placement_area.Right() + 1; i++) {
+ // note that 'i' is of type int32
+ m_cols[i].m_pos += (int16)(i * add_size / num_slots);
+ }
+}
+
+/**
+ * Called from TableSizeData::DoLayout when 'variable cell heights' table needs to enlarge vertically from
+ * its minimal size to the real size by incrementing height of its cells.
+ */
+void TableSizeData::EnlargeHeight_VarSizes(int16 add_size)
+{
+ // Do we need different distribution scheme for var-size tables? If yes, do it here...
+ EnlargeHeight_SameSizes(add_size);
+}
+
+/**
+ * Called from TableSizeData::DoLayout when 'same cell heights' table needs to enlarge vertically from
+ * its minimal size to the real size by incrementing height of its cells.
+ */
+void TableSizeData::EnlargeHeight_SameSizes(int16 add_size)
+{
+ int16 num_slots = m_placement_area.Height();
+ for (int32 i = m_placement_area.Top(); i <= m_placement_area.Bottom() + 1; i++) {
+ // note that 'i' is of type int32
+ m_rows[i].m_pos += (int16)(i * add_size / num_slots);
+ }
+}
+
+/**
+ * Add new table slot with widget. Each slot can span through multiple cells.
+ * @param wi widget to add
+ * @param x_pos zero based column index
+ * @param y_pos zero based row index
+ * @param x_span how many columns this slot will span through
+ * @param y_span how many rows this slot will span through
+ */
+/*virtual*/ CompositeWidget::WidgetIterator Table::AddWidget(Widget *wi, int x_pos, int y_pos, int x_span, int y_span)
+{
+ assert(x_span >= 1);
+ assert(y_span >= 1);
+ Slot *slot = new TableSlot(wi, Rect16(Point16(x_pos, y_pos), Size16(x_span, y_span)));
+ WidgetIterator wit = super::AddSlot(slot);
+ return wit;
+}
+
+/**
+ * Query child widgets for their minimum sizes and calculate own minimum size from them.
+ */
+/*virtual*/ void Table::QuerySizes()
+{
+ /* query children */
+ super::QuerySizes();
+ if (m_widgets.empty()) return;
+
+ TableSizeData *size_data = new TableSizeData(this);
+ m_size_data = size_data;
+ size_data->UpdatePlacementArea();
+ size_data->UpdateEdges();
+ size_data->FillMatrix();
+
+ if ((m_feature_flags & FF_SAME_WIDTH) == 0) {
+ size_data->UpdateColMinSizes_VarSizes();
+ } else {
+ size_data->UpdateColMinSizes_SameSizes();
+ }
+
+ if ((m_feature_flags & FF_SAME_HEIGHT) == 0) {
+ size_data->UpdateRowMinSizes_VarSizes();
+ } else {
+ size_data->UpdateRowMinSizes_SameSizes();
+ }
+
+ int16 L = size_data->m_cols[size_data->m_placement_area.Left()].m_pos;
+ int16 T = size_data->m_rows[size_data->m_placement_area.Top()].m_pos;
+ int16 R = size_data->m_cols[size_data->m_placement_area.Right() + 1].m_pos;
+ int16 B = size_data->m_rows[size_data->m_placement_area.Bottom() + 1].m_pos;
+
+ m_min_size = Size16(R - L, B - T) + size_data->m_int_border * 2;
+}
+
+/**
+ * Layout widgets onto table.
+ */
+/*virtual*/ void Table::DoLayout()
+{
+ assert(!m_size_data.IsNull());
+ TableSizeData *size_data = (TableSizeData*)(SimpleCountedObject*)m_size_data;
+ size_data->DoLayout();
+ /* do layout children */
+ super::DoLayout();
+}
+
+}; // namespace gui