]> git.saurik.com Git - wxWidgets.git/commitdiff
implement support for per-state bitmaps in wxMSW wxButton
authorVadim Zeitlin <vadim@wxwidgets.org>
Mon, 15 Jun 2009 20:18:10 +0000 (20:18 +0000)
committerVadim Zeitlin <vadim@wxwidgets.org>
Mon, 15 Jun 2009 20:18:10 +0000 (20:18 +0000)
git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@61067 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775

samples/widgets/button.cpp
src/msw/button.cpp

index c01bc1cd276af77ba8a348e3909ce3ac1ffdc79f..e6fb8662fb6d8c9079cca6bf8f5e6756b4c3281a 100644 (file)
@@ -121,18 +121,18 @@ protected:
     // ------------
 
     // the check/radio boxes for styles
-    wxCheckBox *m_chkBitmap,
-               *m_chkImage,
+    wxCheckBox *m_chkBitmapOnly,
+               *m_chkTextAndBitmap,
                *m_chkFit,
                *m_chkDefault;
 
     // more checkboxes for wxBitmapButton only
-    wxCheckBox *m_chkUseSelected,
+    wxCheckBox *m_chkUsePressed,
                *m_chkUseFocused,
-               *m_chkUseHover,
+               *m_chkUseCurrent,
                *m_chkUseDisabled;
 
-    // and an image position choice used if m_chkImage is on
+    // and an image position choice used if m_chkTextAndBitmap is on
     wxRadioBox *m_radioImagePos;
 
     wxRadioBox *m_radioHAlign,
@@ -181,13 +181,13 @@ ButtonWidgetsPage::ButtonWidgetsPage(WidgetsBookCtrl *book,
                   : WidgetsPage(book, imaglist, button_xpm)
 {
     // init everything
-    m_chkBitmap =
-    m_chkImage =
+    m_chkBitmapOnly =
+    m_chkTextAndBitmap =
     m_chkFit =
     m_chkDefault =
-    m_chkUseSelected =
+    m_chkUsePressed =
     m_chkUseFocused =
-    m_chkUseHover =
+    m_chkUseCurrent =
     m_chkUseDisabled = (wxCheckBox *)NULL;
 
     m_radioImagePos =
@@ -209,19 +209,24 @@ void ButtonWidgetsPage::CreateContent()
 
     wxSizer *sizerLeft = new wxStaticBoxSizer(box, wxVERTICAL);
 
-    m_chkBitmap = CreateCheckBoxAndAddToSizer(sizerLeft, _T("&Bitmap button"));
-    m_chkImage = CreateCheckBoxAndAddToSizer(sizerLeft, _T("With &image"));
+    m_chkBitmapOnly = CreateCheckBoxAndAddToSizer(sizerLeft, "&Bitmap only");
+    m_chkTextAndBitmap = CreateCheckBoxAndAddToSizer(sizerLeft, "Text &and &bitmap");
     m_chkFit = CreateCheckBoxAndAddToSizer(sizerLeft, _T("&Fit exactly"));
     m_chkDefault = CreateCheckBoxAndAddToSizer(sizerLeft, _T("&Default"));
 
     sizerLeft->AddSpacer(5);
 
     wxSizer *sizerUseLabels =
-        new wxStaticBoxSizer(wxVERTICAL, this, _T("&Use the following bitmaps?"));
-    m_chkUseSelected = CreateCheckBoxAndAddToSizer(sizerUseLabels, _T("&Pushed"));
-    m_chkUseFocused = CreateCheckBoxAndAddToSizer(sizerUseLabels, _T("&Focused"));
-    m_chkUseHover = CreateCheckBoxAndAddToSizer(sizerUseLabels, _T("&Hover"));
-    m_chkUseDisabled = CreateCheckBoxAndAddToSizer(sizerUseLabels, _T("&Disabled"));
+        new wxStaticBoxSizer(wxVERTICAL, this,
+                "&Use the following bitmaps in addition to the normal one?");
+    m_chkUsePressed = CreateCheckBoxAndAddToSizer(sizerUseLabels,
+        "&Pressed (small help icon)");
+    m_chkUseFocused = CreateCheckBoxAndAddToSizer(sizerUseLabels,
+        "&Focused (small error icon)");
+    m_chkUseCurrent = CreateCheckBoxAndAddToSizer(sizerUseLabels,
+        "&Current (small warning icon)");
+    m_chkUseDisabled = CreateCheckBoxAndAddToSizer(sizerUseLabels,
+        "&Disabled (broken image icon)");
     sizerLeft->Add(sizerUseLabels, wxSizerFlags().Expand().Border());
 
     sizerLeft->AddSpacer(10);
@@ -300,14 +305,14 @@ void ButtonWidgetsPage::CreateContent()
 
 void ButtonWidgetsPage::Reset()
 {
-    m_chkBitmap->SetValue(false);
+    m_chkBitmapOnly->SetValue(false);
     m_chkFit->SetValue(true);
-    m_chkImage->SetValue(false);
+    m_chkTextAndBitmap->SetValue(false);
     m_chkDefault->SetValue(false);
 
-    m_chkUseSelected->SetValue(true);
+    m_chkUsePressed->SetValue(true);
     m_chkUseFocused->SetValue(true);
-    m_chkUseHover->SetValue(true);
+    m_chkUseCurrent->SetValue(true);
     m_chkUseDisabled->SetValue(true);
 
     m_radioImagePos->SetSelection(ButtonImagePos_Left);
@@ -376,17 +381,19 @@ void ButtonWidgetsPage::CreateButton()
             break;
     }
 
-    const bool isBitmapButton = m_chkBitmap->GetValue();
-    if ( isBitmapButton )
+    bool showsBitmap = false;
+    if ( m_chkBitmapOnly->GetValue() )
     {
+        showsBitmap = true;
+
         wxBitmapButton *bbtn = new wxBitmapButton(this, ButtonPage_Button,
                                                   CreateBitmap(_T("normal")));
-        if ( m_chkUseSelected->GetValue() )
-            bbtn->SetBitmapSelected(CreateBitmap(_T("pushed")));
+        if ( m_chkUsePressed->GetValue() )
+            bbtn->SetBitmapPressed(CreateBitmap(_T("pushed")));
         if ( m_chkUseFocused->GetValue() )
             bbtn->SetBitmapFocus(CreateBitmap(_T("focused")));
-        if ( m_chkUseHover->GetValue() )
-            bbtn->SetBitmapHover(CreateBitmap(_T("hover")));
+        if ( m_chkUseCurrent->GetValue() )
+            bbtn->SetBitmapCurrent(CreateBitmap(_T("hover")));
         if ( m_chkUseDisabled->GetValue() )
             bbtn->SetBitmapDisabled(CreateBitmap(_T("disabled")));
         m_button = bbtn;
@@ -398,13 +405,10 @@ void ButtonWidgetsPage::CreateButton()
                                 flags);
     }
 
-    m_chkUseSelected->Enable(isBitmapButton);
-    m_chkUseFocused->Enable(isBitmapButton);
-    m_chkUseHover->Enable(isBitmapButton);
-    m_chkUseDisabled->Enable(isBitmapButton);
-
-    if ( m_chkImage->GetValue() )
+    if ( !showsBitmap && m_chkTextAndBitmap->GetValue() )
     {
+        showsBitmap = true;
+
         static const wxDirection positions[] =
         {
             wxLEFT, wxRIGHT, wxTOP, wxBOTTOM
@@ -412,8 +416,22 @@ void ButtonWidgetsPage::CreateButton()
 
         m_button->SetBitmap(wxArtProvider::GetIcon(wxART_INFORMATION),
                             positions[m_radioImagePos->GetSelection()]);
+
+        if ( m_chkUsePressed->GetValue() )
+            m_button->SetBitmapPressed(wxArtProvider::GetIcon(wxART_HELP));
+        if ( m_chkUseFocused->GetValue() )
+            m_button->SetBitmapFocus(wxArtProvider::GetIcon(wxART_ERROR));
+        if ( m_chkUseCurrent->GetValue() )
+            m_button->SetBitmapCurrent(wxArtProvider::GetIcon(wxART_WARNING));
+        if ( m_chkUseDisabled->GetValue() )
+            m_button->SetBitmapDisabled(wxArtProvider::GetIcon(wxART_MISSING_IMAGE));
     }
 
+    m_chkUsePressed->Enable(showsBitmap);
+    m_chkUseFocused->Enable(showsBitmap);
+    m_chkUseCurrent->Enable(showsBitmap);
+    m_chkUseDisabled->Enable(showsBitmap);
+
     if ( m_chkDefault->GetValue() )
     {
         m_button->SetDefault();
index 2b0243b2495e11b717c5ab2ad6945cd3da00eb36..b17908b014a00939136b117f7988e3e7a3fbe466 100644 (file)
@@ -137,8 +137,10 @@ const int OD_BUTTON_MARGIN = 4;
 class wxODButtonImageData : public wxButtonImageData
 {
 public:
-    wxODButtonImageData(wxButton *btn)
+    wxODButtonImageData(wxButton *btn, const wxBitmap& bitmap)
     {
+        SetBitmap(bitmap, wxButton::State_Normal);
+
         m_dir = wxLEFT;
 
         m_margin.x = btn->GetCharWidth();
@@ -192,10 +194,17 @@ class wxXPButtonImageData : public wxButtonImageData
 public:
     // we must be constructed with the size of our images as we need to create
     // the image list
-    wxXPButtonImageData(wxButton *btn, const wxSize& size)
-        : m_iml(size.x, size.y, true /* use mask */, wxButton::State_Max),
+    wxXPButtonImageData(wxButton *btn, const wxBitmap& bitmap)
+        : m_iml(bitmap.GetWidth(), bitmap.GetHeight(), true /* use mask */,
+                wxButton::State_Max),
           m_hwndBtn(GetHwndOf(btn))
     {
+        // initialize all bitmaps to normal state
+        for ( int n = 0; n < wxButton::State_Max; n++ )
+        {
+            m_iml.Add(bitmap);
+        }
+
         m_data.himl = GetHimagelistOf(&m_iml);
 
         // use default margins
@@ -215,22 +224,7 @@ public:
 
     virtual void SetBitmap(const wxBitmap& bitmap, wxButton::State which)
     {
-        const int imagesToAdd = which - m_iml.GetImageCount();
-        if ( imagesToAdd >= 0 )
-        {
-            if ( imagesToAdd > 0 )
-            {
-                const wxBitmap bmpNormal = GetBitmap(wxButton::State_Normal);
-                for ( int n = 0; n < imagesToAdd; n++ )
-                    m_iml.Add(bmpNormal);
-            }
-
-            m_iml.Add(bitmap);
-        }
-        else // we already have this bitmap
-        {
-            m_iml.Replace(which, bitmap);
-        }
+        m_iml.Replace(which, bitmap);
 
         UpdateImageInfo();
     }
@@ -851,20 +845,23 @@ WXLRESULT wxButton::MSWWindowProc(WXUINT nMsg, WXWPARAM wParam, WXLPARAM lParam)
         // as the theme size might have changed
         InvalidateBestSize();
     }
-    else if ( wxUxThemeEngine::GetIfActive() )
+#endif // wxUSE_UXTHEME
+    // must use m_mouseInWindow here instead of IsMouseInWindow()
+    // since we need to know the first time the mouse enters the window
+    // and IsMouseInWindow() would return true in this case
+    else if ( (nMsg == WM_MOUSEMOVE && !m_mouseInWindow) ||
+                nMsg == WM_MOUSELEAVE )
     {
-        // we need to Refresh() if mouse has entered or left window
-        // so we can update the hot tracking state
-        // must use m_mouseInWindow here instead of IsMouseInWindow()
-        // since we need to know the first time the mouse enters the window
-        // and IsMouseInWindow() would return true in this case
-        if ( ( nMsg == WM_MOUSEMOVE && !m_mouseInWindow ) ||
-             nMsg == WM_MOUSELEAVE )
+        if (
+#if wxUSE_UXTHEME
+                wxUxThemeEngine::GetIfActive() ||
+#endif // wxUSE_UXTHEME
+                m_imageData && m_imageData->GetBitmap(State_Current).IsOk()
+           )
         {
             Refresh();
         }
     }
-#endif // wxUSE_UXTHEME
 
     // let the base class do all real processing
     return wxControl::MSWWindowProc(nMsg, wParam, lParam);
@@ -887,12 +884,12 @@ void wxButton::DoSetBitmap(const wxBitmap& bitmap, State which)
 #if wxUSE_UXTHEME
         if ( wxUxThemeEngine::GetIfActive() )
         {
-            m_imageData = new wxXPButtonImageData(this, bitmap.GetSize());
+            m_imageData = new wxXPButtonImageData(this, bitmap);
         }
         else
 #endif // wxUSE_UXTHEME
         {
-            m_imageData = new wxODButtonImageData(this);
+            m_imageData = new wxODButtonImageData(this, bitmap);
             MakeOwnerDrawn();
         }
 
@@ -900,8 +897,10 @@ void wxButton::DoSetBitmap(const wxBitmap& bitmap, State which)
         // changed to account for it
         InvalidateBestSize();
     }
-
-    m_imageData->SetBitmap(bitmap, which);
+    else
+    {
+        m_imageData->SetBitmap(bitmap, which);
+    }
 }
 
 void wxButton::DoSetBitmapMargins(wxCoord x, wxCoord y)
@@ -926,6 +925,25 @@ void wxButton::DoSetBitmapPosition(wxDirection dir)
 namespace
 {
 
+// return the button state using both the ODS_XXX flags specified in state
+// parameter and the current button state
+wxButton::State GetButtonState(wxButton *btn, UINT state)
+{
+    if ( state & ODS_DISABLED )
+        return wxButton::State_Disabled;
+
+    if ( state & ODS_SELECTED )
+        return wxButton::State_Pressed;
+
+    if ( btn->HasCapture() || btn->IsMouseInWindow() )
+        return wxButton::State_Current;
+
+    if ( state & ODS_FOCUS )
+        return wxButton::State_Focused;
+
+    return wxButton::State_Normal;
+}
+
 void DrawButtonText(HDC hdc,
                     RECT *pRect,
                     const wxString& text,
@@ -1064,48 +1082,40 @@ void DrawButtonFrame(HDC hdc, RECT& rectBtn,
 }
 
 #if wxUSE_UXTHEME
-void MSWDrawXPBackground(wxButton *button, HDC hdc, RECT& rectBtn, UINT state)
+void DrawXPBackground(wxButton *button, HDC hdc, RECT& rectBtn, UINT state)
 {
     wxUxThemeHandle theme(button, L"BUTTON");
-    int iState;
 
-    if ( state & ODS_SELECTED )
+    // this array is indexed by wxButton::State values and so must be kept in
+    // sync with it
+    static const uxStates[] =
     {
-        iState = PBS_PRESSED;
-    }
-    else if ( button->HasCapture() || button->IsMouseInWindow() )
-    {
-        iState = PBS_HOT;
-    }
-    else if ( state & ODS_FOCUS )
-    {
-        iState = PBS_DEFAULTED;
-    }
-    else if ( state & ODS_DISABLED )
-    {
-        iState = PBS_DISABLED;
-    }
-    else
-    {
-        iState = PBS_NORMAL;
-    }
+        PBS_NORMAL, PBS_HOT, PBS_PRESSED, PBS_DISABLED, PBS_DEFAULTED
+    };
+
+    int iState = uxStates[GetButtonState(button, state)];
+
+    wxUxThemeEngine * const engine = wxUxThemeEngine::Get();
 
     // draw parent background if needed
-    if ( wxUxThemeEngine::Get()->IsThemeBackgroundPartiallyTransparent(theme,
-                                                                       BP_PUSHBUTTON,
-                                                                       iState) )
+    if ( engine->IsThemeBackgroundPartiallyTransparent
+                 (
+                    theme,
+                    BP_PUSHBUTTON,
+                    iState
+                 ) )
     {
-        wxUxThemeEngine::Get()->DrawThemeParentBackground(GetHwndOf(button), hdc, &rectBtn);
+        engine->DrawThemeParentBackground(GetHwndOf(button), hdc, &rectBtn);
     }
 
     // draw background
-    wxUxThemeEngine::Get()->DrawThemeBackground(theme, hdc, BP_PUSHBUTTON, iState,
-                                                &rectBtn, NULL);
+    engine->DrawThemeBackground(theme, hdc, BP_PUSHBUTTON, iState,
+                                &rectBtn, NULL);
 
     // calculate content area margins
     MARGINS margins;
-    wxUxThemeEngine::Get()->GetThemeMargins(theme, hdc, BP_PUSHBUTTON, iState,
-                                            TMT_CONTENTMARGINS, &rectBtn, &margins);
+    engine->GetThemeMargins(theme, hdc, BP_PUSHBUTTON, iState,
+                            TMT_CONTENTMARGINS, &rectBtn, &margins);
     ::InflateRect(&rectBtn, -margins.cxLeftWidth, -margins.cyTopHeight);
 
     if ( button->UseBgCol() )
@@ -1184,7 +1194,7 @@ bool wxButton::MSWOnDraw(WXDRAWITEMSTRUCT *wxdis)
 #if wxUSE_UXTHEME
     if ( wxUxThemeEngine::GetIfActive() )
     {
-        MSWDrawXPBackground(this, hdc, rectBtn, state);
+        DrawXPBackground(this, hdc, rectBtn, state);
     }
     else
 #endif // wxUSE_UXTHEME
@@ -1231,7 +1241,10 @@ bool wxButton::MSWOnDraw(WXDRAWITEMSTRUCT *wxdis)
     // draw the image, if any
     if ( m_imageData )
     {
-        wxBitmap bmp = m_imageData->GetBitmap(State_Normal);
+        wxBitmap bmp = m_imageData->GetBitmap(GetButtonState(this, state));
+        if ( !bmp.IsOk() )
+            bmp = m_imageData->GetBitmap(State_Normal);
+
         const wxSize sizeBmp = bmp.GetSize();
         const wxSize margin = m_imageData->GetBitmapMargins();
         const wxSize sizeBmpWithMargins(sizeBmp + 2*margin);