summaryrefslogtreecommitdiff
path: root/src/Fl_Window.cxx
diff options
context:
space:
mode:
authorAlbrecht Schlosser <albrechts.fltk@online.de>2022-02-22 23:28:04 +0100
committerAlbrecht Schlosser <albrechts.fltk@online.de>2022-03-01 13:45:51 +0100
commit091712bea8ff5aab89f0f8483ca572c118ca5715 (patch)
treea6afc62f1ebd7bb33e9b1036124d0037d09f0e09 /src/Fl_Window.cxx
parentd4ceb20ad30662861fe5a1471de2b5a202772937 (diff)
Fix default size_range() calculation (issue #392, STR 3352)
Diffstat (limited to 'src/Fl_Window.cxx')
-rw-r--r--src/Fl_Window.cxx215
1 files changed, 188 insertions, 27 deletions
diff --git a/src/Fl_Window.cxx b/src/Fl_Window.cxx
index 77090dc0b..50f39f04e 100644
--- a/src/Fl_Window.cxx
+++ b/src/Fl_Window.cxx
@@ -1,7 +1,7 @@
//
// Window widget class for the Fast Light Tool Kit (FLTK).
//
-// Copyright 1998-2021 by Bill Spitzak and others.
+// Copyright 1998-2022 by Bill Spitzak and others.
//
// This library is free software. Distribution and use rights are outlined in
// the file "COPYING" which should have been included with this file. If this
@@ -54,8 +54,8 @@ void Fl_Window::_Fl_Window() {
xclass_ = 0;
iconlabel_ = 0;
resizable(0);
- size_range_set = 0;
- minw = maxw = minh = maxh = 0;
+ size_range_set_ = 0;
+ minw_ = maxw_ = minh_ = maxh_ = 0;
no_fullscreen_x = 0;
no_fullscreen_y = 0;
no_fullscreen_w = w();
@@ -542,6 +542,8 @@ void Fl_Window::show() {
labeltype(FL_NO_LABEL);
}
Fl_Tooltip::exit(this);
+ if (!shown())
+ default_size_range();
pWindowDriver->show();
}
@@ -600,32 +602,24 @@ int Fl_Window::handle(int ev)
It is undefined what happens if the current window size does not fit
in the constraints passed to size_range().
- If this function is \b not called, FLTK tries to figure out the range
- from the setting of the window's resizable() widget:
+ We recommend to call size_range() if you have a resizable() widget
+ in a main window.
- - If resizable() is NULL (this is the default) then the window cannot
- be resized and the resize border and max-size control will not be
- displayed for the window.
-
- - If either dimension of resizable() is zero, then the minimum size is
- also the maximum size (so the window cannot resize in that direction).
-
- - Otherwise the size of the resizable is irrelevant and the window's
- minimum size is the current size and the maximum size is unlimited
- like if size_range(w(), h(), 0, 0) was called.
+ If this function is \b not called, FLTK tries to figure out the range.
+ Please see the protected method default_size_range() for details.
- \param[in] minWidth, minHeight The smallest the window can be.
+ \param[in] minWidth,minHeight The smallest the window can be.
Either value must be greater than 0.
- \param[in] maxWidth, maxHeight The largest the window can be. If either
+ \param[in] maxWidth,maxHeight The largest the window can be. If either
is equal to the minimum then you cannot resize in that direction.
If either is zero then FLTK picks a maximum size in that direction
such that the window will fill the screen.
- \param[in] deltaX, deltaY These are size increments. The window will be
+ \param[in] deltaX,deltaY These are size increments. The window will be
constrained to widths of <tt>minWidth + N * deltaX</tt>, where N is any
non-negative integer. If these are less or equal to 1 they are ignored
- (this is ignored on Windows).
+ (this is always ignored on Windows).
\param[in] aspectRatio A flag that indicates that the window should preserve
its aspect ratio. This only works if both the maximum and minimum have
@@ -634,14 +628,181 @@ int Fl_Window::handle(int ev)
void Fl_Window::size_range(int minWidth, int minHeight,
int maxWidth, int maxHeight,
int deltaX, int deltaY, int aspectRatio) {
- minw = minWidth;
- minh = minHeight;
- maxw = maxWidth;
- maxh = maxHeight;
- dw = deltaX;
- dh = deltaY;
- aspect = aspectRatio;
- pWindowDriver->size_range();
+ minw_ = minWidth;
+ minh_ = minHeight;
+ maxw_ = maxWidth;
+ maxh_ = maxHeight;
+ dw_ = deltaX;
+ dh_ = deltaY;
+ aspect_ = aspectRatio;
+ size_range_set_ = 1;
+ pWindowDriver->size_range(); // platform specific stuff
+}
+
+/**
+ Protected method to calculate the default size range of a window.
+
+ This method is called internally prior to showing a window to ensure that
+ the window's size range values are calculated if a resizable() widget has
+ been set but size_range() has not been called explicitly.
+
+ This method does nothing if size_range() has been called before.
+
+ Otherwise FLTK tries to figure out the window's size range from the
+ setting of the window's resizable() widget as follows and roughly in
+ the given order.
+
+ -# If resizable() is NULL (this is the default) then the window cannot
+ be resized and the resize border and max-size control will not be
+ displayed for the window.
+
+ -# If either dimension of resizable() is zero, then the window cannot
+ resize in that direction.
+
+ -# The resizable() widget is clipped to the window area.
+
+ -# The non-resizable portion of the window is calculated as the difference
+ of the window's size and the clipped resizable() widget's size.
+
+ -# If either dimension of the clipped resizable() widget is greater
+ than 100, then 100 is considered its minimum width/height. This
+ allows the resizable widget to shrink below its original size.
+
+ -# Finally the minimum width/height of the window is set to the
+ non-resizable portion plus the width/height of the resizable()
+ widget as calculated above.
+
+ In simple words:
+ - It is assumed that the resizable() widget can be indefinitely
+ enlarged and/or shrunk to a minimum width/height of 100 unless
+ it is smaller than that, which is then considered the minimum.
+ - The window's size_range() minimum values are set to the sum
+ of the non-resizable portion of the window and the previously
+ calculated minimum size of the resizable() widget.
+
+ Examples:
+ \code
+ Fl_Window win(400, 400);
+ win.resizable(win);
+ // win.size_range(100, 100, 0, 0);
+ \endcode
+
+ The minimum size of the resizable is 100, hence the minimum size
+ of the total window is also 100 in both directions.
+
+ \code
+ Fl_Window win(400, 400);
+ Fl_Box box(20, 20, 360, 360);
+ win.resizable(box);
+ // win.size_range(140, 140, 0, 0);
+ \endcode
+
+ The calculated minimum width and height would be 20 + 100 + 20 in both
+ dimensions.
+
+ \code
+ Fl_Window win(400, 400);
+ Fl_Box box(200, 0, 500, 300); // note: width 500 too large: clipped
+ win.resizable(box);
+ // win.size_range(300, 200, 0, 0);
+ \endcode
+
+ The width of the resizable is clipped to 200, hence the minimum size of
+ the total window is also 200 (fix) + 100 (min. resizable) in x direction.
+ The minimum value in y direction is 100 (resizable) + 100 (fixed part).
+
+ The calculation is based on clipping the resizable widget to the window
+ area to prevent programming errors and the assumption that the resizable
+ widget can be shrunk to 100x100 or its original size, whichever is smaller.
+
+ If this is not what you want, please use Fl_Window::size_range()
+ explicitly so you can set any appropriate range.
+*/
+void Fl_Window::default_size_range() {
+
+ if (size_range_set_)
+ return;
+ if (!resizable()) {
+ size_range(w(), h(), w(), h());
+ return;
+ }
+
+ // Calculate default size range depending on the resizable() widget
+
+ Fl_Widget *r = resizable();
+
+ int maxw = 0;
+ int maxh = 0;
+
+ // Clip the resizable() widget to the window
+
+ int L = r->x();
+ int R = L + r->w();
+ if (R < 0 || L > w()) R = L; // outside the window
+ else {
+ if (L < 0) L = 0;
+ if (R > w()) R = w();
+ }
+ int rw = R - L;
+
+ int T = r->y();
+ int B = T + r->h();
+ if (B < 0 || T > h()) B = T; // outside the window
+ else {
+ if (T < 0) T = 0;
+ if (B > h()) B = h();
+ }
+ int rh = B - T;
+
+ // Calculate the non-resizable part of the window (STR 3352)
+ // before reducing the size of the resizable widget !
+ int minw = w() - rw;
+ int minh = h() - rh;
+
+ // Limit the resizable dimensions to 100x100 according to the docs.
+ // This makes the resizable widget shrinkable, otherwise it would
+ // only be able to grow (issue #392)
+ if (rw > 100) rw = 100;
+ if (rh > 100) rh = 100;
+
+ // Add the clipped resizable() width/height so we have at least
+ // the non-resizable part + the clipped resizable() size
+ minw += rw;
+ minh += rh;
+
+ // Disable resizing in the respective directions if any dimension
+ // of the resizable widget is zero (see docs)
+ if (r->w() == 0) minw = maxw = w();
+ if (r->h() == 0) minh = maxh = h();
+
+ // Finally set the size range
+ size_range(minw, minh, maxw, maxh);
+}
+
+/**
+ Protected method to determine whether a window is resizable.
+
+ If size_range() has not yet been called this method calculates the
+ default size range values by calling default_size_range().
+
+ This method is for internal use only. The returned value is a bit mask
+ and non-zero if the window is resizable in at least one direction.
+
+ \return non-zero if the window is resizable
+
+ \retval 0 the window is not resizable
+ \retval 1 the window is resizable in horizontal direction (w)
+ \retval 2 the window is resizable in vertical direction (h)
+ \retval 3 the window is resizable in both directions (w and h)
+
+ \see default_size_range()
+*/
+int Fl_Window::is_resizable() {
+ default_size_range();
+ int ret = 0;
+ if (minw_ != maxw_) ret |= 1;
+ if (minh_ != maxh_) ret |= 2;
+ return ret;
}
/** The number of the screen containing the mapped window */