From 7db47d41a1e8c783f0cf9aba41b835cc9950fc96 Mon Sep 17 00:00:00 2001 From: ennewalker Date: Sat, 25 Oct 2008 17:47:37 +0000 Subject: More graphical menu improvements. Inventory menus now have columns. Long entries are now wrapped and then truncated. git-svn-id: https://crawl-ref.svn.sourceforge.net/svnroot/crawl-ref/trunk@7296 c06c8d41-db1a-0410-9941-cceddc491573 --- crawl-ref/source/format.cc | 21 +++++++ crawl-ref/source/format.h | 3 +- crawl-ref/source/invent.cc | 7 +++ crawl-ref/source/invent.h | 8 +-- crawl-ref/source/menu.cc | 7 +++ crawl-ref/source/menu.h | 4 +- crawl-ref/source/tilefont.cc | 112 +++++++++++++++++++++++++++++++++- crawl-ref/source/tilefont.h | 14 +++++ crawl-ref/source/tilereg.cc | 142 ++++++++++++++++++++++++++++++++----------- crawl-ref/source/tilereg.h | 2 + 10 files changed, 276 insertions(+), 44 deletions(-) (limited to 'crawl-ref/source') diff --git a/crawl-ref/source/format.cc b/crawl-ref/source/format.cc index 9cd282e058..cf884f8220 100644 --- a/crawl-ref/source/format.cc +++ b/crawl-ref/source/format.cc @@ -329,6 +329,27 @@ inline void cap(int &i, int max) i = 0; } +char &formatted_string::operator [] (size_t idx) +{ + size_t rel_idx = idx; + int size = ops.size(); + for (int i = 0; i < size; ++i) + { + if (ops[i] != FSOP_TEXT) + continue; + + size_t len = ops[i].text.length(); + if (rel_idx >= len) + rel_idx -= len; + else + return ops[i].text[rel_idx]; + } + ASSERT(!"Invalid index"); + char *invalid = NULL; + return *invalid; +} + + std::string formatted_string::tostring(int s, int e) const { std::string st; diff --git a/crawl-ref/source/format.h b/crawl-ref/source/format.h index 9ddd43576d..297e793106 100644 --- a/crawl-ref/source/format.h +++ b/crawl-ref/source/format.h @@ -26,7 +26,7 @@ class formatted_string { public: formatted_string(int init_colour = 0); - formatted_string(const std::string &s, int init_colour = 0); + explicit formatted_string(const std::string &s, int init_colour = 0); operator std::string() const; void display(int start = 0, int end = -1) const; @@ -51,6 +51,7 @@ public: bool operator < ( const formatted_string &other ) const; const formatted_string &operator += (const formatted_string &other); + char &operator [] (size_t idx); public: static formatted_string parse_string( diff --git a/crawl-ref/source/invent.cc b/crawl-ref/source/invent.cc index 5c4c7ecad5..fbef463669 100644 --- a/crawl-ref/source/invent.cc +++ b/crawl-ref/source/invent.cc @@ -268,6 +268,13 @@ InvShowPrices::~InvShowPrices() InvEntry::set_show_prices(false); } +InvMenu::InvMenu(int mflags) + : Menu(mflags, "inventory"), type(MT_INVLIST), pre_select(NULL), + title_annotate(NULL) +{ + mdisplay->set_num_columns(2); +} + // Returns vector of item_def pointers to each item_def in the given // vector. Note: make sure the original vector stays around for the lifetime // of the use of the item pointers, or mayhem results! diff --git a/crawl-ref/source/invent.h b/crawl-ref/source/invent.h index 8cdabe01b1..5e5e95f53a 100644 --- a/crawl-ref/source/invent.h +++ b/crawl-ref/source/invent.h @@ -117,11 +117,7 @@ public: class InvMenu : public Menu { public: - InvMenu(int mflags = MF_MULTISELECT) - : Menu(mflags, "inventory"), type(MT_INVLIST), pre_select(NULL), - title_annotate(NULL) - { - } + InvMenu(int mflags = MF_MULTISELECT); unsigned char getkey() const; @@ -155,6 +151,8 @@ public: // of the use of the item pointers, or mayhem results! static std::vector xlat_itemvect( const std::vector &); + + virtual int max_columns() const { return 2; } protected: bool process_key(int key); void do_preselect(InvEntry *ie); diff --git a/crawl-ref/source/menu.cc b/crawl-ref/source/menu.cc index a3c7b1e155..a9f4f33109 100644 --- a/crawl-ref/source/menu.cc +++ b/crawl-ref/source/menu.cc @@ -69,6 +69,11 @@ void MenuDisplayTile::draw_more() { tiles.get_menu()->set_more(m_menu->get_more()); } + +void MenuDisplayTile::set_num_columns(int columns) +{ + tiles.get_menu()->set_num_columns(columns); +} #endif Menu::Menu( int _flags, const std::string& tagname ) @@ -83,6 +88,7 @@ Menu::Menu( int _flags, const std::string& tagname ) #else mdisplay = new MenuDisplayText(this); #endif + mdisplay->set_num_columns(1); set_flags(flags); } @@ -102,6 +108,7 @@ Menu::Menu( const formatted_string &fs ) #else mdisplay = new MenuDisplayText(this); #endif + mdisplay->set_num_columns(1); int colour = LIGHTGREY; int last_text_colour = LIGHTGREY; diff --git a/crawl-ref/source/menu.h b/crawl-ref/source/menu.h index ce2b857ada..ca48475b64 100644 --- a/crawl-ref/source/menu.h +++ b/crawl-ref/source/menu.h @@ -196,6 +196,7 @@ public: 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; }; @@ -207,6 +208,7 @@ public: 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; }; @@ -218,6 +220,7 @@ public: 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); }; /////////////////////////////////////////////////////////////////////// @@ -294,7 +297,6 @@ public: virtual int item_colour(int index, const MenuEntry *me) const; int get_y_offset() const { return y_offset; } int get_pagesize() const { return pagesize; } - public: typedef std::string (*selitem_tfn)( const std::vector *sel ); typedef void (*drawitem_tfn)(int index, const MenuEntry *me); diff --git a/crawl-ref/source/tilefont.cc b/crawl-ref/source/tilefont.cc index 93d14aa9dc..e2251d2042 100644 --- a/crawl-ref/source/tilefont.cc +++ b/crawl-ref/source/tilefont.cc @@ -447,7 +447,29 @@ static void _draw_box(int x_pos, int y_pos, float width, float height, glVertexPointer(2, GL_FLOAT, sizeof(box_vert), &verts[0].x); glColorPointer(4, GL_UNSIGNED_BYTE, sizeof(box_vert), &verts[0].r); glDrawArrays(GL_QUADS, 0, sizeof(verts) / sizeof(box_vert)); +} +unsigned int FTFont::string_height(const formatted_string &str) +{ + std::string temp = str.tostring(); + return string_height(temp.c_str()); +} + +unsigned int FTFont::string_height(const char *text) +{ + int height = 1; + for (const char *itr = text; (*itr); itr++) + { + if (*itr == '\n') + height++; + } + return char_height() * height; +} + +unsigned int FTFont::string_width(const formatted_string &str) +{ + std::string temp = str.tostring(); + return string_width(temp.c_str()); } unsigned int FTFont::string_width(const char *text) @@ -455,7 +477,7 @@ unsigned int FTFont::string_width(const char *text) unsigned int base_width = std::max(-m_min_offset, 0); unsigned int max_width = 0; - unsigned int width = 0; + unsigned int width = base_width; unsigned int adjust = 0; for (const char *itr = text; *itr; itr++) { @@ -476,6 +498,79 @@ unsigned int FTFont::string_width(const char *text) return max_width; } +int FTFont::find_index_before_width(const char *text, int max_width) +{ + int width = std::max(-m_min_offset, 0); + + for (int i = 0; text[i]; i++) + { + char c = text[i]; + width += m_glyphs[c].advance; + int adjust = std::max(0, m_glyphs[c].width - m_glyphs[c].advance); + if (width + adjust > max_width) + return i; + } + + return -1; +} + +formatted_string FTFont::split(const formatted_string &str, + unsigned int max_width, unsigned int max_height) +{ + int max_lines = max_height / char_height(); + + if (max_lines < 1) + return formatted_string(); + + formatted_string ret; + ret += str; + + std::string base = str.tostring(); + int num_lines = 0; + + char *line = &base[0]; + while (true) + { + int line_end = find_index_before_width(line, max_width); + if (line_end == -1) + break; + + int space_idx = 0; + for (char *search = &line[line_end]; search > line; search--) + { + if (*search == ' ') + { + space_idx = search - line; + break; + } + } + + if (++num_lines >= max_lines || !space_idx) + { + int ellipses; + if (space_idx && (space_idx - line_end > 2)) + ellipses = space_idx; + else + ellipses = line_end - 2; + + size_t idx = &line[ellipses] - &base[0]; + ret[idx] = '.'; + ret[idx+1] = '.'; + + return ret.substr(0, idx + 2); + } + else + { + line[space_idx] = '\n'; + ret[&line[space_idx] - &base[0]] = '\n'; + } + + line = &line[space_idx+1]; + } + + return ret; +} + void FTFont::render_string(unsigned int px, unsigned int py, const char *text, const coord_def &min_pos, const coord_def &max_pos, @@ -560,12 +655,19 @@ void FTFont::render_string(unsigned int px, unsigned int py, void FTFont::store(FontBuffer &buf, float &x, float &y, const std::string &str, const VColour &col) +{ + store(buf, x, y, str, col, x); +} + +void FTFont::store(FontBuffer &buf, float &x, float &y, + const std::string &str, const VColour &col, float orig_x) { for (unsigned int i = 0; i < str.size(); i++) { char c = str[i]; if (c == '\n') { + x = orig_x; y += m_max_advance.y; } else @@ -577,6 +679,12 @@ void FTFont::store(FontBuffer &buf, float &x, float &y, void FTFont::store(FontBuffer &buf, float &x, float &y, const formatted_string &fs) +{ + store(buf, x, y, fs, x); +} + +void FTFont::store(FontBuffer &buf, float &x, float &y, + const formatted_string &fs, float orig_x) { int colour = LIGHTGREY; for (unsigned int i = 0; i < fs.ops.size(); i++) @@ -588,7 +696,7 @@ void FTFont::store(FontBuffer &buf, float &x, float &y, colour = fs.ops[i].x & 0xF; break; case FSOP_TEXT: - store(buf, x, y, fs.ops[i].text, term_colours[colour]); + store(buf, x, y, fs.ops[i].text, term_colours[colour], orig_x); break; default: case FSOP_CURSOR: diff --git a/crawl-ref/source/tilefont.h b/crawl-ref/source/tilefont.h index ba4101f167..ab81353be4 100644 --- a/crawl-ref/source/tilefont.h +++ b/crawl-ref/source/tilefont.h @@ -57,10 +57,24 @@ public: unsigned int char_height() const { return m_max_advance.y; } unsigned int string_width(const char *text); + unsigned int string_width(const formatted_string &str); + unsigned int string_height(const char *text); + unsigned int string_height(const formatted_string &str); + + // Try to split this string to fit in w x h pixel area. + formatted_string split(const formatted_string &str, unsigned int max_width, + unsigned int max_height); const GenericTexture *font_tex() const { return &m_tex; } protected: + void store(FontBuffer &buf, float &x, float &y, + const std::string &s, const VColour &c, float orig_x); + void store(FontBuffer &buf, float &x, float &y, const formatted_string &fs, + float orig_x); + + int find_index_before_width(const char *str, int max_width); + struct GlyphInfo { // offset before drawing glyph; can be negative diff --git a/crawl-ref/source/tilereg.cc b/crawl-ref/source/tilereg.cc index 6fea149787..021fd9c2bb 100644 --- a/crawl-ref/source/tilereg.cc +++ b/crawl-ref/source/tilereg.cc @@ -2357,7 +2357,7 @@ int CRTRegion::handle_mouse(MouseEvent &event) MenuRegion::MenuRegion(ImageManager *im, FTFont *entry) : m_image(im), m_font_entry(entry), m_mouse_idx(-1), - m_dirty(false), m_font_buf(entry), m_tile_buf(NULL) + m_max_columns(1), m_dirty(false), m_font_buf(entry), m_tile_buf(NULL) { ASSERT(m_image); ASSERT(m_font_entry); @@ -2368,6 +2368,11 @@ MenuRegion::MenuRegion(ImageManager *im, FTFont *entry) : m_entries.resize(128); } +void MenuRegion::set_num_columns(int columns) +{ + m_max_columns = std::max(1, columns); +} + int MenuRegion::mouse_entry(int x, int y) { if (m_dirty) @@ -2450,10 +2455,9 @@ void MenuRegion::place_entries() m_dirty = false; const int heading_indent = 10; - const int tile_ident = 20; + const int tile_indent = 20; const int text_indent = 58; - const unsigned int max_tile_height = 32; - const int column_width = mx / 2; + const int max_tile_height = 32; const int entry_buffer = 1; const VColour selected_colour(50, 50, 10, 255); @@ -2464,8 +2468,11 @@ void MenuRegion::place_entries() TextureID tex = TEX_MAX; int height = 2; + int prev_height = height; - bool mouse_selected = false; + int column = 0; + const int max_columns = std::min(2, m_max_columns); + const int column_width = mx / max_columns; for (unsigned int i = 0; i < m_entries.size(); i++) { @@ -2478,45 +2485,110 @@ void MenuRegion::place_entries() continue; } - m_entries[i].sy = height; - - int text_start = 0; - int text_height = height; + int text_width = m_font_entry->string_width(m_entries[i].text); + int text_height = m_font_entry->char_height(); if (m_entries[i].heading) { - mouse_selected = false; m_entries[i].sx = heading_indent; - text_start = heading_indent; - height += m_font_entry->char_height(); - } - else if (m_entries[i].tile) - { - m_entries[i].sx = tile_ident; - text_start = text_indent; - int entry_height = - std::max(max_tile_height, m_font_entry->char_height()); - height += entry_height; - text_height += (entry_height - m_font_entry->char_height()) / 2; - - ASSERT(m_entries[i].texture == tex || tex == TEX_MAX); - tex = m_entries[i].texture; - m_tile_buf.set_tex(&m_image->m_textures[tex]); - - m_tile_buf.add(m_entries[i].tile, m_entries[i].sx, m_entries[i].sy); + m_entries[i].ex = m_entries[i].sx + text_width; + m_entries[i].sy = height; + m_entries[i].ey = m_entries[i].sy + text_height; + + m_font_buf.add(m_entries[i].text, m_entries[i].sx, m_entries[i].sy); + + height += text_height; + prev_height = height; + column = 0; } else { - m_entries[i].sx = text_start + text_indent; - height += m_font_entry->char_height(); - } + int entry_start; + if (column > 0) + { + entry_start = column * column_width; + m_entries[i].sy = prev_height; + } + else + { + entry_start = 0; + m_entries[i].sy = height; + } + + int text_sx = entry_start + text_indent; - std::string unfrm = m_entries[i].text.tostring(); - m_entries[i].ex = text_start + m_font_entry->string_width(unfrm.c_str()); - m_entries[i].ex = std::max(m_entries[i].ex, column_width); - m_entries[i].ey = height; + int entry_height; + if (m_entries[i].tile) + { + m_entries[i].sx = entry_start + tile_indent; + entry_height = std::max(max_tile_height, text_height); + + // Currently, menus only support one texture at a time. + tex = m_entries[i].texture; + ASSERT(m_entries[i].texture == tex || tex == TEX_MAX); + + m_tile_buf.set_tex(&m_image->m_textures[tex]); + m_tile_buf.add(m_entries[i].tile, m_entries[i].sx, + m_entries[i].sy); + } + else + { + m_entries[i].sx = text_sx; + entry_height = text_height; + } - m_font_buf.add(m_entries[i].text, text_start, text_height); + int text_sy = m_entries[i].sy; + text_sy += (entry_height - m_font_entry->char_height()) / 2; + if (text_sx + text_width > entry_start + column_width) + { + // [enne] - Ugh, hack. Maybe MenuEntry could specify the + // presence and length of this substring? + std::string unfm = m_entries[i].text.tostring(); + bool let = (unfm[1] >= 'a' && unfm[1] <= 'z' + || unfm[1] >= 'A' && unfm[1] <= 'Z'); + bool plus = (unfm[3] == '-' || unfm[3] == '+'); + + formatted_string text; + if (let && plus && unfm[0] == ' ' && unfm[2] == ' ' + && unfm[4] == ' ') + { + formatted_string header = m_entries[i].text.substr(0, 5); + m_font_buf.add(header, text_sx, text_sy); + text_sx += m_font_entry->string_width(header); + text = m_entries[i].text.substr(5); + } + else + { + text += m_entries[i].text; + } + + int w = entry_start + column_width - text_sx; + int h = m_font_entry->char_height() * 2; + formatted_string split = m_font_entry->split(text, w, h); + + int string_height = m_font_entry->string_height(split); + if (string_height > entry_height) + { + text_sy = m_entries[i].sy; + } + m_font_buf.add(split, text_sx, text_sy); + + m_entries[i].ex = entry_start + column_width; + + entry_height = std::max(entry_height, string_height); + } + else + { + m_entries[i].ex = entry_start + column_width; + m_font_buf.add(m_entries[i].text, text_sx, text_sy); + } + + m_entries[i].ey = m_entries[i].sy + entry_height; + + prev_height = m_entries[i].sy; + height = std::max(height, m_entries[i].ey); + column = (column + 1) % max_columns; + } if (m_entries[i].selected) { diff --git a/crawl-ref/source/tilereg.h b/crawl-ref/source/tilereg.h index 4111e6152a..55205ed3e3 100644 --- a/crawl-ref/source/tilereg.h +++ b/crawl-ref/source/tilereg.h @@ -193,6 +193,7 @@ public: void set_entry(int index, const std::string &s, int colour, const MenuEntry *me); void set_offset(int lines); void set_more(const formatted_string &more); + void set_num_columns(int columns); protected: virtual void on_resize(); virtual void place_entries(); @@ -214,6 +215,7 @@ protected: FTFont *m_font_entry; formatted_string m_more; int m_mouse_idx; + int m_max_columns; bool m_dirty; std::vector m_entries; -- cgit v1.2.3-54-g00ecf