]> git.saurik.com Git - wxWidgets.git/blobdiff - src/common/wincmn.cpp
In wxPopupFocusHandler, watch for EVT_CHAR, not EVT_KEY_DOWN.
[wxWidgets.git] / src / common / wincmn.cpp
index b337a659e4e41693d1ced64483f4e2b276ca3596..fdeecde22213c39396ba63c56681ab6372c2659d 100644 (file)
 #endif
 
 #include "wx/platinfo.h"
 #endif
 
 #include "wx/platinfo.h"
+#include "wx/private/window.h"
+
+#ifdef __WXMSW__
+    #include "wx/msw/wrapwin.h"
+#endif
 
 // Windows List
 WXDLLIMPEXP_DATA_CORE(wxWindowList) wxTopLevelWindows;
 
 // Windows List
 WXDLLIMPEXP_DATA_CORE(wxWindowList) wxTopLevelWindows;
@@ -213,9 +218,8 @@ wxWindowBase::wxWindowBase()
 bool wxWindowBase::CreateBase(wxWindowBase *parent,
                               wxWindowID id,
                               const wxPoint& WXUNUSED(pos),
 bool wxWindowBase::CreateBase(wxWindowBase *parent,
                               wxWindowID id,
                               const wxPoint& WXUNUSED(pos),
-                              const wxSize& WXUNUSED(size),
+                              const wxSize& size,
                               long style,
                               long style,
-                              const wxValidator& wxVALIDATOR_PARAM(validator),
                               const wxString& name)
 {
     // ids are limited to 16 bits under MSW so if you care about portability,
                               const wxString& name)
 {
     // ids are limited to 16 bits under MSW so if you care about portability,
@@ -240,9 +244,32 @@ bool wxWindowBase::CreateBase(wxWindowBase *parent,
     // flags by updating the window dynamically and we don't need this here
     m_windowStyle = style;
 
     // flags by updating the window dynamically and we don't need this here
     m_windowStyle = style;
 
+    // assume the user doesn't want this window to shrink beneath its initial
+    // size, this worked like this in wxWidgets 2.8 and before and generally
+    // often makes sense for child windows (for top level ones it definitely
+    // does not as the user should be able to resize the window)
+    //
+    // note that we can't use IsTopLevel() from ctor
+    if ( size != wxDefaultSize && !wxTopLevelWindows.Find((wxWindow *)this) )
+        SetMinSize(size);
+
     SetName(name);
     SetParent(parent);
 
     SetName(name);
     SetParent(parent);
 
+    return true;
+}
+
+bool wxWindowBase::CreateBase(wxWindowBase *parent,
+                              wxWindowID id,
+                              const wxPoint& pos,
+                              const wxSize& size,
+                              long style,
+                              const wxValidator& wxVALIDATOR_PARAM(validator),
+                              const wxString& name)
+{
+    if ( !CreateBase(parent, id, pos, size, style, name) )
+        return false;
+
 #if wxUSE_VALIDATORS
     SetValidator(validator);
 #endif // wxUSE_VALIDATORS
 #if wxUSE_VALIDATORS
     SetValidator(validator);
 #endif // wxUSE_VALIDATORS
@@ -300,6 +327,12 @@ wxWindowBase::~wxWindowBase()
     // we weren't a dialog class
     wxTopLevelWindows.DeleteObject((wxWindow*)this);
 
     // we weren't a dialog class
     wxTopLevelWindows.DeleteObject((wxWindow*)this);
 
+    // Any additional event handlers should be popped before the window is
+    // deleted as otherwise the last handler will be left with a dangling
+    // pointer to this window result in a difficult to diagnose crash later on.
+    wxASSERT_MSG( GetEventHandler() == this,
+                    wxT("any pushed event handlers must have been removed") );
+
 #if wxUSE_MENUS
     // The associated popup menu can still be alive, disassociate from it in
     // this case
 #if wxUSE_MENUS
     // The associated popup menu can still be alive, disassociate from it in
     // this case
@@ -474,7 +507,7 @@ static bool wxHasRealChildren(const wxWindowBase* win)
           node = node->GetNext() )
     {
         wxWindow *win = node->GetData();
           node = node->GetNext() )
     {
         wxWindow *win = node->GetData();
-        if ( !win->IsTopLevel() && win->IsShown() 
+        if ( !win->IsTopLevel() && win->IsShown()
 #if wxUSE_SCROLLBAR
             && !win->IsKindOf(CLASSINFO(wxScrollBar))
 #endif
 #if wxUSE_SCROLLBAR
             && !win->IsKindOf(CLASSINFO(wxScrollBar))
 #endif
@@ -593,19 +626,14 @@ wxSize wxWindowBase::DoGetBestSize() const
     }
     else // ! has children
     {
     }
     else // ! has children
     {
-        // for a generic window there is no natural best size so, if the
-        // minimal size is not set, use the current size but take care to
-        // remember it as minimal size for the next time because our best size
-        // should be constant: otherwise we could get into a situation when the
-        // window is initially at some size, then expanded to a larger size and
-        // then, when the containing window is shrunk back (because our initial
-        // best size had been used for computing the parent min size), we can't
-        // be shrunk back any more because our best size is now bigger
         wxSize size = GetMinSize();
         if ( !size.IsFullySpecified() )
         {
         wxSize size = GetMinSize();
         if ( !size.IsFullySpecified() )
         {
-            size.SetDefaults(GetSize());
-            wxConstCast(this, wxWindowBase)->SetMinSize(size);
+            // if the window doesn't define its best size we assume that it can
+            // be arbitrarily small -- usually this is not the case, of course,
+            // but we have no way to know what the limit is, it should really
+            // override DoGetBestClientSize() itself to tell us
+            size.SetDefaults(wxSize(1, 1));
         }
 
         // return as-is, unadjusted by the client size difference.
         }
 
         // return as-is, unadjusted by the client size difference.
@@ -707,6 +735,21 @@ wxSize wxWindowBase::GetEffectiveMinSize() const
     return min;
 }
 
     return min;
 }
 
+wxSize wxWindowBase::DoGetBorderSize() const
+{
+    // there is one case in which we can implement it for all ports easily:
+    // do it as some classes used by both wxUniv and native ports (e.g.
+    // wxGenericStaticText) do override DoGetBestClientSize() and so this
+    // method must work for them and that ensures that it does, at least in
+    // the default case)
+    if ( GetBorder() == wxBORDER_NONE )
+        return wxSize(0, 0);
+
+    wxFAIL_MSG( "must be overridden if called" );
+
+    return wxDefaultSize;
+}
+
 wxSize wxWindowBase::GetBestSize() const
 {
     if ( !m_windowSizer && m_bestSizeCache.IsFullySpecified() )
 wxSize wxWindowBase::GetBestSize() const
 {
     if ( !m_windowSizer && m_bestSizeCache.IsFullySpecified() )
@@ -896,6 +939,20 @@ void wxWindowBase::SendSizeEventToParent(int flags)
         parent->SendSizeEvent(flags);
 }
 
         parent->SendSizeEvent(flags);
 }
 
+bool wxWindowBase::HasScrollbar(int orient) const
+{
+    // if scrolling in the given direction is disabled, we can't have the
+    // corresponding scrollbar no matter what
+    if ( !CanScroll(orient) )
+        return false;
+
+    const wxSize sizeVirt = GetVirtualSize();
+    const wxSize sizeClient = GetClientSize();
+
+    return orient == wxHORIZONTAL ? sizeVirt.x > sizeClient.x
+                                  : sizeVirt.y > sizeClient.y;
+}
+
 // ----------------------------------------------------------------------------
 // show/hide/enable/disable the window
 // ----------------------------------------------------------------------------
 // ----------------------------------------------------------------------------
 // show/hide/enable/disable the window
 // ----------------------------------------------------------------------------
@@ -1218,7 +1275,7 @@ bool wxWindowBase::RemoveEventHandler(wxEvtHandler *handlerToRemove)
 
     // NOTE: the wxWindow event handler list is always terminated with "this" handler
     wxEvtHandler *handlerCur = GetEventHandler()->GetNextHandler();
 
     // NOTE: the wxWindow event handler list is always terminated with "this" handler
     wxEvtHandler *handlerCur = GetEventHandler()->GetNextHandler();
-    while ( handlerCur != this )
+    while ( handlerCur != this && handlerCur )
     {
         wxEvtHandler *handlerNext = handlerCur->GetNextHandler();
 
     {
         wxEvtHandler *handlerNext = handlerCur->GetNextHandler();
 
@@ -1313,7 +1370,7 @@ wxColour wxWindowBase::GetBackgroundColour() const
         wxColour colBg = GetDefaultAttributes().colBg;
 
         // we must return some valid colour to avoid redoing this every time
         wxColour colBg = GetDefaultAttributes().colBg;
 
         // we must return some valid colour to avoid redoing this every time
-        // and also to avoid surprizing the applications written for older
+        // and also to avoid surprising the applications written for older
         // wxWidgets versions where GetBackgroundColour() always returned
         // something -- so give them something even if it doesn't make sense
         // for this window (e.g. it has a themed background)
         // wxWidgets versions where GetBackgroundColour() always returned
         // something -- so give them something even if it doesn't make sense
         // for this window (e.g. it has a themed background)
@@ -2409,28 +2466,57 @@ void wxWindowBase::DoUpdateWindowUI(wxUpdateUIEvent& event)
 // dialog units translations
 // ----------------------------------------------------------------------------
 
 // dialog units translations
 // ----------------------------------------------------------------------------
 
-wxPoint wxWindowBase::ConvertPixelsToDialog(const wxPoint& pt)
+// 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.
+// It's important that we perform the conversion in identical way, because
+// dialog units natively exist only on Windows and Windows HIG is expressed
+// using them.
+wxSize wxWindowBase::GetDlgUnitBase() const
 {
 {
-    int charWidth = GetCharWidth();
-    int charHeight = GetCharHeight();
+    const wxWindow *parent = wxGetTopLevelParent((wxWindow*)this);
+
+    if ( !parent->m_font.IsOk() )
+    {
+        // Default GUI font is used. This is the most common case, so
+        // cache the results.
+        static wxSize s_defFontSize;
+        if ( s_defFontSize.x == 0 )
+            s_defFontSize = wxPrivate::GetAverageASCIILetterSize(*parent);
+        return s_defFontSize;
+    }
+    else
+    {
+        // Custom font, we always need to compute the result
+        return wxPrivate::GetAverageASCIILetterSize(*parent);
+    }
+}
+
+wxPoint wxWindowBase::ConvertPixelsToDialog(const wxPoint& pt) const
+{
+    const wxSize base = GetDlgUnitBase();
+
+    // NB: wxMulDivInt32() is used, because it correctly rounds the result
+
     wxPoint pt2 = wxDefaultPosition;
     if (pt.x != wxDefaultCoord)
     wxPoint pt2 = wxDefaultPosition;
     if (pt.x != wxDefaultCoord)
-        pt2.x = (int) ((pt.x * 4) / charWidth);
+        pt2.x = wxMulDivInt32(pt.x, 4, base.x);
     if (pt.y != wxDefaultCoord)
     if (pt.y != wxDefaultCoord)
-        pt2.y = (int) ((pt.y * 8) / charHeight);
+        pt2.y = wxMulDivInt32(pt.y, 8, base.y);
 
     return pt2;
 }
 
 
     return pt2;
 }
 
-wxPoint wxWindowBase::ConvertDialogToPixels(const wxPoint& pt)
+wxPoint wxWindowBase::ConvertDialogToPixels(const wxPoint& pt) const
 {
 {
-    int charWidth = GetCharWidth();
-    int charHeight = GetCharHeight();
+    const wxSize base = GetDlgUnitBase();
+
     wxPoint pt2 = wxDefaultPosition;
     if (pt.x != wxDefaultCoord)
     wxPoint pt2 = wxDefaultPosition;
     if (pt.x != wxDefaultCoord)
-        pt2.x = (int) ((pt.x * charWidth) / 4);
+        pt2.x = wxMulDivInt32(pt.x, base.x, 4);
     if (pt.y != wxDefaultCoord)
     if (pt.y != wxDefaultCoord)
-        pt2.y = (int) ((pt.y * charHeight) / 8);
+        pt2.y = wxMulDivInt32(pt.y, base.y, 8);
 
     return pt2;
 }
 
     return pt2;
 }
@@ -2440,7 +2526,7 @@ wxPoint wxWindowBase::ConvertDialogToPixels(const wxPoint& pt)
 // ----------------------------------------------------------------------------
 
 // propagate the colour change event to the subwindows
 // ----------------------------------------------------------------------------
 
 // propagate the colour change event to the subwindows
-void wxWindowBase::OnSysColourChanged(wxSysColourChangedEvent& event)
+void wxWindowBase::OnSysColourChanged(wxSysColourChangedEvent& WXUNUSED(event))
 {
     wxWindowList::compatibility_iterator node = GetChildren().GetFirst();
     while ( node )
 {
     wxWindowList::compatibility_iterator node = GetChildren().GetFirst();
     while ( node )
@@ -2450,7 +2536,7 @@ void wxWindowBase::OnSysColourChanged(wxSysColourChangedEvent& event)
         if ( !win->IsTopLevel() )
         {
             wxSysColourChangedEvent event2;
         if ( !win->IsTopLevel() )
         {
             wxSysColourChangedEvent event2;
-            event.SetEventObject(win);
+            event2.SetEventObject(win);
             win->GetEventHandler()->ProcessEvent(event2);
         }
 
             win->GetEventHandler()->ProcessEvent(event2);
         }
 
@@ -2544,8 +2630,11 @@ wxWindowBase::DoGetPopupMenuSelectionFromUser(wxMenu& menu, int x, int y)
 
 #endif // wxUSE_MENUS
 
 
 #endif // wxUSE_MENUS
 
-// methods for drawing the sizers in a visible way
-#ifdef __WXDEBUG__
+// methods for drawing the sizers in a visible way: this is currently only
+// enabled for "full debug" builds with wxDEBUG_LEVEL==2 as it doesn't work
+// that well and also because we don't want to leave it enabled in default
+// builds used for production
+#if wxDEBUG_LEVEL > 1
 
 static void DrawSizers(wxWindowBase *win);
 
 
 static void DrawSizers(wxWindowBase *win);
 
@@ -2627,22 +2716,25 @@ static void DrawSizers(wxWindowBase *win)
     }
 }
 
     }
 }
 
-#endif // __WXDEBUG__
+#endif // wxDEBUG_LEVEL
 
 // process special middle clicks
 void wxWindowBase::OnMiddleClick( wxMouseEvent& event )
 {
     if ( event.ControlDown() && event.AltDown() )
     {
 
 // process special middle clicks
 void wxWindowBase::OnMiddleClick( wxMouseEvent& event )
 {
     if ( event.ControlDown() && event.AltDown() )
     {
-#ifdef __WXDEBUG__
+#if wxDEBUG_LEVEL > 1
         // Ctrl-Alt-Shift-mclick makes the sizers visible in debug builds
         if ( event.ShiftDown() )
         {
             DrawSizers(this);
         // Ctrl-Alt-Shift-mclick makes the sizers visible in debug builds
         if ( event.ShiftDown() )
         {
             DrawSizers(this);
-            return;
         }
         }
+        else
 #endif // __WXDEBUG__
 #endif // __WXDEBUG__
-        ::wxInfoMessageBox((wxWindow*)this);
+        {
+            // just Ctrl-Alt-middle click shows information about wx version
+            ::wxInfoMessageBox((wxWindow*)this);
+        }
     }
     else
     {
     }
     else
     {