[glom] Details: Align widgets in the first columns of neighbouring layout groups.
- From: Murray Cumming <murrayc src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [glom] Details: Align widgets in the first columns of neighbouring layout groups.
- Date: Sat, 6 Mar 2010 20:40:07 +0000 (UTC)
commit ec80669c75bef3edf13783ca7c22a018758fa053
Author: Murray Cumming <murrayc murrayc com>
Date: Sat Mar 6 21:39:49 2010 +0100
Details: Align widgets in the first columns of neighbouring layout groups.
* glom/utility_widgets/flowtable.[h|cc]: Added get_column_for_first_widget(),
to discover what column a widget is in, and whether it has even been assigned
to a column yet (if the size has been allocated already.)
FlowTableItem: Remember whether the item has a column number and what it is.
on_size_allocate(): Remember the column numbers of items for later retrieval.
* glom/mode_data/flowtablewithfields.[h|cc]: Info, add_field_at_position():
Store the pointer to eventbox too, so we can later discover its column from
the base FlowTable.
Add align_child_group_labels(), to make all first-level labels in child
flowtables share a single Gtk::SizeGroup, making them align.
Add apply_size_group_to_labels() to actually add the labels to the size group.
add_layout_group_at_position(): Call align_child_group_labels() on new
sub-flowtables.
on_size_allocate(): After the base class has allocated the spaces for the
child widgets, after it therefore knows the column positions for the widgets,
call apply_size_group_to_labels() to make them align.
* glom/mode_data/box_data_details.cc: create_layout(): Call
align_child_group_labels() to align items in top-level groups.
ChangeLog | 23 ++++++++
glom/mode_data/box_data_details.cc | 2 +
glom/mode_data/flowtablewithfields.cc | 91 +++++++++++++++++++++++++++++++++
glom/mode_data/flowtablewithfields.h | 20 +++++++-
glom/utility_widgets/flowtable.cc | 47 +++++++++++++++--
glom/utility_widgets/flowtable.h | 23 +++++++-
6 files changed, 197 insertions(+), 9 deletions(-)
---
diff --git a/ChangeLog b/ChangeLog
index 77bd3f8..546101f 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,28 @@
2010-03-06 Murray Cumming <murrayc murrayc com>
+ Details: Align widgets in the first columns of neighbouring layout groups.
+
+ * glom/utility_widgets/flowtable.[h|cc]: Added get_column_for_first_widget(),
+ to discover what column a widget is in, and whether it has even been assigned
+ to a column yet (if the size has been allocated already.)
+ FlowTableItem: Remember whether the item has a column number and what it is.
+ on_size_allocate(): Remember the column numbers of items for later retrieval.
+ * glom/mode_data/flowtablewithfields.[h|cc]: Info, add_field_at_position():
+ Store the pointer to eventbox too, so we can later discover its column from
+ the base FlowTable.
+ Add align_child_group_labels(), to make all first-level labels in child
+ flowtables share a single Gtk::SizeGroup, making them align.
+ Add apply_size_group_to_labels() to actually add the labels to the size group.
+ add_layout_group_at_position(): Call align_child_group_labels() on new
+ sub-flowtables.
+ on_size_allocate(): After the base class has allocated the spaces for the
+ child widgets, after it therefore knows the column positions for the widgets,
+ call apply_size_group_to_labels() to make them align.
+ * glom/mode_data/box_data_details.cc: create_layout(): Call
+ align_child_group_labels() to align items in top-level groups.
+
+2010-03-06 Murray Cumming <murrayc murrayc com>
+
Details: Do not make field widgets too wide, so this fits on a laptop screen.
* glom/utils_ui.cc: get_suitable_field_width_for_widget(): Do not add 150
diff --git a/glom/mode_data/box_data_details.cc b/glom/mode_data/box_data_details.cc
index 2a60f2d..43061c5 100644
--- a/glom/mode_data/box_data_details.cc
+++ b/glom/mode_data/box_data_details.cc
@@ -231,6 +231,8 @@ void Box_Data_Details::create_layout()
{
m_FlowTable.add_layout_group(*iter);
}
+
+ m_FlowTable.align_child_group_labels();
}
#ifndef GLOM_ENABLE_CLIENT_ONLY
diff --git a/glom/mode_data/flowtablewithfields.cc b/glom/mode_data/flowtablewithfields.cc
index 5d38504..5572b53 100644
--- a/glom/mode_data/flowtablewithfields.cc
+++ b/glom/mode_data/flowtablewithfields.cc
@@ -44,6 +44,7 @@ namespace Glom
FlowTableWithFields::Info::Info()
: m_first(0),
+ m_first_eventbox(0),
m_second(0),
m_checkbutton(0)
{
@@ -248,6 +249,8 @@ void FlowTableWithFields::add_layout_group_at_position(const sharedptr<LayoutGro
flow_table->signal_related_record_changed().connect( sigc::mem_fun(*this, &FlowTableWithFields::on_flowtable_related_record_changed) );
flow_table->signal_requested_related_details().connect( sigc::mem_fun(*this, &FlowTableWithFields::on_flowtable_requested_related_details) );
flow_table->signal_script_button_clicked().connect( sigc::mem_fun(*this, &FlowTableWithFields::on_script_button_clicked) );
+
+ flow_table->align_child_group_labels();
}
}
@@ -556,6 +559,7 @@ void FlowTableWithFields::add_field_at_position(const sharedptr<LayoutItem_Field
Gtk::EventBox* eventbox = Gtk::manage(new Gtk::EventBox());
eventbox->add(*info.m_first);
+ info.m_first_eventbox = eventbox; //Remember it so we can retrieve the column number later from FlowTable.
eventbox->set_visible_window(false);
eventbox->set_events(Gdk::ALL_EVENTS_MASK);
eventbox->show_all();
@@ -1242,6 +1246,93 @@ void FlowTableWithFields::on_flowtable_requested_related_details(const Glib::ust
signal_requested_related_details().emit(table_name, primary_key_value);
}
+void FlowTableWithFields::apply_size_group_to_labels(const Glib::RefPtr<Gtk::SizeGroup>& size_group)
+{
+ //Remove widgets from any existing size group:
+ for(type_listFields::iterator iter = m_listFields.begin(); iter != m_listFields.end(); ++iter)
+ {
+ Info info = *iter;
+ Gtk::Label* label = info.m_first;
+ Glib::RefPtr<Gtk::SizeGroup> previous_size_group = info.m_first_in_sizegroup;
+ if(!label || !previous_size_group)
+ continue;
+
+ if(previous_size_group != size_group)
+ {
+ previous_size_group->remove_widget(*label);
+ info.m_first_in_sizegroup.clear();
+ }
+ }
+
+ m_size_group = size_group;
+
+ if(!size_group)
+ return;
+
+ for(type_listFields::iterator iter = m_listFields.begin(); iter != m_listFields.end(); ++iter)
+ {
+ Info info = *iter;
+ Gtk::Label* label = info.m_first;
+ if(!label)
+ continue;
+
+ Gtk::EventBox* label_parent = info.m_first_eventbox;
+ if(!label_parent)
+ continue;
+
+ //Only align labels in the first column, because items in separate columns
+ //couldn't be aligned vertically anyway, and this would cause extra space.
+ //TODO: Use a different SizeGroup for items in 2nd columns?
+ guint column = 0;
+ const bool column_allocated = get_column_for_first_widget(*label_parent, column);
+ if(!column_allocated || (column > 0))
+ continue;
+
+ if(info.m_first_in_sizegroup != size_group)
+ {
+ size_group->add_widget(*label);
+ info.m_first_in_sizegroup = size_group; //Remember it so we can remove it later.
+ }
+ }
+}
+
+void FlowTableWithFields::align_child_group_labels()
+{
+ //Don't bother if there are not >1 groups to align:
+ if(m_sub_flow_tables.size() < 2)
+ return;
+
+ //Create a size group and tell all groups to use is for their labels:
+ Glib::RefPtr<Gtk::SizeGroup> size_group =
+ Gtk::SizeGroup::create(Gtk::SIZE_GROUP_HORIZONTAL);
+ for(type_sub_flow_tables::iterator iter = m_sub_flow_tables.begin(); iter != m_sub_flow_tables.end(); ++iter)
+ {
+ FlowTableWithFields* subtable = *iter;
+ if(subtable)
+ subtable->apply_size_group_to_labels(size_group);
+ }
+}
+
+void FlowTableWithFields::on_size_allocate(Gtk::Allocation& allocation)
+{
+ FlowTable::on_size_allocate(allocation);
+
+ sharedptr<const LayoutGroup> group = get_layout_group();
+ Glib::ustring group_name;
+ if(group)
+ group_name = group->get_name();
+
+ //The widgets have now been allocated their sizes and columns,
+ //so this should be able to work:
+ if(m_columns_allocated_changed)
+ {
+ apply_size_group_to_labels(m_size_group);
+
+ //Prevent unnecessary repeated (endless?) size allocation requested:
+ m_columns_allocated_changed = false;
+ }
+}
+
#ifndef GLOM_ENABLE_CLIENT_ONLY
void FlowTableWithFields::on_dnd_add_layout_item_by_type(int item_type_num, Gtk::Widget* above_widget)
diff --git a/glom/mode_data/flowtablewithfields.h b/glom/mode_data/flowtablewithfields.h
index 1b71a1e..e54424d 100644
--- a/glom/mode_data/flowtablewithfields.h
+++ b/glom/mode_data/flowtablewithfields.h
@@ -102,6 +102,17 @@ public:
virtual void set_design_mode(bool value = true);
virtual void remove_all();
+
+ /** Apply the size group to all field labels.
+ * By calling this method on multiple FlowTables, the field widgets in
+ * different groups can then align.
+ */
+ void apply_size_group_to_labels(const Glib::RefPtr<Gtk::SizeGroup>& size_group);
+
+ /** Create a size group and make all the labels in child flowtables use it,
+ * making them align.
+ */
+ void align_child_group_labels();
/** Get the layout structure, which might have changed in the child widgets since
* the whole widget structure was built.
@@ -180,9 +191,11 @@ private:
Info();
sharedptr<const LayoutItem_Field> m_field; //Store the field information so we know the title, ID, and type.
- Glib::ustring m_group;
Gtk::Label* m_first;
+ Gtk::EventBox* m_first_eventbox; //The label is often inside an eventbox.
+ Glib::RefPtr<Gtk::SizeGroup> m_first_in_sizegroup; //Just to avoid a warning when removing a widget not in a group.
+
DataWidget* m_second;
Gtk::CheckButton* m_checkbutton; //Used instead of first and second if it's a bool.
};
@@ -212,6 +225,8 @@ private:
void add_layout_group_at_position(const sharedptr<LayoutGroup>& group, const type_list_layoutwidgets::iterator& add_before);
void add_layout_notebook_at_position(const sharedptr<LayoutItem_Notebook>& notebook, const type_list_layoutwidgets::iterator& add_before);
void add_layout_portal_at_position(const sharedptr<LayoutItem_Portal>& portal, const type_list_layoutwidgets::iterator& add_before);
+
+ virtual void on_size_allocate(Gtk::Allocation& allocation);
#ifndef GLOM_ENABLE_CLIENT_ONLY
@@ -244,6 +259,9 @@ private:
Gtk::Alignment* m_placeholder;
Glib::ustring m_table_name;
+
+ //Size group shared by this widget's sibling FlowTables.
+ Glib::RefPtr<Gtk::SizeGroup> m_size_group;
type_signal_field_edited m_signal_field_edited;
type_signal_field_open_details_requested m_signal_field_open_details_requested;
diff --git a/glom/utility_widgets/flowtable.cc b/glom/utility_widgets/flowtable.cc
index 02faee4..2e08514 100644
--- a/glom/utility_widgets/flowtable.cc
+++ b/glom/utility_widgets/flowtable.cc
@@ -177,7 +177,9 @@ FlowTable::FlowTableItem::FlowTableItem(Gtk::Widget* first, FlowTable* /* flowta
: m_first(first),
m_second(0),
m_expand_first_full(false),
- m_expand_second(false)
+ m_expand_second(false),
+ m_has_allocated_column(false),
+ m_allocated_column(0)
{
}
@@ -186,7 +188,9 @@ FlowTable::FlowTableItem::FlowTableItem(Gtk::Widget* first, Gtk::Widget* second,
: m_first(first),
m_second(second),
m_expand_first_full(false),
- m_expand_second(false)
+ m_expand_second(false),
+ m_has_allocated_column(false),
+ m_allocated_column(0)
{
}
@@ -201,6 +205,7 @@ FlowTable::FlowTable()
// rather annoying, though I don't see another possibility at the moment. armin.
Glib::ObjectBase("Glom_FlowTable"),
#endif // ! !defined(GLIBMM_DEFAULT_SIGNAL_HANDLERS_ENABLED)
+ m_columns_allocated_changed(false),
m_columns_count(1),
m_column_padding(Utils::DEFAULT_SPACING_SMALL), //A sane default.
m_row_padding(Utils::DEFAULT_SPACING_SMALL), //A sane default.
@@ -722,6 +727,7 @@ void FlowTable::on_size_allocate(Gtk::Allocation& allocation)
int column_child_y_start = allocation.get_y();
+ guint column_number = 0; //Just for remembering it for later.
guint count = m_children.size();
for(guint i = 0; i < count; ++i)
{
@@ -735,7 +741,8 @@ void FlowTable::on_size_allocate(Gtk::Allocation& allocation)
{
//start a new column:
column_child_y_start = allocation.get_y();
- int column_x_start_plus_singles = column_x_start + singles_max_width;
+ ++column_number;
+ const int column_x_start_plus_singles = column_x_start + singles_max_width;
column_x_start = column_x_start_second + second_max_width;
column_x_start = MAX(column_x_start, column_x_start_plus_singles); //Maybe the single items take up even more width.
column_x_start += m_column_padding;
@@ -786,7 +793,7 @@ void FlowTable::on_size_allocate(Gtk::Allocation& allocation)
something_added = true;
}
- if(child_is_visible(second))
+ if(true) //Unecessary check: child_is_visible(second))
{
//Assign space to the child:
@@ -820,6 +827,15 @@ void FlowTable::on_size_allocate(Gtk::Allocation& allocation)
if(something_added)
{
+ //Let later code know where the widgets are, and whether the layout has
+ //changed since m_columns_allocated_changed was last set to false.
+ if(!item.m_has_allocated_column || (item.m_allocated_column != column_number))
+ {
+ item.m_allocated_column = column_number;
+ item.m_has_allocated_column = true;
+ m_columns_allocated_changed = true;
+ }
+
//Start the next child below this child, plus the padding
column_child_y_start += item_height;
column_child_y_start += m_row_padding; //Ignored if this is the last item - we will just start a new column when we find that column_child_y_start is too much.
@@ -896,7 +912,7 @@ void FlowTable::forall_vfunc(gboolean /* include_internals */, GtkCallback callb
{
for(type_vecChildren::const_iterator iter = m_children.begin(); iter != m_children.end(); ++iter)
{
- FlowTableItem item = *iter;
+ const FlowTableItem& item = *iter;
Gtk::Widget* first = item.m_first;
if(first)
@@ -1053,5 +1069,26 @@ bool FlowTable::on_expose_event(GdkEventExpose* event)
#endif
}
+bool FlowTable::get_column_for_first_widget(const Gtk::Widget& first, guint& column)
+{
+ //Initialize output parameter:
+ column = 0;
+
+ for(type_vecChildren::const_iterator iter = m_children.begin(); iter != m_children.end(); ++iter)
+ {
+ const FlowTableItem& item = *iter;
+
+ if((&first == item.m_first) && item.m_has_allocated_column)
+ {
+ column = item.m_allocated_column;
+ return true;
+ }
+ }
+
+ return false;
+}
+
+
+
} //namespace Glom
diff --git a/glom/utility_widgets/flowtable.h b/glom/utility_widgets/flowtable.h
index 3f7aff7..04b990d 100644
--- a/glom/utility_widgets/flowtable.h
+++ b/glom/utility_widgets/flowtable.h
@@ -69,6 +69,12 @@ public:
// Implement forall which is not implemented in gtkmm:
typedef sigc::slot<void, Widget&> ForallSlot;
void forall(const ForallSlot& slot);
+
+ /** Get the column in which the specified "first" widget is placed.
+ * result false if the widget is not one of the "first" widgets, or
+ * if has not yet been placed in a column, because the size has not yet been requested.
+ */
+ bool get_column_for_first_widget(const Gtk::Widget& first, guint& column);
private:
@@ -88,19 +94,22 @@ private:
//Handle child widgets:
virtual void on_size_request(Gtk::Requisition* requisition);
- virtual void on_size_allocate(Gtk::Allocation& allocation);
virtual GType child_type_vfunc() const;
virtual void on_add(Gtk::Widget* child);
virtual void forall_vfunc(gboolean include_internals, GtkCallback callback, gpointer callback_data);
virtual void on_remove(Gtk::Widget* child);
+
+protected:
+
+ virtual void on_size_allocate(Gtk::Allocation& allocation);
+
//Do extra drawing:
//Virtual method overrides:
void on_realize();
void on_unrealize();
bool on_expose_event(GdkEventExpose* event);
-
-protected:
+
int get_column_height(guint start_widget, guint widget_count, int& total_width) const;
/**
@@ -119,6 +128,10 @@ protected:
bool m_expand_first_full;
bool m_expand_second;
+ //The column that the widgets are currently in, due to the size/allocation.
+ bool m_has_allocated_column;
+ guint m_allocated_column;
+
bool operator==(Gtk::Widget* child) const
{
return (child == m_first || child == m_second);
@@ -144,6 +157,10 @@ private:
protected:
typedef std::vector<FlowTableItem> type_vecChildren;
type_vecChildren m_children;
+
+ //Reset this and check it later to see if the layout of items has changed.
+ bool m_columns_allocated_changed;
+
private:
guint m_columns_count;
guint m_column_padding, m_row_padding;
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]