+ wxARROW_UP,
+ wxARROW_DOWN,
+ wxARROW_LEFT,
+ wxARROW_RIGHT
+};
+
+class wxArrowButtonTimer;
+class wxArrowButton;
+
+// ----------------------------------------------------------------------------
+// wxArrowButtonTimer
+// ----------------------------------------------------------------------------
+
+static const unsigned int TICK_BEFORE_START = 10;
+static const unsigned int TICK_BEFORE_EXPONENTIAL = 40;
+static const unsigned int MAX_INCREMENT = 150;
+static const unsigned int TICK_INTERVAL = 113;
+
+class wxArrowButtonTimer : public wxTimer
+{
+public:
+ wxArrowButtonTimer( wxArrowButton* btn, int sign )
+ : m_sign( sign ),
+ m_button( btn )
+ { Reset(); };
+
+ void Notify();
+ void Reset() { m_ticks = 0; m_increment = 1; }
+private:
+ unsigned int m_ticks;
+ unsigned int m_increment;
+ int m_sign;
+ wxArrowButton* m_button;
+};
+
+// ----------------------------------------------------------------------------
+// wxArrowButton
+// ----------------------------------------------------------------------------
+
+class wxArrowButton : public wxControl
+{
+ friend class wxArrowButtonTimer;
+public:
+ wxArrowButton( int increment )
+ : m_increment( increment ),
+ m_timer( 0 ) {}
+
+ wxArrowButton( wxSpinButton* parent, wxWindowID id, ArrowDirection d,
+ const wxPoint& pos = wxDefaultPosition,
+ const wxSize& size = wxDefaultSize, int increment = 1 )
+ : wxControl(),
+ m_increment( increment ),
+ m_timer( 0 )
+ {
+ Create( parent, id, d, pos, size );
+ }
+
+ virtual ~wxArrowButton()
+ { delete m_timer; }
+
+ bool Create( wxSpinButton* parent, wxWindowID id, ArrowDirection d,
+ const wxPoint& pos = wxDefaultPosition,
+ const wxSize& size = wxDefaultSize );
+private:
+ // creates a new timer object, or stops the currently running one
+ wxTimer* GetFreshTimer();
+ wxSpinButton* GetSpinButton() { return (wxSpinButton*)GetParent(); }
+ static void SpinButtonCallback( Widget w, XtPointer clientData,
+ XtPointer WXUNUSED(ptr) );
+ static void StartTimerCallback( Widget w, XtPointer clientData,
+ XtPointer WXUNUSED(ptr) );
+
+ static void StopTimerCallback( Widget w, XtPointer clientData,
+ XtPointer WXUNUSED(ptr) );
+
+ int m_increment;
+ wxArrowButtonTimer* m_timer;
+};
+
+// ----------------------------------------------------------------------------
+// wxArrowButtonTimer implementation
+// ----------------------------------------------------------------------------
+
+void wxArrowButtonTimer::Notify()
+{
+ ++m_ticks;
+ if( m_ticks < TICK_BEFORE_START ) return;
+ // increment every other tick
+ if( m_ticks <= TICK_BEFORE_EXPONENTIAL && m_ticks & 1 )
+ return;
+ if( m_ticks > TICK_BEFORE_EXPONENTIAL )
+ m_increment = 2 * m_increment;
+ if( m_increment >= MAX_INCREMENT ) m_increment = MAX_INCREMENT;
+ m_button->GetSpinButton()->Increment( m_sign * m_increment );
+}
+
+// ----------------------------------------------------------------------------
+// wxArrowButton implementation
+// ----------------------------------------------------------------------------
+
+wxTimer* wxArrowButton::GetFreshTimer()
+{
+ if( m_timer )
+ {
+ m_timer->Stop();
+ m_timer->Reset();
+ }
+ else
+ m_timer = new wxArrowButtonTimer( this, m_increment );
+
+ return m_timer;
+}
+
+void wxArrowButton::SpinButtonCallback( Widget w, XtPointer clientData,
+ XtPointer WXUNUSED(ptr) )
+{
+ if( !wxGetWindowFromTable( w ) )
+ // Widget has been deleted!
+ return;
+
+ wxArrowButton* btn = (wxArrowButton*)clientData;
+
+ btn->GetSpinButton()->Increment( btn->m_increment );
+}
+
+void wxArrowButton::StartTimerCallback( Widget w, XtPointer clientData,
+ XtPointer WXUNUSED(ptr) )
+{
+ if( !wxGetWindowFromTable( w ) )
+ // Widget has been deleted!
+ return;
+
+ wxArrowButton* btn = (wxArrowButton*)clientData;
+ btn->GetFreshTimer()->Start( TICK_INTERVAL );
+}
+
+void wxArrowButton::StopTimerCallback( Widget w, XtPointer clientData,
+ XtPointer WXUNUSED(ptr) )
+{
+ if( !wxGetWindowFromTable( w ) )
+ // Widget has been deleted!
+ return;
+
+ wxArrowButton* btn = (wxArrowButton*)clientData;
+ delete btn->m_timer;
+ btn->m_timer = 0;
+}
+
+bool wxArrowButton::Create( wxSpinButton* parent,
+ wxWindowID WXUNUSED(id),
+ ArrowDirection d,
+ const wxPoint& pos, const wxSize& size )
+{
+ wxCHECK_MSG( parent, false, _T("must have a valid parent") );