#include "wx/statusbr.h"
#include "wx/toolbar.h"
#include "wx/dcclient.h"
-#endif //WX_PRECOMP
-
-#if defined(__WXMAC__) && wxUSE_SCROLLBAR
#include "wx/scrolbar.h"
-#endif
-
-#if wxUSE_CONSTRAINTS
#include "wx/layout.h"
-#endif // wxUSE_CONSTRAINTS
-
-#include "wx/sizer.h"
+ #include "wx/sizer.h"
+#endif //WX_PRECOMP
#if wxUSE_DRAG_AND_DROP
#include "wx/dnd.h"
#else
#include <gtk/gtkfeatures.h>
#endif
- extern const unsigned int gtk_major_version;
- extern const unsigned int gtk_minor_version;
- extern const unsigned int gtk_micro_version;
#endif
+#include "wx/platinfo.h"
+
+// Windows List
+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)
m_windowSizer = (wxSizer *) NULL;
m_containingSizer = (wxSizer *) NULL;
m_autoLayout = false;
+ m_freeId = false;
#if wxUSE_DRAG_AND_DROP
m_dropTarget = (wxDropTarget *)NULL;
m_virtualSize = wxDefaultSize;
- m_minVirtualWidth =
- m_maxVirtualWidth = wxDefaultCoord;
- m_minVirtualHeight =
- m_maxVirtualHeight = wxDefaultCoord;
+ m_scrollHelper = (wxScrollHelper *) NULL;
m_windowVariant = wxWINDOW_VARIANT_NORMAL;
#if wxUSE_SYSTEM_OPTIONS
// 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
+ // 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
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
// ----------------------------------------------------------------------------
{
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
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 )
- {
- if ( m_parent->GetDefaultItem() == this )
- {
- m_parent->SetDefaultItem(NULL);
- }
-
m_parent->RemoveChild(this);
- }
#if wxUSE_CARET
delete m_caret;
#endif
}
+void wxWindowBase::SendDestroyEvent()
+{
+ wxWindowDestroyEvent event;
+ event.SetEventObject(this);
+ event.SetId(GetId());
+ GetEventHandler()->ProcessEvent(event);
+}
+
bool wxWindowBase::Destroy()
{
delete this;
{
if ( !GetChildren().empty() )
{
- SetClientSize(GetBestSize());
+ SetSize(GetBestSize());
}
//else: do nothing if we have no children
}
if ( m_windowSizer )
{
- best = GetWindowSizeForVirtualSize(m_windowSizer->GetMinSize());
+ best = m_windowSizer->GetMinSize();
}
#if wxUSE_CONSTRAINTS
else if ( m_constraints )
#endif
)
{
- // our minimal acceptable size is such that all our visible child windows fit inside
+ // our minimal acceptable size is such that all our visible child
+ // windows fit inside
int maxX = 0,
maxY = 0;
node = node->GetNext() )
{
wxWindow *win = node->GetData();
- if ( win->IsTopLevel() || ( ! win->IsShown() )
+ if ( win->IsTopLevel()
+ || !win->IsShown()
#if wxUSE_STATUSBAR
- || wxDynamicCast(win, wxStatusBar)
+ || wxDynamicCast(win, wxStatusBar)
#endif // wxUSE_STATUSBAR
)
{
maxY = wy + wh;
}
- // for compatibility with the old versions and because it really looks
- // slightly more pretty like this, add a pad
- maxX += 7;
- maxY += 14;
-
best = wxSize(maxX, maxY);
}
else // ! has children
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::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;
-wxSize wxWindowBase::GetBestFittingSize() const
+ 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();
}
-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)
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 )
SetFont(font);
}
-void wxWindowBase::SetVirtualSizeHints( int minW, int minH,
- int maxW, int maxH )
+void wxWindowBase::DoSetSizeHints( int minW, int minH,
+ int maxW, int maxH,
+ int WXUNUSED(incW), int WXUNUSED(incH) )
{
- m_minVirtualWidth = minW;
- m_maxVirtualWidth = maxW;
- m_minVirtualHeight = minH;
- m_maxVirtualHeight = maxH;
+ 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::DoSetVirtualSize( int x, int y )
+
+#if WXWIN_COMPATIBILITY_2_8
+void wxWindowBase::SetVirtualSizeHints(int WXUNUSED(minW), int WXUNUSED(minH),
+ int WXUNUSED(maxW), int WXUNUSED(maxH))
{
- 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;
+}
+void wxWindowBase::SetVirtualSizeHints(const wxSize& WXUNUSED(minsize),
+ const wxSize& WXUNUSED(maxsize))
+{
+}
+#endif // WXWIN_COMPATIBILITY_2_8
+
+void wxWindowBase::DoSetVirtualSize( int x, int y )
+{
m_virtualSize = wxSize(x, y);
}
}
}
-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
// ----------------------------------------------------------------------------
return false;
}
+ const bool oldEnabledState = IsEnabled();
+
// unlink this window from the existing parent.
if ( oldParent )
{
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;
}
return false;
}
+bool wxWindowBase::HandleWindowEvent(wxEvent& event) const
+{
+ return GetEventHandler()->SafelyProcessEvent(event);
+}
+
// ----------------------------------------------------------------------------
// colours, fonts &c
// ----------------------------------------------------------------------------
// logic is the same as above
if ( !m_hasFgCol && !m_foregroundColour.Ok() )
{
- wxASSERT_MSG( !m_hasFgCol, _T("we have invalid explicit fg colour?") );
-
wxColour colFg = GetDefaultAttributes().colFg;
if ( !colFg.Ok() )
{
// 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;
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;
}
}
// get the help string associated with this window (may be empty)
-wxString wxWindowBase::GetHelpText() const
+// default implementation forwards calls to the help provider
+wxString
+wxWindowBase::GetHelpTextAtPoint(const wxPoint & WXUNUSED(pt),
+ wxHelpEvent::Origin WXUNUSED(origin)) const
{
wxString text;
wxHelpProvider *helpProvider = wxHelpProvider::Get();
wxHelpProvider *helpProvider = wxHelpProvider::Get();
if ( helpProvider )
{
- if ( helpProvider->ShowHelp(this) )
+ if ( helpProvider->ShowHelpAtPoint(this, event.GetPosition(), event.GetOrigin()) )
{
// skip the event.Skip() below
return;
#endif // wxUSE_HELP
// ----------------------------------------------------------------------------
-// tooltipsroot.Replace("\\", "/");
+// tooltips
// ----------------------------------------------------------------------------
#if wxUSE_TOOLTIPS
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)
}
// ----------------------------------------------------------------------------
-// do Update UI processing for child controls
+// Update UI processing
// ----------------------------------------------------------------------------
void wxWindowBase::UpdateWindowUI(long flags)
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
// ----------------------------------------------------------------------------
UpdateWindowUI(wxUPDATE_UI_RECURSE);
}
+// ----------------------------------------------------------------------------
+// menu-related functions
+// ----------------------------------------------------------------------------
+
+#if wxUSE_MENUS
+
+// this is used to pass the id of the selected item from the menu event handler
+// to the main function itself
+//
+// it's ok to use a global here as there can be at most one popup menu shown at
+// any time
+static int gs_popupMenuSelection = wxID_NONE;
+
+void wxWindowBase::InternalOnPopupMenu(wxCommandEvent& event)
+{
+ // store the id in a global variable where we'll retrieve it from later
+ gs_popupMenuSelection = event.GetId();
+}
+
+int
+wxWindowBase::DoGetPopupMenuSelectionFromUser(wxMenu& menu, int x, int y)
+{
+ gs_popupMenuSelection = wxID_NONE;
+
+ Connect(wxEVT_COMMAND_MENU_SELECTED,
+ wxCommandEventHandler(wxWindowBase::InternalOnPopupMenu),
+ NULL,
+ this);
+
+ PopupMenu(&menu, x, y);
+
+ Disconnect(wxEVT_COMMAND_MENU_SELECTED,
+ wxCommandEventHandler(wxWindowBase::InternalOnPopupMenu),
+ NULL,
+ this);
+
+ return gs_popupMenuSelection;
+}
+
+#endif // wxUSE_MENUS
+
// methods for drawing the sizers in a visible way
#ifdef __WXDEBUG__
return;
}
#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,
-#if wxUSE_UNICODE
- L" (Unicode)",
-#else
- "",
-#endif
-#ifdef __WXDEBUG__
- _T(" Debug build"),
-#else
- wxEmptyString,
-#endif
- __TDATE__,
- __TTIME__,
-#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()
-#else
- ""
-#endif
- ),
- _T("wxWidgets information"),
- wxICON_INFORMATION | wxOK,
- (wxWindow *)this);
+ ::wxInfoMessageBox((wxWindow*)this);
}
else
-#endif // wxUSE_MSGDLG
{
event.Skip();
}
#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
{
border = GetDefaultBorder();
}
+ else if ( border == wxBORDER_THEME )
+ {
+ border = GetDefaultBorderForControl();
+ }
return border;
}
wxWindow *win;
wxWindowNext *next;
} *wxWindowBase::ms_winCaptureNext = NULL;
+wxWindow *wxWindowBase::ms_winCaptureCurrent = NULL;
+bool wxWindowBase::ms_winCaptureChanging = false;
void wxWindowBase::CaptureMouse()
{
- wxLogTrace(_T("mousecapture"), _T("CaptureMouse(%p)"), this);
+ wxLogTrace(_T("mousecapture"), _T("CaptureMouse(%p)"), wx_static_cast(void*, this));
+
+ wxASSERT_MSG( !ms_winCaptureChanging, _T("recursive CaptureMouse call?") );
+
+ ms_winCaptureChanging = true;
wxWindow *winOld = GetCapture();
if ( winOld )
//else: no mouse capture to save
DoCaptureMouse();
+ ms_winCaptureCurrent = (wxWindow*)this;
+
+ ms_winCaptureChanging = false;
}
void wxWindowBase::ReleaseMouse()
{
- wxLogTrace(_T("mousecapture"), _T("ReleaseMouse(%p)"), this);
+ wxLogTrace(_T("mousecapture"), _T("ReleaseMouse(%p)"), wx_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") );
+ ms_winCaptureChanging = true;
+
DoReleaseMouse();
+ ms_winCaptureCurrent = NULL;
if ( ms_winCaptureNext )
{
((wxWindowBase*)ms_winCaptureNext->win)->DoCaptureMouse();
+ ms_winCaptureCurrent = ms_winCaptureNext->win;
wxWindowNext *item = ms_winCaptureNext;
ms_winCaptureNext = item->next;
}
//else: stack is empty, no previous capture
+ ms_winCaptureChanging = false;
+
wxLogTrace(_T("mousecapture"),
(const wxChar *) _T("After ReleaseMouse() mouse is captured by %p"),
- GetCapture());
+ wx_static_cast(void*, GetCapture()));
+}
+
+static void DoNotifyWindowAboutCaptureLost(wxWindow *win)
+{
+ wxMouseCaptureLostEvent event(win->GetId());
+ event.SetEventObject(win);
+ 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 */
+void wxWindowBase::NotifyCaptureLost()
+{
+ // don't do anything if capture lost was expected, i.e. resulted from
+ // a wx call to ReleaseMouse or CaptureMouse:
+ if ( ms_winCaptureChanging )
+ return;
+
+ // if the capture was lost unexpectedly, notify every window that has
+ // capture (on stack or current) about it and clear the stack:
+
+ if ( ms_winCaptureCurrent )
+ {
+ DoNotifyWindowAboutCaptureLost(ms_winCaptureCurrent);
+ ms_winCaptureCurrent = NULL;
+ }
+
+ while ( ms_winCaptureNext )
+ {
+ wxWindowNext *item = ms_winCaptureNext;
+ ms_winCaptureNext = item->next;
+
+ DoNotifyWindowAboutCaptureLost(item->win);
+
+ delete item;
+ }
}
#if wxUSE_HOTKEY
#endif // wxUSE_HOTKEY
-void wxWindowBase::SendDestroyEvent()
-{
- wxWindowDestroyEvent event;
- event.SetEventObject(this);
- event.SetId(GetId());
- GetEventHandler()->ProcessEvent(event);
-}
-
// ----------------------------------------------------------------------------
// event processing
// ----------------------------------------------------------------------------
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.
-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
+ wxUnusedVar(flags);
+ 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)
+void wxWindowBase::DoMoveInTabOrder(wxWindow *win, WindowOrder move)
{
// check that we're not a top level window
wxCHECK_RET( GetParent(),
// can't just move the node around
wxWindow *self = (wxWindow *)this;
siblings.DeleteObject(self);
- if ( move == MoveAfter )
+ if ( move == OrderAfter )
{
i = i->GetNext();
}
{
siblings.Insert(i, self);
}
- else // MoveAfter and win was the last sibling
+ else // OrderAfter and win was the last sibling
{
siblings.Append(self);
}
if (!GetWindow())
return wxACC_FAIL;
- wxString ht(GetWindow()->GetHelpText());
+ wxString ht(GetWindow()->GetHelpTextAtPoint(wxDefaultPosition, wxHelpEvent::Origin_Keyboard));
if (!ht.empty())
{
*description = ht;
if (!GetWindow())
return wxACC_FAIL;
- wxString ht(GetWindow()->GetHelpText());
+ wxString ht(GetWindow()->GetHelpTextAtPoint(wxDefaultPosition, wxHelpEvent::Origin_Keyboard));
if (!ht.empty())
{
*helpText = ht;
return wxACC_NOT_IMPLEMENTED;
}
+#if wxUSE_VARIANT
// Gets a variant representing the selected children
// of this object.
// Acceptable values:
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;
+}
+
+// ----------------------------------------------------------------------------
+// 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);
+}