Merge XFA to PDFium master at 4dc95e7 on 10/28/2014
[pdfium.git] / xfa_test / FormFiller_Test / FX_SplitterWnd.cpp
1 // FX_SplitterWnd.cpp: implementation of the CFX_SplitterWnd class.\r
2 //\r
3 //////////////////////////////////////////////////////////////////////\r
4 \r
5 #include "stdafx.h"\r
6 //#include "teststatusbar.h"\r
7 #include "FX_SplitterWnd.h"\r
8 \r
9 #include <afxpriv.h>\r
10 \r
11 #ifdef _DEBUG\r
12 #undef THIS_FILE\r
13 static char THIS_FILE[]=__FILE__;\r
14 #define new DEBUG_NEW\r
15 #endif\r
16 \r
17 //////////////////////////////////////////////////////////////////////\r
18 // Construction/Destruction\r
19 //////////////////////////////////////////////////////////////////////\r
20 \r
21 CFX_SplitterWnd::CFX_SplitterWnd()\r
22 {\r
23         m_cxSplitter    = m_cySplitter = 4 + 1 + 1;\r
24         m_cxBorderShare = m_cyBorderShare = 0;\r
25         m_cxSplitterGap = m_cySplitterGap = 4 + 1 + 1;\r
26         m_cxBorder              = m_cyBorder = 1;\r
27         m_nHidedCol             = -1;\r
28         m_bBarLocked    = FALSE;\r
29 }\r
30 \r
31 CFX_SplitterWnd::~CFX_SplitterWnd()\r
32 {\r
33 \r
34 }\r
35 \r
36 BEGIN_MESSAGE_MAP(CFX_SplitterWnd, CSplitterWnd)\r
37         //{{AFX_MSG_MAP(CFX_SplitterWnd)\r
38         ON_WM_LBUTTONDOWN()\r
39         ON_WM_MOUSEMOVE()\r
40         //}}AFX_MSG_MAP\r
41 END_MESSAGE_MAP()\r
42 \r
43 void CFX_SplitterWnd::OnDrawSplitter(CDC *pDC,ESplitType nType,const CRect &rectArg)\r
44 {\r
45         if((nType != splitBorder) || (pDC == NULL))\r
46         {\r
47                 CSplitterWnd::OnDrawSplitter(pDC, nType, rectArg);\r
48                 return;\r
49         }\r
50 \r
51         pDC->Draw3dRect(rectArg, GetSysColor(COLOR_BTNSHADOW), GetSysColor(COLOR_BTNHIGHLIGHT));\r
52 }\r
53 void CFX_SplitterWnd::RecalcLayout()\r
54 {\r
55         ASSERT_VALID(this);\r
56         ASSERT(m_nRows > 0 && m_nCols > 0); // must have at least one pane\r
57 \r
58         CRect rectClient;\r
59         GetClientRect(rectClient);\r
60         rectClient.InflateRect(-m_cxBorder, -m_cyBorder);\r
61 \r
62         CRect rectInside;\r
63         GetInsideRect(rectInside);\r
64 \r
65         // layout columns (restrict to possible sizes)\r
66         LayoutRowCol(m_pColInfo, m_nCols, rectInside.Width(), m_cxSplitterGap);\r
67         LayoutRowCol(m_pRowInfo, m_nRows, rectInside.Height(), m_cySplitterGap);\r
68 \r
69         // adjust the panes (and optionally scroll bars)\r
70 \r
71         // give the hint for the maximum number of HWNDs\r
72         AFX_SIZEPARENTPARAMS layout;\r
73         layout.hDWP = ::BeginDeferWindowPos((m_nCols + 1) * (m_nRows + 1) + 1);\r
74 \r
75         // size of scrollbars\r
76         int cx = rectClient.right - rectInside.right;\r
77         int cy = rectClient.bottom - rectInside.bottom;\r
78 \r
79         // reposition size box\r
80         if (m_bHasHScroll && m_bHasVScroll)\r
81         {\r
82                 CWnd* pScrollBar = GetDlgItem(AFX_IDW_SIZE_BOX);\r
83                 ASSERT(pScrollBar != NULL);\r
84 \r
85                 // fix style if necessary\r
86                 BOOL bSizingParent = (GetSizingParent() != NULL);\r
87                 // modifyStyle returns TRUE if style changes\r
88                 if (pScrollBar->ModifyStyle(SBS_SIZEGRIP|SBS_SIZEBOX,\r
89                                 bSizingParent ? SBS_SIZEGRIP : SBS_SIZEBOX))\r
90                         pScrollBar->Invalidate();\r
91                 pScrollBar->EnableWindow(bSizingParent);\r
92 \r
93                 // reposition the size box\r
94                 DeferClientPos(&layout, pScrollBar,\r
95                         rectInside.right,\r
96                         rectInside.bottom, cx, cy, TRUE);\r
97         }\r
98 \r
99         // reposition scroll bars\r
100         if (m_bHasHScroll)\r
101         {\r
102                 int cxSplitterBox = m_cxSplitter;// split box bigger\r
103                 int x = rectClient.left;\r
104                 int y = rectInside.bottom;\r
105                 for (int col = 0; col < m_nCols; col++)\r
106                 {\r
107                         CWnd* pScrollBar = GetDlgItem(AFX_IDW_HSCROLL_FIRST + col);\r
108                         ASSERT(pScrollBar != NULL);\r
109                         int cx = m_pColInfo[col].nCurSize;\r
110                         if (col == 0 && m_nCols < m_nMaxCols)\r
111                                 x += cxSplitterBox, cx -= cxSplitterBox;\r
112                         DeferClientPos(&layout, pScrollBar, x, y, cx, cy, TRUE);\r
113                         x += cx + m_cxSplitterGap;\r
114                 }\r
115         }\r
116 \r
117         if (m_bHasVScroll)\r
118         {\r
119                 int cySplitterBox = m_cySplitter;// split box bigger\r
120                 int x = rectInside.right;\r
121                 int y = rectClient.top;\r
122                 for (int row = 0; row < m_nRows; row++)\r
123                 {\r
124                         CWnd* pScrollBar = GetDlgItem(AFX_IDW_VSCROLL_FIRST + row);\r
125                         ASSERT(pScrollBar != NULL);\r
126                         int cy = m_pRowInfo[row].nCurSize;\r
127                         if (row == 0 && m_nRows < m_nMaxRows)\r
128                                 y += cySplitterBox, cy -= cySplitterBox;\r
129                         DeferClientPos(&layout, pScrollBar, x, y, cx, cy, TRUE);\r
130                         y += cy + m_cySplitterGap;\r
131                 }\r
132         }\r
133 \r
134         //BLOCK: Reposition all the panes\r
135         {\r
136                 int x = rectClient.left;\r
137                 for (int col = 0; col < m_nCols; col++)\r
138                 {\r
139                         int cx = m_pColInfo[col].nCurSize;\r
140                         int y = rectClient.top;\r
141                         for (int row = 0; row < m_nRows; row++)\r
142                         {\r
143                                 int cy = m_pRowInfo[row].nCurSize;\r
144                                 CWnd* pWnd = GetPane(row, col);\r
145                                 DeferClientPos(&layout, pWnd, x, y, cx, cy, FALSE);\r
146                                 y += cy + m_cySplitterGap;\r
147                         }\r
148                         x += cx + m_cxSplitterGap;\r
149                 }\r
150         }\r
151 \r
152         // move and resize all the windows at once!\r
153         if (layout.hDWP == NULL || !::EndDeferWindowPos(layout.hDWP))\r
154                 TRACE0("Warning: DeferWindowPos failed - low system resources.\n");\r
155 \r
156         // invalidate all the splitter bars (with NULL pDC)\r
157         DrawAllSplitBars(NULL, rectInside.right, rectInside.bottom);\r
158 }\r
159 \r
160 void CFX_SplitterWnd::DeferClientPos(AFX_SIZEPARENTPARAMS *lpLayout,CWnd *pWnd,int x,int y,int cx,int cy,BOOL bScrollBar)\r
161 {\r
162         ASSERT(pWnd != NULL);\r
163         ASSERT(pWnd->m_hWnd != NULL);\r
164 \r
165         if (bScrollBar)\r
166         {\r
167                 // if there is enough room, draw scroll bar without border\r
168                 // if there is not enough room, set the WS_BORDER bit so that\r
169                 //   we will at least get a proper border drawn\r
170                 BOOL bNeedBorder = (cx <= 1 || cy <= 1);\r
171                 pWnd->ModifyStyle(bNeedBorder ? 0 : 1, bNeedBorder ? 1 : 0);\r
172         }\r
173         CRect rect(x, y, x+cx, y+cy);\r
174 \r
175         // adjust for 3d border (splitter windows have implied border)\r
176         if ((pWnd->GetExStyle() & WS_EX_CLIENTEDGE) || pWnd->IsKindOf(RUNTIME_CLASS(CSplitterWnd)))\r
177         {\r
178                 rect.InflateRect(1, 1); // for proper draw CFlatSplitterWnd in view\r
179 //              rect.InflateRect(afxData.cxBorder2, afxData.cyBorder2);\r
180         }\r
181 \r
182         // first check if the new rectangle is the same as the current\r
183         CRect rectOld;\r
184         pWnd->GetWindowRect(rectOld);\r
185         pWnd->GetParent()->ScreenToClient(&rectOld);\r
186         if (rect != rectOld)\r
187                 AfxRepositionWindow(lpLayout, pWnd->m_hWnd, rect);\r
188 }\r
189 \r
190 void CFX_SplitterWnd::LayoutRowCol(CSplitterWnd::CRowColInfo *pInfoArray,int nMax,int nSize,int nSizeSplitter)\r
191 {\r
192         ASSERT(pInfoArray != NULL);\r
193         ASSERT(nMax > 0);\r
194         ASSERT(nSizeSplitter > 0);\r
195 \r
196         CSplitterWnd::CRowColInfo* pInfo;\r
197         int i;\r
198 \r
199         if (nSize < 0)\r
200                 nSize = 0;  // if really too small, layout as zero size\r
201 \r
202         // start with ideal sizes\r
203         for (i = 0, pInfo = pInfoArray; i < nMax-1; i++, pInfo++)\r
204         {\r
205                 if (pInfo->nIdealSize < pInfo->nMinSize)\r
206                         pInfo->nIdealSize = 0;      // too small to see\r
207                 pInfo->nCurSize = pInfo->nIdealSize;\r
208         }\r
209         pInfo->nCurSize = INT_MAX;  // last row/column takes the rest\r
210 \r
211         for (i = 0, pInfo = pInfoArray; i < nMax; i++, pInfo++)\r
212         {\r
213                 ASSERT(nSize >= 0);\r
214                 if (nSize == 0)\r
215                 {\r
216                         // no more room (set pane to be invisible)\r
217                         pInfo->nCurSize = 0;\r
218                         continue;       // don't worry about splitters\r
219                 }\r
220                 else if (nSize < pInfo->nMinSize && i != 0)\r
221                 {\r
222                         // additional panes below the recommended minimum size\r
223                         //   aren't shown and the size goes to the previous pane\r
224                         pInfo->nCurSize = 0;\r
225 \r
226                         // previous pane already has room for splitter + border\r
227                         //   add remaining size and remove the extra border\r
228                         (pInfo-1)->nCurSize += nSize + 2;\r
229                         nSize = 0;\r
230                 }\r
231                 else\r
232                 {\r
233                         // otherwise we can add the second pane\r
234                         ASSERT(nSize > 0);\r
235                         if (pInfo->nCurSize == 0)\r
236                         {\r
237                                 // too small to see\r
238                                 if (i != 0)\r
239                                         pInfo->nCurSize = 0;\r
240                         }\r
241                         else if (nSize < pInfo->nCurSize)\r
242                         {\r
243                                 // this row/col won't fit completely - make as small as possible\r
244                                 pInfo->nCurSize = nSize;\r
245                                 nSize = 0;\r
246                         }\r
247                         else\r
248                         {\r
249                                 // can fit everything\r
250                                 nSize -= pInfo->nCurSize;\r
251                         }\r
252                 }\r
253 \r
254                 // see if we should add a splitter\r
255                 ASSERT(nSize >= 0);\r
256                 if (i != nMax - 1)\r
257                 {\r
258                         // should have a splitter\r
259                         if (nSize > nSizeSplitter)\r
260                         {\r
261                                 nSize -= nSizeSplitter; // leave room for splitter + border\r
262                                 ASSERT(nSize > 0);\r
263                         }\r
264                         else\r
265                         {\r
266                                 // not enough room - add left over less splitter size\r
267                                 pInfo->nCurSize += nSize;\r
268                                 if (pInfo->nCurSize > (nSizeSplitter - 2))\r
269                                         pInfo->nCurSize -= (nSizeSplitter - 2);\r
270                                 nSize = 0;\r
271                         }\r
272                 }\r
273         }\r
274         ASSERT(nSize == 0); // all space should be allocated\r
275 }\r
276 \r
277 void CFX_SplitterWnd::HideColumn(int nCol)\r
278 {\r
279         if ( m_nHidedCol != -1 )\r
280                 return;\r
281 \r
282         ASSERT_VALID(this);\r
283         ASSERT(m_nCols > 1);\r
284         ASSERT(nCol < m_nCols);\r
285         ASSERT(m_nHidedCol == -1);\r
286         m_nHidedCol = nCol;\r
287         \r
288     // if the column has an active window -- change it\r
289         int rowActive, colActive;\r
290         if (GetActivePane(&rowActive, &colActive) != NULL &&\r
291                 colActive == nCol)\r
292         {\r
293                 if (++colActive >= m_nCols)\r
294                         colActive = 0;\r
295                 SetActivePane(rowActive, colActive);\r
296         }\r
297         \r
298     // hide all column panes\r
299         for (int row = 0; row < m_nRows; row++)\r
300         {\r
301                 CWnd* pPaneHide = GetPane(row, nCol);\r
302                 ASSERT(pPaneHide != NULL);\r
303                 pPaneHide->ShowWindow(SW_HIDE);\r
304                 pPaneHide->SetDlgCtrlID(\r
305                         AFX_IDW_PANE_FIRST + row * 16 + m_nCols);\r
306                 \r
307                 for (int col = nCol + 1; col < m_nCols; col++)\r
308                 {\r
309                         CWnd* pPane = GetPane(row, col);\r
310                         ASSERT(pPane != NULL);\r
311                         pPane->SetDlgCtrlID(IdFromRowCol(row, col - 1));\r
312                 }\r
313         }\r
314         m_nCols--;\r
315         m_pColInfo[m_nCols].nCurSize = m_pColInfo[nCol].nCurSize;\r
316         RecalcLayout();\r
317 }\r
318 \r
319 void CFX_SplitterWnd::ShowColumn()\r
320 {\r
321         if ( m_nHidedCol == -1 )\r
322                 return;\r
323 \r
324         ASSERT_VALID(this);\r
325         ASSERT(m_nCols < m_nMaxCols);\r
326         ASSERT(m_nHidedCol != -1);\r
327         \r
328         int colNew = m_nHidedCol;\r
329         m_nHidedCol = -1;\r
330         int cxNew = m_pColInfo[m_nCols].nCurSize;\r
331         m_nCols++;  // add a column\r
332         ASSERT(m_nCols == m_nMaxCols);\r
333         \r
334     // fill the hided column\r
335         int col;\r
336         for (int row = 0; row < m_nRows; row++)\r
337         {\r
338                 CWnd* pPaneShow = GetDlgItem(\r
339                         AFX_IDW_PANE_FIRST + row * 16 + m_nCols);\r
340                 ASSERT(pPaneShow != NULL);\r
341                 pPaneShow->ShowWindow(SW_SHOWNA);\r
342                 \r
343                 for (col = m_nCols - 2; col >= colNew; col--)\r
344                 {\r
345                         CWnd* pPane = GetPane(row, col);\r
346                         ASSERT(pPane != NULL);\r
347                         pPane->SetDlgCtrlID(IdFromRowCol(row, col + 1));\r
348                 }\r
349                 \r
350                 pPaneShow->SetDlgCtrlID(IdFromRowCol(row, colNew));\r
351         }\r
352         \r
353     // new panes have been created -- recalculate layout\r
354         for (col = colNew + 1; col < m_nCols; col++)\r
355                 m_pColInfo[col].nIdealSize = m_pColInfo[col - 1].nCurSize;\r
356         m_pColInfo[colNew].nIdealSize = cxNew;\r
357 \r
358         RecalcLayout();\r
359 }\r
360 \r
361 void CFX_SplitterWnd::OnLButtonDown(UINT nFlags, CPoint point) \r
362 {\r
363         if (!m_bBarLocked)\r
364                 CSplitterWnd::OnLButtonDown(nFlags, point);\r
365 }\r
366 \r
367 void CFX_SplitterWnd::OnMouseMove(UINT nFlags, CPoint point) \r
368 {\r
369         if (!m_bBarLocked)\r
370                 CSplitterWnd::OnMouseMove(nFlags, point);\r
371         else\r
372                 CWnd::OnMouseMove(nFlags, point);       \r
373 }\r