#include "pch.h"
class SubmenuEventSinkDelegate : public ISubmenuEventSink {
private:
ISubmenuEventSink* m_psink;
public:
SubmenuEventSinkDelegate(ISubmenuEventSink* psink) :
m_psink(psink)
{
}
TRef<IPopup> GetSubMenu(IMenuItem* pitem)
{
return m_psink->GetSubMenu(pitem);
}
};
TRef<ISubmenuEventSink> ISubmenuEventSink::CreateDelegate(ISubmenuEventSink* psink)
{
return new SubmenuEventSinkDelegate(psink);
}
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> IMenuCommandSink::CreateDelegate(IMenuCommandSink* psink)
{
return new MenuCommandSinkDelegate(psink);
}
class IMenuItemPrivate : public IMenuItem {
public:
virtual TRef<IPopup> GetPopup(Rect& rect) = 0;
virtual void Select(bool bSelect) = 0;
virtual TRef<Pane> 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:
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();
}
};
IMenuPrivate* m_pmenu;
TRef<ISubmenuEventSink> m_psubmenuEventSink;
int m_id;
TRef<MenuItemPane> m_ppane;
TRef<StringPane> m_pstringPane;
TRef<StringPane> m_pstringPaneAccelerator;
TRef<BorderPane> 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<Pane> ppaneLeft;
TRef<Pane> ppaneRight;
ppaneLeft = new Pane();
ppaneLeft->SetSize(WinPoint(11,11));
TRef<Surface> 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<Pane> ppaneSpace = new Pane();
ppaneSpace->SetSize(WinPoint(2, 0));
TRef<RowPane> 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);
}
}
TRef<IPopup> 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<Pane> GetPane()
{
return m_ppane;
}
char GetAccelerator()
{
return m_chAccelerator;
}
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:
typedef TList<TRef<IMenuItemPrivate> > MenuItemList;
TRef<IPopup> m_ppopup;
MenuItemList m_listItems;
TRef<IMenuItemPrivate> m_pitemSelection;
TRef<IMenuCommandSink> m_psink;
TRef<Modeler> m_pmodeler;
TRef<ColumnPane> m_pcolumnPane;
TRef<Pane> m_ppane;
TRef<IEngineFont> 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
);
}
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;
}
void MouseEnter(IMenuItemPrivate* pitem)
{
SelectItem(pitem);
OpenItem(m_pitemSelection);
}
void MouseLeave(IMenuItemPrivate* pitem)
{
}
void MouseClick(IMenuItemPrivate* pitem)
{
ItemCommand(m_pitemSelection);
}
TRef<IMenuItem> AddMenuItem(
int id,
const ZString& str,
char chAccelerator = 0,
ISubmenuEventSink* psubmenuEventSink = NULL
) {
TRef<IMenuItemPrivate> 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();
}
return NULL;
}
void SetMenuCommandSink(IMenuCommandSink* psink)
{
m_psink = psink;
}
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);
}
}
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: ItemCommand(m_pitemSelection);
return true;
default:
return HandleAccelerator(ks.vk);
}
}
return false;
}
};
TRef<IMenu> CreateMenu(Modeler* pmodeler, IEngineFont* pfont, IMenuCommandSink* psink)
{
return new IMenuImpl(pmodeler, pfont, psink);
}