soui 5.0.0.1
Soui5 Doc
 
Loading...
Searching...
No Matches
SMenuEx.cpp
1#include "include/souistd.h"
2#include "helper/SMenuEx.h"
3#include "helper/SplitString.h"
4#include <layout/SLinearLayout.h>
5SNSBEGIN
6#define TIMERID_POPSUBMENU 100
7#define TIME_PUPSUBMENU 500
8
9#define WIDTH_MENU_INIT 10000
10#define WIDTH_MENU_MAX 2000
11#define WIDTH_MENU_MIN 100.f
12
13#define Y_MIDFLAG L"-1000px"
14#define Y_IMIDFLAG (-1000)
15
16//////////////////////////////////////////////////////////////////////////
17class SMenuExRoot : public SRootWindow {
18 DEF_SOBJECT(SWindow, L"menuRoot")
19 friend class SMenuEx;
20 friend class SMenuExItem;
21
22 protected:
23 SAutoRefPtr<ISkinObj> m_pItemSkin;
24 SAutoRefPtr<ISkinObj> m_pIconSkin;
25 SAutoRefPtr<ISkinObj> m_pCheckSkin;
26 SAutoRefPtr<ISkinObj> m_pArrowSkin;
27 SAutoRefPtr<ISkinObj> m_pSepSkin;
28
29 SMenuEx *m_pMenuEx;
30
31 SLayoutSize m_nItemHei;
32 SLayoutSize m_nIconBarWidth;
33 SLayoutSize m_nTextOffset;
34 SLayoutSize m_iconX, m_iconY;
35 SLayoutSize m_nMinWidth;
36 SLayoutSize m_nSubMenuOffset;
37
38 DWORD m_dwContextHelpId;
39
40 void Copy(SMenuExRoot *pNewMenuExRoot)
41 {
42 pNewMenuExRoot->m_pNcSkin = m_pNcSkin;
43 pNewMenuExRoot->m_pItemSkin = m_pItemSkin;
44 pNewMenuExRoot->m_pIconSkin = m_pIconSkin;
45 pNewMenuExRoot->m_pCheckSkin = m_pCheckSkin;
46 pNewMenuExRoot->m_pArrowSkin = m_pArrowSkin;
47 pNewMenuExRoot->m_pSepSkin = m_pSepSkin;
48 pNewMenuExRoot->m_nItemHei = m_nItemHei;
49 pNewMenuExRoot->m_nIconBarWidth = m_nIconBarWidth;
50 pNewMenuExRoot->m_nTextOffset = m_nTextOffset;
51 pNewMenuExRoot->m_iconX = m_iconX;
52 pNewMenuExRoot->m_iconY = m_iconY;
53 pNewMenuExRoot->m_nMinWidth = m_nMinWidth;
54 pNewMenuExRoot->m_nSubMenuOffset = m_nSubMenuOffset;
55 pNewMenuExRoot->m_style = m_style; // 设置了 些 margin 之类的 属性 也要 copy
56 }
57
58 HRESULT OnAttrIconPos(const SStringW &strValue, BOOL bLoading);
59
60 SOUI_ATTRS_BEGIN()
61 ATTR_SKIN(L"itemSkin", m_pItemSkin, FALSE)
62 ATTR_SKIN(L"checkSkin", m_pCheckSkin, FALSE)
63 ATTR_SKIN(L"sepSkin", m_pSepSkin, FALSE)
64 ATTR_SKIN(L"arrowSkin", m_pArrowSkin, FALSE)
65 ATTR_LAYOUTSIZE(L"itemHeight", m_nItemHei, FALSE)
66 ATTR_CUSTOM(L"iconPos", OnAttrIconPos)
67 ATTR_SKIN(L"iconSkin", m_pIconSkin, FALSE)
68 ATTR_LAYOUTSIZE(L"iconBarWidth", m_nIconBarWidth, FALSE)
69 ATTR_LAYOUTSIZE(L"textOffset", m_nTextOffset, FALSE)
70 ATTR_LAYOUTSIZE(L"minWidth", m_nMinWidth, FALSE)
71 ATTR_LAYOUTSIZE(L"subMenuOffset", m_nSubMenuOffset, FALSE)
72 ATTR_DWORD(L"contextHelpId", m_dwContextHelpId, FALSE)
73 SOUI_ATTRS_END()
74
75 public:
76 SMenuExRoot(SMenuEx *pMenuEx)
77 : m_pItemSkin(GETBUILTINSKIN(SKIN_SYS_MENU_SKIN))
78 , m_pSepSkin(GETBUILTINSKIN(SKIN_SYS_MENU_SEP))
79 , m_pCheckSkin(GETBUILTINSKIN(SKIN_SYS_MENU_CHECK))
80 , m_pArrowSkin(GETBUILTINSKIN(SKIN_SYS_MENU_ARROW))
81 , m_pIconSkin(NULL)
82 , m_pMenuEx(pMenuEx)
83 , m_dwContextHelpId(0)
84 , SRootWindow(pMenuEx)
85 {
86 m_nItemHei.setSize(26.f, SLayoutSize::dp);
87 m_nIconBarWidth.setSize(24.f, SLayoutSize::dp);
88 m_nMinWidth.setSize(WIDTH_MENU_MIN, SLayoutSize::dp);
89 OnAttrLayout(SVBox::GetClassName(), TRUE); // set layout to vbox
90 GetLayoutParam()->SetWrapContent(Both);
91 }
92
93 SMenuExItem *GetNextMenuItem(SMenuExItem *pItem, BOOL bForword, int nCount = 0);
94
95 CSize CalcMenuSize()
96 {
97 HMONITOR hMonitor = MonitorFromWindow(m_pMenuEx->m_hWnd, MONITOR_DEFAULTTOPRIMARY);
98 MONITORINFO monitorInfo = { sizeof(MONITORINFO), 0 };
99 GetMonitorInfo(hMonitor, &monitorInfo);
100 int maxHei = monitorInfo.rcMonitor.bottom - monitorInfo.rcMonitor.top;
101 CSize szRet;
102 GetDesiredSize(&szRet, -1, maxHei);
103 return szRet;
104 }
105
106 STDMETHOD_(void, GetDesiredSize)(THIS_ SIZE *psz, int wid, int hei) OVERRIDE
107 {
108 __baseCls::GetDesiredSize(psz, wid, hei);
109 if (psz->cx > m_nMaxWidth.toPixelSize(GetScale()) && !m_nMaxWidth.isWrapContent())
110 psz->cx = m_nMaxWidth.toPixelSize(GetScale());
111 if (psz->cx < m_nMinWidth.toPixelSize(GetScale()))
112 psz->cx = m_nMinWidth.toPixelSize(GetScale());
113 }
114
115 STDMETHOD_(BOOL, InitFromXml)(THIS_ IXmlNode *pNode) OVERRIDE
116 {
117 SXmlNode xmlNode(pNode);
118 // 找到根节点,获取在根节点上配置的全局菜单对象属性
119 SXmlNode xmlRoot = xmlNode.root().first_child();
120 if (xmlNode != xmlRoot)
121 {
122 __baseCls::__baseCls::InitFromXml(&xmlRoot); // IObject::InitFromXml
123 }
124 BOOL bRet = __baseCls::InitFromXml(&xmlNode);
125 SetWindowText(_T("")); // 防止子菜单显示父级菜单项的文本。
126 return TRUE;
127 }
128
129 BOOL CreateChildren(SXmlNode xmlNode) OVERRIDE
130 {
131 SXmlNode xmlItem = xmlNode.first_child();
132 while (xmlItem)
133 {
134 SWindow *pMenuItem = CreateMenuItem(xmlItem.name());
135 if (pMenuItem)
136 {
137 InsertChild(pMenuItem);
138 pMenuItem->InitFromXml(&xmlItem);
139 pMenuItem->GetLayoutParam()->SetMatchParent(Horz);
140 }
141 xmlItem = xmlItem.next_sibling();
142 }
143 return TRUE;
144 }
145
146 STDMETHOD_(void, UpdateChildrenPosition)(THIS) OVERRIDE
147 {
148 GetLayout()->LayoutChildren(this);
149 }
150
151 virtual void OnScaleChanged(int nScale)
152 {
153 __baseCls::OnScaleChanged(nScale);
154 GetScaleSkin(m_pItemSkin, nScale);
155 GetScaleSkin(m_pIconSkin, nScale);
156 GetScaleSkin(m_pCheckSkin, nScale);
157 GetScaleSkin(m_pArrowSkin, nScale);
158 GetScaleSkin(m_pSepSkin, nScale);
159 }
160
161 SWindow *CreateMenuItem(const SStringW &strItemName);
162};
163
164HRESULT SMenuExRoot::OnAttrIconPos(const SStringW &strValue, BOOL bLoading)
165{
166 SStringWList values;
167 SplitString(strValue, L',', values);
168 if (1 == values.GetCount())
169 {
170 //只设置X时,让Y方向自动居中
171 m_iconX = GETLAYOUTSIZE(values[0]);
172 m_iconY.parseString(Y_MIDFLAG);
173 return S_OK;
174 }
175 else if (2 != values.GetCount())
176 return E_INVALIDARG;
177 m_iconX = GETLAYOUTSIZE(values[0]);
178 m_iconY = GETLAYOUTSIZE(values[1]);
179 return S_OK;
180}
181
182SMenuExItem *SMenuExRoot::GetNextMenuItem(SMenuExItem *pItem, BOOL bForword, int nCount)
183{
184 if ((UINT)nCount == GetChildrenCount())
185 return NULL;
186
187 SMenuExItem *pRet = NULL;
188 if (pItem)
189 {
190 SASSERT(pItem->GetParent() == this);
191 pRet = (SMenuExItem *)pItem->GetWindow(bForword ? GSW_NEXTSIBLING : GSW_PREVSIBLING);
192 }
193 if (!pRet)
194 {
195 pRet = (SMenuExItem *)GetWindow(bForword ? GSW_FIRSTCHILD : GSW_LASTCHILD);
196 }
197
198 if (!pRet->IsDisabled(TRUE))
199 return pRet;
200 else
201 return GetNextMenuItem(pRet, bForword, nCount + 1);
202}
203
204//////////////////////////////////////////////////////////////////////////
205// SMenuExItem
206
208{
209 if (m_pSubMenu)
210 {
211 delete m_pSubMenu;
212 }
213}
214
215SMenuExItem::SMenuExItem(SMenuEx *pOwnerMenu, ISkinObj *pItemSkin)
216 : m_pSubMenu(NULL)
217 , m_pOwnerMenu(pOwnerMenu)
218 , m_iIcon(-1)
219 , m_bCheck(FALSE)
220 , m_bRadio(FALSE)
221 , m_cHotKey(0)
222{
223 m_bDisplay = FALSE;
224 m_pBgSkin = pItemSkin;
225 m_style.m_bTrackMouseEvent = TRUE;
226 m_style.SetAlign(DT_LEFT);
227}
228
230{
231 __baseCls::OnPaint(pRT);
232
233 CRect rc = GetClientRect();
234 SMenuExRoot *pMenuRoot = sobj_cast<SMenuExRoot>(GetRoot());
235 SASSERT(pMenuRoot);
236 rc.right = rc.left + pMenuRoot->m_nIconBarWidth.toPixelSize(GetScale());
237 rc.left += pMenuRoot->m_iconX.toPixelSize(GetScale());
238 int icoY = pMenuRoot->m_iconY.toPixelSize(GetScale());
239
240 if (m_bCheck || m_bRadio)
241 {
242 if (pMenuRoot->m_pCheckSkin)
243 {
244 int nState = 0;
245 if (m_bRadio)
246 {
247 nState = m_bCheck ? 1 : 2;
248 }
249 if (icoY == Y_IMIDFLAG)
250 {
251 icoY = (rc.Height() - pMenuRoot->m_pCheckSkin->GetSkinSize().cy) / 2;
252 }
253 rc.top += icoY;
254 CRect rcIcon(rc.TopLeft(), pMenuRoot->m_pCheckSkin->GetSkinSize());
255 pMenuRoot->m_pCheckSkin->DrawByIndex(pRT, rcIcon, nState);
256 }
257 }
258 else if (pMenuRoot->m_pIconSkin)
259 {
260 if (icoY == Y_IMIDFLAG)
261 {
262 icoY = (rc.Height() - pMenuRoot->m_pIconSkin->GetSkinSize().cy) / 2;
263 }
264 rc.top += icoY;
265 CRect rcIcon(rc.TopLeft(), pMenuRoot->m_pIconSkin->GetSkinSize());
266 pMenuRoot->m_pIconSkin->DrawByIndex(pRT, rcIcon, m_iIcon);
267 }
268
269 if (m_pSubMenu && pMenuRoot->m_pArrowSkin)
270 {
271 CRect rcArrow = GetClientRect();
272 CSize szArrow = pMenuRoot->m_pArrowSkin->GetSkinSize();
273 rcArrow.left = rcArrow.right - szArrow.cx;
274 rcArrow.DeflateRect(0, (rcArrow.Height() - szArrow.cy) / 2);
275
276 pMenuRoot->m_pArrowSkin->DrawByIndex(pRT, rcArrow, (GetState() & WndState_Hover) ? 1 : 0);
277 }
278}
279
281{
282 if (!m_pBgSkin)
283 return FALSE;
284 int nState = 0;
285
287 {
288 nState = 2;
289 }
291 {
292 nState = 1;
293 }
294 if (nState >= m_pBgSkin->GetStates())
295 nState = 0;
296 m_pBgSkin->DrawByIndex(pRT, GetClientRect(), nState);
297
298 return TRUE;
299}
300
301void SMenuExItem::GetTextRect(LPRECT pRect)
302{
303 GetClientRect(pRect);
304 SMenuExRoot *pMenuRoot = sobj_cast<SMenuExRoot>(GetRoot());
305 SASSERT(pMenuRoot);
306 int nScale = GetScale();
307 pRect->left += pMenuRoot->m_nIconBarWidth.toPixelSize(nScale) + pMenuRoot->m_nTextOffset.toPixelSize(nScale);
308 if (m_pSubMenu)
309 pRect->right -= pMenuRoot->m_pArrowSkin->GetSkinSize().cx;
310}
311
312void SMenuExItem::GetDesiredSize(SIZE *psz, int wid, int hei)
313{
314 CSize szRet;
315 __baseCls::GetDesiredSize(&szRet, wid, hei);
316 SMenuExRoot *pMenuRoot = sobj_cast<SMenuExRoot>(GetRoot());
317 SASSERT(pMenuRoot);
318 if (GetChildrenCount() == 0)
319 {
320 if (!GetLayoutParam()->IsSpecifiedSize(Horz))
321 {
322 szRet.cx += pMenuRoot->m_nIconBarWidth.toPixelSize(GetScale()) + pMenuRoot->m_nTextOffset.toPixelSize(GetScale());
323 if (m_pSubMenu)
324 szRet.cx += pMenuRoot->m_pArrowSkin->GetSkinSize().cx; //加上子菜单箭头宽度
325 }
326 }
327 if (!GetLayoutParam()->IsSpecifiedSize(Vert))
328 {
329 szRet.cy = smax(szRet.cy, pMenuRoot->m_nItemHei.toPixelSize(GetScale()));
330 }
331 *psz = szRet;
332}
333
335{
336 __baseCls::CreateChildren(xmlNode);
337 SXmlNode xmlChild = xmlNode.child(SMenuExItem::GetClassName());
338 if (xmlChild)
339 { //有子菜单
340 m_pSubMenu = new SMenuEx(this);
341 m_pSubMenu->LoadMenu2(&xmlNode);
342 }
343 return TRUE;
344}
345
347{
348 if (pszName == NULL)
349 return NULL;
350 if (_wcsicmp(pszName, SMenuExItem::GetClassName()) == 0)
351 return NULL;
352 return __baseCls::CreateChildByName(pszName);
353}
354
355void SMenuExItem::OnSubMenuHided(BOOL bUncheckItem)
356{
357 m_pOwnerMenu->OnSubMenuHided(bUncheckItem);
358}
359
361{
362 return m_cHotKey;
363}
364
365void SMenuExItem::ShowSubMenu(BOOL bCheckFirstItem)
366{
367 if (!m_pSubMenu)
368 return;
369 m_pOwnerMenu->PopupSubMenu(this, bCheckFirstItem);
370}
371
373{
374 if (!m_pSubMenu)
375 return;
376 m_pSubMenu->HideMenu(FALSE);
377}
378
380{
381 return m_pOwnerMenu;
382}
383
385{
386 return m_pSubMenu;
387}
388
389//////////////////////////////////////////////////////////////////////////
390
391class SMenuExSep : public SMenuExItem {
392 DEF_SOBJECT(SMenuExItem, L"sep")
393 public:
394 SMenuExSep(SMenuEx *pOwnerMenu, ISkinObj *pItemSkin)
395 : SMenuExItem(pOwnerMenu, pItemSkin)
396 {
398 m_bDisable = TRUE;
399 }
400
401 STDMETHOD_(void, GetDesiredSize)(THIS_ SIZE *psz, int wid, int hei) OVERRIDE
402 {
403 SMenuExRoot *pMenuRoot = sobj_cast<SMenuExRoot>(GetRoot());
404 SASSERT(pMenuRoot);
405 CSize szRet;
406 szRet.cx = 0;
407 if (!GetLayoutParam()->IsSpecifiedSize(Vert))
408 {
409 if (m_pBgSkin)
410 {
411 szRet.cy = m_pBgSkin->GetSkinSize().cy;
412 if (szRet.cy == 0) //纯色皮肤没有size
413 szRet.cy = 1;
414 }
415 else
416 szRet.cy = 0;
417 }
418 else
419 {
420 szRet.cy = GetLayoutParam()->GetSpecifiedSize(Vert).toPixelSize(GetScale());
421 }
422 szRet.cy += m_style.GetMargin().top + m_style.GetMargin().bottom;
423 *psz = szRet;
424 }
425
426 protected:
427 BOOL OnEraseBkgnd(IRenderTarget *pRT)
428 {
429 if (!m_pBgSkin)
430 return FALSE;
431 m_pBgSkin->DrawByIndex(pRT, GetClientRect(), 0);
432 return TRUE;
433 }
434 void OnPaint(IRenderTarget *pRT)
435 {
436 (void)pRT;
437 }
438 SOUI_MSG_MAP_BEGIN()
439 MSG_WM_PAINT_EX(OnPaint)
440 MSG_WM_ERASEBKGND_EX(OnEraseBkgnd)
441 SOUI_MSG_MAP_END()
442};
443
444//////////////////////////////////////////////////////////////////////////
445SWindow *SMenuExRoot::CreateMenuItem(const SStringW &strItemName)
446{
447 SWindow *pMenuItem = NULL;
448 if (strItemName == SMenuExItem::GetClassName())
449 {
450 pMenuItem = new SMenuExItem(m_pMenuEx, m_pItemSkin);
451 }
452 else if (strItemName == SMenuExSep::GetClassName())
453 {
454 pMenuItem = new SMenuExSep(m_pMenuEx, m_pSepSkin);
455 }
456 //从style里初始化MenuItem
457 if (pMenuItem)
458 SApplication::getSingleton().SetSwndDefAttr(pMenuItem);
459
460 return pMenuItem;
461}
462//////////////////////////////////////////////////////////////////////////
463class SMenuExRunData : public TObjRefImpl<IObjRef> {
464 friend class SMenuEx;
465
466 public:
467 SMenuExRunData(HWND hOwner, int nScale)
468 : m_hOwner(hOwner)
469 , m_bExit(FALSE)
470 , m_nCmdID(-1)
471 , m_nScale(nScale)
472 {
473 }
474
475 BOOL IsMenuWnd(HWND hWnd)
476 {
477 SPOSITION pos = m_lstMenuEx.GetTailPosition();
478 while (pos)
479 {
480 if (m_lstMenuEx.GetPrev(pos)->m_hWnd == hWnd)
481 return TRUE;
482 }
483 return FALSE;
484 }
485
486 void PushMenuEx(SMenuEx *pMenu)
487 {
488 m_lstMenuEx.AddTail(pMenu);
489 }
490
491 SMenuEx *GetMenuEx()
492 {
493 if (m_lstMenuEx.IsEmpty())
494 return 0;
495 return m_lstMenuEx.GetTail();
496 }
497
498 SMenuEx *PopMenuEx()
499 {
500 SASSERT(!m_lstMenuEx.IsEmpty());
501 SMenuEx *pMenuEx = m_lstMenuEx.RemoveTail();
502 return pMenuEx;
503 }
504
505 SMenuEx *SMenuExFromHwnd(HWND hWnd)
506 {
507 SPOSITION pos = m_lstMenuEx.GetTailPosition();
508 while (pos)
509 {
510 SMenuEx *pMenuEx = m_lstMenuEx.GetPrev(pos);
511 if (pMenuEx->m_hWnd == hWnd)
512 return pMenuEx;
513 }
514 return NULL;
515 }
516
517 BOOL IsMenuExited()
518 {
519 return m_bExit;
520 }
521
522 void ExitMenu(int nCmdID)
523 {
524 // hide all menu window
525 SPOSITION pos = m_lstMenuEx.GetTailPosition();
526 while (pos)
527 {
528 SMenuEx *pMenuEx = m_lstMenuEx.GetPrev(pos);
529 pMenuEx->ShowWindow(SW_HIDE);
530 }
531
532 m_bExit = TRUE;
533 m_nCmdID = nCmdID;
534 }
535
536 int GetCmdID()
537 {
538 return m_nCmdID;
539 }
540
541 HWND GetOwner()
542 {
543 return m_hOwner;
544 }
545
546 int GetScale() const
547 {
548 return m_nScale;
549 }
550
551 protected:
552 SList<SMenuEx *> m_lstMenuEx;
553
554 BOOL m_bExit;
555 int m_nCmdID;
556 HWND m_hOwner;
557 int m_nScale;
558};
559
560static SMenuExRunData *s_MenuData = NULL;
561
562//////////////////////////////////////////////////////////////////////////
564 : m_pParent(NULL)
565 , m_pHoverItem(NULL)
566 , m_pCheckItem(NULL)
567 , m_bMenuInitialized(FALSE)
568{
569 m_hostAttr.SetTranslucent(true);
570}
571
572SMenuEx::SMenuEx(SMenuExItem *pParent)
573 : m_pParent(pParent)
574 , m_pHoverItem(NULL)
575 , m_pCheckItem(NULL)
576 , m_bMenuInitialized(FALSE)
577{
578}
579
581{
582 DestroyMenu();
583}
584
586{
587 return new SMenuExRoot(this);
588}
589
590BOOL SMenuEx::LoadMenu(LPCTSTR strMenu)
591{
592 SXmlDoc xmlMenu;
593 BOOL bLoad = LOADXML(xmlMenu, strMenu);
594 if (!bLoad)
595 return FALSE;
596 SXmlNode xmlNode = xmlMenu.root().first_child();
597 return LoadMenu2(&xmlNode);
598}
599
600BOOL SMenuEx::LoadMenuU8(THIS_ LPCSTR resId)
601{
602 SStringT strResId = S_CA2T(resId, CP_UTF8);
603 return LoadMenu(strResId);
604}
605
607{
608 return TRUE;
609}
610
612{
613 if (IsWindow())
614 return FALSE;
615 SXmlNode xmlNode(xmlMenu);
616 if (xmlNode.name() != SStringW(SMenuExRoot::GetClassName()) && xmlNode.name() != SStringW(SMenuExItem::GetClassName()))
617 return FALSE;
618 SXmlDoc souiXml;
619 SXmlNode root = souiXml.root().append_child(L"SOUI");
620 root.append_attribute(L"translucent").set_value(1);
621 if (m_pParent == NULL)
622 {
623 root.append_attribute(L"trCtx").set_value(xmlNode.attribute(L"trCtx").value());
624 }
625
626 HWND hWnd = CreateEx(NULL, WS_POPUP, WS_EX_TOOLWINDOW | WS_EX_TOPMOST | WS_EX_NOACTIVATE, 0, 0, 0, 0, &root);
627 if (!hWnd)
628 return FALSE;
629
630 GetRoot()->InitFromXml(&xmlNode);
631 m_hostAttr.SetSendWheel2Hover(true);
632 return TRUE;
633}
634
635SMenuExItem *SMenuEx::GetMenuItem(int nID, BOOL byCmdId)
636{
637 if (byCmdId)
638 {
639 return FindChildByID2<SMenuExItem>(nID);
640 }
641 else
642 {
643 SMenuExRoot *pMenuRoot = sobj_cast<SMenuExRoot>(GetRoot());
644 SWindow *pItem = pMenuRoot->GetWindow(GSW_FIRSTCHILD);
645 for (int i = 0; i < nID && pItem; i++)
646 {
647 pItem = pItem->GetWindow(GSW_NEXTSIBLING);
648 }
649 return sobj_cast<SMenuExItem>(pItem);
650 }
651}
652
653SMenuEx *SMenuEx::GetSubMenu(int nID, BOOL byCmdId)
654{
655 SMenuExItem *pItem = GetMenuItem(nID, byCmdId);
656 if (!pItem)
657 return NULL;
658 return pItem->GetSubMenu();
659}
660
661IMenuEx *SMenuEx::GetSubMenu(THIS_ int nPos)
662{
663 return GetSubMenu(nPos, FALSE);
664}
665
666UINT SMenuEx::TrackPopupMenu(UINT flag, int x, int y, HWND hOwner, int nScale)
667{
668 if (!IsWindow())
669 return (UINT)-1;
670 if (!s_MenuData)
671 s_MenuData = new SMenuExRunData(hOwner, nScale);
672 else
673 s_MenuData->AddRef();
674
675 HWND hActive = hOwner;
676 if (!hOwner || !::IsWindowEnabled(hOwner))
677 hActive = ::GetActiveWindow();
678
679 HWND hRoot = hActive;
680 while ((::GetWindowLong(hRoot, GWL_STYLE) & WS_CHILD) && ::GetParent(hRoot))
681 {
682 hRoot = ::GetParent(hRoot);
683 }
684 SetForegroundWindow(hRoot);
685
686 ShowMenu(flag, x, y);
687 RunMenu(hRoot);
688 HideMenu(FALSE);
689
690 if (hActive)
691 {
692 CPoint pt;
693 GetCursorPos(&pt);
694 ::ScreenToClient(hActive, &pt);
695 ::PostMessage(hActive, WM_MOUSEMOVE, 0, MAKELPARAM(pt.x, pt.y));
696 }
697
698 int nRet = s_MenuData->GetCmdID();
699 if (0 == s_MenuData->Release())
700 {
701 s_MenuData = NULL;
702 }
703 if (flag & TPM_RETURNCMD)
704 {
705 return nRet;
706 }
707 else
708 {
709 ::SendMessage(hOwner, WM_COMMAND, MAKEWPARAM(nRet, 0), 0);
710 return TRUE;
711 }
712}
713
714void SMenuEx::ShowMenu(UINT uFlag, int x, int y)
715{
716 SMenuExRoot *pMenuRoot = sobj_cast<SMenuExRoot>(GetRoot());
717 SASSERT(pMenuRoot);
718
720 pMenuRoot->SDispatchMessage(UM_SETSCALE, GetScale(), 0);
721
722 CSize szMenu = pMenuRoot->CalcMenuSize();
723
724 pMenuRoot->Move(CRect(CPoint(), szMenu));
725 if (uFlag & TPM_CENTERALIGN)
726 {
727 x -= szMenu.cx / 2;
728 }
729 else if (uFlag & TPM_RIGHTALIGN)
730 {
731 x -= szMenu.cx;
732 }
733
734 if (uFlag & TPM_VCENTERALIGN)
735 {
736 y -= szMenu.cy / 2;
737 }
738 else if (uFlag & TPM_BOTTOMALIGN)
739 {
740 y -= szMenu.cy;
741 }
742
743 HMONITOR hMor = MonitorFromWindow(m_hWnd, MONITOR_DEFAULTTOPRIMARY);
744 MONITORINFO mi = { sizeof(MONITORINFO), 0 };
745 GetMonitorInfo(hMor, &mi);
746 CRect rcMenu(CPoint(x, y), szMenu);
747 CRect rcInter;
748 rcInter.IntersectRect(&rcMenu, &mi.rcMonitor);
749 int subMenuOffset = m_pParent ? pMenuRoot->m_nSubMenuOffset.toPixelSize(GetScale()) : 0;
750 if (rcInter != rcMenu)
751 {
752 if (m_pParent)
753 {
754 SMenuEx *pParent = m_pParent->GetOwnerMenu();
755 CRect rcParent = pParent->GetWindowRect();
756 if (rcMenu.right > mi.rcMonitor.right)
757 {
758 rcMenu.MoveToX(x - szMenu.cx - rcParent.Width() - subMenuOffset);
759 }
760 else
761 {
762 rcMenu.MoveToX(x + subMenuOffset);
763 }
764
765 int xOffset = 0, yOffset = 0;
766 if (rcMenu.left < mi.rcMonitor.left)
767 xOffset = mi.rcMonitor.left - rcMenu.left;
768 else if (rcMenu.right > mi.rcMonitor.right)
769 xOffset = mi.rcMonitor.right - rcMenu.right;
770 if (rcMenu.top < mi.rcMonitor.top)
771 yOffset = mi.rcMonitor.top - rcMenu.top;
772 else if (rcMenu.bottom > mi.rcMonitor.bottom)
773 yOffset = mi.rcMonitor.bottom - rcMenu.bottom;
774
775 rcMenu.OffsetRect(xOffset, yOffset);
776 }
777 else
778 {
779
780 if (rcMenu.right > mi.rcMonitor.right)
781 {
782 rcMenu.MoveToX(x - szMenu.cx - subMenuOffset);
783 }
784 else
785 {
786 rcMenu.MoveToX(x + subMenuOffset);
787 }
788
789 if (rcMenu.top < mi.rcMonitor.top)
790 {
791 rcMenu.MoveToY(y + szMenu.cy);
792 }
793 if (rcMenu.bottom > mi.rcMonitor.bottom)
794 {
795 rcMenu.MoveToY(y - szMenu.cy);
796 }
797 }
798 }
799 else
800 {
801
802 rcMenu.MoveToX(x + subMenuOffset);
803 }
804
805 SetWindowPos(HWND_TOPMOST, rcMenu.left, rcMenu.top, szMenu.cx, szMenu.cy, SWP_SHOWWINDOW | SWP_NOACTIVATE);
806 s_MenuData->PushMenuEx(this);
807}
808
809void SMenuEx::HideMenu(BOOL bUncheckParentItem)
810{
812 return;
813 HideSubMenu();
814 ShowWindow(SW_HIDE);
815 if (m_pCheckItem)
816 {
817 m_pCheckItem->SetCheck(FALSE);
818 m_pCheckItem = NULL;
819 }
820 s_MenuData->PopMenuEx();
821 if (m_pParent)
822 {
823 m_pParent->OnSubMenuHided(bUncheckParentItem);
824 }
825}
826
828{
829 if (m_pCheckItem)
830 m_pCheckItem->HideSubMenu();
831}
832
833int SMenuEx::OnMouseActivate(HWND wndTopLevel, UINT nHitTest, UINT message)
834{
835 return MA_NOACTIVATE;
836}
837
838void SMenuEx::RunMenu(HWND hRoot)
839{
840 SASSERT(s_MenuData);
841
842 BOOL bMsgQuit(FALSE);
843 HWND hCurMenu(NULL);
844
847 for (;;)
848 {
849
850 if (s_MenuData->IsMenuExited())
851 {
852 break;
853 }
854
855 if (GetForegroundWindow() != hRoot)
856 {
857 break;
858 }
859 MSG msg = { 0 };
860
861 for (;;)
862 { //获取菜单相关消息,抄自wine代码
863 if (msgLoop->PeekMsg(&msg, 0, 0, FALSE))
864 {
865 if (!CallMsgFilter(&msg, MSGF_MENU))
866 break;
867 msgLoop->PeekMsg(&msg, msg.message, msg.message, TRUE);
868 }
869 else
870 {
871 msgLoop->WaitMsg();
872 }
873 }
874
875 if (msg.message == WM_KEYDOWN || msg.message == WM_KEYUP || msg.message == WM_SYSKEYDOWN || msg.message == WM_SYSKEYUP)
876 { //拦截alt键
877 if (msg.wParam == VK_MENU)
878 { // handle alt key down, exit menu loop
879 s_MenuData->ExitMenu(0);
880 break;
881 }
882 }
883 else if (msg.message == WM_LBUTTONDOWN || msg.message == WM_RBUTTONDOWN || msg.message == WM_NCLBUTTONDOWN || msg.message == WM_NCRBUTTONDOWN || msg.message == WM_LBUTTONDBLCLK)
884 {
885 // click on other window
886 if (!s_MenuData->IsMenuWnd(msg.hwnd))
887 {
888 s_MenuData->ExitMenu(0);
889 break;
890 }
891 else
892 {
893 SMenuEx *pMenu = s_MenuData->SMenuExFromHwnd(msg.hwnd);
894 pMenu->HideSubMenu();
895 }
896 }
897 else if (msg.message == WM_QUIT)
898 {
899 bMsgQuit = TRUE;
900 }
901
902 //移除消息队列中当前的消息。
903 msgLoop->PeekMsg(&msg, msg.message, msg.message, TRUE);
904
905 //拦截非菜单窗口的MouseMove消息
906 if (msg.message == WM_MOUSEMOVE)
907 {
908 if (msg.hwnd != hCurMenu)
909 {
910 if (hCurMenu)
911 {
912 ::SendMessage(hCurMenu, WM_MOUSELEAVE, 0, 0);
913 }
914 hCurMenu = msg.hwnd;
915 }
916
917 SMenuEx *pMenu = s_MenuData->SMenuExFromHwnd(msg.hwnd);
918 if (!pMenu)
919 {
920 hCurMenu = NULL;
921 }
922 }
923
924 msgLoop->OnMsg(&msg);
925
926 if (msg.message == WM_KEYDOWN || msg.message == WM_KEYUP || msg.message == WM_CHAR)
927 { //将键盘事件强制发送到最后一级菜单窗口,让菜单处理快速键
928 HWND menuWnd = s_MenuData->GetMenuEx()->m_hWnd;
929 ::SendMessage(menuWnd, msg.message, msg.wParam, msg.lParam);
930 }
931
932 if (bMsgQuit)
933 {
934 PostQuitMessage((int)msg.wParam);
935 break;
936 }
937 }
938}
939
940class SMenuExEventOwner {
941 public:
942 SMenuExEventOwner(SMenuEx *pMenuEx)
943 {
944 s_pMenuEx = pMenuEx;
945 }
946 ~SMenuExEventOwner()
947 {
948 s_pMenuEx = NULL;
949 }
950
951 static SMenuEx *GetEvtOwner()
952 {
953 return s_pMenuEx;
954 }
955
956 private:
957 static SMenuEx *s_pMenuEx;
958};
959
960SMenuEx *SMenuExEventOwner::s_pMenuEx = NULL;
961
963{
964 return SMenuExEventOwner::GetEvtOwner();
965}
966
967BOOL SMenuEx::_HandleEvent(IEvtArgs *pEvt)
968{
969 if (pEvt->Sender()->IsClass(SMenuExItem::GetClassName()))
970 {
971 SMenuExItem *pMenuItem = sobj_cast<SMenuExItem>(pEvt->Sender());
972 if (pEvt->GetID() == EventSwndMouseHover::EventID)
973 {
974 if (pMenuItem->GetSubMenu() != NULL)
975 {
976 SNativeWnd::SetTimer(TIMERID_POPSUBMENU, TIME_PUPSUBMENU);
977 m_pHoverItem = pMenuItem;
978 }
979 HideSubMenu();
980 return FALSE;
981 }
982 else if (pEvt->GetID() == EventSwndMouseLeave::EventID)
983 {
984 if (pMenuItem->GetSubMenu() != NULL)
985 {
986 SNativeWnd::KillTimer(TIMERID_POPSUBMENU);
987 m_pHoverItem = NULL;
988 }
989 return FALSE;
990 }
991
992 if (pEvt->GetID() != EventCmd::EventID)
993 return FALSE;
994 SASSERT(pMenuItem);
995 if (pMenuItem->GetSubMenu())
996 {
997 PopupSubMenu(pMenuItem, FALSE);
998 return FALSE;
999 }
1000 else if (pMenuItem->GetID() == 0)
1001 {
1002 return FALSE;
1003 }
1004 s_MenuData->ExitMenu(pMenuItem->GetID());
1005 return TRUE;
1006 }
1007 else if (s_MenuData && ::IsWindow(s_MenuData->GetOwner()))
1008 {
1009 SMenuExEventOwner evtOwner(this);
1010 return (BOOL)::SendMessage(s_MenuData->GetOwner(), UM_MENUEVENT, (WPARAM)this, (LPARAM)pEvt);
1011 }
1012 else
1013 {
1014 return FALSE;
1015 }
1016}
1017
1018void SMenuEx::OnTimer(UINT_PTR timeID)
1019{
1020 if (timeID == TIMERID_POPSUBMENU)
1021 {
1022 PopupSubMenu(m_pHoverItem, FALSE);
1023 }
1024 else
1025 {
1026 SetMsgHandled(FALSE);
1027 }
1028}
1029
1030void SMenuEx::OnSubMenuHided(BOOL bUncheckItem)
1031{
1032 SASSERT(m_pCheckItem);
1033 if (!bUncheckItem)
1034 {
1035 m_pCheckItem->SetCheck(FALSE);
1036 m_pCheckItem = NULL;
1037 }
1038}
1039
1040void SMenuEx::PopupSubMenu(SMenuExItem *pItem, BOOL bCheckFirstItem)
1041{
1042 SNativeWnd::KillTimer(TIMERID_POPSUBMENU);
1043
1044 SMenuEx *pSubMenu = pItem->GetSubMenu();
1045 SASSERT(pSubMenu);
1046 if (!pSubMenu->m_bMenuInitialized)
1047 {
1048 int idx = 0;
1049 SWindow *pPrev = pItem->GetWindow(GSW_PREVSIBLING);
1050 while (pPrev)
1051 {
1052 idx++;
1053 pPrev = pPrev->GetWindow(GSW_PREVSIBLING);
1054 }
1055 pSubMenu->SendInitPopupMenu2Owner(idx);
1056 }
1057
1058 CRect rcWnd = GetRoot()->GetWindowRect();
1059 CRect rcItem = pItem->GetWindowRect();
1060 rcItem.left = rcWnd.left, rcItem.right = rcWnd.right;
1061 ClientToScreen2(&rcItem);
1062
1063 m_pCheckItem = pItem;
1064 m_pCheckItem->SetCheck(TRUE);
1065 pSubMenu->SetWindowLongPtr(GWLP_HWNDPARENT, (ULONG_PTR)m_hWnd);
1066 pSubMenu->ShowMenu(0, rcItem.right, rcItem.top);
1067 if (bCheckFirstItem)
1068 {
1069 SMenuExRoot *pMenuRoot = sobj_cast<SMenuExRoot>(pSubMenu->GetRoot());
1070 SASSERT(pMenuRoot);
1071 SMenuExItem *pFirstItem = pMenuRoot->GetNextMenuItem(NULL, TRUE);
1072 if (pFirstItem)
1073 {
1074 pSubMenu->m_pCheckItem = pFirstItem;
1075 pFirstItem->SetCheck(TRUE);
1076 }
1077 }
1078}
1079
1080void SMenuEx::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags)
1081{
1082 SMenuExRoot *pMenuRoot = sobj_cast<SMenuExRoot>(GetRoot());
1083 SASSERT(pMenuRoot);
1084 switch (nChar)
1085 {
1086 case VK_UP:
1087 case VK_DOWN:
1088 if (m_pCheckItem)
1089 m_pCheckItem->SetCheck(FALSE);
1090 m_pCheckItem = pMenuRoot->GetNextMenuItem(m_pCheckItem, nChar == VK_DOWN);
1091 if (m_pCheckItem)
1092 {
1093 m_pCheckItem->SetCheck(TRUE);
1094 m_pCheckItem->Invalidate();
1095 }
1096 break;
1097 case VK_ESCAPE:
1098 case VK_LEFT:
1099 if (m_pParent)
1100 {
1101 HideMenu(TRUE);
1102 }
1103 else
1104 {
1105 s_MenuData->ExitMenu(0);
1106 }
1107 break;
1108 case VK_RIGHT:
1109 if (m_pCheckItem)
1110 {
1111 m_pCheckItem->ShowSubMenu(TRUE);
1112 }
1113 break;
1114 case VK_RETURN:
1115 if (m_pCheckItem)
1116 m_pCheckItem->FireCommand();
1117 break;
1118 break;
1119 default:
1120 if (isprint(nChar))
1121 {
1122 nChar = tolower(nChar);
1123 SMenuExItem *pMenuItem = (SMenuExItem *)pMenuRoot->GetWindow(GSW_FIRSTCHILD);
1124 while (pMenuItem)
1125 {
1126 if ((UINT)tolower(pMenuItem->GetHotKey()) == nChar)
1127 {
1128 pMenuItem->FireCommand();
1129 return;
1130 }
1131 pMenuItem = (SMenuExItem *)pMenuItem->GetWindow(GSW_NEXTSIBLING);
1132 }
1133 }
1134 else
1135 {
1136 SetMsgHandled(FALSE);
1137 }
1138 break;
1139 }
1140}
1141
1143{
1144 if (m_pParent != NULL)
1145 {
1146 return m_pParent->GetTrCtx();
1147 }
1148 else
1149 {
1151 }
1152}
1153
1155{
1156 if (!s_MenuData)
1157 return 100;
1158 return s_MenuData->GetScale();
1159}
1160
1161void SMenuEx::EndMenu(int nCmdId /*=0*/)
1162{
1163 if (!s_MenuData)
1164 return;
1165 s_MenuData->ExitMenu(nCmdId);
1166 ::PostMessage(s_MenuData->GetOwner(), WM_NULL, 0, 0);
1167}
1168
1169EXTERN_C void EndMenuEx(int nCmdId)
1170{
1171 SMenuEx::EndMenu(nCmdId);
1172}
1173
1174SWindow *SMenuEx::FindItem(UINT uPos, UINT uFlag)
1175{
1176 SMenuExRoot *pMenuRoot = sobj_cast<SMenuExRoot>(GetRoot());
1177 SASSERT(pMenuRoot);
1178 SWindow *pItemRef = NULL;
1179
1180 if (uFlag & MF_BYPOSITION)
1181 {
1182 if (uPos != -1)
1183 {
1184 UINT i = 0;
1185 SWindow *p = pMenuRoot->GetWindow(GSW_FIRSTCHILD);
1186 while (i < uPos && p)
1187 {
1188 i++;
1189 p = p->GetWindow(GSW_NEXTSIBLING);
1190 }
1191 pItemRef = p;
1192 }
1193 }
1194 else // MF_BYCOMMAND
1195 {
1196 pItemRef = pMenuRoot->FindChildByID2<SMenuExItem>(uPos);
1197 }
1198 return pItemRef;
1199}
1200
1201BOOL SMenuEx::InsertMenu(UINT uPos, UINT uFlag, int nId, LPCTSTR lpNewItem, int iIcon)
1202{
1203 SMenuExRoot *pMenuRoot = sobj_cast<SMenuExRoot>(GetRoot());
1204 SASSERT(pMenuRoot);
1205 SWindow *pItemRef = FindItem(uPos, uFlag);
1206
1207 if (uFlag & MF_BYCOMMAND && !pItemRef)
1208 return FALSE;
1209
1210 SMenuExItem *pMenuItem = (SMenuExItem *)pMenuRoot->CreateMenuItem((uFlag & MF_SEPARATOR) ? SMenuExSep::GetClassName() : SMenuExItem::GetClassName());
1211
1212 if (pItemRef)
1213 {
1214 SWindow *pRefPrev = pItemRef->GetWindow(GSW_PREVSIBLING);
1215 if (pRefPrev)
1216 {
1217 pRefPrev->GetParent()->InsertChild(pMenuItem, pRefPrev);
1218 }
1219 else
1220 {
1221 pItemRef->GetParent()->InsertChild(pMenuItem, ICWND_FIRST);
1222 }
1223 }
1224 else
1225 {
1226 pMenuRoot->InsertChild(pMenuItem);
1227 }
1228 if (!(uFlag & MF_SEPARATOR))
1229 {
1230 pMenuItem->SetWindowText(lpNewItem);
1231 if (uFlag & MF_POPUP)
1232 {
1233 pMenuItem->m_pSubMenu = new SMenuEx(pMenuItem);
1234 pMenuItem->m_pSubMenu->IniNullMenu(pMenuRoot);
1235 }
1236
1237 pMenuItem->SetAttribute(L"ID", SStringW().Format(L"%d", nId));
1238 pMenuItem->SetAttribute(L"icon", SStringW().Format(L"%d", iIcon));
1239 if (uFlag & MF_CHECKED)
1240 {
1241 pMenuItem->SetAttribute(L"check", L"1");
1242 }
1243 }
1244
1245 return TRUE;
1246}
1247
1248BOOL SMenuEx::AppendMenu(THIS_ UINT uFlags, int uIDNewItem, LPCTSTR lpNewItem, int iIcon)
1249{
1250 return InsertMenu(-1, uFlags, uIDNewItem, lpNewItem, iIcon);
1251}
1252
1253BOOL SMenuEx::IniNullMenu(SMenuExRoot *ParentRoot)
1254{
1255 HWND hWnd = CreateEx(NULL, WS_POPUP, WS_EX_TOOLWINDOW | WS_EX_TOPMOST, 0, 0, 0, 0);
1256 SXmlDoc souiXml;
1257 SXmlNode root = souiXml.root().append_child(L"SOUI");
1258 root.append_attribute(L"translucent").set_value(1);
1259 InitFromXml(&root);
1260 if (!hWnd)
1261 return FALSE;
1262 SMenuExRoot *pMenuRoot = new SMenuExRoot(this);
1263 if (ParentRoot)
1264 {
1265 //拷贝属性
1266 ParentRoot->Copy(pMenuRoot);
1267 }
1268 GetRoot()->InsertChild(pMenuRoot);
1269 pMenuRoot->SSendMessage(WM_CREATE);
1270 pMenuRoot->GetLayoutParam()->SetWrapContent(Both);
1271 return TRUE;
1272}
1273
1274BOOL SMenuEx::DeleteMenu(UINT uPos, UINT uFlag)
1275{
1276 SMenuExRoot *pMenuRoot = sobj_cast<SMenuExRoot>(GetRoot());
1277 SASSERT(pMenuRoot);
1278 SWindow *pItemRef = FindItem(uPos, uFlag);
1279 if (!pItemRef)
1280 return FALSE;
1281 pMenuRoot->DestroyChild(pItemRef);
1282 return TRUE;
1283}
1284
1285BOOL SMenuEx::CheckMenuItem(UINT uPos, UINT uFlag)
1286{
1287 SMenuExRoot *pMenuRoot = sobj_cast<SMenuExRoot>(GetRoot());
1288 SASSERT(pMenuRoot);
1289 SWindow *pItemRef = FindItem(uPos, uFlag);
1290 if (!pItemRef)
1291 return FALSE;
1292
1293 if (uFlag & MF_CHECKED)
1294 {
1295 pItemRef->SetAttribute(L"check", L"1");
1296 }
1297 else
1298 {
1299 pItemRef->SetAttribute(L"check", L"0");
1300 }
1301 return TRUE;
1302}
1303
1304BOOL SMenuEx::CheckMenuRadioItem(UINT idFirst, UINT idLast, UINT idCheck, UINT uFlags)
1305{
1306 SMenuExRoot *pMenuRoot = sobj_cast<SMenuExRoot>(GetRoot());
1307 SASSERT(pMenuRoot);
1308 SWindow *pItemRefFirst = FindItem(idFirst, uFlags);
1309 SWindow *pItemRefLast = FindItem(idLast, uFlags);
1310 SWindow *pItemRefCheck = FindItem(idCheck, uFlags);
1311
1312 if (!pItemRefFirst || !pItemRefLast || !pItemRefCheck)
1313 return FALSE;
1314
1315 int idxFirst = -1;
1316 int idxLast = -1;
1317 int idxCheck = -1;
1318
1319 SWindow *pChild = pMenuRoot->GetWindow(GSW_FIRSTCHILD);
1320 int i = 0;
1321 while (pChild)
1322 {
1323 if (pChild == pItemRefFirst)
1324 idxFirst = i;
1325 else if (pChild == pItemRefCheck)
1326 idxCheck = i;
1327 else if (pChild == pItemRefLast)
1328 idxLast = i;
1329 pChild = pChild->GetWindow(GSW_NEXTSIBLING);
1330 i++;
1331 }
1332 if (idxFirst == -1 || idxLast == -1 || idxCheck == -1)
1333 return FALSE;
1334 if (idxFirst < idxLast)
1335 {
1336 SWindow *t = pItemRefFirst;
1337 pItemRefFirst = pItemRefLast;
1338 pItemRefLast = t;
1339 int tIdx = idxFirst;
1340 idxFirst = idxLast;
1341 idxLast = tIdx;
1342 }
1343
1344 if (idxFirst > idxCheck || idxLast < idxCheck)
1345 return FALSE;
1346
1347 pChild = pItemRefFirst;
1348 for (;;)
1349 {
1350 pChild->SetAttribute(L"radio", L"1");
1351 if (pChild == pItemRefCheck)
1352 {
1353 pChild->SetAttribute(L"check", L"1");
1354 }
1355 else
1356 {
1357 pChild->SetAttribute(L"check", L"0");
1358 }
1359 if (pChild == pItemRefLast)
1360 break;
1361 else
1362 pChild = pChild->GetWindow(GSW_NEXTSIBLING);
1363 }
1364 return TRUE;
1365}
1366
1368{
1369 if (m_bMenuInitialized)
1370 return;
1371
1372 if (::IsWindow(s_MenuData->GetOwner()))
1373 {
1374 ::SendMessage(s_MenuData->GetOwner(), WM_INITMENUPOPUP, (WPARAM)this, (LPARAM)idx);
1375 }
1376 m_bMenuInitialized = TRUE;
1377}
1378
1380{
1381 SMenuExRoot *pMenuRoot = sobj_cast<SMenuExRoot>(GetRoot());
1382 SASSERT(pMenuRoot);
1383 return pMenuRoot->m_dwContextHelpId;
1384}
1385
1387{
1388 SMenuExRoot *pMenuRoot = sobj_cast<SMenuExRoot>(GetRoot());
1389 SASSERT(pMenuRoot);
1390 pMenuRoot->m_dwContextHelpId = dwId;
1391}
1392
1394{
1395 if (IsWindow())
1396 DestroyWindow();
1397}
1398
1399BOOL SMenuEx::ModifyMenuString(THIS_ UINT uPosition, UINT uFlags, LPCTSTR lpItemString)
1400{
1401 SWindow *pItemRef = FindItem(uPosition, uFlags);
1402 if (!pItemRef)
1403 return FALSE;
1404 pItemRef->SetWindowText(lpItemString);
1405 return TRUE;
1406}
1407
1408BOOL SMenuEx::SetMenuUserData(THIS_ UINT uPosition, UINT uFlags, ULONG_PTR ulUserData)
1409{
1410 SWindow *pItemRef = FindItem(uPosition, uFlags);
1411 if (!pItemRef)
1412 return FALSE;
1413 pItemRef->SetUserData(ulUserData);
1414 return TRUE;
1415}
1416
1417ULONG_PTR SMenuEx::GetMenuUserData(THIS_ UINT uPosition, UINT uFlags)
1418{
1419 SWindow *pItemRef = FindItem(uPosition, uFlags);
1420 if (!pItemRef)
1421 return 0;
1422 return pItemRef->GetUserData();
1423}
1424
1425BOOL SMenuEx::GetMenuString(THIS_ UINT uPosition, UINT uFlags, IStringT *lpItemString)
1426{
1427 SWindow *pItemRef = FindItem(uPosition, uFlags);
1428 if (!pItemRef)
1429 return FALSE;
1430 SStringT strText = pItemRef->GetWindowText();
1431 lpItemString->Copy(&strText);
1432 return TRUE;
1433}
1434
1435SNSEND
@ GSW_FIRSTCHILD
Definition SWnd.h:195
@ GSW_LASTCHILD
Definition SWnd.h:196
@ GSW_PREVSIBLING
Definition SWnd.h:197
@ GSW_NEXTSIBLING
Definition SWnd.h:198
@ WndState_Hover
Definition SWnd.h:76
@ WndState_Check
Definition SWnd.h:78
@ WndState_Disable
Definition SWnd.h:80
@ WndState_PushDown
Definition SWnd.h:77
IMsgLoopFactory * GetMsgLoopFactory() OVERRIDE
Get the message loop factory.
Definition SApp.cpp:598
Smart pointer class for managing COM-style reference-counted objects.
BOOL ShowWindow(int nCmdShow) OVERRIDE
Shows or hides the host window.
BOOL InitFromXml(IXmlNode *pNode) OVERRIDE
Initializes the host window from an XML node.
Definition shostwnd.cpp:440
CRect GetWindowRect() const
Gets the window rectangle.
BOOL DestroyWindow() OVERRIDE
Destroys the host window.
SWindow * GetRoot() const
Gets the root window.
Definition SHostWnd.h:685
SHostWndAttr m_hostAttr
Definition SHostWnd.h:325
friend class SRootWindow
Definition SHostWnd.h:320
LPCWSTR GetTranslatorContext() const OVERRIDE
Gets the translator context for the container.
T * FindChildByID2(int nID, int nDeep=-1)
Finds a child window by its ID with template support.
Definition SHostWnd.h:662
IMessageLoop * GetMsgLoop() OVERRIDE
Gets the message loop interface.
HWND CreateEx(HWND hWndParent, DWORD dwStyle, DWORD dwExStyle, int x, int y, int nWidth, int nHeight, IXmlNode *xmlInit=NULL) OVERRIDE
Creates the host window with extended styles.
Definition shostwnd.cpp:361
int toPixelSize(int scale) const
将大小转换为像素值
扩展菜单类
Definition SMenuEx.h:138
void ShowMenu(UINT uFlag, int x, int y)
显示菜单
Definition SMenuEx.cpp:714
BOOL GetMenuString(UINT uPosition, UINT uFlags, IStringT *lpItemString) OVERRIDE
获取菜单项字符串
Definition SMenuEx.cpp:1425
BOOL ModifyMenuString(UINT uPosition, UINT uFlags, LPCTSTR lpItemString) OVERRIDE
修改菜单项字符串
Definition SMenuEx.cpp:1399
void PopupSubMenu(SMenuExItem *pItem, BOOL bCheckFirstItem)
弹出子菜单
Definition SMenuEx.cpp:1040
virtual BOOL _HandleEvent(IEvtArgs *pEvt)
处理事件
Definition SMenuEx.cpp:967
void DestroyMenu() OVERRIDE
销毁菜单
Definition SMenuEx.cpp:1393
static SMenuEx * GetEvtOwner()
获取事件所有者
Definition SMenuEx.cpp:962
SRootWindow * CreateRoot() override
创建根窗口
Definition SMenuEx.cpp:585
void OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags)
处理按键消息
Definition SMenuEx.cpp:1080
UINT TrackPopupMenu(UINT uFlags, int x, int y, HWND hWnd, int nScale=100) OVERRIDE
跟踪弹出菜单
Definition SMenuEx.cpp:666
static void EndMenu(int nCmdId=0)
结束菜单
Definition SMenuEx.cpp:1161
BOOL DeleteMenu(UINT uPosition, UINT uFlags) OVERRIDE
删除菜单项
Definition SMenuEx.cpp:1274
SWindow * FindItem(UINT uPos, UINT uFlag)
查找菜单项
Definition SMenuEx.cpp:1174
void OnSubMenuHided(BOOL bUncheckItem)
处理子菜单隐藏事件
Definition SMenuEx.cpp:1030
ULONG_PTR GetMenuUserData(UINT uPosition, UINT uFlags) OVERRIDE
获取菜单项用户数据
Definition SMenuEx.cpp:1417
BOOL CheckMenuRadioItem(UINT idFirst, UINT idLast, UINT idCheck, UINT uFlags) OVERRIDE
检查菜单项(单选按钮)
Definition SMenuEx.cpp:1304
DWORD GetContextHelpId() SCONST OVERRIDE
获取上下文帮助ID
Definition SMenuEx.cpp:1379
int GetScale() SCONST OVERRIDE
获取缩放比例
Definition SMenuEx.cpp:1154
SMenuEx(void)
构造函数
Definition SMenuEx.cpp:563
void SetContextHelpId(DWORD dwId) OVERRIDE
设置上下文帮助ID
Definition SMenuEx.cpp:1386
BOOL InsertMenu(UINT uPosition, UINT uFlags, int nIDNewItem, LPCTSTR strText, int iIcon=-1) OVERRIDE
插入菜单项
Definition SMenuEx.cpp:1201
void RunMenu(HWND hOwner)
运行菜单
Definition SMenuEx.cpp:838
BOOL AppendMenu(UINT uFlags, int uIDNewItem, LPCTSTR lpNewItem, int iIcon=-1) OVERRIDE
追加菜单项
Definition SMenuEx.cpp:1248
BOOL OnLoadLayoutFromResourceID(SXmlDoc &xmlDoc) override
从资源ID加载布局
Definition SMenuEx.cpp:606
void SendInitPopupMenu2Owner(int idx)
发送初始化弹出菜单事件给所有者
Definition SMenuEx.cpp:1367
BOOL CheckMenuItem(UINT uIdCheckItem, UINT uCheck) OVERRIDE
检查菜单项
Definition SMenuEx.cpp:1285
BOOL LoadMenuU8(LPCSTR resId) OVERRIDE
加载菜单资源(UTF-8)
Definition SMenuEx.cpp:600
BOOL IniNullMenu(SMenuExRoot *ParentRoot)
初始化一个空菜单(不应在外部调用)
Definition SMenuEx.cpp:1253
SMenuExItem * GetMenuItem(int nID, BOOL byCmdId)
获取菜单项
Definition SMenuEx.cpp:635
BOOL LoadMenu(LPCTSTR resId) OVERRIDE
加载菜单资源
Definition SMenuEx.cpp:590
BOOL LoadMenu2(IXmlNode *xmlMenu) OVERRIDE
加载菜单资源(XML)
Definition SMenuEx.cpp:611
IMenuEx * GetSubMenu(int nPos) OVERRIDE
获取子菜单
Definition SMenuEx.cpp:661
void HideMenu(BOOL bUncheckParentItem)
隐藏菜单
Definition SMenuEx.cpp:809
virtual ~SMenuEx(void)
析构函数
Definition SMenuEx.cpp:580
void HideSubMenu()
隐藏子菜单
Definition SMenuEx.cpp:827
BOOL SetMenuUserData(UINT uPosition, UINT uFlags, ULONG_PTR ulUserData) OVERRIDE
设置菜单项用户数据
Definition SMenuEx.cpp:1408
LPCWSTR GetTranslatorContext() SCONST OVERRIDE
获取翻译上下文
Definition SMenuEx.cpp:1142
void OnTimer(UINT_PTR timeID)
处理定时器消息
Definition SMenuEx.cpp:1018
int OnMouseActivate(HWND wndTopLevel, UINT nHitTest, UINT message)
处理鼠标激活消息
Definition SMenuEx.cpp:833
扩展菜单项类
Definition SMenuEx.h:16
SMenuEx * GetSubMenu()
获取子菜单
Definition SMenuEx.cpp:384
void GetDesiredSize(SIZE *psz, int wid, int hei) OVERRIDE
获取期望的大小
Definition SMenuEx.cpp:312
void OnPaint(IRenderTarget *pRT)
处理绘制消息
Definition SMenuEx.cpp:229
SMenuExItem(SMenuEx *pOwnerMenu, ISkinObj *pItemSkin)
构造函数
Definition SMenuEx.cpp:215
~SMenuExItem()
析构函数
Definition SMenuEx.cpp:207
BOOL CreateChildren(SXmlNode xmlNode) OVERRIDE
创建子窗口
Definition SMenuEx.cpp:334
void OnSubMenuHided(BOOL bUncheckItem)
处理子菜单隐藏事件
Definition SMenuEx.cpp:355
SWindow * CreateChildByName(LPCWSTR pszName) OVERRIDE
根据名称创建子窗口
Definition SMenuEx.cpp:346
void HideSubMenu()
隐藏子菜单
Definition SMenuEx.cpp:372
void ShowSubMenu(BOOL bCheckFirstItem)
显示子菜单
Definition SMenuEx.cpp:365
void GetTextRect(LPRECT pRect) OVERRIDE
获取文本矩形
Definition SMenuEx.cpp:301
BOOL OnEraseBkgnd(IRenderTarget *pRT)
处理擦除背景消息
Definition SMenuEx.cpp:280
WCHAR GetHotKey() const
获取热键字符
Definition SMenuEx.cpp:360
SMenuEx * GetOwnerMenu()
获取所属菜单
Definition SMenuEx.cpp:379
BOOL IsWindowVisible() SCONST OVERRIDE
Checks if the window is visible.
UINT_PTR SetTimer(UINT_PTR nIDEvent, UINT nElapse, void(CALLBACK *lpfnTimer)(HWND, UINT, UINT_PTR, DWORD)=NULL) OVERRIDE
Sets a timer for the window.
BOOL KillTimer(UINT_PTR nIDEvent) OVERRIDE
Kills a timer for the window.
HWND m_hWnd
Handle to the window.
Definition SNativeWnd.h:744
int GetID() SCONST OVERRIDE
Retrieves the object's ID.
Definition Sobject.hpp:134
static LPCWSTR GetClassName()
Definition Sobject.hpp:41
Root window class derived from SWindow.
Definition SHostWnd.h:187
SRootWindow(SHostWnd *pHostWnd)
Constructor for SRootWindow.
Definition shostwnd.cpp:160
static SApplication & getSingleton(void)
Definition SSingleton.h:63
static SApplication * getSingletonPtr(void)
Definition SSingleton.h:73
A class representing an ASCII string.
Definition sstringw.h:96
Base class for SOUI DUI windows.
Definition SWnd.h:286
SAutoRefPtr< ISkinObj > m_pNcSkin
Definition SWnd.h:2623
BOOL DestroyChild(SWindow *pChild)
Destroys a child window.
Definition Swnd.cpp:519
SWindow * GetParent() const
Retrieves the parent window.
Definition Swnd.cpp:3488
BOOL m_bDisplay
Definition SWnd.h:2606
BOOL m_bDisable
Definition SWnd.h:2605
DWORD GetState() SCONST OVERRIDE
Retrieves the current state of the window.
Definition Swnd.cpp:437
ULONG_PTR GetUserData() SCONST OVERRIDE
Retrieves the user data associated with the window.
Definition Swnd.cpp:465
SwndStyle m_style
Definition SWnd.h:2596
int GetWindowText(TCHAR *pBuf, int nBufLen, BOOL bRawText) OVERRIDE
Retrieves the window text.
Definition Swnd.cpp:263
UINT GetChildrenCount() SCONST OVERRIDE
Retrieves the number of child windows.
Definition Swnd.cpp:533
void SDispatchMessage(UINT uMsg, WPARAM wParam=0, LPARAM lParam=0) OVERRIDE
Dispatches a message to the window.
Definition Swnd.cpp:388
int GetScale() SCONST OVERRIDE
Retrieves the scale factor of the window.
Definition Swnd.cpp:3266
T * FindChildByID2(int nID, int nDeep=-1)
Finds a child window by its ID and casts it to a specific type.
Definition SWnd.h:1360
HRESULT OnAttrLayout(const SStringW &strValue, BOOL bLoading)
Handles the 'layout' attribute.
Definition Swnd.cpp:3177
BOOL m_dwState
Definition SWnd.h:2603
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
SWindow * GetRoot() const
Retrieves the root window in the hierarchy.
Definition Swnd.cpp:3493
LRESULT SSendMessage(UINT uMsg, WPARAM wParam=0, LPARAM lParam=0, BOOL *pbMsgHandled=NULL) OVERRIDE
Sends a message to the window.
Definition Swnd.cpp:364
void SetCheck(BOOL bCheck) OVERRIDE
Sets the check state of the window.
Definition Swnd.cpp:671
SWindow()
Constructor.
Definition Swnd.cpp:104
ILayoutParam * GetLayoutParam() SCONST OVERRIDE
Retrieves the layout parameter object associated with the window.
Definition SWnd.h:405
SWindow * GetWindow(int uCode) const
Retrieves a window based on a given code.
Definition Swnd.cpp:3456
BOOL IsDisabled(BOOL bCheckParent=FALSE) SCONST OVERRIDE
Checks if the window is disabled.
Definition Swnd.cpp:638
SLayoutSize m_nMaxWidth
Definition SWnd.h:2626
SAutoRefPtr< ISkinObj > m_pBgSkin
Definition SWnd.h:2622
void SetWindowText(LPCTSTR lpszText) OVERRIDE
Sets the window text.
Definition Swnd.cpp:311
void GetWindowRect(LPRECT prect) SCONST OVERRIDE
Retrieves the bounding rectangle of the window.
ILayout * GetLayout() OVERRIDE
Retrieves the layout object associated with the window.
Definition SWnd.h:396
ULONG_PTR SetUserData(ULONG_PTR uData) OVERRIDE
Sets the user data for the window.
Definition Swnd.cpp:470
void GetScaleSkin(SAutoRefPtr< ISkinObj > &pSkin, int nScale)
Retrieves a scaled skin object based on the current scale factor.
Definition Swnd.cpp:3290
BOOL InitFromXml(IXmlNode *pNode) OVERRIDE
Initializes the window from an XML node.
Definition Swnd.cpp:946
BOOL FireCommand() OVERRIDE
Fires a command event.
Definition Swnd.cpp:2713
void Move(LPCRECT prect) OVERRIDE
Moves the window to a new position and size.
Definition Swnd.cpp:399
bool set_value(const wchar_t *rhs)
Sets the attribute value.
Definition SXml.cpp:130
const wchar_t * value() const
Gets the attribute value.
Definition SXml.cpp:90
Implementation of IXmlDoc.
Definition SXml.h:912
SXmlNode root() const
Retrieves the root node of the document.
Definition SXml.cpp:754
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 first_child() const
Gets the first child node of the node.
Definition SXml.cpp:383
const wchar_t * name() const
Gets the name of the node.
Definition SXml.cpp:363
SXmlAttr attribute(const wchar_t *name, bool bCaseSensitive=false) const
Gets the attribute with the specified name.
Definition SXml.cpp:428
SXmlAttr append_attribute(const wchar_t *name)
Adds an attribute with the specified name.
Definition SXml.cpp:458
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
SXmlNode append_child(XmlNodeType type=node_element)
Adds a child node with the specified type.
Definition SXml.cpp:518
HRESULT CreateMsgLoop(IMessageLoop **ppMsgLoop, IMessageLoop *pParentLoop=NULL) PURE
Creates a message loop.
Interface for rendering target objects.
Definition SRender-i.h:1440
Interface for Skin Objects.
Definition SSkinobj-i.h:29
void DrawByIndex(IRenderTarget *pRT, LPCRECT rcDraw, int iState) SCONST PURE
Draws the skin object to the specified render target with a given index.
SIZE GetSkinSize() SCONST PURE
Retrieves the default size of the skin object.
Interface for XML nodes.
Definition sxml-i.h:128