#include "pch.h" ///////////////////////////////////////////////////////////////////////////// // // SubmenuEventSinkDelegate // ///////////////////////////////////////////////////////////////////////////// class SubmenuEventSinkDelegate : public ISubmenuEventSink { private: ISubmenuEventSink* m_psink; public: SubmenuEventSinkDelegate(ISubmenuEventSink* psink) : m_psink(psink) { } TRef GetSubMenu(IMenuItem* pitem) { return m_psink->GetSubMenu(pitem); } }; TRef ISubmenuEventSink::CreateDelegate(ISubmenuEventSink* psink) { return new SubmenuEventSinkDelegate(psink); } ///////////////////////////////////////////////////////////////////////////// // // MenuCommandSinkDelegate // ///////////////////////////////////////////////////////////////////////////// class MenuCommandSinkDelegate : public IMenuCommandSink { private: IMenuCommandSink* m_psink; public: MenuCommandSinkDelegate(IMenuCommandSink* psink) : m_psink(psink) { } void OnMenuCommand(IMenuItem* pitem) { m_psink->OnMenuCommand(pitem); } void OnMenuSelect(IMenuItem* pitem) { m_psink->OnMenuSelect(pitem); } void OnMenuClose(IMenu* pmenu) { m_psink->OnMenuClose(pmenu); } }; TRef IMenuCommandSink::CreateDelegate(IMenuCommandSink* psink) { return new MenuCommandSinkDelegate(psink); } ///////////////////////////////////////////////////////////////////////////// // // // ///////////////////////////////////////////////////////////////////////////// class IMenuItemPrivate : public IMenuItem { public: virtual TRef GetPopup(Rect& rect) = 0; virtual void Select(bool bSelect) = 0; virtual TRef GetPane() = 0; virtual char GetAccelerator() = 0; }; class IMenuPrivate : public IMenu { public: virtual void MouseEnter(IMenuItemPrivate* pitem) = 0; virtual void MouseLeave(IMenuItemPrivate* pitem) = 0; virtual void MouseClick(IMenuItemPrivate* pitem) = 0; }; ///////////////////////////////////////////////////////////////////////////// // // // ///////////////////////////////////////////////////////////////////////////// class PopupSurfaceSite : public SurfaceSite { public: void UpdateSurface(Surface* psurface) { const Color color(74.0f / 255.0f, 124.0f / 255.0f, 88.0f / 255.0f); psurface->FillSurface(Color::Black()); psurface->FillRect(WinRect(1, 1, 2, 8), color); psurface->FillRect(WinRect(2, 2, 3, 7), color); psurface->FillRect(WinRect(3, 2, 4, 7), color); psurface->FillRect(WinRect(4, 3, 5, 6), color); psurface->FillRect(WinRect(5, 3, 6, 6), color); psurface->FillRect(WinRect(6, 4, 7, 5), color); } }; ///////////////////////////////////////////////////////////////////////////// // // // ///////////////////////////////////////////////////////////////////////////// class IMenuItemImpl : public IMenuItemPrivate { private: ///////////////////////////////////////////////////////////////////////////// // // Types // ///////////////////////////////////////////////////////////////////////////// class MenuItemPane : public Pane { private: IMenuPrivate* m_pmenu; IMenuItemPrivate* m_pitem; public: MenuItemPane( IMenuPrivate* pmenu, IMenuItemPrivate* pitem, Pane* ppaneChild ) : m_pmenu(pmenu), m_pitem(pitem) { InsertAtBottom(ppaneChild); } void UpdateLayout() { DefaultUpdateLayout(); } void MouseEnter(IInputProvider* pprovider, const Point& point) { m_pmenu->MouseEnter(m_pitem); } void MouseLeave(IInputProvider* pprovider, const Point& point) { m_pmenu->MouseLeave(m_pitem); } MouseResult Button( IInputProvider* pprovider, const Point& point, int button, bool bCaptured, bool bInside, bool bDown ) { if (button == 0 && !bDown) { m_pmenu->MouseClick(m_pitem); } return MouseResult(); } }; ///////////////////////////////////////////////////////////////////////////// // // data members // ///////////////////////////////////////////////////////////////////////////// IMenuPrivate* m_pmenu; TRef m_psubmenuEventSink; int m_id; TRef m_ppane; TRef m_pstringPane; TRef m_pstringPaneAccelerator; TRef m_pborderPane; Color m_colorBack; Color m_colorText; Color m_colorSelectedBack; Color m_colorSelectedText; bool m_bSelected; bool m_bEnabled; char m_chAccelerator; public: IMenuItemImpl( IMenuPrivate* pmenu, Modeler* pmodeler, ISubmenuEventSink* psubmenuEventSink, char chAccelerator, int id, const ZString& str, IEngineFont* pfont ) : m_pmenu(pmenu), m_psubmenuEventSink(psubmenuEventSink), m_id(id), m_colorBack( 33 / 255.0f, 20 / 255.0f, 30 / 255.0f), m_colorText( 255 / 255.0f, 255 / 255.0f, 255 / 255.0f), m_colorSelectedBack(197 / 255.0f, 0 / 255.0f, 41 / 255.0f), m_colorSelectedText(255 / 255.0f, 255 / 255.0f, 255 / 255.0f), m_bSelected(false), m_bEnabled(true) { TRef ppaneLeft; TRef ppaneRight; ppaneLeft = new Pane(); ppaneLeft->SetSize(WinPoint(11,11)); TRef psurfacePopup = pmodeler->GetEngine()->CreateSurface( WinPoint(9, 9), SurfaceType2D(), new PopupSurfaceSite() ); psurfacePopup->SetColorKey(Color(0, 0, 0)); if (m_psubmenuEventSink) { ppaneRight = new SurfacePane(psurfacePopup); } else { ppaneRight = new Pane(); ppaneRight->SetSize(psurfacePopup->GetSize()); } m_pstringPane = new StringPane(str, pfont); m_pstringPaneAccelerator = new StringPane(ZString(), pfont); TRef ppaneSpace = new Pane(); ppaneSpace->SetSize(WinPoint(2, 0)); TRef pRow = new RowPane(); pRow->InsertAtBottom(ppaneLeft); pRow->InsertAtBottom(m_pstringPane); pRow->InsertAtBottom(ppaneSpace); pRow->InsertAtBottom(new JustifyPane(JustifyPane::Right, WinPoint(0, 0), m_pstringPaneAccelerator)); pRow->InsertAtBottom(ppaneRight); m_pborderPane = new BorderPane(1, m_colorBack, pRow); m_ppane = new MenuItemPane( m_pmenu, this, m_pborderPane ); UpdateColors(); SetAccelerator(chAccelerator); } void UpdateColors() { if (m_bSelected) { m_pstringPane ->SetTextColor(m_colorSelectedText); m_pstringPaneAccelerator->SetTextColor(m_colorSelectedText); m_pborderPane ->SetColor(m_colorSelectedBack); } else { m_pstringPane ->SetTextColor(m_colorText); m_pstringPaneAccelerator->SetTextColor(m_colorText); m_pborderPane ->SetColor(m_colorBack); } } ///////////////////////////////////////////////////////////////////////////// // // IMenuItemPrivate methods // ///////////////////////////////////////////////////////////////////////////// TRef GetPopup(Rect& rect) { if (m_psubmenuEventSink) { Point point = m_ppane->TransformLocalToImage(WinPoint(0, 0)); rect = Rect( point.X(), point.Y() - (float)m_ppane->YSize(), point.X() + (float)m_ppane->XSize(), point.Y() ); return m_psubmenuEventSink->GetSubMenu(this); } return NULL; } void Select(bool bSelect) { m_bSelected = bSelect; UpdateColors(); } TRef GetPane() { return m_ppane; } char GetAccelerator() { return m_chAccelerator; } ///////////////////////////////////////////////////////////////////////////// // // IMenuItem methods // ///////////////////////////////////////////////////////////////////////////// int GetID() { return m_id; } const ZString& GetString() { return m_pstringPane->GetString(); } void SetString(const ZString& str) { m_pstringPane->SetString(str); } void SetColors( const Color& colorBack, const Color& colorText, const Color& colorSelectedBack, const Color& colorSelectedText ) { m_colorBack = colorBack ; m_colorText = colorText ; m_colorSelectedBack = colorSelectedBack; m_colorSelectedText = colorSelectedText; UpdateColors(); } Color GetColor() { return m_colorBack; } void SetEnabled(bool bEnabled) { m_bEnabled = bEnabled; } bool IsEnabled() { return m_bEnabled; } void SetAccelerator(char ch) { if (ch >= 'a' && ch <= 'z') { ch += 'A' - 'a'; } m_chAccelerator = ch; char chShow = ch; if (chShow == 0) { chShow = ' '; } m_pstringPaneAccelerator->SetString(ZString(chShow, 1)); } }; ///////////////////////////////////////////////////////////////////////////// // // // ///////////////////////////////////////////////////////////////////////////// class IMenuImpl : public IMenuPrivate { private: ///////////////////////////////////////////////////////////////////////////// // // types // ///////////////////////////////////////////////////////////////////////////// typedef TList > MenuItemList; ///////////////////////////////////////////////////////////////////////////// // // data members // ///////////////////////////////////////////////////////////////////////////// TRef m_ppopup; MenuItemList m_listItems; TRef m_pitemSelection; TRef m_psink; TRef m_pmodeler; TRef m_pcolumnPane; TRef m_ppane; TRef m_pfont; public: IMenuImpl( Modeler* pmodeler, IEngineFont* pfont, IMenuCommandSink* psink ) : m_pmodeler(pmodeler), m_pfont(pfont), m_psink(psink) { m_ppane = new EdgePane( m_pcolumnPane = new ColumnPane(), true ); } ///////////////////////////////////////////////////////////////////////////// // // methods // ///////////////////////////////////////////////////////////////////////////// void NextItem() { if (m_pitemSelection == NULL) { SelectItem(m_listItems.GetFront()); } else { MenuItemList::Iterator iter(m_listItems); while (!iter.End()) { if (iter.Value() == m_pitemSelection) { iter.Next(); if (!iter.End()) { SelectItem(iter.Value()); return; } else { SelectItem(m_listItems.GetFront()); } } iter.Next(); } } } void PreviousItem() { if (m_pitemSelection == NULL) { SelectItem(m_listItems.GetEnd()); } else { MenuItemList::Iterator iter(m_listItems); while (!iter.End()) { if (iter.Value() == m_pitemSelection) { iter.Prev(); if (!iter.End()) { SelectItem(iter.Value()); return; } else { SelectItem(m_listItems.GetEnd()); } } iter.Next(); } } } bool OpenItem(IMenuItemPrivate* pitem) { if (pitem && m_ppopup == NULL) { if (m_ppopup) { m_pcontainer->ClosePopup(m_ppopup); } Rect rect; m_ppopup = pitem->GetPopup(rect); if (m_ppopup) { m_pcontainer->OpenPopup(m_ppopup, rect, true, true, this); return true; } } return false; } void SelectItem(IMenuItemPrivate* pitem) { if (pitem != m_pitemSelection) { if (m_ppopup) { m_pcontainer->ClosePopup(m_ppopup); m_ppopup = NULL; } if (m_pitemSelection) { m_pitemSelection->Select(false); } m_pitemSelection = pitem; if (m_pitemSelection) { m_pitemSelection->Select(true); } if (m_psink) { m_psink->OnMenuSelect(m_pitemSelection); } } } void ItemCommand(IMenuItemPrivate* pitem) { if (pitem && pitem->IsEnabled()) { SelectItem(pitem); if (!OpenItem(pitem)) { if (m_psink) { m_psink->OnMenuCommand(pitem); } } } } bool HandleAccelerator(char ch) { MenuItemList::Iterator iter(m_listItems); while (!iter.End()) { if (iter.Value()->GetAccelerator() == ch) { ItemCommand(iter.Value()); return true; } iter.Next(); } return false; } ///////////////////////////////////////////////////////////////////////////// // // IMenuPrivate methods // ///////////////////////////////////////////////////////////////////////////// void MouseEnter(IMenuItemPrivate* pitem) { SelectItem(pitem); OpenItem(m_pitemSelection); } void MouseLeave(IMenuItemPrivate* pitem) { } void MouseClick(IMenuItemPrivate* pitem) { ItemCommand(m_pitemSelection); } ///////////////////////////////////////////////////////////////////////////// // // IMenu methods // ///////////////////////////////////////////////////////////////////////////// TRef AddMenuItem( int id, const ZString& str, char chAccelerator = 0, ISubmenuEventSink* psubmenuEventSink = NULL ) { TRef pitem = new IMenuItemImpl( this, m_pmodeler, psubmenuEventSink, chAccelerator, id, str, m_pfont ); m_listItems.PushEnd(pitem); m_pcolumnPane->InsertAtBottom(pitem->GetPane()); if (m_pitemSelection == NULL) { m_pitemSelection = pitem; pitem->Select(true); } return pitem; } IMenuItem* FindMenuItem(int id) { MenuItemList::Iterator iter(m_listItems); while (!iter.End()) { if (iter.Value()->GetID() == id) { return iter.Value(); } iter.Next(); } // not found return NULL; } void SetMenuCommandSink(IMenuCommandSink* psink) { m_psink = psink; } ///////////////////////////////////////////////////////////////////////////// // // IPopup methods // ///////////////////////////////////////////////////////////////////////////// Pane* GetPane() { return m_ppane; } void ClosePopup(IPopup* ppopup) { ZAssert(m_ppopup == ppopup); m_pcontainer->ClosePopup(ppopup); m_ppopup = NULL; } void OnClose() { if (m_psink) { m_psink->OnMenuClose(this); } } ///////////////////////////////////////////////////////////////////////////// // // IKeyboardInput methods // ///////////////////////////////////////////////////////////////////////////// bool OnChar(IInputProvider* pprovider, const KeyState& ks) { return false; } bool OnKey(IInputProvider* pprovider, const KeyState& ks, bool& fForceTranslate) { if (ks.bDown) { switch (ks.vk) { case VK_DOWN: NextItem(); return true; case VK_UP: PreviousItem(); return true; case VK_RIGHT: OpenItem(m_pitemSelection); return true; case VK_LEFT: case VK_ESCAPE: if (m_ppopupOwner) { m_ppopupOwner->ClosePopup(this); } else { m_pcontainer->ClosePopup(this); } return true; case 13: // enter ItemCommand(m_pitemSelection); return true; default: return HandleAccelerator(ks.vk); } } return false; } }; TRef CreateMenu(Modeler* pmodeler, IEngineFont* pfont, IMenuCommandSink* psink) { return new IMenuImpl(pmodeler, pfont, psink); }