home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / wxos2240.zip / wxWindows-2.4.0 / src / os2 / ownerdrw.cpp < prev    next >
C/C++ Source or Header  |  2003-01-03  |  16KB  |  499 lines

  1. ///////////////////////////////////////////////////////////////////////////////
  2. // Name:        msw/ownerdrw.cpp
  3. // Purpose:     implementation of wxOwnerDrawn class
  4. // Author:      David Webster
  5. // Modified by:
  6. // Created:     10/12/99
  7. // RCS-ID:      $Id: OWNERDRW.CPP,v 1.14.2.3 2002/12/29 21:42:34 SN Exp $
  8. // Copyright:   (c) David Webster
  9. // Licence:     wxWindows license
  10. ///////////////////////////////////////////////////////////////////////////////
  11.  
  12. #ifdef __GNUG__
  13. #pragma implementation
  14. #endif
  15.  
  16. // For compilers that support precompilation, includes "wx.h".
  17. #include "wx/wxprec.h"
  18.  
  19. #ifndef WX_PRECOMP
  20.   #include "wx/window.h"
  21.   #include "wx/os2/private.h"
  22.   #include "wx/font.h"
  23.   #include "wx/bitmap.h"
  24.   #include "wx/dcmemory.h"
  25.   #include "wx/menu.h"
  26.   #include "wx/utils.h"
  27.   #include "wx/settings.h"
  28. #endif
  29.  
  30. #if wxUSE_OWNER_DRAWN
  31.  
  32. #include "wx/ownerdrw.h"
  33. #include "wx/menuitem.h"
  34.  
  35.  
  36. // ============================================================================
  37. // implementation of wxOwnerDrawn class
  38. // ============================================================================
  39.  
  40. //
  41. // ctor
  42. // ----
  43. //
  44. wxOwnerDrawn::wxOwnerDrawn(
  45.   const wxString&                   rsStr
  46. , bool                              bCheckable
  47. , bool                              bMenuItem
  48. )
  49. : m_strName(rsStr)
  50. {
  51.     m_bCheckable   = bCheckable;
  52.     m_bOwnerDrawn  = FALSE;
  53.     m_nHeight      = 0;
  54.     m_nMarginWidth = ms_nLastMarginWidth;
  55.     if (wxNORMAL_FONT)
  56.         m_font = *wxNORMAL_FONT;
  57. } // end of wxOwnerDrawn::wxOwnerDrawn
  58.  
  59. size_t wxOwnerDrawn::ms_nDefaultMarginWidth = 15;
  60.  
  61. size_t wxOwnerDrawn::ms_nLastMarginWidth = ms_nDefaultMarginWidth;
  62.  
  63. //
  64. // Drawing
  65. // -------
  66. //
  67.  
  68. bool wxOwnerDrawn::OnMeasureItem(
  69.   size_t*                           pWidth
  70. , size_t*                           pHeight
  71. )
  72. {
  73.     wxMemoryDC                      vDC;
  74.  
  75.  
  76.     wxString                        sStr = wxStripMenuCodes(m_strName);
  77.  
  78.     //
  79.     // If we have a valid accel string, then pad out
  80.     // the menu string so the menu and accel string are not
  81.     // placed ontop of eachother.
  82.     if (!m_strAccel.empty() )
  83.     {
  84.         sStr.Pad(sStr.Length()%8);
  85.         sStr += m_strAccel;
  86.     }
  87.     vDC.SetFont(GetFont());
  88.     vDC.GetTextExtent( sStr
  89.                       ,(long *)pWidth
  90.                       ,(long *)pHeight
  91.                      );
  92.     if (!m_strAccel.IsEmpty())
  93.     {
  94.         //
  95.         // Measure the accelerator string, and add it's width to
  96.         // the total item width, plus 16 (Accelerators are right justified,
  97.         // with the right edge of the text rectangle 16 pixels left of
  98.         // the right edge of the menu)
  99.         //
  100.         int                         nAccelWidth;
  101.         int                         nAccelHeight;
  102.  
  103.         vDC.GetTextExtent( m_strAccel
  104.                           ,&nAccelWidth
  105.                           ,&nAccelHeight
  106.                          );
  107.         *pWidth += nAccelWidth;
  108.     }
  109.  
  110.     //
  111.     // Add space at the end of the menu for the submenu expansion arrow
  112.     // this will also allow offsetting the accel string from the right edge
  113.     //
  114.     *pWidth += GetDefaultMarginWidth() * 1.5;
  115.  
  116.     //
  117.     // JACS: items still look too tightly packed, so adding 5 pixels.
  118.     //
  119.     (*pHeight) += 5;
  120.  
  121.     //
  122.     // Ray Gilbert's changes - Corrects the problem of a BMP
  123.     // being placed next to text in a menu item, and the BMP does
  124.     // not match the size expected by the system.  This will
  125.     // resize the space so the BMP will fit.  Without this, BMPs
  126.     // must be no larger or smaller than 16x16.
  127.     //
  128.     if (m_bmpChecked.Ok())
  129.     {
  130.         //
  131.         // Is BMP height larger then text height?
  132.         //
  133.         size_t                      nAdjustedHeight = m_bmpChecked.GetHeight() +
  134.                                                       wxSystemSettings::GetMetric(wxSYS_EDGE_Y);
  135.         if (*pHeight < nAdjustedHeight)
  136.             *pHeight = nAdjustedHeight;
  137.  
  138.         //
  139.         // Does BMP encroach on default check menu position?
  140.         //
  141.         size_t                      nAdjustedWidth = m_bmpChecked.GetWidth() +
  142.                                                      (wxSystemSettings::GetMetric(wxSYS_EDGE_X) * 2);
  143.  
  144.         //
  145.         // Do we need to widen margin to fit BMP?
  146.         //
  147.         if ((size_t)GetMarginWidth() < nAdjustedWidth)
  148.             SetMarginWidth(nAdjustedWidth);
  149.  
  150.         //
  151.         // Add the size of the bitmap to our total size...
  152.         //
  153.         *pWidth += GetMarginWidth();
  154.     }
  155.  
  156.     //
  157.     // Add the size of the bitmap to our total size - even if we don't have
  158.     // a bitmap we leave room for one...
  159.     //
  160.     *pWidth += GetMarginWidth();
  161.  
  162.     //
  163.     // Make sure that this item is at least as
  164.     // tall as the user's system settings specify
  165.     //
  166.     if (*pHeight < m_nMinHeight)
  167.         *pHeight = m_nMinHeight;
  168.     m_nHeight = *pHeight;                // remember height for use in OnDrawItem
  169.     return TRUE;
  170. } // end of wxOwnerDrawn::OnMeasureItem
  171.  
  172. // draw the item
  173. bool wxOwnerDrawn::OnDrawItem(
  174.   wxDC&                             rDC
  175. , const wxRect&                     rRect
  176. , wxODAction                        eAction
  177. , wxODStatus                        eStatus
  178. )
  179. {
  180.     //
  181.     // We do nothing on focus change
  182.     //
  183.     if (eAction == wxODFocusChanged )
  184.         return TRUE;
  185.  
  186.     //
  187.     // Select the font and draw the text
  188.     // ---------------------------------
  189.     //
  190.  
  191.     CHARBUNDLE                      vCbnd;
  192.     HPS                             hPS= rDC.GetHPS();
  193.     wxColour                        vColBack;
  194.     wxColour                        vColText;
  195.     COLORREF                        vRef;
  196.     RECTL                           vRect = {rRect.x + 4, rRect.y + 1, rRect.x + (rRect.width - 2), rRect.y + rRect.height};
  197.  
  198.     memset(&vCbnd, 0, sizeof(CHARBUNDLE));
  199.  
  200.     //
  201.     // Use default font if no font set
  202.     //
  203.     if (m_font.Ok())
  204.     {
  205.         m_font.RealizeResource();
  206.     }
  207.     else
  208.     {
  209.         ::GpiSetCharSet(hPS, LCID_DEFAULT);
  210.     }
  211.  
  212.     //
  213.     // Base on the status of the menu item pick the right colors
  214.     //
  215.     if (eStatus & wxODSelected)
  216.     {
  217.         wxColour                        vCol2("WHITE");
  218.         vColBack.Set( (unsigned char)0
  219.                      ,(unsigned char)0
  220.                      ,(unsigned char)160
  221.                     ); // no dark blue in color table
  222.         vColText = vCol2;
  223.     }
  224.     else if (eStatus & wxODDisabled)
  225.     {
  226.         vRef = (ULONG)::WinQuerySysColor( HWND_DESKTOP
  227.                                          ,SYSCLR_MENU // Light gray
  228.                                          ,0L
  229.                                         );
  230.         vColBack.Set( GetRValue(vRef)
  231.                      ,GetGValue(vRef)
  232.                      ,GetBValue(vRef)
  233.                     );
  234.         vRef = (ULONG)::WinQuerySysColor( HWND_DESKTOP
  235.                                          ,SYSCLR_MENUDISABLEDTEXT // dark gray
  236.                                          ,0L
  237.                                         );
  238.         vColText.Set( GetRValue(vRef)
  239.                      ,GetGValue(vRef)
  240.                      ,GetBValue(vRef)
  241.                     );
  242.     }
  243.     else
  244.     {
  245.         //
  246.         // Fall back to default colors if none explicitly specified
  247.         //
  248.         vRef = ::WinQuerySysColor( HWND_DESKTOP
  249.                                   ,SYSCLR_MENU  // we are using gray for all our window backgrounds in wxWindows
  250.                                   ,0L
  251.                                  );
  252.         vColBack.Set( GetRValue(vRef)
  253.                      ,GetGValue(vRef)
  254.                      ,GetBValue(vRef)
  255.                     );
  256.         vRef = ::WinQuerySysColor( HWND_DESKTOP
  257.                                   ,SYSCLR_WINDOWTEXT // Black
  258.                                   ,0L
  259.                                  );
  260.         vColText.Set( GetRValue(vRef)
  261.                      ,GetGValue(vRef)
  262.                      ,GetBValue(vRef)
  263.                     );
  264.     }
  265.  
  266.     rDC.SetTextBackground(vColBack);
  267.     rDC.SetTextForeground(vColText);
  268.     rDC.SetBackgroundMode(wxTRANSPARENT);
  269.     vCbnd.lColor     = vColText.GetPixel();
  270.     vCbnd.lBackColor = vColBack.GetPixel();
  271.     ::GpiSetAttrs( hPS
  272.                   ,PRIM_CHAR
  273.                   ,CBB_BACK_COLOR | CBB_COLOR
  274.                   ,0
  275.                   ,&vCbnd
  276.                  );
  277.     ::GpiSetBackMix( hPS
  278.                     ,BM_LEAVEALONE
  279.                    );
  280.  
  281.     //
  282.     // Paint the background
  283.     //
  284.     ::WinFillRect(hPS, &vRect, vColBack.GetPixel());
  285.  
  286.     //
  287.     // Determine where to draw and leave space for a check-mark.
  288.     //
  289.     int                             nX = rRect.x + GetMarginWidth();
  290.  
  291.     //
  292.     // Unfortunately, unlike Win32, PM has no owner drawn specific text
  293.     // drawing methods like ::DrawState that can cleanly handle accel
  294.     // pneumonics and deal, automatically, with various states, so we have
  295.     // to handle them ourselves. Notice Win32 can't handle \t in ownerdrawn
  296.     // strings either.  We cannot handle mneumonics either.  We display
  297.     // it, though, in hopes we can figure it out some day.
  298.     //
  299.  
  300.     //
  301.     // Display main text and accel text separately to allign better
  302.     //
  303.     wxString                        sTgt = "\t";
  304.     wxString                        sFullString = m_strName; // need to save the original text
  305.     wxString                        sAccel;
  306.     size_t                          nIndex;
  307.     size_t                          nWidth;
  308.     size_t                          nCharWidth;
  309.     size_t                          nHeight;
  310.     bool                            bFoundMneumonic = FALSE;
  311.     bool                            bFoundAccel = FALSE;
  312.  
  313.     //
  314.     // Deal with the tab, extracting the Accel text
  315.     //
  316.     nIndex = sFullString.Find(sTgt.c_str());
  317.     if (nIndex != -1)
  318.     {
  319.         bFoundAccel = TRUE;
  320.         sAccel = sFullString.Mid(nIndex + 1);
  321.         sFullString.Remove(nIndex);
  322.     }
  323.  
  324.     //
  325.     // Deal with the mneumonic character
  326.     //
  327.     sTgt = "~";
  328.     nIndex = sFullString.Find(sTgt.c_str());
  329.     if (nIndex != -1)
  330.     {
  331.         wxString                    sTmp = sFullString;
  332.  
  333.         bFoundMneumonic = TRUE;
  334.         sTmp.Remove(nIndex);
  335.         rDC.GetTextExtent( sTmp
  336.                           ,(long *)&nWidth
  337.                           ,(long *)&nHeight
  338.                          );
  339.         sTmp = sFullString[nIndex + 1];
  340.         rDC.GetTextExtent( sTmp
  341.                           ,(long *)&nCharWidth
  342.                           ,(long *)&nHeight
  343.                          );
  344.         sFullString.Replace(sTgt.c_str(), "", TRUE);
  345.     }
  346.  
  347.     //
  348.     // Draw the main item text sans the accel text
  349.     //
  350.     POINTL                      vPntStart = {nX, rRect.y + 4};
  351.     ::GpiCharStringAt( rDC.GetHPS()
  352.                       ,&vPntStart
  353.                       ,sFullString.length()
  354.                       ,(PCH)sFullString.c_str()
  355.                      );
  356.     if (bFoundMneumonic)
  357.     {
  358.         //
  359.         // Underline the mneumonic -- still won't work, but at least it "looks" right
  360.         //
  361.         wxPen                       vPen;
  362.         POINTL                      vPntEnd = {nX + nWidth + nCharWidth - 3, rRect.y + 2}; //CharWidth is bit wide
  363.  
  364.         vPntStart.x = nX + nWidth - 1;
  365.         vPntStart.y = rRect.y + 2; // Make it look pretty!
  366.         vPen = wxPen(vColText, 1, wxSOLID); // Assuming we are always black
  367.         rDC.SetPen(vPen);
  368.         ::GpiMove(hPS, &vPntStart);
  369.         ::GpiLine(hPS, &vPntEnd);
  370.     }
  371.  
  372.     //
  373.     // Now draw the accel text
  374.     //
  375.     if (bFoundAccel)
  376.     {
  377.         size_t                      nWidth;
  378.         size_t                      nHeight;
  379.  
  380.         rDC.GetTextExtent( sAccel
  381.                           ,(long *)&nWidth
  382.                           ,(long *)&nHeight
  383.                          );
  384.         //
  385.         // Back off the starting position from the right edge
  386.         //
  387.         vPntStart.x = rRect.width - (nWidth + 7);
  388.         vPntStart.y = rRect.y + 4;
  389.         ::GpiCharStringAt( rDC.GetHPS()
  390.                           ,&vPntStart
  391.                           ,sAccel.length()
  392.                           ,(PCH)sAccel.c_str()
  393.                          );
  394.     }
  395.  
  396.     //
  397.     // Draw the bitmap
  398.     // ---------------
  399.     //
  400.     if (IsCheckable() && !m_bmpChecked.Ok())
  401.     {
  402.         if (eStatus & wxODChecked)
  403.         {
  404.             RECTL                   vRect;
  405.             HBITMAP                 hBmpCheck = ::WinGetSysBitmap(HWND_DESKTOP, SBMP_MENUCHECK);
  406.  
  407.             vRect.xLeft   = rRect.x;
  408.             vRect.xRight  = rRect.x + GetMarginWidth();
  409.             vRect.yBottom = rRect.y;
  410.             vRect.yTop    = rRect.y + m_nHeight - 3;
  411.  
  412.             ::WinDrawBitmap( hPS             // PS for this menuitem
  413.                             ,hBmpCheck       // system checkmark
  414.                             ,NULL            // draw the whole bitmap
  415.                             ,(PPOINTL)&vRect // destination -- bottom left corner of the menuitem area
  416.                             ,0L              // ignored
  417.                             ,0L              // draw a bitmap
  418.                             ,DBM_NORMAL      // draw normal size
  419.                            );
  420.         }
  421.     }
  422.     else
  423.     {
  424.         //
  425.         // For uncheckable item we use only the 'checked' bitmap
  426.         //
  427.         wxBitmap                    vBmp(GetBitmap(IsCheckable() ? ((eStatus & wxODChecked) != 0) : TRUE));
  428.  
  429.         if (vBmp.Ok())
  430.         {
  431.  
  432.             wxMemoryDC              vDCMem(&rDC);
  433.             wxMemoryDC*             pOldDC = (wxMemoryDC*)vBmp.GetSelectedInto();
  434.  
  435.             if(pOldDC != NULL)
  436.             {
  437.                 vBmp.SetSelectedInto(NULL);
  438.             }
  439.             vDCMem.SelectObject(vBmp);
  440.  
  441.             //
  442.             // Center bitmap
  443.             //
  444.             int                     nBmpWidth = vBmp.GetWidth();
  445.             int                     nBmpHeight = vBmp.GetHeight();
  446.  
  447.             //
  448.             // There should be enough space!
  449.             //
  450.             wxASSERT((nBmpWidth <= rRect.width) && (nBmpHeight <= rRect.height));
  451.  
  452.             int                     nHeightDiff = m_nHeight - nBmpHeight;
  453.  
  454.             rDC.Blit( rRect.x + (GetMarginWidth() - nBmpWidth) / 2
  455.                      ,rRect.y + nHeightDiff / 2
  456.                      ,nBmpWidth
  457.                      ,nBmpHeight
  458.                      ,&vDCMem
  459.                      ,0
  460.                      ,0
  461.                      ,wxCOPY
  462.                      ,TRUE
  463.                     );
  464.  
  465.             if (eStatus & wxODSelected)
  466.             {
  467.                 RECT                vRectBmp = { rRect.x
  468.                                                 ,rRect.y
  469.                                                 ,rRect.x + GetMarginWidth() - 1
  470.                                                 ,rRect.y + m_nHeight - 1
  471.                                                };
  472.                 POINTL              vPnt1 = {rRect.x + 1, rRect.y + 3}; // Leave a little background border
  473.                 POINTL              vPnt2 = {rRect.x + GetMarginWidth(), rRect.y + m_nHeight - 3};
  474.  
  475.                 LINEBUNDLE          vLine;
  476.  
  477.                 vLine.lColor = vColBack.GetPixel();
  478.                 ::GpiSetAttrs( hPS
  479.                               ,PRIM_LINE
  480.                               ,LBB_COLOR
  481.                               ,0
  482.                               ,&vLine
  483.                              );
  484.                 ::GpiMove(hPS, &vPnt1);
  485.                 ::GpiBox( hPS
  486.                          ,DRO_OUTLINE
  487.                          ,&vPnt2
  488.                          ,0L
  489.                          ,0L
  490.                         );
  491.             }
  492.             vBmp.SetSelectedInto(NULL);
  493.         }
  494.     }
  495.     return TRUE;
  496. } // end of wxOwnerDrawn::OnDrawItem
  497.  
  498. #endif //wxUSE_OWNER_DRAWN
  499.