X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/c4bcd8fcdd68108448a4a839f78adaf4b524bd82..94534bf8db5c1f5fefc9682bcda0f6e84d3e6667:/src/univ/winuniv.cpp diff --git a/src/univ/winuniv.cpp b/src/univ/winuniv.cpp index dbb420c484..6d57da70e0 100644 --- a/src/univ/winuniv.cpp +++ b/src/univ/winuniv.cpp @@ -6,7 +6,7 @@ // Created: 06.08.00 // RCS-ID: $Id$ // Copyright: (c) 2000 SciTech Software, Inc. (www.scitechsoft.com) -// Licence: wxWindows license +// Licence: wxWindows licence /////////////////////////////////////////////////////////////////////////////// // =========================================================================== @@ -17,7 +17,7 @@ // headers // --------------------------------------------------------------------------- -#ifdef __GNUG__ +#if defined(__GNUG__) && !defined(NO_GCC_PRAGMA) #pragma implementation "univwindow.h" #endif @@ -39,6 +39,7 @@ #include "wx/frame.h" #endif // WX_PRECOMP +#include "wx/log.h" #include "wx/univ/colschem.h" #include "wx/univ/renderer.h" #include "wx/univ/theme.h" @@ -73,6 +74,8 @@ IMPLEMENT_DYNAMIC_CLASS(wxWindow, wxWindowGTK) #elif defined(__WXMGL__) IMPLEMENT_DYNAMIC_CLASS(wxWindow, wxWindowMGL) +#elif defined(__WXX11__) + IMPLEMENT_DYNAMIC_CLASS(wxWindow, wxWindowX11) #elif defined(__WXPM__) IMPLEMENT_DYNAMIC_CLASS(wxWindow, wxWindowOS2) #endif @@ -103,9 +106,12 @@ void wxWindow::Init() m_scrollbarVert = m_scrollbarHorz = (wxScrollBar *)NULL; - m_isCurrent = FALSE; + m_isCurrent = false; m_renderer = wxTheme::Get()->GetRenderer(); + + m_oldSize.x = wxDefaultCoord; + m_oldSize.y = wxDefaultCoord; } bool wxWindow::Create(wxWindow *parent, @@ -115,27 +121,74 @@ bool wxWindow::Create(wxWindow *parent, long style, const wxString& name) { + long actualStyle = style; + + // FIXME: may need this on other platforms +#ifdef __WXMSW__ + actualStyle &= ~wxVSCROLL; + actualStyle &= ~wxHSCROLL; +#endif + // we add wxCLIP_CHILDREN to get the same ("natural") behaviour under MSW // as under the other platforms if ( !wxWindowNative::Create(parent, id, pos, size, - style | wxCLIP_CHILDREN, + actualStyle | wxCLIP_CHILDREN, name) ) { - return FALSE; + return false; } - // if we should always have the scrollbar, do show it - if ( GetWindowStyle() & wxALWAYS_SHOW_SB ) + // Set full style again, including those we didn't want present + // when calling the base window Create(). + wxWindowBase::SetWindowStyleFlag(style); + + // if we should always have a vertical scrollbar, do show it + if ( style & wxALWAYS_SHOW_SB ) { - m_scrollbarVert = new wxScrollBar(this, -1, +#if wxUSE_TWO_WINDOWS + SetInsertIntoMain( true ); +#endif + m_scrollbarVert = new wxScrollBar(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxSB_VERTICAL); +#if wxUSE_TWO_WINDOWS + SetInsertIntoMain( false ); +#endif + } + + // if we should always have a horizontal scrollbar, do show it + if ( style & wxHSCROLL ) + { +#if wxUSE_TWO_WINDOWS + SetInsertIntoMain( true ); +#endif + m_scrollbarHorz = new wxScrollBar(this, wxID_ANY, + wxDefaultPosition, wxDefaultSize, + wxSB_HORIZONTAL); +#if wxUSE_TWO_WINDOWS + SetInsertIntoMain( false ); +#endif + } - // and position it + if (m_scrollbarHorz || m_scrollbarVert) + { + // position it/them PositionScrollbars(); } - return TRUE; + return true; +} + +wxWindow::~wxWindow() +{ + m_isBeingDeleted = true; + + // we have to destroy our children before we're destroyed because our + // children suppose that we're of type wxWindow, not just wxWindowNative, + // and so bad things may happen if they're deleted from the base class dtor + // as by then we're not a wxWindow any longer and wxUniv-specific virtual + // functions can't be called + DestroyChildren(); } // ---------------------------------------------------------------------------- @@ -169,41 +222,8 @@ const wxBitmap& wxWindow::GetBackgroundBitmap(int *alignment, // painting // ---------------------------------------------------------------------------- -// the event handler executed when the window background must be painted -void wxWindow::OnErase(wxEraseEvent& event) -{ - if ( !m_renderer ) - { - event.Skip(); - - return; - } - - DoDrawBackground(*event.GetDC()); - - // if we have both scrollbars, we also have a square in the corner between - // them which we must paint - if ( m_scrollbarVert && m_scrollbarHorz ) - { - wxSize size = GetSize(); - wxRect rectClient = GetClientRect(), - rectBorder = m_renderer->GetBorderDimensions(GetBorder()); - - wxRect rectCorner; - rectCorner.x = rectClient.GetRight() + 1; - rectCorner.y = rectClient.GetBottom() + 1; - rectCorner.SetRight(size.x - rectBorder.width); - rectCorner.SetBottom(size.y - rectBorder.height); - - if ( GetUpdateRegion().Contains(rectCorner) ) - { - m_renderer->DrawScrollCorner(*event.GetDC(), rectCorner); - } - } -} - // the event handlers executed when the window must be repainted -void wxWindow::OnNcPaint(wxPaintEvent& event) +void wxWindow::OnNcPaint(wxNcPaintEvent& WXUNUSED(event)) { if ( m_renderer ) { @@ -252,43 +272,101 @@ void wxWindow::OnPaint(wxPaintEvent& event) } } +// the event handler executed when the window background must be painted +void wxWindow::OnErase(wxEraseEvent& event) +{ + if ( !m_renderer ) + { + event.Skip(); + + return; + } + + DoDrawBackground(*event.GetDC()); + + // if we have both scrollbars, we also have a square in the corner between + // them which we must paint + if ( m_scrollbarVert && m_scrollbarHorz ) + { + wxSize size = GetSize(); + wxRect rectClient = GetClientRect(), + rectBorder = m_renderer->GetBorderDimensions(GetBorder()); + + wxRect rectCorner; + rectCorner.x = rectClient.GetRight() + 1; + rectCorner.y = rectClient.GetBottom() + 1; + rectCorner.SetRight(size.x - rectBorder.width); + rectCorner.SetBottom(size.y - rectBorder.height); + + if ( GetUpdateRegion().Contains(rectCorner) ) + { + m_renderer->DrawScrollCorner(*event.GetDC(), rectCorner); + } + } +} + bool wxWindow::DoDrawBackground(wxDC& dc) { - // FIXME: leaving this code in leads to partial bg redraws sometimes under - // MSW wxRect rect; -#ifndef __WXMSW__ - rect = GetUpdateRegion().GetBox(); - if ( !rect.width && !rect.height ) -#endif + + wxSize size = GetSize(); // Why not GetClientSize() ? + rect.x = 0; + rect.y = 0; + rect.width = size.x; + rect.height = size.y; + + wxWindow * const parent = GetParent(); + if ( HasTransparentBackground() && parent && parent->ProvidesBackground() ) { - wxSize size = GetSize(); - rect.width = size.x; - rect.height = size.y; + wxASSERT( !IsTopLevel() ); + + wxPoint pos = GetPosition(); + + AdjustForParentClientOrigin( pos.x, pos.y, 0 ); + + // Adjust DC logical origin + wxCoord org_x, org_y, x, y; + dc.GetLogicalOrigin( &org_x, &org_y ); + x = org_x + pos.x; + y = org_y + pos.y; + dc.SetLogicalOrigin( x, y ); + + // Adjust draw rect + rect.x = pos.x; + rect.y = pos.y; + + // Let parent draw the background + parent->EraseBackground( dc, rect ); + + // Restore DC logical origin + dc.SetLogicalOrigin( org_x, org_y ); + } + else + { + // Draw background ouselves + EraseBackground( dc, rect ); } + return true; +} + +void wxWindow::EraseBackground(wxDC& dc, const wxRect& rect) +{ if ( GetBackgroundBitmap().Ok() ) { - // get the bitmap and the flags + // Get the bitmap and the flags int alignment; wxStretch stretch; wxBitmap bmp = GetBackgroundBitmap(&alignment, &stretch); wxControlRenderer::DrawBitmap(dc, bmp, rect, alignment, stretch); } - else // just fill it with bg colour if no bitmap + else { + // Just fill it with bg colour if no bitmap + m_renderer->DrawBackground(dc, wxTHEME_BG_COLOUR(this), rect, GetStateFlags()); } - - return TRUE; -} - -void wxWindow::EraseBackground(wxDC& dc, const wxRect& rect) -{ - // TODO: handle bg bitmaps here! - - m_renderer->DrawBackground(dc, wxTHEME_BG_COLOUR(this), rect, GetStateFlags()); } void wxWindow::DoDrawBorder(wxDC& dc, const wxRect& rect) @@ -303,7 +381,7 @@ void wxWindow::DoDrawBorder(wxDC& dc, const wxRect& rect) } } -void wxWindow::DoDraw(wxControlRenderer *renderer) +void wxWindow::DoDraw(wxControlRenderer * WXUNUSED(renderer)) { } @@ -337,7 +415,7 @@ void wxWindow::Refresh(bool eraseBackground, const wxRect *rectClient) // debugging helper #ifdef WXDEBUG_REFRESH - static bool s_refreshDebug = FALSE; + static bool s_refreshDebug = false; if ( s_refreshDebug ) { wxWindowDC dc(this); @@ -354,6 +432,19 @@ void wxWindow::Refresh(bool eraseBackground, const wxRect *rectClient) #endif // WXDEBUG_REFRESH wxWindowNative::Refresh(eraseBackground, &rectWin); + + // Refresh all sub controls if any. + wxWindowList::compatibility_iterator node = GetChildren().GetFirst(); + while ( node ) + { + wxWindow *win = node->GetData(); + // Only refresh sub controls when it is visible + // and when it is in the update region. + if(!win->IsKindOf(CLASSINFO(wxTopLevelWindow)) && win->IsShown() && wxRegion(rectWin).Contains(win->GetRect()) != wxOutRegion) + win->Refresh(eraseBackground, &rectWin); + + node = node->GetNext(); + } } // ---------------------------------------------------------------------------- @@ -363,7 +454,7 @@ void wxWindow::Refresh(bool eraseBackground, const wxRect *rectClient) bool wxWindow::Enable(bool enable) { if ( !wxWindowNative::Enable(enable) ) - return FALSE; + return false; // disabled window can't keep focus if ( FindFocus() == this && GetParent() != NULL ) @@ -378,7 +469,7 @@ bool wxWindow::Enable(bool enable) Refresh(); } - return TRUE; + return true; } bool wxWindow::IsFocused() const @@ -389,12 +480,12 @@ bool wxWindow::IsFocused() const bool wxWindow::IsPressed() const { - return FALSE; + return false; } bool wxWindow::IsDefault() const { - return FALSE; + return false; } bool wxWindow::IsCurrent() const @@ -405,14 +496,14 @@ bool wxWindow::IsCurrent() const bool wxWindow::SetCurrent(bool doit) { if ( doit == m_isCurrent ) - return FALSE; + return false; m_isCurrent = doit; if ( CanBeHighlighted() ) Refresh(); - return TRUE; + return true; } int wxWindow::GetStateFlags() const @@ -444,12 +535,114 @@ int wxWindow::GetStateFlags() const void wxWindow::OnSize(wxSizeEvent& event) { + event.Skip(); + if ( m_scrollbarVert || m_scrollbarHorz ) { PositionScrollbars(); } - event.Skip(); +#if 0 // ndef __WXMSW__ + // Refresh the area (strip) previously occupied by the border + + if ( !HasFlag(wxFULL_REPAINT_ON_RESIZE) && IsShown() ) + { + // This code assumes that wxSizeEvent.GetSize() returns + // the area of the entire window, not just the client + // area. + wxSize newSize = event.GetSize(); + + if (m_oldSize.x == wxDefaultCoord && m_oldSize.y == wxDefaultCoord) + { + m_oldSize = newSize; + return; + } + + if (HasFlag( wxSIMPLE_BORDER )) + { + if (newSize.y > m_oldSize.y) + { + wxRect rect; + rect.x = 0; + rect.width = m_oldSize.x; + rect.y = m_oldSize.y-2; + rect.height = 1; + Refresh( true, &rect ); + } + else if (newSize.y < m_oldSize.y) + { + wxRect rect; + rect.y = newSize.y; + rect.x = 0; + rect.height = 1; + rect.width = newSize.x; + wxWindowNative::Refresh( true, &rect ); + } + + if (newSize.x > m_oldSize.x) + { + wxRect rect; + rect.y = 0; + rect.height = m_oldSize.y; + rect.x = m_oldSize.x-2; + rect.width = 1; + Refresh( true, &rect ); + } + else if (newSize.x < m_oldSize.x) + { + wxRect rect; + rect.x = newSize.x; + rect.y = 0; + rect.width = 1; + rect.height = newSize.y; + wxWindowNative::Refresh( true, &rect ); + } + } + else + if (HasFlag( wxSUNKEN_BORDER ) || HasFlag( wxRAISED_BORDER )) + { + if (newSize.y > m_oldSize.y) + { + wxRect rect; + rect.x = 0; + rect.width = m_oldSize.x; + rect.y = m_oldSize.y-4; + rect.height = 2; + Refresh( true, &rect ); + } + else if (newSize.y < m_oldSize.y) + { + wxRect rect; + rect.y = newSize.y; + rect.x = 0; + rect.height = 2; + rect.width = newSize.x; + wxWindowNative::Refresh( true, &rect ); + } + + if (newSize.x > m_oldSize.x) + { + wxRect rect; + rect.y = 0; + rect.height = m_oldSize.y; + rect.x = m_oldSize.x-4; + rect.width = 2; + Refresh( true, &rect ); + } + else if (newSize.x < m_oldSize.x) + { + wxRect rect; + rect.x = newSize.x; + rect.y = 0; + rect.width = 2; + rect.height = newSize.y; + wxWindowNative::Refresh( true, &rect ); + } + } + + m_oldSize = newSize; + } +#endif } wxSize wxWindow::DoGetBestSize() const @@ -474,8 +667,11 @@ wxPoint wxWindow::GetClientAreaOrigin() const { wxPoint pt = wxWindowBase::GetClientAreaOrigin(); +#if wxUSE_TWO_WINDOWS +#else if ( m_renderer ) pt += m_renderer->GetBorderDimensions(GetBorder()).GetPosition(); +#endif return pt; } @@ -657,24 +853,30 @@ void wxWindow::SetScrollbar(int orient, wxASSERT_MSG( pageSize <= range, _T("page size can't be greater than range") ); - bool hasClientSizeChanged = FALSE; + bool hasClientSizeChanged = false; wxScrollBar *scrollbar = GetScrollbar(orient); if ( range && (pageSize < range) ) { if ( !scrollbar ) { // create it - scrollbar = new wxScrollBar(this, -1, +#if wxUSE_TWO_WINDOWS + SetInsertIntoMain( true ); +#endif + scrollbar = new wxScrollBar(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, orient & wxVERTICAL ? wxSB_VERTICAL : wxSB_HORIZONTAL); +#if wxUSE_TWO_WINDOWS + SetInsertIntoMain( false ); +#endif if ( orient & wxVERTICAL ) m_scrollbarVert = scrollbar; else m_scrollbarHorz = scrollbar; // the client area diminished as we created a scrollbar - hasClientSizeChanged = TRUE; + hasClientSizeChanged = true; PositionScrollbars(); } @@ -707,7 +909,7 @@ void wxWindow::SetScrollbar(int orient, m_scrollbarHorz = NULL; // the client area increased as we removed a scrollbar - hasClientSizeChanged = TRUE; + hasClientSizeChanged = true; // the size of the remaining scrollbar must be adjusted if ( m_scrollbarHorz || m_scrollbarVert ) @@ -721,12 +923,16 @@ void wxWindow::SetScrollbar(int orient, // give the window a chance to relayout if ( hasClientSizeChanged ) { +#if wxUSE_TWO_WINDOWS + wxWindowNative::SetSize( GetSize() ); +#else wxSizeEvent event(GetSize()); (void)GetEventHandler()->ProcessEvent(event); +#endif } } -void wxWindow::SetScrollPos(int orient, int pos, bool refresh) +void wxWindow::SetScrollPos(int orient, int pos, bool WXUNUSED(refresh)) { wxScrollBar *scrollbar = GetScrollbar(orient); wxCHECK_RET( scrollbar, _T("no scrollbar to set position for") ); @@ -761,6 +967,14 @@ int wxWindow::GetScrollRange(int orient) const void wxWindow::ScrollWindow(int dx, int dy, const wxRect *rect) { + // use native scrolling when available and do it in generic way + // otherwise: +#ifdef __WXX11__ + + wxWindowNative::ScrollWindow(dx, dy, rect); + +#else // !wxX11 + // before scrolling it, ensure that we don't have any unpainted areas Update(); @@ -769,14 +983,53 @@ void wxWindow::ScrollWindow(int dx, int dy, const wxRect *rect) if ( dx ) { r = ScrollNoRefresh(dx, 0, rect); - Refresh(TRUE /* erase bkgnd */, &r); + Refresh(true /* erase bkgnd */, &r); } if ( dy ) { r = ScrollNoRefresh(0, dy, rect); - Refresh(TRUE /* erase bkgnd */, &r); + Refresh(true /* erase bkgnd */, &r); } + + // scroll children accordingly: + wxPoint offset(dx, dy); + + for (wxWindowList::compatibility_iterator node = GetChildren().GetFirst(); + node; node = node->GetNext()) + { + wxWindow *child = node->GetData(); + if ( child == m_scrollbarVert || child == m_scrollbarHorz ) + continue; + + // VS: Scrolling children has non-trivial semantics. If rect=NULL then + // it is easy: we scroll all children. Otherwise it gets + // complicated: + // 1. if scrolling in one direction only, scroll only + // those children that intersect shaft defined by the rectangle + // and scrolling direction + // 2. if scrolling in both axes, scroll all children + + if ( rect && (dx * dy == 0 /* moving in only one of x, y axis */) ) + { + wxRect childRect = child->GetRect(); + if ( dx == 0 && (childRect.GetLeft() <= rect->GetRight() || + childRect.GetRight() >= rect->GetLeft()) ) + { + child->Move(child->GetPosition() + offset); + } + else if ( dy == 0 && (childRect.GetTop() <= rect->GetBottom() || + childRect.GetBottom() >= rect->GetTop()) ) + { + child->Move(child->GetPosition() + offset); + } + } + else + { + child->Move(child->GetPosition() + offset); + } + } +#endif // wxX11/!wxX11 } wxRect wxWindow::ScrollNoRefresh(int dx, int dy, const wxRect *rectTotal) @@ -933,53 +1186,6 @@ wxRect wxWindow::ScrollNoRefresh(int dx, int dy, const wxRect *rectTotal) return rect; } -// ---------------------------------------------------------------------------- -// mouse capture -// ---------------------------------------------------------------------------- - -struct WXDLLEXPORT wxWindowNext -{ - wxWindow *win; - wxWindowNext *next; -} *wxWindow::ms_winCaptureNext = NULL; - -void wxWindow::CaptureMouse() -{ - wxLogTrace(_T("mousecapture"), _T("CaptureMouse(0x%08x)"), this); - - wxWindow *winOld = GetCapture(); - if ( winOld ) - { - // save it on stack - wxWindowNext *item = new wxWindowNext; - item->win = winOld; - item->next = ms_winCaptureNext; - ms_winCaptureNext = item; - } - //else: no mouse capture to save - - wxWindowNative::CaptureMouse(); -} - -void wxWindow::ReleaseMouse() -{ - wxWindowNative::ReleaseMouse(); - - if ( ms_winCaptureNext ) - { - ms_winCaptureNext->win->CaptureMouse(); - - wxWindowNext *item = ms_winCaptureNext; - ms_winCaptureNext = item->next; - delete item; - } - //else: stack is empty, no previous capture - - wxLogTrace(_T("mousecapture"), - _T("After ReleaseMouse() mouse is captured by 0x%08x"), - GetCapture()); -} - // ---------------------------------------------------------------------------- // accelerators and menu hot keys // ---------------------------------------------------------------------------- @@ -1036,6 +1242,22 @@ void wxWindow::OnKeyDown(wxKeyEvent& event) } #endif // wxUSE_MENUS + // if it wasn't in a menu, try to find a button + if ( command != -1 ) + { + wxWindow* child = win->FindWindow(command); + if ( child && wxDynamicCast(child, wxButton) ) + { + wxCommandEvent eventCmd(wxEVT_COMMAND_BUTTON_CLICKED, command); + eventCmd.SetEventObject(child); + if ( child->GetEventHandler()->ProcessEvent(eventCmd) ) + { + // skip "event.Skip()" below + return; + } + } + } + // don't propagate accels from the child frame to the parent one break; } @@ -1121,3 +1343,29 @@ void wxWindow::OnKeyUp(wxKeyEvent& event) #endif // wxUSE_MENUS +// ---------------------------------------------------------------------------- +// MSW-specific section +// ---------------------------------------------------------------------------- + +#ifdef __WXMSW__ + +#include "wx/msw/private.h" + +WXLRESULT wxWindow::MSWWindowProc(WXUINT message, WXWPARAM wParam, WXLPARAM lParam) +{ + if ( message == WM_NCHITTEST ) + { + // the windows which contain the other windows should let the mouse + // events through, otherwise a window inside a static box would + // never get any events at all + if ( IsStaticBox() ) + { + return HTTRANSPARENT; + } + } + + return wxWindowNative::MSWWindowProc(message, wParam, lParam); +} + +#endif // __WXMSW__ +