diff options
author | Enne Walker <ennewalker@users.sourceforge.net> | 2010-04-19 20:00:06 -0400 |
---|---|---|
committer | Enne Walker <ennewalker@users.sourceforge.net> | 2010-04-25 19:33:13 -0400 |
commit | 8305dc11a61b732984b4bf2a2f8c8f48af84630e (patch) | |
tree | 9f605e327b60ab79111ae7c25bec938ed2261a0b /crawl-ref/source/tilereg-menu.cc | |
parent | edacdc0db313c0f5385631dfcf560f1fdf8e7c8a (diff) | |
download | crawl-ref-8305dc11a61b732984b4bf2a2f8c8f48af84630e.tar.gz crawl-ref-8305dc11a61b732984b4bf2a2f8c8f48af84630e.zip |
Split tilereg.h/cc into multiple files.
No functional changes, just rearranging and exposing functions where
needed.
Diffstat (limited to 'crawl-ref/source/tilereg-menu.cc')
-rw-r--r-- | crawl-ref/source/tilereg-menu.cc | 389 |
1 files changed, 389 insertions, 0 deletions
diff --git a/crawl-ref/source/tilereg-menu.cc b/crawl-ref/source/tilereg-menu.cc new file mode 100644 index 0000000000..45d0d967cb --- /dev/null +++ b/crawl-ref/source/tilereg-menu.cc @@ -0,0 +1,389 @@ +/* + * File: tilereg-menu.cc + * + * Created by: ennewalker on Sat Jan 5 01:33:53 2008 UTC + */ + +#include "AppHdr.h" + +#ifdef USE_TILE + +#include "tilereg-menu.h" + +#include "menu.h" +#include "options.h" +#include "tilebuf.h" +#include "tilefont.h" + +MenuRegion::MenuRegion(ImageManager *im, FontWrapper *entry) : + m_image(im), m_font_entry(entry), m_mouse_idx(-1), + m_max_columns(1), m_dirty(false), m_font_buf(entry) +{ + ASSERT(m_image); + ASSERT(m_font_entry); + + dx = 1; + dy = 1; + + m_entries.resize(128); + + for (int i = 0; i < TEX_MAX; i++) + m_tile_buf[i].set_tex(&m_image->m_textures[i]); +} + +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) + place_entries(); + + for (unsigned int i = 0; i < m_entries.size(); i++) + { + if (!m_entries[i].valid) + continue; + + if (x >= m_entries[i].sx && x <= m_entries[i].ex + && y >= m_entries[i].sy && y <= m_entries[i].ey) + { + return i; + } + } + + return -1; +} + +int MenuRegion::handle_mouse(MouseEvent &event) +{ + m_mouse_idx = -1; + + int x, y; + if (!mouse_pos(event.px, event.py, x, y)) + return 0; + + if (event.event == MouseEvent::MOVE) + { + int old_idx = m_mouse_idx; + m_mouse_idx = mouse_entry(x, y); + if (old_idx == m_mouse_idx) + return 0; + + const VColour mouse_colour(160, 160, 160, 255); + + m_line_buf.clear(); + if (!m_entries[m_mouse_idx].heading && m_entries[m_mouse_idx].key) + { + m_line_buf.add_square(m_entries[m_mouse_idx].sx-1, + m_entries[m_mouse_idx].sy, + m_entries[m_mouse_idx].ex+1, + m_entries[m_mouse_idx].ey+1, + mouse_colour); + } + + return 0; + } + + if (event.event == MouseEvent::PRESS) + { + switch (event.button) + { + case MouseEvent::LEFT: + { + int entry = mouse_entry(x, y); + if (entry == -1) + return 0; + return m_entries[entry].key; + } +#if 0 + // TODO enne - these events are wonky on OS X. + // TODO enne - fix menus so that mouse wheeling doesn't easy exit + case MouseEvent::SCROLL_UP: + return CK_UP; + case MouseEvent::SCROLL_DOWN: + return CK_DOWN; +#endif + default: + return 0; + } + } + + return 0; +} + +void MenuRegion::place_entries() +{ + m_dirty = false; + + const int heading_indent = 10; + const int tile_indent = 20; + const int text_indent = (Options.tile_menu_icons ? 58 : 20); + const int max_tile_height = (Options.tile_menu_icons ? 32 : 0); + const int entry_buffer = 1; + const VColour selected_colour(50, 50, 10, 255); + + m_font_buf.clear(); + m_shape_buf.clear(); + m_line_buf.clear(); + for (int t = 0; t < TEX_MAX; t++) + m_tile_buf[t].clear(); + + int column = 0; + if (!Options.tile_menu_icons) + set_num_columns(1); + const int max_columns = std::min(2, m_max_columns); + const int column_width = mx / max_columns; + + int lines = count_linebreaks(m_more); + int more_height = (lines + 1) * m_font_entry->char_height(); + m_font_buf.add(m_more, sx + ox, ey - oy - more_height); + + int height = 0; + int end_height = my - more_height; + + const int max_entry_height = std::max((int)m_font_entry->char_height() * 2, + max_tile_height); + + for (unsigned int i = 0; i < m_entries.size(); i++) + { + if (!m_entries[i].valid) + { + m_entries[i].sx = 0; + m_entries[i].sy = 0; + m_entries[i].ex = 0; + m_entries[i].ey = 0; + continue; + } + + if (height + max_entry_height > end_height && column <= max_columns) + { + height = 0; + column++; + } + + 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) + { + m_entries[i].sx = heading_indent + column * column_width; + 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; + } + else + { + m_entries[i].sy = height; + int entry_start = column * column_width; + int text_sx = text_indent + entry_start; + + int entry_height; + + if (m_entries[i].tiles.size() > 0) + { + m_entries[i].sx = entry_start + tile_indent; + entry_height = std::max(max_tile_height, text_height); + + for (unsigned int t = 0; t < m_entries[i].tiles.size(); t++) + { + // NOTE: This is not perfect. Tiles will be drawn + // sorted by texture first, e.g. you can never draw + // a dungeon tile over a monster tile. + int tile = m_entries[i].tiles[t].tile; + TextureID tex = m_entries[i].tiles[t].tex; + m_tile_buf[tex].add_unscaled(tile, m_entries[i].sx, + m_entries[i].sy, + m_entries[i].tiles[t].ymax); +// m_tile_buf[tex].add(tile, m_entries[i].sx, m_entries[i].sy, +// 0, 0, true, TILE_Y); + } + } + else + { + m_entries[i].sx = text_sx; + entry_height = text_height; + } + + int text_sy = m_entries[i].sy; + text_sy += (entry_height - m_font_entry->char_height()) / 2; + // Split menu entries that don't fit into a single line into + // two lines. + if (Options.tile_menu_icons + && 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); + + entry_height = std::max(entry_height, string_height); + m_entries[i].ex = entry_start + column_width; + } + else + { + if (max_columns == 1) + m_entries[i].ex = text_sx + text_width; + 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; + height = m_entries[i].ey; + } + + if (m_entries[i].selected) + { + m_shape_buf.add(m_entries[i].sx-1, m_entries[i].sy-1, + m_entries[i].ex+1, m_entries[i].ey+1, + selected_colour); + } + + height += entry_buffer; + } +} + +void MenuRegion::render() +{ +#ifdef DEBUG_TILES_REDRAW + cprintf("rendering MenuRegion\n"); +#endif + if (m_dirty) + place_entries(); + + set_transform(); + m_shape_buf.draw(NULL, NULL); + m_line_buf.draw(NULL, NULL); + for (int i = 0; i < TEX_MAX; i++) + m_tile_buf[i].draw(NULL, NULL); + m_font_buf.draw(NULL, NULL); +} + +void MenuRegion::clear() +{ + m_shape_buf.clear(); + m_line_buf.clear(); + for (int i = 0; i < TEX_MAX; i++) + m_tile_buf[i].clear(); + m_font_buf.clear(); + + m_more.clear(); + + for (unsigned int i = 0; i < m_entries.size(); i++) + m_entries[i].valid = false; + + m_mouse_idx = -1; +} + +void MenuRegion::set_entry(int idx, const std::string &str, int colour, + const MenuEntry *me) +{ + if (idx >= (int)m_entries.size()) + { + int new_size = m_entries.size(); + while (idx >= new_size) + new_size *= 2; + m_entries.resize(new_size); + + // Quiet valgrind warning about unitialized memory. + for (int i = idx + 1; i < new_size; i++) + m_entries[i].valid = false; + } + + MenuRegionEntry &e = m_entries[idx]; + e.valid = true; + e.text.clear(); + e.text.textcolor(colour); + e.text += formatted_string::parse_string(str); + + e.heading = (me->level == MEL_TITLE || me->level == MEL_SUBTITLE); + e.selected = me->selected(); + e.key = me->hotkeys.size() > 0 ? me->hotkeys[0] : 0; + e.sx = e.sy = e.ex = e.ey = 0; + e.tiles.clear(); + me->get_tiles(e.tiles); + + m_dirty = true; +} + +void MenuRegion::on_resize() +{ + // Probably needed, even though for me nothing went wrong when + // I commented it out. (jpeg) + m_dirty = true; +} + +int MenuRegion::maxpagesize() const +{ + // TODO enne - this is a conservative guess. + // It would be better to make menus use a dynamic number of items per page, + // but it'd require a lot more refactoring of menu.cc to handle that. + + const int lines = count_linebreaks(m_more); + const int more_height = (lines + 1) * m_font_entry->char_height(); + + // Similar to the definition of max_entry_height in place_entries(). + // HACK: Increasing height by 1 to make sure all items actually fit + // on the page, though this introduces a few too many empty lines. + const int div = (Options.tile_menu_icons ? 32 + : m_font_entry->char_height() + 1); + + const int pagesize = ((my - more_height) / div) * m_max_columns; + + // Upper limit for inventory menus. (jpeg) + // Non-inventory menus only have one column and need + // *really* big screens to cover more than 52 lines. + if (pagesize > 52) + return (52); + return (pagesize); +} + +void MenuRegion::set_offset(int lines) +{ + oy = (lines - 1) * m_font_entry->char_height() + 4; + my = wy - oy; +} + +void MenuRegion::set_more(const formatted_string &more) +{ + m_more.clear(); + m_more += more; +#if 0 + // Not needed? (jpeg) + m_dirty = true; +#endif +} + +#endif |