]> git.saurik.com Git - wxWidgets.git/blobdiff - src/common/wincmn.cpp
Correct signature of HitTest()
[wxWidgets.git] / src / common / wincmn.cpp
index 62995e54a8acd02bead9e767d983e7a8a0852f16..a48533d9689d1448a0e2811879f689ea18e4902a 100644 (file)
@@ -83,6 +83,8 @@
     extern const unsigned int gtk_micro_version;
 #endif
 
+#include "wx/platinfo.h"
+
 // Windows List
 WXDLLIMPEXP_DATA_CORE(wxWindowList) wxTopLevelWindows;
 
@@ -198,6 +200,8 @@ wxWindowBase::wxWindowBase()
 
     m_virtualSize = wxDefaultSize;
 
+    m_scrollHelper = (wxScrollHelper *) NULL;
+
     m_minVirtualWidth =
     m_maxVirtualWidth = wxDefaultCoord;
     m_minVirtualHeight =
@@ -247,8 +251,12 @@ bool wxWindowBase::CreateBase(wxWindowBase *parent,
     // generate a new id if the user doesn't care about it
     m_windowId = id == wxID_ANY ? NewControlId() : id;
 
+    // don't use SetWindowStyleFlag() here, this function should only be called
+    // to change the flag after creation as it tries to reflect the changes in
+    // flags by updating the window dynamically and we don't need this here
+    m_windowStyle = style;
+
     SetName(name);
-    SetWindowStyleFlag(style);
     SetParent(parent);
 
 #if wxUSE_VALIDATORS
@@ -266,6 +274,28 @@ bool wxWindowBase::CreateBase(wxWindowBase *parent,
     return true;
 }
 
+bool wxWindowBase::ToggleWindowStyle(int flag)
+{
+    wxASSERT_MSG( flag, _T("flags with 0 value can't be toggled") );
+
+    bool rc;
+    long style = GetWindowStyleFlag();
+    if ( style & flag )
+    {
+        style &= ~flag;
+        rc = false;
+    }
+    else // currently off
+    {
+        style |= flag;
+        rc = true;
+    }
+
+    SetWindowStyleFlag(style);
+
+    return rc;
+}
+
 // ----------------------------------------------------------------------------
 // destruction
 // ----------------------------------------------------------------------------
@@ -288,11 +318,9 @@ wxWindowBase::~wxWindowBase()
 
     wxASSERT_MSG( GetChildren().GetCount() == 0, wxT("children not destroyed") );
 
-    // reset the dangling pointer our parent window may keep to us
+    // notify the parent about this window destruction
     if ( m_parent )
-    {
         m_parent->RemoveChild(this);
-    }
 
 #if wxUSE_CARET
     delete m_caret;
@@ -335,6 +363,14 @@ wxWindowBase::~wxWindowBase()
 #endif
 }
 
+void wxWindowBase::SendDestroyEvent()
+{
+    wxWindowDestroyEvent event;
+    event.SetEventObject(this);
+    event.SetId(GetId());
+    GetEventHandler()->ProcessEvent(event);
+}
+
 bool wxWindowBase::Destroy()
 {
     delete this;
@@ -396,7 +432,7 @@ void wxWindowBase::Fit()
 {
     if ( !GetChildren().empty() )
     {
-        SetClientSize(GetBestSize());
+        SetSize(GetBestSize());
     }
     //else: do nothing if we have no children
 }
@@ -447,7 +483,7 @@ wxSize wxWindowBase::DoGetBestSize() const
 
     if ( m_windowSizer )
     {
-        best = GetWindowSizeForVirtualSize(m_windowSizer->GetMinSize());
+        best = m_windowSizer->GetMinSize();
     }
 #if wxUSE_CONSTRAINTS
     else if ( m_constraints )
@@ -563,8 +599,78 @@ wxSize wxWindowBase::DoGetBestSize() const
     return best;
 }
 
+// helper of GetWindowBorderSize(): as many ports don't implement support for
+// wxSYS_BORDER/EDGE_X/Y metrics in their wxSystemSettings, use hard coded
+// fallbacks in this case
+static int wxGetMetricOrDefault(wxSystemMetric what)
+{
+    int rc = wxSystemSettings::GetMetric(what);
+    if ( rc == -1 )
+    {
+        switch ( what )
+        {
+            case wxSYS_BORDER_X:
+            case wxSYS_BORDER_Y:
+                // 2D border is by default 1 pixel wide
+                rc = 1;
+                break;
+
+            case wxSYS_EDGE_X:
+            case wxSYS_EDGE_Y:
+                // 3D borders are by default 2 pixels
+                rc = 2;
+                break;
+
+            default:
+                wxFAIL_MSG( _T("unexpected wxGetMetricOrDefault() argument") );
+                rc = 0;
+        }
+    }
+
+    return rc;
+}
 
-wxSize wxWindowBase::GetBestFittingSize() const
+wxSize wxWindowBase::GetWindowBorderSize() const
+{
+    wxSize size;
+
+    switch ( GetBorder() )
+    {
+        case wxBORDER_NONE:
+            // nothing to do, size is already (0, 0)
+            break;
+
+        case wxBORDER_SIMPLE:
+        case wxBORDER_STATIC:
+            size.x = wxGetMetricOrDefault(wxSYS_BORDER_X);
+            size.y = wxGetMetricOrDefault(wxSYS_BORDER_Y);
+            break;
+
+        case wxBORDER_SUNKEN:
+        case wxBORDER_RAISED:
+            size.x = wxMax(wxGetMetricOrDefault(wxSYS_EDGE_X),
+                           wxGetMetricOrDefault(wxSYS_BORDER_X));
+            size.y = wxMax(wxGetMetricOrDefault(wxSYS_EDGE_Y),
+                           wxGetMetricOrDefault(wxSYS_BORDER_Y));
+            break;
+
+        case wxBORDER_DOUBLE:
+            size.x = wxGetMetricOrDefault(wxSYS_EDGE_X) +
+                        wxGetMetricOrDefault(wxSYS_BORDER_X);
+            size.y = wxGetMetricOrDefault(wxSYS_EDGE_Y) +
+                        wxGetMetricOrDefault(wxSYS_BORDER_Y);
+            break;
+
+        default:
+            wxFAIL_MSG(_T("Unknown border style."));
+            break;
+    }
+
+    // we have borders on both sides
+    return size*2;
+}
+
+wxSize wxWindowBase::GetEffectiveMinSize() const
 {
     // merge the best size with the min size, giving priority to the min size
     wxSize min = GetMinSize();
@@ -578,14 +684,14 @@ wxSize wxWindowBase::GetBestFittingSize() const
 }
 
 
-void wxWindowBase::SetBestFittingSize(const wxSize& size)
+void wxWindowBase::SetInitialSize(const wxSize& size)
 {
     // Set the min size to the size passed in.  This will usually either be
     // wxDefaultSize or the size passed to this window's ctor/Create function.
     SetMinSize(size);
 
     // Merge the size with the best size if needed
-    wxSize best = GetBestFittingSize();
+    wxSize best = GetEffectiveMinSize();
 
     // If the current size doesn't match then change it
     if (GetSize() != best)
@@ -599,23 +705,6 @@ wxPoint wxWindowBase::GetClientAreaOrigin() const
     return wxPoint(0,0);
 }
 
-// set the min/max size of the window
-void wxWindowBase::DoSetSizeHints(int minW, int minH,
-                                  int maxW, int maxH,
-                                  int WXUNUSED(incW), int WXUNUSED(incH))
-{
-    // setting min width greater than max width leads to infinite loops under
-    // X11 and generally doesn't make any sense, so don't allow it
-    wxCHECK_RET( (minW == wxDefaultCoord || maxW == wxDefaultCoord || minW <= maxW) &&
-                    (minH == wxDefaultCoord || maxH == wxDefaultCoord || minH <= maxH),
-                 _T("min width/height must be less than max width/height!") );
-
-    m_minWidth = minW;
-    m_maxWidth = maxW;
-    m_minHeight = minH;
-    m_maxHeight = maxH;
-}
-
 void wxWindowBase::SetWindowVariant( wxWindowVariant variant )
 {
     if ( m_windowVariant != variant )
@@ -661,6 +750,21 @@ void wxWindowBase::DoSetWindowVariant( wxWindowVariant variant )
     SetFont(font);
 }
 
+void wxWindowBase::DoSetSizeHints( int minW, int minH,
+                                   int maxW, int maxH,
+                                   int WXUNUSED(incW), int WXUNUSED(incH) )
+{
+    wxCHECK_RET( (minW == wxDefaultCoord || maxW == wxDefaultCoord || minW <= maxW) &&
+                    (minH == wxDefaultCoord || maxH == wxDefaultCoord || minH <= maxH),
+                 _T("min width/height must be less than max width/height!") );
+
+    m_minWidth = minW;
+    m_maxWidth = maxW;
+    m_minHeight = minH;
+    m_maxHeight = maxH;
+}
+
+
 void wxWindowBase::SetVirtualSizeHints( int minW, int minH,
                                         int maxW, int maxH )
 {
@@ -729,19 +833,63 @@ bool wxWindowBase::Show(bool show)
     }
 }
 
-bool wxWindowBase::Enable(bool enable)
+bool wxWindowBase::IsEnabled() const
 {
-    if ( enable != m_isEnabled )
-    {
-        m_isEnabled = enable;
+    return IsThisEnabled() && (IsTopLevel() || !GetParent() || GetParent()->IsEnabled());
+}
 
-        return true;
-    }
-    else
+void wxWindowBase::NotifyWindowOnEnableChange(bool enabled)
+{
+#ifndef wxHAS_NATIVE_ENABLED_MANAGEMENT
+    DoEnable(enabled);
+#endif // !defined(wxHAS_NATIVE_ENABLED_MANAGEMENT)
+
+    OnEnabled(enabled);
+
+    // If we are top-level then the logic doesn't apply - otherwise
+    // showing a modal dialog would result in total greying out (and ungreying
+    // out later) of everything which would be really ugly
+    if ( IsTopLevel() )
+        return;
+
+    for ( wxWindowList::compatibility_iterator node = GetChildren().GetFirst();
+          node;
+          node = node->GetNext() )
     {
+        wxWindowBase * const child = node->GetData();
+        if ( !child->IsTopLevel() && child->IsThisEnabled() )
+            child->NotifyWindowOnEnableChange(enabled);
+    }
+}
+
+bool wxWindowBase::Enable(bool enable)
+{
+    if ( enable == IsThisEnabled() )
         return false;
+
+    m_isEnabled = enable;
+
+#ifdef wxHAS_NATIVE_ENABLED_MANAGEMENT
+    DoEnable(enable);
+#else // !defined(wxHAS_NATIVE_ENABLED_MANAGEMENT)
+    wxWindowBase * const parent = GetParent();
+    if( !IsTopLevel() && parent && !parent->IsEnabled() )
+    {
+        return true;
     }
+#endif // !defined(wxHAS_NATIVE_ENABLED_MANAGEMENT)
+
+    NotifyWindowOnEnableChange(enable);
+
+    return true;
+}
+
+bool wxWindowBase::IsShownOnScreen() const
+{
+    return IsShown() &&
+           (GetParent() == NULL || GetParent()->IsShownOnScreen());
 }
+
 // ----------------------------------------------------------------------------
 // RTTI
 // ----------------------------------------------------------------------------
@@ -785,6 +933,8 @@ bool wxWindowBase::Reparent(wxWindowBase *newParent)
         return false;
     }
 
+    const bool oldEnabledState = IsEnabled();
+
     // unlink this window from the existing parent.
     if ( oldParent )
     {
@@ -805,6 +955,14 @@ bool wxWindowBase::Reparent(wxWindowBase *newParent)
         wxTopLevelWindows.Append((wxWindow *)this);
     }
 
+    // We need to notify window (and its subwindows) if by changing the parent
+    // we also change our enabled/disabled status.
+    const bool newEnabledState = IsEnabled();
+    if ( newEnabledState != oldEnabledState )
+    {
+        NotifyWindowOnEnableChange(newEnabledState);
+    }
+
     return true;
 }
 
@@ -1017,7 +1175,7 @@ bool wxWindowBase::SetCursor(const wxCursor& cursor)
 {
     // setting an invalid cursor is ok, it means that we don't have any special
     // cursor
-    if ( m_cursor == cursor )
+    if ( m_cursor.IsSameAs(cursor) )
     {
         // no change
         return false;
@@ -1138,12 +1296,12 @@ wxRect wxWindowBase::GetUpdateClientRect() const
     return rectUpdate;
 }
 
-bool wxWindowBase::IsExposed(int x, int y) const
+bool wxWindowBase::DoIsExposed(int x, int y) const
 {
     return m_updateRegion.Contains(x, y) != wxOutRegion;
 }
 
-bool wxWindowBase::IsExposed(int x, int y, int w, int h) const
+bool wxWindowBase::DoIsExposed(int x, int y, int w, int h) const
 {
     return m_updateRegion.Contains(x, y, w, h) != wxOutRegion;
 }
@@ -1495,7 +1653,7 @@ void wxWindowBase::OnHelp(wxHelpEvent& event)
 #endif // wxUSE_HELP
 
 // ----------------------------------------------------------------------------
-// tooltipsroot.Replace("\\", "/");
+// tooltips
 // ----------------------------------------------------------------------------
 
 #if wxUSE_TOOLTIPS
@@ -1648,12 +1806,21 @@ void wxWindowBase::SetSizer(wxSizer *sizer, bool deleteOld)
     if ( sizer == m_windowSizer)
         return;
 
-    if ( deleteOld )
-        delete m_windowSizer;
+    if ( m_windowSizer )
+    {
+        m_windowSizer->SetContainingWindow(NULL);
+
+        if ( deleteOld )
+            delete m_windowSizer;
+    }
 
     m_windowSizer = sizer;
+    if ( m_windowSizer )
+    {
+        m_windowSizer->SetContainingWindow((wxWindow *)this);
+    }
 
-    SetAutoLayout( sizer != NULL );
+    SetAutoLayout(m_windowSizer != NULL);
 }
 
 void wxWindowBase::SetSizerAndFit(wxSizer *sizer, bool deleteOld)
@@ -1970,7 +2137,7 @@ void wxWindowBase::AdjustForParentClientOrigin(int& x, int& y, int sizeFlags) co
 }
 
 // ----------------------------------------------------------------------------
-// do Update UI processing for child controls
+// Update UI processing
 // ----------------------------------------------------------------------------
 
 void wxWindowBase::UpdateWindowUI(long flags)
@@ -2005,23 +2172,6 @@ void wxWindowBase::DoUpdateWindowUI(wxUpdateUIEvent& event)
         Show(event.GetShown());
 }
 
-#if 0
-// call internal idle recursively
-// may be obsolete (wait until OnIdle scheme stabilises)
-void wxWindowBase::ProcessInternalIdle()
-{
-    OnInternalIdle();
-
-    wxWindowList::compatibility_iterator node = GetChildren().GetFirst();
-    while (node)
-    {
-        wxWindow *child = node->GetData();
-        child->ProcessInternalIdle();
-        node = node->GetNext();
-    }
-}
-#endif
-
 // ----------------------------------------------------------------------------
 // dialog units translations
 // ----------------------------------------------------------------------------
@@ -2164,74 +2314,43 @@ void wxWindowBase::OnMiddleClick( wxMouseEvent& event )
 #endif // __WXDEBUG__
 
 #if wxUSE_MSGDLG
-        // don't translate these strings
-        wxString port;
-
-#ifdef __WXUNIVERSAL__
-        port = _T("Univ/");
-#endif // __WXUNIVERSAL__
-
-        switch ( wxGetOsVersion() )
-        {
-            case wxMOTIF_X:            port += _T("Motif"); break;
-            case wxMAC:
-            case wxMAC_DARWIN:         port += _T("Mac"); break;
-            case wxBEOS:               port += _T("BeOS"); break;
-            case wxGTK:
-            case wxGTK_WIN32:
-            case wxGTK_OS2:
-            case wxGTK_BEOS:           port += _T("GTK"); break;
-            case wxWINDOWS:
-            case wxPENWINDOWS:
-            case wxWINDOWS_NT:
-            case wxWIN32S:
-            case wxWIN95:
-            case wxWIN386:             port += _T("MS Windows"); break;
-            case wxMGL_UNIX:
-            case wxMGL_X:
-            case wxMGL_WIN32:
-            case wxMGL_OS2:            port += _T("MGL"); break;
-            case wxWINDOWS_OS2:
-            case wxOS2_PM:             port += _T("OS/2"); break;
-            case wxPALMOS:             port += _T("Palm OS"); break;
-            case wxWINDOWS_CE:         port += _T("Windows CE (generic)"); break;
-            case wxWINDOWS_POCKETPC:   port += _T("Windows CE PocketPC"); break;
-            case wxWINDOWS_SMARTPHONE: port += _T("Windows CE Smartphone"); break;
-            default:            port += _T("unknown"); break;
-        }
-
-        wxMessageBox(wxString::Format(
-                                      _T(
-                                        "       wxWidgets Library (%s port)\nVersion %d.%d.%d%s%s, compiled at %s %s%s\n   Copyright (c) 1995-2006 wxWidgets team"
-                                        ),
-                                      port.c_str(),
-                                      wxMAJOR_VERSION,
-                                      wxMINOR_VERSION,
-                                      wxRELEASE_NUMBER,
+        // don't translate these strings, they're for diagnostics purposes only
+        wxString msg;
+        msg.Printf(_T("wxWidgets Library (%s port)\n")
+                   _T("Version %d.%d.%d%s%s, compiled at %s %s\n")
+                   _T("Runtime version of toolkit used is %d.%d.%s\n")
+                   _T("Copyright (c) 1995-2007 wxWidgets team"),
+                   wxPlatformInfo::Get().GetPortIdName().c_str(),
+                   wxMAJOR_VERSION,
+                   wxMINOR_VERSION,
+                   wxRELEASE_NUMBER,
 #if wxUSE_UNICODE
-                                      L" (Unicode)",
+                   L" (Unicode)",
 #else
-                                      "",
+                   wxEmptyString,
 #endif
 #ifdef __WXDEBUG__
-                                      _T(" Debug build"),
+                   _T(" Debug build"),
 #else
-                                      wxEmptyString,
+                   wxEmptyString,
 #endif
-                                      __TDATE__,
-                                      __TTIME__,
+                   __TDATE__,
+                   __TTIME__,
+                   wxPlatformInfo::Get().GetToolkitMajorVersion(),
+                   wxPlatformInfo::Get().GetToolkitMinorVersion(),
 #ifdef __WXGTK__
-                                      wxString::Format(_T("\nagainst GTK+ %d.%d.%d. Runtime GTK+ version: %d.%d.%d"), GTK_MAJOR_VERSION, GTK_MINOR_VERSION, GTK_MICRO_VERSION, gtk_major_version, gtk_minor_version, gtk_micro_version).c_str()
+                   wxString::Format(_T("\nThe compile-time GTK+ version is %d.%d.%d."), GTK_MAJOR_VERSION, GTK_MINOR_VERSION, GTK_MICRO_VERSION).c_str()
 #else
-                                      ""
+                   wxEmptyString
 #endif
-                                     ),
-                     _T("wxWidgets information"),
+                   );
+
+        wxMessageBox(msg, _T("wxWidgets information"),
                      wxICON_INFORMATION | wxOK,
                      (wxWindow *)this);
+#endif // wxUSE_MSGDLG
     }
     else
-#endif // wxUSE_MSGDLG
     {
         event.Skip();
     }
@@ -2276,14 +2395,14 @@ wxAccessible* wxWindowBase::CreateAccessible()
 #include "wx/listimpl.cpp"
 WX_DEFINE_LIST(wxWindowList)
 
-#else
+#else // !wxUSE_STL
 
 void wxWindowListNode::DeleteData()
 {
     delete (wxWindow *)GetData();
 }
 
-#endif
+#endif // wxUSE_STL/!wxUSE_STL
 
 // ----------------------------------------------------------------------------
 // borders
@@ -2399,10 +2518,14 @@ static void DoNotifyWindowAboutCaptureLost(wxWindow *win)
 {
     wxMouseCaptureLostEvent event(win->GetId());
     event.SetEventObject(win);
-    bool processed = win->GetEventHandler()->ProcessEvent(event);
-
-    wxASSERT_MSG( processed,
-                  _T("window that captured mouse didn't process wxEVT_MOUSE_CAPTURE_LOST") );
+    if ( !win->GetEventHandler()->ProcessEvent(event) )
+    {
+        // windows must handle this event, otherwise the app wouldn't behave
+        // correctly if it loses capture unexpectedly; see the discussion here:
+        // http://sourceforge.net/tracker/index.php?func=detail&aid=1153662&group_id=9863&atid=109863
+        // http://article.gmane.org/gmane.comp.lib.wxwidgets.devel/82376
+        wxFAIL_MSG( _T("window that captured the mouse didn't process wxEVT_MOUSE_CAPTURE_LOST") );
+    }
 }
 
 /* static */
@@ -2452,14 +2575,6 @@ bool wxWindowBase::UnregisterHotKey(int WXUNUSED(hotkeyId))
 
 #endif // wxUSE_HOTKEY
 
-void wxWindowBase::SendDestroyEvent()
-{
-    wxWindowDestroyEvent event;
-    event.SetEventObject(this);
-    event.SetId(GetId());
-    GetEventHandler()->ProcessEvent(event);
-}
-
 // ----------------------------------------------------------------------------
 // event processing
 // ----------------------------------------------------------------------------
@@ -2511,17 +2626,18 @@ bool wxWindowBase::TryParent(wxEvent& event)
 // keyboard navigation
 // ----------------------------------------------------------------------------
 
-// Navigates in the specified direction.
-bool wxWindowBase::Navigate(int flags)
+// Navigates in the specified direction inside this window
+bool wxWindowBase::DoNavigateIn(int flags)
 {
+#ifdef wxHAS_NATIVE_TAB_TRAVERSAL
+    // native code doesn't process our wxNavigationKeyEvents anyhow
+    return false;
+#else // !wxHAS_NATIVE_TAB_TRAVERSAL
     wxNavigationKeyEvent eventNav;
     eventNav.SetFlags(flags);
-    eventNav.SetEventObject(this);
-    if ( GetParent()->GetEventHandler()->ProcessEvent(eventNav) )
-    {
-        return true;
-    }
-    return false;
+    eventNav.SetEventObject(FindFocus());
+    return GetEventHandler()->ProcessEvent(eventNav);
+#endif // wxHAS_NATIVE_TAB_TRAVERSAL/!wxHAS_NATIVE_TAB_TRAVERSAL
 }
 
 void wxWindowBase::DoMoveInTabOrder(wxWindow *win, MoveKind move)
@@ -2985,6 +3101,7 @@ wxAccStatus wxWindowAccessible::GetFocus(int* WXUNUSED(childId), wxAccessible**
     return wxACC_NOT_IMPLEMENTED;
 }
 
+#if wxUSE_VARIANT
 // Gets a variant representing the selected children
 // of this object.
 // Acceptable values:
@@ -3001,5 +3118,24 @@ wxAccStatus wxWindowAccessible::GetSelections(wxVariant* WXUNUSED(selections))
 
     return wxACC_NOT_IMPLEMENTED;
 }
+#endif // wxUSE_VARIANT
 
 #endif // wxUSE_ACCESSIBILITY
+
+// ----------------------------------------------------------------------------
+// RTL support
+// ----------------------------------------------------------------------------
+
+wxCoord
+wxWindowBase::AdjustForLayoutDirection(wxCoord x,
+                                       wxCoord width,
+                                       wxCoord widthTotal) const
+{
+    if ( GetLayoutDirection() == wxLayout_RightToLeft )
+    {
+        x = widthTotal - x - width;
+    }
+
+    return x;
+}
+