mirror of https://gitee.com/openkylin/cwidget.git
26ffc35604 | ||
---|---|---|
.. | ||
config | ||
generic | ||
widgets | ||
Makefile.am | ||
Makefile.in | ||
README.layout | ||
columnify.cc | ||
columnify.h | ||
curses++.cc | ||
curses++.h | ||
dialogs.cc | ||
dialogs.h | ||
fragment.cc | ||
fragment.h | ||
fragment_cache.cc | ||
fragment_cache.h | ||
fragment_contents.h | ||
style.cc | ||
style.h | ||
testcwidget.cc | ||
toplevel.cc | ||
toplevel.h |
README.layout
cwidget/README.layout Daniel Burrows <Daniel_Burrows@brown.edu> -- written 7/17/00 A brief dissertation on the layout system to be used in cwidget. I saw ad-hoc fixes starting to accumulate, and I figure that a thought-out design document won't hurt at all, even if I have to rewrite most of the code to comply with it :-) So, there is a distinct need for widgets to (a) advertise information about their desired size, size constraints, und so weiter, (b) learn when they have been given a new physical size and adjust themselves accordingly (possibly resizing more widgets in a recursive manner), and (c) announce when their requested size has changed and they might (consequently) need a resize. So, here's how we go about doing it. This is not necessarily the objectively *best* way, it is merely *a* way that is fairly logical, capable, and not overly difficult to implement. Complaints should come with an attached and working example of a better layout system, please :-) SIZE REQUESTS To request a desired size, widgets should implement the "size_request" virtual method. This essentially calculates the desired size and returns it. (it would be possible, but IMO too much work, to cache this in a member variable. Size requests should happen relatively rarely.. *crosses fingers*) Sizes will be stored as a separate type, in which w and h values have the expected meanings (ie, w==0 h==0 means the widget is so small it's invisible) In particular, the (0,0) "infinite-resize" hack is NOT supported in this system; other mechanisms should be used to make widgets occupy all available space. The desired size will be treated not only as a target size, but also (whenever possible) as a *minimum* size. This means that widgets which lay other widgets out should never give a widget less size than it requests, unless doing so is absolutely necessary (and even then they should avoid it :P ) Unfortunately, this may not be possible--which means that properly-written widgets should handle situations where they are allocated dramatically smaller windows than expected and not blow up, summon demons, etc. (well, summoning demons is permissible if and only if the user has requested such action) As a special case, the widget will be automatically "hidden" (by setting its window to NULL) if either the width or height is 0. GIVING SIZES TO WIDGETS When a widget's owner assigns it a size, it should call widget->alloc_size(x, y, w, h). This routine will set all the various `official' things needed to give the widget the appropriate coordinates inside the enclosing widget. alloc_size will make the widget invisible if either w or h is 0, as described above. Widgets which contain other widgets should call alloc_size on all their visible children when they themselves have their size allocated (which is why this is a virtual method :) ) ANNOUNCING SIZE CHANGES Calling the "toplevel::queuelayout()" routine will cause a widget to be laid out again when the cwidget main loop is re-entered. In the main loop of the code (or in a toplevel::poll()), the queue will be examined and layout operations performed on the topmost ancestor of each item in the queue. (no widget will be laid out more than once -- at least, not in the final version :) ) This will take place before queued screen redraws, of course :-) (an interesting note is that since, of course, all widgets have their ultimate ancestor in the toplevel widget, a queued resize just means that that widget is laid out again) WHEN TO LAYOUT A signal "do_layout" is available; when this is emitted, widgets should recalculate their layout and reassign sizes and windows to child widgets via alloc_size() (this may be triggered from within alloc_size) TABLE LAYOUT Well, this isn't strictly within the bounds of what I was originally planning to says, but it's complicated and bears writing down... The mechanism for table layout is derived from GTK+ code and -- again -- is not particularly optimal but should work (mostly). I will only describe the computations necessary for rows; the algorithm is perfectly symmetrical with respect to rows and columns. (that is, rows and columns are orthogonal to one another :-) ) Each algorithm will temporarily store information about the width of rows and columns. (this can optionally be cached after the algorithm completes, of course) REQUISITION: (a) The table whose size is being requested will collect all its widgets and sort them according to how many rows each occupies. (b) The table will iterate over the new list by row count in increasing order. For each widget, the total height of the rows it spans will be calculated and compared to its requested height. If the total width is less than the widget's requested width, the height of each row spanned by the widget is incremented by height_diff/nrows, where height_diff is the shortfall and nrows is the number of rows the widget spans. (doing this is a bit tricky; I like the GTK+ approach, which is to iterate over the rows, incrementing each by height_diff/nrows, then decrementing height_diff by that amount and decrementing nrows by 1) ALLOCATION: This is trickier, as there may be shortfall or leftover size. (a) Initial row sizes are calculated as in REQUISITION (b) If the allocated size is larger than the requested size, the number of rows which are allowed to be expanded (ie, at least one member of the row requests expansion (attributes are determined at time of insertion into the table..)) is calculated. The extra size is then distributed amongst these rows in the same way that extra size is distributed in step (b) above. (c) If, on the other hand, the allocated size is less than the requested size, the number of rows which are allowed to be SHRUNK is calculated, and an attempt is made to shrink the table until it fits within the requested space. IMPORTANT NOTE: this may not be successful. In this case, the table will bail and simply truncate its lower extremities. However, this shouldn't be necessary (cross fingers..) except in extreme circumstances..