wesnoth/src/gui/widgets/text.hpp
Ignacio R. Morelle db0b20dae7 gui2/ttext_: Refactor cursor timer setup code
This also makes sure the timer id is set to zero after removing the
timer.
2016-10-12 02:27:27 -03:00

493 lines
14 KiB
C++

/*
Copyright (C) 2008 - 2016 by Mark de Wever <koraq@xs4all.nl>
Part of the Battle for Wesnoth Project http://www.wesnoth.org/
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY.
See the COPYING file for more details.
*/
#ifndef GUI_WIDGETS_TEXT_HPP_INCLUDED
#define GUI_WIDGETS_TEXT_HPP_INCLUDED
//#include "gui/core/event/dispatcher.hpp"
#include "gui/widgets/control.hpp"
#include "../../text.hpp" // We want the file in src/
#include <string>
#include "utils/functional.hpp"
namespace gui2
{
/**
* Abstract base class for text items.
*
* All other text classes should inherit from this base class.
*
* The NOTIFY_MODIFIED event is send when the text is modified.
*
* @todo Validate whether the NOTIFY_MODIFIED is always fired properly. The
* current implementation is added for some quick testing so some cases might
* be forgotten.
*
* Common signal handlers:
* - connect_signal_pre_key_press
*/
class ttext_ : public tcontrol
{
public:
ttext_();
~ttext_();
/** See @ref tcontrol::set_active. */
virtual void set_active(const bool active) override;
/** See @ref tcontrol::get_active. */
virtual bool get_active() const override;
/** See @ref tcontrol::get_state. */
virtual unsigned get_state() const override;
/***** ***** ***** ***** expose some functions ***** ***** ***** *****/
void set_maximum_length(const size_t maximum_length);
size_t get_length() const
{
return text_.get_length();
}
/***** ***** ***** setters / getters for members ***** ****** *****/
/**
* The set_value is virtual for the @ref tpassword_box class.
*
* That class overrides the set_value function to replace it with asterisk.
* There might be more generic way to do it when more classes are needed.
*/
virtual void set_value(const std::string& text);
std::string get_value() const
{
return text_.text();
}
const std::string& text() const
{
return text_.text();
}
/** Set the text_changed callback. */
void set_text_changed_callback(
std::function<void(ttext_* textbox, const std::string text)> cb)
{
text_changed_callback_ = cb;
}
/**
* Sets or clears the text selection.
*
* Setting the selection range will re-position the cursor depending on the
* selection direction, specified by the length's sign. Selecting beyond the
* start or end of the text is safe; the final selection will be limited
* accordingly.
*
* @note The range extents are measured in Unicode characters, not bytes.
* Using byte offsets may produce unexpected results depending on the
* text contents.
*
* @param start Start offset, in characters.
* @param length Selection length, in characters. If zero, the
* current selection is canceled. If negative, the
* selection extends towards the start of the text
* and the cursor will be re-positioned in that
* direction as well; otherwise the selection and
* cursor extend towards the end.
*/
void set_selection(size_t start, int length);
protected:
/**
* Moves the cursor to the end of the line.
*
* @param select Select the text from the original cursor
* position till the end of the line?
*/
virtual void goto_end_of_line(const bool select = false) = 0;
/**
* Moves the cursor to the end of all text.
*
* For a single line text this is the same as goto_end_of_line().
*
* @param select Select the text from the original cursor
* position till the end of the data?
*/
void goto_end_of_data(const bool select = false)
{
set_cursor(text_.get_length(), select);
}
/**
* Moves the cursor to the beginning of the line
*
* @param select Select the text from the original cursor
* position till the beginning of the line?
*/
virtual void goto_start_of_line(const bool select = false) = 0;
/**
* Moves the cursor to the beginning of the data.
*
* @param select Select the text from the original cursor
* position till the beginning of the data?
*/
void goto_start_of_data(const bool select = false)
{
set_cursor(0, select);
}
/** Selects all text. */
void select_all()
{
selection_start_ = 0;
goto_end_of_data(true);
}
/**
* Moves the cursor at the wanted position.
*
* @param offset The wanted new cursor position.
* @param select Select the text from the original cursor
* position till the new position?
*/
void set_cursor(const size_t offset, const bool select);
/**
* Inserts a character at the cursor.
*
* This function is preferred over set_text since it's optimized for
* updating the internal bookkeeping.
*
* @param unicode The unicode value of the character to insert.
*/
virtual void insert_char(const utf8::string& unicode);
/**
* Deletes the character.
*
* @param before_cursor If true it deletes the character before the
* cursor (backspace) else the character after
* the cursor (delete).
*/
virtual void delete_char(const bool before_cursor) = 0;
/** Deletes the current selection. */
virtual void delete_selection() = 0;
/** Copies the current selection. */
virtual void copy_selection(const bool mouse);
/** Pastes the current selection. */
virtual void paste_selection(const bool mouse);
/***** ***** ***** ***** expose some functions ***** ***** ***** *****/
gui2::tpoint get_cursor_position(const unsigned column,
const unsigned line = 0) const
{
return text_.get_cursor_position(column, line);
}
tpoint get_column_line(const tpoint& position) const
{
return text_.get_column_line(position);
}
void set_font_size(const unsigned font_size)
{
text_.set_font_size(font_size);
}
void set_font_style(const unsigned font_style)
{
text_.set_font_style(font_style);
}
void set_maximum_width(const int width)
{
text_.set_maximum_width(width);
}
void set_maximum_height(const int height, const bool multiline)
{
text_.set_maximum_height(height, multiline);
}
void set_ellipse_mode(const PangoEllipsizeMode ellipse_mode)
{
text_.set_ellipse_mode(ellipse_mode);
}
/***** ***** ***** setters / getters for members ***** ****** *****/
size_t get_selection_start() const
{
return selection_start_;
}
void set_selection_start(const size_t selection_start);
size_t get_selection_length() const
{
return selection_length_;
}
void set_selection_length(const int selection_length);
private:
/** Note the order of the states must be the same as defined in
* settings.hpp. */
enum tstate {
ENABLED,
DISABLED,
FOCUSED,
COUNT
};
void set_state(const tstate state);
virtual void toggle_cursor_timer(bool enable);
/** Implements blinking cursor functionality. */
virtual void cursor_timer_callback();
virtual void reset_cursor_state();
/**
* Current state of the widget.
*
* The state of the widget determines what to render and how the widget
* reacts to certain 'events'.
*/
tstate state_;
/** The text entered in the widget. */
font::ttext text_;
/** Start of the selected text. */
size_t selection_start_;
/**
* Length of the selected text.
*
* * positive selection_len_ means selection to the right.
* * negative selection_len_ means selection to the left.
* * selection_len_ == 0 means no selection.
*/
int selection_length_;
size_t cursor_timer_;
unsigned short cursor_alpha_;
unsigned short cursor_blink_rate_ms_;
/****** handling of special keys first the pure virtuals *****/
/**
* Every key can have several behaviors.
*
* Unmodified No modifier is pressed.
* Control The control key is pressed.
* Shift The shift key is pressed.
* Alt The alt key is pressed.
*
* If modifiers together do something else as the sum of the modifiers
* it's listed separately eg.
*
* Control Moves 10 steps at the time.
* Shift Selects the text.
* Control + Shift Inserts 42 in the text.
*
* There are some predefined actions for results.
* Unhandled The key/modifier is ignored and also reported
* unhandled.
* Ignored The key/modifier is ignored and it's
* _expected_ the inherited classes do the same.
* Implementation defined The key/modifier is ignored and it's expected
* the inherited classes will define some meaning
* to it.
*/
/**
* Up arrow key pressed.
*
* The behavior is implementation defined.
*/
virtual void handle_key_up_arrow(SDL_Keymod modifier, bool& handled) = 0;
/**
* Down arrow key pressed.
*
* The behavior is implementation defined.
*/
virtual void handle_key_down_arrow(SDL_Keymod modifier, bool& handled) = 0;
/**
* Clears the current line.
*
* Unmodified Clears the current line.
* Control Ignored.
* Shift Ignored.
* Alt Ignored.
*/
virtual void handle_key_clear_line(SDL_Keymod modifier, bool& handled) = 0;
/**
* Left arrow key pressed.
*
* Unmodified Moves the cursor a character to the left.
* Control Like unmodified but a word instead of a letter
* at the time.
* Shift Selects the text while moving.
* Alt Ignored.
*/
virtual void handle_key_left_arrow(SDL_Keymod modifier, bool& handled);
/**
* Right arrow key pressed.
*
* Unmodified Moves the cursor a character to the right.
* Control Like unmodified but a word instead of a letter
* at the time.
* Shift Selects the text while moving.
* Alt Ignored.
*/
virtual void handle_key_right_arrow(SDL_Keymod modifier, bool& handled);
/**
* Home key pressed.
*
* Unmodified Moves the cursor a to the beginning of the
* line.
* Control Like unmodified but to the beginning of the
* data.
* Shift Selects the text while moving.
* Alt Ignored.
*/
virtual void handle_key_home(SDL_Keymod modifier, bool& handled);
/**
* End key pressed.
*
* Unmodified Moves the cursor a to the end of the line.
* Control Like unmodified but to the end of the data.
* Shift Selects the text while moving.
* Alt Ignored.
*/
virtual void handle_key_end(SDL_Keymod modifier, bool& handled);
/**
* Backspace key pressed.
*
* Unmodified Deletes the character before the cursor,
* ignored if at the beginning of the data.
* Control Ignored.
* Shift Ignored.
* Alt Ignored.
*/
virtual void handle_key_backspace(SDL_Keymod modifier, bool& handled);
/**
* Delete key pressed.
*
* Unmodified If there is a selection that's deleted.
* Else if not at the end of the data the
* character after the cursor is deleted.
* Else the key is ignored.
* ignored if at the beginning of the data.
* Control Ignored.
* Shift Ignored.
* Alt Ignored.
*/
virtual void handle_key_delete(SDL_Keymod modifier, bool& handled);
/**
* Page up key.
*
* Unmodified Unhandled.
* Control Ignored.
* Shift Ignored.
* Alt Ignored.
*/
virtual void handle_key_page_up(SDL_Keymod /*modifier*/, bool& /*handled*/)
{
}
/**
* Page down key.
*
* Unmodified Unhandled.
* Control Ignored.
* Shift Ignored.
* Alt Ignored.
*/
virtual void handle_key_page_down(SDL_Keymod /*modifier*/, bool& /*handled*/)
{
}
protected:
/**
* Default key handler if none of the above functions is called.
*
* Unmodified If invalid unicode it's ignored.
* Else if text selected the selected text is
* replaced with the unicode character send.
* Else the unicode character is inserted after
* the cursor.
* Control Ignored.
* Shift Ignored (already in the unicode value).
* Alt Ignored.
*/
virtual void handle_key_default(bool& handled,
SDL_Keycode key,
SDL_Keymod modifier,
const utf8::string& unicode);
private:
/**
* Text changed callback.
*
* This callback is called in key_press after the key_press event has been
* handled by the control. The parameters to the function are:
* - The widget invoking the callback
* - The new text of the textbox.
*/
std::function<void(ttext_* textbox, const std::string text)>
text_changed_callback_;
/***** ***** ***** signal handlers ***** ****** *****/
void signal_handler_middle_button_click(const event::tevent event,
bool& handled);
void signal_handler_sdl_key_down(const event::tevent event,
bool& handled,
const SDL_Keycode key,
SDL_Keymod modifier,
const utf8::string& unicode);
void signal_handler_receive_keyboard_focus(const event::tevent event);
void signal_handler_lose_keyboard_focus(const event::tevent event);
};
} // namespace gui2
#endif