Module: duim-layouts-internals Synopsis: DUIM layouts Author: Scott McKay, Andy Armstrong Copyright: Original Code is Copyright (c) 1995-2004 Functional Objects, Inc. All rights reserved. License: Functional Objects Library Public License Version 1.0 Dual-license: GNU Lesser General Public License Warranty: Distributed WITHOUT WARRANTY OF ANY KIND /// Space requirements define protocol-class space-requirement () end; define protocol <> () function space-requirement-width (sheet :: , space-req :: ) => (width :: false-or()); function space-requirement-min-width (sheet :: , space-req :: ) => (min-width :: false-or()); function space-requirement-max-width (sheet :: , space-req :: ) => (max-width :: false-or()); function space-requirement-height (sheet :: , space-req :: ) => (height :: false-or()); function space-requirement-min-height (sheet :: , space-req :: ) => (min-height :: false-or()); function space-requirement-max-height (sheet :: , space-req :: ) => (max-height :: false-or()); function space-requirement-components (sheet :: , space-req :: ) => (width :: false-or(), min-width :: false-or(), max-width :: false-or(), height :: false-or(), min-height :: false-or(), max-height :: false-or()); end protocol <>; // This is the size we use for a "fill" component, the idea being that // we should be able sum up at least 100 $fill's without overflowing // into bignums (that is, fit into the 28 bits required by Dylan) // 'floor(10 ^ floor(logn($maximum-integer, 10)) / 100)' define constant $fill :: = 100000; /// Simple space requirement classes define sealed class () end class ; define sealed method space-requirement-components (sheet :: , space-req :: ) => (width :: , min-width :: , max-width :: , height :: , min-height :: , max-height :: ) values(0, 0, 0, 0, 0, 0) end method space-requirement-components; define sealed method space-requirement-width (sheet :: , sr :: ) => (width :: ) 0 end method space-requirement-width; define sealed method space-requirement-min-width (sheet :: , sr :: ) => (min-width :: ) 0 end method space-requirement-min-width; define sealed method space-requirement-max-width (sheet :: , sr :: ) => (max-width :: ) 0 end method space-requirement-max-width; define sealed method space-requirement-height (sheet :: , sr :: ) => (height :: ) 0 end method space-requirement-height; define sealed method space-requirement-min-height (sheet :: , sr :: ) => (min-height :: ) 0 end method space-requirement-min-height; define sealed method space-requirement-max-height (sheet :: , sr :: ) => (max-height :: ) 0 end method space-requirement-max-height; define variable $null-space-requirement :: = make(); define sealed class () sealed constant slot %width :: false-or(), required-init-keyword: width:; sealed constant slot %height :: false-or(), required-init-keyword: height:; end class ; define sealed method space-requirement-components (sheet :: , space-req :: ) => (width :: false-or(), min-width :: false-or(), max-width :: false-or(), height :: false-or(), min-height :: false-or(), max-height :: false-or()) let width = space-req.%width; let height = space-req.%height; values(width, width, width, height, height, height) end method space-requirement-components; define sealed method space-requirement-width (sheet :: , sr :: ) => (width :: false-or()) sr.%width end method space-requirement-width; define sealed method space-requirement-min-width (sheet :: , sr :: ) => (min-width :: false-or()) sr.%width end method space-requirement-min-width; define sealed method space-requirement-max-width (sheet :: , sr :: ) => (max-width :: false-or()) sr.%width end method space-requirement-max-width; define sealed method space-requirement-height (sheet :: , sr :: ) => (height :: false-or()) sr.%height end method space-requirement-height; define sealed method space-requirement-min-height (sheet :: , sr :: ) => (min-height :: false-or()) sr.%height end method space-requirement-min-height; define sealed method space-requirement-max-height (sheet :: , sr :: ) => (max-height :: false-or()) sr.%height end method space-requirement-max-height; define sealed class () sealed constant slot %width :: false-or(), required-init-keyword: width:; sealed constant slot %height :: false-or(), required-init-keyword: height:; end class ; define sealed method space-requirement-components (sheet :: , space-req :: ) => (width :: false-or(), min-width :: , max-width :: , height :: false-or(), min-height :: , max-height :: ) values(space-req.%width, 0, $fill, space-req.%height, 0, $fill) end method space-requirement-components; define sealed method space-requirement-width (sheet :: , sr :: ) => (width :: false-or()) sr.%width end method space-requirement-width; define sealed method space-requirement-min-width (sheet :: , sr :: ) => (min-width :: ) 0 end method space-requirement-min-width; define sealed method space-requirement-max-width (sheet :: , sr :: ) => (max-width :: ) $fill end method space-requirement-max-width; define sealed method space-requirement-height (sheet :: , sr :: ) => (height :: false-or()) sr.%height end method space-requirement-height; define sealed method space-requirement-min-height (sheet :: , sr :: ) => (min-height :: ) 0 end method space-requirement-min-height; define sealed method space-requirement-max-height (sheet :: , sr :: ) => (max-height :: ) $fill end method space-requirement-max-height; define sealed class () sealed constant slot %width :: false-or(), required-init-keyword: width:; sealed constant slot %min-width :: false-or(), required-init-keyword: min-width:; sealed constant slot %max-width :: false-or(), required-init-keyword: max-width:; sealed constant slot %height :: false-or(), required-init-keyword: height:; sealed constant slot %min-height :: false-or(), required-init-keyword: min-height:; sealed constant slot %max-height :: false-or(), required-init-keyword: max-height:; end class ; define sealed method space-requirement-components (sheet :: , space-req :: ) => (width :: false-or(), min-width :: false-or(), max-width :: false-or(), height :: false-or(), min-height :: false-or(), max-height :: false-or()) values(space-req.%width, space-req.%min-width, space-req.%max-width, space-req.%height, space-req.%min-height, space-req.%max-height) end method space-requirement-components; define sealed method space-requirement-width (sheet :: , sr :: ) => (width :: false-or()) sr.%width end method space-requirement-width; define sealed method space-requirement-min-width (sheet :: , sr :: ) => (min-width :: false-or()) sr.%min-width end method space-requirement-min-width; define sealed method space-requirement-max-width (sheet :: , sr :: ) => (max-width :: false-or()) sr.%max-width end method space-requirement-max-width; define sealed method space-requirement-height (sheet :: , sr :: ) => (height :: false-or()) sr.%height end method space-requirement-height; define sealed method space-requirement-min-height (sheet :: , sr :: ) => (min-height :: false-or()) sr.%min-height end method space-requirement-min-height; define sealed method space-requirement-max-height (sheet :: , sr :: ) => (max-height :: false-or()) sr.%max-height end method space-requirement-max-height; /// Complex space requirement classes // A space requirement that allocates enough room to hold the given label define sealed class () sealed constant slot %label :: type-union(, ), required-init-keyword: label:; sealed constant slot %min-width :: false-or() = #f, init-keyword: min-width:; sealed constant slot %max-width :: false-or() = #f, init-keyword: max-width:; sealed constant slot %min-height :: false-or() = #f, init-keyword: min-height:; sealed constant slot %max-height :: false-or() = #f, init-keyword: max-height:; end class ; define sealed method space-requirement-components (sheet :: , space-req :: ) => (width :: , min-width :: , max-width :: , height :: , min-height :: , max-height :: ) let (width, height) = space-requirement-label-size(sheet, space-req); values(width, space-req.%min-width | width, space-req.%max-width | width, height, space-req.%min-height | height, space-req.%max-height | height) end method space-requirement-components; define method space-requirement-label-size (sheet :: , sr :: ) => (width :: , height :: ) let label = sr.%label; select (label by instance?) => let _port = port(sheet); let text-style = get-default-text-style(_port, sheet); // Use the computed width of the label, but the height of the font // Add a few pixels in each direction to keep the label from being squeezed values(ceiling(text-size(_port, label, //--- what about tabs and newlines? text-style: text-style)) + 2, ceiling(font-height(text-style, _port)) + 2); => values(image-width(label), image-height(label)); end end method space-requirement-label-size; define sealed method space-requirement-width (sheet :: , sr :: ) => (width :: ) let (width, height) = space-requirement-label-size(sheet, sr); ignore(height); width end method space-requirement-width; define sealed method space-requirement-min-width (sheet :: , sr :: ) => (min-width :: ) sr.%min-width | begin let (width, height) = space-requirement-label-size(sheet, sr); ignore(height); width end end method space-requirement-min-width; define sealed method space-requirement-max-width (sheet :: , sr :: ) => (max-width :: ) sr.%max-width | begin let (width, height) = space-requirement-label-size(sheet, sr); ignore(height); width end end method space-requirement-max-width; define sealed method space-requirement-height (sheet :: , sr :: ) => (height :: ) let (width, height) = space-requirement-label-size(sheet, sr); ignore(width); height end method space-requirement-height; define sealed method space-requirement-min-height (sheet :: , sr :: ) => (min-height :: ) sr.%min-height | begin let (width, height) = space-requirement-label-size(sheet, sr); ignore(width); height end end method space-requirement-min-height; define sealed method space-requirement-max-height (sheet :: , sr :: ) => (max-height :: ) sr.%max-height | begin let (width, height) = space-requirement-label-size(sheet, sr); ignore(width); height end end method space-requirement-max-height; // A space requirement that calls a function to get the requirements //--- Maybe we should have a "one-shot" functional space requirement //--- that only computes its value once and caches the result? define sealed class () sealed constant slot %function :: , required-init-keyword: function:; end class ; define sealed method space-requirement-components (sheet :: , space-req :: ) => (width :: , min-width :: , max-width :: , height :: , min-height :: , max-height :: ) space-req.%function(sheet) end method space-requirement-components; define sealed method space-requirement-width (sheet :: , sr :: ) => (width :: ) let (w, w-, w+, h, h-, h+) = sr.%function(sheet); ignore(w-, w+, h, h-, h+); w end method space-requirement-width; define sealed method space-requirement-min-width (sheet :: , sr :: ) => (min-width :: ) let (w, w-, w+, h, h-, h+) = sr.%function(sheet); ignore(w, w+, h, h-, h+); w- end method space-requirement-min-width; define sealed method space-requirement-max-width (sheet :: , sr :: ) => (max-width :: ) let (w, w-, w+, h, h-, h+) = sr.%function(sheet); ignore(w, w-, h, h-, h+); w+ end method space-requirement-max-width; define sealed method space-requirement-height (sheet :: , sr :: ) => (height :: ) let (w, w-, w+, h, h-, h+) = sr.%function(sheet); ignore(w, w-, w+, h-, h+); h end method space-requirement-height; define sealed method space-requirement-min-height (sheet :: , sr :: ) => (min-height :: ) let (w, w-, w+, h, h-, h+) = sr.%function(sheet); ignore(w, w-, w+, h, h+); h- end method space-requirement-min-height; define sealed method space-requirement-max-height (sheet :: , sr :: ) => (max-height :: ) let (w, w-, w+, h, h-, h+) = sr.%function(sheet); ignore(w, w-, w+, h, h-); h+ end method space-requirement-max-height; /// Space requirement constructors define sealed method make (class == , #rest initargs, #key label, function, width = 0, min-width = width, max-width = width, height = 0, min-height = height, max-height = height) => (space-req :: ) case label => apply(make, , label: label, initargs); function => apply(make, , function: function, initargs); width == min-width & width == max-width & height == min-height & height == max-height => // Compare with '==' to avoid blowout if width or height is #"compute" if (width == 0 & height == 0) $null-space-requirement else make(, width: width, height: height) end; min-width == 0 & max-width >= $fill & min-height == 0 & max-height >= $fill => make(, width: width, height: height); otherwise => make(, width: width, min-width: min-width, max-width: max-width, height: height, min-height: min-height, max-height: max-height); end end method make; // Seal the constructors and initializers for all space requirements define sealed domain make (subclass()); define sealed domain initialize (); /// Space requirements arithmetic define method space-requirement-combine (sheet :: , function :: , sr1 :: , sr2 :: ) => (space-req :: ) let (w1, w1-, w1+, h1, h1-, h1+) = space-requirement-components(sheet, sr1); let (w2, w2-, w2+, h2, h2-, h2+) = space-requirement-components(sheet, sr2); make(, width: function(w1, w2), min-width: function(w1-, w2-), max-width: function(w1+, w2+), height: function(h1, h2), min-height: function(h1-, h2-), max-height: function(h1+, h2+)) end method space-requirement-combine; // Add two space requirements define inline function space-requirement+* (sheet :: , sr1 :: , sr2 :: ) => (space-req :: ) space-requirement-combine(sheet, \+, sr1, sr2) end function space-requirement+*; // The "spread" version of the above... define method space-requirement+ (sheet :: , space-req :: , #key width :: = 0, min-width :: = width, max-width :: = width, height :: = 0, min-height :: = height, max-height :: = height) => (space-req :: ) let (w :: , w- :: , w+ :: , h :: , h- :: , h+ :: ) = space-requirement-components(sheet, space-req); make(, width: w + width, min-width: w- + min-width, max-width: w+ + max-width, height: h + height, min-height: h- + min-height, max-height: h+ + max-height) end method space-requirement+;