Skip to content

Consider adding a dynamic string providing function to BaseWidgetValue<T,V> #430

Description

@clarencelocke

Is your feature request related to a problem?

Currently the BaseWidgetValue<T,V> template takes a format string specifier and assumes that the literal T value is what is going to be "printed" to the buffer for display.

I have a circumstance where there is a level of indirection for providing the string representation of the value (e.g, const char* stringForValue(const T& value)). I need to do this for both ItemList and ItemRange menu items, which means I had to create 4 new template classes which closely mirror the Item/Widget pairings and have an overridden uint8_t draw(char* buffer, const uint8_t start) method in the widget classes. It felt like I was essentially copying code instead of providing just some minor overrides.

If the BaseWidgetValue<T,V> supported an additional constructor (or template parameter) which described the mechanism for "drawing" the value's representation then that could percolate up through the existing class hierarchy to ItemRange, ItemList and ItemBool.

Describe the solution you'd like?

Starting at BaseWidgetValue<T,V>:

template <typename T>
class ValueDrawer
{
	public:
		virtual uint8_t draw(const T& value, char* buffer, const uint8_t start) = 0;
};


template <typename T>
class PrintfValueDrawer : ValueDrawer<T>
{
	public:
		PrintfValueDrawer(const char* format)
			: ValueDrawer<T>(), format(format)
		{ }
		
		uint8_t draw(const T& value, char* buffer, const uint8_t start) override
		{
	        if (start >= ITEM_DRAW_BUFFER_SIZE) return 0;
	        return snprintf(buffer + start, ITEM_DRAW_BUFFER_SIZE - start, format, value);
		}
		
	private:
		const char* format;
};


template <typename T>
class DynamicStringValueDrawer : ValueDrawer<T>
{
	public:
		typedef const char* (*StringProvingFunction)(const T& value);
	
		DynamicStringValueDrawer(StringProvingFunction stringForValue)
			: ValueDrawer<T>(), stringForValue(stringForValue)
		{ }
		
		uint8_t draw(const T& value, char* buffer, const uint8_t start) override
		{
	        if (start >= ITEM_DRAW_BUFFER_SIZE) return 0;
			
			const char* valueString = stringForValue(value);
			if (valueString == nullptr) return 0;
			
	        return snprintf(buffer + start, ITEM_DRAW_BUFFER_SIZE - start, "%s", valueString);
		}
		
	private:
		StringProvingFunction stringForValue;
};


template <typename T>
class BaseWidgetValue : public BaseWidget
{
	ValueDrawer<T>* valueDrawer;

    BaseWidgetValue(
        const T& value,
        const char* format,
        const uint8_t cursorOffset = 0,
        void (*callback)(const T&) = nullptr)
        : BaseWidgetValue(value, new PrintfValueDrawer(format), cursorOffset, callback)

    BaseWidgetValue(
        const T& value,
        DynamicStringValueDrawer<T>::StringProvingFunction stringForValueFunction,
        const uint8_t cursorOffset = 0,
        void (*callback)(const T&) = nullptr)
        : BaseWidgetValue(value, new DynamicStringValueDrawer(stringForValueFunction), cursorOffset, callback)

    BaseWidgetValue(
        const T& value,
        ValueDrawer<T>* valueDrawer,
        const uint8_t cursorOffset = 0,
        void (*callback)(const T&) = nullptr)
        : BaseWidget(cursorOffset), value(value), valueDrawer(valueDrawer), callback(callback) {}

	uint8_t draw(char* buffer, const uint8_t start) override {
		return valueDrawer->draw(value, buffer, start);
	}		
}

and then the format vs. stringForValueFunction (or just the ValueDrawer<T>*) could then be distributed to all the instantiators of BaseWidgetValue.

Describe alternatives you've considered

I wrote my own subclasses that mirrored the ItemList/WidgetList and ItemRange/WidgetRange pairings so that I could override the WidgetList::draw() and WidgetRange::draw() functions.

Additional context

No response

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    feature-requestAdd new feature to the library

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions