summaryrefslogtreecommitdiff
path: root/libs/gtkmm2ext
diff options
context:
space:
mode:
authorRobin Gareus <robin@gareus.org>2017-01-02 17:13:56 +0100
committerRobin Gareus <robin@gareus.org>2017-01-02 17:13:56 +0100
commitc33f94f686d6d3821ef80bac1af86a3d5ed22e12 (patch)
tree885a9805c3cba6ec341bae6fb879fe585599e956 /libs/gtkmm2ext
parent2ed145cfd4cf02ea5d83df5558df23bafa7e298c (diff)
Enforce minimum pane sizes
* enforce minimum size of child widgets * honor manually set child-minsize in size-requests * ignore hidden children (eg. VCA) * clamp divider position (instead of just ignoring out-of-bounds moves)
Diffstat (limited to 'libs/gtkmm2ext')
-rw-r--r--libs/gtkmm2ext/gtkmm2ext/pane.h4
-rw-r--r--libs/gtkmm2ext/pane.cc93
2 files changed, 68 insertions, 29 deletions
diff --git a/libs/gtkmm2ext/gtkmm2ext/pane.h b/libs/gtkmm2ext/gtkmm2ext/pane.h
index 76eae09dd4..21fba2e9b1 100644
--- a/libs/gtkmm2ext/gtkmm2ext/pane.h
+++ b/libs/gtkmm2ext/gtkmm2ext/pane.h
@@ -55,7 +55,7 @@ class LIBGTKMM2EXT_API Pane : public Gtk::Container
Child (Pane* p, Gtk::Widget* widget, uint32_t ms) : pane (p), w (widget), minsize (ms) {}
};
- typedef std::list<Child> Children;
+ typedef std::vector<Child> Children;
Pane (bool horizontal);
~Pane();
@@ -110,7 +110,7 @@ class LIBGTKMM2EXT_API Pane : public Gtk::Container
void add_divider ();
void handle_child_visibility ();
- bool fract_is_ok (Dividers::size_type, float fract);
+ float constrain_fract (Dividers::size_type, float fract);
static void* notify_child_destroyed (void*);
void* child_destroyed (Gtk::Widget*);
diff --git a/libs/gtkmm2ext/pane.cc b/libs/gtkmm2ext/pane.cc
index 60a6dc543c..8e8b337f32 100644
--- a/libs/gtkmm2ext/pane.cc
+++ b/libs/gtkmm2ext/pane.cc
@@ -17,6 +17,7 @@
*/
+#include <assert.h>
#include <gdkmm/cursor.h>
#include "gtkmm2ext/pane.h"
@@ -97,14 +98,26 @@ Pane::on_size_request (GtkRequisition* req)
for (Children::iterator child = children.begin(); child != children.end(); ++child) {
GtkRequisition r;
+ if (!child->w->is_visible ()) {
+ continue;
+ }
+
child->w->size_request (r);
if (horizontal) {
largest.height = max (largest.height, r.height);
- largest.width += r.width;
+ if (child->minsize) {
+ largest.width += child->minsize;
+ } else {
+ largest.width += r.width;
+ }
} else {
largest.width = max (largest.width, r.width);
- largest.height += r.height;
+ if (child->minsize) {
+ largest.height += child->minsize;
+ } else {
+ largest.height += r.height;
+ }
}
}
@@ -202,6 +215,15 @@ Pane::on_size_allocate (Gtk::Allocation& alloc)
{
reallocate (alloc);
Container::on_size_allocate (alloc);
+
+ /* minumum pane size constraints */
+ Dividers::size_type div = 0;
+ for (Dividers::const_iterator d = dividers.begin(); d != dividers.end(); ++d, ++div) {
+ Pane::set_divider (div, (*d)->fract);
+ }
+ // TODO this needs tweaking for panes with > 2 children
+ // if a child grows, re-check the ones before it.
+ assert (dividers.size () < 3);
}
void
@@ -382,22 +404,44 @@ Pane::set_check_divider_position (bool yn)
check_fract = yn;
}
-bool
-Pane::fract_is_ok (Dividers::size_type div, float fract)
+float
+Pane::constrain_fract (Dividers::size_type div, float fract)
{
-#ifdef __APPLE__
- if (!check_fract) {
- return true;
+ if (get_allocation().get_width() == 1 && get_allocation().get_height() == 1) {
+ /* space not * allocated - * divider being set from startup code. Let it pass,
+ * since our goal is mostly to catch drags to a position that will interfere with window
+ * resizing.
+ */
+ return fract;
}
+ const float size = horizontal ? get_allocation().get_width() : get_allocation().get_height();
- if (get_allocation().get_width() == 1 && get_allocation().get_height() == 1) {
- /* space not * allocated - * divider being set from startup code. Let it pass,
- since our goal is mostly to catch drags to a position that will interfere with window
- resizing.
- */
- return true;
+ // TODO: optimize: cache in Pane::on_size_request
+ Gtk::Requisition prev_req(children.at (div).w->size_request ());
+ Gtk::Requisition next_req(children.at (div + 1).w->size_request ());
+ float prev = divider_width + (horizontal ? prev_req.width : prev_req.height);
+ float next = divider_width + (horizontal ? next_req.width : next_req.height);
+
+ if (children.at (div).minsize) {
+ prev = children.at (div).minsize;
}
+ if (children.at (div + 1).minsize) {
+ next = children.at (div + 1).minsize;
+ }
+
+ if (size * fract < prev) {
+ return prev / size;
+ }
+ if (size * (1.f - fract) < next) {
+ return 1.f - next / size;
+ }
+
+ if (!check_fract) {
+ return fract;
+ }
+
+#ifdef __APPLE__
/* On Quartz, if the pane handle (divider) gets to
be adjacent to the window edge, you can no longer grab it:
@@ -405,37 +449,38 @@ Pane::fract_is_ok (Dividers::size_type div, float fract)
manager ("Finder") as a resize drag on the window edge.
*/
+
if (horizontal) {
if (div == dividers.size() - 1) {
if (get_allocation().get_width() * (1.0 - fract) < (divider_width*2)) {
/* too close to right edge */
- return false;
+ return 1.f - (divider_width * 2.f) / (float) get_allocation().get_width();
}
}
if (div == 0) {
if (get_allocation().get_width() * fract < (divider_width*2)) {
/* too close to left edge */
- return false;
+ return (divider_width * 2.f) / (float)get_allocation().get_width();
}
}
} else {
if (div == dividers.size() - 1) {
if (get_allocation().get_height() * (1.0 - fract) < (divider_width*2)) {
/* too close to bottom */
- return false;
+ return 1.f - (divider_width * 2.f) / (float) get_allocation().get_height();
}
}
if (div == 0) {
- if (get_allocation().get_width() * fract < (divider_width*2)) {
+ if (get_allocation().get_height() * fract < (divider_width*2)) {
/* too close to top */
- return false;
+ return (divider_width * 2.f) / (float) get_allocation().get_height();
}
}
}
#endif
- return true;
+ return fract;
}
bool
@@ -486,10 +531,7 @@ Pane::handle_motion_event (GdkEventMotion* ev, Divider* d)
}
new_fract = min (1.0f, max (0.0f, new_fract));
-
- if (!fract_is_ok (div, new_fract)) {
- return true;
- }
+ new_fract = constrain_fract (div, new_fract);
if (new_fract != d->fract) {
d->fract = new_fract;
@@ -517,10 +559,7 @@ Pane::set_divider (Dividers::size_type div, float fract)
}
fract = max (0.0f, min (1.0f, fract));
-
- if (!fract_is_ok (div, fract)) {
- return;
- }
+ fract = constrain_fract (div, fract);
if (fract != (*d)->fract) {
(*d)->fract = fract;