/*********************************************************************************************** * SliderCtrlX * * Enhanced Slider Control / Slider indicator * * Autors : avpavp, jerson, jibe, koldo * Last modified : June 09, 2011 * * 2do : adjust default values when changing CONTROL/INDICATOR * Better .usc file * Known bugs : Invalid memory access when choosing FillColor with .lay designer (seems to be * only with ubuntu. See http://www.ultimatepp.org/forum/index.php?t=msg&th=6022&start=0& **********************************************************************************************/ #include #include "SliderCtrlX.h" #define IMAGECLASS SliderThumbsImg #define IMAGEFILE #include namespace Upp { SliderCtrlX::SliderCtrlX() : m_nMin(0) , m_nMax(100) , m_bInverted(false) , m_nStep(1) , m_bRound_step(false) , m_bJump(false) , m_bUseCustomThumbs( 0 ) , m_nMajorTicks( 10 ) , m_nMinorTicks( 2 ) , m_nMajorTickSize( 30 ) , m_nMinorTickSize( 20 ) , m_nTickPosition( TOP ) , m_nThickness( 2 ) , m_nSliderType( 0 ) , m_nThumbNumber( 1 ) /*********************************************************************************************** * Constructor * public **********************************************************************************************/ { SetValue( 0 ); border2 = m_nThickness * BORDER_SIZE; Transparent(); m_ThumbImg.Clear(); } SliderCtrlX::~SliderCtrlX() /*********************************************************************************************** * Destructor * virtual - public **********************************************************************************************/ { } SliderCtrlX& SliderCtrlX::AddOutCtrl( Ctrl* c ) /*********************************************************************************************** * public **********************************************************************************************/ { m_vctrlOutput.Add( c ); return *this; } int SliderCtrlX::ClientToSlider(int p) const /*********************************************************************************************** * Converts Slider values to canvas coordinates * private **********************************************************************************************/ { p -= HoVe(m_ThumbSize.cx/2, m_ThumbSize.cy/2); return minmax(m_nMin + iscale(p, m_nMax - m_nMin, HoVe(GetSize().cx - border2 - m_ThumbSize.cx, GetSize().cy - border2 - m_ThumbSize.cy)), Min(), Max()); } void SliderCtrlX::Dec() /*********************************************************************************************** * decrements the slider value * public **********************************************************************************************/ { int n = m_vValues[0]; if(IsNull(m_vValues[0])) n = Max(); else if(n > Min()) { if(m_bRound_step && m_nStep > 1) n = idivfloor(n - 1, m_nStep) * m_nStep; else n -= m_nStep; if(n < Min()) n = Min(); } if(n != m_vValues[0]) { SetValue( n ); WhenSlideFinish(); UpdateActionRefresh(); } } void SliderCtrlX::DrawTick( Draw &w, MAJORMINOR Type, HOVE Orientation, int nPos, int nVal ) /*********************************************************************************************** * draws a tickmark at nPos on canvas * protected **********************************************************************************************/ { Size size = GetSize(); int sz = Orientation == HORZ ? size.cy : size.cx; int nMajorSize = (int)( m_nMajorTickSize / 100.0f * sz * .5 + 0.5f ); int nMinorSize = (int)( m_nMinorTickSize / 100.0f * sz * .5 + 0.5f ); int nMajorWidth = 3; int TickBottomMaj = 0, TickBottomMin = 0, TickTop = 0; String txt; if (LabelFormat) LabelFormat(txt, nVal); else txt = AsString(nVal); switch (m_nTickPosition) { case TOP : TickTop = -2; TickBottomMaj = -nMajorSize -2; TickBottomMin = -nMinorSize -2; break; case MIDDLE_TOP : TickTop = +2 +m_nThickness; TickBottomMaj = -nMajorSize +2 +m_nThickness; TickBottomMin = -nMinorSize +2 +m_nThickness; break; case MIDDLE_BOTTOM : TickTop = 0; TickBottomMaj = nMajorSize; TickBottomMin = nMinorSize; break; case BOTTOM : TickTop = +2 +m_nThickness; TickBottomMaj = nMajorSize +2 +m_nThickness; TickBottomMin = nMinorSize +2 +m_nThickness; break; } if( Orientation == HORZ ) { if( Type == MAJOR ) { w.DrawLine( max( nPos, nMajorWidth >> 1 ), (int)( size.cy * .5 + TickTop), max( nPos, nMajorWidth >> 1 ), (int)(size.cy * .5 + TickBottomMaj), nMajorWidth ); Size sz = GetTextSize( txt, StdFont() ); int nTextPos = nPos - (int)( sz.cx / 2.0f + 0.5f ); nTextPos = min( max( 0, nTextPos ), size.cx - sz.cx ); w.DrawText( nTextPos, 0, txt ); } else { w.DrawLine( nPos, (int)( size.cy * .5 + TickTop), nPos, (int)(size.cy * .5 + TickBottomMin ) ); } } else { // vert if( Type == MAJOR ) { w.DrawLine( (int)( size.cx * .5 + TickTop), max( nPos, nMajorWidth >> 1 ), (int)(size.cx * .5 + TickBottomMaj), max( nPos, nMajorWidth >> 1 ), nMajorWidth ); Size sz = GetTextSize( txt, StdFont() ); int nTextPos = nPos - (int)( sz.cy / 2.0f + 0.5f ); nTextPos = min( max( 0, nTextPos ), size.cy - sz.cy ); w.DrawText( 0, nTextPos, txt ); } else { w.DrawLine( (int)(size.cx / 2 + TickTop), nPos, (int)(size.cx * .5 + TickBottomMin), nPos ); } } } Value SliderCtrlX::GetData() const /*********************************************************************************************** * default read of slider value * virtual - public **********************************************************************************************/ { return m_vValues[0]; } Value SliderCtrlX::GetData( int nIndex ) const /*********************************************************************************************** * reads the slider[n] value * virtual - public **********************************************************************************************/ { return m_vValues[nIndex]; } void SliderCtrlX::GotFocus() /*********************************************************************************************** * virtual - public **********************************************************************************************/ { Refresh(); } int SliderCtrlX::HoVe(int x, int y) const /*********************************************************************************************** * returns x for Hslider or y for Vslider * private **********************************************************************************************/ { return IsVert() ? y : x; } int& SliderCtrlX::HoVeR(int& x, int& y) const /*********************************************************************************************** * returns &x for Hslider or &y for Vslider * private **********************************************************************************************/ { return IsVert() ? y : x; } void SliderCtrlX::Inc() /*********************************************************************************************** * increments * virtual - public **********************************************************************************************/ { int n = m_vValues[0]; if(IsNull(m_vValues[0])) n = Min(); else if(n < Max()) { if(m_bRound_step && m_nStep > 1) n = idivceil(n + 1, m_nStep) * m_nStep; else n += m_nStep; if(n > Max()) n = Max(); } if(n != m_vValues[0]) { SetValue( n ); WhenSlideFinish(); UpdateActionRefresh(); } } bool SliderCtrlX::IsVert() const /*********************************************************************************************** * Checks if the slider is vertically oriented * public **********************************************************************************************/ { return GetSize().cx < GetSize().cy; } bool SliderCtrlX::Key(dword key, int repcnt) /*********************************************************************************************** * handles keys addressed to the slider (GotFocussed) * only if it is a CONTROL * virtual - public **********************************************************************************************/ { // No thumb action for indicator if (m_nSliderType == INDICATOR) return Ctrl::Key(key, repcnt); if(IsEditable()) switch(key) { case K_LEFT: case K_DOWN: Dec(); return true; case K_RIGHT: case K_UP: Inc(); return true; } return Ctrl::Key(key, repcnt); } void SliderCtrlX::LeftDown(Point pos, dword keyflags) /*********************************************************************************************** * handles the left mouse button if the slider is s CONTROL * virtual - public **********************************************************************************************/ { if(!IsEditable()) return; // No thumb action for indicator if (m_nSliderType == INDICATOR) return; SetWantFocus(); int thumbPos = SliderToClient(m_vValues[0]); int p = HoVe(pos.x, pos.y); if(IsNull(thumbPos)) { SetValue( ClientToSlider(p) ); WhenSlideFinish(); UpdateActionRefresh(); } // Did we click on the thumb? else if( ( p >= ( thumbPos - nHalfThumb ) ) && ( p < ( thumbPos + nHalfThumb ) ) ) SetCapture(); else if( m_bJump ) { m_vValues[0] = ClientToSlider(p); WhenSlideFinish(); UpdateActionRefresh(); } else { if( ( ( p < thumbPos) && (m_nMin == Min() ) ) || ( (p > thumbPos) && ( m_nMin == Max() ) ) ) IsInverted() ? Inc() : Dec(); else IsInverted() ? Dec() : Inc(); } Refresh(); } void SliderCtrlX::LeftRepeat(Point p, dword f) /*********************************************************************************************** * virtual - public **********************************************************************************************/ { if(!HasCapture()) LeftDown(p, f); } void SliderCtrlX::LeftUp(Point pos, dword keyflags) /*********************************************************************************************** * virtual - public **********************************************************************************************/ { if (HasCapture()) WhenSlideFinish(); Refresh(); } void SliderCtrlX::LostFocus() /*********************************************************************************************** * virtual - public **********************************************************************************************/ { Refresh(); } SliderCtrlX& SliderCtrlX::MinMax(int _min, int _max) /*********************************************************************************************** * Restricts slider to Min, Max values * public **********************************************************************************************/ { if(m_nMin != _min || m_nMax != _max) { m_nMin = _min; m_nMax = _max; if(!IsNull(m_vValues[0])) { int v = minmax(m_vValues[0], Min(), Max()); if(m_vValues[0] != v) { SetValue( v ); Update(); } } Refresh(); } return *this; } void SliderCtrlX::MouseMove(Point pos, dword keyflags) /*********************************************************************************************** * virtual - public **********************************************************************************************/ { if(HasCapture()) { int n; //int p = HoVe(pos.x, pos.y); //int thumbPos = SliderToClient(m_vValues[0]); if (IsInverted()) n = ClientToSlider(HoVe(GetSize().cx-pos.x, GetSize().cy-pos.y)); else n = ClientToSlider(HoVe(pos.x, pos.y)); if(n != m_vValues[0]) { SetValue( n ); UpdateActionRefresh(); } } } void SliderCtrlX::Paint(Draw& w) /*********************************************************************************************** * Draws the slider on the canvas w * virtual - public **********************************************************************************************/ { Size size = GetSize(); if (m_ThumbImg.IsEmpty()) SetThumbType(m_nThumbNumber); if(IsVert()) { // Vertical slider // Draw Line Border int half = size.cx >> 1; DrawBorder(w, half - BORDER1, BORDER1, border2, size.cy - border2, InsetBorder); if (IsInverted()) // draw the fill where bottom is the min value w.DrawRect(half - BORDER1+1, SliderToClient(m_vValues[0])+1, border2-2, size.cy-SliderToClient(m_vValues[0])-BORDER1-2, m_FillColor); else // draw the fill where top is the min value w.DrawRect(half - BORDER1+1, BORDER1+1, border2-2, SliderToClient(m_vValues[0])-BORDER1-2, m_FillColor); } else { // Horz slider // Draw Line Border int half = size.cy >> 1; DrawBorder(w, BORDER1, half - BORDER1, size.cx - border2, border2, InsetBorder); if (IsInverted()) // draw the fill where left is the min value w.DrawRect(SliderToClient(m_vValues[0]), half - BORDER1+2, size.cx-SliderToClient(m_vValues[0])-2, border2-3, m_FillColor); else // draw the fill where right is the min value w.DrawRect(BORDER1, half - BORDER1+2, SliderToClient(m_vValues[0])-2, border2-3, m_FillColor); } // draw gradations for( int i = Min(); ( m_nMajorTicks > 0 ) && ( i <= Max() ) ; i += ( m_nMinorTicks == 0 ? m_nMajorTicks : m_nMinorTicks ) ) { int nPos = SliderToClient( i ); if( ( m_nMajorTicks != 0 ) && ( i % m_nMajorTicks ) == 0 ) DrawTick( w, MAJOR, (HOVE)HoVe( HORZ, VERT ), nPos, i ); else if( ( m_nMinorTicks != 0 ) && ( i % m_nMinorTicks ) == 0 ) DrawTick( w, MINOR, (HOVE)HoVe( HORZ, VERT ), nPos, i ); } // Draw thumbs if(IsVert()) { // Vertical slider for( int i = m_vValues.GetCount() - 1 ; i >= 0 ; i-- ) { if(!IsNull(m_vValues[i])) { w.DrawImage((size.cx - m_ThumbSize.cx ) >> 1, SliderToClient(m_vValues[i]) - ( m_ThumbSize.cy >> 1 ), HasCapture() || HasFocus() ? ( m_bUseCustomThumbs ? m_vThumbImgsFocus[i] : m_ThumbFImg ) : ( m_bUseCustomThumbs ? m_vThumbImgs[i] : m_ThumbImg ) ); } } } else { // Horz slider for( int i = m_vValues.GetCount() - 1 ; i >= 0 ; i-- ) { if(!IsNull(m_vValues[i])) { w.DrawImage(SliderToClient(m_vValues[i]) - ( m_ThumbSize.cx >> 1 ), m_nThickness + ((size.cy - m_ThumbSize.cy) >> 1), HasCapture() || HasFocus() ? (m_bUseCustomThumbs ? m_vThumbImgsFocus[i] : m_ThumbFImg) : (m_bUseCustomThumbs ? m_vThumbImgs[i] : m_ThumbImg)); } } } if(HasFocus()) DrawFocus(w, size); } void SliderCtrlX::SetData(const Value& v) /*********************************************************************************************** * sets the slider value within its' range * virtual - public **********************************************************************************************/ { SetValue( v ); } SliderCtrlX& SliderCtrlX::SetThumbType(int n) /*********************************************************************************************** * Selects the thumb according to the choosen type * public **********************************************************************************************/ { m_nThumbNumber = n; // This is called before size is known, so we cannot choose the right thumb... if (GetSize().IsEmpty()) { m_ThumbImg.Clear(); return *this; } m_nThumbType = m_nThumbNumber*2; if (IsVert()) m_nThumbNumber = 0; m_ThumbImg = SliderThumbsImg::Get(m_nThumbType); m_ThumbFImg = SliderThumbsImg::Get(m_nThumbType+1); if (IsVert()) { m_ThumbImg = RotateAntiClockwise(m_ThumbImg); m_ThumbFImg = RotateAntiClockwise(m_ThumbFImg); } if (m_nTickPosition == BOTTOM) { IsVert() ? m_ThumbImg = MirrorHorz(m_ThumbImg) : m_ThumbImg = MirrorVert(m_ThumbImg); IsVert() ? m_ThumbFImg = MirrorHorz(m_ThumbFImg) : m_ThumbFImg = MirrorVert(m_ThumbFImg); } m_ThumbSize = m_bUseCustomThumbs ? m_vThumbImgs[0].GetSize() : m_ThumbImg.GetSize(); nHalfThumb = HoVe(m_ThumbSize.cx, m_ThumbSize.cy) >> 1; return *this; } Value SliderCtrlX::SetValue( const Value& v, int nIndex /*= 0 */ ) /*********************************************************************************************** * sets the value for the slider position * public **********************************************************************************************/ { int n = v; if(!IsNull(n)) { n = minmax(n, Min(), Max() ); if(n < Max() && n > Min()) { if(m_bRound_step && m_nStep > 1) n = idivceil(n, m_nStep) * m_nStep; if(n > Max()) n = Max(); if (n < Min()) n = Min(); } if( m_vValues.At(nIndex) != n ) { m_vValues.At(nIndex) = n; if( m_vctrlOutput.GetCount() > nIndex ) m_vctrlOutput[nIndex]->SetData( n ); UpdateRefresh(); } } return m_vValues.At(nIndex); } int SliderCtrlX::SliderToClient(int v) const /*********************************************************************************************** * CONVERTS SLIDER VALUES TO Canvas coordinates * private **********************************************************************************************/ { if(IsNull(v)) return Null; v = minmax(v, Min(), Max()); if( v < 0 ) v = iscalefloor(v - m_nMin, HoVe(GetSize().cx - border2 - m_ThumbSize.cx, GetSize().cy - border2 - m_ThumbSize.cy), m_nMax - m_nMin); else v = iscaleceil(v - m_nMin, HoVe(GetSize().cx - border2 - m_ThumbSize.cx, GetSize().cy - border2 - m_ThumbSize.cy), m_nMax - m_nMin); v += HoVe(m_ThumbSize.cx/2, m_ThumbSize.cy/2); if (IsInverted()) IsVert() ? v = GetSize().cy - v : v = GetSize().cx - v; return v; } }