X-Git-Url: https://git.lizzy.rs/?a=blobdiff_plain;f=src%2FguiTable.cpp;h=a2738afa9dac4d1f2d222a05a83a8bb85f8ea6ee;hb=9f3a5859378ac01648ca0caf01b04ad57c871baa;hp=4d6fc195072add988769a3601c1cfa41512eee09;hpb=e81454fb387cd98b4a63ade83a9eb41f1bdca278;p=minetest.git diff --git a/src/guiTable.cpp b/src/guiTable.cpp index 4d6fc1950..a2738afa9 100644 --- a/src/guiTable.cpp +++ b/src/guiTable.cpp @@ -22,17 +22,21 @@ with this program; if not, write to the Free Software Foundation, Inc., #include #include #include -#include +#include #include #include #include +#include "client/renderingengine.h" #include "debug.h" #include "log.h" -#include "tile.h" +#include "client/tile.h" #include "gettime.h" #include "util/string.h" #include "util/numeric.h" -#include "guiFormSpecMenu.h" // for parseColor() +#include "util/string.h" // for parseColorString() +#include "settings.h" // for settings +#include "porting.h" // for dpi +#include "guiscalingfilter.h" /* GUITable @@ -44,22 +48,7 @@ GUITable::GUITable(gui::IGUIEnvironment *env, ISimpleTextureSource *tsrc ): gui::IGUIElement(gui::EGUIET_ELEMENT, env, parent, id, rectangle), - m_tsrc(tsrc), - m_is_textlist(false), - m_has_tree_column(false), - m_selected(-1), - m_sel_column(0), - m_sel_doubleclick(false), - m_keynav_time(0), - m_keynav_buffer(L""), - m_border(true), - m_color(255, 255, 255, 255), - m_background(255, 0, 0, 0), - m_highlight(255, 70, 100, 50), - m_highlight_text(255, 255, 255, 255), - m_rowheight(1), - m_font(NULL), - m_scrollbar(NULL) + m_tsrc(tsrc) { assert(tsrc != NULL); @@ -89,16 +78,25 @@ GUITable::GUITable(gui::IGUIEnvironment *env, setTabStop(true); setTabOrder(-1); updateAbsolutePosition(); + + core::rect relative_rect = m_scrollbar->getRelativePosition(); + s32 width = (relative_rect.getWidth()/(2.0/3.0)) * + RenderingEngine::getDisplayDensity() * + g_settings->getFloat("gui_scaling"); + m_scrollbar->setRelativePosition(core::rect( + relative_rect.LowerRightCorner.X-width,relative_rect.UpperLeftCorner.Y, + relative_rect.LowerRightCorner.X,relative_rect.LowerRightCorner.Y + )); } GUITable::~GUITable() { - for (size_t i = 0; i < m_rows.size(); ++i) - delete[] m_rows[i].cells; + for (GUITable::Row &row : m_rows) + delete[] row.cells; if (m_font) m_font->drop(); - + m_scrollbar->remove(); } @@ -107,9 +105,9 @@ GUITable::Option GUITable::splitOption(const std::string &str) size_t equal_pos = str.find('='); if (equal_pos == std::string::npos) return GUITable::Option(str, ""); - else - return GUITable::Option(str.substr(0, equal_pos), - str.substr(equal_pos + 1)); + + return GUITable::Option(str.substr(0, equal_pos), + str.substr(equal_pos + 1)); } void GUITable::setTextList(const std::vector &content, @@ -153,7 +151,7 @@ void GUITable::setTextList(const std::vector &content, cell->content_index = allocString(s.substr(2)); } else if (s[0] == '#' && s.size() >= 7 && - GUIFormSpecMenu::parseColor( + parseColorString( s.substr(0,7), cell->color, false)) { // single # for color cell->color_defined = true; @@ -183,22 +181,32 @@ void GUITable::setTable(const TableOptions &options, // j is always a column index, 0-based // k is another index, for example an option index + // Handle a stupid error case... (issue #1187) + if (columns.empty()) { + TableColumn text_column; + text_column.type = "text"; + TableColumns new_columns; + new_columns.push_back(text_column); + setTable(options, new_columns, content); + return; + } + // Handle table options video::SColor default_color(255, 255, 255, 255); s32 opendepth = 0; - for (size_t k = 0; k < options.size(); ++k) { - const std::string &name = options[k].name; - const std::string &value = options[k].value; + for (const Option &option : options) { + const std::string &name = option.name; + const std::string &value = option.value; if (name == "color") - GUIFormSpecMenu::parseColor(value, m_color, false); + parseColorString(value, m_color, false); else if (name == "background") - GUIFormSpecMenu::parseColor(value, m_background, false); + parseColorString(value, m_background, false); else if (name == "border") m_border = is_yes(value); else if (name == "highlight") - GUIFormSpecMenu::parseColor(value, m_highlight, false); + parseColorString(value, m_highlight, false); else if (name == "highlight_text") - GUIFormSpecMenu::parseColor(value, m_highlight_text, false); + parseColorString(value, m_highlight_text, false); else if (name == "opendepth") opendepth = stoi(value); else @@ -216,7 +224,7 @@ void GUITable::setTable(const TableOptions &options, // Append empty strings to content if there is an incomplete row s32 cellcount = rowcount * colcount; while (content.size() < (u32) cellcount) - content.push_back(""); + content.emplace_back(""); // Create temporary rows (for processing columns) struct TempRow { @@ -281,9 +289,9 @@ void GUITable::setTable(const TableOptions &options, width = myround(em * 1.5); // default indent width } - for (size_t k = 0; k < columns[j].options.size(); ++k) { - const std::string &name = columns[j].options[k].name; - const std::string &value = columns[j].options[k].value; + for (const Option &option : columns[j].options) { + const std::string &name = option.name; + const std::string &value = option.value; if (name == "padding") padding = myround(stof(value) * em); else if (name == "tooltip") @@ -395,8 +403,8 @@ void GUITable::setTable(const TableOptions &options, else if (columntype == COLUMN_TYPE_COLOR) { for (s32 i = 0; i < rowcount; ++i) { video::SColor cellcolor(255, 255, 255, 255); - if (GUIFormSpecMenu::parseColor(content[i * colcount + j], cellcolor, true)) - rows[i].colors.push_back(std::make_pair(cellcolor, j+span)); + if (parseColorString(content[i * colcount + j], cellcolor, true)) + rows[i].colors.emplace_back(cellcolor, j+span); } } else if (columntype == COLUMN_TYPE_INDENT || @@ -446,7 +454,7 @@ void GUITable::setTable(const TableOptions &options, } if (m_has_tree_column) { - // Treeview: convent tree to indent cells on leaf rows + // Treeview: convert tree to indent cells on leaf rows for (s32 i = 0; i < rowcount; ++i) { if (i == rowcount-1 || m_rows[i].indent >= m_rows[i+1].indent) for (s32 j = 0; j < m_rows[i].cellcount; ++j) @@ -473,8 +481,8 @@ void GUITable::setTable(const TableOptions &options, void GUITable::clear() { // Clean up cells and rows - for (size_t i = 0; i < m_rows.size(); ++i) - delete[] m_rows[i].cells; + for (GUITable::Row &row : m_rows) + delete[] row.cells; m_rows.clear(); m_visible_rows.clear(); @@ -535,24 +543,46 @@ s32 GUITable::getSelected() const void GUITable::setSelected(s32 index) { + s32 old_selected = m_selected; + m_selected = -1; m_sel_column = 0; m_sel_doubleclick = false; - --index; + --index; // Switch from 1-based indexing to 0-based indexing s32 rowcount = m_rows.size(); + if (rowcount == 0 || index < 0) { + return; + } - if (index >= rowcount) + if (index >= rowcount) { index = rowcount - 1; - while (index >= 0 && m_rows[index].visible_index < 0) - --index; + } + + // If the selected row is not visible, open its ancestors to make it visible + bool selection_invisible = m_rows[index].visible_index < 0; + if (selection_invisible) { + std::set opened_trees; + getOpenedTrees(opened_trees); + s32 indent = m_rows[index].indent; + for (s32 j = index - 1; j >= 0; --j) { + if (m_rows[j].indent < indent) { + opened_trees.insert(j); + indent = m_rows[j].indent; + } + } + setOpenedTrees(opened_trees); + } + if (index >= 0) { m_selected = m_rows[index].visible_index; assert(m_selected >= 0 && m_selected < (s32) m_visible_rows.size()); } - autoScroll(); + if (m_selected != old_selected || selection_invisible) { + autoScroll(); + } } GUITable::DynamicData GUITable::getDynamicData() const @@ -575,11 +605,11 @@ void GUITable::setDynamicData(const DynamicData &dyndata) m_keynav_time = dyndata.keynav_time; m_keynav_buffer = dyndata.keynav_buffer; - m_scrollbar->setPos(dyndata.scrollpos); - setSelected(dyndata.selected); m_sel_column = 0; m_sel_doubleclick = false; + + m_scrollbar->setPos(dyndata.scrollpos); } const c8* GUITable::getTypeName() const @@ -617,10 +647,11 @@ void GUITable::draw() client_clip.UpperLeftCorner.Y += 1; client_clip.UpperLeftCorner.X += 1; client_clip.LowerRightCorner.Y -= 1; - client_clip.LowerRightCorner.X -= - m_scrollbar->isVisible() ? - skin->getSize(gui::EGDS_SCROLLBAR_SIZE) : - 1; + client_clip.LowerRightCorner.X -= 1; + if (m_scrollbar->isVisible()) { + client_clip.LowerRightCorner.X = + m_scrollbar->getAbsolutePosition().UpperLeftCorner.X; + } client_clip.clipAgainst(AbsoluteClippingRect); // draw visible rows @@ -764,7 +795,8 @@ bool GUITable::OnEvent(const SEvent &event) return true; } - else if (event.KeyInput.PressedDown && ( + + if (event.KeyInput.PressedDown && ( event.KeyInput.Key == KEY_LEFT || event.KeyInput.Key == KEY_RIGHT)) { // Open/close subtree via keyboard @@ -786,7 +818,7 @@ bool GUITable::OnEvent(const SEvent &event) } else if (event.KeyInput.PressedDown && event.KeyInput.Char) { // change selection based on text as it is typed - s32 now = getTimeMs(); + u64 now = porting::getTimeMs(); if (now - m_keynav_time >= 500) m_keynav_buffer = L""; m_keynav_time = now; @@ -798,7 +830,7 @@ bool GUITable::OnEvent(const SEvent &event) } // find the selected item, starting at the current selection - // dont change selection if the key buffer matches the current item + // don't change selection if the key buffer matches the current item s32 old_selected = m_selected; s32 start = MYMAX(m_selected, 0); s32 rowcount = m_visible_rows.size(); @@ -823,7 +855,7 @@ bool GUITable::OnEvent(const SEvent &event) if (event.MouseInput.Event == EMIE_MOUSE_WHEEL) { m_scrollbar->setPos(m_scrollbar->getPos() + - (event.MouseInput.Wheel < 0 ? -1 : 1) * + (event.MouseInput.Wheel < 0 ? -3 : 3) * - (s32) m_rowheight / 2); return true; } @@ -841,6 +873,14 @@ bool GUITable::OnEvent(const SEvent &event) // Update tooltip setToolTipText(cell ? m_strings[cell->tooltip_index].c_str() : L""); + // Fix for #1567/#1806: + // IGUIScrollBar passes double click events to its parent, + // which we don't want. Detect this case and discard the event + if (event.MouseInput.Event != EMIE_MOUSE_MOVED && + m_scrollbar->isVisible() && + m_scrollbar->isPointInside(p)) + return true; + if (event.MouseInput.isLeftPressed() && (isPointInside(p) || event.MouseInput.Event == EMIE_MOUSE_MOVED)) { @@ -876,6 +916,11 @@ bool GUITable::OnEvent(const SEvent &event) sel_doubleclick) { sendTableEvent(sel_column, sel_doubleclick); } + + // Treeview: double click opens/closes trees + if (m_has_tree_column && sel_doubleclick) { + toggleVisibleTree(m_selected, 0, false); + } } } return true; @@ -899,14 +944,13 @@ s32 GUITable::allocString(const std::string &text) std::map::iterator it = m_alloc_strings.find(text); if (it == m_alloc_strings.end()) { s32 id = m_strings.size(); - std::wstring wtext = narrow_to_wide(text); - m_strings.push_back(core::stringw(wtext.c_str())); + std::wstring wtext = utf8_to_wide(text); + m_strings.emplace_back(wtext.c_str()); m_alloc_strings.insert(std::make_pair(text, id)); return id; } - else { - return it->second; - } + + return it->second; } s32 GUITable::allocImage(const std::string &imagename) @@ -918,9 +962,8 @@ s32 GUITable::allocImage(const std::string &imagename) m_alloc_images.insert(std::make_pair(imagename, id)); return id; } - else { - return it->second; - } + + return it->second; } void GUITable::allocationComplete() @@ -935,8 +978,8 @@ const GUITable::Row* GUITable::getRow(s32 i) const { if (i >= 0 && i < (s32) m_visible_rows.size()) return &m_rows[m_visible_rows[i]]; - else - return NULL; + + return NULL; } bool GUITable::doesRowStartWith(const Row *row, const core::stringw &str) const @@ -972,11 +1015,10 @@ s32 GUITable::getRowAt(s32 y, bool &really_hovering) const really_hovering = true; return i; } - else if (i < 0) + if (i < 0) return 0; - else - return rowcount - 1; + return rowcount - 1; } s32 GUITable::getCellAt(s32 x, s32 row_i) const @@ -996,7 +1038,8 @@ s32 GUITable::getCellAt(s32 x, s32 row_i) const if (rel_x >= cell->xmin && rel_x <= cell->xmax) return pivot; - else if (rel_x < cell->xmin) + + if (rel_x < cell->xmin) jmax = pivot - 1; else jmin = pivot + 1; @@ -1006,8 +1049,8 @@ s32 GUITable::getCellAt(s32 x, s32 row_i) const rel_x >= row->cells[jmin].xmin && rel_x <= row->cells[jmin].xmax) return jmin; - else - return -1; + + return -1; } void GUITable::autoScroll() @@ -1061,7 +1104,9 @@ void GUITable::getOpenedTrees(std::set &opened_trees) const void GUITable::setOpenedTrees(const std::set &opened_trees) { - s32 old_selected = getSelected(); + s32 old_selected = -1; + if (m_selected >= 0) + old_selected = m_visible_rows[m_selected]; std::vector parents; std::vector closed_parents; @@ -1113,7 +1158,9 @@ void GUITable::setOpenedTrees(const std::set &opened_trees) updateScrollBar(); - setSelected(old_selected); + // m_selected must be updated since it is a visible row index + if (old_selected >= 0) + m_selected = m_rows[old_selected].visible_index; } void GUITable::openTree(s32 to_open)