add new ColorProvider utility

This commit is contained in:
HJfod 2024-02-28 00:27:19 +02:00
parent 5109acf725
commit 36ef4979ed
2 changed files with 154 additions and 0 deletions

View file

@ -0,0 +1,89 @@
#pragma once
#include "../DefaultInclude.hpp"
#include "../loader/Event.hpp"
namespace geode {
struct GEODE_DLL ColorProvidedEvent : public Event {
std::string id;
cocos2d::ccColor4B color;
ColorProvidedEvent(std::string const& id, cocos2d::ccColor4B const& color);
};
class GEODE_DLL ColorProvidedFilter : public EventFilter<ColorProvidedEvent> {
public:
using Callback = void(ColorProvidedEvent*);
protected:
std::string m_id;
public:
ListenerResult handle(utils::MiniFunction<Callback> fn, ColorProvidedEvent* event);
ColorProvidedFilter(std::string const& id);
};
/**
* GD has a lot of hardcoded colors. In addition, mods may very well also
* use hardcoded colors in their UIs, for example for CCLayerColors. This
* makes it hard for texture packs to reliably change colors, since they'd
* have to manually deal with every mod.
*
* To help with this, Geode provides the `ColorProvider` class, which is
* just an index of colors with associated IDs. Mods should use this to
* define their hardcoded colors for their UIs, and texture packs can then
* change the color dynamically.
*
* Mods are not expected to handle in-game color changes, since in nearly
* all cases the texture pack will be applied far from the mod's UI and as
* such just getting the defined color on layer enter will be more than
* enough. However, if the mod does add some static UI that won't be
* naturally refreshed after a texture pack is applied, it should listen
* for `ColorProvidedEvent`s to react accordingly.
*/
class GEODE_DLL ColorProvider final {
private:
class Impl;
Impl* m_impl;
ColorProvider();
public:
// @note See class description
static ColorProvider* get();
/**
* Define a new color with an associated ID. The ID should be prefixed
* with the mod ID. If the color has already been defined, nothing
* happens
* @param id The ID of the color; should be prefixed with mod ID
* @param color The color
* @returns The current value of the color with the ID (same as the
* `color` function)
*/
cocos2d::ccColor4B define(std::string const& id, cocos2d::ccColor4B const& color);
/**
* Override the current value of a color with an associated ID
* @param id The ID of the color
* @param color The color to override with
* @returns The new value of the color, or ccWHITE if the ID doesn't
* exist
*/
cocos2d::ccColor4B override(std::string const& id, cocos2d::ccColor4B const& color);
/**
* Reset the current value of a color to its original definition
* @param id The ID of the color
* @returns The original value of the color, or ccWHITE if the ID
* doesn't exist
*/
cocos2d::ccColor4B reset(std::string const& id);
/**
* Get the current value of a color
* @param id The ID of the color
* @returns The value of the color, or ccWHITE if the ID doesn't exist
*/
cocos2d::ccColor4B color(std::string const& id) const;
};
}

View file

@ -0,0 +1,65 @@
#include <Geode/utils/ColorProvider.hpp>
using namespace geode::prelude;
ColorProvidedEvent::ColorProvidedEvent(std::string const& id, cocos2d::ccColor4B const& color)
: id(id), color(color) {}
ListenerResult ColorProvidedFilter::handle(MiniFunction<Callback> fn, ColorProvidedEvent* event) {
if (event->id == m_id) {
fn(event);
}
return ListenerResult::Propagate;
}
ColorProvidedFilter::ColorProvidedFilter(std::string const& id) : m_id(id) {}
class ColorProvider::Impl {
public:
std::unordered_map<std::string, std::pair<ccColor4B, std::optional<ccColor4B>>> colors;
};
ColorProvider::ColorProvider() : m_impl(new Impl()) {}
ColorProvider* ColorProvider::get() {
static auto inst = new ColorProvider();
return inst;
}
ccColor4B ColorProvider::define(std::string const& id, ccColor4B const& color) {
// `insert` doesn't override existing keys, which is what we want
m_impl->colors.insert({ id, std::pair(color, std::nullopt) });
return this->color(id);
}
ccColor4B ColorProvider::override(std::string const& id, ccColor4B const& color) {
if (m_impl->colors.contains(id)) {
m_impl->colors.at(id).second = color;
ColorProvidedEvent(id, color).post();
return color;
}
else {
log::error("(ColorProvider) Attempted to override color \"{}\", which is not defined", id);
return to4B(ccWHITE);
}
}
ccColor4B ColorProvider::reset(std::string const& id) {
if (m_impl->colors.contains(id)) {
m_impl->colors.at(id).second = std::nullopt;
auto def = m_impl->colors.at(id).first;
ColorProvidedEvent(id, def).post();
return def;
}
else {
log::error("(ColorProvider) Attempted to reset color \"{}\", which is not defined", id);
return to4B(ccWHITE);
}
}
ccColor4B ColorProvider::color(std::string const& id) const {
if (m_impl->colors.contains(id)) {
return m_impl->colors.at(id).second.value_or(m_impl->colors.at(id).first);
}
else {
log::error("(ColorProvider) Attempted to get color \"{}\", which is not defined", id);
return to4B(ccWHITE);
}
}