#include "wx/scrolbar.h"
#include "wx/layout.h"
#include "wx/sizer.h"
+ #include "wx/menu.h"
#endif //WX_PRECOMP
#if wxUSE_DRAG_AND_DROP
WXDLLIMPEXP_DATA_CORE(wxWindowList) wxTopLevelWindows;
// globals
-#if wxUSE_MENUS_NATIVE
+#if wxUSE_MENUS
wxMenu *wxCurrentPopupMenu = NULL;
-#endif // wxUSE_MENUS_NATIVE
+#endif // wxUSE_MENUS
// ----------------------------------------------------------------------------
// static data
m_windowSizer = (wxSizer *) NULL;
m_containingSizer = (wxSizer *) NULL;
m_autoLayout = false;
- m_freeId = false;
#if wxUSE_DRAG_AND_DROP
m_dropTarget = (wxDropTarget *)NULL;
// VZ: this one shouldn't exist...
m_isBeingDeleted = false;
+
+ m_freezeCount = 0;
}
// common part of window creation process
if ( id == wxID_ANY )
{
m_windowId = NewControlId();
-
- // remember to call ReleaseControlId() when this window is destroyed
- m_freeId = true;
}
else // valid id specified
{
{
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
// 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") );
#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()
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 )
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
// ----------------------------------------------------------------------------
GetChildren().Append((wxWindow*)child);
child->SetParent(this);
+
+ // adding a child while frozen will assert when thawn, 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
+ if ( IsFrozen() && !child->IsTopLevel() )
+ child->Thaw();
+
GetChildren().DeleteObject((wxWindow *)child);
child->SetParent(NULL);
}
}
}
+#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)
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
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;
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
return win ? win->GetMainWindowOfCompositeControl() : NULL;
}
+bool wxWindowBase::HasFocus() const
+{
+ wxWindowBase *win = DoFindFocus();
+ return win == this ||
+ win == wxConstCast(this, wxWindowBase)->GetMainWindowOfCompositeControl();
+}
+
// ----------------------------------------------------------------------------
// global functions
// ----------------------------------------------------------------------------
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);
-}