wesnoth/src/widgets/textbox.cpp

184 lines
4.1 KiB
C++

/* $Id$ */
/*
Copyright (C) 2003 by David White <davidnwhite@optusnet.com.au>
Part of the Battle for Wesnoth Project http://wesnoth.whitevine.net
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY.
See the COPYING file for more details.
*/
#include "textbox.hpp"
#include "../font.hpp"
#include "../show_dialog.hpp"
#include "../video.hpp"
#include "SDL.h"
#include <algorithm>
#include <cctype>
namespace gui {
const int font_size = 16;
textbox::textbox(display& disp, int width, const std::string& text)
: widget(), disp_(disp), text_(text), firstOnScreen_(0),
cursor_(text.size()), buffer_(NULL), focus_(true)
{
static const SDL_Rect area = disp.screen_area();
const int height = font::draw_text(NULL,area,font_size,font::NORMAL_COLOUR,"ABCD",0,0).h;
std::cerr << "initializing textbox with height " << height << "\n";
const SDL_Rect starting_rect = {0,0,width,height};
set_location(starting_rect);
}
const std::string& textbox::text() const
{
return text_;
}
void textbox::set_text(std::string text)
{
text_ = text;
cursor_ = text_.size();
}
void textbox::clear()
{
text_ = "";
cursor_ = 0;
firstOnScreen_ = 0;
}
void textbox::draw_cursor(int pos) const
{
const bool show_cursor = (SDL_GetTicks()%1000) > 500;
static const short cursor_colour = short(0xFFFF);
if(show_cursor) {
surface_lock lock(disp_.video().getSurface());
short* dst = lock.pixels() + location().y*disp_.x() + location().x + pos;
for(int i = 0; i != location().h; ++i, dst += disp_.x()) {
*dst = cursor_colour;
}
}
}
void textbox::draw() const
{
if(location().x == 0)
return;
if(buffer_.get() != NULL) {
SDL_Rect rect = location();
SDL_BlitSurface(buffer_,NULL,disp_.video().getSurface(),&rect);
}
gui::draw_solid_tinted_rectangle(location().x,location().y,location().w,location().h,0,0,0,
focus_ ? 0.2 : 0.4, disp_.video().getSurface());
if(cursor_ == 0)
draw_cursor(0);
int pos = 1;
std::string str(1,'x');
const SDL_Rect clip = disp_.screen_area();
//draw the text
for(size_t i = firstOnScreen_; i < text_.size(); ++i) {
str[0] = text_[i];
const SDL_Rect area =
font::draw_text(NULL,clip,font_size,font::NORMAL_COLOUR,str,0,0,
NULL,false,font::NO_MARKUP);
//if we can't fit the next character on screen
if(pos + area.w > location().w) {
if(cursor_ > i)
++firstOnScreen_;
break;
}
font::draw_text(&disp_,clip,font_size,font::NORMAL_COLOUR,str,
location().x + pos, location().y, NULL, false, font::NO_MARKUP);
pos += area.w;
if(cursor_ == i+1)
draw_cursor(pos-1);
}
update_rect(location());
}
void textbox::handle_event(const SDL_Event& event)
{
if(location().x == 0)
return;
int mousex, mousey;
SDL_GetMouseState(&mousex,&mousey);
if(event.type != SDL_KEYDOWN || !focus_)
return;
const SDL_keysym& key = reinterpret_cast<const SDL_KeyboardEvent&>(event).keysym;
const int c = key.sym;
if(c == SDLK_LEFT && cursor_ > 0) {
--cursor_;
if(cursor_ < firstOnScreen_)
--firstOnScreen_;
}
if(c == SDLK_RIGHT && cursor_ < text_.size()) {
++cursor_;
}
if(c == SDLK_BACKSPACE && cursor_ > 0) {
--cursor_;
text_.erase(text_.begin()+cursor_);
if(cursor_ < firstOnScreen_)
--firstOnScreen_;
}
if(c == SDLK_DELETE && !text_.empty()) {
if(cursor_ == text_.size()) {
text_.resize(text_.size()-1);
--cursor_;
} else {
text_.erase(text_.begin()+cursor_);
}
}
const char character = static_cast<char>(key.unicode);
if(isgraph(character) || character == ' ') {
text_.insert(text_.begin()+cursor_,character);
++cursor_;
}
}
void textbox::set_position(int x, int y)
{
SDL_Rect rect = {x,y,location().w,location().h};
set_location(rect);
buffer_.assign(get_surface_portion(disp_.video().getSurface(),rect));
}
void textbox::set_width(int w)
{
SDL_Rect rect = location();
rect.w = w;
set_location(rect);
}
void textbox::set_focus(bool new_focus)
{
focus_ = new_focus;
}
}