#include "wx/settings.h"
#include "wx/dialog.h"
#include "wx/msgdlg.h"
+ #include "wx/msgout.h"
#include "wx/statusbr.h"
#include "wx/toolbar.h"
#include "wx/dcclient.h"
#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
// ----------------------------------------------------------------------------
wxWindowBase::wxWindowBase()
{
// no window yet, no parent nor children
- m_parent = (wxWindow *)NULL;
+ m_parent = NULL;
m_windowId = wxID_ANY;
// no constraints on the minimal window size
#if wxUSE_VALIDATORS
// no validator
- m_windowValidator = (wxValidator *) NULL;
+ m_windowValidator = NULL;
#endif // wxUSE_VALIDATORS
// the colours/fonts are default for now, so leave m_font,
#if wxUSE_CONSTRAINTS
// no constraints whatsoever
- m_constraints = (wxLayoutConstraints *) NULL;
- m_constraintsInvolvedIn = (wxWindowList *) NULL;
+ m_constraints = NULL;
+ m_constraintsInvolvedIn = NULL;
#endif // wxUSE_CONSTRAINTS
- m_windowSizer = (wxSizer *) NULL;
- m_containingSizer = (wxSizer *) NULL;
+ m_windowSizer = NULL;
+ m_containingSizer = NULL;
m_autoLayout = false;
- m_freeId = false;
#if wxUSE_DRAG_AND_DROP
- m_dropTarget = (wxDropTarget *)NULL;
+ m_dropTarget = NULL;
#endif // wxUSE_DRAG_AND_DROP
#if wxUSE_TOOLTIPS
- m_tooltip = (wxToolTip *)NULL;
+ m_tooltip = NULL;
#endif // wxUSE_TOOLTIPS
#if wxUSE_CARET
- m_caret = (wxCaret *)NULL;
+ m_caret = NULL;
#endif // wxUSE_CARET
#if wxUSE_PALETTE
m_virtualSize = wxDefaultSize;
- m_scrollHelper = (wxScrollHelper *) NULL;
-
- m_minVirtualWidth =
- m_maxVirtualWidth = wxDefaultCoord;
- m_minVirtualHeight =
- m_maxVirtualHeight = wxDefaultCoord;
+ m_scrollHelper = NULL;
m_windowVariant = wxWINDOW_VARIANT_NORMAL;
#if wxUSE_SYSTEM_OPTIONS
// Whether we're using the current theme for this window (wxGTK only for now)
m_themeEnabled = false;
- // VZ: this one shouldn't exist...
+ // This is set to true by SendDestroyEvent() which should be called by the
+ // most derived class to ensure that the destruction event is sent as soon
+ // as possible to allow its handlers to still see the undestroyed window
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") );
// notify the parent about this window destruction
#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
+}
+
+bool wxWindowBase::IsBeingDeleted() const
+{
+ return m_isBeingDeleted ||
+ (!IsTopLevel() && m_parent && m_parent->IsBeingDeleted());
}
void wxWindowBase::SendDestroyEvent()
{
+ if ( m_isBeingDeleted )
+ {
+ // we could have been already called from a more derived class dtor,
+ // e.g. ~wxTLW calls us and so does ~wxWindow and the latter call
+ // should be simply ignored
+ return;
+ }
+
+ m_isBeingDeleted = true;
+
wxWindowDestroyEvent event;
event.SetEventObject(this);
event.SetId(GetId());
bool wxWindowBase::Destroy()
{
+ SendDestroyEvent();
+
delete this;
return true;
// 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()
wxWindow *child = node->GetData();
- // note that we really want to call delete and not ->Destroy() here
- // because we want to delete the child immediately, before we are
- // deleted, and delayed deletion would result in problems as our (top
- // level) child could outlive its parent
- delete child;
+ // note that we really want to delete it immediately so don't call the
+ // possible overridden Destroy() version which might not delete the
+ // child immediately resulting in problems with our (top level) child
+ // outliving its parent
+ child->wxWindowBase::Destroy();
wxASSERT_MSG( !GetChildren().Find(child),
wxT("child didn't remove itself using RemoveChild()") );
// 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)
+static int wxGetMetricOrDefault(wxSystemMetric what, const wxWindowBase* win)
{
- int rc = wxSystemSettings::GetMetric(what);
+ int rc = wxSystemSettings::GetMetric(
+ what, static_cast<wxWindow*>(const_cast<wxWindowBase*>(win)));
if ( rc == -1 )
{
switch ( what )
case wxBORDER_SIMPLE:
case wxBORDER_STATIC:
- size.x = wxGetMetricOrDefault(wxSYS_BORDER_X);
- size.y = wxGetMetricOrDefault(wxSYS_BORDER_Y);
+ size.x = wxGetMetricOrDefault(wxSYS_BORDER_X, this);
+ size.y = wxGetMetricOrDefault(wxSYS_BORDER_Y, this);
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));
+ size.x = wxMax(wxGetMetricOrDefault(wxSYS_EDGE_X, this),
+ wxGetMetricOrDefault(wxSYS_BORDER_X, this));
+ size.y = wxMax(wxGetMetricOrDefault(wxSYS_EDGE_Y, this),
+ wxGetMetricOrDefault(wxSYS_BORDER_Y, this));
break;
case wxBORDER_DOUBLE:
- size.x = wxGetMetricOrDefault(wxSYS_EDGE_X) +
- wxGetMetricOrDefault(wxSYS_BORDER_X);
- size.y = wxGetMetricOrDefault(wxSYS_EDGE_Y) +
- wxGetMetricOrDefault(wxSYS_BORDER_Y);
+ size.x = wxGetMetricOrDefault(wxSYS_EDGE_X, this) +
+ wxGetMetricOrDefault(wxSYS_BORDER_X, this);
+ size.y = wxGetMetricOrDefault(wxSYS_EDGE_Y, this) +
+ wxGetMetricOrDefault(wxSYS_BORDER_Y, this);
break;
default:
{
// merge the best size with the min size, giving priority to the min size
wxSize min = GetMinSize();
+
if (min.x == wxDefaultCoord || min.y == wxDefaultCoord)
{
wxSize best = GetBestSize();
if (min.x == wxDefaultCoord) min.x = best.x;
if (min.y == wxDefaultCoord) min.y = best.y;
}
+
return min;
}
+wxSize wxWindowBase::GetBestSize() const
+{
+ if ((!m_windowSizer) && (m_bestSizeCache.IsFullySpecified()))
+ return m_bestSizeCache;
+
+ return DoGetBestSize();
+}
+
+void wxWindowBase::SetMinSize(const wxSize& minSize)
+{
+ m_minWidth = minSize.x;
+ m_minHeight = minSize.y;
+}
+
+void wxWindowBase::SetMaxSize(const wxSize& maxSize)
+{
+ m_maxWidth = maxSize.x;
+ m_maxHeight = maxSize.y;
+}
void wxWindowBase::SetInitialSize(const wxSize& size)
{
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 )
}
-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);
}
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
// ----------------------------------------------------------------------------
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());
}
// ----------------------------------------------------------------------------
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 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);
}
// event handler stuff
// ----------------------------------------------------------------------------
-void wxWindowBase::PushEventHandler(wxEvtHandler *handler)
+void wxWindowBase::SetEventHandler(wxEvtHandler *handler)
+{
+ wxCHECK_RET(handler != NULL, "SetEventHandler(NULL) called");
+
+ m_eventHandler = handler;
+}
+
+void wxWindowBase::SetNextHandler(wxEvtHandler *WXUNUSED(handler))
+{
+ // disable wxEvtHandler chain mechanism for wxWindows:
+ // wxWindow uses its own stack mechanism which doesn't mix well with wxEvtHandler's one
+
+ wxFAIL_MSG("wxWindow cannot be part of a wxEvtHandler chain");
+}
+void wxWindowBase::SetPreviousHandler(wxEvtHandler *WXUNUSED(handler))
+{
+ // we can't simply wxFAIL here as in SetNextHandler: in fact the last
+ // handler of our stack when is destroyed will be Unlink()ed and thus
+ // will call this function to update the pointer of this window...
+
+ //wxFAIL_MSG("wxWindow cannot be part of a wxEvtHandler chain");
+}
+
+void wxWindowBase::PushEventHandler(wxEvtHandler *handlerToPush)
{
+ wxCHECK_RET( handlerToPush != NULL, "PushEventHandler(NULL) called" );
+
+ // the new handler is going to be part of the wxWindow stack of event handlers:
+ // it can't be part also of an event handler double-linked chain:
+ wxASSERT_MSG(handlerToPush->IsUnlinked(),
+ "The handler being pushed in the wxWindow stack shouldn't be part of "
+ "a wxEvtHandler chain; call Unlink() on it first");
+
wxEvtHandler *handlerOld = GetEventHandler();
+ wxCHECK_RET( handlerOld, "an old event handler is NULL?" );
+
+ // now use wxEvtHandler double-linked list to implement a stack:
+ handlerToPush->SetNextHandler(handlerOld);
- handler->SetNextHandler(handlerOld);
+ if (handlerOld != this)
+ handlerOld->SetPreviousHandler(handlerToPush);
- if ( handlerOld )
- GetEventHandler()->SetPreviousHandler(handler);
+ SetEventHandler(handlerToPush);
- SetEventHandler(handler);
+#ifdef __WXDEBUG__
+ // final checks of the operations done above:
+ wxASSERT_MSG( handlerToPush->GetPreviousHandler() == NULL,
+ "the first handler of the wxWindow stack should have no previous handlers set" );
+ wxASSERT_MSG( handlerToPush->GetNextHandler() != NULL,
+ "the first handler of the wxWindow stack should have non-NULL next handler" );
+
+ wxEvtHandler* pLast = handlerToPush;
+ while (pLast && pLast != this)
+ pLast = pLast->GetNextHandler();
+ wxASSERT_MSG( pLast->GetNextHandler() == NULL,
+ "the last handler of the wxWindow stack should have this window as next handler" );
+#endif
}
wxEvtHandler *wxWindowBase::PopEventHandler(bool deleteHandler)
{
- wxEvtHandler *handlerA = GetEventHandler();
- if ( handlerA )
- {
- wxEvtHandler *handlerB = handlerA->GetNextHandler();
- handlerA->SetNextHandler((wxEvtHandler *)NULL);
+ // we need to pop the wxWindow stack, i.e. we need to remove the first handler
- if ( handlerB )
- handlerB->SetPreviousHandler((wxEvtHandler *)NULL);
- SetEventHandler(handlerB);
+ wxEvtHandler *firstHandler = GetEventHandler();
+ wxCHECK_MSG( firstHandler != NULL, NULL, "wxWindow cannot have a NULL event handler" );
+ wxCHECK_MSG( firstHandler != this, NULL, "cannot pop the wxWindow itself" );
+ wxCHECK_MSG( firstHandler->GetPreviousHandler() == NULL, NULL,
+ "the first handler of the wxWindow stack should have no previous handlers set" );
- if ( deleteHandler )
- {
- delete handlerA;
- handlerA = (wxEvtHandler *)NULL;
- }
+ wxEvtHandler *secondHandler = firstHandler->GetNextHandler();
+ wxCHECK_MSG( secondHandler != NULL, NULL,
+ "the first handler of the wxWindow stack should have non-NULL next handler" );
+
+ firstHandler->SetNextHandler(NULL);
+ secondHandler->SetPreviousHandler(NULL);
+
+ // now firstHandler is completely unlinked; set secondHandler as the new window event handler
+ SetEventHandler(secondHandler);
+
+ if ( deleteHandler )
+ {
+ delete firstHandler;
+ firstHandler = NULL;
}
- return handlerA;
+ return firstHandler;
}
-bool wxWindowBase::RemoveEventHandler(wxEvtHandler *handler)
+bool wxWindowBase::RemoveEventHandler(wxEvtHandler *handlerToRemove)
{
- wxCHECK_MSG( handler, false, _T("RemoveEventHandler(NULL) called") );
+ wxCHECK_MSG( handlerToRemove != NULL, false, "RemoveEventHandler(NULL) called" );
+ wxCHECK_MSG( handlerToRemove != this, false, "Cannot remove the window itself" );
- wxEvtHandler *handlerPrev = NULL,
- *handlerCur = GetEventHandler();
- while ( handlerCur )
+ if (handlerToRemove == GetEventHandler())
+ {
+ // removing the first event handler is equivalent to "popping" the stack
+ PopEventHandler(false);
+ return true;
+ }
+
+ // NOTE: the wxWindow event handler list is always terminated with "this" handler
+ wxEvtHandler *handlerCur = GetEventHandler()->GetNextHandler();
+ while ( handlerCur != this )
{
wxEvtHandler *handlerNext = handlerCur->GetNextHandler();
- if ( handlerCur == handler )
+ if ( handlerCur == handlerToRemove )
{
- if ( handlerPrev )
- {
- handlerPrev->SetNextHandler(handlerNext);
- }
- else
- {
- SetEventHandler(handlerNext);
- }
-
- if ( handlerNext )
- {
- handlerNext->SetPreviousHandler ( handlerPrev );
- }
-
- handler->SetNextHandler(NULL);
- handler->SetPreviousHandler(NULL);
+ handlerCur->Unlink();
+ wxASSERT_MSG( handlerCur != GetEventHandler(),
+ "the case Remove == Pop should was already handled" );
return true;
}
- handlerPrev = handlerCur;
handlerCur = handlerNext;
}
return false;
}
+bool wxWindowBase::HandleWindowEvent(wxEvent& event) const
+{
+ // SafelyProcessEvent() will handle exceptions nicely
+ return GetEventHandler()->SafelyProcessEvent(event);
+}
+
// ----------------------------------------------------------------------------
// colours, fonts &c
// ----------------------------------------------------------------------------
wxColour wxWindowBase::GetBackgroundColour() const
{
- if ( !m_backgroundColour.Ok() )
+ if ( !m_backgroundColour.IsOk() )
{
wxASSERT_MSG( !m_hasBgCol, _T("we have invalid explicit bg colour?") );
{
wxColour colFg = GetDefaultAttributes().colFg;
- if ( !colFg.Ok() )
+ if ( !colFg.IsOk() )
colFg = GetClassDefaultAttributes().colFg;
return colFg;
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;
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() );
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;
}
m_font = font;
- m_hasFont = font.Ok();
+ m_hasFont = font.IsOk();
m_inheritFont = m_hasFont;
InvalidateBestSize();
// 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__
if ( id == m_windowId )
return (wxWindow *)this;
- wxWindowBase *res = (wxWindow *)NULL;
+ wxWindowBase *res = NULL;
wxWindowList::compatibility_iterator node;
for ( node = m_children.GetFirst(); node && !res; node = node->GetNext() )
{
if ( name == m_windowName )
return (wxWindow *)this;
- wxWindowBase *res = (wxWindow *)NULL;
+ wxWindowBase *res = NULL;
wxWindowList::compatibility_iterator node;
for ( node = m_children.GetFirst(); node && !res; node = node->GetNext() )
{
}
}
+#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;
}
// setting empty tooltip text does not remove the tooltip any more - use
- // SetToolTip((wxToolTip *)NULL) for this
+ // SetToolTip(NULL) for this
}
void wxWindowBase::DoSetToolTip(wxToolTip *tooltip)
}
delete m_constraintsInvolvedIn;
- m_constraintsInvolvedIn = (wxWindowList *) NULL;
+ m_constraintsInvolvedIn = NULL;
}
}
#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
//
gs_popupMenuSelection = event.GetId();
}
+void wxWindowBase::InternalOnPopupMenuUpdate(wxUpdateUIEvent& WXUNUSED(event))
+{
+ // nothing to do but do not skip it
+}
+
int
wxWindowBase::DoGetPopupMenuSelectionFromUser(wxMenu& menu, int x, int y)
{
NULL,
this);
+ // it is common to construct the menu passed to this function dynamically
+ // using some fixed range of ids which could clash with the ids used
+ // elsewhere in the program, which could result in some menu items being
+ // unintentionally disabled or otherwise modified by update UI handlers
+ // elsewhere in the program code and this is difficult to avoid in the
+ // program itself, so instead we just temporarily suspend UI updating while
+ // this menu is shown
+ Connect(wxEVT_UPDATE_UI,
+ wxUpdateUIEventHandler(wxWindowBase::InternalOnPopupMenuUpdate),
+ NULL,
+ this);
+
PopupMenu(&menu, x, y);
+ Disconnect(wxEVT_UPDATE_UI,
+ wxUpdateUIEventHandler(wxWindowBase::InternalOnPopupMenuUpdate),
+ NULL,
+ this);
Disconnect(wxEVT_COMMAND_MENU_SELECTED,
wxCommandEventHandler(wxWindowBase::InternalOnPopupMenu),
NULL,
static void DrawSizers(wxWindowBase *win);
-static void DrawBorder(wxWindowBase *win, const wxRect& rect, bool fill = false)
+static void DrawBorder(wxWindowBase *win, const wxRect& rect, bool fill, const wxPen* pen)
{
wxClientDC dc((wxWindow *)win);
- dc.SetPen(*wxRED_PEN);
- dc.SetBrush(fill ? wxBrush(*wxRED, wxCROSSDIAG_HATCH): *wxTRANSPARENT_BRUSH);
+ dc.SetPen(*pen);
+ dc.SetBrush(fill ? wxBrush(pen->GetColour(), wxBRUSHSTYLE_CROSSDIAG_HATCH) :
+ *wxTRANSPARENT_BRUSH);
dc.DrawRectangle(rect.Deflate(1, 1));
}
wxSizerItem *item = *i;
if ( item->IsSizer() )
{
- DrawBorder(win, item->GetRect().Deflate(2));
+ DrawBorder(win, item->GetRect().Deflate(2), false, wxRED_PEN);
DrawSizer(win, item->GetSizer());
}
else if ( item->IsSpacer() )
{
- DrawBorder(win, item->GetRect().Deflate(2), true);
+ DrawBorder(win, item->GetRect().Deflate(2), true, wxBLUE_PEN);
}
else if ( item->IsWindow() )
{
DrawSizers(item->GetWindow());
}
+ else
+ wxFAIL_MSG("inconsistent wxSizerItem status!");
}
}
static void DrawSizers(wxWindowBase *win)
{
+ DrawBorder(win, win->GetClientSize(), false, wxGREEN_PEN);
+
wxSizer *sizer = win->GetSizer();
if ( sizer )
{
- DrawBorder(win, win->GetClientSize());
DrawSizer(win, sizer);
}
else // no sizer, still recurse into the children
{
DrawSizers(*i);
}
+
+ // show all kind of sizes of this window; see the "window sizing" topic
+ // overview for more info about the various differences:
+ wxSize fullSz = win->GetSize();
+ wxSize clientSz = win->GetClientSize();
+ wxSize bestSz = win->GetBestSize();
+ wxSize minSz = win->GetMinSize();
+ wxSize maxSz = win->GetMaxSize();
+ wxSize virtualSz = win->GetVirtualSize();
+
+ wxMessageOutputDebug dbgout;
+ dbgout.Printf(
+ "%-10s => fullsz=%4d;%-4d clientsz=%4d;%-4d bestsz=%4d;%-4d minsz=%4d;%-4d maxsz=%4d;%-4d virtualsz=%4d;%-4d\n",
+ win->GetName(),
+ fullSz.x, fullSz.y,
+ clientSz.x, clientSz.y,
+ bestSz.x, bestSz.y,
+ minSz.x, minSz.y,
+ maxSz.x, maxSz.y,
+ virtualSz.x, virtualSz.y);
}
}
void wxWindowBase::CaptureMouse()
{
- wxLogTrace(_T("mousecapture"), _T("CaptureMouse(%p)"), wx_static_cast(void*, this));
+ wxLogTrace(_T("mousecapture"), _T("CaptureMouse(%p)"), static_cast<void*>(this));
wxASSERT_MSG( !ms_winCaptureChanging, _T("recursive CaptureMouse call?") );
void wxWindowBase::ReleaseMouse()
{
- wxLogTrace(_T("mousecapture"), _T("ReleaseMouse(%p)"), wx_static_cast(void*, this));
+ wxLogTrace(_T("mousecapture"), _T("ReleaseMouse(%p)"), static_cast<void*>(this));
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;
wxLogTrace(_T("mousecapture"),
(const wxChar *) _T("After ReleaseMouse() mouse is captured by %p"),
- wx_static_cast(void*, GetCapture()));
+ static_cast<void*>(GetCapture()));
}
static void DoNotifyWindowAboutCaptureLost(wxWindow *win)
// is receiving the event
if ( event.GetEventObject() == this )
{
- wxValidator *validator = GetValidator();
- if ( validator && validator->ProcessEvent(event) )
+ wxValidator * const validator = GetValidator();
+ if ( validator && validator->ProcessEventHere(event) )
{
return true;
}
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();
+}
+
+// ----------------------------------------------------------------------------
+// drag and drop
+// ----------------------------------------------------------------------------
+
+#if wxUSE_DRAG_AND_DROP && !defined(__WXMSW__)
+
+namespace
+{
+
+class DragAcceptFilesTarget : public wxFileDropTarget
+{
+public:
+ DragAcceptFilesTarget(wxWindowBase *win) : m_win(win) {}
+
+ virtual bool OnDropFiles(wxCoord x, wxCoord y,
+ const wxArrayString& filenames)
+ {
+ wxDropFilesEvent event(wxEVT_DROP_FILES,
+ filenames.size(),
+ wxCArrayString(filenames).Release());
+ event.SetEventObject(m_win);
+ event.m_pos.x = x;
+ event.m_pos.y = y;
+
+ return m_win->HandleWindowEvent(event);
+ }
+
+private:
+ wxWindowBase * const m_win;
+
+ wxDECLARE_NO_COPY_CLASS(DragAcceptFilesTarget);
+};
+
+
+} // anonymous namespace
+
+// Generic version of DragAcceptFiles(). It works by installing a simple
+// wxFileDropTarget-to-EVT_DROP_FILES adaptor and therefore cannot be used
+// together with explicit SetDropTarget() calls.
+void wxWindowBase::DragAcceptFiles(bool accept)
+{
+ if ( accept )
+ {
+ wxASSERT_MSG( !GetDropTarget(),
+ "cannot use DragAcceptFiles() and SetDropTarget() together" );
+ SetDropTarget(new DragAcceptFilesTarget(this));
+ }
+ else
+ {
+ SetDropTarget(NULL);
+ }
+}
+
+#endif // wxUSE_DRAG_AND_DROP && !defined(__WXMSW__)
+
// ----------------------------------------------------------------------------
// 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);
-}