diff --git a/include/wx/univ/renderer.h b/include/wx/univ/renderer.h index aa4a5fee3d..7e3e5555bd 100644 --- a/include/wx/univ/renderer.h +++ b/include/wx/univ/renderer.h @@ -13,6 +13,12 @@ wxRenderer class is used to draw all wxWindows controls. This is an ABC and the look of the application is determined by the concrete derivation of wxRenderer used in the program. + + It also contains a few static methods which may be used by the concrete + renderers and provide the functionality which is often similar or identical + in all renderers (using inheritance here would be more restrictive as the + given concrete renderer may need an arbitrary subset of the base class + methods) */ #ifdef __GNUG__ @@ -131,6 +137,14 @@ public: // virtual dtor for any base class virtual ~wxRenderer(); + +protected: + // standard scrollbar hit testing: this assumes that it only has 2 arrows + // and a thumb, so the themes which have more complicated scrollbars (e.g. + // BeOS) can't use this method + static wxHitTest StandardHitTestScrollbar(wxScrollBar *scrollbar, + const wxPoint& pt, + const wxSize& sizeArrow); }; // ---------------------------------------------------------------------------- diff --git a/src/univ/control.cpp b/src/univ/control.cpp index 2c49ab8996..449d95c333 100644 --- a/src/univ/control.cpp +++ b/src/univ/control.cpp @@ -271,7 +271,7 @@ void wxControl::OnFocus(wxFocusEvent& event) wxInputHandler *wxControl::CreateInputHandler() const { - return wxTheme::Get()->GetInputHandler(GetName()); + return wxTheme::Get()->GetInputHandler(GetClassInfo()->GetClassName()); } void wxControl::OnKeyDown(wxKeyEvent& event) diff --git a/src/univ/renderer.cpp b/src/univ/renderer.cpp index a83d1f0a06..ba08495a96 100644 --- a/src/univ/renderer.cpp +++ b/src/univ/renderer.cpp @@ -43,6 +43,71 @@ // implementation // ============================================================================ +// ---------------------------------------------------------------------------- +// wxRenderer +// ---------------------------------------------------------------------------- + +/* static */ +wxHitTest wxRenderer::StandardHitTestScrollbar(wxScrollBar *scrollbar, + const wxPoint& pt, + const wxSize& sizeArrowSB) +{ + // we only need to work with tiehr x or y coord depending on the + // orientation, choose one + wxCoord coord, sizeArrow, sizeTotal; + if ( scrollbar->GetWindowStyle() & wxVERTICAL ) + { + coord = pt.y; + sizeArrow = sizeArrowSB.y; + sizeTotal = scrollbar->GetSize().y; + } + else // horizontal + { + coord = pt.x; + sizeArrow = sizeArrowSB.x; + sizeTotal = scrollbar->GetSize().x; + } + + // test for the arrows first as it's faster + if ( coord < sizeArrow ) + { + return wxHT_SCROLLBAR_ARROW_LINE_1; + } + else if ( coord > sizeTotal - sizeArrow ) + { + return wxHT_SCROLLBAR_ARROW_LINE_2; + } + else + { + // calculate the thumb position in pixels + sizeTotal -= 2*sizeArrow; + wxCoord thumbStart, thumbEnd; + int range = scrollbar->GetRange(); + if ( !range ) + { + thumbStart = + thumbEnd = 0; + } + else + { + int posThumb = scrollbar->GetThumbPosition(), + sizeThumb = scrollbar->GetThumbSize(); + + thumbStart = (sizeTotal*posThumb) / range; + thumbEnd = (sizeTotal*(posThumb + sizeThumb)) / range; + } + + // now compare with the thumb position + coord -= sizeArrow; + if ( coord < thumbStart ) + return wxHT_SCROLLBAR_BAR_1; + else if ( coord > thumbEnd ) + return wxHT_SCROLLBAR_BAR_2; + else + return wxHT_SCROLLBAR_THUMB; + } +} + wxRenderer::~wxRenderer() { } diff --git a/src/univ/themes/gtk.cpp b/src/univ/themes/gtk.cpp index 97be737943..c88ff1437b 100644 --- a/src/univ/themes/gtk.cpp +++ b/src/univ/themes/gtk.cpp @@ -281,9 +281,9 @@ wxInputHandler *wxGTKTheme::GetInputHandler(const wxString& control) // create a new handler n = m_handlerNames.Add(control); - if ( control == wxButtonNameStr ) + if ( control == _T("wxButton") ) handler = new wxGTKButtonInputHandler(m_renderer); - else if ( control == wxScrollBarNameStr ) + else if ( control == _T("wxScrollBar") ) handler = new wxGTKScrollBarInputHandler(m_renderer); else handler = new wxGTKInputHandler(m_renderer); @@ -884,60 +884,7 @@ void wxGTKRenderer::DrawScrollbar(wxDC& dc, wxHitTest wxGTKRenderer::HitTestScrollbar(wxScrollBar *scrollbar, const wxPoint& pt) const { - // we only need to work with tiehr x or y coord depending on the - // orientation, choose one - wxCoord coord, sizeArrow, sizeTotal; - if ( scrollbar->GetWindowStyle() & wxVERTICAL ) - { - coord = pt.y; - sizeArrow = m_sizeScrollbarArrow.y; - sizeTotal = scrollbar->GetSize().y; - } - else // horizontal - { - coord = pt.x; - sizeArrow = m_sizeScrollbarArrow.x; - sizeTotal = scrollbar->GetSize().x; - } - - // test for the arrows first as it's faster - if ( coord < sizeArrow ) - { - return wxHT_SCROLLBAR_ARROW_LINE_1; - } - else if ( coord > sizeTotal - sizeArrow ) - { - return wxHT_SCROLLBAR_ARROW_LINE_2; - } - else - { - // calculate the thumb position in pixels - sizeTotal -= 2*sizeArrow; - wxCoord thumbStart, thumbEnd; - int range = scrollbar->GetRange(); - if ( !range ) - { - thumbStart = - thumbEnd = 0; - } - else - { - int posThumb = scrollbar->GetThumbPosition(), - sizeThumb = scrollbar->GetThumbSize(); - - thumbStart = (sizeTotal*posThumb) / range; - thumbEnd = (sizeTotal*(posThumb + sizeThumb)) / range; - } - - // now compare with the thumb position - coord -= sizeArrow; - if ( coord < thumbStart ) - return wxHT_SCROLLBAR_BAR_1; - else if ( coord > thumbEnd ) - return wxHT_SCROLLBAR_BAR_2; - else - return wxHT_SCROLLBAR_THUMB; - } + return StandardHitTestScrollbar(scrollbar, pt, m_sizeScrollbarArrow); } // ---------------------------------------------------------------------------- diff --git a/src/univ/themes/win32.cpp b/src/univ/themes/win32.cpp index 6b591eb16b..a0cc82922c 100644 --- a/src/univ/themes/win32.cpp +++ b/src/univ/themes/win32.cpp @@ -170,17 +170,22 @@ private: class wxWin32InputHandler : public wxInputHandler { public: + wxWin32InputHandler(wxWin32Renderer *renderer); + virtual wxControlActions Map(wxControl *control, const wxKeyEvent& event, bool pressed); virtual wxControlActions Map(wxControl *control, const wxMouseEvent& event); + +protected: + wxWin32Renderer *m_renderer; }; class wxWin32ButtonInputHandler : public wxWin32InputHandler { public: - wxWin32ButtonInputHandler(); + wxWin32ButtonInputHandler(wxWin32Renderer *renderer); virtual wxControlActions Map(wxControl *control, const wxKeyEvent& event, @@ -192,6 +197,25 @@ private: wxWindow *m_winCapture; }; +class wxWin32ScrollBarInputHandler : public wxWin32InputHandler +{ +public: + wxWin32ScrollBarInputHandler(wxWin32Renderer *renderer); + + virtual wxControlActions Map(wxControl *control, + const wxKeyEvent& event, + bool pressed); + virtual wxControlActions Map(wxControl *control, + const wxMouseEvent& event); + +private: + void Press(wxScrollBar *scrollbar, bool doIt) { } + + wxWindow *m_winCapture; + int m_btnCapture; + wxHitTest m_htLast; +}; + // ---------------------------------------------------------------------------- // wxWin32ColourScheme: uses (default) Win32 colours // ---------------------------------------------------------------------------- @@ -264,12 +288,12 @@ wxInputHandler *wxWin32Theme::GetInputHandler(const wxString& control) // create a new handler n = m_handlerNames.Add(control); - if ( control == wxButtonNameStr ) - handler = new wxWin32ButtonInputHandler; - else if ( control == wxScrollBarNameStr ) - handler = new wxWin32InputHandler; // TODO + if ( control == _T("wxButton") ) + handler = new wxWin32ButtonInputHandler(m_renderer); + else if ( control == _T("wxScrollBar") ) + handler = new wxWin32ScrollBarInputHandler(m_renderer); else - handler = new wxWin32InputHandler; + handler = new wxWin32InputHandler(m_renderer); m_handlers.Insert(handler, n); } @@ -965,7 +989,7 @@ void wxWin32Renderer::DrawScrollbar(wxDC& dc, wxHitTest wxWin32Renderer::HitTestScrollbar(wxScrollBar *scrollbar, const wxPoint& pt) const { - return wxHT_NOWHERE; + return StandardHitTestScrollbar(scrollbar, pt, m_sizeScrollbarArrow); } // ---------------------------------------------------------------------------- @@ -1031,6 +1055,11 @@ void wxWin32Renderer::AdjustSize(wxSize *size, const wxWindow *window) // wxWin32InputHandler // ---------------------------------------------------------------------------- +wxWin32InputHandler::wxWin32InputHandler(wxWin32Renderer *renderer) +{ + m_renderer = renderer; +} + wxControlActions wxWin32InputHandler::Map(wxControl *control, const wxKeyEvent& event, bool pressed) @@ -1048,7 +1077,8 @@ wxControlActions wxWin32InputHandler::Map(wxControl *control, // wxWin32ButtonInputHandler // ---------------------------------------------------------------------------- -wxWin32ButtonInputHandler::wxWin32ButtonInputHandler() +wxWin32ButtonInputHandler::wxWin32ButtonInputHandler(wxWin32Renderer *renderer) + : wxWin32InputHandler(renderer) { m_winCapture = NULL; } @@ -1086,3 +1116,134 @@ wxControlActions wxWin32ButtonInputHandler::Map(wxControl *control, return wxWin32InputHandler::Map(control, event); } + +// ---------------------------------------------------------------------------- +// wxWin32ScrollBarInputHandler +// ---------------------------------------------------------------------------- + +wxWin32ScrollBarInputHandler::wxWin32ScrollBarInputHandler(wxWin32Renderer *renderer) + : wxWin32InputHandler(renderer) +{ + m_winCapture = NULL; + m_htLast = wxHT_NOWHERE; +} + +wxControlActions wxWin32ScrollBarInputHandler::Map(wxControl *control, + const wxKeyEvent& event, + bool pressed) +{ + // we only react to the key presses here + if ( pressed ) + { + switch ( event.GetKeyCode() ) + { + case WXK_DOWN: + case WXK_RIGHT: return wxACTION_SCROLL_LINE_DOWN; + case WXK_UP: + case WXK_LEFT: return wxACTION_SCROLL_LINE_UP; + case WXK_HOME: return wxACTION_SCROLL_START; + case WXK_END: return wxACTION_SCROLL_END; + case WXK_PRIOR: return wxACTION_SCROLL_PAGE_UP; + case WXK_NEXT: return wxACTION_SCROLL_PAGE_DOWN; + } + } + + return wxWin32InputHandler::Map(control, event, pressed); +} + +wxControlActions wxWin32ScrollBarInputHandler::Map(wxControl *control, + const wxMouseEvent& event) +{ + if ( event.IsButton() ) + { + // determine which part of the window mouse is in + wxScrollBar *scrollbar = wxStaticCast(control, wxScrollBar); + wxHitTest ht = m_renderer->HitTestScrollbar + ( + scrollbar, + event.GetPosition() + ); + + // when the mouse is pressed on any scrollbar element, we capture it + // and hold capture until the same mouse button is released + if ( event.ButtonDown() ) + { + if ( !m_winCapture ) + { + m_btnCapture = -1; + for ( int i = 1; i <= 3; i++ ) + { + if ( event.ButtonDown(i) ) + { + m_btnCapture = i; + break; + } + } + + wxASSERT_MSG( m_btnCapture != -1, _T("unknown mouse button") ); + + m_winCapture = control; + m_winCapture->CaptureMouse(); + + // generate the command + bool hasAction = TRUE; + wxControlAction action; + switch ( ht ) + { + case wxHT_SCROLLBAR_ARROW_LINE_1: + action = wxACTION_SCROLL_LINE_UP; + break; + + case wxHT_SCROLLBAR_ARROW_LINE_2: + action = wxACTION_SCROLL_LINE_DOWN; + break; + + case wxHT_SCROLLBAR_BAR_1: + action = wxACTION_SCROLL_PAGE_UP; + break; + + case wxHT_SCROLLBAR_BAR_2: + action = wxACTION_SCROLL_PAGE_DOWN; + break; + + default: + hasAction = FALSE; + } + + if ( hasAction ) + { + control->PerformAction(action, event); + } + + // remove highlighting and press the arrow instead + m_htLast = ht; + Press(scrollbar, TRUE); + } + //else: mouse already captured, nothing to do + } + // release mouse if the *same* button went up + else if ( event.ButtonUp(m_btnCapture) ) + { + if ( m_winCapture ) + { + m_winCapture->ReleaseMouse(); + m_winCapture = NULL; + + // unpress the arrow and highlight the current element + Press(scrollbar, TRUE); + m_htLast = ht; + + control->Refresh(); + } + else + { + // this is not supposed to happen as the button can't go up + // without going down previously and then we'd have + // m_winCapture by now + wxFAIL_MSG( _T("logic error in mouse capturing code") ); + } + } + } + + return wxWin32InputHandler::Map(control, event); +}