]> git.saurik.com Git - wxWidgets.git/blobdiff - src/common/wincmn.cpp
fixing bug 1841377
[wxWidgets.git] / src / common / wincmn.cpp
index 57b4fe195936cc6b4ab5cb5e994d7e52e350e4ab..5c25f4f47a723cf36f027f77fe8f99b06dbaf982 100644 (file)
@@ -89,13 +89,6 @@ WXDLLIMPEXP_DATA_CORE(wxWindowList) wxTopLevelWindows;
 // static data
 // ----------------------------------------------------------------------------
 
-#if defined(__WXPALMOS__)
-int wxWindowBase::ms_lastControlId = 32767;
-#elif defined(__WXPM__)
-int wxWindowBase::ms_lastControlId = 2000;
-#else
-int wxWindowBase::ms_lastControlId = -200;
-#endif
 
 IMPLEMENT_ABSTRACT_CLASS(wxWindowBase, wxEvtHandler)
 
@@ -174,6 +167,7 @@ wxWindowBase::wxWindowBase()
     m_windowSizer = (wxSizer *) NULL;
     m_containingSizer = (wxSizer *) NULL;
     m_autoLayout = false;
+    m_freeId = false;
 
 #if wxUSE_DRAG_AND_DROP
     m_dropTarget = (wxDropTarget *)NULL;
@@ -242,11 +236,22 @@ bool wxWindowBase::CreateBase(wxWindowBase *parent,
     // ids are limited to 16 bits under MSW so if you care about portability,
     // it's not a good idea to use ids out of this range (and negative ids are
     // reserved for wxWidgets own usage)
-    wxASSERT_MSG( id == wxID_ANY || (id >= 0 && id < 32767),
+    wxASSERT_MSG( id == wxID_ANY || (id >= 0 && id < 32767) ||
+                  (id >= wxID_AUTO_LOWEST && id <= wxID_AUTO_HIGHEST),
                   _T("invalid id value") );
 
     // generate a new id if the user doesn't care about it
-    m_windowId = id == wxID_ANY ? NewControlId() : id;
+    if ( id == wxID_ANY )
+    {
+        m_windowId = NewControlId();
+
+        // remember to call ReleaseControlId() when this window is destroyed
+        m_freeId = true;
+    }
+    else // valid id specified
+    {
+        m_windowId = 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
@@ -302,6 +307,10 @@ wxWindowBase::~wxWindowBase()
 {
     wxASSERT_MSG( GetCapture() != this, wxT("attempt to destroy window with mouse capture") );
 
+    // mark the id as unused if we allocated it for this control
+    if ( m_freeId )
+        ReleaseControlId(m_windowId);
+
     // FIXME if these 2 cases result from programming errors in the user code
     //       we should probably assert here instead of silently fixing them
 
@@ -1042,6 +1051,11 @@ bool wxWindowBase::RemoveEventHandler(wxEvtHandler *handler)
     return false;
 }
 
+bool wxWindowBase::HandleWindowEvent(wxEvent& event) const
+{
+    return GetEventHandler()->SafelyProcessEvent(event);
+}
+
 // ----------------------------------------------------------------------------
 // colours, fonts &c
 // ----------------------------------------------------------------------------
@@ -2348,43 +2362,7 @@ void wxWindowBase::OnMiddleClick( wxMouseEvent& event )
             return;
         }
 #endif // __WXDEBUG__
-
-#if wxUSE_MSGDLG
-        // 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)",
-#else
-                   wxEmptyString,
-#endif
-#ifdef __WXDEBUG__
-                   _T(" Debug build"),
-#else
-                   wxEmptyString,
-#endif
-                   __TDATE__,
-                   __TTIME__,
-                   wxPlatformInfo::Get().GetToolkitMajorVersion(),
-                   wxPlatformInfo::Get().GetToolkitMinorVersion(),
-#ifdef __WXGTK__
-                   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
-                   );
-
-        wxMessageBox(msg, _T("wxWidgets information"),
-                     wxICON_INFORMATION | wxOK,
-                     (wxWindow *)this);
-#endif // wxUSE_MSGDLG
+        ::wxInfoMessageBox((wxWindow*)this);
     }
     else
     {
@@ -2662,15 +2640,37 @@ bool wxWindowBase::TryParent(wxEvent& event)
     return wxEvtHandler::TryParent(event);
 }
 
+// ----------------------------------------------------------------------------
+// window relationships
+// ----------------------------------------------------------------------------
+
+wxWindow *wxWindowBase::DoGetSibling(WindowOrder order) const
+{
+    wxCHECK_MSG( GetParent(), NULL,
+                    _T("GetPrev/NextSibling() don't work for TLWs!") );
+
+    wxWindowList& siblings = GetParent()->GetChildren();
+    wxWindowList::compatibility_iterator i = siblings.Find((wxWindow *)this);
+    wxCHECK_MSG( i, NULL, _T("window not a child of its parent?") );
+
+    if ( order == OrderBefore )
+        i = i->GetPrevious();
+    else // OrderAfter
+        i = i->GetNext();
+
+    return i ? i->GetData() : NULL;
+}
+
 // ----------------------------------------------------------------------------
 // keyboard navigation
 // ----------------------------------------------------------------------------
 
 // Navigates in the specified direction inside this window
-bool wxWindowBase::DoNavigateIn(int WXUNUSED(flags))
+bool wxWindowBase::DoNavigateIn(int flags)
 {
 #ifdef wxHAS_NATIVE_TAB_TRAVERSAL
     // native code doesn't process our wxNavigationKeyEvents anyhow
+    wxUnusedVar(flags);
     return false;
 #else // !wxHAS_NATIVE_TAB_TRAVERSAL
     wxNavigationKeyEvent eventNav;
@@ -2680,7 +2680,7 @@ bool wxWindowBase::DoNavigateIn(int WXUNUSED(flags))
 #endif // wxHAS_NATIVE_TAB_TRAVERSAL/!wxHAS_NATIVE_TAB_TRAVERSAL
 }
 
-void wxWindowBase::DoMoveInTabOrder(wxWindow *win, MoveKind move)
+void wxWindowBase::DoMoveInTabOrder(wxWindow *win, WindowOrder move)
 {
     // check that we're not a top level window
     wxCHECK_RET( GetParent(),
@@ -2700,7 +2700,7 @@ void wxWindowBase::DoMoveInTabOrder(wxWindow *win, MoveKind move)
     // can't just move the node around
     wxWindow *self = (wxWindow *)this;
     siblings.DeleteObject(self);
-    if ( move == MoveAfter )
+    if ( move == OrderAfter )
     {
         i = i->GetNext();
     }
@@ -2709,7 +2709,7 @@ void wxWindowBase::DoMoveInTabOrder(wxWindow *win, MoveKind move)
     {
         siblings.Insert(i, self);
     }
-    else // MoveAfter and win was the last sibling
+    else // OrderAfter and win was the last sibling
     {
         siblings.Append(self);
     }
@@ -3179,3 +3179,125 @@ wxWindowBase::AdjustForLayoutDirection(wxCoord x,
     return x;
 }
 
+// ----------------------------------------------------------------------------
+// Window (and menu items) identifiers management
+// ----------------------------------------------------------------------------
+
+namespace
+{
+
+// this array contains, in packed form, the "in use" flags for the entire
+// auto-generated ids range: N-th element of the array contains the flags for
+// ids in [wxID_AUTO_LOWEST + 8*N, wxID_AUTO_LOWEST + 8*N + 7] range
+//
+// initially no ids are in use and we allocate them consecutively, but after we
+// exhaust the entire range, we wrap around and reuse the ids freed in the
+// meanwhile
+wxByte gs_autoIdsInUse[(wxID_AUTO_HIGHEST - wxID_AUTO_LOWEST + 1)/8 + 1] = { 0 };
+
+// this is an optimization used until we wrap around wxID_AUTO_HIGHEST: if this
+// value is < wxID_AUTO_HIGHEST we know that we haven't wrapped yet and so can
+// allocate the ids simply by incrementing it
+static wxWindowID gs_nextControlId = wxID_AUTO_LOWEST;
+
+void MarkAutoIdUsed(wxWindowID id)
+{
+    id -= wxID_AUTO_LOWEST;
+
+    const int theByte = id / 8;
+    const int theBit = id % 8;
+
+    gs_autoIdsInUse[theByte] |= 1 << theBit;
+}
+
+void FreeAutoId(wxWindowID id)
+{
+    id -= wxID_AUTO_LOWEST;
+
+    const int theByte = id / 8;
+    const int theBit = id % 8;
+
+    gs_autoIdsInUse[theByte] &= ~(1 << theBit);
+}
+
+bool IsAutoIdInUse(wxWindowID id)
+{
+    id -= wxID_AUTO_LOWEST;
+
+    const int theByte = id / 8;
+    const int theBit = id % 8;
+
+    return (gs_autoIdsInUse[theByte] & (1 << theBit)) != 0;
+}
+
+} // anonymous namespace
+
+
+/* static */
+bool wxWindowBase::IsAutoGeneratedId(wxWindowID id)
+{
+    if ( id < wxID_AUTO_LOWEST || id > wxID_AUTO_HIGHEST )
+        return false;
+
+    // we shouldn't have any stray ids in this range
+    wxASSERT_MSG( IsAutoIdInUse(id), "unused automatically generated id?" );
+
+    return true;
+}
+
+wxWindowID wxWindowBase::NewControlId(int count)
+{
+    wxASSERT_MSG( count > 0, "can't allocate less than 1 id" );
+
+    if ( gs_nextControlId + count - 1 <= wxID_AUTO_HIGHEST )
+    {
+        // we haven't wrapped yet, so we can just grab the next count ids
+        wxWindowID id = gs_nextControlId;
+
+        while ( count-- )
+            MarkAutoIdUsed(gs_nextControlId++);
+
+        return id;
+    }
+    else // we've already wrapped or are now going to
+    {
+        // brute-force search for the id values
+
+        // number of consecutive free ids found so far
+        int found = 0;
+
+        for ( wxWindowID id = wxID_AUTO_LOWEST; id <= wxID_AUTO_HIGHEST; id++ )
+        {
+            if ( !IsAutoIdInUse(id) )
+            {
+                // found another consecutive available id
+                found++;
+                if ( found == count )
+                {
+                    // mark all count consecutive free ids we found as being in
+                    // use now and rewind back to the start of available range
+                    // in the process
+                    while ( count-- )
+                        MarkAutoIdUsed(id--);
+
+                    return id;
+                }
+            }
+            else // this id is in use
+            {
+                // reset the number of consecutive free values found
+                found = 0;
+            }
+        }
+    }
+
+    // if we get here, there are not enough consecutive free ids
+    return wxID_NONE;
+}
+
+void wxWindowBase::ReleaseControlId(wxWindowID id)
+{
+    wxCHECK_RET( IsAutoGeneratedId(id), "can't release non auto-generated id" );
+
+    FreeAutoId(id);
+}