mirror of
https://github.com/Ardour/ardour.git
synced 2025-12-11 09:06:33 +01:00
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)
This commit is contained in:
parent
2ed145cfd4
commit
c33f94f686
2 changed files with 69 additions and 30 deletions
|
|
@ -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) {}
|
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 (bool horizontal);
|
||||||
~Pane();
|
~Pane();
|
||||||
|
|
@ -110,7 +110,7 @@ class LIBGTKMM2EXT_API Pane : public Gtk::Container
|
||||||
|
|
||||||
void add_divider ();
|
void add_divider ();
|
||||||
void handle_child_visibility ();
|
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*);
|
static void* notify_child_destroyed (void*);
|
||||||
void* child_destroyed (Gtk::Widget*);
|
void* child_destroyed (Gtk::Widget*);
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,7 @@
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
#include <gdkmm/cursor.h>
|
#include <gdkmm/cursor.h>
|
||||||
#include "gtkmm2ext/pane.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) {
|
for (Children::iterator child = children.begin(); child != children.end(); ++child) {
|
||||||
GtkRequisition r;
|
GtkRequisition r;
|
||||||
|
|
||||||
|
if (!child->w->is_visible ()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
child->w->size_request (r);
|
child->w->size_request (r);
|
||||||
|
|
||||||
if (horizontal) {
|
if (horizontal) {
|
||||||
largest.height = max (largest.height, r.height);
|
largest.height = max (largest.height, r.height);
|
||||||
largest.width += r.width;
|
if (child->minsize) {
|
||||||
|
largest.width += child->minsize;
|
||||||
|
} else {
|
||||||
|
largest.width += r.width;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
largest.width = max (largest.width, r.width);
|
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);
|
reallocate (alloc);
|
||||||
Container::on_size_allocate (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
|
void
|
||||||
|
|
@ -382,60 +404,83 @@ Pane::set_check_divider_position (bool yn)
|
||||||
check_fract = yn;
|
check_fract = yn;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
float
|
||||||
Pane::fract_is_ok (Dividers::size_type div, float fract)
|
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) {
|
if (get_allocation().get_width() == 1 && get_allocation().get_height() == 1) {
|
||||||
/* space not * allocated - * divider being set from startup code. Let it pass,
|
/* 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
|
* since our goal is mostly to catch drags to a position that will interfere with window
|
||||||
resizing.
|
* resizing.
|
||||||
*/
|
*/
|
||||||
return true;
|
return fract;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const float size = horizontal ? get_allocation().get_width() : get_allocation().get_height();
|
||||||
|
|
||||||
|
// 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
|
/* On Quartz, if the pane handle (divider) gets to
|
||||||
be adjacent to the window edge, you can no longer grab it:
|
be adjacent to the window edge, you can no longer grab it:
|
||||||
any attempt to do so is interpreted by the Quartz window
|
any attempt to do so is interpreted by the Quartz window
|
||||||
manager ("Finder") as a resize drag on the window edge.
|
manager ("Finder") as a resize drag on the window edge.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
if (horizontal) {
|
if (horizontal) {
|
||||||
if (div == dividers.size() - 1) {
|
if (div == dividers.size() - 1) {
|
||||||
if (get_allocation().get_width() * (1.0 - fract) < (divider_width*2)) {
|
if (get_allocation().get_width() * (1.0 - fract) < (divider_width*2)) {
|
||||||
/* too close to right edge */
|
/* too close to right edge */
|
||||||
return false;
|
return 1.f - (divider_width * 2.f) / (float) get_allocation().get_width();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (div == 0) {
|
if (div == 0) {
|
||||||
if (get_allocation().get_width() * fract < (divider_width*2)) {
|
if (get_allocation().get_width() * fract < (divider_width*2)) {
|
||||||
/* too close to left edge */
|
/* too close to left edge */
|
||||||
return false;
|
return (divider_width * 2.f) / (float)get_allocation().get_width();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (div == dividers.size() - 1) {
|
if (div == dividers.size() - 1) {
|
||||||
if (get_allocation().get_height() * (1.0 - fract) < (divider_width*2)) {
|
if (get_allocation().get_height() * (1.0 - fract) < (divider_width*2)) {
|
||||||
/* too close to bottom */
|
/* too close to bottom */
|
||||||
return false;
|
return 1.f - (divider_width * 2.f) / (float) get_allocation().get_height();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (div == 0) {
|
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 */
|
/* too close to top */
|
||||||
return false;
|
return (divider_width * 2.f) / (float) get_allocation().get_height();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
return true;
|
return fract;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
|
|
@ -486,10 +531,7 @@ Pane::handle_motion_event (GdkEventMotion* ev, Divider* d)
|
||||||
}
|
}
|
||||||
|
|
||||||
new_fract = min (1.0f, max (0.0f, new_fract));
|
new_fract = min (1.0f, max (0.0f, new_fract));
|
||||||
|
new_fract = constrain_fract (div, new_fract);
|
||||||
if (!fract_is_ok (div, new_fract)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (new_fract != d->fract) {
|
if (new_fract != d->fract) {
|
||||||
d->fract = new_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));
|
fract = max (0.0f, min (1.0f, fract));
|
||||||
|
fract = constrain_fract (div, fract);
|
||||||
if (!fract_is_ok (div, fract)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (fract != (*d)->fract) {
|
if (fract != (*d)->fract) {
|
||||||
(*d)->fract = fract;
|
(*d)->fract = fract;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue