diff --git a/client/CMakeLists.txt b/client/CMakeLists.txt index 44fe19d93..59c7eb10f 100644 --- a/client/CMakeLists.txt +++ b/client/CMakeLists.txt @@ -99,6 +99,8 @@ set(client_SRCS widgets/MiscWidgets.cpp widgets/ObjectLists.cpp widgets/TextControls.cpp + widgets/Scrollable.cpp + widgets/Slider.cpp widgets/CArtifactsOfHeroBase.cpp widgets/CArtifactsOfHeroMain.cpp widgets/CArtifactsOfHeroKingdom.cpp @@ -251,6 +253,8 @@ set(client_HEADERS widgets/MiscWidgets.h widgets/ObjectLists.h widgets/TextControls.h + widgets/Scrollable.h + widgets/Slider.h widgets/CArtifactsOfHeroBase.h widgets/CArtifactsOfHeroMain.h widgets/CArtifactsOfHeroKingdom.h diff --git a/client/gui/InterfaceObjectConfigurable.cpp b/client/gui/InterfaceObjectConfigurable.cpp index 4f3a508b4..8e4dfd15c 100644 --- a/client/gui/InterfaceObjectConfigurable.cpp +++ b/client/gui/InterfaceObjectConfigurable.cpp @@ -21,6 +21,7 @@ #include "../widgets/Buttons.h" #include "../widgets/MiscWidgets.h" #include "../widgets/ObjectLists.h" +#include "../widgets/Slider.h" #include "../widgets/TextControls.h" #include "../windows/GUIClasses.h" #include "../windows/InfoWindows.h" diff --git a/client/lobby/CSelectionBase.cpp b/client/lobby/CSelectionBase.cpp index ab58f2a86..69d9ee8b6 100644 --- a/client/lobby/CSelectionBase.cpp +++ b/client/lobby/CSelectionBase.cpp @@ -28,10 +28,11 @@ #include "../gui/Shortcut.h" #include "../gui/WindowHandler.h" #include "../mainmenu/CMainMenu.h" -#include "../widgets/CComponent.h" #include "../widgets/Buttons.h" +#include "../widgets/CComponent.h" #include "../widgets/MiscWidgets.h" #include "../widgets/ObjectLists.h" +#include "../widgets/Slider.h" #include "../widgets/TextControls.h" #include "../windows/GUIClasses.h" #include "../windows/InfoWindows.h" diff --git a/client/lobby/OptionsTab.cpp b/client/lobby/OptionsTab.cpp index df91a5e07..525c9ad5c 100644 --- a/client/lobby/OptionsTab.cpp +++ b/client/lobby/OptionsTab.cpp @@ -20,6 +20,7 @@ #include "../widgets/Buttons.h" #include "../widgets/MiscWidgets.h" #include "../widgets/ObjectLists.h" +#include "../widgets/Slider.h" #include "../widgets/TextControls.h" #include "../windows/GUIClasses.h" #include "../windows/InfoWindows.h" diff --git a/client/lobby/RandomMapTab.cpp b/client/lobby/RandomMapTab.cpp index c203d903c..346f1c59f 100644 --- a/client/lobby/RandomMapTab.cpp +++ b/client/lobby/RandomMapTab.cpp @@ -21,6 +21,7 @@ #include "../widgets/Buttons.h" #include "../widgets/MiscWidgets.h" #include "../widgets/ObjectLists.h" +#include "../widgets/Slider.h" #include "../widgets/TextControls.h" #include "../windows/GUIClasses.h" #include "../windows/InfoWindows.h" diff --git a/client/lobby/SelectionTab.cpp b/client/lobby/SelectionTab.cpp index 1dec28ea7..86c499e0c 100644 --- a/client/lobby/SelectionTab.cpp +++ b/client/lobby/SelectionTab.cpp @@ -22,6 +22,7 @@ #include "../widgets/Buttons.h" #include "../widgets/MiscWidgets.h" #include "../widgets/ObjectLists.h" +#include "../widgets/Slider.h" #include "../widgets/TextControls.h" #include "../windows/GUIClasses.h" #include "../windows/InfoWindows.h" diff --git a/client/widgets/Buttons.cpp b/client/widgets/Buttons.cpp index bfdfc86e6..b4ce17b60 100644 --- a/client/widgets/Buttons.cpp +++ b/client/widgets/Buttons.cpp @@ -472,343 +472,3 @@ int CToggleGroup::getSelected() const { return selectedID; } - -void CSlider::sliderClicked() -{ - addUsedEvents(MOVE); -} - -void CSlider::mouseMoved (const Point & cursorPosition) -{ - double v = 0; - if(horizontal) - { - if( std::abs(cursorPosition.y-(pos.y+pos.h/2)) > pos.h/2+40 || std::abs(cursorPosition.x-(pos.x+pos.w/2)) > pos.w/2 ) - return; - v = cursorPosition.x - pos.x - 24; - v *= positions; - v /= (pos.w - 48); - } - else - { - if(std::abs(cursorPosition.x-(pos.x+pos.w/2)) > pos.w/2+40 || std::abs(cursorPosition.y-(pos.y+pos.h/2)) > pos.h/2 ) - return; - v = cursorPosition.y - pos.y - 24; - v *= positions; - v /= (pos.h - 48); - } - v += 0.5; - if(v!=value) - { - moveTo(static_cast(v)); - } -} - -void CSlider::setScrollStep(int to) -{ - scrollStep = to; -} - -void CSlider::setScrollBounds(const Rect & bounds ) -{ - scrollBounds = bounds; -} - -void CSlider::clearScrollBounds() -{ - scrollBounds = std::nullopt; -} - -int CSlider::getAmount() const -{ - return amount; -} - -int CSlider::getValue() const -{ - return value; -} - -int CSlider::getCapacity() const -{ - return capacity; -} - -void CSlider::moveLeft() -{ - moveTo(value-1); -} - -void CSlider::moveRight() -{ - moveTo(value+1); -} - -void CSlider::moveBy(int amount) -{ - moveTo(value + amount); -} - -void CSlider::updateSliderPos() -{ - if(horizontal) - { - if(positions) - { - double part = static_cast(value) / positions; - part*=(pos.w-48); - int newPos = static_cast(part + pos.x + 16 - slider->pos.x); - slider->moveBy(Point(newPos, 0)); - } - else - slider->moveTo(Point(pos.x+16, pos.y)); - } - else - { - if(positions) - { - double part = static_cast(value) / positions; - part*=(pos.h-48); - int newPos = static_cast(part + pos.y + 16 - slider->pos.y); - slider->moveBy(Point(0, newPos)); - } - else - slider->moveTo(Point(pos.x, pos.y+16)); - } -} - -void CSlider::moveTo(int to) -{ - vstd::amax(to, 0); - vstd::amin(to, positions); - - //same, old position? - if(value == to) - return; - value = to; - - updateSliderPos(); - - moved(to); -} - -void CSlider::clickLeft(tribool down, bool previousState) -{ - if(down && !slider->isBlocked()) - { - double pw = 0; - double rw = 0; - if(horizontal) - { - pw = GH.getCursorPosition().x-pos.x-25; - rw = pw / static_cast(pos.w - 48); - } - else - { - pw = GH.getCursorPosition().y-pos.y-24; - rw = pw / (pos.h-48); - } - if(pw < -8 || pw > (horizontal ? pos.w : pos.h) - 40) - return; - // if (rw>1) return; - // if (rw<0) return; - slider->clickLeft(true, slider->isMouseButtonPressed(MouseButton::LEFT)); - moveTo((int)(rw * positions + 0.5)); - return; - } - removeUsedEvents(MOVE); -} - -bool CSlider::receiveEvent(const Point &position, int eventType) const -{ - if (eventType != WHEEL && eventType != GESTURE_PANNING) - { - return CIntObject::receiveEvent(position, eventType); - } - - if (!scrollBounds) - return true; - - Rect testTarget = *scrollBounds + pos.topLeft(); - - return testTarget.isInside(position); -} - -void CSlider::setPanningStep(int to) -{ - panningDistanceSingle = to; -} - -void CSlider::panning(bool on) -{ - panningDistanceAccumulated = 0; -} - -void CSlider::gesturePanning(const Point & distanceDelta) -{ - if (horizontal) - panningDistanceAccumulated += -distanceDelta.x; - else - panningDistanceAccumulated += distanceDelta.y; - - if (-panningDistanceAccumulated > panningDistanceSingle ) - { - int scrollAmount = (-panningDistanceAccumulated) / panningDistanceSingle; - moveBy(-scrollAmount); - panningDistanceAccumulated += scrollAmount * panningDistanceSingle; - } - - if (panningDistanceAccumulated > panningDistanceSingle ) - { - int scrollAmount = panningDistanceAccumulated / panningDistanceSingle; - moveBy(scrollAmount); - panningDistanceAccumulated += -scrollAmount * panningDistanceSingle; - } -} - -CSlider::CSlider(Point position, int totalw, std::function Moved, int Capacity, int Amount, int Value, bool Horizontal, CSlider::EStyle style) - : CIntObject(LCLICK | RCLICK | WHEEL | GESTURE_PANNING ), - capacity(Capacity), - horizontal(Horizontal), - amount(Amount), - value(Value), - scrollStep(1), - moved(Moved), - panningDistanceAccumulated(0), - panningDistanceSingle(32) -{ - OBJECT_CONSTRUCTION_CAPTURING(255-DISPOSE); - setAmount(amount); - vstd::amax(value, 0); - vstd::amin(value, positions); - - pos.x += position.x; - pos.y += position.y; - - if(style == BROWN) - { - std::string name = horizontal ? "IGPCRDIV.DEF" : "OVBUTN2.DEF"; - //NOTE: this images do not have "blocked" frames. They should be implemented somehow (e.g. palette transform or something...) - - left = std::make_shared(Point(), name, CButton::tooltip()); - right = std::make_shared(Point(), name, CButton::tooltip()); - slider = std::make_shared(Point(), name, CButton::tooltip()); - - left->setImageOrder(0, 1, 1, 1); - right->setImageOrder(2, 3, 3, 3); - slider->setImageOrder(4, 4, 4, 4); - } - else - { - left = std::make_shared(Point(), horizontal ? "SCNRBLF.DEF" : "SCNRBUP.DEF", CButton::tooltip()); - right = std::make_shared(Point(), horizontal ? "SCNRBRT.DEF" : "SCNRBDN.DEF", CButton::tooltip()); - slider = std::make_shared(Point(), "SCNRBSL.DEF", CButton::tooltip()); - } - slider->actOnDown = true; - slider->soundDisabled = true; - left->soundDisabled = true; - right->soundDisabled = true; - - if (horizontal) - right->moveBy(Point(totalw - right->pos.w, 0)); - else - right->moveBy(Point(0, totalw - right->pos.h)); - - left->addCallback(std::bind(&CSlider::moveLeft,this)); - right->addCallback(std::bind(&CSlider::moveRight,this)); - slider->addCallback(std::bind(&CSlider::sliderClicked,this)); - - if(horizontal) - { - pos.h = slider->pos.h; - pos.w = totalw; - } - else - { - pos.w = slider->pos.w; - pos.h = totalw; - } - - updateSliderPos(); -} - -CSlider::~CSlider() = default; - -void CSlider::block( bool on ) -{ - left->block(on); - right->block(on); - slider->block(on); -} - -void CSlider::setAmount( int to ) -{ - amount = to; - positions = to - capacity; - vstd::amax(positions, 0); -} - -void CSlider::showAll(Canvas & to) -{ - to.drawColor(pos, Colors::BLACK); - CIntObject::showAll(to); -} - -void CSlider::wheelScrolled(int distance) -{ - // vertical slider -> scrolling up move slider upwards - // horizontal slider -> scrolling up moves slider towards right - bool positive = ((distance < 0) != horizontal); - - moveTo(value + 3 * (positive ? +scrollStep : -scrollStep)); -} - -void CSlider::keyPressed(EShortcut key) -{ - int moveDest = value; - switch(key) - { - case EShortcut::MOVE_UP: - if (!horizontal) - moveDest = value - scrollStep; - break; - case EShortcut::MOVE_LEFT: - if (horizontal) - moveDest = value - scrollStep; - break; - case EShortcut::MOVE_DOWN: - if (!horizontal) - moveDest = value + scrollStep; - break; - case EShortcut::MOVE_RIGHT: - if (horizontal) - moveDest = value + scrollStep; - break; - case EShortcut::MOVE_PAGE_UP: - moveDest = value - capacity + scrollStep; - break; - case EShortcut::MOVE_PAGE_DOWN: - moveDest = value + capacity - scrollStep; - break; - case EShortcut::MOVE_FIRST: - moveDest = 0; - break; - case EShortcut::MOVE_LAST: - moveDest = amount - capacity; - break; - default: - return; - } - - moveTo(moveDest); -} - -void CSlider::moveToMin() -{ - moveTo(0); -} - -void CSlider::moveToMax() -{ - moveTo(amount); -} diff --git a/client/widgets/Buttons.h b/client/widgets/Buttons.h index 7bb1d83eb..5ff00d005 100644 --- a/client/widgets/Buttons.h +++ b/client/widgets/Buttons.h @@ -181,94 +181,3 @@ public: void setSelectedOnly(int id); int getSelected() const; }; - -/// A typical slider which can be orientated horizontally/vertically. -class CSlider : public CIntObject -{ - //if vertical then left=up - std::shared_ptr left; - std::shared_ptr right; - std::shared_ptr slider; - - std::optional scrollBounds; - - /// how many elements are visible simultaneously - int capacity; - /// number of highest position, or 0 if there is only one - int positions; - /// if true, then slider is not vertical but horizontal - bool horizontal; - /// total amount of elements in the list - int amount; - /// topmost vislble (first active) element - int value; - /// how many elements will be scrolled via one click, default = 1 - int scrollStep; - - /// How far player must move finger/mouse to move slider by 1 via gesture - int panningDistanceSingle; - /// How far have player moved finger/mouse via gesture so far. - int panningDistanceAccumulated; - - CFunctionList moved; - - void updateSliderPos(); - void sliderClicked(); - -public: - enum EStyle - { - BROWN, - BLUE - }; - - void block(bool on); - - /// Controls how many items wil be scrolled via one click - void setScrollStep(int to); - - /// Controls size of panning step needed to move list by 1 item - void setPanningStep(int to); - - /// If set, mouse scroll will only scroll slider when inside of this area - void setScrollBounds(const Rect & bounds ); - void clearScrollBounds(); - - /// Value modifiers - void moveLeft(); - void moveRight(); - void moveTo(int value); - void moveBy(int amount); - void moveToMin(); - void moveToMax(); - - /// Amount modifier - void setAmount(int to); - - /// Accessors - int getAmount() const; - int getValue() const; - int getCapacity() const; - - void addCallback(std::function callback); - - bool receiveEvent(const Point & position, int eventType) const override; - - void keyPressed(EShortcut key) override; - void wheelScrolled(int distance) override; - void gesturePanning(const Point & distanceDelta) override; - void clickLeft(tribool down, bool previousState) override; - void mouseMoved (const Point & cursorPosition) override; - void showAll(Canvas & to) override; - void panning(bool on) override; - - /// @param position coordinates of slider - /// @param length length of slider ribbon, including left/right buttons - /// @param Moved function that will be called whenever slider moves - /// @param Capacity maximal number of visible at once elements - /// @param Amount total amount of elements, including not visible - /// @param Value starting position - CSlider(Point position, int length, std::function Moved, int Capacity, int Amount, - int Value=0, bool Horizontal=true, EStyle style = BROWN); - ~CSlider(); -}; diff --git a/client/widgets/ObjectLists.cpp b/client/widgets/ObjectLists.cpp index d669dd348..a6eb6a6bc 100644 --- a/client/widgets/ObjectLists.cpp +++ b/client/widgets/ObjectLists.cpp @@ -11,7 +11,7 @@ #include "ObjectLists.h" #include "../gui/CGuiHandler.h" -#include "Buttons.h" +#include "Slider.h" CObjectList::CObjectList(CreateFunc create) : createObject(create) diff --git a/client/widgets/Scrollable.cpp b/client/widgets/Scrollable.cpp new file mode 100644 index 000000000..e538a93ef --- /dev/null +++ b/client/widgets/Scrollable.cpp @@ -0,0 +1,12 @@ +/* + * Scrollable.cpp, part of VCMI engine + * + * Authors: listed in file AUTHORS in main folder + * + * License: GNU General Public License v2.0 or later + * Full text of license available in license.txt file, in main folder + * + */ + +#include "StdInc.h" +#include "Scrollable.h" diff --git a/client/widgets/Scrollable.h b/client/widgets/Scrollable.h new file mode 100644 index 000000000..21ee7b77e --- /dev/null +++ b/client/widgets/Scrollable.h @@ -0,0 +1,13 @@ +/* + * Scrollable.h, part of VCMI engine + * + * Authors: listed in file AUTHORS in main folder + * + * License: GNU General Public License v2.0 or later + * Full text of license available in license.txt file, in main folder + * + */ + +#pragma once + +#include "../gui/CIntObject.h" diff --git a/client/widgets/Slider.cpp b/client/widgets/Slider.cpp new file mode 100644 index 000000000..abdf18c6e --- /dev/null +++ b/client/widgets/Slider.cpp @@ -0,0 +1,359 @@ +/* + * Slider.cpp, part of VCMI engine + * + * Authors: listed in file AUTHORS in main folder + * + * License: GNU General Public License v2.0 or later + * Full text of license available in license.txt file, in main folder + * + */ + +#include "StdInc.h" +#include "Slider.h" + +#include "Buttons.h" + +#include "../gui/MouseButton.h" +#include "../gui/Shortcut.h" +#include "../gui/CGuiHandler.h" +#include "../render/Canvas.h" + +void CSlider::sliderClicked() +{ + addUsedEvents(MOVE); +} + +void CSlider::mouseMoved (const Point & cursorPosition) +{ + double v = 0; + if(horizontal) + { + if( std::abs(cursorPosition.y-(pos.y+pos.h/2)) > pos.h/2+40 || std::abs(cursorPosition.x-(pos.x+pos.w/2)) > pos.w/2 ) + return; + v = cursorPosition.x - pos.x - 24; + v *= positions; + v /= (pos.w - 48); + } + else + { + if(std::abs(cursorPosition.x-(pos.x+pos.w/2)) > pos.w/2+40 || std::abs(cursorPosition.y-(pos.y+pos.h/2)) > pos.h/2 ) + return; + v = cursorPosition.y - pos.y - 24; + v *= positions; + v /= (pos.h - 48); + } + v += 0.5; + if(v!=value) + { + moveTo(static_cast(v)); + } +} + +void CSlider::setScrollStep(int to) +{ + scrollStep = to; +} + +void CSlider::setScrollBounds(const Rect & bounds ) +{ + scrollBounds = bounds; +} + +void CSlider::clearScrollBounds() +{ + scrollBounds = std::nullopt; +} + +int CSlider::getAmount() const +{ + return amount; +} + +int CSlider::getValue() const +{ + return value; +} + +int CSlider::getCapacity() const +{ + return capacity; +} + +void CSlider::moveLeft() +{ + moveTo(value-1); +} + +void CSlider::moveRight() +{ + moveTo(value+1); +} + +void CSlider::moveBy(int amount) +{ + moveTo(value + amount); +} + +void CSlider::updateSliderPos() +{ + if(horizontal) + { + if(positions) + { + double part = static_cast(value) / positions; + part*=(pos.w-48); + int newPos = static_cast(part + pos.x + 16 - slider->pos.x); + slider->moveBy(Point(newPos, 0)); + } + else + slider->moveTo(Point(pos.x+16, pos.y)); + } + else + { + if(positions) + { + double part = static_cast(value) / positions; + part*=(pos.h-48); + int newPos = static_cast(part + pos.y + 16 - slider->pos.y); + slider->moveBy(Point(0, newPos)); + } + else + slider->moveTo(Point(pos.x, pos.y+16)); + } +} + +void CSlider::moveTo(int to) +{ + vstd::amax(to, 0); + vstd::amin(to, positions); + + //same, old position? + if(value == to) + return; + value = to; + + updateSliderPos(); + + moved(to); +} + +void CSlider::clickLeft(tribool down, bool previousState) +{ + if(down && !slider->isBlocked()) + { + double pw = 0; + double rw = 0; + if(horizontal) + { + pw = GH.getCursorPosition().x-pos.x-25; + rw = pw / static_cast(pos.w - 48); + } + else + { + pw = GH.getCursorPosition().y-pos.y-24; + rw = pw / (pos.h-48); + } + if(pw < -8 || pw > (horizontal ? pos.w : pos.h) - 40) + return; + // if (rw>1) return; + // if (rw<0) return; + slider->clickLeft(true, slider->isMouseButtonPressed(MouseButton::LEFT)); + moveTo((int)(rw * positions + 0.5)); + return; + } + removeUsedEvents(MOVE); +} + +bool CSlider::receiveEvent(const Point &position, int eventType) const +{ + if (eventType != WHEEL && eventType != GESTURE_PANNING) + { + return CIntObject::receiveEvent(position, eventType); + } + + if (!scrollBounds) + return true; + + Rect testTarget = *scrollBounds + pos.topLeft(); + + return testTarget.isInside(position); +} + +void CSlider::setPanningStep(int to) +{ + panningDistanceSingle = to; +} + +void CSlider::panning(bool on) +{ + panningDistanceAccumulated = 0; +} + +void CSlider::gesturePanning(const Point & distanceDelta) +{ + if (horizontal) + panningDistanceAccumulated += -distanceDelta.x; + else + panningDistanceAccumulated += distanceDelta.y; + + if (-panningDistanceAccumulated > panningDistanceSingle ) + { + int scrollAmount = (-panningDistanceAccumulated) / panningDistanceSingle; + moveBy(-scrollAmount); + panningDistanceAccumulated += scrollAmount * panningDistanceSingle; + } + + if (panningDistanceAccumulated > panningDistanceSingle ) + { + int scrollAmount = panningDistanceAccumulated / panningDistanceSingle; + moveBy(scrollAmount); + panningDistanceAccumulated += -scrollAmount * panningDistanceSingle; + } +} + +CSlider::CSlider(Point position, int totalw, std::function Moved, int Capacity, int Amount, int Value, bool Horizontal, CSlider::EStyle style) + : CIntObject(LCLICK | RCLICK | WHEEL | GESTURE_PANNING ), + capacity(Capacity), + horizontal(Horizontal), + amount(Amount), + value(Value), + scrollStep(1), + moved(Moved), + panningDistanceAccumulated(0), + panningDistanceSingle(32) +{ + OBJECT_CONSTRUCTION_CAPTURING(255-DISPOSE); + setAmount(amount); + vstd::amax(value, 0); + vstd::amin(value, positions); + + pos.x += position.x; + pos.y += position.y; + + if(style == BROWN) + { + std::string name = horizontal ? "IGPCRDIV.DEF" : "OVBUTN2.DEF"; + //NOTE: this images do not have "blocked" frames. They should be implemented somehow (e.g. palette transform or something...) + + left = std::make_shared(Point(), name, CButton::tooltip()); + right = std::make_shared(Point(), name, CButton::tooltip()); + slider = std::make_shared(Point(), name, CButton::tooltip()); + + left->setImageOrder(0, 1, 1, 1); + right->setImageOrder(2, 3, 3, 3); + slider->setImageOrder(4, 4, 4, 4); + } + else + { + left = std::make_shared(Point(), horizontal ? "SCNRBLF.DEF" : "SCNRBUP.DEF", CButton::tooltip()); + right = std::make_shared(Point(), horizontal ? "SCNRBRT.DEF" : "SCNRBDN.DEF", CButton::tooltip()); + slider = std::make_shared(Point(), "SCNRBSL.DEF", CButton::tooltip()); + } + slider->actOnDown = true; + slider->soundDisabled = true; + left->soundDisabled = true; + right->soundDisabled = true; + + if (horizontal) + right->moveBy(Point(totalw - right->pos.w, 0)); + else + right->moveBy(Point(0, totalw - right->pos.h)); + + left->addCallback(std::bind(&CSlider::moveLeft,this)); + right->addCallback(std::bind(&CSlider::moveRight,this)); + slider->addCallback(std::bind(&CSlider::sliderClicked,this)); + + if(horizontal) + { + pos.h = slider->pos.h; + pos.w = totalw; + } + else + { + pos.w = slider->pos.w; + pos.h = totalw; + } + + updateSliderPos(); +} + +CSlider::~CSlider() = default; + +void CSlider::block( bool on ) +{ + left->block(on); + right->block(on); + slider->block(on); +} + +void CSlider::setAmount( int to ) +{ + amount = to; + positions = to - capacity; + vstd::amax(positions, 0); +} + +void CSlider::showAll(Canvas & to) +{ + to.drawColor(pos, Colors::BLACK); + CIntObject::showAll(to); +} + +void CSlider::wheelScrolled(int distance) +{ + // vertical slider -> scrolling up move slider upwards + // horizontal slider -> scrolling up moves slider towards right + bool positive = ((distance < 0) != horizontal); + + moveTo(value + 3 * (positive ? +scrollStep : -scrollStep)); +} + +void CSlider::keyPressed(EShortcut key) +{ + int moveDest = value; + switch(key) + { + case EShortcut::MOVE_UP: + if (!horizontal) + moveDest = value - scrollStep; + break; + case EShortcut::MOVE_LEFT: + if (horizontal) + moveDest = value - scrollStep; + break; + case EShortcut::MOVE_DOWN: + if (!horizontal) + moveDest = value + scrollStep; + break; + case EShortcut::MOVE_RIGHT: + if (horizontal) + moveDest = value + scrollStep; + break; + case EShortcut::MOVE_PAGE_UP: + moveDest = value - capacity + scrollStep; + break; + case EShortcut::MOVE_PAGE_DOWN: + moveDest = value + capacity - scrollStep; + break; + case EShortcut::MOVE_FIRST: + moveDest = 0; + break; + case EShortcut::MOVE_LAST: + moveDest = amount - capacity; + break; + default: + return; + } + + moveTo(moveDest); +} + +void CSlider::moveToMin() +{ + moveTo(0); +} + +void CSlider::moveToMax() +{ + moveTo(amount); +} diff --git a/client/widgets/Slider.h b/client/widgets/Slider.h new file mode 100644 index 000000000..52566b4e1 --- /dev/null +++ b/client/widgets/Slider.h @@ -0,0 +1,107 @@ +/* + * Slider.h, part of VCMI engine + * + * Authors: listed in file AUTHORS in main folder + * + * License: GNU General Public License v2.0 or later + * Full text of license available in license.txt file, in main folder + * + */ + +#pragma once + +#include "Scrollable.h" +#include "../../lib/FunctionList.h" + +class CButton; + +/// A typical slider which can be orientated horizontally/vertically. +class CSlider : public CIntObject +{ + //if vertical then left=up + std::shared_ptr left; + std::shared_ptr right; + std::shared_ptr slider; + + std::optional scrollBounds; + + /// how many elements are visible simultaneously + int capacity; + /// number of highest position, or 0 if there is only one + int positions; + /// if true, then slider is not vertical but horizontal + bool horizontal; + /// total amount of elements in the list + int amount; + /// topmost vislble (first active) element + int value; + /// how many elements will be scrolled via one click, default = 1 + int scrollStep; + + /// How far player must move finger/mouse to move slider by 1 via gesture + int panningDistanceSingle; + /// How far have player moved finger/mouse via gesture so far. + int panningDistanceAccumulated; + + CFunctionList moved; + + void updateSliderPos(); + void sliderClicked(); + +public: + enum EStyle + { + BROWN, + BLUE + }; + + void block(bool on); + + /// Controls how many items wil be scrolled via one click + void setScrollStep(int to); + + /// Controls size of panning step needed to move list by 1 item + void setPanningStep(int to); + + /// If set, mouse scroll will only scroll slider when inside of this area + void setScrollBounds(const Rect & bounds ); + void clearScrollBounds(); + + /// Value modifiers + void moveLeft(); + void moveRight(); + void moveTo(int value); + void moveBy(int amount); + void moveToMin(); + void moveToMax(); + + /// Amount modifier + void setAmount(int to); + + /// Accessors + int getAmount() const; + int getValue() const; + int getCapacity() const; + + void addCallback(std::function callback); + + bool receiveEvent(const Point & position, int eventType) const override; + + void keyPressed(EShortcut key) override; + void wheelScrolled(int distance) override; + void gesturePanning(const Point & distanceDelta) override; + void clickLeft(tribool down, bool previousState) override; + void mouseMoved (const Point & cursorPosition) override; + void showAll(Canvas & to) override; + void panning(bool on) override; + + /// @param position coordinates of slider + /// @param length length of slider ribbon, including left/right buttons + /// @param Moved function that will be called whenever slider moves + /// @param Capacity maximal number of visible at once elements + /// @param Amount total amount of elements, including not visible + /// @param Value starting position + CSlider(Point position, int length, std::function Moved, int Capacity, int Amount, + int Value=0, bool Horizontal=true, EStyle style = BROWN); + ~CSlider(); +}; diff --git a/client/widgets/TextControls.cpp b/client/widgets/TextControls.cpp index a89b96feb..159671f0d 100644 --- a/client/widgets/TextControls.cpp +++ b/client/widgets/TextControls.cpp @@ -10,7 +10,7 @@ #include "StdInc.h" #include "TextControls.h" -#include "Buttons.h" +#include "Slider.h" #include "Images.h" #include "../CPlayerInterface.h" diff --git a/client/windows/CMessage.cpp b/client/windows/CMessage.cpp index 837d104d6..bf897be96 100644 --- a/client/windows/CMessage.cpp +++ b/client/windows/CMessage.cpp @@ -18,6 +18,7 @@ #include "../windows/InfoWindows.h" #include "../widgets/Buttons.h" #include "../widgets/CComponent.h" +#include "../widgets/Slider.h" #include "../widgets/TextControls.h" #include "../gui/CGuiHandler.h" #include "../render/CAnimation.h" diff --git a/client/windows/CQuestLog.cpp b/client/windows/CQuestLog.cpp index ce95ef9f6..52ac093f6 100644 --- a/client/windows/CQuestLog.cpp +++ b/client/windows/CQuestLog.cpp @@ -15,9 +15,10 @@ #include "../gui/CGuiHandler.h" #include "../gui/Shortcut.h" -#include "../widgets/CComponent.h" -#include "../adventureMap/AdventureMapInterface.h" #include "../widgets/Buttons.h" +#include "../widgets/CComponent.h" +#include "../widgets/Slider.h" +#include "../adventureMap/AdventureMapInterface.h" #include "../adventureMap/CMinimap.h" #include "../render/Canvas.h" #include "../renderSDL/SDL_Extensions.h" diff --git a/client/windows/CTradeWindow.cpp b/client/windows/CTradeWindow.cpp index 87d3a3642..7cac653cf 100644 --- a/client/windows/CTradeWindow.cpp +++ b/client/windows/CTradeWindow.cpp @@ -18,6 +18,7 @@ #include "../gui/Shortcut.h" #include "../gui/WindowHandler.h" #include "../widgets/Buttons.h" +#include "../widgets/Slider.h" #include "../widgets/TextControls.h" #include "../windows/InfoWindows.h" diff --git a/client/windows/CreaturePurchaseCard.cpp b/client/windows/CreaturePurchaseCard.cpp index c09132d5b..b61a21890 100644 --- a/client/windows/CreaturePurchaseCard.cpp +++ b/client/windows/CreaturePurchaseCard.cpp @@ -19,6 +19,7 @@ #include "../gui/TextAlignment.h" #include "../gui/WindowHandler.h" #include "../widgets/Buttons.h" +#include "../widgets/Slider.h" #include "../widgets/TextControls.h" #include "../widgets/CreatureCostBox.h" diff --git a/client/windows/GUIClasses.cpp b/client/windows/GUIClasses.cpp index 4f7161656..20923b4e0 100644 --- a/client/windows/GUIClasses.cpp +++ b/client/windows/GUIClasses.cpp @@ -21,7 +21,6 @@ #include "../CVideoHandler.h" #include "../CServerHandler.h" -//#include "../adventureMap/CResDataBar.h" #include "../battle/BattleInterfaceClasses.h" #include "../battle/BattleInterface.h" @@ -35,6 +34,7 @@ #include "../widgets/MiscWidgets.h" #include "../widgets/CreatureCostBox.h" #include "../widgets/Buttons.h" +#include "../widgets/Slider.h" #include "../widgets/TextControls.h" #include "../widgets/ObjectLists.h" diff --git a/client/windows/QuickRecruitmentWindow.cpp b/client/windows/QuickRecruitmentWindow.cpp index 46089f898..5339ce495 100644 --- a/client/windows/QuickRecruitmentWindow.cpp +++ b/client/windows/QuickRecruitmentWindow.cpp @@ -13,6 +13,7 @@ #include "../CPlayerInterface.h" #include "../widgets/Buttons.h" #include "../widgets/CreatureCostBox.h" +#include "../widgets/Slider.h" #include "../gui/CGuiHandler.h" #include "../gui/Shortcut.h" #include "../../CCallback.h" diff --git a/client/windows/settings/GeneralOptionsTab.cpp b/client/windows/settings/GeneralOptionsTab.cpp index 5573e0830..cca9e0895 100644 --- a/client/windows/settings/GeneralOptionsTab.cpp +++ b/client/windows/settings/GeneralOptionsTab.cpp @@ -16,6 +16,7 @@ #include "../../gui/CGuiHandler.h" #include "../../gui/WindowHandler.h" #include "../../widgets/Buttons.h" +#include "../../widgets/Slider.h" #include "../../widgets/TextControls.h" #include "../../widgets/Images.h" #include "CGameInfo.h"