widgets sources were moved.

This commit is contained in:
zas 2003-09-19 10:26:23 +00:00
parent 0ca41693ba
commit add635388c
6 changed files with 754 additions and 0 deletions

251
src/widgets/button.cpp Normal file
View file

@ -0,0 +1,251 @@
/* $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 "button.hpp"
#include "../font.hpp"
#include "../util.hpp"
namespace gui {
const int font_size = 14;
const int horizontal_padding = 10;
const int vertical_padding = 10;
button::button(display& disp, const std::string& label, button::TYPE type,
const std::string& button_image_name) :
label_(label), display_(&disp),
x_(0), y_(0), button_(true), state_(UNINIT),
image_(NULL), pressedImage_(NULL), type_(type)
{
SDL_Surface* button_image =
disp.getImage("buttons/button.png",display::UNSCALED);
SDL_Surface* pressed_image =
disp.getImage("buttons/button-pressed.png", display::UNSCALED);
SDL_Surface* active_image =
disp.getImage("buttons/button-active.png", display::UNSCALED);
if(!button_image_name.empty()) {
button_image = disp.getImage("buttons/" + button_image_name +
"-button.png", display::UNSCALED);
pressed_image = disp.getImage("buttons/" + button_image_name +
"-button-pressed.png",display::UNSCALED);
active_image = disp.getImage("buttons/" + button_image_name +
"-button-active.png",display::UNSCALED);
}
if(pressed_image == NULL)
pressed_image = button_image;
if(active_image == NULL)
active_image = button_image;
if(button_image == NULL)
throw error();
textRect_.x = 0;
textRect_.y = 0;
textRect_.w = 1024;
textRect_.h = 768;
textRect_ = font::draw_text(NULL,textRect_,font_size,
font::NORMAL_COLOUR,label_,0,0);
const int width = maximum(textRect_.w+horizontal_padding,button_image->w);
const int height = maximum(textRect_.h+horizontal_padding,button_image->h);
image_ = scale_surface(button_image,width,height);
pressedImage_ = scale_surface(pressed_image,width,height);
activeImage_ = scale_surface(active_image,width,height);
}
button::button(const button& b) : label_(b.label_), display_(b.display_),
image_(NULL), pressedImage_(NULL),
x_(b.x_), y_(b.y_), textRect_(b.textRect_),
button_(b.button_), state_(b.state_),
type_(b.type_)
{
image_ = scale_surface(b.image_,b.image_->w,b.image_->h);
pressedImage_ = scale_surface(b.pressedImage_,b.pressedImage_->w,
b.pressedImage_->h);
activeImage_ = scale_surface(b.activeImage_,b.activeImage_->w,
b.activeImage_->h);
}
button& button::operator=(const button& b)
{
if(image_ != NULL)
SDL_FreeSurface(image_);
if(pressedImage_ != NULL)
SDL_FreeSurface(pressedImage_);
label_ = b.label_;
display_ = b.display_;
image_ = scale_surface(b.image_,b.image_->w,b.image_->h);
pressedImage_ = scale_surface(b.pressedImage_,b.pressedImage_->w,
b.pressedImage_->h);
activeImage_ = scale_surface(b.activeImage_,b.activeImage_->w,
b.activeImage_->h);
x_ = b.x_;
y_ = b.y_;
textRect_ = b.textRect_;
button_ = b.button_;
state_ = b.state_;
type_ = b.type_;
return *this;
}
button::~button()
{
if(pressedImage_ != NULL)
SDL_FreeSurface(pressedImage_);
if(activeImage_ != NULL)
SDL_FreeSurface(activeImage_);
if(image_ != NULL)
SDL_FreeSurface(image_);
}
void button::set_check(bool check)
{
if(type_ == TYPE_CHECK)
state_ = check ? PRESSED : NORMAL;
}
bool button::checked() const
{
return state_ == PRESSED;
}
void button::draw()
{
SDL_Surface* image = image_;
int offset = 0;
switch(state_) {
case ACTIVE: image = activeImage_;
break;
case PRESSED: image = pressedImage_;
offset = 1;
break;
}
const SDL_Rect clipArea = {0,0,1024,768};
const int textx = x_ + image->w/2 - textRect_.w/2 + offset;
const int texty = y_ + image->h/2 - textRect_.h/2 + offset;
display_->blit_surface(x_,y_,image);
font::draw_text(display_,clipArea,font_size,
font::NORMAL_COLOUR,label_,textx,texty);
display_->video().update(x_,y_,width(),height());
}
bool button::hit(int x, int y) const
{
if(x > x_ && x < x_ + image_->w &&
y > y_ && y < y_ + image_->h) {
x -= x_;
y -= y_;
int row_width = image_->w;
if((row_width%2) == 1)
++row_width;
if(*(reinterpret_cast<short*>(image_->pixels)+y*row_width+x) != 0)
return true;
}
return false;
}
void button::set_x(int val) { x_ = val; }
void button::set_y(int val) { y_ = val; }
int button::width() const
{
return image_->w;
}
int button::height() const
{
return image_->h;
}
bool button::process(int mousex, int mousey, bool button)
{
enum MOUSE_STATE { UNCHANGED, UP, DOWN };
MOUSE_STATE mouse_state = UNCHANGED;
if(button && !button_)
mouse_state = DOWN;
else if(!button && button_)
mouse_state = UP;
button_ = button;
const STATE start_state = state_;
if(type_ == TYPE_PRESS) {
switch(state_) {
case UNINIT:
state_ = NORMAL;
break;
case NORMAL:
if(hit(mousex,mousey))
state_ = ACTIVE;
break;
case ACTIVE:
if(mouse_state == DOWN && hit(mousex,mousey))
state_ = PRESSED;
else if(!hit(mousex,mousey))
state_ = NORMAL;
break;
case PRESSED:
if(mouse_state == UP) {
if(hit(mousex,mousey)) {
state_ = ACTIVE;
draw();
return true;
} else {
state_ = NORMAL;
}
}
}
} else if(type_ == TYPE_CHECK) {
switch(state_) {
case NORMAL:
if(mouse_state == UP && hit(mousex,mousey)) {
state_ = PRESSED;
draw();
return true;
}
break;
case PRESSED:
if(mouse_state == UP && hit(mousex,mousey)) {
state_ = NORMAL;
draw();
return true;
}
break;
}
}
if(state_ != start_state) {
draw();
}
return false;
}
}

71
src/widgets/button.hpp Normal file
View file

@ -0,0 +1,71 @@
/* $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.
*/
#ifndef BUTTON_H_INCLUDED
#define BUTTON_H_INCLUDED
#include "SDL.h"
#include "../display.hpp"
#include <vector>
namespace gui {
class button
{
public:
struct error {};
enum TYPE { TYPE_PRESS, TYPE_CHECK };
button(display& disp, const std::string& label, TYPE type=TYPE_PRESS,
const std::string& button_image="");
button(const button& b);
button& operator=(const button& b);
~button();
void set_check(bool check);
bool checked() const;
void draw();
void set_x(int val);
void set_y(int val);
int width() const;
int height() const;
bool process(int mousex, int mousey, bool button);
private:
std::string label_;
display* display_;
SDL_Surface* image_, *pressedImage_, *activeImage_;
int x_, y_;
SDL_Rect textRect_;
bool button_;
enum STATE { UNINIT, NORMAL, ACTIVE, PRESSED };
STATE state_;
TYPE type_;
bool hit(int x, int y) const;
}; //end class button
}
#endif

146
src/widgets/slider.cpp Normal file
View file

@ -0,0 +1,146 @@
/* $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 "slider.hpp"
#include <algorithm>
#include <iostream>
namespace gui {
slider::slider(display& disp, SDL_Rect& rect, double value)
: disp_(disp), image_(disp.getImage("buttons/slider.png",display::UNSCALED)),
selectedImage_(disp.getImage("buttons/slider-selected.png",display::UNSCALED)),
area_(rect), buffer_(NULL), value_(value), drawn_(false),
clicked_(true), dragging_(false), highlight_(false)
{
background_changed();
if(selectedImage_ == NULL) {
std::cerr << "defaulting to normal image\n";
selectedImage_ = image_;
}
}
int slider::height(display& disp)
{
SDL_Surface* const image = disp.getImage("buttons/slider.png",
display::UNSCALED);
if(image != NULL)
return image->h;
else
return 0;
}
void slider::draw()
{
drawn_ = true;
SDL_Surface* const image = highlight_ ? selectedImage_ : image_;
if(image == NULL || buffer_.get() == NULL)
return;
const int hpadding = image->w/2;
if(hpadding*2 >= area_.w)
return;
SDL_Surface* const screen = disp_.video().getSurface();
SDL_BlitSurface(buffer_,NULL,screen,&area_);
display::Pixel* const pixels =
reinterpret_cast<display::Pixel*>(screen->pixels);
display::Pixel* const line_dest = pixels + screen->w*(area_.y+area_.h/3) +
area_.x + hpadding;
std::fill(line_dest,line_dest+area_.w-hpadding*2,0xFFFF);
SDL_Rect slider = slider_area();
disp_.blit_surface(slider.x,slider.y,image);
disp_.update_rect(area_);
}
double slider::process(int mousex, int mousey, bool button)
{
if(image_ == NULL)
return 0.0;
bool should_draw = !drawn_;
const SDL_Rect& hit_area = slider_area();
//std::cerr << mousex << ", " << mousey << ": " << hit_area.x << "-" << (hit_area.x+hit_area.w) << "," << hit_area.y << "-" << (hit_area.y+hit_area.h) << "\n";
const bool on = mousex > hit_area.x && mousex <= hit_area.x+hit_area.w &&
mousey > hit_area.y && mousey <= hit_area.y+hit_area.h;
if(on != highlight_) {
highlight_ = on;
should_draw = true;
}
const bool new_click = button && !clicked_;
if(new_click && on) {
dragging_ = true;
}
if(!button) {
dragging_ = false;
}
clicked_ = button;
double new_value = value_;
if(dragging_) {
new_value = double(mousex - (area_.x + image_->w/2))/
double(area_.w - image_->w);
if(new_value < 0.0)
new_value = 0.0;
if(new_value > 1.0)
new_value = 1.0;
}
if(should_draw || new_value != value_)
draw();
if(new_value != value_) {
value_ = new_value;
return value_;
} else {
return -1.0;
}
}
SDL_Rect slider::slider_area() const
{
static const SDL_Rect default_value = {0,0,0,0};
if(image_ == NULL)
return default_value;
const int hpadding = image_->w/2;
if(hpadding*2 >= area_.w)
return default_value;
const int position = int(value_*double(area_.w - hpadding*2));
const int xpos = area_.x + position;
SDL_Rect res = {xpos,area_.y,image_->w,image_->h};
return res;
}
void slider::background_changed()
{
if(image_ != NULL) {
area_.h = image_->h;
buffer_.assign(get_surface_portion(disp_.video().getSurface(),area_));
}
}
}

56
src/widgets/slider.hpp Normal file
View file

@ -0,0 +1,56 @@
/* $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.
*/
#ifndef SLIDER_HPP_INCLUDED
#define SLIDER_HPP_INCLUDED
#include "SDL.h"
#include "../display.hpp"
#include "../sdl_utils.hpp"
#include <vector>
namespace gui {
class slider
{
display& disp_;
SDL_Surface* image_, *selectedImage_;
scoped_sdl_surface buffer_;
SDL_Rect area_;
double value_;
bool drawn_;
bool highlight_, clicked_, dragging_;
SDL_Rect slider_area() const;
public:
slider(display& disp, SDL_Rect& rect, double value);
static int height(display& disp);
void draw();
double process(int mousex, int mousey, bool button);
const SDL_Rect& area() const;
void background_changed();
};
}
#endif

172
src/widgets/textbox.cpp Normal file
View file

@ -0,0 +1,172 @@
/* $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 "SDL.h"
#include <algorithm>
#include <cctype>
namespace gui {
const int font_size = 16;
textbox::textbox(display& disp, int width, const std::string& text)
: disp_(disp), text_(text), firstOnScreen_(0),
cursor_(text.size()), height_(-1), width_(width), x_(-1), y_(-1),
lastLArrow_(false), lastRArrow_(false),
lastDelete_(false), lastBackspace_(false), buffer_(NULL)
{
std::fill(previousKeyState_,
previousKeyState_+CHAR_LENGTH,false);
static const SDL_Rect area = {0,0,1024,768};
height_ = font::draw_text(NULL,area,font_size,font::NORMAL_COLOUR,
"ABCD",0,0).h;
}
int textbox::height() const
{
return height_;
}
int textbox::width() const
{
return width_;
}
const std::string& textbox::text() const
{
return text_;
}
void textbox::draw_cursor(int pos) const
{
const bool show_cursor = (SDL_GetTicks()%1000) > 500;
static const short cursor_colour = 0xFFFF;
if(show_cursor) {
short* dst = reinterpret_cast<short*>(
disp_.video().getSurface()->pixels) + y_*disp_.x() +
x_ + pos;
for(int i = 0; i != height(); ++i, dst += disp_.x()) {
*dst = cursor_colour;
}
}
}
void textbox::draw() const
{
if(x_ == -1)
return;
if(buffer_.get() != NULL) {
SDL_Rect rect = { x_, y_, width(), height() };
SDL_BlitSurface(buffer_,NULL,disp_.video().getSurface(),&rect);
}
if(cursor_ == 0)
draw_cursor(0);
int pos = 1;
std::string str(1,'x');
static const SDL_Rect clip = {0,0,1024,768};
//draw the text
for(int 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);
//if we can't fit the next character on screen
if(pos + area.w > width()) {
break;
}
font::draw_text(&disp_,clip,font_size,font::NORMAL_COLOUR,str,
x_ + pos, y_);
pos += area.w;
if(cursor_ == i+1)
draw_cursor(pos-1);
}
disp_.video().update(x_,y_,width(),height());
}
void textbox::process()
{
if(key_[KEY_LEFT] && !lastLArrow_ && cursor_ > 0) {
--cursor_;
if(cursor_ < firstOnScreen_)
--firstOnScreen_;
}
if(key_[KEY_RIGHT] && !lastRArrow_ && cursor_ < text_.size()) {
++cursor_;
}
if(key_[KEY_BACKSPACE] && !lastBackspace_ && cursor_ > 0) {
--cursor_;
text_.erase(text_.begin()+cursor_);
if(cursor_ < firstOnScreen_)
--firstOnScreen_;
}
if(key_[KEY_DELETE] && !lastDelete_ && !text_.empty()) {
if(cursor_ == text_.size()) {
text_.resize(text_.size()-1);
--cursor_;
} else {
text_.erase(text_.begin()+cursor_);
}
}
lastLArrow_ = key_[KEY_LEFT];
lastRArrow_ = key_[KEY_RIGHT];
lastBackspace_ = key_[KEY_BACKSPACE];
lastDelete_ = key_[KEY_DELETE];
for(char c = INPUT_CHAR_START; c != INPUT_CHAR_END; ++c) {
char character = c;
if(islower(character) && (key_[KEY_LSHIFT] || key_[KEY_RSHIFT])) {
character = toupper(character);
}
const bool val = key_[c];
if(val && !previousKeyState_[c-INPUT_CHAR_START]) {
text_.insert(text_.begin()+cursor_,character);
++cursor_;
}
previousKeyState_[c-INPUT_CHAR_START] = val;
}
draw();
}
void textbox::set_location(int x, int y)
{
x_ = x;
y_ = y;
SDL_Rect portion;
portion.x = x_;
portion.y = y_;
portion.w = width();
portion.h = height();
buffer_.assign(get_surface_portion(disp_.video().getSurface(),portion));
}
}

58
src/widgets/textbox.hpp Normal file
View file

@ -0,0 +1,58 @@
/* $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.
*/
#ifndef TEXTBOX_HPP_INCLUDED
#define TEXTBOX_HPP_INCLUDED
#include "../display.hpp"
#include "../key.hpp"
#include "../sdl_utils.hpp"
namespace gui {
#define INPUT_CHAR_START (' ')
#define INPUT_CHAR_END ('~' + 1)
#define CHAR_LENGTH (INPUT_CHAR_END - INPUT_CHAR_START)
class textbox
{
display& disp_;
std::string text_;
unsigned int firstOnScreen_, cursor_;
int height_, width_;
scoped_sdl_surface buffer_;
int x_, y_;
CKey key_;
bool previousKeyState_[CHAR_LENGTH];
bool lastLArrow_, lastRArrow_, lastDelete_, lastBackspace_;
void draw_cursor(int pos) const;
public:
textbox(display& disp, int width, const std::string& text="");
int height() const;
int width() const;
const std::string& text() const;
void draw() const;
void process();
void set_location(int x, int y);
};
}
#endif