X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/8cb172b4f12fae80b06d5936108a1bc7f2521674..a1d6c5df6f91f034663953fb5d43daa1b65187f3:/src/univ/winuniv.cpp diff --git a/src/univ/winuniv.cpp b/src/univ/winuniv.cpp index 5066ebe080..1842fc485e 100644 --- a/src/univ/winuniv.cpp +++ b/src/univ/winuniv.cpp @@ -1,12 +1,12 @@ /////////////////////////////////////////////////////////////////////////////// -// Name: univ/window.cpp +// Name: src/univ/winuniv.cpp // Purpose: implementation of extra wxWindow methods for wxUniv port // Author: Vadim Zeitlin // Modified by: // Created: 06.08.00 // RCS-ID: $Id$ -// Copyright: (c) 2000 Vadim Zeitlin -// Licence: wxWindows license +// Copyright: (c) 2000 SciTech Software, Inc. (www.scitechsoft.com) +// Licence: wxWindows licence /////////////////////////////////////////////////////////////////////////////// // =========================================================================== @@ -17,10 +17,6 @@ // headers // --------------------------------------------------------------------------- -#ifdef __GNUG__ - #pragma implementation "univwindow.h" -#endif - // For compilers that support precompilation, includes "wx.h". #include "wx/wxprec.h" @@ -28,36 +24,65 @@ #pragma hdrstop #endif +#include "wx/window.h" + #ifndef WX_PRECOMP #include "wx/app.h" - #include "wx/window.h" #include "wx/dcclient.h" #include "wx/dcmemory.h" #include "wx/event.h" #include "wx/scrolbar.h" #include "wx/menu.h" #include "wx/frame.h" + #include "wx/log.h" + #include "wx/button.h" #endif // WX_PRECOMP #include "wx/univ/colschem.h" #include "wx/univ/renderer.h" #include "wx/univ/theme.h" + #if wxUSE_CARET #include "wx/caret.h" #endif // wxUSE_CARET -// turn Refresh() debugging on/off -#define WXDEBUG_REFRESH +#if wxDEBUG_LEVEL >= 2 + // turn Refresh() debugging on/off + #define WXDEBUG_REFRESH +#endif -#ifndef __WXDEBUG__ - #undef WXDEBUG_REFRESH +#if defined(WXDEBUG_REFRESH) && defined(__WXMSW__) && !defined(__WXMICROWIN__) +#include "wx/msw/private.h" #endif // ============================================================================ // implementation // ============================================================================ +// ---------------------------------------------------------------------------- +// scrollbars class +// ---------------------------------------------------------------------------- + +// This is scrollbar class used to implement wxWindow's "built-in" scrollbars; +// unlike the standard wxScrollBar class, this one is positioned outside of its +// parent's client area +class wxWindowScrollBar : public wxScrollBar +{ +public: + wxWindowScrollBar(wxWindow *parent, + wxWindowID id, + const wxPoint& pos = wxDefaultPosition, + const wxSize& size = wxDefaultSize, + long style = wxSB_HORIZONTAL) + : wxScrollBar(parent, id, pos, size, style) + { + } + + virtual bool CanBeOutsideClientArea() const { return true; } +}; + + // ---------------------------------------------------------------------------- // event tables // ---------------------------------------------------------------------------- @@ -67,8 +92,14 @@ IMPLEMENT_DYNAMIC_CLASS(wxWindow, wxWindowMSW) #elif defined(__WXGTK__) IMPLEMENT_DYNAMIC_CLASS(wxWindow, wxWindowGTK) -#elif defined(__WXMGL__) - IMPLEMENT_DYNAMIC_CLASS(wxWindow, wxWindowMGL) +#elif defined(__WXOSX_OR_COCOA__) + IMPLEMENT_DYNAMIC_CLASS(wxWindow, wxWindowMac) +#elif defined(__WXDFB__) + IMPLEMENT_DYNAMIC_CLASS(wxWindow, wxWindowDFB) +#elif defined(__WXX11__) + IMPLEMENT_DYNAMIC_CLASS(wxWindow, wxWindowX11) +#elif defined(__WXPM__) + IMPLEMENT_DYNAMIC_CLASS(wxWindow, wxWindowOS2) #endif BEGIN_EVENT_TABLE(wxWindow, wxWindowNative) @@ -94,12 +125,17 @@ END_EVENT_TABLE() void wxWindow::Init() { +#if wxUSE_SCROLLBAR m_scrollbarVert = - m_scrollbarHorz = (wxScrollBar *)NULL; + m_scrollbarHorz = NULL; +#endif // wxUSE_SCROLLBAR - m_isCurrent = FALSE; + m_isCurrent = false; m_renderer = wxTheme::Get()->GetRenderer(); + + m_oldSize.x = wxDefaultCoord; + m_oldSize.y = wxDefaultCoord; } bool wxWindow::Create(wxWindow *parent, @@ -109,33 +145,99 @@ bool wxWindow::Create(wxWindow *parent, long style, const wxString& name) { - // we add wxCLIP_CHILDREN and wxNO_FULL_REPAINT_ON_RESIZE because without - // these styles we can't get rid of flicker on wxMSW - if ( !wxWindowNative::Create(parent, id, pos, size, - style | - wxCLIP_CHILDREN | - wxNO_FULL_REPAINT_ON_RESIZE, name) ) + // Get default border + wxBorder border = GetBorder(style); + style &= ~wxBORDER_MASK; + style |= border; + + long actualStyle = style; + + // we add wxCLIP_CHILDREN to get the same ("natural") behaviour under MSW + // as under the other platforms + actualStyle |= wxCLIP_CHILDREN; + + actualStyle &= ~wxVSCROLL; + actualStyle &= ~wxHSCROLL; + +#ifdef __WXMSW__ + // without this, borders (non-client areas in general) are not repainted + // correctly when resizing; apparently, native NC areas are fully repainted + // even without this style by MSW, but wxUniv implements client area + // itself, so it doesn't work correctly for us + // + // FIXME: this is very expensive, we need to fix the (commented-out) code + // in OnSize() instead + actualStyle |= wxFULL_REPAINT_ON_RESIZE; +#endif + + if ( !wxWindowNative::Create(parent, id, pos, size, actualStyle, name) ) + return false; + + // Set full style again, including those we didn't want present + // when calling the base window Create(). + wxWindowBase::SetWindowStyleFlag(style); + + // if we allow or should always have a vertical scrollbar, make it + if ( style & wxVSCROLL || style & wxALWAYS_SHOW_SB ) { - return FALSE; +#if wxUSE_TWO_WINDOWS + SetInsertIntoMain( true ); +#endif +#if wxUSE_SCROLLBAR + m_scrollbarVert = new wxWindowScrollBar(this, wxID_ANY, + wxDefaultPosition, wxDefaultSize, + wxSB_VERTICAL); +#endif // wxUSE_SCROLLBAR +#if wxUSE_TWO_WINDOWS + SetInsertIntoMain( false ); +#endif } - // if we should always have the scrollbar, do show it - if ( GetWindowStyle() & wxALWAYS_SHOW_SB ) + // if we should allow a horizontal scrollbar, make it + if ( style & wxHSCROLL ) { - m_scrollbarVert = new wxScrollBar(this, -1, - wxDefaultPosition, wxDefaultSize, - wxSB_VERTICAL); +#if wxUSE_TWO_WINDOWS + SetInsertIntoMain( true ); +#endif +#if wxUSE_SCROLLBAR + m_scrollbarHorz = new wxWindowScrollBar(this, wxID_ANY, + wxDefaultPosition, wxDefaultSize, + wxSB_HORIZONTAL); +#endif // wxUSE_SCROLLBAR +#if wxUSE_TWO_WINDOWS + SetInsertIntoMain( false ); +#endif + } - // and position it +#if wxUSE_SCROLLBAR + if (m_scrollbarHorz || m_scrollbarVert) + { + // position it/them PositionScrollbars(); } +#endif // wxUSE_SCROLLBAR + + return true; +} - // the colours/fonts are default - m_hasBgCol = - m_hasFgCol = - m_hasFont = FALSE; +wxWindow::~wxWindow() +{ + SendDestroyEvent(); + +#if wxUSE_SCROLLBAR + // clear pointers to scrollbar before deleting the children: they are + // children and so will be deleted by DestroyChildren() call below and if + // any code using the scrollbars would be called in the process or from + // ~wxWindowBase, the app would crash: + m_scrollbarVert = m_scrollbarHorz = NULL; +#endif - return 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(); } // ---------------------------------------------------------------------------- @@ -154,7 +256,7 @@ void wxWindow::SetBackground(const wxBitmap& bitmap, const wxBitmap& wxWindow::GetBackgroundBitmap(int *alignment, wxStretch *stretch) const { - if ( m_bitmapBg.Ok() ) + if ( m_bitmapBg.IsOk() ) { if ( alignment ) *alignment = m_alignBgBitmap; @@ -169,52 +271,15 @@ 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 ) { // get the window rect - wxRect rect; - wxSize size = GetSize(); - rect.x = - rect.y = 0; - rect.width = size.x; - rect.height = size.y; + wxRect rect(GetSize()); +#if wxUSE_SCROLLBAR // if the scrollbars are outside the border, we must adjust the rect to // exclude them if ( !m_renderer->AreScrollbarsInsideBorder() ) @@ -227,6 +292,7 @@ void wxWindow::OnNcPaint(wxPaintEvent& event) if ( scrollbar ) rect.height -= scrollbar->GetSize().y; } +#endif // wxUSE_SCROLLBAR // get the DC and draw the border on it wxWindowDC dc(this); @@ -252,43 +318,109 @@ 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 wxUSE_SCROLLBAR + // 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); + } + } +#endif // wxUSE_SCROLLBAR +} + 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() && !UseBgCol() && parent ) { - wxSize size = GetSize(); - rect.width = size.x; - rect.height = size.y; + // DirectFB paints the parent first, then its child windows, so by + // the time this code is called, parent's background was already + // drawn and there's no point in (imperfectly!) duplicating the work + // here: +#ifndef __WXDFB__ + 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 ); +#endif // !__WXDFB__ + } + else + { + // Draw background ourselves + EraseBackground( dc, rect ); } - if ( GetBackgroundBitmap().Ok() ) + return true; +} + +void wxWindow::EraseBackground(wxDC& dc, const wxRect& rect) +{ + if ( GetBackgroundBitmap().IsOk() ) { - // 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,41 +435,43 @@ void wxWindow::DoDrawBorder(wxDC& dc, const wxRect& rect) } } -void wxWindow::DoDraw(wxControlRenderer *renderer) +void wxWindow::DoDraw(wxControlRenderer * WXUNUSED(renderer)) { } -void wxWindow::Refresh(bool eraseBackground, const wxRect *rectClient) +void wxWindow::Refresh(bool eraseBackground, const wxRect *rect) { - wxRect rectWin; - wxPoint pt = GetClientAreaOrigin(); + wxRect rectClient; // the same rectangle in client coordinates + wxPoint origin = GetClientAreaOrigin(); wxSize size = GetClientSize(); - if ( rectClient ) + if ( rect ) { - rectWin = *rectClient; + // the rectangle passed as argument is in client coordinates + rectClient = *rect; // don't refresh anything beyond the client area (scrollbars for // example) - if ( rectWin.GetRight() > size.x ) - rectWin.SetRight(size.x); - if ( rectWin.GetBottom() > size.y ) - rectWin.SetBottom(size.y); + if ( rectClient.GetRight() > size.x ) + rectClient.SetRight(size.x); + if ( rectClient.GetBottom() > size.y ) + rectClient.SetBottom(size.y); - rectWin.Offset(pt); } else // refresh the entire client area { - rectWin.x = pt.x; - rectWin.y = pt.y; - rectWin.width = size.x; - rectWin.height = size.y; + // x,y is already set to 0 by default + rectClient.SetSize(size); } + // convert refresh rectangle to window coordinates: + wxRect rectWin(rectClient); + rectWin.Offset(origin); + // debugging helper #ifdef WXDEBUG_REFRESH - static bool s_refreshDebug = FALSE; + static bool s_refreshDebug = false; if ( s_refreshDebug ) { wxWindowDC dc(this); @@ -354,6 +488,33 @@ void wxWindow::Refresh(bool eraseBackground, const wxRect *rectClient) #endif // WXDEBUG_REFRESH wxWindowNative::Refresh(eraseBackground, &rectWin); + + // Refresh all sub controls if any. + wxWindowList& children = GetChildren(); + for ( wxWindowList::iterator i = children.begin(); i != children.end(); ++i ) + { + wxWindow *child = *i; + // only refresh subcontrols if they are visible: + if ( child->IsTopLevel() || !child->IsShown() || child->IsFrozen() ) + continue; + + // ...and when the subcontrols are in the update region: + wxRect childrect(child->GetRect()); + childrect.Intersect(rectClient); + if ( childrect.IsEmpty() ) + continue; + + // refresh the subcontrol now: + childrect.Offset(-child->GetPosition()); + // NB: We must call wxWindowNative version because we need to refresh + // the entire control, not just its client area, and this is why we + // don't account for child client area origin here neither. Also + // note that we don't pass eraseBackground to the child, but use + // true instead: this is because we can't be sure that + // eraseBackground=false is safe for children as well and not only + // for the parent. + child->wxWindowNative::Refresh(eraseBackground, &childrect); + } } // ---------------------------------------------------------------------------- @@ -363,10 +524,10 @@ 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 ) + if ( FindFocus() == this && GetParent() != NULL ) { GetParent()->SetFocus(); } @@ -378,23 +539,22 @@ bool wxWindow::Enable(bool enable) Refresh(); } - return TRUE; + return true; } bool wxWindow::IsFocused() const { - wxWindow *self = wxConstCast(this, wxWindow); - return self->FindFocus() == self; + return FindFocus() == this; } bool wxWindow::IsPressed() const { - return FALSE; + return false; } bool wxWindow::IsDefault() const { - return FALSE; + return false; } bool wxWindow::IsCurrent() const @@ -405,14 +565,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,22 +604,121 @@ int wxWindow::GetStateFlags() const void wxWindow::OnSize(wxSizeEvent& event) { + event.Skip(); + +#if wxUSE_SCROLLBAR if ( m_scrollbarVert || m_scrollbarHorz ) { PositionScrollbars(); } +#endif // wxUSE_SCROLLBAR - event.Skip(); -} +#if 0 // ndef __WXMSW__ + // Refresh the area (strip) previously occupied by the border -wxSize wxWindow::DoGetBestSize() const -{ - return AdjustSize(DoGetBestClientSize()); + 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 ) || HasFlag( wxBORDER_THEME )) + { + 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::DoGetBestClientSize() const +wxSize wxWindow::DoGetBorderSize() const { - return wxWindowNative::DoGetBestSize(); + return AdjustSize(wxSize(0, 0)); } wxSize wxWindow::AdjustSize(const wxSize& size) const @@ -474,14 +733,26 @@ 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; } void wxWindow::DoGetClientSize(int *width, int *height) const { + // if it is a native window, we assume it handles the scrollbars itself + // too - and if it doesn't, there is not much we can do + if ( !m_renderer ) + { + wxWindowNative::DoGetClientSize(width, height); + + return; + } + int w, h; wxWindowNative::DoGetClientSize(&w, &h); @@ -492,21 +763,16 @@ void wxWindow::DoGetClientSize(int *width, int *height) const if ( m_renderer ) rectBorder = m_renderer->GetBorderDimensions(GetBorder()); - bool inside = m_renderer->AreScrollbarsInsideBorder(); - if ( width ) { +#if wxUSE_SCROLLBAR // in any case, take account of the scrollbar if ( m_scrollbarVert ) w -= m_scrollbarVert->GetSize().x; +#endif // wxUSE_SCROLLBAR - // if we don't have scrollbar or if it is outside the border (and not - // blended into it), take account of the right border as well - if ( !m_scrollbarVert || inside ) - w -= rectBorder.width; - - // and always account for the left border - *width = w - rectBorder.x; + // account for the left and right borders + *width = w - rectBorder.x - rectBorder.width; // we shouldn't return invalid width if ( *width < 0 ) @@ -515,13 +781,12 @@ void wxWindow::DoGetClientSize(int *width, int *height) const if ( height ) { +#if wxUSE_SCROLLBAR if ( m_scrollbarHorz ) h -= m_scrollbarHorz->GetSize().y; +#endif // wxUSE_SCROLLBAR - if ( !m_scrollbarHorz || inside ) - h -= rectBorder.height; - - *height = h - rectBorder.y; + *height = h - rectBorder.y - rectBorder.height; // we shouldn't return invalid height if ( *height < 0 ) @@ -539,17 +804,18 @@ void wxWindow::DoSetClientSize(int width, int height) // and the scrollbars (as they may be offset into the border, use the // scrollbar position, not size - this supposes that PositionScrollbars() // had been called before) - bool inside = m_renderer->AreScrollbarsInsideBorder(); wxSize size = GetSize(); +#if wxUSE_SCROLLBAR if ( m_scrollbarVert ) width += size.x - m_scrollbarVert->GetPosition().x; - if ( !m_scrollbarVert || inside ) - width += rectBorder.width; +#endif // wxUSE_SCROLLBAR + width += rectBorder.width; +#if wxUSE_SCROLLBAR if ( m_scrollbarHorz ) height += size.y - m_scrollbarHorz->GetPosition().y; - if ( !m_scrollbarHorz || inside ) - height += rectBorder.height; +#endif // wxUSE_SCROLLBAR + height += rectBorder.height; wxWindowNative::DoSetClientSize(width, height); } @@ -557,6 +823,8 @@ void wxWindow::DoSetClientSize(int width, int height) wxHitTest wxWindow::DoHitTest(wxCoord x, wxCoord y) const { wxHitTest ht = wxWindowNative::DoHitTest(x, y); + +#if wxUSE_SCROLLBAR if ( ht == wxHT_WINDOW_INSIDE ) { if ( m_scrollbarVert && x >= m_scrollbarVert->GetPosition().x ) @@ -571,6 +839,7 @@ wxHitTest wxWindow::DoHitTest(wxCoord x, wxCoord y) const : wxHT_WINDOW_HORZ_SCROLLBAR; } } +#endif // wxUSE_SCROLLBAR return ht; } @@ -583,15 +852,18 @@ wxHitTest wxWindow::DoHitTest(wxCoord x, wxCoord y) const void wxWindow::RefreshScrollbars() { +#if wxUSE_SCROLLBAR if ( m_scrollbarHorz ) m_scrollbarHorz->Refresh(); if ( m_scrollbarVert ) m_scrollbarVert->Refresh(); +#endif // wxUSE_SCROLLBAR } void wxWindow::PositionScrollbars() { +#if wxUSE_SCROLLBAR // do not use GetClientSize/Rect as it relies on the scrollbars being // correctly positioned @@ -637,6 +909,7 @@ void wxWindow::PositionScrollbars() } RefreshScrollbars(); +#endif // wxUSE_SCROLLBAR } void wxWindow::SetScrollbar(int orient, @@ -645,24 +918,34 @@ void wxWindow::SetScrollbar(int orient, int range, bool refresh) { - bool hasClientSizeChanged = FALSE; +#if wxUSE_SCROLLBAR + wxASSERT_MSG( pageSize <= range, + wxT("page size can't be greater than range") ); + + bool hasClientSizeChanged = false; wxScrollBar *scrollbar = GetScrollbar(orient); - if ( range ) + if ( range && (pageSize < range) ) { if ( !scrollbar ) { // create it - scrollbar = new wxScrollBar(this, -1, - wxDefaultPosition, wxDefaultSize, - orient & wxVERTICAL ? wxSB_VERTICAL - : wxSB_HORIZONTAL); +#if wxUSE_TWO_WINDOWS + SetInsertIntoMain( true ); +#endif + scrollbar = new wxWindowScrollBar(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(); } @@ -695,7 +978,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 ) @@ -709,41 +992,85 @@ 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 } +#else + wxUnusedVar(orient); + wxUnusedVar(pos); + wxUnusedVar(pageSize); + wxUnusedVar(range); + wxUnusedVar(refresh); +#endif // wxUSE_SCROLLBAR } -void wxWindow::SetScrollPos(int orient, int pos, bool refresh) +void wxWindow::SetScrollPos(int orient, int pos, bool WXUNUSED(refresh)) { +#if wxUSE_SCROLLBAR wxScrollBar *scrollbar = GetScrollbar(orient); - wxCHECK_RET( scrollbar, _T("no scrollbar to set position for") ); - scrollbar->SetThumbPosition(pos); + if (scrollbar) + scrollbar->SetThumbPosition(pos); + + // VZ: I think we can safely ignore this as we always refresh it + // automatically whenever the value chanegs +#if 0 if ( refresh ) Refresh(); +#endif +#else + wxUnusedVar(orient); + wxUnusedVar(pos); +#endif // wxUSE_SCROLLBAR } int wxWindow::GetScrollPos(int orient) const { +#if wxUSE_SCROLLBAR wxScrollBar *scrollbar = GetScrollbar(orient); return scrollbar ? scrollbar->GetThumbPosition() : 0; +#else + wxUnusedVar(orient); + return 0; +#endif // wxUSE_SCROLLBAR } int wxWindow::GetScrollThumb(int orient) const { +#if wxUSE_SCROLLBAR wxScrollBar *scrollbar = GetScrollbar(orient); return scrollbar ? scrollbar->GetThumbSize() : 0; +#else + wxUnusedVar(orient); + return 0; +#endif // wxUSE_SCROLLBAR } int wxWindow::GetScrollRange(int orient) const { +#if wxUSE_SCROLLBAR wxScrollBar *scrollbar = GetScrollbar(orient); return scrollbar ? scrollbar->GetRange() : 0; +#else + wxUnusedVar(orient); + return 0; +#endif // wxUSE_SCROLLBAR } 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(); @@ -752,19 +1079,66 @@ 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 wxUSE_SCROLLBAR + if ( child == m_scrollbarVert || child == m_scrollbarHorz ) + continue; +#endif // wxUSE_SCROLLBAR + + // 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 + + bool shouldMove = false; + + 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()) ) + { + shouldMove = true; + } + else if ( dy == 0 && (childRect.GetTop() <= rect->GetBottom() || + childRect.GetBottom() >= rect->GetTop()) ) + { + shouldMove = true; + } + // else: child outside of scrolling shaft, don't move + } + else // scrolling in both axes or rect=NULL + { + shouldMove = true; + } + + if ( shouldMove ) + child->Move(child->GetPosition() + offset, wxSIZE_ALLOW_MINUS_ONE); } +#endif // wxX11/!wxX11 } wxRect wxWindow::ScrollNoRefresh(int dx, int dy, const wxRect *rectTotal) { - wxASSERT_MSG( !dx || !dy, _T("can't be used for diag scrolling") ); + wxASSERT_MSG( !dx || !dy, wxT("can't be used for diag scrolling") ); // the rect to refresh (which we will calculate) wxRect rect; @@ -779,7 +1153,7 @@ wxRect wxWindow::ScrollNoRefresh(int dx, int dy, const wxRect *rectTotal) // location wxSize sizeTotal = rectTotal ? rectTotal->GetSize() : GetClientSize(); - wxLogTrace(_T("scroll"), _T("rect is %dx%d, scroll by %d, %d"), + wxLogTrace(wxT("scroll"), wxT("rect is %dx%d, scroll by %d, %d"), sizeTotal.x, sizeTotal.y, dx, dy); // the initial and end point of the region we move in client coords @@ -797,7 +1171,7 @@ wxRect wxWindow::ScrollNoRefresh(int dx, int dy, const wxRect *rectTotal) if ( size.x <= 0 || size.y <= 0 ) { // just redraw everything as nothing of the displayed image will stay - wxLogTrace(_T("scroll"), _T("refreshing everything")); + wxLogTrace(wxT("scroll"), wxT("refreshing everything")); rect = rectTotal ? *rectTotal : wxRect(0, 0, sizeTotal.x, sizeTotal.y); } @@ -842,15 +1216,15 @@ wxRect wxWindow::ScrollNoRefresh(int dx, int dy, const wxRect *rectTotal) wxMemoryDC dcMem; dcMem.SelectObject(bmp); - dcMem.Blit(wxPoint(0, 0), size, &dc, ptSource -#if defined(__WXGTK__) && !defined(__WX_DC_BLIT_FIXED__) + dcMem.Blit(wxPoint(0,0), size, &dc, ptSource +#if defined(__WXGTK__) && !defined(wxHAS_WORKING_GTK_DC_BLIT) + GetClientAreaOrigin() #endif // broken wxGTK wxDC::Blit ); - dc.Blit(ptDest, size, &dcMem, wxPoint(0, 0)); + dc.Blit(ptDest, size, &dcMem, wxPoint(0,0)); - wxLogTrace(_T("scroll"), - _T("Blit: (%d, %d) of size %dx%d -> (%d, %d)"), + wxLogTrace(wxT("scroll"), + wxT("Blit: (%d, %d) of size %dx%d -> (%d, %d)"), ptSource.x, ptSource.y, size.x, size.y, ptDest.x, ptDest.y); @@ -881,7 +1255,7 @@ wxRect wxWindow::ScrollNoRefresh(int dx, int dy, const wxRect *rectTotal) rect.height = sizeTotal.y; - wxLogTrace(_T("scroll"), _T("refreshing (%d, %d)-(%d, %d)"), + wxLogTrace(wxT("scroll"), wxT("refreshing (%d, %d)-(%d, %d)"), rect.x, rect.y, rect.GetRight() + 1, rect.GetBottom() + 1); } @@ -902,7 +1276,7 @@ wxRect wxWindow::ScrollNoRefresh(int dx, int dy, const wxRect *rectTotal) rect.width = sizeTotal.x; - wxLogTrace(_T("scroll"), _T("refreshing (%d, %d)-(%d, %d)"), + wxLogTrace(wxT("scroll"), wxT("refreshing (%d, %d)-(%d, %d)"), rect.x, rect.y, rect.GetRight() + 1, rect.GetBottom() + 1); } @@ -916,81 +1290,6 @@ wxRect wxWindow::ScrollNoRefresh(int dx, int dy, const wxRect *rectTotal) return rect; } -// ---------------------------------------------------------------------------- -// colours/fonts -// ---------------------------------------------------------------------------- - -bool wxWindow::SetBackgroundColour(const wxColour& colour) -{ - if ( !wxWindowNative::SetBackgroundColour(colour) ) - return FALSE; - - m_hasBgCol = TRUE; - - return TRUE; -} - -bool wxWindow::SetForegroundColour(const wxColour& colour) -{ - if ( !wxWindowNative::SetForegroundColour(colour) ) - return FALSE; - - m_hasFgCol = TRUE; - - return TRUE; -} - -bool wxWindow::SetFont(const wxFont& font) -{ - if ( !wxWindowNative::SetFont(font) ) - return FALSE; - - m_hasFont = TRUE; - - return TRUE; -} - -// ---------------------------------------------------------------------------- -// mouse capture -// ---------------------------------------------------------------------------- - -struct WXDLLEXPORT wxWindowNext -{ - wxWindow *win; - wxWindowNext *next; -} *wxWindow::ms_winCaptureNext = NULL; - -void wxWindow::CaptureMouse() -{ - 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 -} - // ---------------------------------------------------------------------------- // accelerators and menu hot keys // ---------------------------------------------------------------------------- @@ -1006,7 +1305,7 @@ void wxWindow::OnKeyDown(wxKeyEvent& event) { #if wxUSE_MENUS int key = event.GetKeyCode(); - if ( !event.ControlDown() && (key == WXK_MENU || key == WXK_F10) ) + if ( !event.ControlDown() && (key == WXK_ALT || key == WXK_F10) ) { ms_winLastAltPress = this; @@ -1047,6 +1346,24 @@ void wxWindow::OnKeyDown(wxKeyEvent& event) } #endif // wxUSE_MENUS +#if wxUSE_BUTTON + // 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; + } + } + } +#endif // wxUSE_BUTTON + // don't propagate accels from the child frame to the parent one break; } @@ -1101,13 +1418,32 @@ void wxWindow::OnChar(wxKeyEvent& event) } } + // if Return was pressed, see if there's a default button to activate + if ( !event.HasModifiers() && event.GetKeyCode() == WXK_RETURN ) + { + wxTopLevelWindow * + tlw = wxDynamicCast(wxGetTopLevelParent(this), wxTopLevelWindow); + if ( tlw ) + { + wxButton *btn = wxDynamicCast(tlw->GetDefaultItem(), wxButton); + if ( btn ) + { + wxCommandEvent evt(wxEVT_COMMAND_BUTTON_CLICKED, btn->GetId()); + evt.SetEventObject(btn); + btn->Command(evt); + return; + } + } + } + + event.Skip(); } void wxWindow::OnKeyUp(wxKeyEvent& event) { int key = event.GetKeyCode(); - if ( !event.HasModifiers() && (key == WXK_MENU || key == WXK_F10) ) + if ( !event.HasModifiers() && (key == WXK_ALT || key == WXK_F10) ) { // only process Alt release specially if there were no other key // presses since Alt had been pressed and if both events happened in @@ -1132,3 +1468,28 @@ 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__