soui 5.0.0.1
Soui5 Doc
 
Loading...
Searching...
No Matches
SSplitWnd.cpp
1#include "souistd.h"
2#include "control/SSplitWnd.h"
3
4SNSBEGIN
5
6#define DEF_SEPSIZE 5
7
9 : m_nPriority(0)
10 , m_nSizeIdeal(20, SLayoutSize::dp)
11 , m_nSizeMin(0, SLayoutSize::dp)
12 , m_nSizeMax(10000, SLayoutSize::dp)
13{
14 GetEventSet()->addEvent(EVENTID(EventSplitPaneMoved));
15}
16
17void SSplitPane::Move(CRect rc)
18{
19 SWindow::Move(rc);
20 EventSplitPaneMoved evt(this);
21 evt.rcPane = rc;
22 FireEvent(evt);
23}
24
25//////////////////////////////////////////////////////////////////////////
27 : m_orintation(Vertical)
28 , m_bAdjustable(TRUE)
29 , m_spliterSize(DEF_SEPSIZE)
30 , m_pSkinSep(NULL)
31 , m_iDragSep(-1)
32{
33}
34
38
39BOOL SSplitWnd::ShowPane(UINT iPane)
40{
41 if (iPane < 0 || iPane >= m_lstPane.GetCount())
42 return FALSE;
43
44 m_lstPane[iPane]->SetVisible(TRUE);
46 return TRUE;
47}
48
49BOOL SSplitWnd::HidePane(UINT iPane)
50{
51 if (iPane < 0 || iPane >= m_lstPane.GetCount())
52 return FALSE;
53
54 m_lstPane[iPane]->SetVisible(FALSE);
56 return TRUE;
57}
58
60{
61 if (!xmlNode)
62 return FALSE;
63 SXmlNode xmlPane = xmlNode.child(SSplitPane::GetClassName());
64 while (xmlPane)
65 {
66 SSplitPane *pPane = new SSplitPane();
67 InsertChild(pPane);
68 if (pPane->InitFromXml(&xmlPane))
69 {
70 InsertItem(pPane);
71 }
72 xmlPane = xmlPane.next_sibling(SSplitPane::GetClassName());
73 }
74 return TRUE;
75}
76
77BOOL SSplitWnd::OnSetCursor(const CPoint &pt)
78{
79 if (!m_bAdjustable)
80 return FALSE;
81 HCURSOR hCursor = GETRESPROVIDER->LoadCursor((m_orintation == Vertical) ? IDC_SIZEWE : IDC_SIZENS);
82 SetCursor(hCursor);
83 return TRUE;
84}
85
87{
88 if (!m_pSkinSep)
89 return;
90
91 CRect rcClient;
92 GetChildrenLayoutRect(&rcClient);
93
94 CRect rcSep = rcClient;
95 if (m_orintation == Vertical)
96 rcSep.right = rcClient.left;
97 else
98 rcSep.bottom = rcSep.top;
99
100 LONG &RB = (m_orintation == Vertical) ? rcSep.right : rcSep.bottom;
101 LONG &LT = (m_orintation == Vertical) ? rcSep.left : rcSep.top;
102
103 for (int i = 0; i < (int)m_lstPane.GetCount() - 1; i++)
104 {
105 if (!m_lstPane[i]->IsVisible())
106 continue;
107 CRect rcPane = m_lstPane[i]->GetWindowRect();
108 RB += (m_orintation == Vertical) ? rcPane.Width() : rcPane.Height();
109 LT = RB;
110 RB += m_spliterSize;
111 m_pSkinSep->DrawByIndex(pRT, rcSep, 0);
112 }
113}
114
115void SSplitWnd::OnLButtonDown(UINT nFlags, CPoint pt)
116{
117 __baseCls::OnLButtonDown(nFlags, pt);
118
119 if (!m_bAdjustable)
120 return;
121
122 m_ptDragPrev = pt;
123 if (m_orintation == Vertical)
124 {
125 for (int i = 0; i < (int)m_lstPane.GetCount(); i++)
126 {
127 if (m_ptDragPrev.x < m_lstPane[i]->GetWindowRect().left)
128 {
129 m_iDragSep = i - 1;
130 break;
131 }
132 }
133 }
134 else
135 {
136 for (int i = 0; i < (int)m_lstPane.GetCount(); i++)
137 {
138 if (m_ptDragPrev.y < m_lstPane[i]->GetWindowRect().top)
139 {
140 m_iDragSep = i - 1;
141 break;
142 }
143 }
144 }
145}
146
147void SSplitWnd::OnLButtonUp(UINT nFlags, CPoint pt)
148{
149 __baseCls::OnLButtonUp(nFlags, pt);
150 m_iDragSep = -1;
151}
152
153void SSplitWnd::OnMouseMove(UINT nFlags, CPoint pt)
154{
155 if (-1 == m_iDragSep)
156 return;
157
158 //将列表分裂成两组。
159 SplitPaneList lstPane1, lstPane2;
160 SplitPaneList lstPriority1, lstPriority2;
161
162 for (int i = 0; i < (int)m_lstPane.GetCount(); i++)
163 {
164 if (i <= m_iDragSep)
165 lstPane1.Add(m_lstPane[i]);
166 else
167 lstPane2.Add(m_lstPane[i]);
168 }
169
170 for (int i = 0; i < (int)m_lstPriority.GetCount(); i++)
171 {
172 SSplitPane *pane = m_lstPriority[i];
173 int idx = m_lstPane.Find(pane);
174 SASSERT(idx != -1);
175 if (idx <= m_iDragSep)
176 lstPriority1.Add(pane);
177 else
178 lstPriority2.Add(pane);
179 }
180
181 CPoint diffPoint = m_ptDragPrev;
182 m_ptDragPrev = pt;
183 diffPoint = m_ptDragPrev - diffPoint;
184 int diff = m_orintation == Vertical ? diffPoint.x : diffPoint.y;
185
186 PANESIZELIST lstPaneSize1, lstPaneSize2;
187 FatchPaneSizeInfo(lstPriority1, lstPaneSize1);
188 FatchPaneSizeInfo(lstPriority2, lstPaneSize2);
189
190 if (diff > 0)
191 {
192 int maxShrink = 0, maxExtent = 0;
193 for (int i = 0; i < (int)lstPaneSize1.GetCount(); i++)
194 {
195 maxExtent += lstPaneSize1[i].maximum - lstPaneSize1[i].actural;
196 }
197 for (int i = 0; i < (int)lstPaneSize2.GetCount(); i++)
198 {
199 maxShrink += lstPaneSize2[i].actural - lstPaneSize2[i].minimum;
200 }
201 diff = smin(diff, smin(maxShrink, maxExtent));
202 if (diff == 0)
203 return;
204
205 //伸长part1
206 int idxPrev = lstPriority1.Find(lstPane1.GetAt(lstPane1.GetCount() - 1));
207 SASSERT(idxPrev != -1);
208 PANESIZE &paneSize1 = lstPaneSize1[idxPrev];
209
210 int max_digest = paneSize1.maximum - paneSize1.actural;
211 if (max_digest > diff)
212 {
213 paneSize1.actural += diff;
214 }
215 else
216 {
217 paneSize1.actural += max_digest;
218 PANESIZE szBackup = paneSize1;
219 lstPaneSize1.RemoveAt(idxPrev);
220 int remain = diff - max_digest;
221 AdjustPanesSize(lstPaneSize1, remain);
222 lstPaneSize1.InsertAt(idxPrev, szBackup);
223 }
224
225 //压缩part2
226 int idxNext = lstPriority2.Find(lstPane2[0]);
227 SASSERT(idxNext != -1);
228 PANESIZE &paneSize2 = lstPaneSize2[idxNext];
229
230 max_digest = paneSize2.actural - paneSize2.minimum;
231 if (max_digest > diff)
232 {
233 paneSize2.actural -= diff;
234 }
235 else
236 {
237 paneSize2.actural -= max_digest;
238 PANESIZE szBackup = paneSize2;
239 lstPaneSize2.RemoveAt(idxNext);
240 int remain = max_digest - diff; // remain < 0
241 AdjustPanesSize(lstPaneSize2, remain);
242 lstPaneSize2.InsertAt(idxNext, szBackup);
243 }
244 }
245 else
246 {
247 int maxShrink = 0, maxExtent = 0;
248 for (int i = 0; i < (int)lstPaneSize2.GetCount(); i++)
249 {
250 maxExtent += lstPaneSize2[i].maximum - lstPaneSize2[i].actural;
251 }
252 for (int i = 0; i < (int)lstPaneSize1.GetCount(); i++)
253 {
254 maxShrink += lstPaneSize1[i].actural - lstPaneSize1[i].minimum;
255 }
256
257 diff *= -1;
258 diff = smin(diff, smin(maxShrink, maxExtent));
259 if (diff == 0)
260 return;
261
262 //压缩part1
263 int idxPrev = lstPriority1.Find(lstPane1.GetAt(lstPane1.GetCount() - 1));
264 SASSERT(idxPrev != -1);
265 PANESIZE &paneSize1 = lstPaneSize1[idxPrev];
266
267 int max_digest = paneSize1.actural - paneSize1.minimum;
268 if (max_digest > diff)
269 {
270 paneSize1.actural -= diff;
271 }
272 else
273 {
274 paneSize1.actural -= max_digest;
275 PANESIZE szBackup = paneSize1;
276 lstPaneSize1.RemoveAt(idxPrev);
277 int remain = max_digest - diff; // remain < 0
278 AdjustPanesSize(lstPaneSize1, remain);
279 lstPaneSize1.InsertAt(idxPrev, szBackup);
280 }
281
282 //伸长part2
283 int idxNext = lstPriority2.Find(lstPane2[0]);
284 SASSERT(idxNext != -1);
285 PANESIZE &paneSize2 = lstPaneSize2[idxNext];
286
287 max_digest = paneSize2.maximum - paneSize2.actural;
288 if (max_digest > diff)
289 {
290 paneSize2.actural += diff;
291 }
292 else
293 {
294 paneSize2.actural += max_digest;
295 PANESIZE szBackup = paneSize2;
296 lstPaneSize2.RemoveAt(idxNext);
297 int remain = diff - max_digest;
298 AdjustPanesSize(lstPaneSize2, remain);
299 lstPaneSize2.InsertAt(idxNext, szBackup);
300 }
301 diff *= -1;
302 }
303 //根据新分配的窗口大小重置窗口位置
304 CRect rcClient;
305 GetChildrenLayoutRect(&rcClient);
306 int nOffset = m_orintation == Vertical ? rcClient.left : rcClient.top;
307 nOffset = ResetPanesPostion(lstPane1, lstPriority1, lstPaneSize1, nOffset);
308 ResetPanesPostion(lstPane2, lstPriority2, lstPaneSize2, nOffset);
309 Invalidate();
310 Update();
311}
312
313int SSplitWnd::PaneIndex(const SStringW &strName) const
314{
315 for (UINT i = 0; i < m_lstPane.GetCount(); i++)
316 {
317 if (m_lstPane[i]->GetName() == strName)
318 return i;
319 }
320 return -1;
321}
322
324{
325 if (iPane >= m_lstPane.GetCount())
326 return FALSE;
327 return m_lstPane[iPane];
328}
329
331{
332 RECT rcLayout;
333 GetChildrenLayoutRect(&rcLayout);
334 Relayout(rcLayout);
335}
336
338{
339 int index = m_lstPane.Find(pane);
340 if (index == -1)
341 return;
342
343 m_lstPane.RemoveAt(index);
344
345 index = m_lstPriority.Find(pane);
346 m_lstPriority.RemoveAt(index);
347
349}
350
352{
353 CRect rc = GetClientRect();
354 rc.DeflateRect(GetStyle().GetPadding());
355 *prc = rc;
356}
357
358int SSplitWnd::InsertItem(SSplitPane *pane, int index /*= -1 */)
359{
360 //禁止重复插入
361 if (m_lstPane.Find(pane) != -1)
362 {
363 SASSERT(FALSE);
364 return -1;
365 }
366
367 if (index < 0)
368 {
369 index = (int)m_lstPane.GetCount();
370 }
371
372 m_lstPane.InsertAt(index, pane);
373 m_lstPriority.Add(pane);
375
376 CRect rcContainer;
377 GetChildrenLayoutRect(&rcContainer);
378
379 if (!rcContainer.IsRectEmpty())
380 {
381 PANESIZELIST lstPaneSize;
382 FatchPaneSizeInfo(m_lstPriority, lstPaneSize);
383
384 const int index = m_lstPriority.Find(pane);
385 lstPaneSize[index].actural = lstPaneSize[index].preferred;
386
387 Relayout(rcContainer, lstPaneSize);
388 }
389 return index;
390}
391
392void SSplitWnd::Relayout(const CRect &rc, PANESIZELIST lstPaneSize /*=PANESIZELIST()*/)
393{
394 if (lstPaneSize.IsEmpty())
395 {
396 FatchPaneSizeInfo(m_lstPriority, lstPaneSize);
397 }
398 int actural = 0;
399 for (int i = 0; i < (int)lstPaneSize.GetCount(); i++)
400 actural += lstPaneSize[i].actural;
401
402 int nVisiblePanelCount = 0;
403 for (int i = 0; i < (int)m_lstPriority.GetCount(); i++)
404 {
405 if (m_lstPriority[i]->IsVisible())
406 ++nVisiblePanelCount;
407 }
408
409 int remain = ((Vertical == m_orintation) ? rc.Width() : rc.Height()) - actural - (nVisiblePanelCount - 1) * m_spliterSize;
410 AdjustPanesSize(lstPaneSize, remain);
411 int nOffset = (Vertical == m_orintation) ? rc.left : rc.top;
412 ResetPanesPostion(m_lstPane, m_lstPriority, lstPaneSize, nOffset);
413}
414
415int SSplitWnd::AdjustPanesSize(PANESIZELIST &lstPriority, int remain)
416{
417 // step 1: 将残余量按优先级从高到低顺序根据期望size在窗口间分配
418 for (int i = 0; i < (int)lstPriority.GetCount(); i++)
419 {
420 PANESIZE &pane = lstPriority[i];
421 if (remain > 0)
422 { //扩大窗口
423 if (pane.preferred < pane.actural)
424 continue;
425
426 int max_digest = pane.preferred - pane.actural;
427 if (max_digest >= remain)
428 {
429 pane.actural += remain;
430 remain = 0;
431 break;
432 }
433 else
434 {
435 pane.actural += max_digest;
436 remain -= max_digest;
437 }
438 }
439 else
440 { //缩小窗口
441 if (pane.preferred > pane.actural)
442 continue;
443
444 int max_digest = pane.actural - pane.preferred;
445 if (max_digest > -remain)
446 {
447 pane.actural += remain;
448 remain = 0;
449 break;
450 }
451 else
452 {
453 pane.actural -= max_digest;
454 remain += max_digest;
455 }
456 }
457 }
458 // step 2: 将残余量按优先级从低到高顺序在窗口的极值间分配
459 if (remain)
460 {
461 for (int i = (int)lstPriority.GetCount() - 1; i >= 0; i--)
462 {
463 PANESIZE &pane = lstPriority[i];
464 if (remain > 0)
465 { //扩大窗口
466 int max_digest = pane.maximum - pane.actural;
467 if (max_digest >= remain)
468 {
469 pane.actural += remain;
470 remain = 0;
471 break;
472 }
473 else
474 {
475 pane.actural += max_digest;
476 remain -= max_digest;
477 }
478 }
479 else
480 { //缩小窗口
481 int max_digest = pane.actural - pane.minimum;
482 if (max_digest > -remain)
483 {
484 pane.actural += remain;
485 remain = 0;
486 break;
487 }
488 else
489 {
490 pane.actural -= max_digest;
491 remain += max_digest;
492 }
493 }
494 }
495 }
496 return remain;
497}
498
499int SSplitWnd::ResetPanesPostion(SplitPaneList &lstPane, SplitPaneList &lstPanePriority, PANESIZELIST &lstPaneSize, int offset)
500{
501 CRect rc;
503 for (int i = 0; i < (int)lstPane.GetCount(); i++)
504 {
505 int idx = lstPanePriority.Find(lstPane[i]);
506 SASSERT(idx != -1);
507 if (m_orintation == Vertical)
508 {
509 rc.left = (offset);
510 rc.right = (offset + lstPaneSize[idx].actural);
511 }
512 else
513 {
514 rc.top = (offset);
515 rc.bottom = (offset + lstPaneSize[idx].actural);
516 }
517 if (lstPane[i]->IsVisible()) //窗口不可见时不修改窗口size
518 {
519 lstPane[i]->Move(rc);
520 offset += lstPaneSize[idx].actural + m_spliterSize;
521 }
522 else
523 {
524 offset += lstPaneSize[idx].actural;
525 }
526 }
527 return offset;
528}
529
530void SSplitWnd::FatchPaneSizeInfo(const SplitPaneList &lstPane, PANESIZELIST &lstPaneSize)
531{
532 lstPaneSize.SetCount(lstPane.GetCount()); //分配空间
533
534 for (int i = 0; i < (int)lstPane.GetCount(); i++)
535 {
536 if (!lstPane[i]->IsVisible())
537 {
538 lstPaneSize[i].actural = 0;
539 lstPaneSize[i].preferred = 0;
540 lstPaneSize[i].minimum = 0;
541 lstPaneSize[i].maximum = 0;
542 continue;
543 }
544
545 lstPaneSize[i].preferred = lstPane[i]->m_nSizeIdeal.toPixelSize(GetScale());
546 lstPaneSize[i].minimum = lstPane[i]->m_nSizeMin.toPixelSize(GetScale());
547 lstPaneSize[i].maximum = lstPane[i]->m_nSizeMax.toPixelSize(GetScale());
548
549 CRect rcItem;
550 lstPane[i]->GetWindowRect(&rcItem);
551 if (m_orintation == Vertical)
552 {
553 lstPaneSize[i].actural = rcItem.Width();
554 }
555 else
556 {
557 lstPaneSize[i].actural = rcItem.Height();
558 }
559 if (lstPaneSize[i].actural == 0)
560 lstPaneSize[i].actural = lstPane[i]->m_nSizeMin.toPixelSize(GetScale());
561 }
562}
563
564int SSplitWnd::FunComp(const void *p1, const void *p2)
565{
566 SSplitPane *pane1 = *(SSplitPane **)p1;
567 SSplitPane *pane2 = *(SSplitPane **)p2;
568 return pane2->m_nPriority - pane1->m_nPriority;
569}
570
571void SSplitWnd::SortPriorityList(SplitPaneList &lstPane)
572{
573 qsort(lstPane.GetData(), lstPane.GetCount(), sizeof(SSplitPane *), FunComp);
574}
575
576SNSEND
Definition of the SSplitWnd and related classes.
BOOL addEvent(DWORD dwEventID, LPCWSTR pszEventHandlerName)
添加一个新事件到事件集
布局大小类
Definition SLayoutSize.h:10
LPCWSTR GetName() SCONST OVERRIDE
Definition Sobject.hpp:108
static LPCWSTR GetClassName()
Definition Sobject.hpp:41
A pane within a split window.
Definition SSplitWnd.h:26
SLayoutSize m_nSizeIdeal
Definition SSplitWnd.h:57
SSplitPane()
Constructor for SSplitPane.
Definition SSplitWnd.cpp:8
SLayoutSize m_nSizeMin
Definition SSplitWnd.h:58
SLayoutSize m_nSizeMax
Definition SSplitWnd.h:59
void Move(CRect rc)
Moves the pane to a new position.
Definition SSplitWnd.cpp:17
int m_nPriority
Definition SSplitWnd.h:60
void Relayout(const CRect &rc, PANESIZELIST lstPaneSize=PANESIZELIST())
Relayouts the panes within the window.
static int FunComp(const void *p1, const void *p2)
Comparison function for qsort.
virtual BOOL CreateChildren(SXmlNode xmlNode)
Creates child windows from an XML node.
Definition SSplitWnd.cpp:59
int m_orintation
Definition SSplitWnd.h:101
void OnLButtonUp(UINT nFlags, CPoint pt)
Handles left mouse button up events.
SplitPaneList m_lstPane
Definition SSplitWnd.h:98
SAutoRefPtr< ISkinObj > m_pSkinSep
Definition SSplitWnd.h:104
SSplitWnd(void)
Constructor for SSplitWnd.
Definition SSplitWnd.cpp:26
void UpdateChildrenPosition() OVERRIDE
Updates the positions of child windows.
void OnLButtonDown(UINT nFlags, CPoint pt)
Handles left mouse button down events.
int InsertItem(SSplitPane *pane, int index=-1)
Inserts a new pane.
void OnMouseMove(UINT nFlags, CPoint pt)
Handles mouse move events.
void RemoveItem(SSplitPane *pane)
Removes a pane.
void GetChildrenLayoutRect(RECT *prc) SCONST OVERRIDE
Retrieves the layout rectangle for child windows.
int m_spliterSize
Definition SSplitWnd.h:100
BOOL HidePane(UINT iPane)
Hides a pane.
Definition SSplitWnd.cpp:49
int ResetPanesPostion(SplitPaneList &lstPane, SplitPaneList &lstPanePriority, PANESIZELIST &lstPaneSize, int offset)
Resets the positions of the panes based on size information.
SSplitPane * GetPane(UINT iPane)
Retrieves a pane by index.
int m_iDragSep
Definition SSplitWnd.h:107
void FatchPaneSizeInfo(const SplitPaneList &lstPane, PANESIZELIST &lstPaneSize)
Fetches size information for the panes.
CPoint m_ptDragPrev
Definition SSplitWnd.h:106
virtual BOOL OnSetCursor(const CPoint &pt)
Sets the cursor.
Definition SSplitWnd.cpp:77
int AdjustPanesSize(PANESIZELIST &lstPriority, int remain)
Adjusts the sizes of the panes.
BOOL m_bAdjustable
Definition SSplitWnd.h:103
int PaneIndex(const SStringW &strName) const
Retrieves the index of a pane by its name.
virtual ~SSplitWnd(void)
Destructor for SSplitWnd.
Definition SSplitWnd.cpp:35
void SortPriorityList(SplitPaneList &lstPane)
Sorts the pane list by priority.
SplitPaneList m_lstPriority
Definition SSplitWnd.h:99
BOOL ShowPane(UINT iPane)
Shows a pane.
Definition SSplitWnd.cpp:39
void OnPaint(IRenderTarget *pRT)
Paints the window.
Definition SSplitWnd.cpp:86
A class representing an ASCII string.
Definition sstringw.h:96
BOOL FireEvent(IEvtArgs *evt) OVERRIDE
Fires an event.
Definition Swnd.cpp:1540
int GetScale() SCONST OVERRIDE
Retrieves the scale factor of the window.
Definition Swnd.cpp:3266
BOOL IsVisible(BOOL bCheckParent=FALSE) SCONST OVERRIDE
Checks if the window is visible.
Definition Swnd.cpp:646
virtual CRect GetClientRect() const
Retrieves the client rectangle of the window.
Definition Swnd.cpp:243
void InsertChild(SWindow *pNewChild, SWindow *pInsertAfter=NULL)
Inserts a child window into the window tree.
Definition Swnd.cpp:538
SEventSet * GetEventSet()
Retrieves the event set associated with the window.
Definition SWnd.h:1290
void Invalidate() OVERRIDE
Invalidates the entire window.
Definition Swnd.cpp:1437
BOOL InitFromXml(IXmlNode *pNode) OVERRIDE
Initializes the window from an XML node.
Definition Swnd.cpp:946
void Update(BOOL bForce=FALSE) OVERRIDE
Updates the window.
Definition Swnd.cpp:1430
const SwndStyle & GetStyle() const
Retrieves the style of the window.
Definition Swnd.cpp:716
void Move(LPCRECT prect) OVERRIDE
Moves the window to a new position and size.
Definition Swnd.cpp:399
Class representing an XML node.
Definition SXml.h:352
SXmlNode next_sibling() const
Gets the next sibling node in the children list of the parent node.
Definition SXml.cpp:393
SXmlNode child(const wchar_t *name, bool bCaseSensitive=false) const
Gets the child node, attribute, or next/previous sibling with the specified name.
Definition SXml.cpp:423
Interface for rendering target objects.
Definition SRender-i.h:1440