Made text_font_size mandatory and fixed all content to obey that.

Cleaned up some std::cerr to use proper logging.

Rather ugly proof-of-concept to get the cursor working in a
text_box. This still needs quite some polishing but the basics work.
This commit is contained in:
Mark de Wever 2008-04-06 14:06:28 +00:00
parent 514827f389
commit 941bc3dc59
8 changed files with 307 additions and 87 deletions

View file

@ -16,6 +16,8 @@
max_width = 0
max_height = 22
text_font_size = {FONT_SIZE_NORMAL__NORMAL}
[state_enabled]
full_redraw = "true"

View file

@ -16,6 +16,8 @@
max_width = 0
max_height = 22
text_font_size = {FONT_SIZE_NORMAL__NORMAL}
[state_enabled]
full_redraw = "true"
@ -43,6 +45,16 @@
text = "(text)"
[/text]
# cursor
[line]
x1 = "(cursor_offset) + 5"
y1 = 2
x2 = "(cursor_offset) + 5"
y2 = "(height - 4)"
colour = "255, 255, 255, 255"
thickness = 1
[/line]
[/draw]
[/state_enabled]
@ -74,6 +86,8 @@
text = "(text)"
[/text]
# no cursor when disabled.
[/draw]
[/state_disabled]
@ -105,6 +119,16 @@
text = "(text)"
[/text]
# cursor
[line]
x1 = "(cursor_offset) + 5"
y1 = 2
x2 = "(cursor_offset) + 5"
y2 = "(height - 4)"
colour = "0, 0, 0, 255"
thickness = 1
[/line]
[/draw]
[/state_focussed]

View file

@ -14,12 +14,12 @@
#include "gui/dialogs/addon_connect.hpp"
#include "gui/widgets/button.hpp"
#include "gui/widgets/widget.hpp"
#include "gui/widgets/window.hpp"
#include "gui/widgets/window_builder.hpp"
#include "gui/widgets/button.hpp"
#include "gui/widgets/settings.hpp"
#include "gui/widgets/text_box.hpp"
#include "log.hpp"
#include "video.hpp"
@ -36,16 +36,15 @@ void taddon_connect::show(CVideo& video)
gui2::init();
twindow window = build(video, get_id(ADDON_CONNECT));
tcontrol* host_widget = dynamic_cast<tcontrol*>(window.get_widget_by_id("host_name"));
ttext_box* host_widget = dynamic_cast<ttext_box*>(window.get_widget_by_id("host_name"));
if(host_widget) {
host_widget->set_label(host_name_);
host_widget->set_text(host_name_);
}
retval_ = window.show(true);
if(host_widget) {
host_name_= host_widget->label();
host_name_= host_widget->get_text();
}
}

View file

@ -45,10 +45,6 @@ public:
const std::string& label() const { return label_; }
//! Note when modifing the label the caller should set the widget to
//! dirty.
std::string& label() { return label_; }
// Note setting the tooltip_ doesn't dirty an object.
void set_tooltip(const t_string& tooltip) { tooltip_ = tooltip; }
const t_string& tooltip() const { return tooltip_; }

View file

@ -142,7 +142,7 @@ const std::string& tgui_definition::read(const config& cfg)
VALIDATE(!id.empty(), missing_mandatory_wml_key("gui", "id"));
VALIDATE(!description.empty(), missing_mandatory_wml_key("gui", "description"));
std::cerr << "Parsing gui " << id << '\n';
DBG_G_P << "Parsing gui " << id << '\n';
/***** Window definitions *****/
const config::child_list& window_cfgs = cfg.get_children("window_definition");
@ -234,7 +234,7 @@ const std::string& tbutton_definition::read(const config& cfg)
VALIDATE(!id.empty(), missing_mandatory_wml_key("gui", "id"));
VALIDATE(!description.empty(), missing_mandatory_wml_key("gui", "description"));
std::cerr << "Parsing button " << id << '\n';
DBG_G_P << "Parsing button " << id << '\n';
const config::child_list& cfgs = cfg.get_children("resolution");
VALIDATE(!cfgs.empty(), _("No resolution defined."));
@ -285,7 +285,7 @@ const std::string& tlabel_definition::read(const config& cfg)
VALIDATE(!id.empty(), missing_mandatory_wml_key("gui", "id"));
VALIDATE(!description.empty(), missing_mandatory_wml_key("gui", "description"));
std::cerr << "Parsing label " << id << '\n';
DBG_G_P << "Parsing label " << id << '\n';
const config::child_list& cfgs = cfg.get_children("resolution");
VALIDATE(!cfgs.empty(), _("No resolution defined."));
@ -369,14 +369,15 @@ tresolution_definition_::tresolution_definition_(const config& cfg) :
* text_extra_height = (unsigned = 0)
* The extra height needed to determine the
* minimal size for the text.
* text_font_size = (unsigned =0)
* The font size, which needs to be used to
* text_font_size = (unsigned) The font size, which needs to be used to
* determine the minimal size for the text.
*
* [/resolution]
*/
std::cerr << "Parsing resolution "
VALIDATE(text_font_size, missing_mandatory_wml_key("resolution", "text_font_size"));
DBG_G_P << "Parsing resolution "
<< window_width << ", " << window_height << '\n';
}
@ -413,7 +414,7 @@ const std::string& ttext_box_definition::read(const config& cfg)
VALIDATE(!id.empty(), missing_mandatory_wml_key("gui", "id"));
VALIDATE(!description.empty(), missing_mandatory_wml_key("gui", "description"));
std::cerr << "Parsing text_box " << id << '\n';
DBG_G_P << "Parsing text_box " << id << '\n';
const config::child_list& cfgs = cfg.get_children("resolution");
VALIDATE(!cfgs.empty(), _("No resolution defined."));
@ -462,7 +463,7 @@ const std::string& twindow_definition::read(const config& cfg)
VALIDATE(!id.empty(), missing_mandatory_wml_key("gui", "id"));
VALIDATE(!description.empty(), missing_mandatory_wml_key("gui", "description"));
std::cerr << "Parsing window " << id << '\n';
DBG_G_P << "Parsing window " << id << '\n';
const config::child_list& cfgs = cfg.get_children("resolution");
VALIDATE(!cfgs.empty(), _("No resolution defined."));
@ -508,7 +509,7 @@ twindow_definition::tresolution::tresolution(const config& cfg) :
* [/resolution]
*/
std::cerr << "Parsing resolution "
DBG_G_P << "Parsing resolution "
<< window_width << ", " << window_height << '\n';
}

View file

@ -14,7 +14,12 @@
#include "gui/widgets/text_box.hpp"
#include "font.hpp"
#include "foreach.hpp"
#include "log.hpp"
#include "serialization/string_utils.hpp"
#include <numeric>
#define DBG_G LOG_STREAM(debug, gui)
#define LOG_G LOG_STREAM(info, gui)
@ -50,18 +55,17 @@ void ttext_::set_cursor(const size_t offset, const bool select)
} else { // sel_start_ < offset
sel_len_ = - (sel_start_ - offset);
}
set_canvas_text();
set_dirty();
} else {
assert(offset <= label().size());
assert(offset <= text_.size());
sel_start_ = offset;
sel_len_ = 0;
}
}
bool ttext_::full_redraw() const
{
// FIXME make sure definition_ is valid before usage!
return definition_->state[get_state()].full_redraw;
set_canvas_text();
set_dirty();
}
}
void ttext_::mouse_move(tevent_handler&)
@ -98,7 +102,7 @@ void ttext_::mouse_left_button_double_click(tevent_handler&)
DBG_G_E << "Text_box: left mouse button double click.\n";
sel_start_ = 0;
sel_len_ = label().size();
sel_len_ = text_.size();
}
@ -183,23 +187,18 @@ void ttext_::key_press(tevent_handler& event, bool& handled, SDLKey key, SDLMod
}
tpoint ttext_::get_best_size() const
{
if(definition_ == std::vector<ttext_box_definition::tresolution>::const_iterator()) {
return tpoint(get_text_box(definition())->default_width, get_text_box(definition())->default_height);
} else {
return tpoint(definition_->default_width, definition_->default_height);
}
}
void ttext_::set_text(const std::string& text)
{
if(text != text_) {
text_ = text;
calculate_char_offset();
void ttext_::set_best_size(const tpoint& origin)
{
resolve_definition();
set_x(origin.x);
set_y(origin.y);
set_width(definition_->default_width);
set_height(definition_->default_height);
// default to put the cursor at the end of the buffer.
sel_start_ = text_.size();
sel_len_ = 0;
set_canvas_text();
set_dirty();
}
}
void ttext_::set_state(tstate state)
@ -210,20 +209,6 @@ void ttext_::set_state(tstate state)
}
}
void ttext_::resolve_definition()
{
if(definition_ == std::vector<ttext_box_definition::tresolution>::const_iterator()) {
definition_ = get_text_box(definition());
assert(canvas().size() == definition_->state.size());
for(size_t i = 0; i < canvas().size(); ++i) {
canvas(i) = definition_->state[i].canvas;
}
set_canvas_text();
}
}
// Go a character left of not at start of buffer else beep.
// ctrl moves a word instead of character.
// shift selects while moving.
@ -245,7 +230,7 @@ void ttext_::handle_key_right_arrow(SDLMod modifier, bool& handled)
DBG_G_E << "Text_box: key press: right arrow.\n";
handled = true;
if(sel_start_ < label().size()) {
if(sel_start_ < text_.size()) {
set_cursor(sel_start_ + 1, modifier & KMOD_SHIFT);
}
}
@ -287,10 +272,7 @@ void ttext_::handle_key_backspace(SDLMod modifier, bool& handled)
handled = true;
if(sel_start_){
label().erase(--sel_start_, 1);
set_canvas_text();
set_dirty();
set_cursor(sel_start_, false);
delete_char(true);
} else {
// FIXME beep
}
@ -304,13 +286,10 @@ void ttext_::handle_key_delete(SDLMod modifier, bool& handled)
handled = true;
if(sel_len_ != 0) {
assert(false); // FIXME implement
} else {
label().erase(sel_start_, 1);
set_canvas_text();
set_dirty();
delete_selection();
} else if (sel_start_ < text_.size()) {
delete_char(false);
}
}
void ttext_::handle_key_default(bool& handled, SDLKey key, SDLMod modifier, Uint16 unicode)
@ -319,18 +298,187 @@ void ttext_::handle_key_default(bool& handled, SDLKey key, SDLMod modifier, Uint
if(unicode >= 32 && unicode != 127) {
handled = true;
label().insert(label().begin() + sel_start_++, unicode);
set_canvas_text();
set_dirty();
insert_char(unicode);
}
}
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);
}
//! Helper function for text more efficient as set_text.
//! Inserts a character at the cursor.
void ttext_box::insert_char(Uint16 unicode)
{
if(sel_len() > 0) {
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, definition_->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(text());
tmp.insert(tmp.begin() + sel_start(), unicode);
text() = utils::wstring_to_string(tmp);
// Update the widths.
character_offset_.insert(character_offset_.begin() + sel_start(), width);
if(sel_start() != 0) {
character_offset_[sel_start()] += character_offset_[sel_start() - 1];
}
++sel_start();
for(size_t i = sel_start(); i < character_offset_.size(); ++i) {
character_offset_[i] += width;
}
set_cursor(sel_start(), false);
set_canvas_text();
set_dirty();
}
//! Deletes the character.
//!
//! @param before_cursor If true it deletes the character before the cursor
//! (backspace) else the character after the cursor
//! (delete).
void ttext_box::delete_char(const bool before_cursor)
{
if(before_cursor) {
--sel_start();
set_cursor(sel_start(), false);
}
sel_len() = 1;
delete_selection();
}
//! Deletes the current selection.
void ttext_box::delete_selection()
{
assert(sel_len() != 0);
// If we have a negative range change it to a positive range.
// This makes the rest of the algoritms easier.
if(sel_len() < 0) {
sel_len() = - sel_len();
sel_start() -= sel_len();
set_cursor(sel_start(), false);
}
// Update the text, we need to assume it's a wide string.
wide_string tmp = utils::string_to_wstring(text());
tmp.erase(tmp.begin() + sel_start(), tmp.begin() + sel_start() + sel_len());
text() = utils::wstring_to_string(tmp);
// Update the offsets
const unsigned width = character_offset_[sel_start() + sel_len() - 1] -
(sel_start() ? character_offset_[sel_start() - 1] : 0);
character_offset_.erase(character_offset_.begin() + sel_start(), character_offset_.begin() + sel_start() + sel_len());
for(size_t i = sel_start(); i < character_offset_.size(); ++i) {
character_offset_[i] -= width;
}
sel_len() = 0;
set_canvas_text();
set_dirty();
}
bool ttext_box::full_redraw() const
{
if(definition_ != std::vector<ttext_box_definition::tresolution>::const_iterator()) {
return definition_->state[get_state()].full_redraw;
} else {
return 0;
}
}
//! Inherited from tcontrol.
void ttext_box::set_canvas_text()
{
foreach(tcanvas& tmp, canvas()) {
tmp.set_variable("text", variant(text()));
//FIXME add selection info.
if(text().empty() || sel_start() == 0) {
tmp.set_variable("cursor_offset", variant(0));
} else {
tmp.set_variable("cursor_offset", variant(character_offset_[sel_start() -1] + 0));
}
}
}
tpoint ttext_box::get_best_size() const
{
if(definition_ == std::vector<ttext_box_definition::tresolution>::const_iterator()) {
return tpoint(get_text_box(definition())->default_width, get_text_box(definition())->default_height);
} else {
return tpoint(definition_->default_width, definition_->default_height);
}
}
void ttext_box::set_best_size(const tpoint& origin)
{
resolve_definition();
set_x(origin.x);
set_y(origin.y);
set_width(definition_->default_width);
set_height(definition_->default_height);
}
//! Calculates the offsets of all chars.
void ttext_box::calculate_char_offset()
{
character_offset_.clear();
std::string rendered_text;
const unsigned font_size =
definition_ == std::vector<ttext_box_definition::tresolution>::const_iterator() ?
0 : definition_->text_font_size;
// FIXME we assume the text start at offset 0!!!
foreach(const wchar_t& unicode, utils::string_to_wstring(text())) {
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_clear_line(SDLMod modifier, bool& handled)
{
handled = true;
set_label("");
set_sel_start(0);
set_sel_len(0);
set_text("");
}
void ttext_box::resolve_definition()
{
if(definition_ == std::vector<ttext_box_definition::tresolution>::const_iterator()) {
definition_ = get_text_box(definition());
assert(canvas().size() == definition_->state.size());
for(size_t i = 0; i < canvas().size(); ++i) {
canvas(i) = definition_->state[i].canvas;
}
calculate_char_offset();
set_canvas_text();
}
}
} //namespace gui2

View file

@ -33,17 +33,16 @@ class ttext_ : public tcontrol
public:
ttext_() :
tcontrol(COUNT),
definition_(),
dragging_(false),
text_(),
sel_start_(0),
sel_len_(0),
max_length_(std::string::npos)
max_length_(std::string::npos),
dragging_(false)
{}
void set_active(const bool active) { /*FIXME IMPLEMENT*/ };
bool get_active() const { return true; /* FIXME IMPLEMENT */ }
unsigned get_state() const { return 0; /* FIXME IMPLEMENT */ }
bool full_redraw() const;
void mouse_move(tevent_handler&);
void mouse_hover(tevent_handler&);
@ -54,14 +53,15 @@ public:
void key_press(tevent_handler& event, bool& handled, SDLKey key, SDLMod modifier, Uint16 unicode);
tpoint get_best_size() const;
void set_best_size(const tpoint& origin);
void set_text(const std::string& text);
std::string get_text() const { return text_; }
const std::string& text() const { return text_; }
protected:
virtual void goto_end_of_line(const bool select = false) = 0;
void goto_end_of_data(const bool select = false) { set_cursor(label().size(), select); }
void goto_end_of_data(const bool select = false) { set_cursor(text_.size(), select); }
virtual void goto_start_of_line(const bool select = false) = 0;
void goto_start_of_data(const bool select = false) { set_cursor(0, select); }
@ -74,6 +74,23 @@ protected:
size_t get_sel_len() const { return sel_len_; }
void set_sel_len(const unsigned sel_len) { sel_len_ = sel_len; set_dirty(); }
//! Inserts a character at the cursor.
virtual void insert_char(Uint16 unicode) = 0;
//! Deletes the character.
virtual void delete_char(const bool before_cursor) = 0;
//! Deletes the current selection.
virtual void delete_selection() = 0;
protected:
std::string& text() { return text_; }
size_t& sel_start() { return sel_start_; }
int& sel_len() { return sel_len_; }
private:
//! Note the order of the states must be the same as defined in settings.hpp.
enum tstate { ENABLED, DISABLED, FOCUSSED, COUNT };
@ -81,18 +98,23 @@ private:
void set_state(tstate state);
tstate state_;
std::vector<ttext_box_definition::tresolution>::const_iterator definition_;
void resolve_definition();
//! The text in the widget.
std::string text_;
//! Calculates the offsets of all chars.
virtual void calculate_char_offset() = 0;
bool dragging_;
size_t sel_start_;
//! positive sel_len_ means selection to the right.
//! negative sel_len_ means selection to the left.
//! sel_len_ == 0 means no selection.
unsigned sel_len_;
int sel_len_;
size_t max_length_;
//! Is the mouse in dragging mode, this affects selection in mouse movee
bool dragging_;
// handling of special keys first the pure virtuals
virtual void handle_key_up_arrow(SDLMod modifier, bool& handled) = 0;
virtual void handle_key_down_arrow(SDLMod modifier, bool& handled) = 0;
@ -132,6 +154,8 @@ private:
// These are ignored by a single line edit box which is the default behaviour.
virtual void handle_key_page_up(SDLMod modifier, bool& handled) {}
virtual void handle_key_page_down(SDLMod modifier, bool& handled) {}
virtual void resolve_definition() = 0;
};
//! Class for a single line text area.
@ -141,7 +165,9 @@ class ttext_box : public ttext_
public:
ttext_box() :
ttext_()
ttext_(),
character_offset_(),
definition_()
{}
@ -155,11 +181,26 @@ protected:
// void copy();
// void paste();
//
//! Inherited from ttext_.
void insert_char(Uint16 unicode);
//! Inherited from ttext_.
void delete_char(const bool before_cursor);
//! Inherited from ttext_.
void delete_selection();
bool full_redraw() const;
//! Inherited from tcontrol.
void set_canvas_text();
void goto_end_of_line(const bool select = false) { goto_end_of_data(select); }
void goto_start_of_line(const bool select = false) { goto_start_of_data(select); }
tpoint get_best_size() const;
void set_best_size(const tpoint& origin);
private:
void handle_key_up_arrow(SDLMod modifier, bool& handled) {};
@ -168,7 +209,15 @@ private:
// Clears the current line
void handle_key_clear_line(SDLMod modifier, bool& handled);
//! Contains the end offset of each character in the text area.
std::vector<unsigned> character_offset_;
//! Inherited from ttext_.
void calculate_char_offset();
std::vector<ttext_box_definition::tresolution>::const_iterator definition_;
void resolve_definition();
};

View file

@ -299,7 +299,8 @@ twidget* tbuilder_text_box::build() const
text_box->set_id(id);
text_box->set_definition(definition);
text_box->set_label(label);
// A textbox doesn't have a label but a text
text_box->set_text(label);
DBG_G << "Window builder: placed text box '" << id << "' with defintion '"
<< definition << "'.\n";