diff --git a/loader/include/Geode/UI.hpp b/loader/include/Geode/UI.hpp index 54edc0236..a6aa5b0f0 100644 --- a/loader/include/Geode/UI.hpp +++ b/loader/include/Geode/UI.hpp @@ -17,6 +17,7 @@ #include "ui/MDTextArea.hpp" #include "ui/Notification.hpp" #include "ui/Popup.hpp" +#include "ui/ProgressBar.hpp" #include "ui/SceneManager.hpp" #include "ui/Scrollbar.hpp" #include "ui/ScrollLayer.hpp" diff --git a/loader/include/Geode/ui/ProgressBar.hpp b/loader/include/Geode/ui/ProgressBar.hpp new file mode 100644 index 000000000..add5fe886 --- /dev/null +++ b/loader/include/Geode/ui/ProgressBar.hpp @@ -0,0 +1,90 @@ +#pragma once + +#include + +namespace geode { + // Enum for progress bar style + enum class ProgressBarStyle { + Level = 0, + Solid = 1, + }; + + // Custom class for the progress bar + class ProgressBar : public cocos2d::CCNode { + protected: + class Impl; + std::unique_ptr m_impl; + + ProgressBar(); + virtual ~ProgressBar(); + + // Reloads the style of the progress bar + void reloadStyle(); + + bool init() override; + + public: + // Create a custom progress bar + static ProgressBar* create(); + + /** + * Set the style of the progress bar + * + * @param style Style to switch to + */ + void setStyle(ProgressBarStyle style); + + /** + * Set the color of the fill of the bar + * + * @param color RGB color object + */ + void setFillColor(ccColor3B color); + + /** + * Set the precision of the percentage label + * + * @param precision Number of decimal places to show in the percentage label + */ + void setPrecision(size_t precision); + + /** + * Update the size of the fill of the bar + * + * @param value A float from 0 to 100 + */ + virtual void updateProgress(float value); + + /** + * Show the label displaying the current percentage of progress + * + * @param bool Whether to toggle visibility + */ + void showProgressLabel(bool show); + + /** + * Get the current progress percentage of the bar + */ + float getProgress() const; + + /** + * Get the progress percentage text label node + */ + CCLabelBMFont* getProgressLabel() const; + + /** + * Get the current style of the progress bar + */ + ProgressBarStyle getStyle() const; + + /** + * Get the current color of the fill of the progress bar + */ + ccColor3B getFillColor() const; + + /** + * Get the precision of the percentage label + */ + size_t getPrecision() const; + }; +}; \ No newline at end of file diff --git a/loader/src/ui/nodes/ProgressBar.cpp b/loader/src/ui/nodes/ProgressBar.cpp new file mode 100644 index 000000000..88a4bb960 --- /dev/null +++ b/loader/src/ui/nodes/ProgressBar.cpp @@ -0,0 +1,189 @@ +#include +#include + +using namespace geode::prelude; + +class ProgressBar::Impl final { +public: + // Progress bar outline + Ref progressBar = nullptr; + // Progress bar fill + CCSprite* progressBarFill = nullptr; + // The text label displaying the percentage + Ref progressPercentLabel = nullptr; + + // Current progress bar fill percentage ranging from 0 to 100 + float progress = 0.0f; + + // Style of the progress bar + ProgressBarStyle style = ProgressBarStyle::Level; + // Current color of the filled progress bar + ccColor3B progressBarFillColor = { 255, 255, 255 }; + // Whether to show the label showing the percentage of the current progress + bool showProgressPercentLabel = false; + // Precision of the percentage on the progress percent label + size_t precision = 0; + + // Max width for the progress fill bar node + float progressBarFillMaxWidth = 0.0f; + // Max height for the progress fill bar node + float progressBarFillMaxHeight = 0.0f; +}; + +ProgressBar::ProgressBar() { + m_impl = std::make_unique(); +}; + +ProgressBar::~ProgressBar() {}; + +void ProgressBar::reloadStyle() { + switch (m_impl->style) { + case ProgressBarStyle::Level: { + m_impl->progressBar = CCSprite::create("slidergroove2.png"); + m_impl->progressBar->setID("progress-bar"); + m_impl->progressBar->setAnchorPoint({ 0.5, 0.5 }); + m_impl->progressBar->setPosition({ m_impl->progressBar->getScaledContentWidth() / 2.0f, m_impl->progressBar->getScaledContentHeight() / 2.0f }); + m_impl->progressBar->setZOrder(1); + + m_impl->progressBarFill = CCSprite::create("sliderBar2.png"); + m_impl->progressBarFill->setID("progress-bar-fill"); + m_impl->progressBarFill->setAnchorPoint({ 0, 0.5 }); + m_impl->progressBarFill->setPosition({ 2.0f, m_impl->progressBar->getScaledContentHeight() / 2.0f }); + m_impl->progressBarFill->setColor(m_impl->progressBarFillColor); + m_impl->progressBarFill->setZOrder(-1); + + m_impl->progressBarFillMaxWidth = m_impl->progressBar->getScaledContentWidth() - 4.0f; + m_impl->progressBarFillMaxHeight = m_impl->progressBarFill->getScaledContentHeight() - 0.5f; + + m_impl->progressPercentLabel = CCLabelBMFont::create("0%", "bigFont.fnt"); + m_impl->progressPercentLabel->setID("progress-percent-label"); + m_impl->progressPercentLabel->setScale(0.5f); + m_impl->progressPercentLabel->setAnchorPoint({ 0, 0.5 }); + m_impl->progressPercentLabel->setPosition({ m_impl->progressBar->getScaledContentWidth() + 2.5f, m_impl->progressBar->getScaledContentHeight() / 2.0f }); + m_impl->progressPercentLabel->setAlignment(CCTextAlignment::kCCTextAlignmentLeft); + m_impl->progressPercentLabel->setVisible(m_impl->showProgressPercentLabel); + m_impl->progressPercentLabel->setZOrder(1); + } break; + + case ProgressBarStyle::Solid: { + m_impl->progressBar = CCSprite::create("GJ_progressBar_001.png"); + m_impl->progressBar->setID("progress-bar"); + m_impl->progressBar->setAnchorPoint({ 0.5, 0.5 }); + m_impl->progressBar->setPosition({ m_impl->progressBar->getScaledContentWidth() / 2.0f, m_impl->progressBar->getScaledContentHeight() / 2.0f }); + m_impl->progressBar->setColor({ 0, 0, 0 }); + m_impl->progressBar->setOpacity(125); + m_impl->progressBar->setZOrder(-1); + + m_impl->progressBarFill = CCSprite::create("GJ_progressBar_001.png"); + m_impl->progressBarFill->setID("progress-bar-fill"); + m_impl->progressBarFill->setScale(0.992f); + m_impl->progressBarFill->setScaleY(0.86f); + m_impl->progressBarFill->setAnchorPoint({ 0, 0.5 }); + m_impl->progressBarFill->setPosition({ 1.36f, m_impl->progressBar->getScaledContentHeight() / 2.0f }); + m_impl->progressBarFill->setColor(m_impl->progressBarFillColor); + m_impl->progressBarFill->setZOrder(0); + + m_impl->progressBarFillMaxWidth = m_impl->progressBar->getScaledContentWidth(); + m_impl->progressBarFillMaxHeight = 20.0f; + + m_impl->progressPercentLabel = CCLabelBMFont::create("0%", "bigFont.fnt"); + m_impl->progressPercentLabel->setID("progress-percent-label"); + m_impl->progressPercentLabel->setScale(0.5f); + m_impl->progressPercentLabel->setAnchorPoint({ 0.5, 0.5 }); + m_impl->progressPercentLabel->setPosition({ m_impl->progressBar->getScaledContentWidth() / 2.0f, m_impl->progressBar->getScaledContentHeight() / 2.0f }); + m_impl->progressPercentLabel->setAlignment(CCTextAlignment::kCCTextAlignmentCenter); + m_impl->progressPercentLabel->setVisible(m_impl->showProgressPercentLabel); + m_impl->progressPercentLabel->setZOrder(1); + } break; + }; + + this->setScaledContentSize(m_impl->progressBar->getScaledContentSize()); + + m_impl->progressBar->addChild(m_impl->progressBarFill); + + this->addChild(m_impl->progressBar); + this->addChild(m_impl->progressPercentLabel); + + this->updateProgress(m_impl->progress); +}; + +bool ProgressBar::init() { + if (!CCNode::init()) return false; + + this->reloadStyle(); + + return true; +}; + +void ProgressBar::setStyle(ProgressBarStyle style) { + if (m_impl->style != style) { + m_impl->style = style; + + this->removeAllChildren(); + this->reloadStyle(); // setup again with new style + }; +}; + +void ProgressBar::setFillColor(ccColor3B color) { + m_impl->progressBarFillColor = color; + if (m_impl->progressBarFill) m_impl->progressBarFill->setColor(color); +}; + +void ProgressBar::setPrecision(size_t precision) { + m_impl->precision = precision; + this->updateProgress(m_impl->progress); // update label with new precision +}; + +void ProgressBar::updateProgress(float value) { + if (value > 100.0f) value = 100.0f; + if (value < 0.0f) value = 0.0f; + + m_impl->progress = value; + + if (m_impl->progressBarFill) { + float width = m_impl->progressBarFillMaxWidth * (m_impl->progress / 100.0f); + m_impl->progressBarFill->setTextureRect({ 0.0f, 0.0f, width, m_impl->progressBarFillMaxHeight }); + }; + + if (m_impl->progressPercentLabel) { + auto percentString = fmt::format("{}%", geode::utils::numToString(m_impl->progress, m_impl->precision)); + m_impl->progressPercentLabel->setCString(percentString.c_str()); + }; +}; + +void ProgressBar::showProgressLabel(bool show) { + m_impl->showProgressPercentLabel = show; + if (m_impl->progressPercentLabel) m_impl->progressPercentLabel->setVisible(show); +}; + +float ProgressBar::getProgress() const { + return m_impl->progress; +}; + +CCLabelBMFont* ProgressBar::getProgressLabel() const { + return m_impl->progressPercentLabel; +}; + +ProgressBarStyle ProgressBar::getStyle() const { + return m_impl->style; +}; + +ccColor3B ProgressBar::getFillColor() const { + return m_impl->progressBarFillColor; +}; + +size_t ProgressBar::getPrecision() const { + return m_impl->precision; +}; + +ProgressBar* ProgressBar::create() { + auto ret = new ProgressBar(); + + if (ret && ret->init()) { + ret->autorelease(); + return ret; + }; + + delete ret; + return nullptr; +}; \ No newline at end of file