X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/b3c861501a451503b31c075ccb59d16b0ae01e99..9cb0c458c4601f444437f7e816efe654158eaf90:/src/univ/winuniv.cpp diff --git a/src/univ/winuniv.cpp b/src/univ/winuniv.cpp index c0b7f7a02c..bea3acdaf1 100644 --- a/src/univ/winuniv.cpp +++ b/src/univ/winuniv.cpp @@ -60,6 +60,29 @@ // 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 // ---------------------------------------------------------------------------- @@ -122,22 +145,33 @@ bool wxWindow::Create(wxWindow *parent, long style, const wxString& name) { + // Get default border + wxBorder border = GetBorder(style); + style &= ~wxBORDER_MASK; + style |= border; + long actualStyle = style; - // FIXME: may need this on other platforms -#ifdef __WXMSW__ + // 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 - // we add wxCLIP_CHILDREN to get the same ("natural") behaviour under MSW - // as under the other platforms - if ( !wxWindowNative::Create(parent, id, pos, size, - actualStyle | wxCLIP_CHILDREN, - name) ) - { + 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(). @@ -150,9 +184,9 @@ bool wxWindow::Create(wxWindow *parent, SetInsertIntoMain( true ); #endif #if wxUSE_SCROLLBAR - m_scrollbarVert = new wxScrollBar(this, wxID_ANY, - wxDefaultPosition, wxDefaultSize, - wxSB_VERTICAL); + m_scrollbarVert = new wxWindowScrollBar(this, wxID_ANY, + wxDefaultPosition, wxDefaultSize, + wxSB_VERTICAL); #endif // wxUSE_SCROLLBAR #if wxUSE_TWO_WINDOWS SetInsertIntoMain( false ); @@ -166,9 +200,9 @@ bool wxWindow::Create(wxWindow *parent, SetInsertIntoMain( true ); #endif #if wxUSE_SCROLLBAR - m_scrollbarHorz = new wxScrollBar(this, wxID_ANY, - wxDefaultPosition, wxDefaultSize, - wxSB_HORIZONTAL); + m_scrollbarHorz = new wxWindowScrollBar(this, wxID_ANY, + wxDefaultPosition, wxDefaultSize, + wxSB_HORIZONTAL); #endif // wxUSE_SCROLLBAR #if wxUSE_TWO_WINDOWS SetInsertIntoMain( false ); @@ -190,6 +224,14 @@ wxWindow::~wxWindow() { m_isBeingDeleted = true; +#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 + // 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 @@ -322,8 +364,13 @@ bool wxWindow::DoDrawBackground(wxDC& dc) rect.height = size.y; wxWindow * const parent = GetParent(); - if ( HasTransparentBackground() && parent ) + if ( HasTransparentBackground() && !UseBgCol() && parent ) { + // 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(); @@ -346,6 +393,7 @@ bool wxWindow::DoDrawBackground(wxDC& dc) // Restore DC logical origin dc.SetLogicalOrigin( org_x, org_y ); +#endif // !__WXDFB__ } else { @@ -391,34 +439,36 @@ 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; @@ -440,16 +490,30 @@ void wxWindow::Refresh(bool eraseBackground, const wxRect *rectClient) wxWindowNative::Refresh(eraseBackground, &rectWin); // Refresh all sub controls if any. - wxWindowList::compatibility_iterator node = GetChildren().GetFirst(); - while ( node ) + wxWindowList& children = GetChildren(); + for ( wxWindowList::iterator i = children.begin(); i != children.end(); ++i ) { - 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); + wxWindow *child = *i; + // only refresh subcontrols if they are visible: + if ( child->IsTopLevel() || !child->IsShown() || child->IsFrozen() ) + continue; - node = node->GetNext(); + // ...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); } } @@ -606,7 +670,7 @@ void wxWindow::OnSize(wxSizeEvent& event) } } else - if (HasFlag( wxSUNKEN_BORDER ) || HasFlag( wxRAISED_BORDER )) + if (HasFlag( wxSUNKEN_BORDER ) || HasFlag( wxRAISED_BORDER ) || HasFlag( wxBORDER_THEME )) { if (newSize.y > m_oldSize.y) { @@ -704,8 +768,6 @@ 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 @@ -714,17 +776,8 @@ void wxWindow::DoGetClientSize(int *width, int *height) const 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 ( -#if wxUSE_SCROLLBAR - !m_scrollbarVert || -#endif // wxUSE_SCROLLBAR - 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 ) @@ -738,14 +791,7 @@ void wxWindow::DoGetClientSize(int *width, int *height) const h -= m_scrollbarHorz->GetSize().y; #endif // wxUSE_SCROLLBAR - if ( -#if wxUSE_SCROLLBAR - !m_scrollbarHorz || -#endif // wxUSE_SCROLLBAR - inside ) - h -= rectBorder.height; - - *height = h - rectBorder.y; + *height = h - rectBorder.y - rectBorder.height; // we shouldn't return invalid height if ( *height < 0 ) @@ -763,29 +809,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; #endif // wxUSE_SCROLLBAR - if ( -#if wxUSE_SCROLLBAR - !m_scrollbarVert || -#endif // wxUSE_SCROLLBAR - inside ) - width += rectBorder.width; + width += rectBorder.width; #if wxUSE_SCROLLBAR if ( m_scrollbarHorz ) height += size.y - m_scrollbarHorz->GetPosition().y; #endif // wxUSE_SCROLLBAR - if ( -#if wxUSE_SCROLLBAR - !m_scrollbarHorz || -#endif // wxUSE_SCROLLBAR - inside ) - height += rectBorder.height; + height += rectBorder.height; wxWindowNative::DoSetClientSize(width, height); } @@ -902,10 +937,10 @@ void wxWindow::SetScrollbar(int orient, #if wxUSE_TWO_WINDOWS SetInsertIntoMain( true ); #endif - scrollbar = new wxScrollBar(this, wxID_ANY, - wxDefaultPosition, wxDefaultSize, - orient & wxVERTICAL ? wxSB_VERTICAL - : wxSB_HORIZONTAL); + scrollbar = new wxWindowScrollBar(this, wxID_ANY, + wxDefaultPosition, wxDefaultSize, + orient & wxVERTICAL ? wxSB_VERTICAL + : wxSB_HORIZONTAL); #if wxUSE_TWO_WINDOWS SetInsertIntoMain( false ); #endif @@ -1078,24 +1113,30 @@ void wxWindow::ScrollWindow(int dx, int dy, const wxRect *rect) // 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()) ) { - child->Move(child->GetPosition() + offset); + shouldMove = true; } else if ( dy == 0 && (childRect.GetTop() <= rect->GetBottom() || childRect.GetBottom() >= rect->GetTop()) ) { - child->Move(child->GetPosition() + offset); + shouldMove = true; } + // else: child outside of scrolling shaft, don't move } - else + else // scrolling in both axes or rect=NULL { - child->Move(child->GetPosition() + offset); + shouldMove = true; } + + if ( shouldMove ) + child->Move(child->GetPosition() + offset, wxSIZE_ALLOW_MINUS_ONE); } #endif // wxX11/!wxX11 } @@ -1310,6 +1351,7 @@ 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 ) { @@ -1325,6 +1367,7 @@ void wxWindow::OnKeyDown(wxKeyEvent& event) } } } +#endif // wxUSE_BUTTON // don't propagate accels from the child frame to the parent one break; @@ -1380,6 +1423,25 @@ 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(); }