more scrollbar input handling: extracted common bits to wxStdScrollBarHandler

git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/branches/wxUNIVERSAL@8174 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
Vadim Zeitlin
2000-08-24 12:12:35 +00:00
parent 46f2baf74e
commit 89196a1dab
8 changed files with 570 additions and 583 deletions

View File

@@ -50,4 +50,115 @@ public:
virtual ~wxInputHandler();
};
// ============================================================================
// The classes below provide the standard input handling for some controls so
// that the code can be reused in different themes. All of these classes chain
// to an existing input handler (which must be given to the ctor) and so allow
// custom processing of the events which they don't handle themselves.
// ============================================================================
// ----------------------------------------------------------------------------
// wxStdInputHandler is just a base class for all other "standard" handlers
// ----------------------------------------------------------------------------
class WXDLLEXPORT wxStdInputHandler : public wxInputHandler
{
public:
wxStdInputHandler(wxInputHandler *handler) : m_handler(handler) { }
virtual wxControlActions Map(wxControl *control,
const wxKeyEvent& event,
bool pressed)
{ return m_handler->Map(control, event, pressed); }
virtual wxControlActions Map(wxControl *control,
const wxMouseEvent& event)
{ return m_handler->Map(control, event); }
virtual bool OnMouseMove(wxControl *control, const wxMouseEvent& event)
{ return m_handler->OnMouseMove(control, event); }
private:
wxInputHandler *m_handler;
};
// ----------------------------------------------------------------------------
// wxStdButtonInputHandler: translates SPACE and ENTER keys and the left mouse
// click into button press/release actions
// ----------------------------------------------------------------------------
class WXDLLEXPORT wxStdButtonInputHandler : public wxStdInputHandler
{
public:
wxStdButtonInputHandler(wxInputHandler *inphand);
virtual wxControlActions Map(wxControl *control,
const wxKeyEvent& event,
bool pressed);
virtual wxControlActions Map(wxControl *control,
const wxMouseEvent& event);
virtual bool OnMouseMove(wxControl *control, const wxMouseEvent& event);
private:
// the window (button) which has capture or NULL and the flag telling if
// the mouse is inside the button which captured it or not
wxWindow *m_winCapture;
bool m_winHasMouse;
};
// ----------------------------------------------------------------------------
// common scrollbar input handler: it manages clicks on the standard scrollbar
// elements (line arrows, bar, thumb)
// ----------------------------------------------------------------------------
class WXDLLEXPORT wxStdScrollBarInputHandler : public wxStdInputHandler
{
public:
// constructor takes a renderer (used for scrollbar hit testing) and the
// base handler to which all unhandled events are forwarded
wxStdScrollBarInputHandler(wxRenderer *renderer,
wxInputHandler *inphand);
virtual wxControlActions Map(wxControl *control,
const wxKeyEvent& event,
bool pressed);
virtual wxControlActions Map(wxControl *control,
const wxMouseEvent& event);
virtual bool OnMouseMove(wxControl *control, const wxMouseEvent& event);
protected:
// the methods which must be overridden in the derived class
// return TRUE to stop scrolling when the mouse leaves the scrollbar (Win32
// behaviour) or FALSE to continue (GTK+)
virtual bool OnMouseLeave() = 0;
// return TRUE if the mouse button can be used to activate scrollbar, FALSE
// if not (only left mouse button can do it under Windows, any button under
// GTK+)
virtual bool IsAllowedButton(int button) = 0;
// set or clear the specified flag on the scrollbar element corresponding
// to m_htLast
void SetElementState(wxScrollBar *scrollbar, int flag, bool doIt);
// [un]highlight the scrollbar element corresponding to m_htLast
void Highlight(wxScrollBar *scrollbar, bool doIt)
{ SetElementState(scrollbar, wxCONTROL_CURRENT, doIt); }
// [un]press the scrollbar element corresponding to m_htLast
void Press(wxScrollBar *scrollbar, bool doIt)
{ SetElementState(scrollbar, wxCONTROL_PRESSED, doIt); }
// the window (scrollbar) which has capture or NULL and the flag telling if
// the mouse is inside the element which captured it or not
wxWindow *m_winCapture;
bool m_winHasMouse;
int m_btnCapture; // the mouse button which has captured mouse
// one of wxHT_SCROLLBAR_XXX value: where has the mouse been last time?
wxHitTest m_htLast;
// the renderer (we use it only for hit testing)
wxRenderer *m_renderer;
};
#endif // _WX_UNIV_INPHAND_H_

View File

@@ -46,6 +46,7 @@ enum wxHitTest
wxHT_NOWHERE,
// scrollbar
wxHT_SCROLLBAR_FIRST = wxHT_NOWHERE,
wxHT_SCROLLBAR_ARROW_LINE_1, // left or upper arrow to scroll by line
wxHT_SCROLLBAR_ARROW_LINE_2, // right or down
wxHT_SCROLLBAR_ARROW_PAGE_1, // left or upper arrow to scroll by page
@@ -53,6 +54,7 @@ enum wxHitTest
wxHT_SCROLLBAR_THUMB, // on the thumb
wxHT_SCROLLBAR_BAR_1, // bar to the left/above the thumb
wxHT_SCROLLBAR_BAR_2, // bar to the right/below the thumb
wxHT_SCROLLBAR_LAST,
wxHT_MAX
};

View File

@@ -16,6 +16,8 @@
#pragma interface "univscrolbar.h"
#endif
#include "wx/univ/renderer.h" // for wxHitTest
class WXDLLEXPORT wxInputHandler;
// ----------------------------------------------------------------------------
@@ -42,15 +44,17 @@ class WXDLLEXPORT wxInputHandler;
class WXDLLEXPORT wxScrollBar : public wxScrollBarBase
{
public:
// the parts of the scrollbar
// scrollbar elements: they correspond to wxHT_SCROLLBAR_XXX constants but
// start from 0 which allows to use them as array indices
enum Element
{
Element_Arrow_Line_1,
Element_Arrow_Line_2,
Element_Arrow_Page_1,
Element_Arrow_Page_2,
Element_Thumb,
Element_Bar,
Element_Arrow_Thumb,
Element_Bar_1,
Element_Bar_2,
Element_Max
};
@@ -99,10 +103,8 @@ public:
const wxEvent& event);
// wxScrollBar sub elements state (combination of wxCONTROL_XXX)
void SetState(Element elem, int flags)
{ m_elementsState[elem] = flags; }
int GetState(Element elem) const
{ return m_elementsState[elem]; }
void SetState(Element which, int flags) { m_elementsState[which] = flags; }
int GetState(Element which) const { return m_elementsState[which]; }
protected:
virtual wxSize DoGetBestSize() const;
@@ -110,7 +112,7 @@ protected:
// SetThumbPosition() helper
void DoSetThumb(int thumbPos);
// common part of all ctors
void Init();

View File

@@ -1015,7 +1015,7 @@ void wxWindow::OnIdle(wxIdleEvent& event)
state |= MK_MBUTTON;
if ( GetKeyState( VK_RBUTTON ) )
state |= MK_RBUTTON;
wxMouseEvent event(wxEVT_LEAVE_WINDOW);
InitMouseEvent(event, pt.x, pt.y, state);
@@ -3273,13 +3273,22 @@ bool wxWindow::HandleMouseMove(int x, int y, WXUINT flags)
{
if ( !m_mouseInWindow )
{
// Generate an ENTER event
m_mouseInWindow = TRUE;
// it would be wrogn to assume that just because we get a mouse move
// event the mouse is inside the window: although this is usually true,
// it is not if we had captured the mouse, so we need to check the
// mouse coordinates here
POINT pt;
::GetCursorPos(&pt);
if ( ::WindowFromPoint(pt) == GetHwnd() )
{
// Generate an ENTER event
m_mouseInWindow = TRUE;
wxMouseEvent event(wxEVT_ENTER_WINDOW);
InitMouseEvent(event, x, y, flags);
wxMouseEvent event(wxEVT_ENTER_WINDOW);
InitMouseEvent(event, x, y, flags);
(void)GetEventHandler()->ProcessEvent(event);
(void)GetEventHandler()->ProcessEvent(event);
}
}
#if wxUSE_MOUSEEVENT_HACK

View File

@@ -37,6 +37,10 @@
// implementation
// ============================================================================
// ----------------------------------------------------------------------------
// wxInputHandler
// ----------------------------------------------------------------------------
bool wxInputHandler::OnMouseMove(wxControl * WXUNUSED(control),
const wxMouseEvent& WXUNUSED(event))
{
@@ -46,3 +50,308 @@ bool wxInputHandler::OnMouseMove(wxControl * WXUNUSED(control),
wxInputHandler::~wxInputHandler()
{
}
// ----------------------------------------------------------------------------
// wxStdButtonInputHandler
// ----------------------------------------------------------------------------
wxStdButtonInputHandler::wxStdButtonInputHandler(wxInputHandler *handler)
: wxStdInputHandler(handler)
{
m_winCapture = NULL;
}
wxControlActions wxStdButtonInputHandler::Map(wxControl *control,
const wxKeyEvent& event,
bool pressed)
{
int keycode = event.GetKeyCode();
if ( keycode == WXK_SPACE || keycode == WXK_RETURN )
{
return wxACTION_BUTTON_TOGGLE;
}
return wxStdInputHandler::Map(control, event, pressed);
}
wxControlActions wxStdButtonInputHandler::Map(wxControl *control,
const wxMouseEvent& event)
{
// the button has 2 states: pressed and normal with the following
// transitions between them:
//
// normal -> left down -> capture mouse and go to pressed state
// pressed -> left up inside -> generate click -> go to normal
// outside ------------------>
//
// the other mouse buttons are ignored
if ( event.Button(1) )
{
if ( event.ButtonDown(1) )
{
m_winCapture = control;
m_winCapture->CaptureMouse();
m_winHasMouse = TRUE;
return wxACTION_BUTTON_PRESS;
}
else // up
{
m_winCapture->ReleaseMouse();
m_winCapture = NULL;
if ( m_winHasMouse )
{
// this will generate a click event
return wxACTION_BUTTON_TOGGLE;
}
//else: the mouse was released outside the window, this doesn't
// count as a click
}
}
return wxStdInputHandler::Map(control, event);
}
bool wxStdButtonInputHandler::OnMouseMove(wxControl *control,
const wxMouseEvent& event)
{
// we only have to do soemthing when the mouse leaves/enters the pressed
// button and don't care about the other ones
if ( event.GetEventObject() == m_winCapture )
{
// leaving the button should remove its pressed state
if ( event.Leaving() )
{
// remember that the mouse is now outside
m_winHasMouse = FALSE;
// we do have a pressed button, so release it
if ( control->PerformAction(wxACTION_BUTTON_RELEASE, event) )
{
// the button state changed, refresh needed
return TRUE;
}
}
// and entering it back should make it pressed again if it had been
// pressed
else if ( event.Entering() )
{
// the mouse is (back) inside the button
m_winHasMouse = TRUE;
// we did have a pressed button which we released when leaving the
// window, press it again
if ( control->PerformAction(wxACTION_BUTTON_PRESS, event) )
{
return TRUE;
}
}
}
return wxStdInputHandler::OnMouseMove(control, event);
}
// ----------------------------------------------------------------------------
// wxStdScrollBarInputHandler
// ----------------------------------------------------------------------------
wxStdScrollBarInputHandler::wxStdScrollBarInputHandler(wxRenderer *renderer,
wxInputHandler *handler)
: wxStdInputHandler(handler)
{
m_renderer = renderer;
m_winCapture = NULL;
m_htLast = wxHT_NOWHERE;
}
void wxStdScrollBarInputHandler::SetElementState(wxScrollBar *control,
int flag,
bool doIt)
{
if ( m_htLast > wxHT_SCROLLBAR_FIRST && m_htLast < wxHT_SCROLLBAR_LAST )
{
wxScrollBar::Element
elem = (wxScrollBar::Element)(m_htLast - wxHT_SCROLLBAR_FIRST - 1);
int flags = control->GetState(elem);
if ( doIt )
flags |= flag;
else
flags &= ~flag;
control->SetState(elem, flags);
}
}
wxControlActions wxStdScrollBarInputHandler::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 wxStdInputHandler::Map(control, event, pressed);
}
wxControlActions wxStdScrollBarInputHandler::Map(wxControl *control,
const wxMouseEvent& event)
{
// is this a click event from an acceptable button?
int btn = -1;
if ( event.IsButton() )
{
for ( int i = 1; i <= 3; i++ )
{
if ( event.Button(i) )
{
btn = i;
break;
}
}
wxASSERT_MSG( btn != -1, _T("unknown mouse button") );
}
if ( (btn != -1) && IsAllowedButton(btn) )
{
// 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 = btn;
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
Highlight(scrollbar, FALSE);
m_htLast = ht;
Press(scrollbar, TRUE);
control->Refresh();
}
//else: mouse already captured, nothing to do
}
// release mouse if the *same* button went up
else if ( btn == m_btnCapture )
{
if ( m_winCapture )
{
m_winCapture->ReleaseMouse();
m_winCapture = NULL;
m_btnCapture = -1;
// unpress the arrow and highlight the current element
Press(scrollbar, FALSE);
m_htLast = ht;
Highlight(scrollbar, TRUE);
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 wxStdInputHandler::Map(control, event);
}
bool wxStdScrollBarInputHandler::OnMouseMove(wxControl *control,
const wxMouseEvent& event)
{
if ( m_winCapture )
{
// everything is locked while the mouse is captured, so don't do
// anything
return FALSE;
}
wxScrollBar *scrollbar = wxStaticCast(control, wxScrollBar);
if ( event.Moving() )
{
wxHitTest ht = m_renderer->HitTestScrollbar
(
scrollbar,
event.GetPosition()
);
if ( ht == m_htLast )
{
// nothing changed
return FALSE;
}
#ifdef DEBUG_MOUSE
wxLogDebug("Scrollbar::OnMouseMove: ht = %d", ht);
#endif // DEBUG_MOUSE
Highlight(scrollbar, FALSE);
m_htLast = ht;
Highlight(scrollbar, TRUE);
}
else if ( event.Leaving() )
{
Highlight(scrollbar, FALSE);
m_htLast = wxHT_NOWHERE;
}
// highlighting changed
return TRUE;
}

View File

@@ -56,7 +56,7 @@ void wxScrollBar::Init()
m_thumbPos =
m_pageSize = 0;
for ( size_t n = 0; n < Element_Max; n++ )
for ( size_t n = 0; n < WXSIZEOF(m_elementsState); n++ )
{
m_elementsState[n] = 0;
}

View File

@@ -162,53 +162,15 @@ protected:
wxGTKRenderer *m_renderer;
};
class wxGTKButtonInputHandler : public wxGTKInputHandler
class wxGTKScrollBarInputHandler : public wxStdScrollBarInputHandler
{
public:
wxGTKButtonInputHandler(wxGTKRenderer *renderer);
wxGTKScrollBarInputHandler(wxRenderer *renderer, wxInputHandler *handler)
: wxStdScrollBarInputHandler(renderer, handler) { }
virtual wxControlActions Map(wxControl *control,
const wxKeyEvent& event,
bool pressed);
virtual wxControlActions Map(wxControl *control,
const wxMouseEvent& event);
virtual bool OnMouseMove(wxControl *control, const wxMouseEvent& event);
private:
wxWindow *m_winCapture;
bool m_winHasMouse;
};
class wxGTKScrollBarInputHandler : public wxGTKInputHandler
{
public:
wxGTKScrollBarInputHandler(wxGTKRenderer *renderer);
virtual wxControlActions Map(wxControl *control,
const wxKeyEvent& event,
bool pressed);
virtual wxControlActions Map(wxControl *control,
const wxMouseEvent& event);
virtual bool OnMouseMove(wxControl *control, const wxMouseEvent& event);
private:
// set or clear the specified flag on the scrollbar element corresponding
// to m_htLast
void SetElementState(wxScrollBar *scrollbar, int flag, bool doIt);
// [un]highlight the scrollbar element corresponding to m_htLast
void Highlight(wxScrollBar *scrollbar, bool doIt)
{ SetElementState(scrollbar, wxCONTROL_CURRENT, doIt); }
// [un]press the scrollbar element corresponding to m_htLast
void Press(wxScrollBar *scrollbar, bool doIt)
{ SetElementState(scrollbar, wxCONTROL_PRESSED, doIt); }
wxWindow *m_winCapture;
int m_btnCapture; // the mouse button which was captured mouse
bool m_winHasMouse;
wxHitTest m_htLast;
protected:
virtual bool OnMouseLeave() { return FALSE; }
virtual bool IsAllowedButton(int WXUNUSED(button)) { return TRUE; }
};
// ----------------------------------------------------------------------------
@@ -282,9 +244,10 @@ wxInputHandler *wxGTKTheme::GetInputHandler(const wxString& control)
n = m_handlerNames.Add(control);
if ( control == _T("wxButton") )
handler = new wxGTKButtonInputHandler(m_renderer);
handler = new wxStdButtonInputHandler(GetInputHandler(_T("wxControl")));
else if ( control == _T("wxScrollBar") )
handler = new wxGTKScrollBarInputHandler(m_renderer);
handler = new wxGTKScrollBarInputHandler(m_renderer,
GetInputHandler(_T("wxControl")));
else
handler = new wxGTKInputHandler(m_renderer);
@@ -810,9 +773,9 @@ void wxGTKRenderer::DrawScrollbar(wxDC& dc,
"\tthumb: 0x%04x\n"
"\tthumb from %d to %d",
orient == wxVERTICAL ? "vertical" : "horizontal",
flags[wxScrollBar::Element_Arrow_Line_1],
flags[wxScrollBar::Element_Arrow_Line_2],
flags[wxScrollBar::Element_Thumb],
flags[wxHT_SCROLLBAR_ARROW_LINE_1],
flags[wxHT_SCROLLBAR_ARROW_LINE_2],
flags[wxHT_SCROLLBAR_THUMB],
thumbPosStart, thumbPosEnd);
#endif // DEBUG_MOUSE
@@ -850,7 +813,7 @@ void wxGTKRenderer::DrawScrollbar(wxDC& dc,
for ( size_t nArrow = 0; nArrow < 2; nArrow++ )
{
DrawArrow(dc, arrowDir[nArrow], rectArrow[nArrow],
flags[wxScrollBar::Element_Arrow_Line_1 + nArrow]);
flags[wxHT_SCROLLBAR_ARROW_LINE_1 + nArrow]);
}
// and, finally, the thumb, if any
@@ -874,7 +837,7 @@ void wxGTKRenderer::DrawScrollbar(wxDC& dc,
// the thumb is never pressed never has focus border under GTK and the
// scrollbar background never changes at all
int flagsThumb = flags[wxScrollBar::Element_Thumb] &
int flagsThumb = flags[wxHT_SCROLLBAR_THUMB] &
~(wxCONTROL_PRESSED | wxCONTROL_FOCUSED);
DrawButtonBorder(dc, rectThumb, flagsThumb, &rectThumb);
DrawBackground(dc, rectThumb, flagsThumb);
@@ -995,300 +958,3 @@ bool wxGTKInputHandler::OnMouseMove(wxControl *control,
return TRUE;
}
// ----------------------------------------------------------------------------
// wxGTKButtonInputHandler
// ----------------------------------------------------------------------------
wxGTKButtonInputHandler::wxGTKButtonInputHandler(wxGTKRenderer *renderer)
: wxGTKInputHandler(renderer)
{
m_winCapture = NULL;
}
wxControlActions wxGTKButtonInputHandler::Map(wxControl *control,
const wxKeyEvent& event,
bool pressed)
{
int keycode = event.GetKeyCode();
if ( keycode == WXK_SPACE || keycode == WXK_RETURN )
{
return wxACTION_BUTTON_TOGGLE;
}
return wxGTKInputHandler::Map(control, event, pressed);
}
wxControlActions wxGTKButtonInputHandler::Map(wxControl *control,
const wxMouseEvent& event)
{
// the button has 2 states: pressed and normal with the following
// transitions between them:
//
// normal -> left down -> capture mouse and go to pressed state
// pressed -> left up inside -> generate click -> go to normal
// outside ------------------>
//
// the other mouse buttons are ignored
if ( event.Button(1) )
{
if ( event.ButtonDown(1) )
{
m_winCapture = control;
m_winCapture->CaptureMouse();
m_winHasMouse = TRUE;
return wxACTION_BUTTON_PRESS;
}
else // up
{
m_winCapture->ReleaseMouse();
m_winCapture = NULL;
if ( m_winHasMouse )
{
// this will generate a click event
return wxACTION_BUTTON_TOGGLE;
}
//else: the mouse was released outside the window, this doesn't
// count as a click
}
}
return wxGTKInputHandler::Map(control, event);
}
bool wxGTKButtonInputHandler::OnMouseMove(wxControl *control,
const wxMouseEvent& event)
{
// leaving the button should remove its pressed state
if ( event.Leaving() )
{
if ( m_winCapture )
{
// we do have a pressed button, so release it
control->PerformAction(wxACTION_BUTTON_RELEASE, event);
// remember that the mouse is now outside
m_winHasMouse = FALSE;
}
}
// and entering it back should make it pressed again if it had been
// pressed
else if ( event.Entering() )
{
if ( m_winCapture )
{
// we did have a pressed button which we released when leaving the
// window, press it again
control->PerformAction(wxACTION_BUTTON_PRESS, event);
// and the mouse is (back) inside it
m_winHasMouse = TRUE;
}
}
return wxGTKInputHandler::OnMouseMove(control, event);
}
// ----------------------------------------------------------------------------
// wxGTKScrollBarInputHandler
// ----------------------------------------------------------------------------
wxGTKScrollBarInputHandler::wxGTKScrollBarInputHandler(wxGTKRenderer *renderer)
: wxGTKInputHandler(renderer)
{
m_winCapture = NULL;
m_htLast = wxHT_NOWHERE;
}
void wxGTKScrollBarInputHandler::SetElementState(wxScrollBar *control,
int flag,
bool doIt)
{
wxScrollBar::Element elem;
switch ( m_htLast )
{
case wxHT_SCROLLBAR_ARROW_LINE_1:
elem = wxScrollBar::Element_Arrow_Line_1;
break;
case wxHT_SCROLLBAR_ARROW_LINE_2:
elem = wxScrollBar::Element_Arrow_Line_2;
break;
case wxHT_SCROLLBAR_THUMB:
elem = wxScrollBar::Element_Thumb;
break;
/*
we don't highlight nor press the bar
case wxHT_SCROLLBAR_BAR_1:
case wxHT_SCROLLBAR_BAR_2:
*/
default:
elem = wxScrollBar::Element_Max;
}
if ( elem != wxScrollBar::Element_Max )
{
int flags = control->GetState(elem);
if ( doIt )
flags |= flag;
else
flags &= ~flag;
control->SetState(elem, flags);
}
}
wxControlActions wxGTKScrollBarInputHandler::Map(wxControl *control,
const wxKeyEvent& event,
bool pressed)
{
// weirdly enough, GTK+ scrollbars don't have keyboard support - maybe we
// should still have it though (TODO)?
return wxGTKInputHandler::Map(control, event, pressed);
}
wxControlActions wxGTKScrollBarInputHandler::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
Highlight(scrollbar, FALSE);
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;
Highlight(scrollbar, TRUE);
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 wxGTKInputHandler::Map(control, event);
}
bool wxGTKScrollBarInputHandler::OnMouseMove(wxControl *control,
const wxMouseEvent& event)
{
if ( m_winCapture )
{
// everything is locked while the mouse is captured, so don't do
// anything
return FALSE;
}
wxScrollBar *scrollbar = wxStaticCast(control, wxScrollBar);
if ( event.Moving() )
{
wxHitTest ht = m_renderer->HitTestScrollbar
(
scrollbar,
event.GetPosition()
);
if ( ht == m_htLast )
{
// nothing changed
return FALSE;
}
#ifdef DEBUG_MOUSE
wxLogDebug("Scrollbar::OnMouseMove: ht = %d", ht);
#endif // DEBUG_MOUSE
Highlight(scrollbar, FALSE);
m_htLast = ht;
Highlight(scrollbar, TRUE);
}
else if ( event.Leaving() )
{
Highlight(scrollbar, FALSE);
m_htLast = wxHT_NOWHERE;
}
// highlighting changed
return TRUE;
}

View File

@@ -61,6 +61,7 @@ public:
{
Arrow_Normal,
Arrow_Disabled,
Arrow_Pressed,
Arrow_StateMax
};
@@ -132,7 +133,7 @@ protected:
void DrawRaisedBorder(wxDC& dc, wxRect *rect);
// draw the border used for scrollbar arrows
void DrawArrowBorder(wxDC& dc, wxRect *rect);
void DrawArrowBorder(wxDC& dc, wxRect *rect, bool isPressed = FALSE);
// public DrawArrow()s helper
void DrawArrow(wxDC& dc, const wxRect& rect,
@@ -182,38 +183,26 @@ protected:
wxWin32Renderer *m_renderer;
};
class wxWin32ButtonInputHandler : public wxWin32InputHandler
class wxWin32ScrollBarInputHandler : public wxStdScrollBarInputHandler
{
public:
wxWin32ButtonInputHandler(wxWin32Renderer *renderer);
wxWin32ScrollBarInputHandler(wxWin32Renderer *renderer,
wxInputHandler *handler)
: wxStdScrollBarInputHandler(renderer, handler) { }
virtual wxControlActions Map(wxControl *control,
const wxKeyEvent& event,
bool pressed);
virtual wxControlActions Map(wxControl *control,
const wxMouseEvent& event);
// we don't highlight scrollbar elements, so there is no need to process
// mouse move events
virtual bool OnMouseMove(wxControl *control, const wxMouseEvent& event)
{
if ( event.Moving() )
return FALSE;
private:
wxWindow *m_winCapture;
};
return wxStdScrollBarInputHandler::OnMouseMove(control, event);
}
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;
protected:
virtual bool OnMouseLeave() { return TRUE; }
virtual bool IsAllowedButton(int button) { return button == 1; }
};
// ----------------------------------------------------------------------------
@@ -289,9 +278,10 @@ wxInputHandler *wxWin32Theme::GetInputHandler(const wxString& control)
n = m_handlerNames.Add(control);
if ( control == _T("wxButton") )
handler = new wxWin32ButtonInputHandler(m_renderer);
handler = new wxStdButtonInputHandler(GetInputHandler(_T("wxControl")));
else if ( control == _T("wxScrollBar") )
handler = new wxWin32ScrollBarInputHandler(m_renderer);
handler = new wxWin32ScrollBarInputHandler(m_renderer,
GetInputHandler(_T("wxControl")));
else
handler = new wxWin32InputHandler(m_renderer);
@@ -322,6 +312,10 @@ wxColour wxWin32ColourScheme::Get(wxWin32ColourScheme::StdColour col,
{
case CONTROL: return wxColour(0xc0c0c0);
case CONTROL_TEXT: return *wxBLACK;
case SCROLLBAR: if ( flags & wxCONTROL_PRESSED )
return *wxBLACK;
else
return wxColour(0xe0e0e0);
case HIGHLIGHT: return wxColour(0x800000);
case HIGHLIGHT_TEXT: return wxColour(0xffffff);
@@ -500,6 +494,8 @@ wxWin32Renderer::wxWin32Renderer(const wxColourScheme *scheme)
m_bmpArrows[Arrow_Normal][n].SetMask(mask);
mask = new wxMask(m_bmpArrows[Arrow_Disabled][n], *wxWHITE);
m_bmpArrows[Arrow_Disabled][n].SetMask(mask);
m_bmpArrows[Arrow_Pressed][n] = m_bmpArrows[Arrow_Normal][n];
}
}
@@ -624,10 +620,25 @@ void wxWin32Renderer::DrawRaisedBorder(wxDC& dc, wxRect *rect)
DrawShadedRect(dc, rect, m_penLightGrey, m_penDarkGrey);
}
void wxWin32Renderer::DrawArrowBorder(wxDC& dc, wxRect *rect)
void wxWin32Renderer::DrawArrowBorder(wxDC& dc, wxRect *rect, bool isPressed)
{
DrawShadedRect(dc, rect, m_penLightGrey, m_penBlack);
DrawShadedRect(dc, rect, m_penHighlight, m_penDarkGrey);
if ( isPressed )
{
DrawRect(dc, rect, m_penDarkGrey);
// the arrow is usually drawn inside border of width 2 and is offset by
// another pixel in both directions when it's pressed - as the border
// in this case is more narrow as well, we have to adjust rect like
// this:
rect->Inflate(-1);
rect->x++;
rect->y++;
}
else
{
DrawShadedRect(dc, rect, m_penLightGrey, m_penBlack);
DrawShadedRect(dc, rect, m_penHighlight, m_penDarkGrey);
}
}
void wxWin32Renderer::DrawBorder(wxDC& dc,
@@ -912,7 +923,7 @@ void wxWin32Renderer::DrawArrowButton(wxDC& dc,
wxArrowStyle arrowStyle)
{
wxRect rect = rectAll;
DrawArrowBorder(dc, &rect);
DrawArrowBorder(dc, &rect, arrowStyle == Arrow_Pressed);
DrawArrow(dc, rect, arrowDir, arrowStyle);
}
@@ -923,10 +934,6 @@ void wxWin32Renderer::DrawScrollbar(wxDC& dc,
const wxRect& rect,
const int *flags)
{
int flagsSb = flags ? flags[0] : 0;
wxArrowStyle arrowStyle = flagsSb & wxCONTROL_DISABLED ? Arrow_Disabled
: Arrow_Normal;
// first, draw the arrows at the ends
wxRect rectArrow[2];
wxArrowDirection arrowDir[2];
@@ -952,24 +959,34 @@ void wxWin32Renderer::DrawScrollbar(wxDC& dc,
arrowDir[1] = Arrow_Right;
}
wxArrowStyle arrowStyle;
for ( size_t nArrow = 0; nArrow < 2; nArrow++ )
{
int flagsArrow = flags[wxScrollBar::Element_Arrow_Line_1 + nArrow];
if ( flagsArrow & wxCONTROL_PRESSED )
arrowStyle = Arrow_Pressed;
else if ( flagsArrow & wxCONTROL_DISABLED )
arrowStyle = Arrow_Disabled;
else
arrowStyle = Arrow_Normal;
DrawArrowButton(dc, rectArrow[nArrow], arrowDir[nArrow], arrowStyle);
}
// next draw the scrollbar area
// next draw the scrollbar area: in a normal state, we draw it all in one
// call to DoDrawBackground(), but when either part of the bar is pressed,
// we paint them separately
wxRect rectBar = rect;
if ( orient == wxVERTICAL )
rectBar.Inflate(0, -m_sizeScrollbarArrow.y);
rectBar.Inflate(0, -(m_sizeScrollbarArrow.y + 1));
else
rectBar.Inflate(-m_sizeScrollbarArrow.x, 0);
rectBar.Inflate(-(m_sizeScrollbarArrow.x + 1), 0);
DoDrawBackground(dc, m_colHighlight, rectBar);
// and, finally, the thumb, if any
// calculate the thumb position
wxRect rectThumb;
if ( thumbPosStart < thumbPosEnd )
{
wxRect rectThumb = rectBar;
rectThumb = rectBar;
if ( orient == wxVERTICAL )
{
rectThumb.y += (rectBar.height*thumbPosStart)/100;
@@ -980,7 +997,53 @@ void wxWin32Renderer::DrawScrollbar(wxDC& dc,
rectThumb.x += (rectBar.width*thumbPosStart)/100;
rectThumb.width = (rectBar.width*(thumbPosEnd - thumbPosStart))/100;
}
}
//else: no thumb
if ( (flags[wxScrollBar::Element_Bar_1] & wxCONTROL_PRESSED) ||
(flags[wxScrollBar::Element_Bar_2] & wxCONTROL_PRESSED) )
{
// calculate the bounding boxes for each of 2 bar parts
wxRect rectBars[2];
rectBars[0] =
rectBars[1] = rectBar;
if ( orient == wxVERTICAL )
{
rectBars[0].SetTop(m_sizeScrollbarArrow.y);
rectBars[0].SetBottom(rectThumb.GetTop() - 1);
rectBars[1].SetTop(rectThumb.GetBottom() + 1);
rectBars[1].SetBottom(rectBar.GetBottom());
}
else // horizontal
{
rectBars[0].SetLeft(m_sizeScrollbarArrow.x);
rectBars[0].SetRight(rectThumb.GetLeft() - 1);
rectBars[1].SetLeft(rectThumb.GetRight() + 1);
rectBars[1].SetRight(rectBar.GetRight());
}
for ( size_t nBar = 0; nBar < 2; nBar++ )
{
DoDrawBackground(
dc,
m_scheme->Get
(
wxColourScheme::SCROLLBAR,
flags[wxScrollBar::Element_Bar_1 + nBar]
),
rectBars[nBar]
);
}
}
else // nothing is pressed
{
DoDrawBackground(dc, m_scheme->Get(wxColourScheme::SCROLLBAR), rectBar);
}
// and, finally, the thumb, if any
if ( thumbPosStart < thumbPosEnd )
{
// we don't use the flags, the thumb never changes appearance
DrawArrowBorder(dc, &rectThumb);
DrawBackground(dc, rectThumb);
}
@@ -1072,178 +1135,3 @@ wxControlActions wxWin32InputHandler::Map(wxControl *control,
{
return wxACTION_NONE;
}
// ----------------------------------------------------------------------------
// wxWin32ButtonInputHandler
// ----------------------------------------------------------------------------
wxWin32ButtonInputHandler::wxWin32ButtonInputHandler(wxWin32Renderer *renderer)
: wxWin32InputHandler(renderer)
{
m_winCapture = NULL;
}
wxControlActions wxWin32ButtonInputHandler::Map(wxControl *control,
const wxKeyEvent& event,
bool pressed)
{
int keycode = event.GetKeyCode();
if ( keycode == WXK_SPACE || keycode == WXK_RETURN )
{
return wxACTION_BUTTON_TOGGLE;
}
return wxWin32InputHandler::Map(control, event, pressed);
}
wxControlActions wxWin32ButtonInputHandler::Map(wxControl *control,
const wxMouseEvent& event)
{
if ( event.IsButton() )
{
if ( event.ButtonDown() )
{
m_winCapture = wxWindow::FindFocus();
m_winCapture->CaptureMouse();
}
else // up
{
m_winCapture->ReleaseMouse();
}
return wxACTION_BUTTON_TOGGLE;
}
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);
}