X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/7e0f753950f9c3fe004818b9d7ba733a22bd169d..fcdd53359135f790b85728c4254b97095a56dad8:/src/common/wincmn.cpp diff --git a/src/common/wincmn.cpp b/src/common/wincmn.cpp index 13ccfb0e47..a519ffd7f0 100644 --- a/src/common/wincmn.cpp +++ b/src/common/wincmn.cpp @@ -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 @@ -78,9 +79,6 @@ #else #include #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" @@ -88,17 +86,15 @@ // Windows List WXDLLIMPEXP_DATA_CORE(wxWindowList) wxTopLevelWindows; +// globals +#if wxUSE_MENUS +wxMenu *wxCurrentPopupMenu = NULL; +#endif // wxUSE_MENUS + // ---------------------------------------------------------------------------- // 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) @@ -202,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) ) @@ -220,6 +211,8 @@ wxWindowBase::wxWindowBase() // VZ: this one shouldn't exist... m_isBeingDeleted = false; + + m_freezeCount = 0; } // common part of window creation process @@ -245,11 +238,19 @@ bool wxWindowBase::CreateBase(wxWindowBase *parent, // 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(); + } + 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 @@ -316,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 @@ -361,6 +369,20 @@ 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 +} + +bool wxWindowBase::IsBeingDeleted() const +{ + return m_isBeingDeleted || + (!IsTopLevel() && m_parent && m_parent->IsBeingDeleted()); } void wxWindowBase::SendDestroyEvent() @@ -386,7 +408,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() @@ -602,9 +624,10 @@ wxSize wxWindowBase::DoGetBestSize() const // 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(const_cast(win))); if ( rc == -1 ) { switch ( what ) @@ -642,23 +665,23 @@ wxSize wxWindowBase::GetWindowBorderSize() const 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: @@ -705,6 +728,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 ) @@ -765,26 +804,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); } @@ -815,6 +848,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 // ---------------------------------------------------------------------------- @@ -886,8 +936,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()); } // ---------------------------------------------------------------------------- @@ -899,6 +952,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 // ---------------------------------------------------------------------------- @@ -914,12 +1013,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); } @@ -1045,6 +1157,11 @@ bool wxWindowBase::RemoveEventHandler(wxEvtHandler *handler) return false; } +bool wxWindowBase::HandleWindowEvent(wxEvent& event) const +{ + return GetEventHandler()->SafelyProcessEvent(event); +} + // ---------------------------------------------------------------------------- // colours, fonts &c // ---------------------------------------------------------------------------- @@ -1105,7 +1222,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?") ); @@ -1131,11 +1248,9 @@ wxColour wxWindowBase::GetForegroundColour() const // 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; @@ -1149,7 +1264,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; @@ -1164,7 +1279,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() ); @@ -1189,12 +1304,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; @@ -1212,7 +1327,7 @@ bool wxWindowBase::SetFont(const wxFont& font) } m_font = font; - m_hasFont = font.Ok(); + m_hasFont = font.IsOk(); m_inheritFont = m_hasFont; InvalidateBestSize(); @@ -1311,7 +1426,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__ @@ -1607,6 +1722,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) @@ -1617,6 +1733,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 @@ -1640,7 +1757,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; @@ -2238,6 +2377,79 @@ void wxWindowBase::OnInitDialog( wxInitDialogEvent &WXUNUSED(event) ) 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(); +} + +void wxWindowBase::InternalOnPopupMenuUpdate(wxUpdateUIEvent& WXUNUSED(event)) +{ + // nothing to do but do not skip it +} + +int +wxWindowBase::DoGetPopupMenuSelectionFromUser(wxMenu& menu, int x, int y) +{ + gs_popupMenuSelection = wxID_NONE; + + Connect(wxEVT_COMMAND_MENU_SELECTED, + wxCommandEventHandler(wxWindowBase::InternalOnPopupMenu), + 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, + this); + + return gs_popupMenuSelection; +} + +#endif // wxUSE_MENUS + // methods for drawing the sizers in a visible way #ifdef __WXDEBUG__ @@ -2247,7 +2459,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)); } @@ -2312,45 +2524,9 @@ void wxWindowBase::OnMiddleClick( wxMouseEvent& event ) 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(); } @@ -2415,6 +2591,10 @@ wxBorder wxWindowBase::GetBorder(long flags) const { border = GetDefaultBorder(); } + else if ( border == wxBORDER_THEME ) + { + border = GetDefaultBorderForControl(); + } return border; } @@ -2458,7 +2638,7 @@ bool wxWindowBase::ms_winCaptureChanging = false; void wxWindowBase::CaptureMouse() { - wxLogTrace(_T("mousecapture"), _T("CaptureMouse(%p)"), wx_static_cast(void*, this)); + wxLogTrace(_T("mousecapture"), _T("CaptureMouse(%p)"), static_cast(this)); wxASSERT_MSG( !ms_winCaptureChanging, _T("recursive CaptureMouse call?") ); @@ -2485,11 +2665,14 @@ void wxWindowBase::CaptureMouse() void wxWindowBase::ReleaseMouse() { - wxLogTrace(_T("mousecapture"), _T("ReleaseMouse(%p)"), wx_static_cast(void*, this)); + wxLogTrace(_T("mousecapture"), _T("ReleaseMouse(%p)"), static_cast(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; @@ -2511,7 +2694,7 @@ void wxWindowBase::ReleaseMouse() wxLogTrace(_T("mousecapture"), (const wxChar *) _T("After ReleaseMouse() mouse is captured by %p"), - wx_static_cast(void*, GetCapture())); + static_cast(GetCapture())); } static void DoNotifyWindowAboutCaptureLost(wxWindow *win) @@ -2586,8 +2769,8 @@ bool wxWindowBase::TryValidator(wxEvent& wxVALIDATOR_PARAM(event)) // 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; } @@ -2622,6 +2805,27 @@ bool wxWindowBase::TryParent(wxEvent& event) 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 // ---------------------------------------------------------------------------- @@ -2631,16 +2835,38 @@ 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; + 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 } -void wxWindowBase::DoMoveInTabOrder(wxWindow *win, MoveKind move) +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 wxCHECK_RET( GetParent(), @@ -2660,7 +2886,7 @@ void wxWindowBase::DoMoveInTabOrder(wxWindow *win, MoveKind move) // can't just move the node around wxWindow *self = (wxWindow *)this; siblings.DeleteObject(self); - if ( move == MoveAfter ) + if ( move == OrderAfter ) { i = i->GetNext(); } @@ -2669,7 +2895,7 @@ void wxWindowBase::DoMoveInTabOrder(wxWindow *win, MoveKind move) { siblings.Insert(i, self); } - else // MoveAfter and win was the last sibling + else // OrderAfter and win was the last sibling { siblings.Append(self); } @@ -2685,6 +2911,68 @@ void wxWindowBase::DoMoveInTabOrder(wxWindow *win, MoveKind move) 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; + + DECLARE_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 // ---------------------------------------------------------------------------- @@ -3139,3 +3427,4 @@ wxWindowBase::AdjustForLayoutDirection(wxCoord x, return x; } +