source: src/AtlAutosizeDlg.h @ 314

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

UI adjustments.

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