]> git.saurik.com Git - wxWidgets.git/blobdiff - src/common/wincmn.cpp
move wxIconArray declaration out of header, remove unneccessary copy ctor and assignm...
[wxWidgets.git] / src / common / wincmn.cpp
index 8d16cbcdfdc9f16c7b16f78c463cdcffdc18e548..c40aa1d746070b42912850d697c976a42a95738a 100644 (file)
@@ -44,6 +44,7 @@
     #include "wx/scrolbar.h"
     #include "wx/layout.h"
     #include "wx/sizer.h"
+    #include "wx/menu.h"
 #endif //WX_PRECOMP
 
 #if wxUSE_DRAG_AND_DROP
 // Windows List
 WXDLLIMPEXP_DATA_CORE(wxWindowList) wxTopLevelWindows;
 
+// globals
+#if wxUSE_MENUS
+wxMenu *wxCurrentPopupMenu = NULL;
+#endif // wxUSE_MENUS
+
 // ----------------------------------------------------------------------------
 // static data
 // ----------------------------------------------------------------------------
@@ -167,7 +173,6 @@ 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;
@@ -193,11 +198,6 @@ wxWindowBase::wxWindowBase()
 
     m_scrollHelper = (wxScrollHelper *) NULL;
 
-    m_minVirtualWidth =
-    m_maxVirtualWidth = wxDefaultCoord;
-    m_minVirtualHeight =
-    m_maxVirtualHeight = wxDefaultCoord;
-
     m_windowVariant = wxWINDOW_VARIANT_NORMAL;
 #if wxUSE_SYSTEM_OPTIONS
     if ( wxSystemOptions::HasOption(wxWINDOW_DEFAULT_VARIANT) )
@@ -211,6 +211,8 @@ wxWindowBase::wxWindowBase()
 
     // VZ: this one shouldn't exist...
     m_isBeingDeleted = false;
+
+    m_freezeCount = 0;
 }
 
 // common part of window creation process
@@ -244,9 +246,6 @@ bool wxWindowBase::CreateBase(wxWindowBase *parent,
     if ( id == wxID_ANY )
     {
         m_windowId = NewControlId();
-
-        // remember to call ReleaseControlId() when this window is destroyed
-        m_freeId = true;
     }
     else // valid id specified
     {
@@ -307,10 +306,6 @@ 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
 
@@ -322,6 +317,13 @@ wxWindowBase::~wxWindowBase()
     // we weren't a dialog class
     wxTopLevelWindows.DeleteObject((wxWindow*)this);
 
+#if wxUSE_MENUS
+    // The associated popup menu can still be alive, disassociate from it in
+    // this case
+    if ( wxCurrentPopupMenu && wxCurrentPopupMenu->GetInvokingWindow() == this )
+        wxCurrentPopupMenu->SetInvokingWindow(NULL);
+#endif // wxUSE_MENUS
+
     wxASSERT_MSG( GetChildren().GetCount() == 0, wxT("children not destroyed") );
 
     // notify the parent about this window destruction
@@ -367,6 +369,14 @@ wxWindowBase::~wxWindowBase()
 #if wxUSE_ACCESSIBILITY
     delete m_accessible;
 #endif
+
+#if wxUSE_HELP
+    // NB: this has to be called unconditionally, because we don't know
+    //     whether this window has associated help text or not
+    wxHelpProvider *helpProvider = wxHelpProvider::Get();
+    if ( helpProvider )
+        helpProvider->RemoveHelp(this);
+#endif
 }
 
 void wxWindowBase::SendDestroyEvent()
@@ -392,7 +402,7 @@ bool wxWindowBase::Close(bool force)
 
     // return false if window wasn't closed because the application vetoed the
     // close event
-    return GetEventHandler()->ProcessEvent(event) && !event.GetVeto();
+    return HandleWindowEvent(event) && !event.GetVeto();
 }
 
 bool wxWindowBase::DestroyChildren()
@@ -711,6 +721,22 @@ wxPoint wxWindowBase::GetClientAreaOrigin() const
     return wxPoint(0,0);
 }
 
+wxSize wxWindowBase::ClientToWindowSize(const wxSize& size) const
+{
+    const wxSize diff(GetSize() - GetClientSize());
+
+    return wxSize(size.x == -1 ? -1 : size.x + diff.x,
+                  size.y == -1 ? -1 : size.y + diff.y);
+}
+
+wxSize wxWindowBase::WindowToClientSize(const wxSize& size) const
+{
+    const wxSize diff(GetSize() - GetClientSize());
+
+    return wxSize(size.x == -1 ? -1 : size.x - diff.x,
+                  size.y == -1 ? -1 : size.y - diff.y);
+}
+
 void wxWindowBase::SetWindowVariant( wxWindowVariant variant )
 {
     if ( m_windowVariant != variant )
@@ -771,26 +797,20 @@ void wxWindowBase::DoSetSizeHints( int minW, int minH,
 }
 
 
-void wxWindowBase::SetVirtualSizeHints( int minW, int minH,
-                                        int maxW, int maxH )
+#if WXWIN_COMPATIBILITY_2_8
+void wxWindowBase::SetVirtualSizeHints(int WXUNUSED(minW), int WXUNUSED(minH),
+                                       int WXUNUSED(maxW), int WXUNUSED(maxH))
 {
-    m_minVirtualWidth = minW;
-    m_maxVirtualWidth = maxW;
-    m_minVirtualHeight = minH;
-    m_maxVirtualHeight = maxH;
 }
 
-void wxWindowBase::DoSetVirtualSize( int x, int y )
+void wxWindowBase::SetVirtualSizeHints(const wxSize& WXUNUSED(minsize),
+                                       const wxSize& WXUNUSED(maxsize))
 {
-    if ( m_minVirtualWidth != wxDefaultCoord && m_minVirtualWidth > x )
-        x = m_minVirtualWidth;
-    if ( m_maxVirtualWidth != wxDefaultCoord && m_maxVirtualWidth < x )
-        x = m_maxVirtualWidth;
-    if ( m_minVirtualHeight != wxDefaultCoord && m_minVirtualHeight > y )
-        y = m_minVirtualHeight;
-    if ( m_maxVirtualHeight != wxDefaultCoord && m_maxVirtualHeight < y )
-        y = m_maxVirtualHeight;
+}
+#endif // WXWIN_COMPATIBILITY_2_8
 
+void wxWindowBase::DoSetVirtualSize( int x, int y )
+{
     m_virtualSize = wxSize(x, y);
 }
 
@@ -821,6 +841,23 @@ void wxWindowBase::DoGetScreenPosition(int *x, int *y) const
     ClientToScreen(x, y);
 }
 
+void wxWindowBase::SendSizeEvent(int flags)
+{
+    wxSizeEvent event(GetSize(), GetId());
+    event.SetEventObject(this);
+    if ( flags & wxSEND_EVENT_POST )
+        wxPostEvent(this, event);
+    else
+        HandleWindowEvent(event);
+}
+
+void wxWindowBase::SendSizeEventToParent(int flags)
+{
+    wxWindow * const parent = GetParent();
+    if ( parent && !parent->IsBeingDeleted() )
+        parent->SendSizeEvent(flags);
+}
+
 // ----------------------------------------------------------------------------
 // show/hide/enable/disable the window
 // ----------------------------------------------------------------------------
@@ -892,8 +929,11 @@ bool wxWindowBase::Enable(bool enable)
 
 bool wxWindowBase::IsShownOnScreen() const
 {
+    // A window is shown on screen if it itself is shown and so are all its
+    // parents. But if a window is toplevel one, then its always visible on
+    // screen if IsShown() returns true, even if it has a hidden parent.
     return IsShown() &&
-           (GetParent() == NULL || GetParent()->IsShownOnScreen());
+           (IsTopLevel() || GetParent() == NULL || GetParent()->IsShownOnScreen());
 }
 
 // ----------------------------------------------------------------------------
@@ -905,6 +945,52 @@ bool wxWindowBase::IsTopLevel() const
     return false;
 }
 
+// ----------------------------------------------------------------------------
+// Freeze/Thaw
+// ----------------------------------------------------------------------------
+
+void wxWindowBase::Freeze()
+{
+    if ( !m_freezeCount++ )
+    {
+        // physically freeze this window:
+        DoFreeze();
+
+        // and recursively freeze all children:
+        for ( wxWindowList::iterator i = GetChildren().begin();
+              i != GetChildren().end(); ++i )
+        {
+            wxWindow *child = *i;
+            if ( child->IsTopLevel() )
+                continue;
+
+            child->Freeze();
+        }
+    }
+}
+
+void wxWindowBase::Thaw()
+{
+    wxASSERT_MSG( m_freezeCount, "Thaw() without matching Freeze()" );
+
+    if ( !--m_freezeCount )
+    {
+        // recursively thaw all children:
+        for ( wxWindowList::iterator i = GetChildren().begin();
+              i != GetChildren().end(); ++i )
+        {
+            wxWindow *child = *i;
+            if ( child->IsTopLevel() )
+                continue;
+
+            child->Thaw();
+        }
+
+        // physically thaw this window:
+        DoThaw();
+    }
+}
+
 // ----------------------------------------------------------------------------
 // reparenting the window
 // ----------------------------------------------------------------------------
@@ -920,12 +1006,25 @@ void wxWindowBase::AddChild(wxWindowBase *child)
 
     GetChildren().Append((wxWindow*)child);
     child->SetParent(this);
+
+    // adding a child while frozen will assert when thawed, so freeze it as if
+    // it had been already present when we were frozen
+    if ( IsFrozen() && !child->IsTopLevel() )
+        child->Freeze();
 }
 
 void wxWindowBase::RemoveChild(wxWindowBase *child)
 {
     wxCHECK_RET( child, wxT("can't remove a NULL child") );
 
+    // removing a child while frozen may result in permanently frozen window
+    // if used e.g. from Reparent(), so thaw it
+    //
+    // NB: IsTopLevel() doesn't return true any more when a TLW child is being
+    //     removed from its ~wxWindowBase, so check for IsBeingDeleted() too
+    if ( IsFrozen() && !child->IsBeingDeleted() && !child->IsTopLevel() )
+        child->Thaw();
+
     GetChildren().DeleteObject((wxWindow *)child);
     child->SetParent(NULL);
 }
@@ -1051,6 +1150,11 @@ bool wxWindowBase::RemoveEventHandler(wxEvtHandler *handler)
     return false;
 }
 
+bool wxWindowBase::HandleWindowEvent(wxEvent& event) const
+{
+    return GetEventHandler()->SafelyProcessEvent(event);
+}
+
 // ----------------------------------------------------------------------------
 // colours, fonts &c
 // ----------------------------------------------------------------------------
@@ -1111,7 +1215,7 @@ wxWindowBase::GetClassDefaultAttributes(wxWindowVariant WXUNUSED(variant))
 
 wxColour wxWindowBase::GetBackgroundColour() const
 {
-    if ( !m_backgroundColour.Ok() )
+    if ( !m_backgroundColour.IsOk() )
     {
         wxASSERT_MSG( !m_hasBgCol, _T("we have invalid explicit bg colour?") );
 
@@ -1139,7 +1243,7 @@ wxColour wxWindowBase::GetForegroundColour() const
     {
         wxColour colFg = GetDefaultAttributes().colFg;
 
-        if ( !colFg.Ok() )
+        if ( !colFg.IsOk() )
             colFg = GetClassDefaultAttributes().colFg;
 
         return colFg;
@@ -1153,7 +1257,7 @@ bool wxWindowBase::SetBackgroundColour( const wxColour &colour )
     if ( colour == m_backgroundColour )
         return false;
 
-    m_hasBgCol = colour.Ok();
+    m_hasBgCol = colour.IsOk();
     if ( m_backgroundStyle != wxBG_STYLE_CUSTOM )
         m_backgroundStyle = m_hasBgCol ? wxBG_STYLE_COLOUR : wxBG_STYLE_SYSTEM;
 
@@ -1168,7 +1272,7 @@ bool wxWindowBase::SetForegroundColour( const wxColour &colour )
     if (colour == m_foregroundColour )
         return false;
 
-    m_hasFgCol = colour.Ok();
+    m_hasFgCol = colour.IsOk();
     m_inheritFgCol = m_hasFgCol;
     m_foregroundColour = colour;
     SetThemeEnabled( !m_hasFgCol && !m_backgroundColour.Ok() );
@@ -1193,12 +1297,12 @@ bool wxWindowBase::SetCursor(const wxCursor& cursor)
 wxFont wxWindowBase::GetFont() const
 {
     // logic is the same as in GetBackgroundColour()
-    if ( !m_font.Ok() )
+    if ( !m_font.IsOk() )
     {
         wxASSERT_MSG( !m_hasFont, _T("we have invalid explicit font?") );
 
         wxFont font = GetDefaultAttributes().font;
-        if ( !font.Ok() )
+        if ( !font.IsOk() )
             font = GetClassDefaultAttributes().font;
 
         return font;
@@ -1216,7 +1320,7 @@ bool wxWindowBase::SetFont(const wxFont& font)
     }
 
     m_font = font;
-    m_hasFont = font.Ok();
+    m_hasFont = font.IsOk();
     m_inheritFont = m_hasFont;
 
     InvalidateBestSize();
@@ -1315,7 +1419,7 @@ void wxWindowBase::ClearBackground()
     // wxGTK uses its own version, no need to add never used code
 #ifndef __WXGTK__
     wxClientDC dc((wxWindow *)this);
-    wxBrush brush(GetBackgroundColour(), wxSOLID);
+    wxBrush brush(GetBackgroundColour(), wxBRUSHSTYLE_SOLID);
     dc.SetBackground(brush);
     dc.Clear();
 #endif // __WXGTK__
@@ -1611,6 +1715,7 @@ void wxWindowBase::SetHelpText(const wxString& text)
     }
 }
 
+#if WXWIN_COMPATIBILITY_2_8
 // associate this help text with all windows with the same id as this
 // one
 void wxWindowBase::SetHelpTextForId(const wxString& text)
@@ -1621,6 +1726,7 @@ void wxWindowBase::SetHelpTextForId(const wxString& text)
         helpProvider->AddHelp(GetId(), text);
     }
 }
+#endif // WXWIN_COMPATIBILITY_2_8
 
 // get the help string associated with this window (may be empty)
 // default implementation forwards calls to the help provider
@@ -1644,7 +1750,29 @@ void wxWindowBase::OnHelp(wxHelpEvent& event)
     wxHelpProvider *helpProvider = wxHelpProvider::Get();
     if ( helpProvider )
     {
-        if ( helpProvider->ShowHelpAtPoint(this, event.GetPosition(), event.GetOrigin()) )
+        wxPoint pos = event.GetPosition();
+        const wxHelpEvent::Origin origin = event.GetOrigin();
+        if ( origin == wxHelpEvent::Origin_Keyboard )
+        {
+            // if the help event was generated from keyboard it shouldn't
+            // appear at the mouse position (which is still the only position
+            // associated with help event) if the mouse is far away, although
+            // we still do use the mouse position if it's over the window
+            // because we suppose the user looks approximately at the mouse
+            // already and so it would be more convenient than showing tooltip
+            // at some arbitrary position which can be quite far from it
+            const wxRect rectClient = GetClientRect();
+            if ( !rectClient.Contains(ScreenToClient(pos)) )
+            {
+                // position help slightly under and to the right of this window
+                pos = ClientToScreen(wxPoint(
+                        2*GetCharWidth(),
+                        rectClient.height + GetCharHeight()
+                      ));
+            }
+        }
+
+        if ( helpProvider->ShowHelpAtPoint(this, pos, origin) )
         {
             // skip the event.Skip() below
             return;
@@ -2248,6 +2376,17 @@ void wxWindowBase::OnInitDialog( wxInitDialogEvent &WXUNUSED(event) )
 
 #if wxUSE_MENUS
 
+bool wxWindowBase::PopupMenu(wxMenu *menu, int x, int y)
+{
+    wxCHECK_MSG( menu, false, "can't popup NULL menu" );
+
+    wxCurrentPopupMenu = menu;
+    const bool rc = DoPopupMenu(menu, x, y);
+    wxCurrentPopupMenu = NULL;
+
+    return rc;
+}
+
 // this is used to pass the id of the selected item from the menu event handler
 // to the main function itself
 //
@@ -2292,7 +2431,7 @@ static void DrawBorder(wxWindowBase *win, const wxRect& rect, bool fill = false)
 {
     wxClientDC dc((wxWindow *)win);
     dc.SetPen(*wxRED_PEN);
-    dc.SetBrush(fill ? wxBrush(*wxRED, wxCROSSDIAG_HATCH): *wxTRANSPARENT_BRUSH);
+    dc.SetBrush(fill ? wxBrush(*wxRED, wxBRUSHSTYLE_CROSSDIAG_HATCH) : *wxTRANSPARENT_BRUSH);
     dc.DrawRectangle(rect.Deflate(1, 1));
 }
 
@@ -2502,7 +2641,10 @@ void wxWindowBase::ReleaseMouse()
 
     wxASSERT_MSG( !ms_winCaptureChanging, _T("recursive ReleaseMouse call?") );
 
-    wxASSERT_MSG( GetCapture() == this, wxT("attempt to release mouse, but this window hasn't captured it") );
+    wxASSERT_MSG( GetCapture() == this,
+                  "attempt to release mouse, but this window hasn't captured it" );
+    wxASSERT_MSG( ms_winCaptureCurrent == this,
+                  "attempt to release mouse, but this window hasn't captured it" );
 
     ms_winCaptureChanging = true;
 
@@ -2645,7 +2787,7 @@ wxWindow *wxWindowBase::DoGetSibling(WindowOrder order) const
                     _T("GetPrev/NextSibling() don't work for TLWs!") );
 
     wxWindowList& siblings = GetParent()->GetChildren();
-    wxWindowList::compatibility_iterator i = siblings.Find(this);
+    wxWindowList::compatibility_iterator i = siblings.Find((wxWindow *)this);
     wxCHECK_MSG( i, NULL, _T("window not a child of its parent?") );
 
     if ( order == OrderBefore )
@@ -2669,12 +2811,33 @@ bool wxWindowBase::DoNavigateIn(int flags)
     return false;
 #else // !wxHAS_NATIVE_TAB_TRAVERSAL
     wxNavigationKeyEvent eventNav;
+    wxWindow *focused = FindFocus();
+    eventNav.SetCurrentFocus(focused);
+    eventNav.SetEventObject(focused);
     eventNav.SetFlags(flags);
-    eventNav.SetEventObject(FindFocus());
     return GetEventHandler()->ProcessEvent(eventNav);
 #endif // wxHAS_NATIVE_TAB_TRAVERSAL/!wxHAS_NATIVE_TAB_TRAVERSAL
 }
 
+bool wxWindowBase::HandleAsNavigationKey(const wxKeyEvent& event)
+{
+    if ( event.GetKeyCode() != WXK_TAB )
+        return false;
+
+    int flags = wxNavigationKeyEvent::FromTab;
+
+    if ( event.ShiftDown() )
+        flags |= wxNavigationKeyEvent::IsBackward;
+    else
+        flags |= wxNavigationKeyEvent::IsForward;
+
+    if ( event.ControlDown() )
+        flags |= wxNavigationKeyEvent::WinChange;
+
+    Navigate(flags);
+    return true;
+}
+
 void wxWindowBase::DoMoveInTabOrder(wxWindow *win, WindowOrder move)
 {
     // check that we're not a top level window
@@ -2720,6 +2883,13 @@ void wxWindowBase::DoMoveInTabOrder(wxWindow *win, WindowOrder move)
     return win ? win->GetMainWindowOfCompositeControl() : NULL;
 }
 
+bool wxWindowBase::HasFocus() const
+{
+    wxWindowBase *win = DoFindFocus();
+    return win == this ||
+           win == wxConstCast(this, wxWindowBase)->GetMainWindowOfCompositeControl();
+}
+
 // ----------------------------------------------------------------------------
 // global functions
 // ----------------------------------------------------------------------------
@@ -3174,125 +3344,4 @@ 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);
-}