/* Minetest Copyright (C) 2013 celeron55, Perttu Ahola <celeron55@gmail.com> This program is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #ifndef GUITABLE_HEADER #define GUITABLE_HEADER #include <map> #include <set> #include <string> #include <vector> #include <iostream> #include "irrlichttypes_extrabloated.h" class ISimpleTextureSource; /* A table GUI element for GUIFormSpecMenu. Sends a EGET_TABLE_CHANGED event to the parent when an item is selected or double-clicked. Call checkEvent() to get info. Credits: The interface and implementation of this class are (very) loosely based on the Irrlicht classes CGUITable and CGUIListBox. CGUITable and CGUIListBox are licensed under the Irrlicht license; they are Copyright (C) 2002-2012 Nikolaus Gebhardt */ class GUITable : public gui::IGUIElement { public: /* Stores dynamic data that should be preserved when updating a formspec */ struct DynamicData { s32 selected; s32 scrollpos; s32 keynav_time; core::stringw keynav_buffer; std::set<s32> opened_trees; DynamicData() { selected = 0; scrollpos = 0; keynav_time = 0; } }; /* An option of the form <name>=<value> */ struct Option { std::string name; std::string value; Option(const std::string &name_, const std::string &value_) { name = name_; value = value_; } }; /* A list of options that concern the entire table */ typedef std::vector<Option> TableOptions; /* A column with options */ struct TableColumn { std::string type; std::vector<Option> options; }; typedef std::vector<TableColumn> TableColumns; GUITable(gui::IGUIEnvironment *env, gui::IGUIElement *parent, s32 id, core::rect<s32> rectangle, ISimpleTextureSource *tsrc); virtual ~GUITable(); /* Split a string of the form "name=value" into name and value */ static Option splitOption(const std::string &str); /* Set textlist-like options, columns and data */ void setTextList(const std::vector<std::string> &content, bool transparent); /* Set generic table options, columns and content */ // Adds empty strings to end of content if there is an incomplete row void setTable(const TableOptions &options, const TableColumns &columns, std::vector<std::string> &content); /* Clear the table */ void clear(); /* Get info about last event (string such as "CHG:1:2") */ // Call this after EGET_TABLE_CHANGED std::string checkEvent(); /* Get index of currently selected row (first=1; 0 if none selected) */ s32 getSelected() const; /* Set currently selected row (first=1; 0 if none selected) */ // If given index is not visible at the moment, select its parent // Autoscroll to make the selected row fully visible void setSelected(s32 index); /* Get selection, scroll position and opened (sub)trees */ DynamicData getDynamicData() const; /* Set selection, scroll position and opened (sub)trees */ void setDynamicData(const DynamicData &dyndata); /* Returns "GUITable" */ virtual const c8* getTypeName() const; /* Must be called when position or size changes */ virtual void updateAbsolutePosition(); /* Irrlicht draw method */ virtual void draw(); /* Irrlicht event handler */ virtual bool OnEvent(const SEvent &event); protected: enum ColumnType { COLUMN_TYPE_TEXT, COLUMN_TYPE_IMAGE, COLUMN_TYPE_COLOR, COLUMN_TYPE_INDENT, COLUMN_TYPE_TREE, }; struct Cell { s32 xmin; s32 xmax; s32 xpos; ColumnType content_type; s32 content_index; s32 tooltip_index; video::SColor color; bool color_defined; s32 reported_column; }; struct Row { Cell *cells; s32 cellcount; s32 indent; // visible_index >= 0: is index of row in m_visible_rows // visible_index == -1: parent open but other ancestor closed // visible_index == -2: parent closed s32 visible_index; }; // Texture source ISimpleTextureSource *m_tsrc; // Table content (including hidden rows) std::vector<Row> m_rows; // Table content (only visible; indices into m_rows) std::vector<s32> m_visible_rows; bool m_is_textlist; bool m_has_tree_column; // Selection status s32 m_selected; // index of row (1...n), or 0 if none selected s32 m_sel_column; bool m_sel_doubleclick; // Keyboard navigation stuff s32 m_keynav_time; core::stringw m_keynav_buffer; // Drawing and geometry information bool m_border; video::SColor m_color; video::SColor m_background; video::SColor m_highlight; video::SColor m_highlight_text; s32 m_rowheight; gui::IGUIFont *m_font; gui::IGUIScrollBar *m_scrollbar; // Allocated strings and images std::vector<core::stringw> m_strings; std::vector<video::ITexture*> m_images; std::map<std::string, s32> m_alloc_strings; std::map<std::string, s32> m_alloc_images; s32 allocString(const std::string &text); s32 allocImage(const std::string &imagename); void allocationComplete(); // Helper for draw() that draws a single cell void drawCell(const Cell *cell, video::SColor color, const core::rect<s32> &rowrect, const core::rect<s32> &client_clip); // Returns the i-th visible row (NULL if i is invalid) const Row *getRow(s32 i) const; // Key navigation helper bool doesRowStartWith(const Row *row, const core::stringw &str) const; // Returns the row at a given screen Y coordinate // Returns index i such that m_rows[i] is valid (or -1 on error) s32 getRowAt(s32 y, bool &really_hovering) const; // Returns the cell at a given screen X coordinate within m_rows[row_i] // Returns index j such that m_rows[row_i].cells[j] is valid // (or -1 on error) s32 getCellAt(s32 x, s32 row_i) const; // Make the selected row fully visible void autoScroll(); // Should be called when m_rowcount or m_rowheight changes void updateScrollBar(); // Sends EET_GUI_EVENT / EGET_TABLE_CHANGED to parent void sendTableEvent(s32 column, bool doubleclick); // Functions that help deal with hidden rows // The following functions take raw row indices (hidden rows not skipped) void getOpenedTrees(std::set<s32> &opened_trees) const; void setOpenedTrees(const std::set<s32> &opened_trees); void openTree(s32 to_open); void closeTree(s32 to_close); // The following function takes a visible row index (hidden rows skipped) // dir: -1 = left (close), 0 = auto (toggle), 1 = right (open) void toggleVisibleTree(s32 row_i, int dir, bool move_selection); // Aligns cell content in column according to alignment specification // align = 0: left aligned, 1: centered, 2: right aligned, 3: inline static void alignContent(Cell *cell, s32 xmax, s32 content_width, s32 align); }; #endif