From fb56cbf6072ab4988e1fa334e2a35a51f1274958 Mon Sep 17 00:00:00 2001 From: Nat Quayle Nelson Date: Thu, 29 May 2025 17:04:11 -0500 Subject: [PATCH] Editor search field for terrains, monsters, items in palette --- src/dialogxml/dialogs/dialog.cpp | 158 +++++++++++++++------------- src/dialogxml/dialogs/dialog.hpp | 3 + src/dialogxml/widgets/control.cpp | 5 + src/dialogxml/widgets/control.hpp | 1 + src/dialogxml/widgets/field.cpp | 60 +++++++++++ src/dialogxml/widgets/field.hpp | 7 +- src/dialogxml/widgets/scrollbar.cpp | 6 -- src/dialogxml/widgets/scrollbar.hpp | 1 - src/global.hpp | 2 +- src/scenedit/scen.graphics.cpp | 116 +++++++++++++------- src/scenedit/scen.main.cpp | 22 ++++ 11 files changed, 262 insertions(+), 119 deletions(-) diff --git a/src/dialogxml/dialogs/dialog.cpp b/src/dialogxml/dialogs/dialog.cpp index c827f17f..74773409 100644 --- a/src/dialogxml/dialogs/dialog.cpp +++ b/src/dialogxml/dialogs/dialog.cpp @@ -646,89 +646,99 @@ void cDialog::stackWindowsCorrectly() { } } -// This method handles one event received by the dialog. -void cDialog::handle_one_event(const sf::Event& currentEvent, cFramerateLimiter& fps_limiter) { +cKey translate_sfml_key(sf::Event::KeyEvent key_event) { using Key = sf::Keyboard::Key; cKey key; + switch(key_event.code){ + case Key::Up: + key.spec = true; + key.k = key_up; + break; + case Key::Right: + key.spec = true; + key.k = key_right; + break; + case Key::Left: + key.spec = true; + key.k = key_left; + break; + case Key::Down: + key.spec = true; + key.k = key_down; + break; + case Key::Escape: + key.spec = true; + key.k = key_esc; + break; + case Key::Return: // TODO: Also enter (keypad) + key.spec = true; + key.k = key_enter; + break; + case Key::BackSpace: + key.spec = true; + key.k = key_bsp; + break; + case Key::Delete: + key.spec = true; + key.k = key_del; + break; + case Key::Tab: + key.spec = true; + key.k = key_tab; + break; + case Key::Insert: + key.spec = true; + key.k = key_insert; + break; + case Key::F1: + key.spec = true; + key.k = key_help; + break; + case Key::Home: + key.spec = true; + key.k = key_home; + break; + case Key::End: + key.spec = true; + key.k = key_end; + break; + case Key::PageUp: + key.spec = true; + key.k = key_pgup; + break; + case Key::PageDown: + key.spec = true; + key.k = key_pgdn; + break; + default: + key.spec = false; + key.c = keyToChar(key_event.code, false); + break; + } + key.mod = mod_none; + if(key_event.*systemKey) + key.mod += mod_ctrl; + if(key_event.shift) key.mod += mod_shift; + if(key_event.alt) key.mod += mod_alt; + return key; +} + +// This method handles one event received by the dialog. +void cDialog::handle_one_event(const sf::Event& currentEvent, cFramerateLimiter& fps_limiter) { + // HACK: This needs to be stored between consecutive invocations of this function static cKey pendingKey = {true}; std::string itemHit = ""; location where; - + cKey key; switch(currentEvent.type) { case sf::Event::KeyPressed: - switch(currentEvent.key.code){ - case Key::Up: - key.spec = true; - key.k = key_up; - break; - case Key::Right: - key.spec = true; - key.k = key_right; - break; - case Key::Left: - key.spec = true; - key.k = key_left; - break; - case Key::Down: - key.spec = true; - key.k = key_down; - break; - case Key::Escape: - key.spec = true; - key.k = key_esc; - break; - case Key::Return: // TODO: Also enter (keypad) - key.spec = true; - key.k = key_enter; - break; - case Key::BackSpace: - key.spec = true; - key.k = key_bsp; - break; - case Key::Delete: - key.spec = true; - key.k = key_del; - break; - case Key::Tab: - key.spec = true; - key.k = key_tab; - break; - case Key::Insert: - key.spec = true; - key.k = key_insert; - break; - case Key::F1: - key.spec = true; - key.k = key_help; - break; - case Key::Home: - key.spec = true; - key.k = key_home; - break; - case Key::End: - key.spec = true; - key.k = key_end; - break; - case Key::PageUp: - key.spec = true; - key.k = key_pgup; - break; - case Key::PageDown: - key.spec = true; - key.k = key_pgdn; - break; - default: - key.spec = false; - key.c = keyToChar(currentEvent.key.code, false); - break; - } - key.mod = mod_none; - if(currentEvent.key.*systemKey) - key.mod += mod_ctrl; - if(currentEvent.key.shift) key.mod += mod_shift; - if(currentEvent.key.alt) key.mod += mod_alt; + key = translate_sfml_key(currentEvent.key); + + // Handles button hotkeys. Note that the event still falls through to text fields. + // It probably shouldn't, because right now we have to be careful not to put a button + // on the same dialog as a field if its hotkey is a typable character. process_keystroke(key); // Now check for focused fields. if(currentFocus.empty()) break; diff --git a/src/dialogxml/dialogs/dialog.hpp b/src/dialogxml/dialogs/dialog.hpp index e1dc6e90..ee09f328 100644 --- a/src/dialogxml/dialogs/dialog.hpp +++ b/src/dialogxml/dialogs/dialog.hpp @@ -13,6 +13,7 @@ /// Dialog-related classes and types. #include +#include #include #include @@ -55,6 +56,8 @@ protected: void increment(); }; +cKey translate_sfml_key(sf::Event::KeyEvent); + /// Defines a fancy dialog box with various controls. class cDialog : public iComponent, public iNameGiver { friend class cDialogIterator; diff --git a/src/dialogxml/widgets/control.cpp b/src/dialogxml/widgets/control.cpp index 416bd1ad..5d16bb15 100644 --- a/src/dialogxml/widgets/control.cpp +++ b/src/dialogxml/widgets/control.cpp @@ -715,3 +715,8 @@ void cControl::restore(storage_t to) { if(to.find("visible") != to.end()) boost::any_cast(to["visible"]) ? show() : hide(); } + +// Translate raw x/y position using the view of the current rendering target +location cControl::translated_location(const sf::Vector2i point) const { + return location { const_cast(this)->getWindow().mapPixelToCoords(point) }; +} \ No newline at end of file diff --git a/src/dialogxml/widgets/control.hpp b/src/dialogxml/widgets/control.hpp index 4adb827d..8502447b 100644 --- a/src/dialogxml/widgets/control.hpp +++ b/src/dialogxml/widgets/control.hpp @@ -493,6 +493,7 @@ protected: /// Plays the proper sound for this control being clicked on void playClickSound(); static std::string generateRandomString(); + location translated_location(const sf::Vector2i) const; private: friend class cDialog; // This is so it can access parseColour and anchor friend class cContainer; // This is so it can access anchor diff --git a/src/dialogxml/widgets/field.cpp b/src/dialogxml/widgets/field.cpp index f10fc9df..6f18e3bf 100644 --- a/src/dialogxml/widgets/field.cpp +++ b/src/dialogxml/widgets/field.cpp @@ -139,6 +139,66 @@ void cTextField::replay_selection(ticpp::Element& next_action) { redraw(); } +// Parentless text field handle input +bool cTextField::handle_event(const sf::Event& event) { + // Not visible -> not interested + if(!this->isVisible()) + return false; + + static cKey pendingKey; + + switch(event.type) { + case sf::Event::MouseButtonPressed: + return this->handle_mouse_pressed(event); + case sf::Event::KeyPressed: + return this->handle_key_pressed(event, pendingKey); + case sf::Event::TextEntered: + if(!pendingKey.spec && haveFocus) { + pendingKey.c = event.text.unicode; + if(pendingKey.c != '\t') + handleInput(pendingKey, true); + } + break; + default: break; + } + + return false; +} + +bool cTextField::handle_key_pressed(const sf::Event& event, cKey& pendingKey) { + if(haveFocus){ + cKey key = translate_sfml_key(event.key); + // TODO if multiple parentless fields ever exist, tab order will need to be handled + + // If it's a character key, and the system key (control/command) is not pressed, + // we have an upcoming TextEntered event which contains more information. + // Otherwise, handle it right away. But never handle enter or escape. + if((key.spec && key.k != key_enter && key.k != key_esc) || mod_contains(key.mod, mod_ctrl)) + handleInput(key, true); + pendingKey = key; + return true; + } + return false; +} + +// Parentless text field toggle focus on click +bool cTextField::handle_mouse_pressed(const sf::Event& event) { + location event_location = this->translated_location({ + event.mouseButton.x, + event.mouseButton.y + }); + + bool in_bounds = event_location.in(this->getBounds()); + // TODO if multiple parentless fields ever exist, focus must be taken from the other one here + haveFocus = in_bounds; + insertionPoint = 0; + if(haveFocus){ + static cFramerateLimiter fps_limiter; + handleClick(event_location, fps_limiter); + } + return in_bounds; +} + bool cTextField::handleClick(location clickLoc, cFramerateLimiter& fps_limiter) { if(!haveFocus && getDialog() && !getDialog()->setFocus(this)) return true; haveFocus = true; diff --git a/src/dialogxml/widgets/field.hpp b/src/dialogxml/widgets/field.hpp index 30eeb7be..c2c52e37 100644 --- a/src/dialogxml/widgets/field.hpp +++ b/src/dialogxml/widgets/field.hpp @@ -16,6 +16,8 @@ #include "control.hpp" #include "gfx/render_text.hpp" #include "tools/undo.hpp" +#include "tools/drawable.hpp" +#include "tools/event_listener.hpp" /// The field's expected input type. enum eFldType { @@ -31,7 +33,7 @@ enum eFldType { /// (If there's a current selection, the mobile end of the selection is kept in view.) /// Mouse support is currently nonexistent, except for focusing when clicked. /// There is no Unicode support. -class cTextField : public cControl { +class cTextField : public cControl, public iEventListener, public iDrawable { public: bool parseAttribute(ticpp::Attribute& attr, std::string tagName, std::string fname) override; bool parseContent(ticpp::Node& content, int n, std::string tagName, std::string fname, std::string& text) override; @@ -43,6 +45,9 @@ public: return {EVT_FOCUS, EVT_DEFOCUS}; } bool handleClick(location where, cFramerateLimiter& fps_limiter) override; + bool handle_event(const sf::Event&) override; + bool handle_mouse_pressed(const sf::Event&); + bool handle_key_pressed(const sf::Event&, cKey& pendingKey); void setText(std::string to) override; storage_t store() const override; void restore(storage_t to) override; diff --git a/src/dialogxml/widgets/scrollbar.cpp b/src/dialogxml/widgets/scrollbar.cpp index cc196682..9397b9bf 100644 --- a/src/dialogxml/widgets/scrollbar.cpp +++ b/src/dialogxml/widgets/scrollbar.cpp @@ -111,12 +111,6 @@ eScrollStyle cScrollbar::getStyle() const { return style; } -// TODO: centralize this translation somewhere -// Translate raw x/y position using the view of the current rendering target -location cScrollbar::translated_location(const sf::Vector2i point) const { - return location { const_cast(this)->getWindow().mapPixelToCoords(point) }; -} - bool cScrollbar::handle_event(const sf::Event& event) { // Not visible -> not interested if(!this->isVisible()) diff --git a/src/dialogxml/widgets/scrollbar.hpp b/src/dialogxml/widgets/scrollbar.hpp index 0b1fb87d..344cc1fe 100644 --- a/src/dialogxml/widgets/scrollbar.hpp +++ b/src/dialogxml/widgets/scrollbar.hpp @@ -53,7 +53,6 @@ class cScrollbar : public cControl, public iEventListener, public iDrawable { // in the inventory area). rectangle wheel_event_rect {0, 0, 0, 0}; void draw_vertical(), draw_horizontal(); - location translated_location(const sf::Vector2i) const; eScrollbarPart location_to_part(const location& location) const; location mouse_pressed_at; int drag_start_position; diff --git a/src/global.hpp b/src/global.hpp index f4fbde43..ed36db29 100644 --- a/src/global.hpp +++ b/src/global.hpp @@ -29,7 +29,7 @@ const char* oboeVersionString(); // Window Resolutions const short boe_width = 605, boe_height = 430; const short pc_width = 590, pc_height = 440; -const short scen_width = 584, scen_height = 420; +const short scen_width = 584, scen_height = 435; // A convenient alias namespace boost { namespace filesystem {} namespace process {}} diff --git a/src/scenedit/scen.graphics.cpp b/src/scenedit/scen.graphics.cpp index 6a02f339..d40823e6 100644 --- a/src/scenedit/scen.graphics.cpp +++ b/src/scenedit/scen.graphics.cpp @@ -18,6 +18,8 @@ #include "tools/cursors.hpp" #include "tools/winutil.hpp" #include +#include +#include "dialogxml/widgets/field.hpp" #include "dialogxml/dialogs/dialog.hpp" @@ -54,6 +56,8 @@ extern sf::Texture bg_gworld; extern rectangle right_buttons[NRSONPAGE]; extern rectangle right_scrollbar_rect; extern std::shared_ptr right_sbar, pal_sbar; +extern std::shared_ptr palette_search_field; +extern rectangle search_field_text_rect; extern boost::variant, cTownperson, cTown::cItem, vector2d> clipboard; extern bool left_buttons_active,right_buttons_active; @@ -439,6 +443,11 @@ void draw_main_screen() { if((overall_mode < MODE_MAIN_SCREEN) || (overall_mode == MODE_EDIT_TYPES)) { place_location(); set_up_terrain_buttons(false); + TextStyle style; + win_draw_string(mainPtr(), search_field_text_rect, "Search:", eTextMode::WRAP, style); + palette_search_field->show(); + }else{ + palette_search_field->hide(); } @@ -540,31 +549,46 @@ void set_up_terrain_buttons(bool reset) { int first = pal_sbar->getPosition() * 16; if(draw_mode == DRAW_MONST) first++, max++; int end = min(first + 256, max); + + std::string search_query = palette_search_field->getText(); + boost::algorithm::to_lower(search_query); + boost::algorithm::trim(search_query); + + // How transparent to make non-matching elements in the palette + static const sf::Uint8 FILTER_ALPHA = 255 / 8; // first make terrain buttons sf::Texture& editor_mixed = *ResMgr::graphics.get("edbuttons"); for(short i = first; i < end; i++) { + sf::Color colour = Colours::WHITE; + sf::Color frame_colour = Colours::BLACK; rectangle draw_rect = terrain_rects[i - first]; draw_rect.offset(RIGHT_AREA_UL_X, RIGHT_AREA_UL_Y); switch(draw_mode){ - case DRAW_TERRAIN: + case DRAW_TERRAIN:{ if(i == scenario.ter_types.size()) { rect_draw_some_item(editor_mixed, ter_plus_from, mainPtr(), draw_rect); break; } + const cTerrain& ter = scenario.ter_types[i]; + + std::string name = ter.name; + boost::algorithm::to_lower(name); + if(!search_query.empty() && name.find(search_query) == std::string::npos) colour.a = FILTER_ALPHA; + ter_from = ter_from_base; - pic = scenario.ter_types[i].picture; + pic = ter.picture; if(pic >= 1000) { std::shared_ptr source_gworld; graf_pos_ref(source_gworld, ter_from) = spec_scen_g.find_graphic(pic % 1000); - rect_draw_some_item(*source_gworld, ter_from, mainPtr(), draw_rect); + rect_draw_some_item(*source_gworld, ter_from, mainPtr(), draw_rect, sf::BlendAlpha, colour); } else if(pic < 960) { pic = pic % 50; ter_from.offset(28 * (pic % 10), 36 * (pic / 10)); - int which_sheet = scenario.ter_types[i].picture / 50; + int which_sheet = ter.picture / 50; rect_draw_some_item(*ResMgr::graphics.get("ter" + std::to_string(1 + which_sheet)), - ter_from, mainPtr(), draw_rect); + ter_from, mainPtr(), draw_rect, sf::BlendAlpha, colour); } else { pic = (pic - 560) % 50; @@ -572,7 +596,7 @@ void set_up_terrain_buttons(bool reset) { ter_from.right = ter_from.left + 28; ter_from.top = 36 * (pic % 5); ter_from.bottom = ter_from.top + 36; - rect_draw_some_item(*ResMgr::graphics.get("teranim"), ter_from, mainPtr(), draw_rect); + rect_draw_some_item(*ResMgr::graphics.get("teranim"), ter_from, mainPtr(), draw_rect, sf::BlendAlpha, colour); } small_i = get_small_icon(i); @@ -582,31 +606,39 @@ void set_up_terrain_buttons(bool reset) { tiny_to.top = tiny_to.bottom - 7; tiny_to.left = tiny_to.right - 7; if(small_i >= 0 && small_i < 255) - rect_draw_some_item(editor_mixed, tiny_from, mainPtr(), tiny_to); - break; - case DRAW_MONST: - pic = scenario.scen_monsters[i].picture_num; + rect_draw_some_item(editor_mixed, tiny_from, mainPtr(), tiny_to, sf::BlendAlpha, colour); + }break; + case DRAW_MONST:{ + const cMonster& monst = scenario.scen_monsters[i]; + + std::string name = monst.m_name; + boost::algorithm::to_lower(name); + if(!search_query.empty() && name.find(search_query) == std::string::npos){ + colour.a = frame_colour.a = FILTER_ALPHA; + } + + pic = monst.picture_num; tiny_to = draw_rect; - frame_rect(mainPtr(), tiny_to, sf::Color::Black); + frame_rect(mainPtr(), tiny_to, frame_colour); if(pic >= 4000) { pic %= 1000; tiny_to.width() = tiny_to.width() / 2; tiny_to.height() = tiny_to.height() / 2; std::shared_ptr source_gworld; graf_pos_ref(source_gworld, ter_from) = spec_scen_g.find_graphic(pic); - rect_draw_some_item(*source_gworld, ter_from, mainPtr(), tiny_to, sf::BlendAlpha); + rect_draw_some_item(*source_gworld, ter_from, mainPtr(), tiny_to, sf::BlendAlpha, colour); pic++; tiny_to.offset(tiny_to.width(), 0); graf_pos_ref(source_gworld, ter_from) = spec_scen_g.find_graphic(pic); - rect_draw_some_item(*source_gworld, ter_from, mainPtr(), tiny_to, sf::BlendAlpha); + rect_draw_some_item(*source_gworld, ter_from, mainPtr(), tiny_to, sf::BlendAlpha, colour); pic++; tiny_to.offset(-tiny_to.width(), tiny_to.height()); graf_pos_ref(source_gworld, ter_from) = spec_scen_g.find_graphic(pic); - rect_draw_some_item(*source_gworld, ter_from, mainPtr(), tiny_to, sf::BlendAlpha); + rect_draw_some_item(*source_gworld, ter_from, mainPtr(), tiny_to, sf::BlendAlpha, colour); pic++; tiny_to.offset(tiny_to.width(), 0); graf_pos_ref(source_gworld, ter_from) = spec_scen_g.find_graphic(pic); - rect_draw_some_item(*source_gworld, ter_from, mainPtr(), tiny_to, sf::BlendAlpha); + rect_draw_some_item(*source_gworld, ter_from, mainPtr(), tiny_to, sf::BlendAlpha, colour); } else if(pic >= 3000) { pic %= 1000; tiny_to.width() = tiny_to.width() / 2; @@ -614,11 +646,11 @@ void set_up_terrain_buttons(bool reset) { tiny_to.offset(tiny_to.width() / 2, 0); std::shared_ptr source_gworld; graf_pos_ref(source_gworld, ter_from) = spec_scen_g.find_graphic(pic); - rect_draw_some_item(*source_gworld, ter_from, mainPtr(), tiny_to, sf::BlendAlpha); + rect_draw_some_item(*source_gworld, ter_from, mainPtr(), tiny_to, sf::BlendAlpha, colour); pic++; tiny_to.offset(0, tiny_to.height()); graf_pos_ref(source_gworld, ter_from) = spec_scen_g.find_graphic(pic); - rect_draw_some_item(*source_gworld, ter_from, mainPtr(), tiny_to, sf::BlendAlpha); + rect_draw_some_item(*source_gworld, ter_from, mainPtr(), tiny_to, sf::BlendAlpha, colour); } else if(pic >= 2000) { pic %= 1000; tiny_to.width() = tiny_to.width() / 2; @@ -626,16 +658,16 @@ void set_up_terrain_buttons(bool reset) { tiny_to.offset(0, tiny_to.height() / 2); std::shared_ptr source_gworld; graf_pos_ref(source_gworld, ter_from) = spec_scen_g.find_graphic(pic); - rect_draw_some_item(*source_gworld, ter_from, mainPtr(), tiny_to, sf::BlendAlpha); + rect_draw_some_item(*source_gworld, ter_from, mainPtr(), tiny_to, sf::BlendAlpha, colour); pic++; tiny_to.offset(tiny_to.width(), 0); graf_pos_ref(source_gworld, ter_from) = spec_scen_g.find_graphic(pic); - rect_draw_some_item(*source_gworld, ter_from, mainPtr(), tiny_to, sf::BlendAlpha); + rect_draw_some_item(*source_gworld, ter_from, mainPtr(), tiny_to, sf::BlendAlpha, colour); } else if(pic >= 1000) { pic %= 1000; std::shared_ptr source_gworld; graf_pos_ref(source_gworld, ter_from) = spec_scen_g.find_graphic(pic); - rect_draw_some_item(*source_gworld, ter_from, mainPtr(), tiny_to, sf::BlendAlpha); + rect_draw_some_item(*source_gworld, ter_from, mainPtr(), tiny_to, sf::BlendAlpha, colour); } else { auto pic_info = m_pic_index[pic]; pic = pic_info.i; @@ -646,59 +678,71 @@ void set_up_terrain_buttons(bool reset) { tiny_to.width() = tiny_to.width() / 2; tiny_to.height() = tiny_to.height() / 2; ter_from = calc_rect(2 * ((pic % 20) / 10), (pic % 20) % 10); - rect_draw_some_item(monst_gworld(pic / 20), ter_from, mainPtr(), tiny_to, sf::BlendAlpha); + rect_draw_some_item(monst_gworld(pic / 20), ter_from, mainPtr(), tiny_to, sf::BlendAlpha, colour); pic++; tiny_to.offset(tiny_to.width(), 0); ter_from = calc_rect(2 * ((pic % 20) / 10), (pic % 20) % 10); - rect_draw_some_item(monst_gworld(pic / 20), ter_from, mainPtr(), tiny_to, sf::BlendAlpha); + rect_draw_some_item(monst_gworld(pic / 20), ter_from, mainPtr(), tiny_to, sf::BlendAlpha, colour); pic++; tiny_to.offset(-tiny_to.width(), tiny_to.height()); ter_from = calc_rect(2 * ((pic % 20) / 10), (pic % 20) % 10); - rect_draw_some_item(monst_gworld(pic / 20), ter_from, mainPtr(), tiny_to, sf::BlendAlpha); + rect_draw_some_item(monst_gworld(pic / 20), ter_from, mainPtr(), tiny_to, sf::BlendAlpha, colour); pic++; tiny_to.offset(tiny_to.width(), 0); ter_from = calc_rect(2 * ((pic % 20) / 10), (pic % 20) % 10); - rect_draw_some_item(monst_gworld(pic / 20), ter_from, mainPtr(), tiny_to, sf::BlendAlpha); + rect_draw_some_item(monst_gworld(pic / 20), ter_from, mainPtr(), tiny_to, sf::BlendAlpha, colour); } else if(pic_info.y == 2) { tiny_to.width() = tiny_to.width() / 2; tiny_to.height() = tiny_to.height() / 2; tiny_to.offset(tiny_to.width() / 2, 0); ter_from = calc_rect(2 * ((pic % 20) / 10), (pic % 20) % 10); - rect_draw_some_item(monst_gworld(pic / 20), ter_from, mainPtr(), tiny_to, sf::BlendAlpha); + rect_draw_some_item(monst_gworld(pic / 20), ter_from, mainPtr(), tiny_to, sf::BlendAlpha, colour); pic++; tiny_to.offset(0, tiny_to.height()); ter_from = calc_rect(2 * ((pic % 20) / 10), (pic % 20) % 10); - rect_draw_some_item(monst_gworld(pic / 20), ter_from, mainPtr(), tiny_to, sf::BlendAlpha); + rect_draw_some_item(monst_gworld(pic / 20), ter_from, mainPtr(), tiny_to, sf::BlendAlpha, colour); } else if(pic_info.x == 2) { tiny_to.width() = tiny_to.width() / 2; tiny_to.height() = tiny_to.height() / 2; tiny_to.offset(0, tiny_to.height() / 2); ter_from = calc_rect(2 * ((pic % 20) / 10), (pic % 20) % 10); - rect_draw_some_item(monst_gworld(pic / 20), ter_from, mainPtr(), tiny_to, sf::BlendAlpha); + rect_draw_some_item(monst_gworld(pic / 20), ter_from, mainPtr(), tiny_to, sf::BlendAlpha, colour); pic++; tiny_to.offset(tiny_to.width(), 0); ter_from = calc_rect(2 * ((pic % 20) / 10), (pic % 20) % 10); - rect_draw_some_item(monst_gworld(pic / 20), ter_from, mainPtr(), tiny_to, sf::BlendAlpha); + rect_draw_some_item(monst_gworld(pic / 20), ter_from, mainPtr(), tiny_to, sf::BlendAlpha, colour); } else { ter_from = calc_rect(2 * ((pic % 20) / 10), (pic % 20) % 10); - rect_draw_some_item(monst_gworld(pic / 20), ter_from, mainPtr(), tiny_to, sf::BlendAlpha); + rect_draw_some_item(monst_gworld(pic / 20), ter_from, mainPtr(), tiny_to, sf::BlendAlpha, colour); } } - break; - case DRAW_ITEM: - pic = scenario.scen_items[i].graphic_num; + }break; + case DRAW_ITEM:{ + const cItem& item = scenario.scen_items[i]; + pic = item.graphic_num; + + std::string fname = item.full_name; + boost::algorithm::to_lower(fname); + // Maybe a designer will want to search for the unidentified name of a cursed item? + std::string name = item.name; + boost::algorithm::to_lower(name); + + if(!search_query.empty() && fname.find(search_query) == std::string::npos && name.find(search_query) == std::string::npos){ + colour.a = frame_colour.a = FILTER_ALPHA; + } + tiny_to = draw_rect; - frame_rect(mainPtr(), tiny_to, sf::Color::Black); + frame_rect(mainPtr(), tiny_to, frame_colour); if(pic >= 1000) { std::shared_ptr source_gworld; graf_pos_ref(source_gworld, ter_from) = spec_scen_g.find_graphic(pic % 1000); - rect_draw_some_item(*source_gworld, ter_from, mainPtr(), tiny_to, sf::BlendAlpha); + rect_draw_some_item(*source_gworld, ter_from, mainPtr(), tiny_to, sf::BlendAlpha, colour); } else { tiny_from = {0,0,18,18}; tiny_from.offset((pic % 10) * 18,(pic / 10) * 18); - rect_draw_some_item(*ResMgr::graphics.get("tinyobj"), tiny_from, mainPtr(), tiny_to, sf::BlendAlpha); + rect_draw_some_item(*ResMgr::graphics.get("tinyobj"), tiny_from, mainPtr(), tiny_to, sf::BlendAlpha, colour); } - break; + }break; } } diff --git a/src/scenedit/scen.main.cpp b/src/scenedit/scen.main.cpp index 98200055..0d4c9ebe 100644 --- a/src/scenedit/scen.main.cpp +++ b/src/scenedit/scen.main.cpp @@ -59,6 +59,7 @@ short cur_viewing_mode = 0; short cen_x, cen_y; eScenMode overall_mode = MODE_INTRO_SCREEN; std::shared_ptr right_sbar, pal_sbar; +std::shared_ptr palette_search_field; short mode_count = 0; short right_button_hovered = -1; @@ -91,6 +92,8 @@ void save_prefs(); cScenario scenario; rectangle right_sbar_rect; extern rectangle terrain_buttons_rect; +rectangle search_field_text_rect; +rectangle search_field_rect; extern void set_up_apple_events(); @@ -245,6 +248,24 @@ static void init_scrollbars() { init_sbar(pal_sbar, "pal_sbar", pal_sbar_rect, pal_sbar_event_rect, 16); } +static void init_search_field() { + search_field_text_rect.top = RIGHT_AREA_UL_Y + RIGHT_AREA_HEIGHT + 16; + search_field_text_rect.bottom = search_field_text_rect.top + 12; + search_field_text_rect.left = RIGHT_AREA_UL_X + 5; + TextStyle style; + search_field_text_rect.right = search_field_text_rect.left + string_length("Search: ", style); + search_field_rect = search_field_text_rect; + search_field_rect.offset({search_field_text_rect.width() + 5, -2}); + search_field_rect.width() = RIGHT_AREA_WIDTH / 2; + + static cParentless mainWin(mainPtr()); + palette_search_field.reset(new cTextField(mainWin)); + palette_search_field->setBounds(search_field_rect); + palette_search_field->show(); + drawable_mgr.add_drawable(UI_LAYER_DEFAULT, "search_field", palette_search_field); + event_listeners["search_field"] = std::dynamic_pointer_cast(palette_search_field); +} + sf::FloatRect compute_viewport(const sf::RenderWindow& mainPtr, float ui_scale) { // See compute_viewport() in boe.graphics.cpp @@ -340,6 +361,7 @@ void init_scened(int argc, char* argv[]) { cen_y = 18; init_scrollbars(); + init_search_field(); init_lb(); init_rb();