wg_menu.cpp

00001 // wg_menu.cpp
00002 //
00003 // CMenu implementation
00004 //
00005 //
00006 // Copyright (c) 2002-2004 Rob Wiskow
00007 // rob-dev@boxedchaos.com
00008 //
00009 // This library is free software; you can redistribute it and/or
00010 // modify it under the terms of the GNU Lesser General Public
00011 // License as published by the Free Software Foundation; either
00012 // version 2.1 of the License, or (at your option) any later version.
00013 //
00014 // This library is distributed in the hope that it will be useful,
00015 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00016 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
00017 // Lesser General Public License for more details.
00018 //
00019 // You should have received a copy of the GNU Lesser General Public
00020 // License along with this library; if not, write to the Free Software
00021 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
00022 //
00023 
00024 
00025 #include "wgui_include_config.h"
00026 #include "wg_menu.h"
00027 #include "std_ex.h"
00028 #include "wg_application.h"
00029 #include "wg_message_server.h"
00030 #include "wg_view.h"
00031 #include "wutil_debug.h"
00032 #include "wg_error.h"
00033 
00034 
00035 namespace wGui
00036 {
00037 
00038 // CMenuBase
00039 
00040 CMenuBase::CMenuBase(const CRect& WindowRect, CWindow* pParent, CFontEngine* pFontEngine) :
00041      CWindow(WindowRect, pParent),
00042      m_pHighlightedItem(0),
00043      m_bCachedRectsValid(false),
00044      m_pActivePopup(0),
00045      m_hRightArrowBitmap(WGRES_RIGHT_ARROW_BITMAP),
00046      m_HighlightColor(DEFAULT_BACKGROUND_COLOR),
00047      m_pPopupTimer(0)
00048 {
00049      if (pFontEngine)
00050      {
00051           m_pFontEngine = pFontEngine;
00052      }
00053      else
00054      {
00055           m_pFontEngine = CApplication::Instance()->GetDefaultFontEngine();
00056      }
00057 
00058      m_HighlightColor = CApplication::Instance()->GetDefaultSelectionColor();
00059 
00060      CMessageServer::Instance().RegisterMessageClient(this, CMessage::MOUSE_MOVE);
00061      CMessageServer::Instance().RegisterMessageClient(this, CMessage::CTRL_SINGLELCLICK);
00062      CMessageServer::Instance().RegisterMessageClient(this, CMessage::CTRL_TIMER);
00063 
00064      m_pPopupTimer = new CTimer(this);
00065 }
00066 
00067 
00068 CMenuBase::~CMenuBase(void)
00069 {
00070      delete m_pPopupTimer;
00071      m_pPopupTimer = 0;
00072 }
00073 
00074 
00075 void CMenuBase::InsertMenuItem(const SMenuItem& MenuItem, int iPosition)
00076 {
00077      m_MenuItems.insert((iPosition == -1) ? m_MenuItems.end() : m_MenuItems.begin() + iPosition,
00078           s_MenuItemInfo(MenuItem, CRenderedString(m_pFontEngine, MenuItem.sItemText, CRenderedString::VALIGN_TOP), CRect()));
00079      m_bCachedRectsValid = false;
00080 //   Draw();
00081 }
00082 
00083 
00084 void CMenuBase::RemoveMenuItem(int iPosition)
00085 {
00086      m_MenuItems.erase(m_MenuItems.begin() + iPosition);
00087      m_bCachedRectsValid = false;
00088      Draw();
00089 }
00090 
00091 
00092 void CMenuBase::HideActivePopup(void)
00093 {
00094      if (m_pActivePopup)
00095      {
00096           m_pActivePopup->Hide();
00097           m_pActivePopup = 0;
00098      }
00099 }
00100 
00101 
00102 bool CMenuBase::OnMouseButtonDown(CPoint Point, unsigned int Button)
00103 {
00104      // We can't do quite the same thing as normal since children of menus don't appear inside their bounds
00105      bool bResult = false;
00106 
00107      if (m_bVisible)
00108      {
00109           for (std::list<CWindow*>::reverse_iterator iter = m_ChildWindows.rbegin(); iter != m_ChildWindows.rend(); ++iter)
00110           {
00111                bResult = (*iter)->OnMouseButtonDown(Point, Button);
00112                if (bResult)
00113                {
00114                     break;
00115                }
00116           }
00117      }
00118 
00119      return bResult;
00120 }
00121 
00122 
00123 bool CMenuBase::HandleMessage(CMessage* pMessage)
00124 {
00125      bool bHandled = false;
00126 
00127      if (pMessage)
00128      {
00129           switch(pMessage->MessageType())
00130           {
00131           case CMessage::MOUSE_MOVE:
00132           {
00133                CMouseMessage* pMouseMessage = dynamic_cast<CMouseMessage*>(pMessage);
00134                if (m_bVisible && pMouseMessage &&
00135                     m_WindowRect.SizeRect().HitTest(ViewToWindow(pMouseMessage->Point)) == CRect::RELPOS_INSIDE)
00136                {
00137                     UpdateCachedRects();
00138                     SMenuItem* pOldHighlight = m_pHighlightedItem;
00139                     m_pHighlightedItem = 0;
00140                     CPoint WindowPoint(ViewToWindow(pMouseMessage->Point));
00141                     for (t_MenuItemVector::iterator iter = m_MenuItems.begin(); iter != m_MenuItems.end(); ++iter)
00142                     {
00143                          if (iter->Rect.HitTest(WindowPoint) == CRect::RELPOS_INSIDE && !iter->MenuItem.bSpacer)
00144                          {
00145                               m_pHighlightedItem = &(iter->MenuItem);
00146                               break;
00147                          }
00148                     }
00149                     if (pOldHighlight != m_pHighlightedItem)
00150                     {
00151                          m_pPopupTimer->StopTimer();
00152                          if (m_pHighlightedItem && m_pHighlightedItem->pPopup)
00153                          {
00154                               m_pPopupTimer->StartTimer(1000);
00155                          }
00156                          Draw();
00157                     }
00158                }
00159                else if (m_pHighlightedItem != 0)
00160                {
00161                     m_pPopupTimer->StopTimer();
00162                     m_pHighlightedItem = 0;
00163                     Draw();
00164                }
00165                break;
00166           }
00167           case CMessage::CTRL_SINGLELCLICK:
00168           {
00169                TIntMessage* pCtrlMessage = dynamic_cast<TIntMessage*>(pMessage);
00170                if (pCtrlMessage && pCtrlMessage->Destination() == this)
00171                {
00172                     for (t_MenuItemVector::iterator iter = m_MenuItems.begin(); iter != m_MenuItems.end(); ++iter)
00173                     {
00174                          if (pCtrlMessage->Source() == iter->MenuItem.pPopup)
00175                          {
00176                               CMessageServer::Instance().QueueMessage(new TIntMessage(CMessage::CTRL_SINGLELCLICK, m_pParentWindow,
00177                                    this, pCtrlMessage->Value()));
00178                               bHandled = true;
00179                               break;
00180                          }
00181                     }
00182                }
00183                break;
00184           }
00185           case CMessage::CTRL_TIMER:
00186           {
00187                if (pMessage->Destination() == this)
00188                {
00189                     bHandled = true;
00190                }
00191                break;
00192           }
00193           default :
00194                bHandled = CWindow::HandleMessage(pMessage);
00195                break;
00196           }
00197      }
00198 
00199      return bHandled;
00200 }
00201 
00202 
00203 // CMenu
00204 
00205 CMenu::CMenu(const CRect& WindowRect, CWindow* pParent, CFontEngine* pFontEngine) :
00206      CMenuBase(WindowRect, pParent, pFontEngine)
00207 {
00208      CMessageServer::Instance().RegisterMessageClient(this, CMessage::MOUSE_MOVE);
00209      Draw();
00210 }
00211 
00212 
00213 CMenu::~CMenu(void)
00214 {
00215 
00216 }
00217 
00218 
00219 void CMenu::InsertMenuItem(const SMenuItem& MenuItem, int iPosition)
00220 {
00221      m_MenuItems.insert((iPosition == -1) ? m_MenuItems.end() : m_MenuItems.begin() + iPosition,
00222           s_MenuItemInfo(MenuItem, CRenderedString(m_pFontEngine, MenuItem.sItemText, CRenderedString::VALIGN_NORMAL), CRect()));
00223      m_bCachedRectsValid = false;
00224      if (MenuItem.pPopup)
00225      {
00226           MenuItem.pPopup->SetParentMenu(this);
00227      }
00228      Draw();
00229 }
00230 
00231 
00232 void CMenu::Draw(void) const
00233 {
00234      CWindow::Draw();
00235 
00236      if (m_pSDLSurface)
00237      {
00238           CPainter Painter(m_pSDLSurface, CPainter::PAINT_REPLACE);
00239           UpdateCachedRects();
00240           for (t_MenuItemVector::const_iterator iter = m_MenuItems.begin(); iter != m_MenuItems.end(); ++iter)
00241           {
00242                if (m_pHighlightedItem == &(iter->MenuItem))
00243                {
00244                     Painter.DrawRect(iter->Rect, true, m_HighlightColor, m_HighlightColor);
00245                }
00246                CRect TextRect(iter->Rect);
00247                TextRect.Grow(-2);
00248                if (iter->MenuItem.bSpacer)
00249                {
00250                     Painter.DrawVLine(TextRect.Top(), TextRect.Bottom(), TextRect.Left(), COLOR_LIGHTGRAY);
00251                     Painter.DrawVLine(TextRect.Top(), TextRect.Bottom(), TextRect.Right(), COLOR_DARKGRAY);
00252                }
00253                else
00254                     iter->RenderedString.Draw(m_pSDLSurface, TextRect, CPoint(TextRect.Left(), (TextRect.Top() + TextRect.Bottom()) * 3 / 4));
00255           }
00256      }
00257 }
00258 
00259 
00260 bool CMenu::OnMouseButtonDown(CPoint Point, unsigned int Button)
00261 {
00262      bool bResult = CMenuBase::OnMouseButtonDown(Point, Button);
00263 
00264      if (!bResult && m_bVisible && (Button == CMouseMessage::LEFT) &&
00265           (m_WindowRect.SizeRect().HitTest(ViewToWindow(Point)) == CRect::RELPOS_INSIDE))
00266      {
00267           UpdateCachedRects();
00268           for (t_MenuItemVector::iterator iter = m_MenuItems.begin(); iter != m_MenuItems.end(); ++iter)
00269           {
00270                if (iter->Rect.HitTest(ViewToWindow(Point)) == CRect::RELPOS_INSIDE && !iter->MenuItem.bSpacer)
00271                {
00272                     HideActivePopup();
00273                     if (iter->MenuItem.pPopup)
00274                     {
00275                          CPopupMenu* pPopup = dynamic_cast<CPopupMenu*>(iter->MenuItem.pPopup);
00276                          if (pPopup)
00277                          {
00278                               m_pActivePopup = pPopup;
00279                               ShowActivePopup(iter->Rect, GetAncestor(ROOT)->GetClientRect());
00280                          }
00281                     }
00282                     else
00283                     {
00284                          CMessageServer::Instance().QueueMessage(new TIntMessage(CMessage::CTRL_SINGLELCLICK, m_pParentWindow, this, iter->MenuItem.iItemId));
00285                     }
00286                     break;
00287                }
00288           }
00289           bResult = true;
00290      }
00291 
00292      return bResult;
00293 }
00294 
00295 
00296 bool CMenu::HandleMessage(CMessage* pMessage)
00297 {
00298      bool bHandled = false;
00299 
00300      if (pMessage)
00301      {
00302           switch(pMessage->MessageType())
00303           {
00304           case CMessage::MOUSE_MOVE:
00305           {
00306                CMouseMessage* pMouseMessage = dynamic_cast<CMouseMessage*>(pMessage);
00307                if (m_bVisible && pMouseMessage &&
00308                     m_WindowRect.SizeRect().HitTest(ViewToWindow(pMouseMessage->Point)) == CRect::RELPOS_INSIDE)
00309                {
00310                     UpdateCachedRects();
00311                     SMenuItem* pOldHighlight = m_pHighlightedItem;
00312                     m_pHighlightedItem = 0;
00313                     CPoint WindowPoint(ViewToWindow(pMouseMessage->Point));
00314                     for (t_MenuItemVector::iterator iter = m_MenuItems.begin(); iter != m_MenuItems.end(); ++iter)
00315                     {
00316                          if (iter->Rect.HitTest(WindowPoint) == CRect::RELPOS_INSIDE && !iter->MenuItem.bSpacer)
00317                          {
00318                               m_pHighlightedItem = &(iter->MenuItem);
00319                               break;
00320                          }
00321                     }
00322                     if (pOldHighlight != m_pHighlightedItem)
00323                     {
00324                          Draw();
00325                     }
00326                }
00327                else if (m_pHighlightedItem != 0)
00328                {
00329                     m_pHighlightedItem = 0;
00330                     Draw();
00331                }
00332                break;
00333           }
00334           default :
00335                bHandled = CMenuBase::HandleMessage(pMessage);
00336                break;
00337           }
00338      }
00339 
00340      return bHandled;
00341 }
00342 
00343 
00344 void CMenu::UpdateCachedRects(void) const
00345 {
00346      if (!m_bCachedRectsValid)
00347      {
00348           CRect SubRect(m_WindowRect.SizeRect());
00349           SubRect.Grow(-2);
00350           int iWidth = 5;
00351           for (t_MenuItemVector::iterator iter = m_MenuItems.begin(); iter != m_MenuItems.end(); ++iter)
00352           {
00353                if (iter->MenuItem.bSpacer)
00354                {
00355                     CRect TextRect(SubRect.Left() + iWidth, SubRect.Top() + 2, SubRect.Left() + iWidth + 1, SubRect.Bottom() - 2);
00356                     TextRect.Grow(2);
00357                     iter->Rect = TextRect;
00358                     iWidth += 9;
00359                }
00360                else
00361                {
00362                     CPoint Dims;
00363                     iter->RenderedString.GetMetrics(&Dims, 0, 0);
00364                     CRect TextRect(SubRect.Left() + iWidth, SubRect.Top() + 2, SubRect.Left() + iWidth + Dims.XPos(), SubRect.Bottom() - 2);
00365                     TextRect.Grow(2);
00366                     iter->Rect = TextRect;
00367                     iWidth += Dims.XPos() + 8;
00368                }
00369           }
00370           m_bCachedRectsValid = true;
00371      }
00372 }
00373 
00374 
00375 void CMenu::ShowActivePopup(const CRect& ParentRect, const CRect& BoundingRect)
00376 {
00377      // TODO: Add bounds checking for all edges.  Apply this same bounds checking logic to the popup root menu too.
00378      if (!m_pActivePopup)
00379      {
00380           throw(Wg_Ex_App(L"CMenu::ShowActivePopup() : Trying to show active popup menu when pActivePopup is NULL!"));
00381      }
00382      CRect MenuRect = m_pActivePopup->GetWindowRect();
00383      if (BoundingRect.HitTest(ParentRect.BottomLeft() + CPoint(MenuRect.Width(), 0)) & CRect::RELPOS_RIGHT)
00384      {
00385           int xDelta = BoundingRect.Right() - ParentRect.Left() + MenuRect.Width();
00386           if (!(BoundingRect.HitTest(ParentRect.BottomLeft() + CPoint(xDelta, 0)) & CRect::RELPOS_LEFT))
00387           {
00388                m_pActivePopup->Show(ParentRect.BottomLeft() + CPoint(xDelta, 5));
00389           }
00390      }
00391      else
00392      {
00393           m_pActivePopup->Show(ParentRect.BottomLeft() + CPoint(0, 5));
00394      }
00395      // Pop the popup to the top of the draw order and everything
00396      m_pActivePopup->SetNewParent(m_pActivePopup->GetAncestor(PARENT));
00397 }
00398 
00399 
00400 // CPopupMenu
00401 
00402 CPopupMenu::CPopupMenu(const CRect& WindowRect, CWindow* pParent, CFontEngine* pFontEngine) :
00403      CMenuBase(WindowRect, pParent, pFontEngine),
00404      m_pParentMenu(0)
00405 {
00406      m_bVisible = false;
00407      CMessageServer::Instance().RegisterMessageClient(this, CMessage::MOUSE_BUTTONDOWN);
00408      Draw();
00409 }
00410 
00411 
00412 CPopupMenu::~CPopupMenu(void)
00413 {
00414 
00415 }
00416 
00417 
00418 void CPopupMenu::Show(CPoint Position)
00419 {
00420      if (m_bVisible)
00421      {
00422           Hide();
00423      }
00424 
00425      int iHeight = 4;
00426      for (t_MenuItemVector::iterator iter = m_MenuItems.begin(); iter != m_MenuItems.end(); ++iter)
00427      {
00428           if (iter->MenuItem.bSpacer)
00429                iHeight += 6;
00430           else
00431           {
00432                CPoint Dims;
00433                iter->RenderedString.GetMetrics(&Dims, 0, 0);
00434                iHeight += Dims.YPos() + 5;
00435           }
00436      }
00437 
00438      //Bounds checking for menus, so that we don't draw off screen, since we can't.
00439      CRect TestRect = GetAncestor(ROOT)->GetWindowRect();
00440 
00441      if ( Position.XPos() < 0 )
00442      {
00443           Position.SetX(0);
00444      }
00445 
00446      if ( Position.YPos() < 0 )
00447      {
00448           Position.SetY(0);
00449      }
00450 
00451      if ( Position.XPos() + m_WindowRect.Width() > TestRect.Width() )
00452      {
00453           Position.SetX(Position.XPos() - ((Position.XPos() + m_WindowRect.Width()) - TestRect.Width()));
00454      }
00455 
00456      if ( Position.YPos() + m_WindowRect.Height() > TestRect.Height() )
00457      {
00458           Position.SetY(Position.YPos() - ((Position.YPos() + m_WindowRect.Height()) - TestRect.Bottom()));
00459      }
00460 
00461      SetWindowRect(GetAncestor(PARENT)->ViewToClient(CRect(Position, Position + CPoint(m_WindowRect.Width() - 1, iHeight + 2))));
00462      m_bVisible = true;
00463      CView* pView = GetView();
00464      if (pView && !dynamic_cast<CPopupMenu*>(m_pParentWindow))
00465      {
00466           pView->SetFloatingWindow(this);
00467      }
00468      Draw();
00469 }
00470 
00471 
00472 void CPopupMenu::Hide(void)
00473 {
00474      HideActivePopup();
00475      m_bVisible = false;
00476      m_bCachedRectsValid = false;
00477      CView* pView = GetView();
00478      if (!dynamic_cast<CPopupMenu*>(m_pParentWindow) && pView && pView->GetFloatingWindow() == this)
00479      {
00480           pView->SetFloatingWindow(0);
00481      }
00482      CMessageServer::Instance().QueueMessage(new CMessage(CMessage::APP_PAINT, 0, this));
00483      m_pHighlightedItem = 0;
00484      Draw();
00485 }
00486 
00487 
00488 void CPopupMenu::HideAll(void)
00489 {
00490      CPopupMenu* pParentPopup = dynamic_cast<CPopupMenu*>(m_pParentWindow);
00491      if (pParentPopup)
00492      {
00493           pParentPopup->HideAll();
00494      }
00495      else
00496      {
00497           CMenu* pRootMenu = dynamic_cast<CMenu*>(m_pParentWindow);
00498           if (pRootMenu)
00499           {
00500                pRootMenu->HideActivePopup();
00501           }
00502           else
00503           {
00504                Hide();
00505           }
00506      }
00507 }
00508 
00509 
00510 bool CPopupMenu::IsInsideChild(const CPoint& Point) const
00511 {
00512      if (m_WindowRect.SizeRect().HitTest(ViewToWindow(Point)) == CRect::RELPOS_INSIDE)
00513      {
00514           return true;
00515      }
00516      if (!m_pActivePopup)
00517      {
00518           return false;
00519      }
00520      return m_pActivePopup->IsInsideChild(Point);
00521 }
00522 
00523 
00524 void CPopupMenu::Draw(void) const
00525 {
00526      CWindow::Draw();
00527 
00528      if (m_pSDLSurface)
00529      {
00530           CPainter Painter(m_pSDLSurface, CPainter::PAINT_REPLACE);
00531           Painter.DrawRect(m_WindowRect.SizeRect(), false, COLOR_LIGHTGRAY);
00532           Painter.DrawHLine(0, m_WindowRect.Width(), m_WindowRect.Height(), COLOR_DARKGRAY);
00533           Painter.DrawVLine(0, m_WindowRect.Height(), m_WindowRect.Width(), COLOR_DARKGRAY);
00534           UpdateCachedRects();
00535           for (t_MenuItemVector::const_iterator iter = m_MenuItems.begin(); iter != m_MenuItems.end(); ++iter)
00536           {
00537                if (m_pHighlightedItem == &(iter->MenuItem))
00538                {
00539                     Painter.DrawRect(iter->Rect, true, m_HighlightColor, m_HighlightColor);
00540                }
00541                CRect TextRect(iter->Rect);
00542                TextRect.Grow(-2);
00543                if (iter->MenuItem.bSpacer)
00544                {
00545                     Painter.DrawHLine(TextRect.Left(), TextRect.Right(), TextRect.Top(), COLOR_LIGHTGRAY);
00546                     Painter.DrawHLine(TextRect.Left(), TextRect.Right(), TextRect.Bottom(), COLOR_DARKGRAY);
00547                }
00548                else
00549                     iter->RenderedString.Draw(m_pSDLSurface, TextRect, TextRect.TopLeft());
00550                if (iter->MenuItem.pPopup)
00551                {
00552                     CRect ArrowRect(iter->Rect);
00553                     ArrowRect.SetLeft(ArrowRect.Right() - m_hRightArrowBitmap.Bitmap()->w);
00554                     SDL_Rect SourceRect;
00555                     SourceRect.x = stdex::safe_static_cast<short int>(0);
00556                     SourceRect.y = stdex::safe_static_cast<short int>((m_hRightArrowBitmap.Bitmap()->h - ArrowRect.Height()) / 2 < 0 ?
00557                          0 : (m_hRightArrowBitmap.Bitmap()->h - ArrowRect.Height()) / 2);
00558                     SourceRect.w = stdex::safe_static_cast<short int>(m_hRightArrowBitmap.Bitmap()->w);
00559                     SourceRect.h = stdex::safe_static_cast<short int>(std::min(ArrowRect.Height(), m_hRightArrowBitmap.Bitmap()->h));
00560                     SDL_Rect DestRect;
00561                     DestRect.x = stdex::safe_static_cast<short int>(ArrowRect.Left());
00562                     DestRect.y = stdex::safe_static_cast<short int>((ArrowRect.Height() - m_hRightArrowBitmap.Bitmap()->h) / 2 < 0 ?
00563                          ArrowRect.Top() : ArrowRect.Top() + (ArrowRect.Height() - m_hRightArrowBitmap.Bitmap()->h) / 2);
00564                     DestRect.w = stdex::safe_static_cast<short int>(m_hRightArrowBitmap.Bitmap()->w);
00565                     DestRect.h = stdex::safe_static_cast<short int>(std::min(ArrowRect.Height(), m_hRightArrowBitmap.Bitmap()->h));
00566                     SDL_BlitSurface(m_hRightArrowBitmap.Bitmap(), &SourceRect, m_pSDLSurface, &DestRect);
00567                }
00568           }
00569      }
00570 }
00571 
00572 
00573 void CPopupMenu::PaintToSurface(SDL_Surface& /*ScreenSurface*/, SDL_Surface& FloatingSurface, const CPoint& Offset) const
00574 {
00575      if (m_bVisible)
00576      {
00577           SDL_Rect SourceRect = CRect(m_WindowRect.SizeRect()).SDLRect();
00578           SDL_Rect DestRect = CRect(m_WindowRect + Offset).SDLRect();
00579           SDL_BlitSurface(m_pSDLSurface, &SourceRect, &FloatingSurface, &DestRect);
00580           CPoint NewOffset = m_ClientRect.TopLeft() + m_WindowRect.TopLeft() + Offset;
00581           for (std::list<CWindow*>::const_iterator iter = m_ChildWindows.begin(); iter != m_ChildWindows.end(); ++iter)
00582           {
00583                (*iter)->PaintToSurface(FloatingSurface, FloatingSurface, NewOffset);
00584           }
00585      }
00586 }
00587 
00588 
00589 bool CPopupMenu::OnMouseButtonDown(CPoint Point, unsigned int Button)
00590 {
00591      bool bResult = CMenuBase::OnMouseButtonDown(Point, Button);
00592 
00593      CPoint WindowPoint(ViewToWindow(Point));
00594      if (!bResult && m_bVisible && (m_WindowRect.SizeRect().HitTest(WindowPoint) == CRect::RELPOS_INSIDE))
00595      {
00596           UpdateCachedRects();
00597           for (t_MenuItemVector::iterator iter = m_MenuItems.begin(); iter != m_MenuItems.end(); ++iter)
00598           {
00599                if (iter->Rect.HitTest(WindowPoint) == CRect::RELPOS_INSIDE && !iter->MenuItem.bSpacer)
00600                {
00601                     if (!iter->MenuItem.pPopup)
00602                     {
00603                          CMessageClient* pDestination = m_pParentWindow;
00604                          if (m_pParentMenu)
00605                          {
00606                               pDestination = m_pParentMenu;
00607                          }
00608                          CMessageServer::Instance().QueueMessage(new TIntMessage(CMessage::CTRL_SINGLELCLICK, pDestination, this, iter->MenuItem.iItemId));
00609                          HideAll();
00610                     }
00611                     else
00612                     {
00613                          HideActivePopup();
00614                          m_pActivePopup = iter->MenuItem.pPopup;
00615                          ShowActivePopup(iter->Rect, GetAncestor(ROOT)->GetClientRect());
00616                     }
00617                     break;
00618                }
00619           }
00620           bResult = true;
00621      }
00622 
00623      return bResult;
00624 }
00625 
00626 
00627 bool CPopupMenu::HandleMessage(CMessage* pMessage)
00628 {
00629      bool bHandled = false;
00630 
00631      if (pMessage)
00632      {
00633           switch(pMessage->MessageType())
00634           {
00635           case CMessage::MOUSE_BUTTONDOWN:
00636           {
00637                CMouseMessage* pMouseMessage = dynamic_cast<CMouseMessage*>(pMessage);
00638                if (m_bVisible && pMouseMessage &&
00639                     m_WindowRect.SizeRect().HitTest(ViewToWindow(pMouseMessage->Point)) != CRect::RELPOS_INSIDE)
00640                {
00641                     // If the user clicked outside the window, we just want to hide the window,
00642                     // and then pass the message on (bHandled = false)
00643                     // But we only want the root popup to do this, and only if none of it's children were hit
00644                     if (!dynamic_cast<CPopupMenu*>(m_pParentWindow) && !IsInsideChild(pMouseMessage->Point) &&
00645                          !(m_pParentMenu && m_pParentMenu->GetWindowRect().SizeRect().HitTest(
00646                          m_pParentMenu->ViewToWindow(pMouseMessage->Point)) == CRect::RELPOS_INSIDE))
00647                     {
00648                          HideAll();
00649                     }
00650                }
00651                break;
00652           }
00653           case CMessage::CTRL_TIMER:
00654           {
00655                if (pMessage->Destination() == this)
00656                {
00657                     CRect ItemRect;
00658                     for (t_MenuItemVector::iterator iter = m_MenuItems.begin(); iter != m_MenuItems.end(); ++iter)
00659                     {
00660                          if (m_pHighlightedItem == &(iter->MenuItem))
00661                          {
00662                               ItemRect = iter->Rect;
00663                               break;
00664                          }
00665                     }
00666                     if (m_pHighlightedItem && m_pHighlightedItem->pPopup)
00667                     {
00668                          HideActivePopup();
00669                          m_pActivePopup = m_pHighlightedItem->pPopup;
00670                          ShowActivePopup(ItemRect, GetAncestor(ROOT)->GetClientRect());
00671                     }
00672                     bHandled = true;
00673                }
00674                break;
00675           }
00676           default :
00677                bHandled = CMenuBase::HandleMessage(pMessage);
00678                break;
00679           }
00680      }
00681 
00682      return bHandled;
00683 }
00684 
00685 
00686 void CPopupMenu::UpdateCachedRects(void) const
00687 {
00688      if (!m_bCachedRectsValid)
00689      {
00690           CRect SubRect(m_WindowRect.SizeRect());
00691           SubRect.Grow(-2);
00692           int iHeight = 4;
00693           for (t_MenuItemVector::iterator iter = m_MenuItems.begin(); iter != m_MenuItems.end(); ++iter)
00694           {
00695                if (iter->MenuItem.bSpacer)
00696                {
00697                     CRect TextRect(SubRect.Left() + 3, SubRect.Top() + iHeight, SubRect.Right() - 3, SubRect.Top() + iHeight + 1);
00698                     TextRect.Grow(2);
00699                     iter->Rect = TextRect;
00700                     iHeight += 6;
00701                }
00702                else
00703                {
00704                     CPoint Dims;
00705                     iter->RenderedString.GetMetrics(&Dims, 0, 0);
00706                     CRect TextRect(SubRect.Left() + 3, SubRect.Top() + iHeight, SubRect.Right() - 3, SubRect.Top() + iHeight + Dims.YPos());
00707                     TextRect.Grow(2);
00708                     iter->Rect = TextRect;
00709                     iHeight += Dims.YPos() + 5;
00710                }
00711           }
00712           m_bCachedRectsValid = true;
00713      }
00714 }
00715 
00716 
00717 void CPopupMenu::ShowActivePopup(const CRect& ParentRect, const CRect& BoundingRect)
00718 {
00719      // TODO: Add bounds checking for all edges.  Apply this same bounds checking logic to the popup root menu too.
00720      if (!m_pActivePopup)
00721      {
00722           throw(Wg_Ex_App(L"CPopupMenu::ShowActivePopup() : Trying to show active popup menu when pActivePopup is NULL!"));
00723      }
00724 
00725      CRect MenuRect = m_pActivePopup->GetWindowRect();
00726 
00727      //Test to see if we're going to draw the menu off the right side of the screen, if we are, then we'll correct it to draw to the left of the menu
00728      if (BoundingRect.HitTest(ParentRect.TopRight() + CPoint(5, 0) + CPoint(MenuRect.Width(), 0)) & CRect::RELPOS_RIGHT)
00729      {
00730           m_pActivePopup->Show(ClientToView(ParentRect.TopLeft() - CPoint(MenuRect.Width() + 5, 0)) - m_ClientRect.TopLeft());
00731      }
00732      else
00733      {
00734           m_pActivePopup->Show(ClientToView(ParentRect.TopRight() + CPoint(5, 0)) - m_ClientRect.TopLeft());
00735      }
00736 }
00737 
00738 }

Generated on Wed May 16 23:11:26 2007 for wGui by  doxygen 1.5.1