]> git.saurik.com Git - wxWidgets.git/blobdiff - src/msw/button.cpp
Add support for IEC and SI size units to wxFileName::GetHumanReadableSize().
[wxWidgets.git] / src / msw / button.cpp
index c81472bebc848e2dffde05228bb7419dece9f7eb..407981a03a3061dc0a9de3ebc684ed6649df9c2f 100644 (file)
     #include "wx/dcscreen.h"
     #include "wx/dcclient.h"
     #include "wx/toplevel.h"
     #include "wx/dcscreen.h"
     #include "wx/dcclient.h"
     #include "wx/toplevel.h"
-    #include "wx/imaglist.h"
 #endif
 
 #endif
 
+#include "wx/imaglist.h"
 #include "wx/stockitem.h"
 #include "wx/msw/private.h"
 #include "wx/msw/private/button.h"
 #include "wx/msw/private/dc.h"
 #include "wx/stockitem.h"
 #include "wx/msw/private.h"
 #include "wx/msw/private/button.h"
 #include "wx/msw/private/dc.h"
+#include "wx/private/window.h"
 
 using namespace wxMSWImpl;
 
 
 using namespace wxMSWImpl;
 
@@ -102,6 +103,12 @@ using namespace wxMSWImpl;
     #define DT_HIDEPREFIX       0x00100000
 #endif
 
     #define DT_HIDEPREFIX       0x00100000
 #endif
 
+// set the value for BCM_SETSHIELD (for the UAC shield) if it's not defined in
+// the header
+#ifndef BCM_SETSHIELD
+    #define BCM_SETSHIELD       0x160c
+#endif
+
 // ----------------------------------------------------------------------------
 // button image data
 // ----------------------------------------------------------------------------
 // ----------------------------------------------------------------------------
 // button image data
 // ----------------------------------------------------------------------------
@@ -432,7 +439,9 @@ void wxMSWButton::UpdateMultilineStyle(HWND hwnd, const wxString& label)
         ::SetWindowLong(hwnd, GWL_STYLE, styleNew);
 }
 
         ::SetWindowLong(hwnd, GWL_STYLE, styleNew);
 }
 
-wxSize wxMSWButton::GetFittingSize(wxWindow *win, const wxSize& sizeLabel)
+wxSize wxMSWButton::GetFittingSize(wxWindow *win,
+                                   const wxSize& sizeLabel,
+                                   int flags)
 {
     // FIXME: this is pure guesswork, need to retrieve the real button margins
     wxSize sizeBtn = sizeLabel;
 {
     // FIXME: this is pure guesswork, need to retrieve the real button margins
     wxSize sizeBtn = sizeLabel;
@@ -440,24 +449,31 @@ wxSize wxMSWButton::GetFittingSize(wxWindow *win, const wxSize& sizeLabel)
     sizeBtn.x += 3*win->GetCharWidth();
     sizeBtn.y = 11*EDIT_HEIGHT_FROM_CHAR_HEIGHT(sizeLabel.y)/10;
 
     sizeBtn.x += 3*win->GetCharWidth();
     sizeBtn.y = 11*EDIT_HEIGHT_FROM_CHAR_HEIGHT(sizeLabel.y)/10;
 
+    // account for the shield UAC icon if we have it
+    if ( flags & Size_AuthNeeded )
+        sizeBtn.x += wxSystemSettings::GetMetric(wxSYS_SMALLICON_X);
+
     return sizeBtn;
 }
 
     return sizeBtn;
 }
 
-wxSize wxMSWButton::ComputeBestSize(wxControl *btn)
+wxSize wxMSWButton::ComputeBestSize(wxControl *btn, int flags)
 {
     wxClientDC dc(btn);
 
     wxSize sizeBtn;
     dc.GetMultiLineTextExtent(btn->GetLabelText(), &sizeBtn.x, &sizeBtn.y);
 
 {
     wxClientDC dc(btn);
 
     wxSize sizeBtn;
     dc.GetMultiLineTextExtent(btn->GetLabelText(), &sizeBtn.x, &sizeBtn.y);
 
-    sizeBtn = GetFittingSize(btn, sizeBtn);
+    sizeBtn = GetFittingSize(btn, sizeBtn, flags);
 
     // all buttons have at least the standard size unless the user explicitly
     // wants them to be of smaller size and used wxBU_EXACTFIT style when
     // creating the button
     if ( !btn->HasFlag(wxBU_EXACTFIT) )
     {
 
     // all buttons have at least the standard size unless the user explicitly
     // wants them to be of smaller size and used wxBU_EXACTFIT style when
     // creating the button
     if ( !btn->HasFlag(wxBU_EXACTFIT) )
     {
-        wxSize sizeDef = wxButton::GetDefaultSize();
+        // The size of a standard button in the dialog units is 50x14, use it.
+        // Note that we intentionally don't use GetDefaultSize() here, because
+        // it's inexact -- dialog units depend on this dialog's font.
+        wxSize sizeDef = btn->ConvertDialogToPixels(wxSize(50, 14));
         if ( sizeBtn.x < sizeDef.x )
             sizeBtn.x = sizeDef.x;
         if ( sizeBtn.y < sizeDef.y )
         if ( sizeBtn.x < sizeDef.x )
             sizeBtn.x = sizeDef.x;
         if ( sizeBtn.y < sizeDef.y )
@@ -482,6 +498,8 @@ bool wxButton::Create(wxWindow *parent,
                       const wxValidator& validator,
                       const wxString& name)
 {
                       const wxValidator& validator,
                       const wxString& name)
 {
+    m_authNeeded = false;
+
     wxString label(lbl);
     if (label.empty() && wxIsStockID(id))
     {
     wxString label(lbl);
     if (label.empty() && wxIsStockID(id))
     {
@@ -574,10 +592,16 @@ wxSize wxButton::DoGetBestSize() const
 {
     wxSize size;
 
 {
     wxSize size;
 
-    // account for the text part
-    if ( ShowsLabel() )
+    // account for the text part if we have it or if we don't have any image at
+    // all (buttons initially created with empty label should still have a non
+    // zero size)
+    if ( ShowsLabel() || !m_imageData )
     {
     {
-        size = wxMSWButton::ComputeBestSize(const_cast<wxButton *>(this));
+        int flags = 0;
+        if ( GetAuthNeeded() )
+            flags |= wxMSWButton::Size_AuthNeeded;
+
+        size = wxMSWButton::ComputeBestSize(const_cast<wxButton *>(this), flags);
     }
 
     if ( m_imageData )
     }
 
     if ( m_imageData )
@@ -657,16 +681,20 @@ wxSize wxButtonBase::GetDefaultSize()
         wxScreenDC dc;
         dc.SetFont(wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT));
 
         wxScreenDC dc;
         dc.SetFont(wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT));
 
-        // the size of a standard button in the dialog units is 50x14,
-        // translate this to pixels
-        // NB1: the multipliers come from the Windows convention
-        // NB2: the extra +1/+2 were needed to get the size be the same as the
-        //      size of the buttons in the standard dialog - I don't know how
-        //      this happens, but on my system this size is 75x23 in pixels and
-        //      23*8 isn't even divisible by 14... Would be nice to understand
-        //      why these constants are needed though!
-        s_sizeBtn.x = (50 * (dc.GetCharWidth() + 1))/4;
-        s_sizeBtn.y = ((14 * dc.GetCharHeight()) + 2)/8;
+        // The size of a standard button in the dialog units is 50x14,
+        // translate this to pixels.
+        //
+        // Windows' computes dialog units using average character width over
+        // upper- and lower-case ASCII alphabet and not using the average
+        // character width metadata stored in the font; see
+        // http://support.microsoft.com/default.aspx/kb/145994 for detailed
+        // discussion.
+        //
+        // NB: wxMulDivInt32() is used, because it correctly rounds the result
+
+        const wxSize base = wxPrivate::GetAverageASCIILetterSize(dc);
+        s_sizeBtn.x = wxMulDivInt32(50, base.x, 4);
+        s_sizeBtn.y = wxMulDivInt32(14, base.y, 8);
     }
 
     return s_sizeBtn;
     }
 
     return s_sizeBtn;
@@ -677,6 +705,14 @@ wxSize wxButtonBase::GetDefaultSize()
 // ----------------------------------------------------------------------------
 
 /*
 // ----------------------------------------------------------------------------
 
 /*
+   The comment below and all this code is probably due to not using WM_NEXTDLGCTL
+   message when changing focus (but just SetFocus() which is not enough), see
+   http://blogs.msdn.com/oldnewthing/archive/2004/08/02/205624.aspx for the
+   full explanation.
+
+   TODO: Do use WM_NEXTDLGCTL and get rid of all this code.
+
+
    "Everything you ever wanted to know about the default buttons" or "Why do we
    have to do all this?"
 
    "Everything you ever wanted to know about the default buttons" or "Why do we
    have to do all this?"
 
@@ -918,7 +954,7 @@ WXLRESULT wxButton::MSWWindowProc(WXUINT nMsg, WXWPARAM wParam, WXLPARAM lParam)
 #if wxUSE_UXTHEME
                 wxUxThemeEngine::GetIfActive() ||
 #endif // wxUSE_UXTHEME
 #if wxUSE_UXTHEME
                 wxUxThemeEngine::GetIfActive() ||
 #endif // wxUSE_UXTHEME
-                m_imageData && m_imageData->GetBitmap(State_Current).IsOk()
+                 (m_imageData && m_imageData->GetBitmap(State_Current).IsOk())
                 )
            )
         {
                 )
            )
         {
@@ -930,6 +966,26 @@ WXLRESULT wxButton::MSWWindowProc(WXUINT nMsg, WXWPARAM wParam, WXLPARAM lParam)
     return wxControl::MSWWindowProc(nMsg, wParam, lParam);
 }
 
     return wxControl::MSWWindowProc(nMsg, wParam, lParam);
 }
 
+// ----------------------------------------------------------------------------
+// authentication needed handling
+// ----------------------------------------------------------------------------
+
+bool wxButton::DoGetAuthNeeded() const
+{
+    return m_authNeeded;
+}
+
+void wxButton::DoSetAuthNeeded(bool show)
+{
+    // show/hide UAC symbol on Windows Vista and later
+    if ( wxGetWinVersion() >= wxWinVersion_6 )
+    {
+        m_authNeeded = show;
+        ::SendMessage(GetHwnd(), BCM_SETSHIELD, 0, show);
+        InvalidateBestSize();
+    }
+}
+
 // ----------------------------------------------------------------------------
 // button images
 // ----------------------------------------------------------------------------
 // ----------------------------------------------------------------------------
 // button images
 // ----------------------------------------------------------------------------
@@ -984,6 +1040,7 @@ void wxButton::DoSetBitmapMargins(wxCoord x, wxCoord y)
     wxCHECK_RET( m_imageData, "SetBitmap() must be called first" );
 
     m_imageData->SetBitmapMargins(x, y);
     wxCHECK_RET( m_imageData, "SetBitmap() must be called first" );
 
     m_imageData->SetBitmapMargins(x, y);
+    InvalidateBestSize();
 }
 
 void wxButton::DoSetBitmapPosition(wxDirection dir)
 }
 
 void wxButton::DoSetBitmapPosition(wxDirection dir)
@@ -991,6 +1048,7 @@ void wxButton::DoSetBitmapPosition(wxDirection dir)
     wxCHECK_RET( m_imageData, "SetBitmap() must be called first" );
 
     m_imageData->SetBitmapPosition(dir);
     wxCHECK_RET( m_imageData, "SetBitmap() must be called first" );
 
     m_imageData->SetBitmapPosition(dir);
+    InvalidateBestSize();
 }
 
 // ----------------------------------------------------------------------------
 }
 
 // ----------------------------------------------------------------------------