Let the text widget use a font text object.
With this change a lot of helper code can be moved to pango. This is also required since the text size between pango and the old SDL_TTF library might differ. Also fixes some crashing bugs when special characters were used in the text boxes.
This commit is contained in:
parent
bbede1d7f6
commit
5c1fe9bec3
4 changed files with 65 additions and 155 deletions
|
@ -67,7 +67,7 @@ void ttext_::mouse_left_button_double_click(tevent_handler&)
|
|||
DBG_G_E << "Text: left mouse button double click.\n";
|
||||
|
||||
selection_start_ = 0;
|
||||
selection_length_ = text_.size();
|
||||
selection_length_ = text_.get_length();
|
||||
|
||||
}
|
||||
|
||||
|
@ -206,12 +206,11 @@ void ttext_::key_press(tevent_handler& /*event*/,
|
|||
|
||||
void ttext_::set_value(const std::string& text)
|
||||
{
|
||||
if(text != text_) {
|
||||
text_ = text;
|
||||
calculate_char_offset();
|
||||
if(text != text_.text()) {
|
||||
text_.set_text(text, false);
|
||||
|
||||
// default to put the cursor at the end of the buffer.
|
||||
selection_start_ = text_.size();
|
||||
selection_start_ = text_.get_length();
|
||||
selection_length_ = 0;
|
||||
set_canvas_text();
|
||||
set_dirty();
|
||||
|
@ -236,7 +235,7 @@ void ttext_::set_cursor(const size_t offset, const bool select)
|
|||
set_dirty();
|
||||
|
||||
} else {
|
||||
assert(offset <= text_.size());
|
||||
assert(offset <= text_.get_length());
|
||||
selection_start_ = offset;
|
||||
selection_length_ = 0;
|
||||
|
||||
|
@ -245,6 +244,18 @@ void ttext_::set_cursor(const size_t offset, const bool select)
|
|||
}
|
||||
}
|
||||
|
||||
void ttext_::insert_char(const Uint16 unicode)
|
||||
{
|
||||
delete_selection();
|
||||
|
||||
text_.insert_unicode(selection_start_, unicode);
|
||||
|
||||
// Update status
|
||||
set_cursor(selection_start_ + 1, false);
|
||||
set_canvas_text();
|
||||
set_dirty();
|
||||
}
|
||||
|
||||
void ttext_::copy_selection(const bool mouse)
|
||||
{
|
||||
int length = selection_length_;
|
||||
|
@ -255,7 +266,7 @@ void ttext_::copy_selection(const bool mouse)
|
|||
start -= length;
|
||||
}
|
||||
|
||||
const wide_string& wtext = utils::string_to_wstring(text_);
|
||||
const wide_string& wtext = utils::string_to_wstring(text_.text());
|
||||
const std::string& text = utils::wstring_to_string(
|
||||
wide_string(wtext.begin() + start, wtext.begin() + start + length));
|
||||
|
||||
|
@ -271,11 +282,8 @@ void ttext_::paste_selection(const bool mouse)
|
|||
|
||||
delete_selection();
|
||||
|
||||
text_.insert(selection_start_, text);
|
||||
selection_start_ += text_.insert_text(selection_start_, text);
|
||||
|
||||
selection_start_ += utils::string_to_wstring(text).size();
|
||||
|
||||
calculate_char_offset();
|
||||
set_canvas_text();
|
||||
set_dirty();
|
||||
}
|
||||
|
@ -323,7 +331,7 @@ void ttext_::handle_key_right_arrow(SDLMod modifier, bool& handled)
|
|||
|
||||
handled = true;
|
||||
const int offset = selection_start_ + 1 + selection_length_;
|
||||
if(offset <= text_.size()) {
|
||||
if(offset <= text_.get_length()) {
|
||||
set_cursor(offset, modifier & KMOD_SHIFT);
|
||||
}
|
||||
}
|
||||
|
@ -369,7 +377,7 @@ void ttext_::handle_key_delete(SDLMod /*modifier*/, bool& handled)
|
|||
handled = true;
|
||||
if(selection_length_ != 0) {
|
||||
delete_selection();
|
||||
} else if (selection_start_ < text_.size()) {
|
||||
} else if (selection_start_ < text_.get_length()) {
|
||||
delete_char(false);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
#define GUI_WIDGETS_TEXT_HPP_INCLUDED
|
||||
|
||||
#include "gui/widgets/control.hpp"
|
||||
#include "../../text.hpp"
|
||||
|
||||
#include <string>
|
||||
|
||||
|
@ -72,9 +73,9 @@ public:
|
|||
/***** ***** ***** setters / getters for members ***** ****** *****/
|
||||
|
||||
void set_value(const std::string& text);
|
||||
std::string get_value() const { return text_; }
|
||||
std::string get_value() const { return text_.text(); }
|
||||
|
||||
const std::string& text() const { return text_; }
|
||||
const std::string& text() const { return text_.text(); }
|
||||
|
||||
protected:
|
||||
|
||||
|
@ -95,10 +96,10 @@ protected:
|
|||
* position till the end of the data?
|
||||
*/
|
||||
void goto_end_of_data(const bool select = false)
|
||||
{ set_cursor(text_.size(), select); }
|
||||
{ set_cursor(text_.get_length(), select); }
|
||||
|
||||
/**
|
||||
* Moves the cursor to the beginning of the line.
|
||||
* 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?
|
||||
|
@ -133,7 +134,7 @@ protected:
|
|||
*
|
||||
* @param unicode The unicode value of the character to insert.
|
||||
*/
|
||||
virtual void insert_char(const Uint16 unicode) = 0;
|
||||
void insert_char(const Uint16 unicode);
|
||||
|
||||
/**
|
||||
* Deletes the character.
|
||||
|
@ -153,6 +154,15 @@ protected:
|
|||
/** 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); }
|
||||
|
||||
/***** ***** ***** setters / getters for members ***** ****** *****/
|
||||
|
||||
size_t get_selection_start() const { return selection_start_; }
|
||||
|
@ -161,6 +171,7 @@ protected:
|
|||
size_t get_selection_length() const { return selection_length_; }
|
||||
void set_selection_length(const unsigned selection_length);
|
||||
|
||||
|
||||
private:
|
||||
/** Note the order of the states must be the same as defined in settings.hpp. */
|
||||
enum tstate { ENABLED, DISABLED, FOCUSSED, COUNT };
|
||||
|
@ -176,10 +187,7 @@ private:
|
|||
tstate state_;
|
||||
|
||||
/** The text entered in the widget. */
|
||||
std::string text_;
|
||||
|
||||
/** Calculates the offsets of all chars. */
|
||||
virtual void calculate_char_offset() = 0;
|
||||
font::ttext text_;
|
||||
|
||||
/** Start of the selected text. */
|
||||
size_t selection_start_;
|
||||
|
|
|
@ -46,12 +46,6 @@
|
|||
|
||||
namespace gui2 {
|
||||
|
||||
static surface render_text(const std::string& text, unsigned font_size)
|
||||
{
|
||||
static SDL_Color col = {0, 0, 0, 0};
|
||||
return font::get_rendered_text(text, font_size, col, TTF_STYLE_NORMAL);
|
||||
}
|
||||
|
||||
ttext_history ttext_history::get_history(const std::string& id, const bool enabled)
|
||||
{
|
||||
std::vector<std::string>* vec = preferences::get_history(id);
|
||||
|
@ -121,41 +115,36 @@ void ttext_box::set_size(const SDL_Rect& rect)
|
|||
|
||||
void ttext_box::set_canvas_text()
|
||||
{
|
||||
/***** Gather the info *****/
|
||||
|
||||
// Set the cursor info.
|
||||
const unsigned start = get_selection_start();
|
||||
const int length = get_selection_length();
|
||||
|
||||
// Set the selection info
|
||||
unsigned start_offset = 0;
|
||||
unsigned end_offset = 0;
|
||||
if(length == 0) {
|
||||
// No nothing.
|
||||
} else if(length > 0) {
|
||||
start_offset = get_cursor_position(start).x;
|
||||
end_offset = get_cursor_position(start + length).x;
|
||||
} else {
|
||||
start_offset = get_cursor_position(start + length).x;
|
||||
end_offset = get_cursor_position(start).x;
|
||||
}
|
||||
|
||||
/***** Set in all canvases *****/
|
||||
|
||||
foreach(tcanvas& tmp, canvas()) {
|
||||
|
||||
// NOTE when get_selection_start() == - get_selection_length() then the
|
||||
// offset calculation will access character_offset_[-1] so add special
|
||||
// cases to use 0 instead. The same can happen if
|
||||
// get_selection_start() == 0.
|
||||
|
||||
// Set the general variables.
|
||||
tmp.set_variable("text", variant(get_value()));
|
||||
tmp.set_variable("text_x_offset", variant(text_x_offset_));
|
||||
tmp.set_variable("text_y_offset", variant(text_y_offset_));
|
||||
|
||||
// Set the cursor info.
|
||||
const unsigned start = get_selection_start();
|
||||
const int len = get_selection_length();
|
||||
if(get_value().empty() || start + len == 0) {
|
||||
tmp.set_variable("cursor_offset", variant(0));
|
||||
} else {
|
||||
tmp.set_variable("cursor_offset",
|
||||
variant(character_offset_[start - 1 + len]));
|
||||
}
|
||||
tmp.set_variable("cursor_offset",
|
||||
variant(get_cursor_position(start + length).x));
|
||||
|
||||
// Set the seleciton info
|
||||
unsigned start_offset = 0;
|
||||
unsigned end_offset = 0;
|
||||
if(len == 0) {
|
||||
// No nothing.
|
||||
} else if(len > 0) {
|
||||
start_offset = start == 0 ? 0 :character_offset_[start - 1];
|
||||
end_offset = character_offset_[start - 1 + len];
|
||||
} else {
|
||||
start_offset =
|
||||
(start + len == 0) ? 0 : character_offset_[start - 1 + len];
|
||||
end_offset = character_offset_[start - 1];
|
||||
}
|
||||
tmp.set_variable("selection_offset", variant(start_offset));
|
||||
tmp.set_variable("selection_width", variant(end_offset - start_offset ));
|
||||
}
|
||||
|
@ -196,46 +185,6 @@ void ttext_box::mouse_left_button_double_click(tevent_handler&)
|
|||
select_all();
|
||||
}
|
||||
|
||||
void ttext_box::insert_char(const Uint16 unicode)
|
||||
{
|
||||
delete_selection();
|
||||
|
||||
// Determine the width of the new character.
|
||||
std::string tmp_text;
|
||||
tmp_text.insert(tmp_text.begin(), unicode);
|
||||
|
||||
surface surf = render_text(tmp_text, config()->text_font_size);
|
||||
assert(surf);
|
||||
const unsigned width = surf->w;
|
||||
|
||||
// Insert the char in the buffer, we need to assume it's a wide string.
|
||||
wide_string tmp = utils::string_to_wstring(get_value());
|
||||
tmp.insert(tmp.begin() + get_selection_start(), unicode);
|
||||
|
||||
// Update the widths.
|
||||
character_offset_.insert(
|
||||
character_offset_.begin() + get_selection_start(), width);
|
||||
|
||||
if(get_selection_start() != 0) {
|
||||
character_offset_[get_selection_start()]
|
||||
+= character_offset_[get_selection_start() - 1];
|
||||
}
|
||||
|
||||
const unsigned start = get_selection_start() + 1;
|
||||
// set_value also resets the selection start, maybe add a real insert
|
||||
// member to avoid that.
|
||||
set_value(utils::wstring_to_string(tmp));
|
||||
for(size_t i = start;
|
||||
i < character_offset_.size(); ++i) {
|
||||
|
||||
character_offset_[i] += width;
|
||||
}
|
||||
|
||||
set_cursor(start, false);
|
||||
set_canvas_text();
|
||||
set_dirty();
|
||||
}
|
||||
|
||||
void ttext_box::delete_char(const bool before_cursor)
|
||||
{
|
||||
if(before_cursor) {
|
||||
|
@ -283,8 +232,8 @@ void ttext_box::handle_mouse_selection(
|
|||
return;
|
||||
}
|
||||
|
||||
int offset =
|
||||
get_character_offset_at(mouse.x - static_cast<int>(text_x_offset_));
|
||||
int offset = get_column_line(tpoint(
|
||||
mouse.x - text_x_offset_, mouse.y - text_y_offset_)).x;
|
||||
|
||||
if(offset < 0) {
|
||||
return;
|
||||
|
@ -297,19 +246,6 @@ void ttext_box::handle_mouse_selection(
|
|||
dragging_ |= start_selection;
|
||||
}
|
||||
|
||||
unsigned ttext_box::get_character_offset_at(const unsigned offset)
|
||||
{
|
||||
unsigned result = 0;
|
||||
foreach(unsigned off, character_offset_) {
|
||||
if(offset < off) {
|
||||
return result;
|
||||
}
|
||||
|
||||
++result;
|
||||
}
|
||||
return get_value().size();
|
||||
}
|
||||
|
||||
void ttext_box::update_offsets()
|
||||
{
|
||||
assert(config());
|
||||
|
@ -340,23 +276,6 @@ void ttext_box::update_offsets()
|
|||
set_canvas_text();
|
||||
}
|
||||
|
||||
void ttext_box::calculate_char_offset()
|
||||
{
|
||||
assert(config());
|
||||
character_offset_.clear();
|
||||
|
||||
std::string rendered_text;
|
||||
const unsigned font_size = config()->text_font_size;
|
||||
|
||||
foreach(const wchar_t& unicode, utils::string_to_wstring(get_value())) {
|
||||
rendered_text.insert(rendered_text.end(), unicode);
|
||||
surface surf = render_text(rendered_text, font_size);
|
||||
assert(surf);
|
||||
character_offset_.push_back(surf->w);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void ttext_box::handle_key_up_arrow(SDLMod /*modifier*/, bool& handled)
|
||||
{
|
||||
if (history_.get_enabled()) {
|
||||
|
|
|
@ -115,7 +115,6 @@ class ttext_box : public ttext_
|
|||
public:
|
||||
ttext_box() :
|
||||
ttext_(),
|
||||
character_offset_(),
|
||||
history_(),
|
||||
text_x_offset_(0),
|
||||
text_y_offset_(0),
|
||||
|
@ -161,9 +160,6 @@ protected:
|
|||
void goto_start_of_line(const bool select = false)
|
||||
{ goto_start_of_data(select); }
|
||||
|
||||
/** Inherited from ttext_. */
|
||||
void insert_char(const Uint16 unicode);
|
||||
|
||||
/** Inherited from ttext_. */
|
||||
void delete_char(const bool before_cursor);
|
||||
|
||||
|
@ -176,32 +172,14 @@ protected:
|
|||
|
||||
private:
|
||||
|
||||
/**
|
||||
* Contains the end offset of each character in the text area.
|
||||
*
|
||||
* This is used for placing the cursor at the proper offset and determine
|
||||
* the offset for a mouse click.
|
||||
*/
|
||||
std::vector<unsigned> character_offset_;
|
||||
|
||||
/**
|
||||
* Gets the character at the wanted offset.
|
||||
*
|
||||
* If the click is beyond the text, the last character will be selected.
|
||||
*
|
||||
* @param offset The offset in the widget to test.
|
||||
*
|
||||
* @returns The character offset where the click occured.
|
||||
*/
|
||||
unsigned get_character_offset_at(const unsigned offset);
|
||||
|
||||
/** The history text for this widget. */
|
||||
ttext_history history_;
|
||||
|
||||
/**
|
||||
* The x offset in the widget where the text starts.
|
||||
*
|
||||
* This value is needed for get_character_offset_at()
|
||||
* This value is needed to translate a location in the widget to a location
|
||||
* in the text.
|
||||
*/
|
||||
unsigned text_x_offset_;
|
||||
|
||||
|
@ -225,9 +203,6 @@ private:
|
|||
/** Is the mouse in dragging mode, this affects selection in mouse move */
|
||||
bool dragging_;
|
||||
|
||||
/** Inherited from ttext_. */
|
||||
void calculate_char_offset();
|
||||
|
||||
/**
|
||||
* Inherited from ttext_.
|
||||
*
|
||||
|
|
Loading…
Add table
Reference in a new issue