Files
oboe/src/dialogxml/widgets/field.hpp

131 lines
4.4 KiB
C++

/*
* field.h
* BoE
*
* Created by Celtic Minstrel on 11/05/09.
*
*/
#ifndef FIELD_H
#define FIELD_H
/// @file
/// Field-related classes and types.
#include <string>
#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 {
FLD_INT, ///< A field that accepts only integers.
FLD_UINT, ///< A field that accepts only positive integers.
FLD_REAL, ///< A field that accepts any real (floating-point) number.
FLD_TEXT, ///< A field that accepts any text. This is the default.
};
/// An editable text field.
/// The text field supports multiline input and text selection.
/// It automatically scrolls to keep the insertion point in view.
/// (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, 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;
/// For text fields, this is triggered when it loses or gains the input focus.
/// @copydoc cControl::getSupportedHandlers
///
/// @todo Document possible handlers
std::set<eDlogEvt> getSupportedHandlers() const override {
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;
/// Get the current input type of the field.
/// @return The input type.
eFldType getInputType();
/// Set the input type of the field.
/// @param newType The new input type.
void setInputType(eFldType newType);
/// Create a new editable text field.
/// @param parent The parent.
explicit cTextField(iComponent& parent);
bool isClickable() const override;
bool isFocusable() const override;
bool isScrollable() const override;
virtual ~cTextField();
void draw() override;
/// Check if this text field currently has input focus.
/// @return true if it it is currently focused.
bool hasFocus() const;
/// Handle keyboard input.
/// @param key The keypress to handle.
void handleInput(cKey key, bool record = false);
cTextField& operator=(cTextField& other) = delete;
cTextField(cTextField& other) = delete;
/// This field is only used by cDialog during the loading process. Changing it will have no effect.
long tabOrder = 0;
void replay_selection(ticpp::Element& next_action);
private:
void callHandler(event_fcn<EVT_FOCUS>::type onFocus, cDialog& me, std::string id) override;
bool callHandler(event_fcn<EVT_DEFOCUS>::type onFocus, cDialog& me, std::string id) override;
bool manageFormat(eFormat prop, bool set, boost::any* val) override;
void set_ip(location clickLoc, int cTextField::* insertionPoint);
void record_selection();
cUndoList history;
action_ptr current_action;
eFldType field_type;
bool haveFocus;
int insertionPoint;
int selectionPoint;
sf::Color color;
bool ip_visible;
sf::Clock ip_timer, hist_timer, click_timer;
bool changeMade = true;
rectangle text_rect;
std::vector<snippet_t> snippets;
int ip_row, ip_col;
/// Setting maxChars AFTER the player has a chance to type in the field would be a bad idea.
/// So would calling setText() with a string longer than maxChars.
/// Really, it should probably only be set in xml, as the attribute "max-chars".
int maxChars = -1;
friend class aTextInsert;
friend class aTextDelete;
};
class aTextInsert : public cAction {
cTextField& in;
int at;
std::string text;
bool undo_me() override, redo_me() override;
public:
aTextInsert(cTextField& in, int at, std::string text = "");
void append(char c);
~aTextInsert() {}
};
class aTextDelete : public cAction {
cTextField& in;
int start, end, ip;
std::string text;
bool undo_me() override, redo_me() override;
public:
aTextDelete(cTextField& in, int start, int end);
aTextDelete(cTextField& in, int start, std::string content, bool from_start);
void append_front(char c);
void append_back(char c);
~aTextDelete() {}
};
#endif