source: trunk/src/AtlAutosizeDlg.h @ 390

Revision 390, 75.8 KB checked in by Eoin, 12 years ago (diff)

Adding some WTL:: namespace prefixes.

Line 
1/** \mainpage
2 *      \subpage atlautosizedlg See atlautosizedlg for infos and the license of atlautosizedlg.h\n
3 */
4
5/** \page atlautosizedlg atlautosizedlg.h
6 *
7 *  \section License License
8 *  Copyright (c) 2006 Massimiliano Alberti <xanatos@geocities.com>
9 *
10 *  Permission is hereby granted, free of charge, to any person obtaining
11 *  a copy of this software and associated Subjectation files (the
12 *  "Software"), to deal in the Software without restriction, including
13 *  without limitation the rights to use, copy, modify, merge, publish,
14 *  distribute, sublicense, and/or sell copies of the Software, and to
15 *  permit persons to whom the Software is furnished to do so, subject
16 *  to the following conditions:
17 *
18 *  The above copyright notice and this permission notice shall be included
19 *  in all copies or substantial portions of the Software.
20 *
21 *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
22 *  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
23 *  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
24 *  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
25 *  CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
26 *  TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
27 *  SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
28 *
29 *  \section VersionHistory Version History
30 *  \li atlautosizedlg.h  1.0   Apr 2006  Initial Release
31 *  \li atlautosizedlg.h  2.0   Jun 2006  Nearly rebuilt. Now supports multilevel
32 *
33 *  \section TODO TODO
34 *
35 */
36
37/** \file
38 *  This header contains classes useful to reorder controls in a window
39 */
40
41#pragma once
42
43#ifndef __ATLAUTOSIZEDLG_H__
44#define __ATLAUTOSIZEDLG_H__
45
46#ifndef __ATLWIN_H__
47#error atlautosizedlg.h requires atlwin.h to be included first
48#endif
49
50#define TRACEAUTOSIZE
51
52//
53
54namespace ATL
55{
56
57//
58
59// #define TRACEAUTOSIZE ///< Define this to see in the Output window the tracing of the base size of the cols and rows
60// #define TRACEAUTOSIZE2 ///< Define this to see in the Output window the tracing of the calced size of the cols and rows
61
62//
63
64/// \name Transparent ctrls (Group Boxes and Static Controls)
65/*@{*/
66
67/// This "facility" is used to make the redraw of transparent controls (only Group Boxes and Static Controls) smoother.
68/** Simply list the IDs of the controls in the ... part of the TRANSPARENT_LIST()
69 *  \param theClass Name of the class using the facility
70 *  \param ... List of IDs of controls that are transparent. They'll be redrawn in a special way
71 */
72#define TRANSPARENT_LIST(theClass, ...) \
73        BOOL HandleTransparentMap(WTL::CDCHandle dc = NULL) \
74        { \
75                int tcCtrls[] = {0, __VA_ARGS__, INT_MAX}; \
76                if (dc) { \
77                        int *ptcCtrl = tcCtrls + 1; \
78                        while (*ptcCtrl != INT_MAX) { \
79                                DrawTransparentCtrl(dc, *ptcCtrl); \
80                                ptcCtrl++; \
81                        } \
82                } else { \
83                        int *ptcCtrl = tcCtrls + 1; \
84                        while (*ptcCtrl != INT_MAX) { \
85                                InitializeTransparentCtrl(*ptcCtrl); \
86                                ptcCtrl++; \
87                        } \
88                } \
89                return TRUE; \
90        }
91
92/// The main "facility" to control the positioning and sizing of the ctrls.
93/** The BEGIN_WINDOW_MAP() MUST be paired by a END_WINDOW_MAP().
94 *  \param theClass Name of the class using the facility
95 *  \param ... In order: LeftRightBorder, TopBottomBorder, HorizontalGap, VerticalGap. Positive if DLGUnits, negative for Pixels
96 */
97 
98#define BEGIN_WINDOW_MAP_INLINE(theClass, /*LeftRightBorder, TopBottomBorder, HGap, VGap*/...) \
99        ATLASSERT(sizeof(int) == sizeof(theClass::CCtrlCounter) && "\"Strange\" compiler. The library is not compatible"); \
100                CRowsIndex *p = NULL; p; \
101                const int _auto = WMSRC_AUTO, _exp = WMSRC_EXPANDABLE, _contr = WMSRC_CONTRACTABLE, _eq = WMSRC_EQUAL, _gap = WMSRC_GAP, _gapm = WMSRC_GAPM, _nog = WMSRC_NOGAP, _ = WMSCTRL_EMPTY, __ = WMSCTRL_EMPTY, _r = WMSCTRL_EXPRIGHT, _d = WMSCTRL_EXPDOWN; \
102                _auto; _exp; _contr; _eq; _gap, _gapm, _nog; _; __; _r; _d; \
103                static CCtrlCounter s_iCtrls[] = {0, _FirstParam(__VA_ARGS__), _SecondParam(__VA_ARGS__), _ThirdParam(__VA_ARGS__), _FourthParam(__VA_ARGS__),
104
105#define BEGIN_WINDOW_MAP(theClass, /*LeftRightBorder, TopBottomBorder, HGap, VGap*/...) \
106        static CWindowMapStruct* GetWindowMap() \
107        { \
108                ATLASSERT(sizeof(int) == sizeof(CCtrlCounter) && "\"Strange\" compiler. The library is not compatible"); \
109                CRowsIndex *p = NULL; p; \
110                const int _auto = WMSRC_AUTO, _exp = WMSRC_EXPANDABLE, _contr = WMSRC_CONTRACTABLE, _eq = WMSRC_EQUAL, _gap = WMSRC_GAP, _gapm = WMSRC_GAPM, _nog = WMSRC_NOGAP, _ = WMSCTRL_EMPTY, __ = WMSCTRL_EMPTY, _r = WMSCTRL_EXPRIGHT, _d = WMSCTRL_EXPDOWN; \
111                _auto; _exp; _contr; _eq; _gap, _gapm, _nog; _; __; _r; _d; \
112                static CCtrlCounter s_iCtrls[] = {0, _FirstParam(__VA_ARGS__), _SecondParam(__VA_ARGS__), _ThirdParam(__VA_ARGS__), _FourthParam(__VA_ARGS__),
113
114/// "Footer" of the Window Map.
115#define END_WINDOW_MAP_INLINE() \
116                }; ATLASSERT(!p); \
117                return (CWindowMapStruct*)s_iCtrls;
118               
119               
120/// "Footer" of the Window Map.
121#define END_WINDOW_MAP() \
122                }; ATLASSERT(!p); \
123                return (CWindowMapStruct*)s_iCtrls; \
124        }
125
126
127/*@}*/
128
129//
130
131/// \name Ctrl group header and footer
132/*@{*/
133
134/// "Header" of a rect ctrl group. MUST be paired with a WMB_END()
135/** \param ... List of WMB_COL() columns comma separated
136 */
137#define WMB_HEAD(...)   (_Init(p, (CRowsIndex*)_alloca(sizeof(CRowsIndex))), _Init(p, (CRowsIndex*)_alloca(sizeof(CRowsIndex))), _Init(p, (CRowsIndex*)_alloca(sizeof(CRowsIndex))), WMH_BEGIN), \
138                                                        CCtrlCounter(p->m_pPrev->m_pPrev) /* Size */, CCtrlCounter(p->m_pPrev) /* NumRows */, 0 /*NumCtrls*/, \
139                                                        0 /*ColWidthFixed*/, 0 /*ColWidthMin*/, 0 /*ColWidthMax*/, 0 /*ColExpand*/, 0 /*ColContract*/, \
140                                                        0 /*RowHeightFixed*/, 0 /*RowHeightMin*/, 0 /*RowHeightMax*/, 0 /*RowExpand*/, 0 /*RowContract*/, \
141                                                        CCtrlCounter(p) /* NumCols */, __VA_ARGS__, CCtrlCounter(p, 1, 3, WMH_END)
142
143/// "Footer" of a rect ctrl group. MUST be paired with a WMB_HEAD()
144#define WMB_END()               CCtrlCounter(p, -1, 1, _DeInit(p, WM_END))
145
146/*@}*/
147
148//
149
150/// \name Ctrl group Cols
151/*@{*/
152
153/// Auto-min and auto-max column. To be used with WMB_HEAD()
154/** \param _size The size and type of the column. For example WMSRC_AUTO/_auto or WMSRC_EXPANDABLE/_exp
155 */
156#define WMB_COL(_size)                                                  _size, WMSRCMM_SIZECALC, WMSRCMM_SIZECALC
157
158/// Fixed-min and auto-max column. To be used with WMB_HEAD()
159/** \param _size The size and type of the column. For example WMSRC_AUTO/_auto or WMSRC_EXPANDABLE/_exp
160 *      \param _min Min-size of the column. Positive if DLGUnits, negative for Pixels
161 */
162#define WMB_COLMIN(_size, _min)                                 _size, _min, WMSRCMM_SIZECALC
163
164/// Auto-min and fixed-max column. To be used with WMB_HEAD()
165/** \param _size The size and type of the column. For example WMSRC_AUTO/_auto or WMSRC_EXPANDABLE/_exp
166 *      \param _max Max-size of the column. Positive if DLGUnits, negative for Pixels
167 */
168#define WMB_COLMAX(_size, _max)                                 _size, WMSRCMM_SIZECALC, _max
169
170/// Fixed-min and fixed-max column. To be used with WMB_HEAD()
171/** \param _size The size and type of the column. For example WMSRC_AUTO/_auto or WMSRC_EXPANDABLE/_exp
172 *      \param _min Min-size of the column. Positive if DLGUnits, negative for Pixels
173 *      \param _max Max-size of the column. Positive if DLGUnits, negative for Pixels
174 */
175#define WMB_COLMINMAX(_size, _min, _max)                _size, _min, _max
176
177/// 0-min and auto-max column. To be used with WMB_HEAD()
178/** \param _size The size and type of the column. For example WMSRC_AUTO/_auto or WMSRC_EXPANDABLE/_exp
179 */
180#define WMB_COLNOMIN(_size)                                             _size, 0, WMSRCMM_SIZECALC
181
182/// Auto-min and infinite-max column. To be used with WMB_HEAD()
183/** \param _size The size and type of the column. For example WMSRC_AUTO/_auto or WMSRC_EXPANDABLE/_exp
184 */
185#define WMB_COLNOMAX(_size)                                             _size, WMSRCMM_SIZECALC, WMSRCMM_MAXVAL
186
187/// 0-min and infinite-max column. To be used with WMB_HEAD()
188/** \param _size The size and type of the column. For example WMSRC_AUTO/_auto or WMSRC_EXPANDABLE/_exp
189 */
190#define WMB_COLNOMINNOMAX(_size)                                _size, 0, WMSRCMM_MAXVAL
191
192/// Fixed-min and infinite-max column. To be used with WMB_HEAD()
193/** \param _size The size and type of the column. For example WMSRC_AUTO/_auto or WMSRC_EXPANDABLE/_exp
194 *      \param _min Min-size of the column. Positive if DLGUnits, negative for Pixels
195 */
196#define WMB_COLMINNOMAX(_size, _min)                    _size, _min, WMSRCMM_MAXVAL
197
198/// 0-min and fixed-max column. To be used with WMB_HEAD()
199/** \param _size The size and type of the column. For example WMSRC_AUTO/_auto or WMSRC_EXPANDABLE/_exp
200 *      \param _max Max-size of the column. Positive if DLGUnits, negative for Pixels
201 */
202#define WMB_COLNOMINMAX(_size, _max)                    _size, 0, _max
203/*@}*/
204
205//
206
207/// \name Ctrl group Rows
208/*@{*/
209
210/// Auto-min and auto-max row. To be used with WMB_HEAD()
211/** \param _size The size and type of the row. For example WMSRC_AUTO/_auto or WMSRC_EXPANDABLE/_exp
212 *  \param ... Comma separated list of IDs if ctrls (or WMB_HEAD()/WMB_END() ctrl groups, or WMSCTRL_EMPTY/_/__ or WMSCTRL_EXPRIGHT/_r or WMSCTRL_EXPDOWN/_d)
213 */
214#define WMB_ROW(_size, ...)                                             (_IncRow(p), WMR_BEGIN), _size, WMSRCMM_SIZECALC, WMSRCMM_SIZECALC, __VA_ARGS__, WMR_END
215
216/// Fixed-min and auto-max row. To be used with WMB_HEAD()
217/** \param _size The size and type of the row. For example WMSRC_AUTO/_auto or WMSRC_EXPANDABLE/_exp
218 *      \param _min Min-size of the row. Positive if DLGUnits, negative for Pixels
219 *  \param ... Comma separated list of IDs if ctrls (or WMB_HEAD()/WMB_END() ctrl groups, or WMSCTRL_EMPTY/_/__ or WMSCTRL_EXPRIGHT/_r or WMSCTRL_EXPDOWN/_d)
220 */
221#define WMB_ROWMIN(_size, _min, ...)                    (_IncRow(p), WMR_BEGIN), _size, _min, WMSRCMM_SIZECALC, __VA_ARGS__, WMR_END
222
223/// Auto-min and fixed-max row. To be used with WMB_HEAD()
224/** \param _size The size and type of the row. For example WMSRC_AUTO/_auto or WMSRC_EXPANDABLE/_exp
225 *      \param _max Max-size of the row. Positive if DLGUnits, negative for Pixels
226 *  \param ... Comma separated list of IDs if ctrls (or WMB_HEAD()/WMB_END() ctrl groups, or WMSCTRL_EMPTY/_/__ or WMSCTRL_EXPRIGHT/_r or WMSCTRL_EXPDOWN/_d)
227 */
228#define WMB_ROWMAX(_size, _max, ...)                    (_IncRow(p), WMR_BEGIN), _size, WMSRCMM_SIZECALC, _max, __VA_ARGS__, WMR_END
229
230/// Fixed-min and fixed-max row. To be used with WMB_HEAD()
231/** \param _size The size and type of the row. For example WMSRC_AUTO/_auto or WMSRC_EXPANDABLE/_exp
232 *      \param _min Min-size of the row. Positive if DLGUnits, negative for Pixels
233 *      \param _max Max-size of the row. Positive if DLGUnits, negative for Pixels
234 *  \param ... Comma separated list of IDs if ctrls (or WMB_HEAD()/WMB_END() ctrl groups, or WMSCTRL_EMPTY/_/__ or WMSCTRL_EXPRIGHT/_r or WMSCTRL_EXPDOWN/_d)
235 */
236#define WMB_ROWMINMAX(_size, _min, _max, ...)   (_IncRow(p), WMR_BEGIN), _size, _min, _max, __VA_ARGS__, WMR_END
237
238/// 0-min and auto-max row. To be used with WMB_HEAD()
239/** \param _size The size and type of the row. For example WMSRC_AUTO/_auto or WMSRC_EXPANDABLE/_exp
240 *  \param ... Comma separated list of IDs if ctrls (or WMB_HEAD()/WMB_END() ctrl groups, or WMSCTRL_EMPTY/_/__ or WMSCTRL_EXPRIGHT/_r or WMSCTRL_EXPDOWN/_d)
241 */
242#define WMB_ROWNOMIN(_size, ...)                                                (_IncRow(p), WMR_BEGIN), _size, 0, WMSRCMM_SIZECALC, __VA_ARGS__, WMR_END
243
244/// Auto-min and infinite-max row. To be used with WMB_HEAD()
245/** \param _size The size and type of the row. For example WMSRC_AUTO/_auto or WMSRC_EXPANDABLE/_exp
246 *  \param ... Comma separated list of IDs if ctrls (or WMB_HEAD()/WMB_END() ctrl groups, or WMSCTRL_EMPTY/_/__ or WMSCTRL_EXPRIGHT/_r or WMSCTRL_EXPDOWN/_d)
247 */
248#define WMB_ROWNOMAX(_size, ...)                                                (_IncRow(p), WMR_BEGIN), _size, WMSRCMM_SIZECALC, WMSRCMM_MAXVAL, __VA_ARGS__, WMR_END
249
250/// 0-min and infinite-max row. To be used with WMB_HEAD()
251/** \param _size The size and type of the row. For example WMSRC_AUTO/_auto or WMSRC_EXPANDABLE/_exp
252 *  \param ... Comma separated list of IDs if ctrls (or WMB_HEAD()/WMB_END() ctrl groups, or WMSCTRL_EMPTY/_/__ or WMSCTRL_EXPRIGHT/_r or WMSCTRL_EXPDOWN/_d)
253 */
254#define WMB_ROWNOMINNOMAX(_size, ...)                           (_IncRow(p), WMR_BEGIN), _size, 0, WMSRCMM_MAXVAL, __VA_ARGS__, WMR_END
255
256/// Fixed-min and infinite-max row. To be used with WMB_HEAD()
257/** \param _size The size and type of the row. For example WMSRC_AUTO/_auto or WMSRC_EXPANDABLE/_exp
258 *      \param _min Min-size of the row. Positive if DLGUnits, negative for Pixels
259 *  \param ... Comma separated list of IDs if ctrls (or WMB_HEAD()/WMB_END() ctrl groups, or WMSCTRL_EMPTY/_/__ or WMSCTRL_EXPRIGHT/_r or WMSCTRL_EXPDOWN/_d)
260 */
261#define WMB_ROWMINNOMAX(_size, _min, ...)                       (_IncRow(p), WMR_BEGIN), _size, _min, WMSRCMM_MAXVAL, __VA_ARGS__, WMR_END
262
263/// 0-min and fixed-max row. To be used with WMB_HEAD()
264/** \param _size The size and type of the row. For example WMSRC_AUTO/_auto or WMSRC_EXPANDABLE/_exp
265 *      \param _max Max-size of the row. Positive if DLGUnits, negative for Pixels
266 *  \param ... Comma separated list of IDs if ctrls (or WMB_HEAD()/WMB_END() ctrl groups, or WMSCTRL_EMPTY/_/__ or WMSCTRL_EXPRIGHT/_r or WMSCTRL_EXPDOWN/_d)
267 */
268#define WMB_ROWNOMINMAX(_size, _max, ...)                       (_IncRow(p), WMR_BEGIN), _size, 0, _max, __VA_ARGS__, WMR_END
269
270/*@}*/
271
272//
273
274/// \name User constants (format of columns/rows)
275/*@{*/
276#define WMSRC_AUTO                              0x40000000L             ///< [_auto] Use the maximum width/height of the controls in the column/row as the size. No optional parameter
277#define WMSRC_EXPANDABLE                0x30000000L             ///< [_exp] The column/row will be proportionally expanded. Optional parameter: "weight" of the column/row (DEFAULT: 100)
278#define WMSRC_CONTRACTABLE              0x20000000L             ///< [_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)
279#define WMSRC_EQUAL                             0x10000000L             ///< [_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)
280#define WMSRC_GAP                               0x07000000L             ///< [_gap] The column/row will be GAP wide (usefull for some tricks). Optional parameter: "extra" width/height ADDED to the column. Positive if DLGUnits, negative (remember the ^) for Pixels
281#define WMSRC_GAPM                              0x06000000L             ///< [_gapm] The column/row will be GAP wide (usefull for some tricks). Optional parameter: "extra" width/height SUBTRACTED (minimum 0) to the column. Positive if DLGUnits, negative (remember the ^) for Pixels
282#define WMSRC_FIXED                             0x00000000L             ///< [(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
283
284#define WMSRC_NOGAP                             0x08000000L             ///< [_nog] (this is a special flag 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
285/*@}*/
286
287/// \name Internal constants (format of columns/rows)
288/*@{*/
289#define WMSRC_TYPEMASK                  0x77000000L             ///< Extracts the Type of a column/row descriptor
290#define WMSRC_EXSTYLEMASK               0x08000000L             ///< Extracts the Extended Style (WMSRC_NOGAP) of a column/row descriptor
291#define WMSRC_VALMASK                   0x80FFFFFFL             ///< Extracts the Parameter of a column/row descriptor. Note that if the parameter is negative then extra care will be needed for the Type and ExStyle
292
293//
294
295#define WMSRCMM_SIZECALC                        0x40000000L             ///< The minimum and/or maximum width/height of a column/row will be auto-calced by the library
296#define WMSRCMM_NEEDCALC                        0x20000000L             ///< Internally used!
297
298#define WMSRCMM_TYPEMASK                        0x70000000L             ///< Extracts the Type of a min/max column/row descriptor
299#define WMSRCMM_VALMASK                         0x8FFFFFFFL             ///< Extracts the Value of a min/max column/row descriptor. Positive if DLGUnits, negative (remember the ^) for Pixels
300
301#define WMSRCMM_MAXVAL                          0x0FFFFFFFL             ///< The maximum width/height of a min/max column/row descriptor ("infinite" width/height)
302
303//
304
305#define WMSRC_DEFEXPANDABLEVAL          100                     ///< The default Expandable "weight"
306#define WMSRC_DEFCONTRACTABLEVAL        100                     ///< The default Contractable "weight"
307/*@}*/
308
309//
310
311/// \name Internally used signatures
312/*@{*/
313#define WMH_BEGIN                       0xFFFFFFFFL             ///< Header Begin
314#define WMH_END                         0xFFFFFFFEL             ///< Header End
315
316#define WMR_BEGIN                       0xFFFFFFFDL             ///< Row Begin
317#define WMR_END                         0xFFFFFFFCL             ///< Row End
318
319#define WM_END                          0xFFFFFFFBL             ///< Ctrl Group End
320/*@}*/
321
322//
323
324/// \name User constants (cell format)
325/*@{*/
326#define WMSCTRL_EXPRIGHT                0x40000001L             ///< [_r] The ctrl on the left of this cell will continue in this cell
327#define WMSCTRL_EXPDOWN                 0x40000002L             ///< [_d] The ctrl on the top of this cell will continue in this cell
328
329#define WMSCTRL_EMPTY                   0x00000000L             ///< [_ & __] The cell is empty (you could directly use 0, but it would be more ugly to debug)
330/*@}*/
331
332/// \name Internal constants (cell format)
333/*@{*/
334#define WMSCTRL_CONTINUEMASK    0x40000000L             ///< "continue" mask (can be used to check for a continue)
335
336#define WMSCTRL_TYPEMASK                0x70000000L             ///< Extracts the Type of a ctrl
337#define WMSCTRL_VALMASK                 0x8FFFFFFFL             ///< Extracts the ID of a ctrl
338/*@}*/
339
340//
341
342/// A no overflow integer class
343/** It's probably quite slow because I wasn't able to use the overflow
344 *  flag of the processor so I had to use int64s. I hope the compiler
345 *  will optimize it. The class has the same size as an int and is an int
346 *  with some operators overloaded. Only sums, subtractions and comparisons
347 *  are supported.
348 */
349class int_no
350{
351public:
352        int m_iVal;             ///< The integer value
353
354public:
355        /// Constructor
356        /** \param iVal Base value
357         */
358        int_no(int iVal = 0) : m_iVal(iVal)
359        {
360        }
361
362        /// Pointer to the integer
363        operator int*()
364        {
365                return &m_iVal;
366        }
367
368        /// Reference to the integer
369        operator int&() 
370        {
371                return m_iVal;
372        }
373
374        /// "=" operator
375        /** \param iVal New value
376         */
377        int_no& operator=(int iVal)
378        {
379                m_iVal = iVal;
380                return *this;
381        }
382
383        /// Equal operator
384        /** \param iVal Value to be compared with
385         */
386        bool operator ==(int iVal) const
387        {
388                return m_iVal == iVal;
389        }
390
391        /// Unequal operator
392        /** \param iVal Value to be compared with
393         */
394        bool operator !=(int iVal) const
395        {
396                return m_iVal != iVal;
397        }
398
399        /// Greater than operator
400        /** \param iVal Value to be compared with
401         */
402        bool operator >(int iVal) const
403        {
404                return m_iVal > iVal;
405        }
406
407        /// Greater-or-equal operator
408        /** \param iVal Value to be compared with
409         */
410        bool operator >=(int iVal) const
411        {
412                return m_iVal >= iVal;
413        }
414
415        /// Lesser than operator
416        /** \param iVal Value to be compared with
417         */
418        bool operator <(int iVal) const
419        {
420                return m_iVal < iVal;
421        }
422
423        /// Lesser-or-equal operator
424        /** \param iVal Value to be compared with
425         */
426        bool operator <=(int iVal) const
427        {
428                return m_iVal <= iVal;
429        }
430
431        /// Add to the integer
432        /** \param iVal Value to be added
433         */
434        int_no& operator+=(int iVal)
435        {
436                __int64 iTmp = (__int64)m_iVal + iVal;
437
438                if (iTmp > INT_MAX) {
439                        m_iVal = INT_MAX;
440                } else if (iTmp < INT_MIN) {
441                        m_iVal = INT_MIN;
442                } else {
443                        m_iVal = (int)iTmp;
444                }
445
446                return *this;
447        }
448
449        /// Subtract from the integer
450        /** \param iVal Value to be subtracted
451         */
452        int_no& operator-=(int iVal)
453        {
454                return operator-=(0 - iVal);
455        }       
456
457        /// Add operator
458        /** \param iVal Value to be added
459         */
460        const int operator+(int iVal) const
461        {
462                int_no iRes = *this;
463                iRes += iVal;
464                return iRes;
465        }
466
467        /// Subtract operator
468        /** \param iVal Value to be subtracted
469         */
470        const int operator-(int iVal) const
471        {
472                return operator+(0 - iVal);
473        }
474};
475
476//
477
478/// The main class for the positioning and sizing of the ctrls.
479/** You MUST derive your class from this class. You CAN derive your class from CScrollImpl.
480 *  You MUST chain this class to the BEGIN_MSG_MAP()/END_MSG_MAP(). You SHOULD chain this class
481 *  before chaining CScrollImpl. You MUST remember to use the full name CAutoSizeWindow<T, ...> when
482 *  using methods (hint: DoPaint) present in multiple base classes.
483 *  You MUST manually call CAutoSizeWindow<T, ...>::DoPaint() from T::DoPaint() if you derive your class
484 *  from CScrollImpl. You MUST let the handling of some messages proceed and not stop it unless you know
485 *  what you are doing. This class processes WM_CREATE/WM_INITDIALOG, WM_GETMINMAXINFO, WM_PAINT, WM_SIZE.
486 *  Note that if you want to handle WM_PAINT you MUST use a T::DoPaint method. This class will stop the
487 *  handling of the WM_PAINT message.
488 *  \param T The name of the derived class
489 *  \param t_bAutoMinSize If true this class will automatically handle the minimum and maximum size of the window
490 */
491template <class T, bool t_bAutoMinSize = true>
492class CAutoSizeWindow
493{
494protected: 
495        typedef CAutoSizeWindow<T> thisClass; ///< A shortcut to the complete name of this class
496
497public:
498#pragma pack(push, 4)
499        /// The margins/gaps of the window
500        struct CMargins
501        {
502                int m_iLeftRight;
503                int m_iTopBottom;
504                int m_iXGap;
505                int m_iYGap;
506        };
507
508        /// The ctrl group
509        struct CCtrlGroup
510        {
511                int m_iSignature;
512
513                int m_iSize;
514                int m_iNumRows;
515                int m_iNumCtrls;
516                int m_iColWidthFixed;
517                int m_iColWidthMin;
518                int m_iColWidthMax;
519                int m_iColExpand;
520                int m_iColContract;
521
522                int m_iRowHeightFixed;
523                int m_iRowHeightMin;
524                int m_iRowHeightMax;
525                int m_iRowExpand;
526                int m_iRowContract;
527
528                int m_iNumCols;
529
530                int m_iCtrls[1];
531        };
532
533        /// The "container" for the main ctrl group
534        struct CWindowMapStruct
535        {
536                int m_iSignature;
537                CMargins m_margins;
538                CCtrlGroup m_header;
539        };
540#pragma pack(pop)
541
542        TRANSPARENT_LIST(CAutoSizeWindow<T>); ///< Empty transparent list
543
544protected:
545        struct CCtrlCounter;
546
547        /// Support struct of CCtrlCounter. It's built to be a linked list (each element points to the previous one)
548        struct CRowsIndex
549        {
550                CCtrlCounter *m_piNum;
551                CRowsIndex *m_pPrev;
552        };
553
554        /// Multiple "templated" static-based counter. t_iType is the Counter number
555        /** \return Counter value
556         */
557        template<int t_iType>
558        int Func()
559        {
560                static int i = 0;
561                i++;
562               
563                return i;
564        }
565
566        /// This "class" counts the number of controls of a ctrl group. It uses an external CRowsIndex to support itself
567        struct CCtrlCounter
568        {
569                int m_iID;
570
571                CCtrlCounter(int iID) : m_iID(iID)
572                {
573                }
574
575                CCtrlCounter(CRowsIndex* pri) : m_iID(0)
576                {
577                        pri->m_piNum = this;
578                }
579
580                CCtrlCounter(CRowsIndex *&pcn, int iAdder, int iDiv, int iID) : m_iID(iID)
581                {
582                        pcn->m_piNum->m_iID = (int)(this - pcn->m_piNum) - iAdder;
583                        ATLASSERT(pcn->m_piNum->m_iID % iDiv == 0 && _T("Are you forgetting a WMB_COL()?"));
584                        pcn->m_piNum->m_iID /= iDiv;
585                        pcn = pcn->m_pPrev;
586                }
587
588                const CCtrlCounter operator++()
589                {
590                        m_iID++;
591                        return *this;
592                }
593
594                const CCtrlCounter operator++(int)
595                {
596                        const CCtrlCounter tmp(*this); 
597                        ++(*this); 
598                        return tmp; 
599                }
600
601                operator int()
602                {
603                        return m_iID;
604                }
605        };
606
607public:
608        BEGIN_MSG_MAP(CAutoSizeWindow)
609                MESSAGE_HANDLER(WM_CREATE, OnCreate)
610                MESSAGE_HANDLER(WM_INITDIALOG, OnCreate)
611                if (t_bAutoMinSize) {
612                        MESSAGE_HANDLER(WM_GETMINMAXINFO, OnGetMinMaxInfo)
613                }
614                MESSAGE_HANDLER(WM_SIZE, OnSize)
615                MESSAGE_HANDLER(WM_PAINT, OnPaint)
616        END_MSG_MAP()
617
618public:
619        LRESULT OnCreate(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled)
620        {
621                T* pT = static_cast<T*>(this);
622                if (!pT->CtrlsInitialize()) {
623                        ATLTRACE(_T("Not initialized.\n"));
624                } 
625
626                __if_not_exists(T::GetScrollOffset) {
627                        else if (t_bAutoMinSize) {
628                                SIZE sizeMin, sizeMax;
629       
630                                pT->GetMinMaxSize(sizeMin, sizeMax);
631       
632                                RECT rectNew = {0, 0};
633
634                                RECT rectClient;
635                                pT->GetClientRect(&rectClient);
636
637                                if (rectClient.right < sizeMin.cx) {
638                                        rectNew.right = sizeMin.cx;
639                                } else if (rectClient.right > sizeMax.cy) {
640                                        rectNew.right = sizeMax.cx;
641                                } else {
642                                        rectNew.right = rectClient.right;
643                                }
644
645                                if (rectClient.bottom < sizeMin.cy) {
646                                        rectNew.bottom = sizeMin.cy;
647                                } else if (rectClient.bottom > sizeMax.cy) {
648                                        rectNew.bottom = sizeMax.cy;
649                                } else {
650                                        rectNew.bottom = rectClient.bottom;
651                                }
652
653                                if (rectNew.right != rectClient.right || rectNew.bottom != rectClient.bottom) {
654                                        RECT rectWindow;
655                                        pT->GetWindowRect(&rectWindow);
656                                        pT->MapWindowPoints(NULL, (LPPOINT)&rectNew, 2);
657
658                                        rectNew.right += rectWindow.right - rectWindow.left - rectNew.right + rectNew.left;
659                                        rectNew.bottom += rectWindow.bottom - rectWindow.top - rectNew.bottom + rectNew.top;
660
661                                        pT->SetWindowPos(NULL, 0, 0, rectNew.right - rectNew.left, rectNew.bottom - rectNew.top, SWP_NOACTIVATE|SWP_NOOWNERZORDER|SWP_NOZORDER|SWP_NOMOVE);
662                                }
663                        }
664                }
665
666                bHandled = FALSE;
667                return 0;
668        }
669
670        LRESULT OnGetMinMaxInfo(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& /*bHandled*/)
671        {
672                MINMAXINFO *pMinMax = (MINMAXINFO*)lParam;
673
674                T* pT = static_cast<T*>(this);
675
676                SIZE sizeMin, sizeMax;
677
678                pT->GetMinMaxSize(sizeMin, sizeMax);
679
680                RECT rectWindow, rectClient;
681                pT->GetWindowRect(&rectWindow);
682                pT->GetClientRect(&rectClient);
683                pT->MapWindowPoints(NULL, (LPPOINT)&rectClient, 2);
684
685                __if_not_exists(T::GetScrollOffset) {
686                        pMinMax->ptMinTrackSize.x = sizeMin.cx + rectWindow.right - rectWindow.left - rectClient.right + rectClient.left;
687                        pMinMax->ptMinTrackSize.y = sizeMin.cy + rectWindow.bottom - rectWindow.top - rectClient.bottom + rectClient.top;
688                }
689               
690                if (pMinMax->ptMaxTrackSize.x > sizeMax.cx) {
691                        pMinMax->ptMaxTrackSize.x = sizeMax.cx;
692                }
693
694                if (pMinMax->ptMaxTrackSize.y > sizeMax.cy) {
695                        pMinMax->ptMaxTrackSize.y = sizeMax.cy;
696                }
697
698                if (pMinMax->ptMaxSize.x > sizeMax.cx) {
699                        pMinMax->ptMaxSize.x = sizeMax.cx;
700                }
701
702                if (pMinMax->ptMaxSize.y > sizeMax.cy) {
703                        pMinMax->ptMaxSize.y = sizeMax.cy;
704                }
705
706                return 0;
707        }
708
709        LRESULT OnSize(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled)
710        {
711                if (!wParam) {
712                        T* pT = static_cast<T*>(this);
713                        pT->CtrlsArrange();
714                }
715
716                bHandled = FALSE;
717                return 0;
718        }
719
720        LRESULT OnPaint(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& /*bHandled*/)
721        {
722                T* pT = static_cast<T*>(this);
723
724                POINT pt = {0};
725                __if_exists(T::GetScrollOffset) {
726                        pT->GetScrollOffset(pt);
727                }
728
729                if(wParam != NULL) {
730                        WTL::CDCHandle dc = (HDC)wParam;
731                        dc.SetViewportOrg(-pt.x, -pt.y);
732                        pT->DoPaint(dc);
733                } else {
734                        WTL::CPaintDC dc(pT->m_hWnd);
735                        dc.SetViewportOrg(-pt.x, -pt.y);
736                        pT->DoPaint(dc.m_hDC);
737                }
738               
739                return 0;
740        }
741       
742        //
743
744        /// Initializes the window.
745        /** \param piCtrls Ctrls map
746         *  \param bForce Force the initialization (the window will be reinitialized if already initialized)
747         *  \return TRUE if successful, FALSE if failed
748         */
749        BOOL CtrlsInitialize(CWindowMapStruct *piCtrls = T::GetWindowMap(), BOOL bForce = FALSE)
750        {
751                if (piCtrls->m_iSignature && !bForce) {
752                        return TRUE;
753                }
754
755                T* pT = static_cast<T*>(this);
756
757                if (!pT->m_hWnd) {
758                        ATLTRACE(_T("Window not initialized.\n"));
759                        return FALSE;
760                }
761
762#ifdef DEBUG
763                if (!pT->IsWindow()) {
764                        ATLTRACE(_T("Window not initialized.\n"));
765                        return FALSE;
766                }
767#endif
768
769                if (!piCtrls->m_iSignature) {
770                        pT->HandleTransparentMap();
771                }
772
773                RECT rectUnits = {4, 8, 0, 0};
774                ATLVERIFY(pT->MapDialogRect(&rectUnits));
775                LONG lXUnits = rectUnits.left, lYUnits = rectUnits.top;
776
777                CMargins marginsPix;
778                _CheckMargins(lXUnits, 4, lYUnits, 8, &piCtrls->m_margins, &marginsPix);
779
780                BOOL bRes;
781                ATLVERIFY((bRes = pT->_CtrlsInitialize(&piCtrls->m_header, &marginsPix, lXUnits, lYUnits)) != FALSE);
782                if (bRes) {
783                        piCtrls->m_iSignature = 1;
784                        return TRUE;
785                } else {
786                        return FALSE;
787                }
788        }
789
790        /// Arranges the ctrls of the window. Initializes the window if necessary
791        /** \param piCtrls Ctrls map
792         *  \return TRUE if successful, FALSE if failure
793         */
794        BOOL CtrlsArrange(CWindowMapStruct *piCtrls = T::GetWindowMap())
795        {
796                T* pT = static_cast<T*>(this);
797
798                if (!pT->CtrlsInitialize(piCtrls)) {
799                        ATLTRACE(_T("Not initialized.\n"));
800                        return FALSE;
801                }
802
803                RECT rectUnits = {4, 8, 0, 0};
804                ATLVERIFY(pT->MapDialogRect(&rectUnits));
805                LONG lXUnits = rectUnits.left, lYUnits = rectUnits.top;
806
807                RECT rect;
808                ATLVERIFY(pT->GetClientRect(&rect));
809
810                CMargins marginsPix;
811                _CheckMargins(lXUnits, 4, lYUnits, 8, &piCtrls->m_margins, &marginsPix);
812
813                rect.right = (rect.right > marginsPix.m_iLeftRight ? rect.right - marginsPix.m_iLeftRight : 0);
814                rect.bottom = (rect.bottom > marginsPix.m_iTopBottom ? rect.bottom - marginsPix.m_iTopBottom : 0);
815
816                CCtrlGroup *pheader = &piCtrls->m_header;
817
818                if (rect.right < pheader->m_iColWidthMin) {
819                        rect.right = pheader->m_iColWidthMin;
820                }
821
822                if (rect.bottom < pheader->m_iRowHeightMin) {
823                        rect.bottom = pheader->m_iRowHeightMin;
824                }
825
826                HDWP hdwp;
827                ATLVERIFY((hdwp = ::BeginDeferWindowPos(pheader->m_iNumCtrls)) != NULL);
828                if (!hdwp) {
829                        return FALSE;
830                }
831
832                BOOL bRes;
833                ATLVERIFY((bRes = _CtrlsArrange(hdwp, pheader, &marginsPix, lXUnits, lYUnits, &rect)) != FALSE);
834
835                ATLVERIFY(::EndDeferWindowPos(hdwp));
836
837                return bRes;
838        }
839
840        /// Gets the minimum size of the window. Initializes the window if necessary
841        /** \param sizeMin This variable will contain the minimum size of the window
842         *  \param piCtrls Ctrls map
843         *  \return TRUE if successful, FALSE if failure
844         */
845        BOOL GetMinSize(SIZE &sizeMin, CWindowMapStruct *piCtrls = T::GetWindowMap())
846        {
847                SIZE sz;
848                return GetMinMaxSize(sizeMin, sz, piCtrls);
849        }
850
851        /// Gets the maximum size of the window. Initializes the window if necessary
852        /** \param sizeMax This variable will contain the maximum size of the window
853         *  \param piCtrls Ctrls map
854         *  \return TRUE if successful, FALSE if failure
855         */
856        BOOL GetMaxSize(SIZE &sizeMax, CWindowMapStruct *piCtrls = T::GetWindowMap())
857        {
858                SIZE sz;
859                return GetMinMaxSize(sz, sizeMax, piCtrls);
860        }
861
862        /// Gets the minimum and maximum size of the window. Initializes the window if necessary
863        /** \param sizeMin This variable will contain the minimum size of the window
864         *  \param sizeMax This variable will contain the maximum size of the window
865         *  \param piCtrls Ctrls map
866         *  \return TRUE if successful, FALSE if failure
867         */
868        BOOL GetMinMaxSize(SIZE &sizeMin, SIZE &sizeMax, CWindowMapStruct *piCtrls = T::GetWindowMap())
869        {
870                if (!CtrlsInitialize(piCtrls)) {
871                        ATLTRACE(_T("Not initialized.\n"));
872                        return FALSE;
873                }
874
875                T* pT = static_cast<T*>(this);
876
877                RECT rectUnits = {4, 8, 0, 0};
878                ATLVERIFY(pT->MapDialogRect(&rectUnits));
879                LONG lXUnits = rectUnits.left, lYUnits = rectUnits.top;
880
881                CMargins marginsPix;
882                _CheckMargins(lXUnits, 4, lYUnits, 8, &piCtrls->m_margins, &marginsPix);
883
884                CCtrlGroup *pheader = &piCtrls->m_header;
885                sizeMin.cx = pheader->m_iColWidthMin + marginsPix.m_iLeftRight;
886                sizeMin.cy = pheader->m_iRowHeightMin + marginsPix.m_iTopBottom;
887
888                if (pheader->m_iColWidthMax != INT_MAX) {
889                        sizeMax.cx = pheader->m_iColWidthMax + marginsPix.m_iLeftRight;
890                } else {
891                        sizeMax.cx = INT_MAX;
892                }
893
894                if (pheader->m_iRowHeightMax != INT_MAX) {
895                        sizeMax.cy = pheader->m_iRowHeightMax + marginsPix.m_iTopBottom;
896                } else {
897                        sizeMax.cy = INT_MAX;
898                }
899
900                return TRUE;
901        }
902
903        /// Does the paint work. You can override it, but remember to call this method in the end, otherwise Transparent ctrls won't be painted.
904        /** \param dc The hDC to paint to
905         */
906        void DoPaint(WTL::CDCHandle dc)
907        {
908                T* pT = static_cast<T*>(this);
909                ATLVERIFY(pT->HandleTransparentMap(dc));
910        }
911
912protected:
913        BOOL _CtrlsInitialize(CCtrlGroup *pheader, CMargins *pmargins, LONG lXUnits, LONG lYUnits, BOOL bMain = TRUE)
914        {
915                if (pheader->m_iSignature != WMH_BEGIN) {
916                        ATLTRACE(_T("Wrong header format. Aborted.\n"));
917                        return FALSE;
918                }
919
920                int *piHeadCols = pheader->m_iCtrls;
921
922                if (piHeadCols[pheader->m_iNumCols * 3] != WMH_END) {
923                        ATLTRACE(_T("Wrong header format. Aborted.\n"));
924                        return FALSE;
925                }
926
927                if (*((int*)pheader + pheader->m_iSize) != WM_END) {
928                        ATLTRACE(_T("Wrong header format. Aborted.\n"));
929                        return FALSE;
930                }
931
932                int *piCell = piHeadCols + pheader->m_iNumCols * 3 + 1;
933
934                if (*piCell != WMR_BEGIN && *piCell != WM_END) {
935                        ATLTRACE(_T("Malformed endrow in header.\n"));
936                        return FALSE;
937                }
938
939                T* pT = static_cast<T*>(this);
940
941                int iColWidthFixed = 0;
942                int iColWidthMin = 0;
943                int_no iColWidthMax = 0;
944                int iColExpand = 0;
945                int iColContract = 0;
946
947                int *piColAuto = (int*)_alloca(pheader->m_iNumCols * sizeof(int));
948
949                if (bMain) {
950                        iColWidthFixed += pmargins->m_iLeftRight;
951                        iColWidthMin += pmargins->m_iLeftRight;
952                        iColWidthMax += pmargins->m_iLeftRight;
953                }
954
955                for (int i = 0; i < pheader->m_iNumCols; i++) {
956                        int iType, iStyle, iVal;
957                        _TypeVal(piHeadCols[i * 3], iType, iStyle, iVal);
958
959                        if (i && !(iStyle & WMSRC_NOGAP)) {
960                                iColWidthFixed += pmargins->m_iXGap;
961                                iColWidthMin += pmargins->m_iXGap;
962                                iColWidthMax += pmargins->m_iXGap;
963                        }
964
965                        if (iType == WMSRC_AUTO) {
966                                piColAuto[i] = 0;
967
968                                piHeadCols[i * 3] = iType|iStyle;
969
970                                _SetVariableMinMax(i, piHeadCols + i * 3);
971                        } else if (iType == WMSRC_EXPANDABLE) {
972                                piColAuto[i] = INT_MIN;
973
974                                if (iVal > 0) {
975                                        iColExpand += iVal;
976                                } else if (iVal == 0) {
977                                        piHeadCols[i * 3] |= WMSRC_DEFEXPANDABLEVAL;
978                                        iColExpand += WMSRC_DEFEXPANDABLEVAL;
979                                } else {
980                                        ATLTRACE(_T("Wrong value in column: %d. Ignored.\n"), i);
981                                        piHeadCols[i * 3] = iType|iStyle|WMSRC_DEFEXPANDABLEVAL;
982                                        iColExpand += WMSRC_DEFEXPANDABLEVAL;
983                                }
984
985                                _SetVariableMinMax(i, piHeadCols + i * 3);
986                        } else if (iType == WMSRC_CONTRACTABLE) {
987                                piColAuto[i] = INT_MIN;
988
989                                if (iVal > 0) {
990                                        iColContract += iVal;
991                                } else if (iVal == 0) {
992                                        piHeadCols[i * 3] |= WMSRC_DEFCONTRACTABLEVAL;
993                                        iColContract += WMSRC_DEFCONTRACTABLEVAL;
994                                } else {
995                                        ATLTRACE(_T("Wrong value in column: %d. Ignored.\n"), i);
996                                        piHeadCols[i * 3] = iType|iStyle|WMSRC_DEFCONTRACTABLEVAL;
997                                        iColContract += WMSRC_DEFCONTRACTABLEVAL;
998                                }
999
1000                                _SetVariableMinMax(i, piHeadCols + i * 3);
1001                        } else if (iType == WMSRC_EQUAL) {
1002                                if (iVal >= i || iVal < 0) {
1003                                        ATLTRACE(_T("Columns can be equal only to preceeding columns. Flag in column: %d ignored. Auto-column set.\n"), i);
1004                                        piHeadCols[i * 3] = WMSRC_AUTO|iStyle;
1005                                        piColAuto[i] = 0;
1006
1007                                        _SetVariableMinMax(i, piHeadCols + i * 3);
1008                                } else {
1009                                        int iColDef = iVal;
1010                                        while (piColAuto[iColDef] < 0 && piColAuto[iColDef] != INT_MIN) {
1011                                                iColDef = -piColAuto[iColDef] - 1;
1012                                        }
1013
1014                                        int iTypeDef, iStyleDef, iValDef;
1015                                        _TypeVal(piHeadCols[iColDef * 3], iTypeDef, iStyleDef, iValDef);
1016
1017                                        _CheckEqualMinMax(i, piHeadCols + i * 3);
1018
1019                                        piColAuto[i] = -(iColDef + 1);
1020
1021                                        if (iTypeDef == WMSRC_AUTO) {
1022                                        } else if (iTypeDef == WMSRC_EXPANDABLE) {
1023                                                iColExpand += iValDef;
1024                                        } else if (iTypeDef == WMSRC_CONTRACTABLE) {
1025                                                iColContract += iValDef;
1026                                        } else if (iTypeDef == WMSRC_GAP) {
1027                                                int iWidth = pmargins->m_iXGap;
1028                                                if (iValDef > 0) {
1029                                                        iWidth += ::MulDiv(iValDef, lXUnits, 4);
1030                                                } else {
1031                                                        iWidth += (-iValDef);
1032                                                }
1033                                        } else if (iTypeDef == WMSRC_GAPM) {
1034                                                int iWidth = pmargins->m_iXGap;
1035                                                if (iValDef > 0) {
1036                                                        iWidth -= ::MulDiv(iValDef, lXUnits, 4);
1037                                                } else {
1038                                                        iWidth -= (-iValDef);
1039                                                }
1040
1041                                                if (iWidth < 0) {
1042                                                        iWidth = 0;
1043                                                }
1044                                        } else {
1045                                                int iWidth;
1046                                                if (iValDef > 0) {
1047                                                        iWidth = ::MulDiv(iValDef, lXUnits, 4);
1048                                                } else {
1049                                                        iWidth = -iValDef;
1050                                                }
1051                                        }
1052                                }
1053                        } else if (iType == WMSRC_GAP) {
1054                                piColAuto[i] = INT_MIN;
1055
1056                                int iWidth = pmargins->m_iXGap;
1057                                if (iVal > 0) {
1058                                        iWidth += ::MulDiv(iVal, lXUnits, 4);
1059                                } else {
1060                                        iWidth += (-iVal);
1061                                }
1062
1063                                _CheckFixedMinMax(i, piHeadCols + i * 3, lXUnits, 4, iWidth);
1064                        } else if (iType == WMSRC_GAPM) {
1065                                piColAuto[i] = INT_MIN;
1066
1067                                int iWidth = pmargins->m_iXGap;
1068                                if (iVal > 0) {
1069                                        iWidth -= ::MulDiv(iVal, lXUnits, 4);
1070                                } else {
1071                                        iWidth -= (-iVal);
1072                                }
1073
1074                                if (iWidth < 0) {
1075                                        iWidth = 0;
1076                                }
1077
1078                                _CheckFixedMinMax(i, piHeadCols + i * 3, lXUnits, 4, iWidth);
1079                        } else {
1080                                if (iVal > 0) {
1081                                        if (iType) {
1082                                                ATLTRACE(_T("Wrong flag in column: %d. Ignored. Auto-column set.\n"), i);
1083                                                piHeadCols[i * 3] = WMSRC_AUTO|iStyle;
1084                                                piColAuto[i] = 0;
1085
1086                                                _SetVariableMinMax(i, piHeadCols + i * 3);
1087                                        } else {
1088                                                piColAuto[i] = INT_MIN;
1089
1090                                                int iWidth = ::MulDiv(iVal, lXUnits, 4);
1091
1092                                                _CheckFixedMinMax(i, piHeadCols + i * 3, lXUnits, 4, iWidth);
1093                                        }
1094                                } else {
1095                                        piColAuto[i] = INT_MIN;
1096
1097                                        int iWidth = -iVal;
1098
1099                                        _CheckFixedMinMax(i, piHeadCols + i * 3, lXUnits, 4, iWidth);
1100                                }
1101                        }
1102                }
1103
1104                int iNumCtrls = 0;
1105
1106                int iRow = 0, iRowDef = 0;
1107                int iRowHeightFixed = 0;
1108                int iRowHeightMin = 0;
1109                int_no iRowHeightMax = 0;
1110                int iRowExpand = 0;
1111                int iRowContract = 0;
1112
1113                if (pheader->m_iNumRows) {
1114                        int *piRowAuto = (int*)_alloca(pheader->m_iNumRows * sizeof(int));
1115                        int **ppiRowBegin = (int**)_alloca(pheader->m_iNumRows * sizeof(int*));
1116
1117                        if (bMain) {
1118                                iRowHeightFixed += pmargins->m_iTopBottom;
1119                                iRowHeightMin += pmargins->m_iTopBottom;
1120                                iRowHeightMax += pmargins->m_iTopBottom;
1121                        }
1122
1123                        while (*piCell != WM_END) {
1124                                ppiRowBegin[iRow] = piCell;
1125
1126                                if (ppiRowBegin[iRow][0] == WMR_BEGIN) {
1127                                        int iType, iStyle, iVal;
1128                                        _TypeVal(ppiRowBegin[iRow][1], iType, iStyle, iVal);
1129
1130                                        if (iRow && !(iStyle & WMSRC_NOGAP)) {
1131                                                iRowHeightFixed += pmargins->m_iYGap;
1132                                                iRowHeightMin += pmargins->m_iYGap;
1133                                                iRowHeightMax += pmargins->m_iYGap;
1134                                        }
1135
1136                                        if (iType == WMSRC_AUTO) {
1137                                                piRowAuto[iRow] = 0;
1138                                                iRowDef = iRow;
1139
1140                                                ppiRowBegin[iRow][1] = iType|iStyle;
1141
1142                                                _SetVariableMinMax(iRow, ppiRowBegin[iRow] + 1);
1143                                        } else if (iType == WMSRC_EXPANDABLE) {
1144                                                piRowAuto[iRow] = INT_MIN;
1145                                                iRowDef = iRow;
1146
1147                                                if (iVal > 0) {
1148                                                        iRowExpand += iVal;
1149                                                } else if (iVal == 0) {
1150                                                        ppiRowBegin[iRow][1] |= WMSRC_DEFEXPANDABLEVAL;
1151                                                        iRowExpand += WMSRC_DEFEXPANDABLEVAL;
1152                                                } else {
1153                                                        ATLTRACE(_T("Wrong value in row: %d. Ignored.\n"), iRow);
1154                                                        ppiRowBegin[iRow][1] = iType|iStyle|WMSRC_DEFEXPANDABLEVAL;
1155                                                        iRowExpand += WMSRC_DEFEXPANDABLEVAL;
1156                                                }
1157
1158                                                _SetVariableMinMax(iRow, ppiRowBegin[iRow] + 1);
1159                                        } else if (iType == WMSRC_CONTRACTABLE) {
1160                                                piRowAuto[iRow] = INT_MIN;
1161                                                iRowDef = iRow;
1162
1163                                                if (iVal > 0) {
1164                                                        iRowContract += iVal;
1165                                                } else if (iVal == 0) {
1166                                                        ppiRowBegin[iRow][1] |= WMSRC_DEFCONTRACTABLEVAL;
1167                                                        iRowContract += WMSRC_DEFCONTRACTABLEVAL;
1168                                                } else {
1169                                                        ATLTRACE(_T("Wrong value in row: %d. Ignored.\n"), iRow);
1170                                                        ppiRowBegin[iRow][1] = iType|iStyle|WMSRC_DEFCONTRACTABLEVAL;
1171                                                        iRowContract += WMSRC_DEFCONTRACTABLEVAL;
1172                                                }
1173
1174                                                _SetVariableMinMax(iRow, ppiRowBegin[iRow] + 1);
1175                                        } else if (iType == WMSRC_EQUAL) {
1176                                                if (iVal >= iRow || iVal < 0) {
1177                                                        ATLTRACE(_T("Rows can be equal only to preceeding rows. Flag in row: %d ignored. Auto-row set.\n"), iRow);
1178                                                        ppiRowBegin[iRow][1] = WMSRC_AUTO|iStyle;
1179                                                        piRowAuto[iRow] = 0;
1180                                                        iRowDef = iRow;
1181
1182                                                        _SetVariableMinMax(iRow, ppiRowBegin[iRow] + 1);
1183                                                } else {
1184                                                        iRowDef = iVal;
1185                                                        while (piRowAuto[iRowDef] < 0 && piRowAuto[iRowDef] != INT_MIN) {
1186                                                                iRowDef = -piRowAuto[iRowDef] - 1;
1187                                                        }
1188
1189                                                        int iTypeDef, iStyleDef, iValDef;
1190                                                        _TypeVal(ppiRowBegin[iRowDef][1], iTypeDef, iStyleDef, iValDef);
1191
1192                                                        _CheckEqualMinMax(iRow, ppiRowBegin[iRow] + 1);
1193
1194                                                        if (iTypeDef == WMSRC_AUTO) {
1195                                                                piRowAuto[iRow] = -(iRowDef + 1);
1196                                                        } else if (iTypeDef == WMSRC_EXPANDABLE) {
1197                                                                piRowAuto[iRow] = INT_MIN;
1198
1199                                                                iRowExpand += iValDef;
1200                                                        } else if (iTypeDef == WMSRC_CONTRACTABLE) {
1201                                                                piRowAuto[iRow] = INT_MIN;
1202
1203                                                                iRowContract += iValDef;
1204                                                        } else if (iTypeDef == WMSRC_GAP) {
1205                                                                piRowAuto[iRow] = INT_MIN;
1206
1207                                                                int iHeight = pmargins->m_iYGap;
1208                                                                if (iValDef > 0) {
1209                                                                        iHeight += ::MulDiv(iValDef, lYUnits, 8);
1210                                                                } else {
1211                                                                        iHeight += (-iValDef);
1212                                                                }
1213                                                        } else if (iTypeDef == WMSRC_GAPM) {
1214                                                                piRowAuto[iRow] = INT_MIN;
1215
1216                                                                int iHeight = pmargins->m_iYGap;
1217                                                                if (iValDef > 0) {
1218                                                                        iHeight -= ::MulDiv(iValDef, lYUnits, 8);
1219                                                                } else {
1220                                                                        iHeight -= (-iValDef);
1221                                                                }
1222
1223                                                                if (iHeight < 0) {
1224                                                                        iHeight = 0;
1225                                                                }
1226                                                        } else {
1227                                                                piRowAuto[iRow] = INT_MIN;
1228
1229                                                                int iHeight;
1230                                                                if (iValDef > 0) {
1231                                                                        iHeight = ::MulDiv(iValDef, lYUnits, 8);
1232                                                                } else {
1233                                                                        iHeight = -iValDef;
1234                                                                }
1235                                                        }
1236                                                }
1237                                        } else if (iType == WMSRC_GAP) {
1238                                                piRowAuto[iRow] = INT_MIN;
1239                                                iRowDef = iRow;
1240
1241                                                int iHeight = pmargins->m_iYGap;
1242                                                if (iVal > 0) {
1243                                                        iHeight += ::MulDiv(iVal, lYUnits, 8);
1244                                                } else {
1245                                                        iHeight += (-iVal);
1246                                                }
1247
1248                                                _CheckFixedMinMax(iRow, ppiRowBegin[iRow] + 1, lYUnits, 8, iHeight);
1249                                        } else if (iType == WMSRC_GAPM) {
1250                                                piRowAuto[iRow] = INT_MIN;
1251                                                iRowDef = iRow;
1252
1253                                                int iHeight = pmargins->m_iYGap;
1254                                                if (iVal > 0) {
1255                                                        iHeight -= ::MulDiv(iVal, lYUnits, 8);
1256                                                } else {
1257                                                        iHeight -= (-iVal);
1258                                                }
1259
1260                                                if (iHeight < 0) {
1261                                                        iHeight = 0;
1262                                                }
1263
1264                                                _CheckFixedMinMax(iRow, ppiRowBegin[iRow] + 1, lYUnits, 8, iHeight);
1265                                        } else {
1266                                                iRowDef = iRow;
1267                                                if (iVal > 0) {
1268                                                        if (iType) {
1269                                                                ATLTRACE(_T("Wrong flag in row: %d. Ignored. Auto-row set.\n"), iRow);
1270                                                                ppiRowBegin[iRow][1] = WMSRC_AUTO|iStyle;
1271                                                                piRowAuto[iRow] = 0;
1272
1273                                                                _SetVariableMinMax(iRow, ppiRowBegin[iRow] + 1);
1274                                                        } else {
1275                                                                piRowAuto[iRow] = INT_MIN;
1276
1277                                                                int iHeight = ::MulDiv(iVal, lYUnits, 8);
1278
1279                                                                _CheckFixedMinMax(iRow, ppiRowBegin[iRow] + 1, lYUnits, 8, iHeight);
1280                                                        }
1281                                                } else {
1282                                                        piRowAuto[iRow] = INT_MIN;
1283
1284                                                        int iHeight = -iVal;
1285
1286                                                        _CheckFixedMinMax(iRow, ppiRowBegin[iRow] + 1, lYUnits, 8, iHeight);
1287                                                }
1288                                        }
1289
1290                                        piCell += 4;
1291
1292                                        int iCol = 0, iColDef = 0;
1293                                        while (*piCell != WMR_END && *piCell != WM_END) {
1294                                                if (iCol < pheader->m_iNumCols) {
1295                                                        iColDef = (piColAuto[iCol] == INT_MIN || piColAuto[iCol] >= 0 ? iCol: -piColAuto[iCol] - 1);
1296
1297                                                        if (*piCell != WMH_BEGIN && *piCell != WMSCTRL_EMPTY && *piCell != WMSCTRL_EXPDOWN && *piCell != WMSCTRL_EXPRIGHT) {
1298                                                                iNumCtrls++;
1299                                                                if (piColAuto[iColDef] != INT_MIN || piRowAuto[iRowDef] != INT_MIN || 
1300                                                                        piHeadCols[iColDef * 3 + 1] & WMSRCMM_NEEDCALC || piHeadCols[iColDef * 3 + 2] & WMSRCMM_NEEDCALC || 
1301                                                                        ppiRowBegin[iRowDef][2] & WMSRCMM_NEEDCALC || ppiRowBegin[iRowDef][3] & WMSRCMM_NEEDCALC) {
1302
1303                                                                        HWND hWnd = pT->GetDlgItem(*piCell);
1304                                                                        if (!hWnd) {
1305                                                                                ATLTRACE(_T("Inexistant ctrl in row: %d, col: %d. Ignored.\n"), iRow, iCol);
1306                                                                        } else {
1307                                                                                const MINMAXINFO mmOrig = {0, 0, INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MAX};
1308                                                                                MINMAXINFO mm = mmOrig;
1309
1310                                                                                ::SendMessage(hWnd, WM_GETMINMAXINFO, 0, (LPARAM)&mm);
1311                                                                                if (::memcmp(&mm, &mmOrig, sizeof(MINMAXINFO)) != 0) {
1312                                                                                        _CalcAuto(piColAuto[iColDef], mm.ptMinTrackSize.x);
1313                                                                                        _CalcMinMaxAuto(piHeadCols + iColDef * 3, mm.ptMinTrackSize.x, mm.ptMaxTrackSize.x);
1314
1315                                                                                        _CalcAuto(piRowAuto[iRowDef], mm.ptMinTrackSize.y);
1316                                                                                        _CalcMinMaxAuto(ppiRowBegin[iRowDef] + 1, mm.ptMinTrackSize.y, mm.ptMaxTrackSize.y);
1317                                                                                } else {
1318                                                                                        RECT rect = {0};
1319                                                                                        ATLVERIFY(::GetWindowRect(hWnd, &rect));
1320
1321                                                                                        int iWidth = rect.right - rect.left;
1322                                                                                        _CalcAuto(piColAuto[iColDef], iWidth);
1323
1324                                                                                        int iHeight = rect.bottom - rect.top;
1325                                                                                        _CalcAuto(piRowAuto[iRowDef], iHeight);
1326                                                                                }
1327                                                                        }
1328                                                                }
1329                                                        } else if (*piCell == WMH_BEGIN) {
1330                                                                CCtrlGroup *pheaderNew = (CCtrlGroup*)piCell; 
1331                                                                if (_CtrlsInitialize(pheaderNew, pmargins, lXUnits, lYUnits, FALSE)) {
1332                                                                        _CalcAuto(piColAuto[iColDef], pheaderNew->m_iColWidthMin);
1333                                                                        _CalcMinMaxAuto(piHeadCols + iColDef * 3, pheaderNew->m_iColWidthMin, pheaderNew->m_iColWidthMax);
1334
1335                                                                        _CalcAuto(piRowAuto[iRowDef], pheaderNew->m_iRowHeightMin);
1336                                                                        _CalcMinMaxAuto(ppiRowBegin[iRowDef] + 1, pheaderNew->m_iRowHeightMin, pheaderNew->m_iRowHeightMax);
1337
1338                                                                        iNumCtrls += pheaderNew->m_iNumCtrls;
1339
1340                                                                        piCell += piCell[1];
1341                                                                } else {
1342                                                                        return FALSE;
1343                                                                }
1344                                                        }
1345                                                } else {
1346                                                        ATLTRACE(_T("Too many columns. Row: %d, col: %d ignored.\n"), iRow, iCol);
1347
1348                                                        if (*piCell == WMH_BEGIN) {
1349                                                                piCell += piCell[1];
1350                                                        }
1351                                                }
1352
1353                                                iCol++;
1354                                                piCell++;
1355                                        }
1356
1357                                        if (*piCell == WM_END) {
1358                                                ATLTRACE(_T("Malformed endrow in row: %d. Ignored.\n"), iRow);
1359                                        } 
1360                                } else {
1361                                        ATLTRACE(_T("Malformed row: %d. Skipped. \n"), iRow);
1362                                        while (*piCell != WMR_END && *piCell != WM_END) {
1363                                                piCell++;
1364                                        }
1365
1366                                        piRowAuto[iRow] = INT_MIN;
1367                                }
1368
1369                                iRow++;
1370
1371                                if (*piCell != WM_END) {
1372                                        piCell++;
1373                                }
1374                        }
1375
1376#ifdef TRACEAUTOSIZE
1377                        ATLTRACE("Rows: ");
1378#endif
1379                        for (int i = 0; i < iRow; i++) {
1380                                if (piRowAuto[i] != INT_MIN) {
1381                                        if (piRowAuto[i] >= 0) {
1382                                                _CheckAutoMinMax(ppiRowBegin[i] + 1, piRowAuto[i]);
1383                                                int iType = ppiRowBegin[i][1] & WMSRC_TYPEMASK;
1384                                                _AddMinMax(i, ppiRowBegin[i] + 1, lYUnits, 8, iRowHeightFixed, iType, iRowHeightMin, iRowHeightMax);
1385                                                _SetAuto(ppiRowBegin[i] + 1, lYUnits, 8, piRowAuto[i]);
1386                                        } else {
1387                                                int iDef = -piRowAuto[i] - 1;
1388                                                int iType = ppiRowBegin[iDef][1] & WMSRC_TYPEMASK;
1389                                                _AddMinMax(i, ppiRowBegin[iDef] + 1, lYUnits, 8, iRowHeightFixed, iType, iRowHeightMin, iRowHeightMax);
1390                                        }
1391                                } else {
1392                                        int iType = ppiRowBegin[i][1] & WMSRC_TYPEMASK;
1393                                        _AddMinMax(i, ppiRowBegin[i] + 1, lYUnits, 8, iRowHeightFixed, iType, iRowHeightMin, iRowHeightMax);
1394                                }
1395
1396#ifdef TRACEAUTOSIZE
1397                                int iTypeMin, iTypeMax;
1398                                int iMinPix, iMaxPix;
1399                                _LoadMinMax(ppiRowBegin[i] + 1, lYUnits, 8, iTypeMin, iMinPix, iTypeMax, iMaxPix);
1400                                ATLTRACE("%d-%d ", iMinPix, iMaxPix);
1401#endif
1402                        }
1403                }
1404
1405#ifdef TRACEAUTOSIZE
1406                ATLTRACE("\nCols: ");
1407#endif
1408                for (int i = 0; i < pheader->m_iNumCols; i++) {
1409                        if (piColAuto[i] != INT_MIN) {
1410                                if (piColAuto[i] >= 0) {
1411                                        _CheckAutoMinMax(piHeadCols + i * 3, piColAuto[i]);
1412                                        int iType = piHeadCols[i * 3] & WMSRC_TYPEMASK;
1413                                        _AddMinMax(i, piHeadCols + i * 3, lXUnits, 4, iColWidthFixed, iType, iColWidthMin, iColWidthMax);
1414                                        _SetAuto(piHeadCols + i * 3, lXUnits, 4, piColAuto[i]);
1415                                } else {
1416                                        int iDef = -piColAuto[i] - 1;
1417                                        int iType = piHeadCols[iDef * 3] & WMSRC_TYPEMASK;
1418                                        _AddMinMax(i, piHeadCols + iDef * 3, lXUnits, 4, iColWidthFixed, iType, iColWidthMin, iColWidthMax);
1419                                }
1420                        } else {
1421                                int iType = piHeadCols[i * 3] & WMSRC_TYPEMASK;
1422                                _AddMinMax(i, piHeadCols + i * 3, lXUnits, 4, iColWidthFixed, iType, iColWidthMin, iColWidthMax);
1423                        }
1424
1425#ifdef TRACEAUTOSIZE
1426                        int iTypeMin, iTypeMax;
1427                        int iMinPix, iMaxPix;
1428                        _LoadMinMax(piHeadCols + i * 3, lXUnits, 4, iTypeMin, iMinPix, iTypeMax, iMaxPix);
1429                        ATLTRACE("%d-%d ", iMinPix, iMaxPix);
1430#endif
1431                }
1432
1433#ifdef TRACEAUTOSIZE
1434                ATLTRACE("\n");
1435#endif
1436
1437                if (iRow != pheader->m_iNumRows) {
1438                        ATLTRACE(_T("Number of rows incorrect. Fixed.\n"));
1439                        pheader->m_iNumRows = iRow;
1440                }
1441
1442                pheader->m_iNumCtrls = iNumCtrls;
1443                pheader->m_iColWidthFixed = iColWidthFixed;
1444                pheader->m_iColWidthMin = iColWidthMin;
1445                pheader->m_iColWidthMax = iColWidthMax;
1446                pheader->m_iColExpand = iColExpand;
1447                pheader->m_iColContract = iColContract;
1448
1449                pheader->m_iRowHeightFixed = iRowHeightFixed;
1450                pheader->m_iRowHeightMin = iRowHeightMin;
1451                pheader->m_iRowHeightMax = iRowHeightMax;
1452                pheader->m_iRowExpand = iRowExpand;
1453                pheader->m_iRowContract = iRowContract;
1454
1455#ifdef TRACEAUTOSIZE
1456                ATLTRACE("Fixed: %d, %d. Min: %d, %d. Max: %d, %d\n", iColWidthFixed, iRowHeightFixed, iColWidthMin, iRowHeightMin, iColWidthMax, iRowHeightMax);
1457#endif
1458
1459                ATLASSERT(*piCell == WM_END);
1460                return TRUE;
1461        }
1462
1463        BOOL _CtrlsArrange(HDWP &hdwp, CCtrlGroup *pheader, CMargins *pmargins, LONG lXUnits, LONG lYUnits, RECT *pRectWindow, BOOL bMain = TRUE)
1464        {
1465                if (pheader->m_iSignature != WMH_BEGIN) {
1466                        ATLTRACE(_T("Wrong header format. Aborted.\n"));
1467                        return FALSE;
1468                }
1469
1470                int *piHeadCols = pheader->m_iCtrls;
1471
1472                int *piCell = piHeadCols + pheader->m_iNumCols * 3 + 1;
1473
1474                T* pT = static_cast<T*>(this);
1475
1476                if (pheader->m_iNumRows) {
1477                        int iColTrueMin = pheader->m_iColWidthMin;
1478                        int iColTrueMax = pheader->m_iColWidthMax;
1479
1480                        int iRowTrueMin = pheader->m_iRowHeightMin;
1481                        int iRowTrueMax = pheader->m_iRowHeightMax;
1482
1483                        int iWidth = pRectWindow->right - pRectWindow->left;
1484                        int iTotalColContract;
1485
1486                        if (iWidth < iColTrueMin) {
1487                                ATLTRACE(_T("Width too small! Needed %d more pixels.\n"), iColTrueMin - iWidth);
1488                                iTotalColContract = 0;
1489                        } else if (iWidth >= iColTrueMin && iWidth <= iColTrueMax) {
1490                                iTotalColContract = 0;
1491                        } else {
1492                                iTotalColContract = iWidth - iColTrueMax;
1493                                iWidth = iColTrueMax;
1494                        }
1495
1496                        int iHeight = pRectWindow->bottom - pRectWindow->top;
1497                        int iTotalRowContract;
1498
1499                        if (iHeight < iRowTrueMin) {
1500                                ATLTRACE(_T("Height too small! Needed %d more pixels.\n"), iRowTrueMin - iHeight);
1501                                iTotalRowContract = 0;
1502                        } else if (iHeight >= iRowTrueMin && iHeight <= iRowTrueMax) {
1503                                iTotalRowContract = 0;
1504                        } else {
1505                                iTotalRowContract = iHeight - iRowTrueMax;
1506                                iHeight = iRowTrueMax;
1507                        }
1508
1509#ifdef TRACEAUTOSIZE2
1510                        ATLTRACE("Rect: %d, %d\n", iWidth, iHeight);
1511#endif
1512
1513                        int iTotalColExpand = (iWidth > iColTrueMin ? iWidth - pheader->m_iColWidthFixed : 0);
1514                        int iColExpand = pheader->m_iColExpand, iColContract = pheader->m_iColContract;
1515
1516                        int iTotalRowExpand = (iHeight > iRowTrueMin ? iHeight - pheader->m_iRowHeightFixed : 0);
1517                        int iRowExpand = pheader->m_iRowExpand, iRowContract = pheader->m_iRowContract;
1518
1519                        int *piWidthCol = (int*)_alloca(pheader->m_iNumCols * sizeof(int));
1520
1521                        int iWidthTotal = pRectWindow->left;
1522                        if (bMain) {
1523                                iWidthTotal += pmargins->m_iLeftRight;
1524                        }
1525
1526#ifdef TRACEAUTOSIZE2
1527                        ATLTRACE("Cols: ");
1528#endif
1529
1530                        for (int i = 0; i < pheader->m_iNumCols; i++) {
1531                                int iType, iStyle, iVal;
1532                                _TypeVal(piHeadCols[i * 3], iType, iStyle, iVal);
1533
1534                                if (i && !(iStyle & WMSRC_NOGAP)) {
1535                                        iWidthTotal += pmargins->m_iXGap;
1536                                }
1537
1538                                if (iWidthTotal > pRectWindow->right) {
1539                                        iWidthTotal = pRectWindow->right;
1540                                }
1541
1542                                int iTypeMin, iTypeMax;
1543                                int iMinPix, iMaxPix;
1544                                _LoadMinMax(piHeadCols + i * 3, lXUnits, 4, iTypeMin, iMinPix, iTypeMax, iMaxPix);
1545
1546                                if (iType == WMSRC_AUTO) {
1547                                        piWidthCol[i] = iVal;
1548                                } else if (iType == WMSRC_EXPANDABLE) {
1549                                        piWidthCol[i] = ::MulDiv(iTotalColExpand, iVal, iColExpand);
1550                                        _NormalizeColRow(piWidthCol[i], iMinPix, iMaxPix);
1551                                        iColExpand -= iVal;
1552                                        iTotalColExpand = (iTotalColExpand > piWidthCol[i] ? iTotalColExpand - piWidthCol[i] : 0);
1553                                } else if (iType == WMSRC_CONTRACTABLE) {
1554                                        piWidthCol[i] = ::MulDiv(iTotalColContract, iVal, iColContract);
1555                                        _NormalizeColRow(piWidthCol[i], iMinPix, iMaxPix);
1556                                        iColContract -= iVal;
1557                                        iTotalColContract = (iTotalColContract > piWidthCol[i] ? iTotalColContract - piWidthCol[i] : 0);
1558                                } else if (iType == WMSRC_EQUAL) {
1559                                        int iColDef = iVal;
1560                                        int iTypeDef, iStyleDef, iValDef;
1561                                        do {
1562                                                _TypeVal(piHeadCols[iColDef * 3], iTypeDef, iStyleDef, iValDef);
1563                                        } while (iTypeDef == WMSRC_EQUAL && (iColDef = iValDef) == iColDef);
1564
1565                                        int iTypeMinDef, iTypeMaxDef;
1566                                        int iMinPixDef, iMaxPixDef;
1567                                        _LoadMinMax(piHeadCols + iColDef * 3, lXUnits, 4, iTypeMinDef, iMinPixDef, iTypeMaxDef, iMaxPixDef);
1568
1569                                        if (iTypeDef == WMSRC_AUTO) {
1570                                                piWidthCol[i] = iValDef;
1571                                        } else if (iTypeDef == WMSRC_EXPANDABLE) {
1572                                                piWidthCol[i] = ::MulDiv(iTotalColExpand, iValDef, iColExpand);
1573                                                _NormalizeColRow(piWidthCol[i], iMinPixDef, iMaxPixDef);
1574                                                iColExpand -= iValDef;
1575                                                iTotalColExpand = (iTotalColExpand > piWidthCol[i] ? iTotalColExpand - piWidthCol[i] : 0);
1576                                        } else if (iTypeDef == WMSRC_CONTRACTABLE) {
1577                                                piWidthCol[i] = ::MulDiv(iTotalColContract, iValDef, iColContract);
1578                                                _NormalizeColRow(piWidthCol[i], iMinPixDef, iMaxPixDef);
1579                                                iColContract -= iValDef;
1580                                                iTotalColContract = (iTotalColContract > piWidthCol[i] ? iTotalColContract - piWidthCol[i] : 0);
1581                                        } else if (iTypeDef == WMSRC_GAP) {
1582                                                piWidthCol[i] = iMinPixDef;
1583                                        } else if (iTypeDef == WMSRC_GAPM) {
1584                                                piWidthCol[i] = iMinPixDef;
1585                                        } else {
1586                                                piWidthCol[i] = iMinPixDef;
1587                                        }               
1588                                } else if (iType == WMSRC_GAP) {
1589                                        piWidthCol[i] = iMinPix;
1590                                } else if (iType == WMSRC_GAPM) {
1591                                        piWidthCol[i] = iMinPix;
1592                                } else {
1593                                        piWidthCol[i] = iMinPix;
1594                                }
1595
1596                                iWidthTotal += piWidthCol[i];
1597                                if (iWidthTotal > pRectWindow->right) {
1598                                        piWidthCol[i] -= iWidthTotal - pRectWindow->right;
1599                                        iWidthTotal = pRectWindow->right;
1600                                }
1601
1602#ifdef TRACEAUTOSIZE2
1603                                ATLTRACE("%d ", piWidthCol[i]);
1604#endif
1605                        }
1606
1607                        int *piHeightRow = (int*)_alloca(pheader->m_iNumRows * sizeof(int));
1608                        int **ppiRowBegin = (int**)_alloca(pheader->m_iNumRows * sizeof(int*));
1609
1610                        HWND *phWnd = (HWND*)_alloca(pheader->m_iNumCols * sizeof(HWND));
1611                        int **ppiCtrl = (int**)_alloca(pheader->m_iNumCols * sizeof(int**));
1612                        RECT *prect = (RECT*)_alloca(pheader->m_iNumCols * sizeof(RECT));
1613                        ::memset(phWnd, 0, pheader->m_iNumCols * sizeof(HWND));
1614                        ::memset(ppiCtrl, 0, pheader->m_iNumCols * sizeof(int**));
1615
1616                        int iHeightTotal = pRectWindow->top;
1617                        if (bMain) {
1618                                iHeightTotal += pmargins->m_iTopBottom;
1619                        }
1620
1621                        int iRow = 0;
1622
1623#ifdef TRACEAUTOSIZE2
1624                        ATLTRACE("\nRows: ");
1625#endif
1626
1627                        while (*piCell != WM_END) {
1628                                ppiRowBegin[iRow] = piCell;
1629
1630                                if (*piCell == WMR_BEGIN) {
1631                                        int iType, iStyle, iVal;
1632                                        _TypeVal(piCell[1], iType, iStyle, iVal);
1633
1634                                        if (iRow && !(iStyle & WMSRC_NOGAP)) {
1635                                                iHeightTotal += pmargins->m_iYGap;
1636                                        }
1637
1638                                        if (iHeightTotal > pRectWindow->bottom) {
1639                                                iHeightTotal = pRectWindow->bottom;
1640                                        }
1641
1642                                        int iTypeMin, iTypeMax;
1643                                        int iMinPix, iMaxPix;
1644                                        _LoadMinMax(ppiRowBegin[iRow] + 1, lYUnits, 8, iTypeMin, iMinPix, iTypeMax, iMaxPix);
1645
1646                                        if (iType == WMSRC_AUTO) {
1647                                                piHeightRow[iRow] = iVal;
1648                                        } else if (iType == WMSRC_EXPANDABLE) {
1649                                                piHeightRow[iRow] = ::MulDiv(iTotalRowExpand, iVal, iRowExpand);
1650                                                _NormalizeColRow(piHeightRow[iRow], iMinPix, iMaxPix);
1651                                                iRowExpand -= iVal;
1652                                                iTotalRowExpand = (iTotalColExpand > piHeightRow[iRow] ? iTotalColExpand - piHeightRow[iRow] : 0);
1653                                        } else if (iType == WMSRC_CONTRACTABLE) {
1654                                                piHeightRow[iRow] = ::MulDiv(iTotalRowContract, iVal, iRowContract);
1655                                                _NormalizeColRow(piHeightRow[iRow], iMinPix, iMaxPix);
1656                                                iRowContract -= iVal;
1657                                                iTotalRowContract = (iTotalColContract > piHeightRow[iRow] ? iTotalColContract - piHeightRow[iRow] : 0);
1658                                        } else if (iType == WMSRC_EQUAL) {
1659                                                int iRowDef = iVal;
1660                                                int iTypeDef, iStyleDef, iValDef;
1661                                                do {
1662                                                        _TypeVal(ppiRowBegin[iRowDef][1], iTypeDef, iStyleDef, iValDef);
1663                                                } while (iTypeDef == WMSRC_EQUAL && (iRowDef = iValDef) == iRowDef);
1664
1665                                                int iTypeMinDef, iTypeMaxDef;
1666                                                int iMinPixDef, iMaxPixDef;
1667                                                _LoadMinMax(ppiRowBegin[iRowDef] + 1, lYUnits, 8, iTypeMinDef, iMinPixDef, iTypeMaxDef, iMaxPixDef);
1668
1669                                                if (iTypeDef == WMSRC_AUTO) {
1670                                                        piHeightRow[iRow] = iValDef;
1671                                                } else if (iTypeDef == WMSRC_EXPANDABLE) {
1672                                                        piHeightRow[iRow] = ::MulDiv(iTotalRowExpand, iValDef, iRowExpand);
1673                                                        _NormalizeColRow(piHeightRow[iRow], iMinPix, iMaxPix);
1674                                                        iRowExpand -= iValDef;
1675                                                        iTotalRowExpand = (iTotalColExpand > piHeightRow[iRow] ? iTotalColExpand - piHeightRow[iRow] : 0);
1676                                                } else if (iTypeDef == WMSRC_CONTRACTABLE) {
1677                                                        piHeightRow[iRow] = ::MulDiv(iTotalRowContract, iValDef, iRowContract);
1678                                                        _NormalizeColRow(piHeightRow[iRow], iMinPix, iMaxPix);
1679                                                        iRowContract -= iValDef;
1680                                                        iTotalRowContract = (iTotalColContract > piHeightRow[iRow] ? iTotalColContract - piHeightRow[iRow] : 0);
1681                                                } else if (iTypeDef == WMSRC_GAP) {
1682                                                        piHeightRow[iRow] = iMinPixDef;
1683                                                } else if (iTypeDef == WMSRC_GAPM) {
1684                                                        piHeightRow[iRow] = iMinPixDef;
1685                                                } else {
1686                                                        piHeightRow[iRow] = iMinPixDef;
1687                                                }               
1688                                        } else if (iType == WMSRC_GAP) {
1689                                                piHeightRow[iRow] = iMinPix;
1690                                        } else if (iType == WMSRC_GAPM) {
1691                                                piHeightRow[iRow] = iMinPix;
1692                                        } else {
1693                                                piHeightRow[iRow] = iMinPix;
1694                                        }
1695
1696                                        if (iHeightTotal + piHeightRow[iRow] > pRectWindow->bottom) {
1697                                                piHeightRow[iRow] = pRectWindow->bottom - iHeightTotal;
1698                                        }
1699
1700#ifdef TRACEAUTOSIZE2
1701                                        ATLTRACE("%d ", piHeightRow[iRow]);
1702#endif
1703
1704                                        piCell += 4;
1705
1706                                        int iCol = 0;
1707                                        RECT *pLastRect = NULL;
1708
1709                                        int iWidthTotal = pRectWindow->left;
1710                                        if (bMain) {
1711                                                iWidthTotal += pmargins->m_iLeftRight;
1712                                        }
1713
1714                                        while (*piCell != WM_END && *piCell != WMR_END) {
1715                                                if (iCol < pheader->m_iNumCols) {
1716                                                        if (iCol && !(piHeadCols[iCol * 3] & WMSRC_NOGAP)) {
1717                                                                iWidthTotal += pmargins->m_iXGap;
1718                                                        }
1719
1720                                                        if (iWidthTotal > pRectWindow->right) {
1721                                                                iWidthTotal = pRectWindow->right;
1722                                                        }
1723
1724                                                        if (*piCell != WMSCTRL_EXPDOWN) {
1725                                                                if (!_MoveCtrl(iCol, hdwp, phWnd, ppiCtrl, prect, pmargins, lXUnits, lYUnits)) {
1726                                                                        return FALSE;
1727                                                                }
1728
1729                                                                if (*piCell != WMSCTRL_EMPTY && *piCell != WMSCTRL_EXPRIGHT) {
1730                                                                        prect[iCol].left = iWidthTotal;
1731                                                                        prect[iCol].top = iHeightTotal;
1732                                                                        prect[iCol].right = piWidthCol[iCol];
1733                                                                        prect[iCol].bottom = piHeightRow[iRow];
1734                                                                        pLastRect = &prect[iCol];
1735
1736                                                                        if (*piCell != WMH_BEGIN) {
1737                                                                                phWnd[iCol] = pT->GetDlgItem(*piCell);
1738                                                                                ppiCtrl[iCol] = NULL;
1739                                                                                if (!phWnd[iCol]) {
1740                                                                                        phWnd[iCol] = (HWND)-1;
1741                                                                                        ATLTRACE(_T("Inexistant ctrl in row: %d, col: %d. Ignored.\n"), iRow, iCol);
1742                                                                                }
1743                                                                        } else {
1744                                                                                phWnd[iCol] = NULL;
1745                                                                                ppiCtrl[iCol] = piCell;
1746                                                                                piCell += piCell[1];
1747                                                                        }
1748                                                                } else {
1749                                                                        phWnd[iCol] = NULL;
1750                                                                        ppiCtrl[iCol] = NULL;
1751                                                                        if (*piCell != WMSCTRL_EXPRIGHT) {
1752                                                                                pLastRect = NULL;
1753                                                                        }
1754                                                                }
1755                                                        } 
1756
1757                                                        if (*piCell == WMSCTRL_EXPRIGHT) {
1758                                                                if (pLastRect) {
1759                                                                        pLastRect->right += piWidthCol[iCol];
1760                                                                        if ((piHeadCols[iCol * 3] & WMSRC_NOGAP) != WMSRC_NOGAP && iCol) {
1761                                                                                pLastRect->right += pmargins->m_iXGap;
1762                                                                                if (pLastRect->left + pLastRect->right > pRectWindow->right) {
1763                                                                                        pLastRect->right = pRectWindow->right - pLastRect->left;
1764                                                                                }
1765                                                                        }
1766                                                                } else {
1767                                                                        ATLTRACE(_T("Wrong continue right flag in row: %d, column: %d. Ignored.\n"), iRow, iCol);
1768                                                                }
1769                                                        } else if (*piCell == WMSCTRL_EXPDOWN) {
1770                                                                if (phWnd[iCol] || ppiCtrl[iCol]) {
1771                                                                        prect[iCol].bottom += piHeightRow[iRow];
1772                                                                        if (iRow && !(iStyle & WMSRC_NOGAP)) {
1773                                                                                prect[iCol].bottom += pmargins->m_iYGap;
1774                                                                                if (prect[iCol].top + prect[iCol].bottom > pRectWindow->bottom) {
1775                                                                                        prect[iCol].bottom = pRectWindow->bottom - prect[iCol].top;
1776                                                                                }
1777                                                                        }
1778                                                                } else {
1779                                                                        ATLTRACE(_T("Wrong continue down flag in row: %d, column: %d. Ignored.\n"), iRow, iCol);
1780                                                                }
1781                                                                pLastRect = NULL;
1782                                                        }
1783
1784                                                        iWidthTotal += piWidthCol[iCol];
1785                                                }
1786
1787                                                iCol++;
1788                                                piCell++;
1789                                        }
1790
1791                                        for (int i = iCol; i < pheader->m_iNumCols; i++) {
1792                                                if (!_MoveCtrl(i, hdwp, phWnd, ppiCtrl, prect, pmargins, lXUnits, lYUnits)) {
1793                                                        return FALSE;
1794                                                }
1795                                        }
1796                                } else {
1797                                        ATLTRACE(_T("Malformed row: %d. Skipped. \n"), iRow);
1798                                        while (*piCell != WMR_END && *piCell != WM_END) {
1799                                                piCell++;
1800                                        }
1801
1802                                        for (int i = 0; i < pheader->m_iNumCols; i++) {
1803                                                if (!_MoveCtrl(i, hdwp, phWnd, ppiCtrl, prect, pmargins, lXUnits, lYUnits)) {
1804                                                        return FALSE;
1805                                                }
1806                                        }
1807
1808                                        piHeightRow[iRow] = 0;
1809                                }
1810
1811                                iHeightTotal += piHeightRow[iRow];
1812
1813                                if (*piCell != WM_END) {
1814                                        piCell++;
1815                                } else {
1816                                        ATLTRACE(_T("Malformed endrow in row: %d. Ignored.\n"), iRow);
1817                                }
1818
1819                                iRow++;
1820                        }                       
1821
1822                        for (int i = 0; i < pheader->m_iNumCols; i++) {
1823                                if (!_MoveCtrl(i, hdwp, phWnd, ppiCtrl, prect, pmargins, lXUnits, lYUnits)) {
1824                                        return FALSE;
1825                                }
1826                        }
1827                }
1828
1829                ATLASSERT(*piCell == WM_END);
1830
1831                return TRUE;
1832        }
1833
1834        BOOL _MoveCtrl(int iCol, HDWP &hdwp, HWND *phWnd, int **ppiCtrl, RECT *prect, CMargins *pmargins, LONG lXUnits, LONG lYUnits)
1835        {
1836                if (phWnd[iCol] && phWnd[iCol] != (HWND)-1) {
1837                        POINT pt = {0};
1838                        __if_exists(T::GetScrollOffset) {
1839                                T* pT = static_cast<T*>(this);
1840                                pT->GetScrollOffset(pt);
1841                        }
1842
1843                        UINT uiFlags = ::GetWindowLong(phWnd[iCol], GWL_EXSTYLE) & WS_EX_TRANSPARENT ? SWP_NOCOPYBITS : 0;
1844                        ATLVERIFY((hdwp = ::DeferWindowPos(hdwp, phWnd[iCol], NULL, prect[iCol].left - pt.x, prect[iCol].top - pt.y, prect[iCol].right, prect[iCol].bottom, SWP_NOACTIVATE|SWP_NOOWNERZORDER|SWP_NOZORDER|uiFlags)) != NULL);
1845                        if (!hdwp) {
1846                                return FALSE;
1847                        }
1848                        phWnd[iCol] = NULL;
1849                } else if (ppiCtrl[iCol]) {
1850                        RECT rect = {prect[iCol].left, prect[iCol].top, prect[iCol].left + prect[iCol].right, prect[iCol].top + prect[iCol].bottom};
1851                        if (!_CtrlsArrange(hdwp, (CCtrlGroup*)ppiCtrl[iCol], pmargins, lXUnits, lYUnits, &rect, FALSE)) {
1852                                return FALSE;
1853                        }
1854
1855                        ppiCtrl[iCol] = NULL;
1856                }
1857
1858                return TRUE;
1859        }
1860
1861        /// Converts margins and gaps from DLGU or Pixels to Pixels
1862        static void _CheckMargins(long lXUnits, int iXUnitsBase, long lYUnits, int iYUnitsBase, const CMargins *pmargins, CMargins *pmarginsPix)
1863        {
1864                pmarginsPix->m_iLeftRight = (pmargins->m_iLeftRight > 0 ? ::MulDiv(pmargins->m_iLeftRight, lXUnits, iXUnitsBase) : -pmargins->m_iLeftRight);
1865                pmarginsPix->m_iTopBottom = (pmargins->m_iTopBottom > 0 ? ::MulDiv(pmargins->m_iTopBottom, lYUnits, iYUnitsBase) : -pmargins->m_iTopBottom);
1866                pmarginsPix->m_iXGap = (pmargins->m_iXGap > 0 ? ::MulDiv(pmargins->m_iXGap, lXUnits, iXUnitsBase) : -pmargins->m_iXGap);
1867                pmarginsPix->m_iYGap = (pmargins->m_iYGap > 0 ? ::MulDiv(pmargins->m_iYGap, lYUnits, iYUnitsBase) : -pmargins->m_iYGap);
1868        }
1869
1870        /// Splits the type of a Row/Col in Type, ExStyle and Val
1871        static void _TypeVal(int iBase, int &iType, int &iStyle, int &iVal)
1872        {
1873                if (iBase >= 0) {
1874                        iType = iBase & WMSRC_TYPEMASK;
1875                        iStyle = iBase & WMSRC_EXSTYLEMASK;
1876                        iVal = iBase & WMSRC_VALMASK;
1877                } else {
1878                        iBase = 0 - iBase;
1879                        iType = iBase & WMSRC_TYPEMASK;
1880                        iStyle = iBase & WMSRC_EXSTYLEMASK;
1881                        iVal = -(int)(iBase & WMSRC_VALMASK);
1882                }
1883        }
1884
1885        static void _SetVariableMinMax(int iCR, int *piColRow)
1886        {
1887                _SetVariableMinMax(iCR, piColRow[1]);
1888                _SetVariableMinMax(iCR, piColRow[2], WMSRCMM_MAXVAL);
1889        }
1890
1891        static void _SetVariableMinMax(int iCR, int &iBase, int iVal = 0)
1892        {
1893                iCR;
1894
1895                BOOL bNeg = iBase < 0;
1896
1897                if (bNeg) {
1898                        iBase = -iBase;
1899                }
1900
1901                if (iBase & WMSRCMM_SIZECALC) {
1902                        iBase = WMSRCMM_SIZECALC|WMSRCMM_NEEDCALC|iVal;
1903                        bNeg = FALSE;
1904                } else if (iBase & WMSRCMM_NEEDCALC) {
1905                        ATLTRACE(_T("Wrong min-max flag in column (or row): %d. Fixed.\n"), iCR);
1906                        iBase &= ~WMSRCMM_NEEDCALC;
1907                }
1908
1909                if (bNeg) {
1910                        iBase = -iBase;
1911                }
1912        }
1913
1914        static void _CheckEqualMinMax(int iCR, int *piColRow)
1915        {
1916                _CheckEqualMinMax(iCR, piColRow[1]);
1917                _CheckEqualMinMax(iCR, piColRow[2]);
1918        }
1919
1920        static void _CheckEqualMinMax(int iCR, int &iBase)
1921        {
1922                iCR;
1923
1924                BOOL bNeg = iBase < 0;
1925
1926                if (bNeg) {
1927                        iBase = -iBase;
1928                }
1929
1930                if (!(iBase & WMSRCMM_SIZECALC)) {
1931                        ATLTRACE(_T("Equal columns/rows can't have min/max value. Ignored value in column (or row) %d.\n"), iCR);
1932                } else if (iBase & WMSRCMM_NEEDCALC) {
1933                        ATLTRACE(_T("Wrong min-max flag in column (or row): %d. Fixed.\n"), iCR);
1934                }
1935
1936                iBase = WMSRCMM_SIZECALC;
1937        }
1938
1939        static void _CheckFixedMinMax(int iCR, int *piColRow, long lXYUnits, int iXYUnitsBase, int iVal)
1940        {
1941                _CheckFixedMinMax(iCR, piColRow[1], lXYUnits, iXYUnitsBase, iVal);
1942                _CheckFixedMinMax(iCR, piColRow[2], lXYUnits, iXYUnitsBase, iVal);
1943        }
1944
1945        static void _CheckFixedMinMax(int iCR, int &iBase, long lXYUnits, int iXYUnitsBase, int iVal)
1946        {
1947                iCR;
1948
1949                BOOL bNeg = iBase < 0;
1950
1951                if (bNeg) {
1952                        iBase = -iBase;
1953                }
1954
1955                if (iBase & WMSRCMM_SIZECALC) {
1956                        iBase = WMSRCMM_SIZECALC|iVal;
1957                } else {
1958                        if (iBase & WMSRCMM_NEEDCALC) {
1959                                ATLTRACE(_T("Wrong min-max flag in column (or row): %d. Fixed.\n"), iCR);
1960                                iBase &= ~WMSRCMM_NEEDCALC;
1961                        }
1962
1963                        int iBasePix = (iBase > 0 ? ::MulDiv(iBase, lXYUnits, iXYUnitsBase) : -iBase);
1964
1965                        if (iBasePix != iVal) {
1966                                ATLTRACE(_T("Wrong min-max value in column (or row): %d. Fixed.\n"), iCR);
1967                                iBase = iVal;
1968                                bNeg = FALSE;
1969                        }
1970                }
1971
1972                if (bNeg) {
1973                        iBase = -iBase;
1974                }
1975        }
1976
1977        static void _CalcAuto(int &iVal, int iMin)
1978        {
1979                if (iVal != INT_MIN) {
1980                        if (iMin > iVal) {
1981                                iVal = iMin;
1982                        }
1983                }
1984        }
1985
1986        static void _CheckAutoMinMax(int *piColRow, int iVal)
1987        {
1988                {
1989                        BOOL bNeg = piColRow[1] < 0;
1990
1991                        if (bNeg) {
1992                                piColRow[1] = -piColRow[1];
1993                        }
1994
1995                        if (piColRow[1] & WMSRCMM_SIZECALC) {
1996                                piColRow[1] = WMSRCMM_SIZECALC|iVal;
1997                        }
1998
1999                        if (bNeg) {
2000                                piColRow[1] = -piColRow[1];
2001                        }
2002                }
2003
2004                {
2005                        BOOL bNeg = piColRow[2] < 0;
2006
2007                        if (bNeg) {
2008                                piColRow[2] = -piColRow[2];
2009                        }
2010                       
2011                        if (piColRow[2] & WMSRCMM_SIZECALC) {
2012                                piColRow[2] = WMSRCMM_SIZECALC|iVal;
2013                        }
2014
2015                        if (bNeg) {
2016                                piColRow[2] = -piColRow[2];
2017                        }
2018                }
2019        }
2020
2021        static void _CalcMinMaxAuto(int *piColRow, int iMin, int iMax)
2022        {
2023                {
2024                        BOOL bNeg = piColRow[1] < 0;
2025
2026                        if (bNeg) {
2027                                piColRow[1] = -piColRow[1];
2028                        }
2029
2030                        if (piColRow[1] & WMSRCMM_NEEDCALC) {
2031                                iMin &= WMSRCMM_VALMASK;
2032                                int iMinPix = piColRow[1] & WMSRCMM_VALMASK;
2033                                if (iMin > iMinPix) {
2034                                        piColRow[1] = WMSRCMM_SIZECALC|iMin;
2035                                }
2036                        }
2037
2038                        if (bNeg) {
2039                                piColRow[1] = -piColRow[1];
2040                        }
2041                }
2042
2043                {
2044                        BOOL bNeg = piColRow[2] < 0;
2045
2046                        if (bNeg) {
2047                                piColRow[2] = -piColRow[2];
2048                        }
2049
2050                        if (piColRow[2] & WMSRCMM_NEEDCALC) {
2051                                iMax &= WMSRCMM_VALMASK;
2052                                int iMaxPix = piColRow[2] & WMSRCMM_VALMASK;
2053                                if (iMax < iMaxPix) {
2054                                        piColRow[2] = WMSRCMM_SIZECALC|iMax;
2055                                }
2056                        }
2057
2058                        if (bNeg) {
2059                                piColRow[2] = -piColRow[2];
2060                        }
2061                }
2062        }
2063
2064        static void _SetAuto(int *piColRow, long lXYUnits, int iXYUnitsBase, int iVal)
2065        {
2066                int iTypeMin, iTypeMax;
2067                int iMinPix, iMaxPix;
2068                _LoadMinMax(piColRow, lXYUnits, iXYUnitsBase, iTypeMin, iMinPix, iTypeMax, iMaxPix);
2069
2070                _NormalizeColRow(iVal, iMinPix, iMaxPix);
2071
2072                piColRow[0] &= ~WMSRC_VALMASK;
2073                piColRow[0] |= iVal & WMSRC_VALMASK;
2074        }
2075
2076        static void _AddMinMax(int iCR, int *piColRow, long lXYUnits, int iXYUnitsBase, int &iFixed, int iType, int &iMin, int_no &iMax)
2077        {
2078                iCR;
2079                int iTypeMin, iTypeMax;
2080                int iMinPix, iMaxPix;
2081                _LoadMinMax(piColRow, lXYUnits, iXYUnitsBase, iTypeMin, iMinPix, iTypeMax, iMaxPix);
2082
2083                if (iTypeMin) {
2084                        if (iTypeMax) {
2085                                if (iMinPix > iMaxPix) {
2086                                        ATLTRACE(_T("Auto-min-value > auto-max-value in column (or row): %d. Fixed. Now auto-max-value = Auto-min-value.\n"), iCR);
2087                                        if (piColRow[2] < 0) {
2088                                                piColRow[2] = -piColRow[2];
2089                                        }
2090                                        piColRow[2] &= WMSRCMM_TYPEMASK;
2091                                        piColRow[2] |= iMinPix;
2092                                        iMaxPix = iMinPix;
2093                                }
2094                        } else {
2095                                if (iMinPix > iMaxPix) {
2096                                        ATLTRACE(_T("Auto-min-value > max-value in column (or row): %d. Fixed. Now auto-min-value = man-value.\n"), iCR);
2097                                        if (piColRow[1] < 0) {
2098                                                piColRow[1] = -piColRow[1];
2099                                        }
2100                                        piColRow[1] &= WMSRCMM_TYPEMASK;
2101                                        piColRow[1] |= iMaxPix;
2102                                        iMinPix = iMaxPix;
2103                                }
2104                        }
2105                } else if (iTypeMax) {
2106                        if (iMinPix > iMaxPix) {
2107                                ATLTRACE(_T("Min-value > auto-max-value in column (or row): %d. Fixed. Now auto-max-value = min-value.\n"), iCR);
2108                                if (piColRow[2] < 0) {
2109                                        piColRow[2] = -piColRow[2];
2110                                }
2111                                piColRow[2] &= WMSRCMM_TYPEMASK;
2112                                piColRow[2] |= iMinPix;
2113                                iMaxPix = iMinPix;
2114                        }
2115                } else {
2116                        if (iMinPix > iMaxPix) {
2117                                ATLTRACE(_T("Min-value > max-value in column (or row): %d. Fixed. Now max-value = min-value.\n"), iCR);
2118                                piColRow[2] = iMinPix;
2119                        }
2120                }
2121
2122                iMin += iMinPix;
2123
2124                if (iType != WMSRC_CONTRACTABLE) {
2125                        iMax += iMaxPix;
2126                }
2127
2128                if (iType != WMSRC_EXPANDABLE && iType != WMSRC_CONTRACTABLE) {
2129                        iFixed += iMinPix;
2130                }
2131        }
2132
2133        static void _LoadMinMax(int *piColRow, long lXYUnits, int iXYUnitsBase, int &iTypeMin, int &iMin, int &iTypeMax, int &iMax)
2134        {
2135                if (piColRow[1] >= 0) {
2136                        iTypeMin = piColRow[1] & WMSRCMM_TYPEMASK;
2137                        iMin = piColRow[1] & WMSRCMM_VALMASK;
2138                } else {
2139                        iTypeMin = (-piColRow[1]) & WMSRCMM_TYPEMASK;
2140                        iMin = -(int)((-piColRow[1]) & WMSRCMM_VALMASK);
2141                }
2142
2143                if (!iTypeMin) {
2144                        iMin = (iMin > 0 ? ::MulDiv(iMin, lXYUnits, iXYUnitsBase) : -iMin);
2145                }
2146
2147                if (piColRow[2] >= 0) {
2148                        iTypeMax = piColRow[2] & WMSRCMM_TYPEMASK;
2149                        iMax = piColRow[2] & WMSRCMM_VALMASK;
2150                } else {
2151                        iTypeMax = (-piColRow[2]) & WMSRCMM_TYPEMASK;
2152                        iMax = -(int)((-piColRow[2]) & WMSRCMM_VALMASK);
2153                }
2154
2155                if (iMax == WMSRCMM_MAXVAL) {
2156                        iMax = INT_MAX;
2157                } else if (!iTypeMax) {
2158                        iMax = (iMax > 0 ? ::MulDiv(iMax, lXYUnits, iXYUnitsBase) : -iMax);
2159                }
2160        }
2161
2162        static void _NormalizeColRow(int &iVal, int iMin, int iMax)
2163        {
2164                if (iVal < iMin) {
2165                        iVal = iMin;
2166                } else if (iVal > iMax) {
2167                        iVal = iMax;
2168                }
2169        }
2170
2171        static void _Init(CRowsIndex *&p, CRowsIndex *q)
2172        {
2173                q->m_piNum = NULL;
2174                q->m_pPrev = p;
2175                p = q;
2176        }
2177
2178        static int _DeInit(CRowsIndex *&p, int iRet)
2179        {
2180                p = p->m_pPrev;
2181                return iRet;
2182        }
2183
2184        static void _IncRow(CRowsIndex *q)
2185        {
2186                (*q->m_piNum)++;
2187        }
2188
2189        static int _FirstParam(int a = 0, int b = 0, int c = 0, int d = 0)
2190        {
2191                b; c; d;
2192                return a;
2193        }
2194
2195        static int _SecondParam(int a = 0, int b = 0, int c = 0, int d = 0)
2196        {
2197                a; c; d;
2198                return b;
2199        }
2200
2201        static int _ThirdParam(int a = 0, int b = 0, int c = 0, int d = 0)
2202        {
2203                a; b; d;
2204                return c;
2205        }
2206
2207        static int _FourthParam(int a = 0, int b = 0, int c = 0, int d = 0)
2208        {
2209                a; b; c;
2210                return d;
2211        }
2212
2213        //
2214
2215protected:
2216        BOOL InitializeTransparentCtrl(int iCtrl)
2217        {
2218                T* pT = static_cast<T*>(this);
2219                HWND hWnd = pT->GetDlgItem(iCtrl);
2220
2221                if (hWnd) {
2222                        TCHAR szName[256];
2223                        ATLVERIFY(::GetClassName(hWnd, szName, 256));
2224
2225                        WNDPROC wp;
2226                        if (::_tcscmp(_T("Button"), szName) == 0) {
2227                                wp = TransparentWindowProc<1>;
2228                        } else {
2229                                wp = TransparentWindowProc<0>;
2230                        }
2231
2232                        ::ShowWindow(hWnd, SW_HIDE);
2233                        WNDPROC wpOld = (WNDPROC)::SetWindowLongPtr(hWnd, GWLP_WNDPROC, (LONG_PTR)wp);
2234                        ATLVERIFY(::SetWindowLongPtr(hWnd, GWLP_USERDATA, (LONG_PTR)wpOld) == 0);
2235                }
2236
2237                return TRUE;
2238        }
2239
2240        BOOL DrawTransparentCtrl(WTL::CDCHandle dc, int iCtrl)
2241        {
2242                T* pT = static_cast<T*>(this);
2243                HWND hWnd = pT->GetDlgItem(iCtrl);
2244
2245                if (hWnd) {
2246                        RECT rect;
2247                        ::GetWindowRect(hWnd, &rect);
2248                        ::MapWindowPoints(NULL, pT->m_hWnd, (LPPOINT)&rect, 1);
2249
2250                        POINT pt;
2251                        dc.SetViewportOrg(rect.left, rect.top, &pt);
2252
2253                        ::SendMessage(hWnd, WM_PRINT, (WPARAM)dc.m_hDC, PRF_CHILDREN|PRF_CLIENT|PRF_NONCLIENT|PRF_OWNED);
2254
2255                        dc.SetViewportOrg(pt.x, pt.y);
2256                }
2257
2258                return TRUE;
2259        }
2260
2261        template <int t_iType>
2262        static LRESULT CALLBACK TransparentWindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
2263        {
2264                int iOffset, iOffsetTop;
2265
2266                if (t_iType) {
2267                        iOffsetTop = 5;
2268                        iOffset = 5;
2269                } else {
2270                        iOffsetTop = 5;
2271                        iOffset = 5;
2272                }
2273
2274                if (uMsg == WM_WINDOWPOSCHANGING) {
2275                        WINDOWPOS *pwp = (WINDOWPOS*)lParam;
2276
2277                        if ((pwp->flags & (SWP_NOSIZE|SWP_NOMOVE)) == 0) {
2278                                HWND hWndParent = ::GetParent(hWnd);
2279                                RECT rectOld, rectNew, rectMax;
2280                                ::GetWindowRect(hWnd, &rectOld);
2281                                ::MapWindowPoints(NULL, hWndParent, (LPPOINT)&rectOld, 2);
2282
2283                                if ((pwp->flags & SWP_NOMOVE) == 0) {
2284                                        rectNew.left = pwp->x;
2285                                        rectNew.top = pwp->y;
2286                                } else {
2287                                        rectNew.left = rectOld.left;
2288                                        rectNew.top = rectOld.top;
2289                                }
2290
2291                                if ((pwp->flags & SWP_NOSIZE) == 0) {
2292                                        rectNew.right = pwp->cx;
2293                                        rectNew.bottom = pwp->cy;
2294                                } else {
2295                                        rectNew.right = rectOld.right - rectOld.left;
2296                                        rectNew.bottom = rectOld.bottom - rectOld.top;
2297                                }
2298
2299                                rectNew.right += rectNew.left;
2300                                rectNew.bottom += rectNew.top;
2301
2302                                rectMax.left = min(rectOld.left, rectNew.left);
2303                                rectMax.top = min(rectOld.top, rectNew.top);
2304                                rectMax.right = max(rectOld.right, rectNew.right);
2305                                rectMax.bottom = max(rectOld.bottom, rectNew.bottom);
2306
2307                                int iAreaOld = (rectOld.right - rectOld.left) * (rectOld.bottom - rectOld.top);
2308                                int iAreaNew = (rectNew.right - rectNew.left) * (rectNew.bottom - rectNew.top);
2309                                RECT rectInv[4];
2310                                int iArea[] = {0, 0, 0, 0};
2311
2312                                if (rectOld.left < rectNew.left) {
2313                                        RECT rect = {rectOld.left, rectMax.top, rectNew.left + iOffset, rectMax.bottom};
2314                                        iArea[0] = (rect.right - rect.left) * (rect.bottom - rect.top);
2315                                        rectInv[0] = rect;
2316                                } else if (rectOld.left > rectNew.left) {
2317                                        RECT rect = {rectNew.left, rectMax.top, rectOld.left + iOffset, rectMax.bottom};
2318                                        iArea[0] = (rect.right - rect.left) * (rect.bottom - rect.top);
2319                                        rectInv[0] = rect;
2320                                }
2321
2322                                if (rectOld.right < rectNew.right) {
2323                                        RECT rect = {rectOld.right - iOffset, rectMax.top, rectNew.right, rectMax.bottom};
2324                                        iArea[1] = (rect.right - rect.left) * (rect.bottom - rect.top);
2325                                        rectInv[1] = rect;
2326                                } else if (rectOld.right > rectNew.right) {
2327                                        RECT rect = {rectNew.right - iOffset, rectMax.top, rectOld.right, rectMax.bottom};
2328                                        iArea[1] = (rect.right - rect.left) * (rect.bottom - rect.top);
2329                                        rectInv[1] = rect;
2330                                }
2331
2332                                if (rectOld.top != rectNew.top) {
2333                                        if (t_iType) {
2334                                                HWND hWndParent = ::GetParent(hWnd);
2335                                                int iHeight = _GetFontSize(hWnd, hWndParent);
2336
2337                                                iOffsetTop += iHeight / 2;
2338                                        }
2339
2340                                        if (rectOld.top < rectNew.top) {
2341                                                RECT rect = {rectMax.left, rectOld.top, rectMax.right, rectNew.top + iOffsetTop};
2342                                                iArea[2] = (rect.right - rect.left) * (rect.bottom - rect.top);
2343                                                rectInv[2] = rect;
2344                                        } else if (rectOld.top > rectNew.top) {
2345                                                RECT rect = {rectMax.left, rectNew.top, rectMax.right, rectOld.top + iOffsetTop};
2346                                                iArea[2] = (rect.right - rect.left) * (rect.bottom - rect.top);
2347                                                rectInv[2] = rect;
2348                                        }
2349                                }
2350
2351                                if (rectOld.bottom < rectNew.bottom) {
2352                                        RECT rect = {rectMax.left, rectOld.bottom - iOffset, rectMax.right, rectNew.bottom};
2353                                        iArea[3] = (rect.right - rect.left) * (rect.bottom - rect.top);
2354                                        rectInv[3] = rect;
2355                                } else if (rectOld.bottom > rectNew.bottom) {
2356                                        RECT rect = {rectMax.left, rectNew.bottom - iOffset, rectMax.right, rectOld.bottom};
2357                                        iArea[3] = (rect.right - rect.left) * (rect.bottom - rect.top);
2358                                        rectInv[3] = rect;
2359                                }
2360
2361                                int iAreaTot1 = iAreaOld + iAreaNew;
2362                                int iAreaTot2 = iArea[0] + iArea[1] + iArea[2] + iArea[3];
2363
2364                                if (iAreaTot1 <= iAreaTot2) {
2365                                        ::InvalidateRect(hWndParent, &rectOld, TRUE);
2366                                        ::InvalidateRect(hWndParent, &rectNew, TRUE);
2367                                } else {
2368                                        for (int i = 0; i < 4; i++) {
2369                                                if (iArea[i]) {
2370                                                        ::InvalidateRect(hWndParent, &rectInv[i], TRUE);
2371                                                }
2372                                        }
2373                                }
2374                        }
2375                } else if (t_iType && uMsg == WM_UPDATEUISTATE) {
2376                        if (HIWORD(wParam) & UISF_HIDEACCEL) {
2377                                HWND hWndParent = ::GetParent(hWnd);
2378                                int iHeight = _GetFontSize(hWnd, hWndParent);
2379
2380                                RECT rect;
2381                                ::GetWindowRect(hWnd, &rect);
2382                                ::MapWindowPoints(NULL, hWndParent, (LPPOINT)&rect, 2);
2383                                rect.bottom = rect.top + iHeight + 2;
2384
2385                                ::InvalidateRect(hWndParent, &rect, TRUE);
2386                        }
2387                }
2388
2389                WNDPROC wp = (WNDPROC)(LONG_PTR)::GetWindowLongPtr(hWnd, GWLP_USERDATA);
2390                return ::CallWindowProc(wp, hWnd, uMsg, wParam, lParam);
2391        }
2392
2393        static int _GetFontSize(HWND hWnd, HWND hWndParent)
2394        {
2395                HFONT hFont = (HFONT)::SendMessage(hWnd, WM_GETFONT, 0, 0);
2396
2397                HDC hDC = ::GetDC(hWndParent);
2398
2399                HFONT hOldFont = (HFONT)::SelectObject(hDC, (HGDIOBJ)hFont);
2400
2401                TEXTMETRIC tm;
2402                ::GetTextMetrics(hDC, &tm);
2403
2404                ::SelectObject(hDC, (HGDIOBJ)hOldFont);
2405
2406                return tm.tmHeight - tm.tmDescent;
2407
2408//              Not used anymore (better results with GetTextMetrics):
2409//              LOGFONT lf;
2410//              ::GetObject(hFont, sizeof(LOGFONT), (HGDIOBJ)&lf)
2411//              return -MulDiv(lf.lfHeight, 72, dc.GetDeviceCaps(LOGPIXELSY));
2412        }
2413};
2414
2415//
2416
2417} // namespace ATL
2418
2419//
2420
2421#endif // __ATLAUTOSIZEDLG_H__
Note: See TracBrowser for help on using the repository browser.