/** * @file * @brief Menus and associated malarkey. **/ #ifndef __MENU_H__ #define __MENU_H__ #include #include #include #include #include #include "externs.h" #include "format.h" #ifdef USE_TILE #include "tiledoll.h" #endif #ifdef USE_TILE_LOCAL #include "tilebuf.h" #endif class formatted_string; enum MenuEntryLevel { MEL_NONE = -1, MEL_TITLE, MEL_SUBTITLE, MEL_ITEM, }; struct menu_letter { char letter; menu_letter() : letter('a') { } menu_letter(char c) : letter(c) { } operator char () const { return letter; } const menu_letter &operator ++ () { letter = letter == 'z'? 'A' : letter == 'Z'? 'a' : letter + 1; return *this; } // dummy postfix argument unnamed to stop gcc from complaining menu_letter operator ++ (int) { menu_letter copy = *this; operator++(); return copy; } }; // XXX Use inheritance instead of duplicate code struct menu_letter2 { char letter; menu_letter2() : letter('a') { } menu_letter2(char c) : letter(c) { } operator char () const { return letter; } const menu_letter2 &operator ++ () { letter = letter == 'z'? '0' : letter == '9'? 'a' : letter + 1; return *this; } menu_letter2 operator ++ (int) { menu_letter2 copy = *this; operator++(); return copy; } }; struct item_def; class Menu; int menu_colour(const string &itemtext, const string &prefix = "", const string &tag = ""); const int MENU_ITEM_STOCK_COLOUR = LIGHTGREY; class MenuEntry { public: string tag; string text; int quantity, selected_qty; int colour; vector hotkeys; MenuEntryLevel level; bool preselected; void *data; #ifdef USE_TILE vector tiles; #endif public: MenuEntry(const string &txt = string(), MenuEntryLevel lev = MEL_ITEM, int qty = 0, int hotk = 0, bool preselect = false) : text(txt), quantity(qty), selected_qty(0), colour(-1), hotkeys(), level(lev), preselected(preselect), data(NULL) { colour = (lev == MEL_ITEM ? MENU_ITEM_STOCK_COLOUR : lev == MEL_SUBTITLE ? BLUE : WHITE); if (hotk) hotkeys.push_back(hotk); } virtual ~MenuEntry() { } bool operator<(const MenuEntry& rhs) const { return text < rhs.text; } void add_hotkey(int key) { if (key && !is_hotkey(key)) hotkeys.push_back(key); } bool is_hotkey(int key) const { return find(hotkeys.begin(), hotkeys.end(), key) != hotkeys.end(); } bool is_primary_hotkey(int key) const { return hotkeys.size()? hotkeys[0] == key : false; } virtual string get_text(const bool unused = false) const { if (level == MEL_ITEM && hotkeys.size()) { char buf[300]; snprintf(buf, sizeof buf, " %c %c %s", hotkeys[0], preselected ? '+' : '-', text.c_str()); return string(buf); } return text; } virtual int highlight_colour() const { return menu_colour(get_text(), "", tag); } virtual bool selected() const { return selected_qty > 0 && quantity; } // -1: Invert // -2: Select all virtual void select(int qty = -1) { if (qty == -2) selected_qty = quantity; else if (selected()) selected_qty = 0; else if (quantity) selected_qty = (qty == -1 ? quantity : qty); } virtual string get_filter_text() const { return get_text(); } #ifdef USE_TILE virtual bool get_tiles(vector& tileset) const; virtual void add_tile(tile_def tile); #endif }; class ToggleableMenuEntry : public MenuEntry { public: string alt_text; ToggleableMenuEntry(const string &txt = string(), const string &alt_txt = string(), MenuEntryLevel lev = MEL_ITEM, int qty = 0, int hotk = 0, bool preselect = false) : MenuEntry(txt, lev, qty, hotk, preselect), alt_text(alt_txt) {} void toggle() { text.swap(alt_text); } }; class MonsterMenuEntry : public MenuEntry { public: MonsterMenuEntry(const string &str, const monster_info* mon, int hotkey); #ifdef USE_TILE virtual bool get_tiles(vector& tileset) const; #endif }; #ifdef USE_TILE class PlayerMenuEntry : public MenuEntry { public: PlayerMenuEntry(const string &str); virtual bool get_tiles(vector& tileset) const; }; #endif class FeatureMenuEntry : public MenuEntry { public: coord_def pos; dungeon_feature_type feat; FeatureMenuEntry(const string &str, const coord_def p, int hotkey); FeatureMenuEntry(const string &str, const dungeon_feature_type f, int hotkey); #ifdef USE_TILE virtual bool get_tiles(vector& tileset) const; #endif }; class MenuHighlighter { public: virtual int entry_colour(const MenuEntry *entry) const; virtual ~MenuHighlighter() { } }; enum MenuFlag { MF_NOSELECT = 0x0000, ///< No selection is permitted MF_SINGLESELECT = 0x0001, ///< Select just one item MF_MULTISELECT = 0x0002, ///< Select multiple items MF_NO_SELECT_QTY = 0x0004, ///< Disallow partial selections MF_ANYPRINTABLE = 0x0008, ///< Any printable character is valid, and ///< closes the menu. MF_SELECT_BY_PAGE = 0x0010, ///< Allow selections to occur only on ///< currently-visible page. MF_ALWAYS_SHOW_MORE = 0x0020, ///< Always show the -more- footer MF_NOWRAP = 0x0040, ///< Paging past the end will not wrap back. MF_ALLOW_FILTER = 0x0080, ///< Control-F will ask for regex and ///< select the appropriate items. MF_ALLOW_FORMATTING = 0x0100, ///< Parse index for formatted-string MF_SHOW_PAGENUMBERS = 0x0200, ///< Show "(page X of Y)" when appropriate MF_TOGGLE_ACTION = 0x0400, ///< ToggleableMenu toggles action as well MF_EASY_EXIT = 0x1000, ///< Exit when scrolling off the end MF_START_AT_END = 0x2000, ///< Scroll to end of list MF_PRESELECTED = 0x4000, ///< Has a preselected entry. MF_QUIET_SELECT = 0x8000, ///< No selection box and no count. }; class MenuDisplay { public: MenuDisplay(Menu *menu); virtual ~MenuDisplay() {} virtual void draw_stock_item(int index, const MenuEntry *me) = 0; virtual void set_offset(int lines) = 0; virtual void draw_more() = 0; virtual void set_num_columns(int columns) = 0; protected: Menu *m_menu; }; class MenuDisplayText : public MenuDisplay { public: MenuDisplayText(Menu *menu); virtual void draw_stock_item(int index, const MenuEntry *me); virtual void draw_more(); virtual void set_offset(int lines) { m_starty = lines; } virtual void set_num_columns(int columns) {} protected: int m_starty; }; class MenuDisplayTile : public MenuDisplay { public: MenuDisplayTile(Menu *menu); virtual void draw_stock_item(int index, const MenuEntry *me); virtual void set_offset(int lines); virtual void draw_more(); virtual void set_num_columns(int columns); }; /////////////////////////////////////////////////////////////////////// // NOTE // As a general contract, any pointers you pass to Menu methods are OWNED BY // THE MENU, and will be deleted by the Menu on destruction. So any pointers // you pass in MUST be allocated with new, or Crawl will crash. #define NUMBUFSIZ 10 // FIXME: MenuEntry is a large object, and shouldn't be used for // showing text files. class Menu { public: Menu(int flags = MF_MULTISELECT, const string& tagname = "", bool text_only = true); virtual ~Menu(); // Remove all items from the Menu, leave title intact. void clear(); // Sets menu flags to new_flags. If use_options is true, game options may // override options. void set_flags(int new_flags, bool use_options = true); int get_flags() const { return flags; } virtual bool is_set(int flag) const; void set_tag(const string& t) { tag = t; } bool draw_title_suffix(const string &s, bool titlefirst = true); bool draw_title_suffix(const formatted_string &fs, bool titlefirst = true); void update_title(); // Sets a replacement for the default -more- string. void set_more(const formatted_string &more); // Shows a stock message about scrolling the menu instead of -more- void set_more(); const formatted_string &get_more() const { return more; } void set_highlighter(MenuHighlighter *h); void set_title(MenuEntry *e, bool first = true); void add_entry(MenuEntry *entry); void get_selected(vector *sel) const; virtual int get_cursor() const; void set_maxpagesize(int max); int maxpagesize() const { return max_pagesize; } void set_select_filter(vector filter) { select_filter = filter; } int getkey() const { return lastch; } void reset(); virtual vector show(bool reuse_selections = false); vector selected_entries() const; size_t item_count() const { return items.size(); } // Get entry index, skipping quantity 0 entries. Returns -1 if not found. int get_entry_index(const MenuEntry *e) const; virtual int item_colour(int index, const MenuEntry *me) const; int get_y_offset() const { return y_offset; } int get_pagesize() const { return pagesize; } typedef string (*selitem_tfn)(const vector *sel); typedef void (*drawitem_tfn)(int index, const MenuEntry *me); typedef int (*keyfilter_tfn)(int keyin); selitem_tfn f_selitem; drawitem_tfn f_drawitem; keyfilter_tfn f_keyfilter; enum cycle { CYCLE_NONE, CYCLE_TOGGLE, CYCLE_CYCLE } action_cycle; enum action { ACT_EXECUTE, ACT_EXAMINE, ACT_MISC, ACT_NUM } menu_action; #ifdef USE_TILE_WEB void webtiles_write_menu(bool replace = false) const; void webtiles_scroll(int first); void webtiles_handle_item_request(int start, int end); #endif protected: MenuEntry *title; MenuEntry *title2; int flags; string tag; int first_entry, y_offset; int pagesize, max_pagesize; formatted_string more; vector items; vector sel; vector select_filter; // Class that is queried to colour menu entries. MenuHighlighter *highlighter; int num; int lastch; bool alive; int last_selected; MenuDisplay *mdisplay; protected: void check_add_formatted_line(int firstcol, int nextcol, string &line, bool check_eol); void do_menu(); virtual string get_select_count_string(int count) const; virtual void draw_select_count(int count, bool force = false); virtual void draw_item(int index) const; virtual void draw_index_item(int index, const MenuEntry *me) const; virtual void draw_stock_item(int index, const MenuEntry *me) const; #ifdef USE_TILE_WEB void webtiles_set_title(const formatted_string title); void webtiles_set_suffix(const formatted_string title); void webtiles_update_item(int index) const; void webtiles_update_title() const; void webtiles_update_scroll_pos() const; virtual void webtiles_write_title() const; virtual void webtiles_write_item(int index, const MenuEntry *me) const; void webtiles_update_section_boundaries(); int _webtiles_section_start; int _webtiles_section_end; bool _webtiles_title_changed; formatted_string _webtiles_title; formatted_string _webtiles_suffix; inline int webtiles_section_start() const { return _webtiles_section_start == -1 ? 0 : _webtiles_section_start; } inline int webtiles_section_end() const { return _webtiles_section_end == -1 ? items.size() : _webtiles_section_end; } #endif virtual void draw_title(); virtual void write_title(); virtual int title_height() const; virtual void draw_menu(); virtual bool page_down(); virtual bool line_down(); virtual bool page_up(); virtual bool line_up(); virtual int pre_process(int key); virtual int post_process(int key); bool in_page(int index) const; void deselect_all(bool update_view = true); virtual void select_items(int key, int qty = -1); void select_item_index(int idx, int qty, bool draw_cursor = true); void select_index(int index, int qty = -1); bool is_hotkey(int index, int key); virtual bool is_selectable(int index) const; virtual bool process_key(int keyin); virtual bool allow_easy_exit() const; }; /// Allows toggling by specific keys. class ToggleableMenu : public Menu { public: ToggleableMenu(int _flags = MF_MULTISELECT, bool text_only = true) : Menu(_flags, "", text_only) {} void add_toggle_key(int newkey) { toggle_keys.push_back(newkey); } protected: virtual int pre_process(int key); vector toggle_keys; }; // This is only tangentially related to menus, but what the heck. // Note, column margins start on 1, not 0. class column_composer { public: // Number of columns and left margins for 2nd, 3rd, ... nth column. column_composer(int ncols, ...); void clear(); void add_formatted(int ncol, const string &tagged_text, bool add_separator = true, bool eol_ends_format = true, bool (*text_filter)(const string &tag) = NULL, int margin = -1); vector formatted_lines() const; void set_pagesize(int pagesize); private: struct column; void compose_formatted_column( const vector &lines, int start_col, int margin); void strip_blank_lines(vector &) const; private: struct column { int margin; int lines; column(int marg = 1) : margin(marg), lines(0) { } }; int pagesize; vector columns; vector flines; }; // This class is for when (some of) your items are formatted, and // you want mostly a browser. // // If MF_NOSELECT, hotkeys jump to menu items. // If MF_SINGLESELECT, hotkeys end the menu immediately. // MF_MULTISELECT is not supported. class formatted_scroller : public Menu { public: formatted_scroller(); formatted_scroller(int flags, const string& s); virtual void add_item_formatted_string(const formatted_string& s, int hotkey = 0); virtual void add_item_string(const string& s, int hotkey = 0); virtual void add_text(const string& s, bool new_line = false); virtual bool jump_to_hotkey(int keyin); virtual vector show(bool reuse_selections = false); virtual ~formatted_scroller(); protected: virtual bool page_down(); virtual bool line_down(); virtual bool page_up(); virtual bool line_up(); virtual void draw_index_item(int index, const MenuEntry* me) const; virtual bool process_key(int keyin); bool jump_to(int linenum); #ifdef USE_TILE_WEB virtual void webtiles_write_item(int index, const MenuEntry* me) const; #endif }; /** * @author Janne "felirx" Lahdenpera * Abstract base class interface for all menu items to inherit from. * Each item should know how it's rendered. * Rendering should only check the item bounds and screen bounds to prevent * assertion errors. */ class MenuItem { public: MenuItem(); virtual ~MenuItem(); void set_height(const int height); void set_id(int id) { m_item_id = id; } int get_id() const { return m_item_id; } virtual void set_bounds(const coord_def& min_coord, const coord_def& max_coord); virtual void set_bounds_no_multiply(const coord_def& min_coord, const coord_def& max_coord); virtual void move(const coord_def& delta); virtual const coord_def& get_min_coord() const { return m_min_coord; } virtual const coord_def& get_max_coord() const { return m_max_coord; } virtual void set_description_text(const string& text) { m_description = text; } virtual const string& get_description_text() const { return m_description; } #ifdef USE_TILE_LOCAL virtual bool handle_mouse(const MouseEvent& me) {return false; } #endif virtual void select(bool toggle); virtual void select(bool toggle, int value); virtual bool selected() const; virtual void allow_highlight(bool toggle); virtual bool can_be_highlighted() const; virtual void set_highlight_colour(COLORS colour); virtual COLORS get_highlight_colour() const; virtual void set_fg_colour(COLORS colour); virtual void set_bg_colour(COLORS colour); virtual COLORS get_fg_colour() const; virtual COLORS get_bg_colour() const; virtual void set_visible(bool flag); virtual bool is_visible() const; virtual void render() = 0; void add_hotkey(int key); const vector& get_hotkeys() const; void clear_hotkeys(); void set_link_left(MenuItem* item); void set_link_right(MenuItem* item); void set_link_up(MenuItem* item); void set_link_down(MenuItem* item); MenuItem* get_link_left() const; MenuItem* get_link_right() const; MenuItem* get_link_up() const; MenuItem* get_link_down() const; protected: coord_def m_min_coord; coord_def m_max_coord; bool m_selected; bool m_allow_highlight; bool m_dirty; bool m_visible; vector m_hotkeys; string m_description; COLORS m_fg_colour; COLORS m_highlight_colour; int m_bg_colour; MenuItem* m_link_left; MenuItem* m_link_right; MenuItem* m_link_up; MenuItem* m_link_down; #ifdef USE_TILE_LOCAL // Holds the conversion values to translate unit values to pixel values unsigned int m_unit_width_pixels; unsigned int m_unit_height_pixels; int get_vertical_offset() const; #endif int m_item_id; }; /** * Basic Item with string unformatted text that can be selected */ class TextItem : public MenuItem { public: TextItem(); virtual ~TextItem(); virtual void set_bounds(const coord_def& min_coord, const coord_def& max_coord); virtual void set_bounds_no_multiply(const coord_def& min_coord, const coord_def& max_coord); virtual void render(); void set_text(const string& text); const string& get_text() const; protected: void _wrap_text(); string m_text; string m_render_text; #ifdef USE_TILE_LOCAL FontBuffer m_font_buf; #endif }; /** * Behaves the same as TextItem, except selection has been overridden to always * return false */ class NoSelectTextItem : public TextItem { public: NoSelectTextItem(); virtual ~NoSelectTextItem(); virtual bool selected() const; virtual bool can_be_highlighted() const; }; /** * Behaves the same as TextItem but use formatted text for rendering. * It ignores bg_colour. * TODO: add bg_colour support to formatted_string and merge this with TextItem. */ class FormattedTextItem : public TextItem { public: virtual void render(); }; /** * Holds an arbitrary number of tiles, currently rendered on top of each other */ #ifdef USE_TILE_LOCAL class TextTileItem : public TextItem { public: TextTileItem(); virtual ~TextTileItem(); virtual void set_bounds(const coord_def& min_coord, const coord_def& max_coord); virtual void render(); virtual void add_tile(tile_def tile); void clear_tile() { m_tiles.clear(); }; protected: vector m_tiles; FixedVector m_tile_buf; }; /** * Specialization of TextTileItem that knows how to pack a player doll * TODO: reform _pack_doll() since it currently holds duplicate code from * tilereg.cc pack_doll_buf() */ class SaveMenuItem : public TextTileItem { public: friend class TilesFramework; SaveMenuItem(); virtual ~SaveMenuItem(); virtual void render(); void set_doll(dolls_data doll); protected: void _pack_doll(); dolls_data m_save_doll; }; #endif class PrecisionMenu; /** * Abstract base class interface for all attachable objects. * Objects are generally containers that hold MenuItems, however special * objects are also possible, for instance MenuDescriptor, MenuButton. * All objects should have an unique string name, although the uniqueness * is not enforced or checked right now. */ class MenuObject { public: enum InputReturnValue { INPUT_NO_ACTION, // Nothing happened INPUT_SELECTED, // Something got selected INPUT_DESELECTED, // Something got deselected INPUT_END_MENU_SUCCESS, // Call the menu to end INPUT_END_MENU_ABORT, // Call the menu to clear all selections and end INPUT_ACTIVE_CHANGED, // Mouse position or keyboard event changed active INPUT_FOCUS_RELEASE_UP, // Selection went out of menu from top INPUT_FOCUS_RELEASE_DOWN, // Selection went out of menu from down INPUT_FOCUS_RELEASE_LEFT, // Selection went out of menu from left INPUT_FOCUS_RELEASE_RIGHT,// Selection went out of menu from right INPUT_FOCUS_LOST, // Eg. the user is moving his mouse somewhere else }; MenuObject(); virtual ~MenuObject(); void set_height(const int height); void init(const coord_def& min_coord, const coord_def& max_coord, const string& name); const coord_def& get_min_coord() const { return m_min_coord; } const coord_def& get_max_coord() const { return m_max_coord; } const string& get_name() const { return m_object_name; } virtual void allow_focus(bool toggle); virtual bool can_be_focused(); virtual InputReturnValue process_input(int key) = 0; #ifdef USE_TILE_LOCAL virtual InputReturnValue handle_mouse(const MouseEvent& me) = 0; #endif virtual void render() = 0; virtual void set_active_item(int ID) = 0; virtual void set_active_item(MenuItem* item) = 0; virtual void activate_first_item() = 0; virtual void activate_last_item() = 0; virtual void set_visible(bool flag); virtual bool is_visible() const; virtual vector get_selected_items(); virtual bool select_item(int index) = 0; virtual bool select_item(MenuItem* item) = 0; virtual MenuItem* find_item_by_hotkey(int key); virtual MenuItem* select_item_by_hotkey(int key); virtual void clear_selections(); virtual MenuItem* get_active_item() = 0; virtual bool attach_item(MenuItem* item) = 0; protected: enum Direction { UP, DOWN, LEFT, RIGHT, }; virtual void _place_items() = 0; virtual bool _is_mouse_in_bounds(const coord_def& pos); virtual MenuItem* _find_item_by_mouse_coords(const coord_def& pos); virtual MenuItem* _find_item_by_direction(const MenuItem* start, MenuObject::Direction dir) = 0; bool m_dirty; bool m_allow_focus; bool m_visible; coord_def m_min_coord; coord_def m_max_coord; string m_object_name; // by default, entries are held in a vector // if you need a different behaviour, please override the // affected methods vector m_entries; #ifdef USE_TILE_LOCAL // Holds the conversion values to translate unit values to pixel values unsigned int m_unit_width_pixels; unsigned int m_unit_height_pixels; #endif }; /** * Container object that holds MenuItems in a 2d plane. * There is no internal hierarchy structure inside the menu, thus the objects * are freely placed within the boundaries of the container */ class MenuFreeform : public MenuObject { public: MenuFreeform(); virtual ~MenuFreeform(); virtual InputReturnValue process_input(int key); #ifdef USE_TILE_LOCAL virtual InputReturnValue handle_mouse(const MouseEvent& me); #endif virtual void render(); virtual MenuItem* get_active_item(); virtual void set_active_item(int ID); virtual void set_active_item(MenuItem* item); virtual void activate_first_item(); virtual void activate_last_item(); void set_default_item(MenuItem* item); void activate_default_item(); virtual bool select_item(int index); virtual bool select_item(MenuItem* item); virtual bool attach_item(MenuItem* item); protected: virtual void _place_items(); virtual void _set_active_item_by_index(int index); virtual MenuItem* _find_item_by_direction(const MenuItem* start, MenuObject::Direction dir); // cursor position MenuItem* m_active_item; MenuItem* m_default_item; }; /** * Container that can hold any number of objects in a scroll list style. * Only certain number of items are visible at the same time. * Navigating the list works with ARROW_UP and ARROW_DOWN keys. * Eventually it should also support scrollbars. */ class MenuScroller : public MenuObject { public: MenuScroller(); virtual ~MenuScroller(); virtual InputReturnValue process_input(int key); #ifdef USE_TILE_LOCAL virtual InputReturnValue handle_mouse(const MouseEvent& me); #endif virtual void render(); virtual MenuItem* get_active_item(); virtual void set_active_item(int ID); virtual void set_active_item(MenuItem* item); virtual void activate_first_item(); virtual void activate_last_item(); virtual bool select_item(int index); virtual bool select_item(MenuItem* item); virtual bool attach_item(MenuItem* item); protected: virtual void _place_items(); virtual void _set_active_item_by_index(int index); virtual MenuItem* _find_item_by_direction(int start_index, MenuObject::Direction dir); virtual MenuItem* _find_item_by_direction(const MenuItem* start, MenuObject::Direction dir) { return NULL; } int m_topmost_visible; int m_currently_active; int m_items_shown; #ifdef USE_TILE_LOCAL TextTileItem *m_arrow_up; TextTileItem *m_arrow_down; #endif }; /** * Base class for various descriptor and highlighter objects. * These should probably be attached last to the menu to be rendered last. */ class MenuDescriptor : public MenuObject { public: MenuDescriptor(PrecisionMenu* parent); virtual ~MenuDescriptor(); void init(const coord_def& min_coord, const coord_def& max_coord, const string& name); virtual InputReturnValue process_input(int key); #ifdef USE_TILE_LOCAL virtual InputReturnValue handle_mouse(const MouseEvent& me); #endif virtual void render(); // these are not used, clear them virtual vector get_selected_items(); virtual MenuItem* get_active_item() { return NULL; } virtual bool attach_item(MenuItem* item) { return false; } virtual void set_active_item(int index) {} virtual void set_active_item(MenuItem* item) {} virtual void activate_first_item() {} virtual void activate_last_item() {} virtual bool select_item(int index) { return false; } virtual bool select_item(MenuItem* item) { return false;} virtual MenuItem* select_item_by_hotkey(int key) { return NULL; } virtual void clear_selections() {} // Do not allow focus virtual void allow_focus(bool toggle) {} virtual bool can_be_focused() { return false; } protected: virtual void _place_items(); virtual MenuItem* _find_item_by_mouse_coords(const coord_def& pos) { return NULL; } virtual MenuItem* _find_item_by_direction(const MenuItem* start, MenuObject::Direction dir) { return NULL; } // Used to pull out currently active item PrecisionMenu* m_parent; MenuItem* m_active_item; NoSelectTextItem m_desc_item; }; /** * Class for mouse over tooltips, does nothing if USE_TILE_LOCAL is not defined * TODO: actually implement render() and _place_items() */ class MenuTooltip : public MenuDescriptor { public: MenuTooltip(PrecisionMenu* parent); virtual ~MenuTooltip(); #ifdef USE_TILE_LOCAL virtual InputReturnValue handle_mouse(const MouseEvent& me); #endif virtual void render(); protected: virtual void _place_items(); #ifdef USE_TILE_LOCAL ShapeBuffer m_background; FontBuffer m_font_buf; #endif }; /** * Highlighter object. * TILES: It will create a colored rectangle around the currently active item. * CONSOLE: It will muck with the Item background color, setting it to highlight * colour, reverting the change when active changes. */ class BoxMenuHighlighter : public MenuObject { public: BoxMenuHighlighter(PrecisionMenu* parent); virtual ~BoxMenuHighlighter(); virtual InputReturnValue process_input(int key); #ifdef USE_TILE_LOCAL virtual InputReturnValue handle_mouse(const MouseEvent& me); #endif virtual void render(); // these are not used, clear them virtual vector get_selected_items(); virtual MenuItem* get_active_item() { return NULL; } virtual bool attach_item(MenuItem* item) { return false; } virtual void set_active_item(int index) {} virtual void set_active_item(MenuItem* item) {} virtual void activate_first_item() {} virtual void activate_last_item() {} virtual bool select_item(int index) { return false; } virtual bool select_item(MenuItem* item) { return false;} virtual MenuItem* select_item_by_hotkey(int key) { return NULL; } virtual void clear_selections() {} // Do not allow focus virtual void allow_focus(bool toggle) {} virtual bool can_be_focused() { return false; } protected: virtual void _place_items(); virtual MenuItem* _find_item_by_mouse_coords(const coord_def& pos) { return NULL; } virtual MenuItem* _find_item_by_direction(const MenuItem* start, MenuObject::Direction dir) { return NULL; } // Used to pull out currently active item PrecisionMenu* m_parent; MenuItem* m_active_item; #ifdef USE_TILE_LOCAL LineBuffer m_line_buf; #else COLORS m_old_bg_colour; #endif }; class BlackWhiteHighlighter : public BoxMenuHighlighter { public: BlackWhiteHighlighter(PrecisionMenu* parent); virtual ~BlackWhiteHighlighter(); virtual void render(); protected: virtual void _place_items(); #ifdef USE_TILE_LOCAL // Tiles does not seem to support background colors ShapeBuffer m_shape_buf; #endif COLORS m_old_bg_colour; COLORS m_old_fg_colour; }; /** * Base operations for a button to work. * TODO: implement */ class MenuButton : public MenuObject { public: protected: }; /** * Inheritable root node of a menu that holds MenuObjects. * It is always full screen. * Everything attached to it it owns, thus deleting the memory when it exits the * scope. * TODO: add multiple paging support */ class PrecisionMenu { public: enum SelectType { PRECISION_SINGLESELECT, PRECISION_MULTISELECT, }; PrecisionMenu(); virtual ~PrecisionMenu(); virtual void set_select_type(SelectType flag); virtual void clear(); virtual void draw_menu(); virtual bool process_key(int key); #ifdef USE_TILE_LOCAL virtual int handle_mouse(const MouseEvent& me); #endif // not const on purpose virtual vector get_selected_items(); virtual void attach_object(MenuObject* item); virtual MenuObject* get_object_by_name(const string& search); virtual MenuItem* get_active_item(); virtual void set_active_object(MenuObject* object); virtual void clear_selections(); protected: // These correspond to the Arrow keys when used for browsing the menus enum Direction { UP, DOWN, LEFT, RIGHT, }; MenuObject* _find_object_by_direction(const MenuObject* start, Direction dir); vector m_attached_objects; MenuObject* m_active_object; SelectType m_select_type; }; int linebreak_string(string& s, int maxcol, bool indent = false); string get_linebreak_string(const string& s, int maxcol); #ifdef USE_TILE_LOCAL class Popup { public: // constructors Popup(string prompt); // accessors // get/set prompt text void set_prompt(string prompt); string get_prompt() { return m_prompt; } // methods // add a menu entry to the popup void push_entry(MenuEntry *me); // remove a menu entry from the popup MenuEntry* next_entry(); // draw the popup and return key pressed int pop(); protected: vector m_entries; string m_prompt; private: unsigned int m_curr; }; #endif #endif