Introduction
Bwahahahhah... My second article/library/program! This library (based on the ATL libraries and supporting the WTL libraries) will make the controls of your windows auto-sizing. They'll adapt to the size of the window.
The library is quite advanced... It supports transparent controls, nested groups of controls, controls that span multiple rows and columns, scrollable windows, auto-setting the minimum and maximum size of the window and many other things... BUT it's quite beta material... I haven't tested all the features in all the possible combinations.
The library requires VC++ (I have tested it with VC++ 8.0, but it should work with earlier versions... I'm not very sure how much earlier, because I use many "strange tricks" of VC++), ATL (probably at least 7.0) and it supports the WTL libraries (to compile the AutoSizeScroll you'll need a recent version of WTL. WTL 7.5 IS recent... Anything else IS NOT!)
Notes
If you are a purist of C++ you SHOUDN'T look at the library... I have done so many wrong things that you would become ill only by seeing them :-) I've used quite liberally the
_alloca
"function" even in the middle of array initialization, used the "," operator, and too many other "wrong" things... BUT I have commented all the main methods and constants with Doxygen, so you can "compile" the documentation (already compiled in .html and .chm format). The library doesn't use heap based memory. It only uses the stack.... And it uses it quite much... (no... you won't need megabytes of stack... Only a kilobyte or so probably)
How does the library work
(note that this image IS very similar to one of http://www.codeproject.com/dialog/EvaLayout.asp ... But plagiarism IS a form of flattery)
Observe that we have divided our window in cols and rows (the orange lines). Light gray rectangles are the ctrls of the window. The white rectangle is a ctrlless area.
Our ctrls can span multiple columns/rows (for example ctrl 6 and 9 span 2 and 3 columns, the 8 spans 2 rows).
A ctrl can even be an aggregated group of ctrls (a nested area) (see that under the 11-12-13-14 ctrls there is a light gray rectangle that spans three columns and two rows).
The aggregated group of ctrls can in turn be divided in columns and rows (3 columns and two rows, the dark grey rectangles). Now we will learn how to describe this to the library.
Using the library
You'll need to include atlautosizedlg.h
after the atlwin.h
include (probably in stdafx.h
). In the stdafx.h before the first #include
put this:
#define WINVER 0x0500
#define _WIN32_WINNT 0x0500
Then in the dlg/window class declaration add this:
class MyClass : public ..., public CAutoSizeWindow<MyClass>
BEGIN_WINDOW_MAP(MyClass, 10, 10, 8, 8)
WMB_HEAD( WMB_COL(60), WMB_COL(_exp), WMB_COL(25), WMB_COL(75)),
WMB_ROW(15, ID1, _, ID3, ID4),
WMB_ROW(15, ID5, ID6, _r, ID7),
WMB_ROW(15, ID8, ID9, _r, _r),
WMB_ROW(_exp, _d),
WMB_ROW(15, ID10),
WMB_END()
END_WINDOW_MAP()
What do we see? We see that we have to begin with a BEGIN_WINDOW_MAP()
. The first parameter is the name of the class, then we have a left/right margin, a top/down margin, a horizontal gap between ctrls and a vertical gap between controls. Then we have a column header. Each column is described in this format: WMB_COL(size)
.
REMEMBER: All the sizes can be expressed in Dialog Units (look in the MSDN for what a DLGUnit is, and remember that it's the measure unit used by the Visual Studio) or in Pixels. To use Pixels make the number negative. So 60
is 60 DLGUnits, -60
is 60 Pixels. If you have special flags to pass to macros you can do something like this: 60|FLAG1
or -60 ^ FLAG1
(you HAVE to use the XOR (^
) operator with negative numbers). For the empty ID2
we use a single underscore (_
) (or even a double underscore (__
) will work).
Note that not all the rows need to be "complete". The last row (the one with ID10
) is not complete and everything works.
We used _r
and _d
to make a ctrl span multiple columns and rows (_r
= right, _d
= down). _exp
means that instead of a fixed width/height the column/row will expand to be as large as possible.
We HAVEN'T included ctrls 11-14. Now we will include them... Instead of
WMB_ROW(_exp, _d),
WMB_ROW(15, ID10),
put this:
WMB_ROW(_exp, _d, WMB_HEAD( WMB_COL(35), WMB_COL(_exp), WMB_COL(30)),
WMB_ROW(_exp, ID12, ID13, ID14),
WMB_ROW(30, ID15, _r, _r),
WMB_END()),
_r, _r),
WMB_ROW(15, ID10, _d),
Note how the commas are used. There is nearly always a comma after a macro, unless the macro is the last parameter of another macro. The last WMB_END()
before END_WINDOW_MAP()
MUSTN'T have a comma. Note that to make a ctrl (or a group of ctrls) span multiple cols AND rows you do this:
IDCtrl, _r, _r,
_d, __, __,
_d, __, __
Under the _r
you don't need to add _d
or _r
... You can even put another ctrl (hint hint: group boxes with ctrls)
IDGroup, _r, _r, _r,
_d, ID1, ID2,
_d, ID3, ID4,
_d
The extra _r
and _d
are to give some space between the right margin of the ID2
and ID4
and the right margin of the group box.
To make everything work at the end of the BEGIN_MSG_MAP()
you must add:
BEGIN_MSG_MAP(MyClass)
...
CHAIN_MSG_MAP(CAutoSizeWindow<MyClass>)
END_MSG_MAP()
To make everything work perfectly you should activate the WS_CLIPCHILDREN
, WS_CLIPSIBLINGS
styles of the container window and give the transparent style to group boxes and IMAGE controls used as rectangles. Now everything should work...
Transparent controls
This library supports transparent Group Boxes and IMAGE controls used as rectangles. To activate this support add:
TRANSPARENT_LIST(MyClass, IDGroupBox1, IDImageCtrl1, IDGroupBox2, IDImageCtrl2)
before the BEGIN_WINDOW_MAP()
or after the END_WINDOW_MAP()
and remember to put the WS_EX_TRANSPARENT
extended style to the controls!!
Other tricks
There are too many "special" things you can do...
Column/rows sizes
- [
_auto
] Use the maximum width/height of the controls in the column/row as the size. No optional parameter
- [
_exp
] The column/row will be proportionally expanded. Optional parameter: "weight" of the column/row (DEFAULT: 100)
- [
_contr
] If all the other rows/columns are already maxed out, the remaining space will be divided proportionally between Contractable columns. Optional parameter: "weight" of the column/row (DEFAULT: 100)
- [
_eq
] The column/row will have the same width/height and the same min/max width/height of another column/row. Necessary parameter: the number of the column/row (zero based. The first column/row is the number 0)
- [
_gap
] The column/row will be GAP wide (useful for some tricks). Optional parameter: "extra" width/height ADDED to the column. Positive if DLGUnits, negative (remember the ^
) for Pixels
- [
_gapm
] The column/row will be GAP wide (useful for some tricks). Optional parameter: "extra" width/height SUBTRACTED (minimum 0) to the column. Positive if DLGUnits, negative (remember the ^
) for Pixels
- [
(nothing)
] The width/height of the column is fixed. Necessary parameter: the width/height of the column/row. Positive if DLGUnits, negative (remember the ^
) for Pixels. Note that you don't need to use WMSRC_FIXED
because it's 0
- [
_nog
] (this is a special flag that you have to add to the other flags). Do not prepend the usual gap before this column/row. The first column/row doesn't have a gap.
Cell expansion
- [
_r
] The ctrl on the left of this cell will continue in this cell
- [
_d
] The ctrl on the top of this cell will continue in this cell
- [
_
& __
] The cell is empty (you could directly use 0, but it would be more difficult to debug)
Minimum and maximum sizes of columns and rows
Instead of WMB_COL(size)
or WMB_ROW(size, ctrls...)
you can use other macros that will let you decide the minimum and maximum width/height of columns/rows.
These macros are named in a standard way: MIN
before MAX
, nothing means that the program will try to calc the value itself, NOMIN
or NOMAX
means that there isn't a minimum (the minimum is 0) or there isn't a maximum.
So we have WMB_COL
, WMB_COLMIN
, WMB_COLMAX
, WMB_COLMINMAX
, WMB_COLNOMIN
, WMB_COLNOMAX
, WMB_COLNOMINNOMAX
, WMB_COLNOMINMAX
, WMB_COLMINNOMAX
and the respective WMB_ROW*
the minimum and/or maximum value are given in this way:
WMB_COLMIN(sizeflag, minsize)
WMB_COLMAX(sizeflag, maxsize)
WMB_COLMINMAX(sizeflag, minsize, maxsize)
WMB_ROWMIN(sizeflag, minsize, ctrls...)
WMB_ROWMAX(sizeflag, maxsize, ctrls...)
WMB_ROWMINMAX(sizeflag, minsize, maxsize, ctrls...)
NOMIN
and NOMAX
modifiers don't need a parameter. So WMB_COLNOMIN(sizeflag)
, WMB_ROWNOMINMAX(sizeflag, maxsize, ctrls...)
... REMEMBER: All the sizes can be expressed in Dialog Units or in Pixels. To use Pixels make the number negative.
References
While I was too much lazy to really read them, this library is based on the pictures (meaning that I opened the page, watched the pictures and found that they were very beautiful and gave me the right direction) of:
(no, I'm not kidding... Initially I only wanted to create a macro based version of EvaLayout... (remember, I didn't truly read the article... my attention span was too much short in that period) So the 1.0 version of the library was born... Then I decided that I wanted nestable groups of ctrls... And, in the end, a strange hybrid of the two articles was born. But I was really too much lazy to read them... they were so long... So if you won't read this article completely I won't be angry with you :-) I'm not very sure I would read my article :-) )
Comparison with other similar libraries
I'm adding this section because some persons has asked for it. The world is FULL of libraries that move controls in a window. WTL has one. Paul DiLascia did one of the most famous in 2001. You can use whatever library you want. My life won't change. I'll even help you... Here there is a small selection: (the first one is the DiLascia's one, it's pure Windows API. The next three ones are MFC (I'm not sure, but they should be)... Perhaps they have ATL Support. The others are WTL (at least one is simply an explanation of the standard WTL library and another is a little expansion of the standard WTL library))
I HATE to compare my programs with the programs of other... I always think I'm sinning of pride when I do it. There are as many ways of doing things as there are programmers... Programs are not always better or worse... very often they are only different. If you can't see the differences in the libraries then you shouldn't program. If you don't have the time to select the right library for your program then you should choose one at random and hope it's the best one. There are persons that buy the first thing they see... There are others that try to discover the differences between similar products and then buy the better one/the cheaper one/the most balanced...
I CAN tell you what my library does:
- It's ATL/WTL (some libraries are MFC)
- It's MACRO based. The layout of the controls in the MACRO is similar (in a left-to-right, top-to bottom, rows are rows, cols are cols) to what will appear on the screen
- It's very fast. The matrix is read only once from the first to the last element (once for each OnSize event at least). No heap memory is allocated. API calls are limited and their results are cached. No extra memory is allocated by the initialization. For a single level ctrl group the matrix is big something like 21 + (3 * cols + 5 * rows + 1 * number of ctrls) integers (give or take one or two integers)
- It has a solution for group box flickering that supports the alt key in WinXP (in XP the accelerators are normally hidden unless you press the alt key. Then they are showed)
- It can do nearly all the layouts... some layouts are more difficult of others. You have to use intelligence to use this library... You need variable gaps? Put the standard gap at 0 and add empty rows/columns between your rows/columns. You need to align a ctrl to the left or the right of a bounding box? Add an empty expandable (or contractable) column to the left or to the right of the ctrl
I CAN even tell you what my library can't do:
- This is a library to move ctrls in a window. It isn't a window management library. I won't give you methods to save the position of the window in the registry. I won't give you grippers to resize the window. I won't give you scrollbars (but scrollbars ARE supported through
CScrollImpl
)
- The internal format of the matrix is a mess. The matrix is statically allocated so modifying directly it is not a good thing BUT you can give to the library another matrix: observe that all the methods have as a parameter the matrix.
- I won't give you a "30% of the total size" ctrl, because it isn't possible... You have a 5 pixel column and a 75% column and a 10 pixel width window. What happens? One of the two constraints can't be respected.
And finally I CAN tell you the main differences between libraries:
- Some are MACRO based (mine and Paul DiLascia's for example) others are class based (you add the controls to a class in the initialization of the window... Something like Handler += ctrl1; Handler += ctrl2; ... or there is a library where the layout is stored in strings that can even be saved in external files)
- Some libraries handle only the resizing of controls. They start from what you give them in the dialog editor and then expand/contract the controls proportionally. They can move the controls but they move them relatively to their initial position in the dialog editor (the WTL standard library for example and many others... Nearly all the non-grid based). Other libraries (mine and others) let you decide the position of the controls somewhere in the program. The dialog editor is used only to add the controls and modify their styles.
- Some are Windows API only, some are MFC, some are ATL/WTL (perhaps there are even MFC/ATL libraries)
History
- atlautosizedlg.h 1.0 Apr 2006 Initial Release (not published)
- atlautosizedlg.h 2.0 Jun 2006 Nearly rebuilt. Now supports multilevel
License
I�m a BSD guy, so I�ll license this library under the MIT license (a simplified BSD license).
Copyright (c) 2006 Massimiliano Alberti xanatos(at)geocities.com
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.