Editor search field for terrains, monsters, items in palette

This commit is contained in:
2025-05-29 17:04:11 -05:00
parent 73f171b3ec
commit fb56cbf607
11 changed files with 262 additions and 119 deletions

View File

@@ -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;

View File

@@ -13,6 +13,7 @@
/// Dialog-related classes and types.
#include <SFML/Graphics.hpp>
#include <SFML/Window/Event.hpp>
#include <string>
#include <map>
@@ -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;

View File

@@ -715,3 +715,8 @@ void cControl::restore(storage_t to) {
if(to.find("visible") != to.end())
boost::any_cast<bool>(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<cControl*>(this)->getWindow().mapPixelToCoords(point) };
}

View File

@@ -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

View File

@@ -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;

View File

@@ -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;

View File

@@ -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<cScrollbar*>(this)->getWindow().mapPixelToCoords(point) };
}
bool cScrollbar::handle_event(const sf::Event& event) {
// Not visible -> not interested
if(!this->isVisible())

View File

@@ -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;