#include "wx/scrolbar.h"
#include "wx/layout.h"
#include "wx/sizer.h"
+ #include "wx/menu.h"
#endif //WX_PRECOMP
#if wxUSE_DRAG_AND_DROP
#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;
+// globals
+#if wxUSE_MENUS_NATIVE
+wxMenu *wxCurrentPopupMenu = NULL;
+#endif // wxUSE_MENUS_NATIVE
+
// ----------------------------------------------------------------------------
// 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_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) )
// 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
{
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);
- wxASSERT_MSG( GetChildren().GetCount() == 0, wxT("children not destroyed") );
-
- // reset the top-level parent's default item if it is this widget
- if ( m_parent )
- {
- wxTopLevelWindow *tlw = wxDynamicCast(wxGetTopLevelParent((wxWindow*)this),
- wxTopLevelWindow);
+ // The associated popup menu can still be alive, disassociate from it in
+ // this case
+ if ( wxCurrentPopupMenu && wxCurrentPopupMenu->GetInvokingWindow() == this )
+ wxCurrentPopupMenu->SetInvokingWindow(NULL);
- if ( tlw && tlw->GetDefaultItem() == this )
- tlw->SetDefaultItem(NULL);
- if ( tlw && tlw->GetTmpDefaultItem() == this )
- tlw->SetTmpDefaultItem(NULL);
- }
+ 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 )
- {
m_parent->RemoveChild(this);
- }
#if wxUSE_CARET
delete m_caret;
if ( m_windowSizer )
{
- // Adjust to window size, since the return value of GetWindowSizeForVirtualSize is
- // expressed in window and not client size
- wxSize minSize = m_windowSizer->GetMinSize();
- wxSize size(GetSize());
- wxSize clientSize(GetClientSize());
-
- wxSize minWindowSize(minSize.x + size.x - clientSize.x,
- minSize.y + size.y - clientSize.y);
-
- best = GetWindowSizeForVirtualSize(minWindowSize);
-
- return best;
+ best = m_windowSizer->GetMinSize();
}
#if wxUSE_CONSTRAINTS
else if ( m_constraints )
}
-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);
}
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;
}
+bool wxWindowBase::HandleWindowEvent(wxEvent& event) const
+{
+ 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?") );
// 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() )
+ 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();
UpdateWindowUI(wxUPDATE_UI_RECURSE);
}
+// ----------------------------------------------------------------------------
+// menu-related functions
+// ----------------------------------------------------------------------------
+
+#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
+//
+// 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, they're for diagnostics purposes only
- wxString msg;
- msg.Printf(_T("wxWidgets Library (%s port)\n")
- _T("Version %d.%d.%d%s%s, compiled at %s %s\n")
- _T("Runtime version of toolkit used is %d.%d.%s\n")
- _T("Copyright (c) 1995-2007 wxWidgets team"),
- wxPlatformInfo::Get().GetPortIdName().c_str(),
- wxMAJOR_VERSION,
- wxMINOR_VERSION,
- wxRELEASE_NUMBER,
-#if wxUSE_UNICODE
- L" (Unicode)",
-#else
- wxEmptyString,
-#endif
-#ifdef __WXDEBUG__
- _T(" Debug build"),
-#else
- wxEmptyString,
-#endif
- __TDATE__,
- __TTIME__,
- wxPlatformInfo::Get().GetToolkitMajorVersion(),
- wxPlatformInfo::Get().GetToolkitMinorVersion(),
-#ifdef __WXGTK__
- wxString::Format(_T("\nThe compile-time GTK+ version is %d.%d.%d."), GTK_MAJOR_VERSION, GTK_MINOR_VERSION, GTK_MICRO_VERSION).c_str()
-#else
- wxEmptyString
-#endif
- );
-
- wxMessageBox(msg, _T("wxWidgets information"),
- wxICON_INFORMATION | wxOK,
- (wxWindow *)this);
+ ::wxInfoMessageBox((wxWindow*)this);
}
else
-#endif // wxUSE_MSGDLG
{
event.Skip();
}
{
border = GetDefaultBorder();
}
+ else if ( border == wxBORDER_THEME )
+ {
+ border = GetDefaultBorderForControl();
+ }
return border;
}
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
// ----------------------------------------------------------------------------
{
#ifdef wxHAS_NATIVE_TAB_TRAVERSAL
// native code doesn't process our wxNavigationKeyEvents anyhow
+ wxUnusedVar(flags);
return false;
#else // !wxHAS_NATIVE_TAB_TRAVERSAL
wxNavigationKeyEvent 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);
}
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);
+}