mirror of
https://github.com/GearsProgress/Poke_Transporter_GB.git
synced 2026-03-21 17:34:42 -05:00
This commit implements a vertical menu widget, which should be quite a bit more flexible than what we currently have. It defines interfaces in order to respond to selection changes, show and hide. And has a i_item_widget interface class to allow you to use custom item widgets. This is done in preparation for adding a debug menu, in which I kinda want to add toggle options while using the same vertical_menu widget. Right now, vertical_menu is only used in Select_Menu. Needless to say that Select_Menu was reworked quite a bit. Still, in terms of visuals or functionality, the changes should be invisible for now. I mean, I didn't do anything *new* with it yet.
245 lines
6.7 KiB
C++
245 lines
6.7 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 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 |