From 4c67d7220e8654babf38f95a6b59a114183fea3c Mon Sep 17 00:00:00 2001 From: Nat Quayle Nelson Date: Sat, 31 Aug 2024 14:12:19 -0500 Subject: [PATCH] record and replay scrollbar movement from user input --- src/dialogxml/widgets/scrollbar.cpp | 65 +++++++++++++++++------------ src/dialogxml/widgets/scrollbar.hpp | 5 ++- src/game/boe.main.cpp | 8 ++++ 3 files changed, 51 insertions(+), 27 deletions(-) diff --git a/src/dialogxml/widgets/scrollbar.cpp b/src/dialogxml/widgets/scrollbar.cpp index 1b237251..045b26d2 100644 --- a/src/dialogxml/widgets/scrollbar.cpp +++ b/src/dialogxml/widgets/scrollbar.cpp @@ -13,6 +13,8 @@ #include "gfx/render_shapes.hpp" #include "mathutil.hpp" #include "tools/cursors.hpp" +#include "replay.hpp" +#include std::string cScrollbar::scroll_textures[NUM_STYLES] = { "dlogscrollwh", @@ -38,7 +40,19 @@ bool cScrollbar::isScrollable() const { return true; } -void cScrollbar::setPosition(long newPos) { +void cScrollbar::setName(std::string name) { + this->name = name; +} + +void cScrollbar::setPosition(long newPos, bool record) { + if(record && recording){ + std::map info; + info["name"] = name; + // Might as well record newPos before it gets clamped, so replays will verify that clamping + // still works. + info["newPos"] = boost::lexical_cast(newPos); + record_action("scrollbar_setPosition", info); + } pos = minmax(0,max,newPos); } @@ -132,7 +146,7 @@ bool cScrollbar::handle_mouse_wheel_scrolled(const sf::Event& event) { if(!(event_location.in(this->wheel_event_rect) || event_location.in(this->getBounds()))) return false; - this->setPosition(this->getPosition() - event.mouseWheel.delta); + this->setPosition(this->getPosition() - event.mouseWheel.delta, true); return true; } @@ -246,28 +260,34 @@ void cScrollbar::handle_thumb_drag(const location& event_location) { // significantly large compared to the pixel size of the scrollbar). int diff_in_steps = (current - start) * this->max / (thumb_max_position - thumb_min_position); - this->setPosition(this->drag_start_position + diff_in_steps); + this->setPosition(this->drag_start_position + diff_in_steps, true); +} + +void cScrollbar::handlePressedPart(eScrollbarPart pressedPart) { + long newPos = -1; + switch(pressedPart) { + case PART_UP: newPos = pos - 1; break; + case PART_DOWN: newPos = pos + 1; break; + + case PART_PGUP: newPos = pos - this->pgsz; break; + case PART_PGDN: newPos = pos + this->pgsz; break; + + case PART_THUMB: break; + + default: break; + } + if(newPos != -1){ + setPosition(newPos, true); + } + } bool cScrollbar::handle_mouse_released(const sf::Event&) { // Mouse released while not pressed -> not interested // NOTE: depressed actually means pressed if(!this->depressed) return false; - - switch(this->pressedPart) { - case PART_UP: this->pos--; break; - case PART_DOWN: this->pos++; break; - - case PART_PGUP: this->pos -= this->pgsz; break; - case PART_PGDN: this->pos += this->pgsz; break; - - case PART_THUMB: break; - - default: break; - } - // Normalize - this->pos = minmax(0, this->max, this->pos); + handlePressedPart(this->pressedPart); // NOTE: depressed actually means pressed this->depressed = false; @@ -309,13 +329,7 @@ bool cScrollbar::handleClick(location where, cFramerateLimiter& fps_limiter) { clickLoc = inWindow->mapPixelToCoords(clickLoc); clicked = frame.contains(clickLoc); depressed = false; - switch(pressedPart) { - case PART_UP: pos--; break; - case PART_PGUP: pos -= pgsz; break; - case PART_PGDN: pos += pgsz; break; - case PART_DOWN: pos++; break; - case PART_THUMB: break; - } + handlePressedPart(pressedPart); } else if(e.type == sf::Event::MouseMoved){ restore_cursor(); switch(pressedPart) { @@ -330,7 +344,7 @@ bool cScrollbar::handleClick(location where, cFramerateLimiter& fps_limiter) { // We want the pos that will make thumbPos = mousePos - diff // In draw(), thumbPos is calculated as bar_start + bar_thickness + pos * (bar_size - bar_thickness) / max // So solving for pos gives (mousePos - diff - bar_start - bar_thickness) * max / (bar_size - bar_thickness) - pos = (mousePos - diff - bar_start - btn_size) * max / (bar_size - btn_size); + setPosition((mousePos - diff - bar_start - btn_size) * max / (bar_size - btn_size), true); break; case PART_PGDN: depressed = mousePos >= thumbPos + btn_size && mousePos < bar_end - btn_size; @@ -343,7 +357,6 @@ bool cScrollbar::handleClick(location where, cFramerateLimiter& fps_limiter) { toLoc = inWindow->mapPixelToCoords(toLoc); if(pressedPart != PART_THUMB && !frame.contains(toLoc)) depressed = false; } - pos = minmax(0,max,pos); if(parent && !link.empty()) parent->getControl(link).setTextToNum(pos); thumbPos = bar_start; diff --git a/src/dialogxml/widgets/scrollbar.hpp b/src/dialogxml/widgets/scrollbar.hpp index 483b8e6e..f479ee9a 100644 --- a/src/dialogxml/widgets/scrollbar.hpp +++ b/src/dialogxml/widgets/scrollbar.hpp @@ -27,6 +27,7 @@ enum eScrollStyle { /// using the methods to get the scrollbar's position. /// Alternatively, it can be used as a slider control. class cScrollbar : public cControl, public iEventListener, public iDrawable { + std::string name; int pos, max, pgsz; std::string link; // Make sure this is equal to the number of constants in eScrollStyle @@ -43,6 +44,7 @@ class cScrollbar : public cControl, public iEventListener, public iDrawable { PART_PGDN, PART_DOWN, } pressedPart; + void handlePressedPart(eScrollbarPart pressedPart); eScrollStyle style = SCROLL_WHITE; bool vert = true; static std::string scroll_textures[NUM_STYLES]; @@ -103,9 +105,10 @@ public: /// Get the scrollbar style. /// @return The style eScrollStyle getStyle() const; + void setName(std::string name); /// Set the scrollbar thumb's current position. /// @param to The new position. - void setPosition(long to); + void setPosition(long to, bool record = false); /// Set the scrollbar thumb's maximum value. /// @param to The maximum value. void setMaximum(long to); diff --git a/src/game/boe.main.cpp b/src/game/boe.main.cpp index 9497b8ee..cb818ad5 100644 --- a/src/game/boe.main.cpp +++ b/src/game/boe.main.cpp @@ -177,6 +177,7 @@ int main(int argc, char* argv[]) { static void init_sbar(std::shared_ptr& sbar, const std::string& name, rectangle rect, rectangle events_rect, int max, int pgSz, int start = 0) { sbar.reset(new cScrollbar(mainPtr)); + sbar->setName(name); sbar->setBounds(rect); sbar->setMaximum(max); sbar->setPosition(start); @@ -539,6 +540,13 @@ static void replay_next_action() { handle_talk_node(word_rect.node); }else if(t == "end_shop_mode"){ end_shop_mode(); + }else if(t == "scrollbar_setPosition"){ + auto info = info_from_action(next_action); + std::string name = info["name"]; + long newPos = boost::lexical_cast(info["newPos"]); + + std::shared_ptr sbar = std::dynamic_pointer_cast(event_listeners[name]); + sbar->setPosition(newPos); }else{ std::ostringstream sstr; sstr << "Couldn't replay action: " << next_action;