diff options
| author | Albrecht Schlosser <albrechts.fltk@online.de> | 2022-02-22 23:28:04 +0100 |
|---|---|---|
| committer | Albrecht Schlosser <albrechts.fltk@online.de> | 2022-03-01 13:45:51 +0100 |
| commit | 091712bea8ff5aab89f0f8483ca572c118ca5715 (patch) | |
| tree | a6afc62f1ebd7bb33e9b1036124d0037d09f0e09 /src/Fl_Window.cxx | |
| parent | d4ceb20ad30662861fe5a1471de2b5a202772937 (diff) | |
Fix default size_range() calculation (issue #392, STR 3352)
Diffstat (limited to 'src/Fl_Window.cxx')
| -rw-r--r-- | src/Fl_Window.cxx | 215 |
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 */ |
