diff --git a/include/scenes/TestScene.h b/include/scenes/TestScene.h index b882356..712abd2 100755 --- a/include/scenes/TestScene.h +++ b/include/scenes/TestScene.h @@ -2,8 +2,16 @@ #define _TESTSCENE_H #include "scenes/AbstractUIScene.h" -#include "core/RDPQGraphics.h" #include "core/Sprite.h" +#include "widget/ScrollWidget.h" + +#include + +class ImageWidget; +class TextWidget; + +typedef std::vector WidgetList; + class TestScene : public AbstractUIScene { @@ -17,20 +25,11 @@ public: void render(RDPQGraphics& gfx, const Rectangle& sceneBounds) override; protected: private: - rdpq_font_t* arialFont_; - uint8_t arialFontId_; - uint8_t fontStyleWhite_; + ScrollWidget scrollWidget_; + WidgetFocusChainSegment scrollWidgetFocusSegment_; + WidgetList widgets_; sprite_t* pokeballSprite_; sprite_t* oakSprite_; - sprite_t* menu9SliceSprite_; - const Rectangle rectBounds_; - const Rectangle textRect_; - const Rectangle spriteBounds_; - Rectangle oakBounds_; - Rectangle oakSrcBounds_; - const Rectangle menuBounds_; - TextRenderSettings textRenderSettings_; - const SpriteRenderSettings menuRenderSettings_; }; #endif \ No newline at end of file diff --git a/include/widget/IWidget.h b/include/widget/IWidget.h index 95983c7..fc10f86 100755 --- a/include/widget/IWidget.h +++ b/include/widget/IWidget.h @@ -12,6 +12,7 @@ class RDPQGraphics; class IWidget { public: + virtual ~IWidget(){} /** * @brief Returns whether the widget is currently focused */ diff --git a/include/widget/ScrollWidget.h b/include/widget/ScrollWidget.h index 3d69ab9..012fcb2 100644 --- a/include/widget/ScrollWidget.h +++ b/include/widget/ScrollWidget.h @@ -33,9 +33,12 @@ public: uint32_t getDurationInMs() const override; void start(const Point& startPoint, const Point& endPoint); + void extend(const Point& endPoint); protected: void apply(float pos) override; private: + Point calculatePoint(float pos); + ScrollWidget* list_; Point windowStartPoint_; Point windowEndPoint_; @@ -69,6 +72,7 @@ public: void addWidget(IWidget* widget); void removeWidget(IWidget* widget); + void clearWidgets(); bool handleUserInput(const joypad_inputs_t& userInput) override; void render(RDPQGraphics& gfx, const Rectangle& parentBounds) override; diff --git a/src/scenes/TestScene.cpp b/src/scenes/TestScene.cpp index 89fffd0..a466aa0 100755 --- a/src/scenes/TestScene.cpp +++ b/src/scenes/TestScene.cpp @@ -1,7 +1,9 @@ #include "scenes/TestScene.h" #include "core/RDPQGraphics.h" +#include "core/FontManager.h" +#include "widget/ImageWidget.h" +#include "widget/TextWidget.h" -#include #include static const char* tvtypeToString(tv_type_t type) @@ -21,23 +23,13 @@ static const char* tvtypeToString(tv_type_t type) TestScene::TestScene(SceneDependencies& deps, void*) : AbstractUIScene(deps) - , arialFont_(nullptr) - , arialFontId_(1) - , fontStyleWhite_(0) + , scrollWidget_(deps.animationManager) + , scrollWidgetFocusSegment_({ + .current = &scrollWidget_ + }) + , widgets_() , pokeballSprite_(nullptr) , oakSprite_(nullptr) - , menu9SliceSprite_(nullptr) - , rectBounds_({0, 0, 320, 240}) - , textRect_({70, 70, 180, 60}) - , spriteBounds_({320 - 128, 0, 128, 128}) - , oakBounds_({0}) - , oakSrcBounds_({0}) - , menuBounds_({ 100, 20, 100, 100}) - , textRenderSettings_({}) - , menuRenderSettings_({ - .renderMode = SpriteRenderMode::NINESLICE, - .srcRect = { 6, 6, 6, 6 } - }) { } @@ -47,47 +39,129 @@ TestScene::~TestScene() void TestScene::init() { - arialFont_ = rdpq_font_load("rom://Arial.font64"); - rdpq_fontstyle_t arialWhiteFontStyle = { - .color = RGBA32(0xFF, 0xFF, 0xFF, 0xFF) - }; - rdpq_font_style(arialFont_, fontStyleWhite_, &arialWhiteFontStyle); - - // TODO: this is a problem: there's no way to unregister a font. - // Therefore if we'd load the same font > 1 times, we'll get a crash (due to assert) - // We'll need to create a FontManager class to handle this - rdpq_text_register_font(arialFontId_, arialFont_); - textRenderSettings_.fontId = arialFontId_; - + uint8_t widgetType; + const uint8_t fontId = deps_.fontManager.getFont("rom://Arial.font64"); pokeballSprite_ = sprite_load("rom:/pokeball.sprite"); oakSprite_ = sprite_load("rom://oak.sprite"); - menu9SliceSprite_ = sprite_load("rom://menu-bg-9slice.sprite"); - oakBounds_ ={10, 80, oakSprite_->width, oakSprite_->height}; - oakSrcBounds_ = {oakSprite_->width / 3, oakSprite_->height / 3, oakSprite_->width * 2 / 3, oakSprite_->height * 2 / 3}; + debugf("Hello Phil! Your tv type is: %s\r\n", tvtypeToString(get_tv_type())); - printf("Hello Phil! Your tv type is: %s\n", tvtypeToString(get_tv_type())); + const ScrollWidgetStyle scrollStyle = { + .scrollStep = 10 + }; + + scrollWidget_.setBounds(Rectangle{0, 0, 320, 240}); + scrollWidget_.setStyle(scrollStyle); + scrollWidget_.setFocused(true); + setFocusChain(&scrollWidgetFocusSegment_); + + const Dimensions textDimensions = {.width = 50, .height = 16}; + const Dimensions oakDimensions = {.width = oakSprite_->width, .height = oakSprite_->height }; + const Dimensions pokeballDimensions = {.width = pokeballSprite_->width, .height = pokeballSprite_->height}; + + TextWidgetStyle type1Style = { + .size = {textDimensions.width, textDimensions.height}, + .renderSettingsNotFocused = { + .fontId = fontId + } + }; + + ImageWidgetStyle type2Style = { + .size = oakDimensions, + .image = { + .sprite = oakSprite_, + .spriteBounds = {0, 0, oakDimensions.width, oakDimensions.height} + } + }; + + ImageWidgetStyle type3Style = { + .size = pokeballDimensions, + .image = { + .sprite = pokeballSprite_, + .spriteBounds = {0, 0, pokeballDimensions.width, pokeballDimensions.height} + } + }; + + int curXPos = 0; + int curYPos = 0; + int nextYPos = 0; + for(uint8_t i=0; i < 6; ++i) + { + for(uint8_t j=0; j < 6; ++j) + { + widgetType = (j % 3); + + switch(widgetType) + { + case 0: + { + TextWidget* textWidget = new TextWidget(); + textWidget->setStyle(type1Style); + textWidget->setBounds(Rectangle{curXPos, curYPos, textDimensions.width, textDimensions.height}); + textWidget->setData("Hello!"); + scrollWidget_.addWidget(textWidget); + widgets_.push_back(textWidget); + curXPos += textDimensions.width; + if(curYPos + textDimensions.height > nextYPos) + { + nextYPos = curYPos + textDimensions.height; + } + break; + } + case 1: + { + ImageWidget* imageWidget = new ImageWidget(); + imageWidget->setStyle(type2Style); + imageWidget->setBounds(Rectangle{curXPos, curYPos, oakDimensions.width, oakDimensions.height}); + scrollWidget_.addWidget(imageWidget); + widgets_.push_back(imageWidget); + curXPos += oakDimensions.width; + if(curYPos + oakDimensions.height > nextYPos) + { + nextYPos = curYPos + oakDimensions.height; + } + break; + } + case 2: + { + ImageWidget* imageWidget = new ImageWidget(); + imageWidget->setStyle(type3Style); + imageWidget->setBounds(Rectangle{curXPos, curYPos, pokeballDimensions.width, pokeballDimensions.height}); + scrollWidget_.addWidget(imageWidget); + widgets_.push_back(imageWidget); + curXPos += pokeballDimensions.width; + if(curYPos + pokeballDimensions.height > nextYPos) + { + nextYPos = curYPos + pokeballDimensions.height; + } + break; + } + default: + break; + } + } + curYPos = nextYPos; + curXPos = 0; + } } void TestScene::destroy() { - sprite_free(menu9SliceSprite_); - menu9SliceSprite_ = nullptr; + scrollWidget_.clearWidgets(); + for(IWidget* widget : widgets_) + { + delete widget; + } + widgets_.clear(); sprite_free(oakSprite_); oakSprite_ = nullptr; sprite_free(pokeballSprite_); pokeballSprite_ = nullptr; - - rdpq_font_free(arialFont_); } -void TestScene::render(RDPQGraphics& gfx, const Rectangle& /*sceneBounds*/) +void TestScene::render(RDPQGraphics& gfx, const Rectangle& sceneBounds) { -// gfx.fillRectangle(rectBounds_, RGBA32(200, 0, 0, 0)); -// gfx.drawText(textRect_, "Hello Phil!", textRenderSettings_); -// gfx.drawSprite(spriteBounds_, pokeballSprite_, SpriteRenderSettings()); -// gfx.drawSprite(oakBounds_, oakSprite_, {.srcRect = oakSrcBounds_}); - gfx.drawSprite(menuBounds_, menu9SliceSprite_, menuRenderSettings_); + scrollWidget_.render(gfx, sceneBounds); } \ No newline at end of file diff --git a/src/widget/ScrollWidget.cpp b/src/widget/ScrollWidget.cpp index a6cca5f..869c571 100644 --- a/src/widget/ScrollWidget.cpp +++ b/src/widget/ScrollWidget.cpp @@ -110,15 +110,28 @@ uint32_t MoveScrollWidgetWindowAnimation::getDurationInMs() const void MoveScrollWidgetWindowAnimation::start(const Point& startPoint, const Point& endPoint) { + currentTimePos_ = 0.f; windowStartPoint_ = startPoint; windowEndPoint_ = endPoint; } +void MoveScrollWidgetWindowAnimation::extend(const Point& endPoint) +{ + const Point currentPoint = calculatePoint(currentTimePos_); + start(currentPoint, endPoint); +} + void MoveScrollWidgetWindowAnimation::apply(float pos) +{ + const Point newWindowStart = calculatePoint(pos); + list_->setWindowStart(newWindowStart); +} + +Point MoveScrollWidgetWindowAnimation::calculatePoint(float pos) { const int px = static_cast(ceil(windowStartPoint_.x + (pos * (windowEndPoint_.x - windowStartPoint_.x)))); const int py = static_cast(ceil(windowStartPoint_.y + (pos * (windowEndPoint_.y - windowStartPoint_.y)))); - list_->setWindowStart(Point{px, py}); + return Point{px, py}; } ScrollWidget::ScrollWidget(AnimationManager& animManager) @@ -195,6 +208,12 @@ void ScrollWidget::removeWidget(IWidget* widget) recalculateWindowSize(); } +void ScrollWidget::clearWidgets() +{ + widgets_.clear(); + windowBounds_ = {0}; +} + bool ScrollWidget::handleUserInput(const joypad_inputs_t& userInput) { if(!focused_ || style_.scrollStep == 0) @@ -203,21 +222,25 @@ bool ScrollWidget::handleUserInput(const joypad_inputs_t& userInput) } const FloatVector scrollDirection = determineScrollDirection(userInput); +// debugf("[ScrollWidget]: %s: scrollDirection [%f, %f]\r\n", __FUNCTION__, scrollDirection.x, scrollDirection.y); if(scrollDirection.x == 0.f && scrollDirection.y == 0.f) { return false; } - if(!windowAnimation_.isFinished()) - { - windowAnimation_.skipToEnd(); - } - const Point windowStartPoint = {.x = windowBounds_.x, .y = windowBounds_.y}; Point windowEndPoint = {.x = windowBounds_.x, .y = windowBounds_.y}; - windowEndPoint.x += static_cast(ceil(scrollDirection.x * style_.scrollStep)); windowEndPoint.y += static_cast(ceil(scrollDirection.y * style_.scrollStep)); - windowAnimation_.start(windowStartPoint, windowEndPoint); + + if(!windowAnimation_.isFinished()) + { + windowAnimation_.extend(windowEndPoint); + } + else + { + const Point windowStartPoint = {.x = windowBounds_.x, .y = windowBounds_.y}; + windowAnimation_.start(windowStartPoint, windowEndPoint); + } return true; }