Poke_Transporter_GB/include/vertical_menu.h
Philippe Symons b84939b49a Add debug menu UI when you press L+R in the main menu.
It's only the UI yet. It only shows a couple of dummy options right now.
2026-03-09 19:56:32 +01:00

250 lines
6.9 KiB
C++

#ifndef _VERTICAL_MENU_H
#define _VERTICAL_MENU_H
#include "typeDefs.h"
#include "libstd_replacements.h"
#include "text_data_table.h"
enum class MenuInputHandleState
{
/**
* @brief This value means no input was handled
*/
NOT_HANDLED,
/**
* @brief This value means that the input was handled.
*/
HANDLED,
/**
* @brief Same as HANDLED, but also indicates that the viewport should be updated.
* degrades to HANDLED after passing through vertical_menu::handle_input()
*/
HANDLED_UPDATE_VIEWPORT,
/**
* @brief This value means that a choice was made.
* This means that if the vertical_menu is running with ::run(),
* it should exit and return that choice.
*/
CHOICE_MADE,
/**
* @brief The menu was cancelled.
*/
CANCELLED
};
/**
* @brief This interface represents an item widget in the vertical menu.
* It's responsible for rendering itself and handling its input if
* the widget is focused.
*/
class i_item_widget
{
public:
virtual ~i_item_widget();
virtual void render_item(text_data_table &text_table, unsigned x, unsigned y, bool is_focused) = 0;
virtual MenuInputHandleState handle_input() = 0;
protected:
private:
};
/**
* @brief This interface allows you to register a handler
* to deal with selection changes.
* This is useful for managing external components, such as a cursor.
*/
class i_vertical_menu_state_changed_handler
{
public:
virtual ~i_vertical_menu_state_changed_handler();
virtual void on_show() = 0;
virtual void on_hide() = 0;
virtual void on_selection_changed(unsigned new_index, unsigned x, unsigned y) = 0;
protected:
private:
};
/**
* @brief If you are using the vertical_menu::run() function,
* you may want to manage external components on very run cycle.
* This interface allows you to do that by implementing the i_run_cycle_handler
*/
class i_run_cycle_handler
{
public:
virtual ~i_run_cycle_handler();
virtual void on_run_cycle() = 0;
protected:
private:
};
typedef struct vertical_menu_settings
{
unsigned x;
unsigned y;
unsigned width;
unsigned height;
unsigned margin_top;
unsigned margin_bottom;
unsigned initial_focus_index;
unsigned item_height;
int text_table_index;
/**
* @brief This boolean indicates whether the menu
* can be "cancelled with the B button."
*/
bool allow_cancel;
/**
* @brief This boolean indicates whether the menu should take
* ownership of its item widgets.
* That means that if this boolean is true,
* the destructor of vertical_menu will delete/free all of its
* item widgets.
*/
bool should_delete_item_widgets_on_destruct;
/**
* @brief This boolean indicates whether the state changed handler (cursor?)
* should be hidden when the menu is not focused.
*/
bool should_hide_state_changed_handler_on_not_focused;
} vertical_menu_settings;
class vertical_menu
{
public:
vertical_menu(const vertical_menu_settings &settings);
~vertical_menu();
void show();
void hide();
/**
* @brief Get the current settings of this widget
*/
const vertical_menu_settings& get_settings() const;
/**
* @brief Replace the settings of this widget.
*/
void set_settings(const vertical_menu_settings &settings);
/**
* @brief This function is a way to bulk add item widgets to the menu.
* The main difference between calling this function and add_item_widget()
* multiple times is that this function will reserve() enough space in the
* vector first, to avoid multiple resizes.
*/
void add_item_widgets(i_item_widget **item_widgets, unsigned num_widgets);
/**
* @brief This function adds an item widget to the menu.
* The menu will take ownership of the pointer, if
* settings_.should_delete_item_widgets_on_destruct is true.
* Otherwise, the caller is responsible for managing the memory of the item widgets.
*/
void add_item_widget(i_item_widget *item_widget);
/**
* @brief This function clears all item widgets from the menu.
* If settings_.should_delete_item_widgets_on_destruct is true,
* it will also delete the item widgets.
*/
void clear_item_widgets();
/**
* @brief This function gets the item widget
* at the given index.
*/
i_item_widget* get_item_widget_at(unsigned index) const;
/**
* @brief Sets whether the menu is focused or not.
* A focused menu will handle input.
*/
void set_focused(bool is_focused);
/**
* @brief This function handles button input for the menu.
*/
MenuInputHandleState handle_input();
/**
* @brief This function updates the viewport by
* re-rendering the visible items.
*/
void update_viewport();
void clear_viewport();
/**
* @brief This function can be used to manage a blocking call
* to vertical_menu, in which you want vertical_menu
* to handle everything.
*
* This can be useful during one of those script_array commands.
* Alternatively, you can just call handle_input() and manage the loop
* manually.
*
* @return Will return the index of the chosen item if a choice was made,
* or UINT32_MAX if no choice was made and the menu was exited in some other way
* (ex: B button).
*/
unsigned run();
/**
* @brief Sets the optional state changed handler.
* This is useful for managing external components, such as a cursor.
*/
void set_state_changed_handler(i_vertical_menu_state_changed_handler *handler);
/**
* @brief This function sets a handler that will run on every
* cycle in the run() function.
*
* It's only relevant if you use ::run() though.
*/
void set_run_cycle_handler(i_run_cycle_handler *handler);
protected:
private:
void handle_selection_change(unsigned new_index, unsigned x, unsigned y);
vertical_menu_settings settings_;
i_vertical_menu_state_changed_handler *state_changed_handler_;
i_run_cycle_handler *run_cycle_handler_;
unsigned focused_index_;
unsigned viewport_start_index_;
ptgb::vector<i_item_widget*> items_;
bool is_focused_;
};
typedef struct simple_item_widget_data
{
struct
{
unsigned text_table_index;
unsigned margin_left;
unsigned margin_top;
} text;
unsigned value;
void (*on_execute_callback)(void *context);
} simple_item_widget_data;
class simple_item_renderer : public i_item_widget
{
public:
simple_item_renderer(const simple_item_widget_data &data);
virtual ~simple_item_renderer();
const simple_item_widget_data& get_data() const;
void render_item(text_data_table &text_table, unsigned x, unsigned y, bool is_focused) override;
MenuInputHandleState handle_input() override;
protected:
private:
simple_item_widget_data data_;
};
#endif