//  // // # # ### # # -= Nuclex Library =-  // // ## # # # ## ## SliderWidget.cpp - Slider GUI component  // // ### # # ###  // // # ### # ### Slider which can be moved within a limited range  // // # ## # # ## ##  // // # # ### # # R1 (C)2002-2004 Markus Ewald -> License.txt  // //  // #include "Nuclex/GUI/SliderWidget.h" #include "Nuclex/Video/VertexDrawer.h" #include "Nuclex/Input/KeyboardInputDevice.h" //#include "DirectX/DInput.h" //!!Temporary #include "Nuclex/Kernel.h" using namespace Nuclex; using namespace Nuclex::GUI; SliderWidget::Painter SliderWidget::DefaultPainter; namespace { float clamp(float f) { return min(max(f, 0.0f), 1.0f); } } // ############################################################################################# // // # Nuclex::GUI::SliderWidget::SliderWidget() Constructor # // // ############################################################################################# // /** Initializes a new slider widget @param Region Region in which to place the slider @param fPosition Initial position of the slider, from 0.0 to 1.0 @param fSize The slider element's size @param Steps Number of steps from the left side to the right side. A number of 0 will disable stepping. @param sStyle The slider's visual style @param Painter Delegate used for drawing the slider. */ SliderWidget::SliderWidget(const Box2 &Region, float fPosition, float fSize, size_t Steps, Orientation eOrientation, const string sStyle, Painter &ThePainter) : Widget(Region, sStyle), m_eOrientation(eOrientation), m_bEnabled(true), m_Painter(ThePainter), m_bDragging(false), m_bHover(false), m_fPosition(fPosition), m_fWidth(fSize), m_Steps(Steps) { // Make sure the user provided position is valid when using steps snapToStep(); } // ############################################################################################# // // # Nuclex::GUI::SliderWidget::clone() # // // ############################################################################################# // /** Creates a clone of the slider @return The cloned slider */ shared_ptr SliderWidget::clone() const { return shared_ptr(new SliderWidget(*this)); } // ############################################################################################# // // # Nuclex::GUI::SliderWidget::setEnabled() # // // ############################################################################################# // /** Enables or disables the slider @param bEnabled Whether the slider should be enabled or disabled */ void SliderWidget::setEnabled(bool bEnabled) { m_bEnabled = bEnabled; if(!bEnabled) m_bDragging = false; } // ############################################################################################# // // # Nuclex::GUI::SliderWidget::processUserInput() # // // ############################################################################################# // /** Processes an input event which has been sent to the button @param InputEvent The input event's data */ bool SliderWidget::processInput(const InputReceiver::Event &InputEvent) { switch(InputEvent.eType) { // Update the slider when the mouse is moved case InputReceiver::Event::T_MOUSEMOVE: { m_bHover = getSliderRegion().intersects(Point2(InputEvent.Location, StaticCastTag())); // Is the slider element being dragged ? if(m_bDragging) { float fOldPosition = m_fPosition; // Adjust the slider elements position Point2 Location = Point2(InputEvent.Location, StaticCastTag()) - m_DragPoint; if(m_eOrientation == O_HORIZONTAL) m_fPosition = clamp((Location.X - m_Region.TL.X) / (m_Region.getWidth() - getSliderWidth())); else m_fPosition = clamp((Location.Y - m_Region.TL.Y) / (m_Region.getHeight() - getSliderWidth())); snapToStep(); // Fire an event if the position has been changed if(m_fPosition != fOldPosition) OnSlide(m_fPosition); } break; } // Mouse button pressed within slider region case InputReceiver::Event::T_MOUSEBUTTONDOWN: { // Calculate slider region Box2 SliderRegion(getSliderRegion()); // Left mouse ? Move or drag slider. if(InputEvent.nButton == 0) { long nMovement; if(m_eOrientation == O_HORIZONTAL) nMovement = (InputEvent.Location.X < SliderRegion.TL.X) ? -1 : ((InputEvent.Location.X >= SliderRegion.BR.X) ? +1 : 0); else nMovement = (InputEvent.Location.Y < SliderRegion.TL.Y) ? -1 : ((InputEvent.Location.Y >= SliderRegion.BR.Y) ? +1 : 0); // Move (if clicked beside the slider element) or begin dragging if(nMovement) { move(nMovement); } else { m_DragPoint = Point2(InputEvent.Location, StaticCastTag()); if(m_eOrientation == O_HORIZONTAL) m_DragPoint.X -= m_Region.TL.X + (m_Region.getWidth() - getSliderWidth()) * m_fPosition; else m_DragPoint.Y -= m_Region.TL.Y + (m_Region.getHeight() - getSliderWidth()) * m_fPosition; m_bDragging = true; } } m_bHover = getSliderRegion().intersects(Point2(InputEvent.Location, StaticCastTag())); break; } // Mouse button released, stop dragging case InputReceiver::Event::T_MOUSEBUTTONUP: { m_bHover = getSliderRegion().intersects(Point2(InputEvent.Location, StaticCastTag())); if(m_bDragging && (InputEvent.nButton == 0)) m_bDragging = false; break; } // Key pressed while slider widget was focused case InputReceiver::Event::T_KEYDOWN: { long nMovement; if((InputEvent.cKey == Input::KeyboardInputDevice::getScancode(L"Left")) || (InputEvent.cKey == Input::KeyboardInputDevice::getScancode(L"Up"))) nMovement = -1; else if((InputEvent.cKey == Input::KeyboardInputDevice::getScancode(L"Right")) || (InputEvent.cKey == Input::KeyboardInputDevice::getScancode(L"Down"))) nMovement = +1; else nMovement = 0; move(nMovement); break; } } return true; } // ############################################################################################# // // # Nuclex::GUI::SliderWidget::getSliderRegion() # // // ############################################################################################# // Box2 SliderWidget::getSliderRegion() const { float fSliderWidth = getSliderWidth(); float fScrollWidth = (m_eOrientation == O_HORIZONTAL) ? (m_Region.BR.X - m_Region.TL.X) - fSliderWidth: (m_Region.BR.Y - m_Region.TL.Y) - fSliderWidth; if(m_eOrientation == O_HORIZONTAL) return Box2( static_cast(round(m_Region.TL.X + fScrollWidth * m_fPosition)), m_Region.TL.Y, static_cast(round(m_Region.TL.X + fScrollWidth * m_fPosition + fSliderWidth)), m_Region.BR.Y ); else return Box2( m_Region.TL.X, static_cast(round(m_Region.TL.Y + fScrollWidth * m_fPosition)), m_Region.BR.X, static_cast(round(m_Region.TL.Y + fScrollWidth * m_fPosition + fSliderWidth)) ); } // ############################################################################################# // // # Nuclex::GUI::SliderWidget::snapToStep() # // // ############################################################################################# // void SliderWidget::snapToStep() { if(m_Steps > 0) { float fPosition = 0; float fMinDistance = 1.0f; for(size_t Step = 0; Step < m_Steps; ++Step) { float fDistance = fabs((static_cast(Step) / (m_Steps - 1)) - m_fPosition); if(fDistance < fMinDistance) { fPosition = static_cast(Step) / (m_Steps - 1); fMinDistance = fDistance; } } m_fPosition = fPosition; } } void SliderWidget::move(long nClicks) { float fOldPosition = m_fPosition; if(m_Steps > 0) m_fPosition += static_cast(nClicks) / (m_Steps - 1); else m_fPosition += m_fWidth * static_cast(nClicks) / 2; if(m_fPosition != fOldPosition) OnSlide(m_fPosition); }