Project::OSiRiON - Git repositories
Project::OSiRiON
News . About . Screenshots . Downloads . Forum . Wiki . Tracker . Git
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/client/chat.cc202
-rw-r--r--src/client/chat.h46
-rw-r--r--src/client/client.cc28
-rw-r--r--src/client/client.h6
-rw-r--r--src/client/console.cc2
-rw-r--r--src/client/input.cc61
-rw-r--r--src/client/keyboard.cc21
-rw-r--r--src/client/keyboard.h8
-rw-r--r--src/client/video.cc148
-rw-r--r--src/client/video.h25
-rw-r--r--src/client/view.cc170
-rw-r--r--src/client/view.h9
-rw-r--r--src/render/camera.cc22
-rw-r--r--src/render/camera.h21
-rw-r--r--src/render/draw.cc5
-rw-r--r--src/render/render.cc207
-rw-r--r--src/render/render.h3
-rw-r--r--src/ui/Makefile.am6
-rw-r--r--src/ui/bitmap.cc11
-rw-r--r--src/ui/bitmap.h33
-rw-r--r--src/ui/button.cc32
-rw-r--r--src/ui/button.h45
-rw-r--r--src/ui/container.h36
-rw-r--r--src/ui/definitions.h7
-rw-r--r--src/ui/font.cc13
-rw-r--r--src/ui/font.h51
-rw-r--r--src/ui/input.cc174
-rw-r--r--src/ui/input.h55
-rw-r--r--src/ui/label.cc13
-rw-r--r--src/ui/label.h38
-rw-r--r--src/ui/menu.cc47
-rw-r--r--src/ui/menu.h22
-rw-r--r--src/ui/paint.cc66
-rw-r--r--src/ui/paint.h12
-rw-r--r--src/ui/palette.cc16
-rw-r--r--src/ui/palette.h51
-rw-r--r--src/ui/ui.cc191
-rw-r--r--src/ui/ui.h99
-rw-r--r--src/ui/widget.cc253
-rw-r--r--src/ui/widget.h330
-rw-r--r--src/ui/window.cc9
-rw-r--r--src/ui/window.h24
42 files changed, 1607 insertions, 1011 deletions
diff --git a/src/client/chat.cc b/src/client/chat.cc
index 6f63a6d..bdeebe2 100644
--- a/src/client/chat.cc
+++ b/src/client/chat.cc
@@ -5,129 +5,86 @@
*/
#include "auxiliary/functions.h"
-#include "core/core.h"
#include "client/chat.h"
+#include "client/client.h"
#include "client/console.h"
-#include "client/keyboard.h"
-#include "client/video.h"
+#include "core/core.h"
#include "render/render.h"
+#include "sys/sys.h"
+#include "ui/ui.h"
namespace client {
-namespace chat {
-
-// input history
-std::deque<std::string> history;
-std::deque<std::string>::reverse_iterator history_pos;
-size_t input_pos = 0;
-
-// chatbox visibility
-bool chat_visible = false;
-
-//--- public ------------------------------------------------------
-
-void init()
+Chat::Chat(ui::Widget *parent) : ui::Widget(parent)
{
- // add engine functions
+ set_label("chat");
history.clear();
history.push_back("");
history_pos = history.rbegin();
- input_pos = 0;
+
+ chat_label = new ui::Label(this, "^BSay^F:^B");
+ chat_label->set_alignment(ui::AlignLeft | ui::AlignVCenter);
+
+ chat_input = new ui::Input(this);
+ chat_input->set_border(true);
+
+ chat_input->set_focus();
+
+ set_background(true);
+ set_visible(false);
}
-void shutdown()
+Chat::~Chat()
{
history.clear();
- input_pos = 0;
}
-bool visible()
-{
- return chat_visible;
-}
-void draw()
+void Chat::show()
{
- using namespace render;
-
- if (console()->visible() || !visible())
- return;
+ Widget::show();
- size_t width = (size_t) (video::width / Text::fontwidth()) - 8;
- float y = video::height*8/10;
- Text::draw(4, y, "^BSay^F:^B ");
+ raise();
+ set_focus();
- std::string firstpart((*history_pos).substr(0, input_pos));
- size_t draw_width = 0;
- const char *c = firstpart.c_str();
-
- while (*c) {
- if (aux::is_color_code(c)) {
- c++;
- } else {
- draw_width++;
- }
- c++;
- }
-
- c = firstpart.c_str();
- while (*c && draw_width > width - 2) {
- if (aux::is_color_code(c)) {
- c++;
- Text::setcolor(*c);
- } else {
- draw_width--;
- }
- c++;
- }
-
- if (*c) {
- Text::draw(4+5*Text::fontwidth(), y, c);
- }
-
- if (input_pos < (*history_pos).size()) {
- // FIXME limit to width
- if (input_pos > 1 && aux::is_color_code((*history_pos).c_str() + input_pos -1)) {
- Text::setcolor((*history_pos)[input_pos]);
- }
- c = (*history_pos).c_str() + input_pos;
- Text::draw(4+Text::fontwidth()*(draw_width+5), y, c);
- }
+ history_pos = history.rbegin();
+ (*history_pos).clear();
+ chat_input->set_text((*history_pos));
+}
- // draw cursor
- if ((core::application()->time() - ::floorf(core::application()->time())) < 0.5f) {
- std::string cursor("^B");
- cursor += (char) 11;
- Text::draw(4+Text::fontwidth()*(draw_width+5), y , cursor);
- }
+void Chat::toggle()
+{
+ if (visible())
+ hide();
+ else
+ show();
}
-void toggle()
+void Chat::resize()
{
- chat_visible = !chat_visible;
- if (chat_visible) {
- input_pos = 0;
- history_pos = history.rbegin();
- (*history_pos).clear();
- }
+ chat_label->set_location(font()->width(), height() / 5.0f);
+ chat_label->set_size(width() - font()->width() * 2, height() / 5.0f);
- setkeyboardmode(console()->visible() || (core::application()->connected() && chat::visible()));
+ chat_input->set_location(font()->width(), height() / 5.0f * 3.0f);
+ chat_input->set_size(width() - font()->width() * 2, height() / 5.0f);
}
-void keypressed(unsigned int key)
+bool Chat::on_keypress(const int key, const unsigned int modifier)
{
- std::deque<std::string>::reverse_iterator upit;
+ History::reverse_iterator upit;
switch( key ) {
case SDLK_ESCAPE:
- toggle();
- break;
+ if (visible()) {
+ hide();
+ return true;
+ } else {
+ return false;
+ }
+ case SDLK_RETURN:
+ if (chat_input->text().size()) {
+ (*history_pos).assign(chat_input->text());
- case SDLK_TAB:
- core::CommandBuffer::complete( (*history_pos), input_pos);
- break;
- case SDLK_RETURN:
- if ((*history_pos).size()) {
// store input into history
while (history.size() >= MAXHISTOLINES) {
history.pop_front();
@@ -142,61 +99,46 @@ void keypressed(unsigned int key)
history.push_back("");
history_pos = history.rbegin();
- input_pos = 0;
+ chat_input->set_text((*history_pos));
}
- toggle();
+
+ hide();
+ return true;
break;
+
case SDLK_UP:
upit = history_pos;
++upit;
if (upit != history.rend()) {
history_pos = upit;
- input_pos = (*history_pos).size();
+ chat_input->set_text((*history_pos));
}
+ return true;
break;
+
case SDLK_DOWN:
if (history_pos != history.rbegin()) {
--history_pos;
- input_pos = (*history_pos).size();
- }
- break;
- case SDLK_HOME:
- input_pos = 0;
- break;
- case SDLK_END:
- input_pos = (*history_pos).size();
- break;
- case SDLK_LEFT:
- if (input_pos > 0)
- input_pos--;
- break;
- case SDLK_RIGHT:
- if (input_pos < (*history_pos).size())
- input_pos++;
- break;
- case SDLK_DELETE:
- if ((*history_pos).size() && input_pos < (*history_pos).size()) {
- (*history_pos).erase(input_pos, 1);
- }
- break;
- case SDLK_BACKSPACE:
- if ((*history_pos).size() && input_pos) {
- (*history_pos).erase(input_pos-1, 1);
- input_pos--;
- }
- break;
- default:
- if ((key >= 32 ) && (key <175)) {
- if (input_pos == (*history_pos).size())
- (*history_pos) += (char)key;
- else
- (*history_pos).insert(input_pos, 1, (char)key);
- input_pos++;
+ chat_input->set_text((*history_pos));
}
+ return true;
break;
}
-}
+ return false;
}
+void Chat::event_draw()
+{
+ if (!client()->connected()) {
+ hide();
+ return;
+ }
+
+ if (ui::root()->active())
+ return;
+ else
+ Widget::event_draw();
}
+
+} // namespace client
diff --git a/src/client/chat.h b/src/client/chat.h
index fdf4c70..0bef2b4 100644
--- a/src/client/chat.h
+++ b/src/client/chat.h
@@ -7,35 +7,43 @@
#ifndef __INCLUDED_CLIENT_CHAT_H__
#define __INCLUDED_CLIENT_CHAT_H__
-#include "sys/consoleinterface.h"
-
#include <sstream>
#include <deque>
-namespace client {
+#include "ui/input.h"
+#include "ui/label.h"
+#include "ui/window.h"
-/// the client chatbox
-namespace chat {
+namespace client {
-/// initialize chatbox functions
-void init();
+class Chat : public ui::Widget
+{
+public:
+ Chat(ui::Widget *parent = 0);
+ ~Chat();
-/// shut down chatbox functions
-void shutdown();
+ virtual void show();
+ void toggle();
-/// draw the chatbox
-void draw();
+protected:
+ virtual void event_draw();
+ virtual void resize();
+
+ virtual bool on_keypress(const int key, const unsigned int modifier);
+
-/// toggle the chatbox
-void toggle();
+private:
+ ui::Label *chat_label;
+ ui::Input *chat_input;
+
+ typedef std::deque<std::string> History;
+
+ History history;
+ History::reverse_iterator history_pos;
+};
-/// handle keyboard input
-void keypressed(unsigned int key);
-/// true of the console is visible
-bool visible();
-}
+} // namespace client
-}
#endif // __INCLUDED_CLIENT_CHAT_H__
diff --git a/src/client/client.cc b/src/client/client.cc
index 3f368a7..ac4c0e3 100644
--- a/src/client/client.cc
+++ b/src/client/client.cc
@@ -12,7 +12,6 @@
#include "audio/audio.h"
#include "audio/sources.h"
-#include "client/chat.h"
#include "client/client.h"
#include "client/video.h"
#include "client/console.h"
@@ -52,6 +51,13 @@ void func_r_restart(std::string const &args)
video::restart();
}
+void func_ui_chat(std::string const &args)
+{
+ if (core::application()->connected()) {
+ client()->view()->chat()->toggle();
+ }
+}
+
//--- public ------------------------------------------------------
void client_main(int count, char **arguments)
@@ -108,16 +114,13 @@ void Client::init(int count, char **arguments)
// initialize user interface
ui::init();
- new View(ui::root());
+ client_view = new View(ui::root());
// Initialize the video subsystem
if (!video::init()) {
quit(1);
}
- // initialize console
- chat::init();
-
// initialize input
input::init();
@@ -129,9 +132,12 @@ void Client::init(int count, char **arguments)
func = core::Func::add("r_restart", (core::FuncPtr) func_r_restart);
func->set_info("restart render subsystem");
+
+ func = core::Func::add("ui_chat", func_ui_chat);
+ func->set_info("toggle chat window");
- func = core::Func::add("snd_restart", (core::FuncPtr) func_snd_restart);
- func->set_info("restart audio subsystem");
+ //func = core::Func::add("snd_restart", (core::FuncPtr) func_snd_restart);
+ //func->set_info("restart audio subsystem");
}
void Client::run()
@@ -215,10 +221,8 @@ void Client::shutdown()
if (connected()) disconnect();
core::Func::remove("r_restart");
-
- core::Func::remove("snd_restart");
-
- chat::shutdown();
+ core::Func::remove("ui_chat");
+ //core::Func::remove("snd_restart");
audio::shutdown();
@@ -245,8 +249,8 @@ void Client::notify_connect()
void Client::notify_disconnect()
{
// FIXME unload sounds
- //audio::reset();
render::reset();
+ input::reset();
}
void Client::notify_zonechange()
diff --git a/src/client/client.h b/src/client/client.h
index bd7af6b..dc70e16 100644
--- a/src/client/client.h
+++ b/src/client/client.h
@@ -8,6 +8,7 @@
#define __INCLUDED_CLIENT_H__
#include "core/application.h"
+#include "client/view.h"
/// client part of the engine
namespace client {
@@ -46,10 +47,15 @@ public:
/// disconnect notification
virtual void notify_disconnect();
+ /// the main client view
+ inline View *view() { return client_view; }
+
protected:
/// run a client frame
virtual void frame(float seconds);
+private:
+ View *client_view;
};
diff --git a/src/client/console.cc b/src/client/console.cc
index 96da900..47f95f7 100644
--- a/src/client/console.cc
+++ b/src/client/console.cc
@@ -92,7 +92,7 @@ void Console::toggle()
SDL_ShowCursor(SDL_DISABLE);
}
- setkeyboardmode(console()->visible() || (core::application()->connected() && chat::visible()));
+ //setkeyboardmode(console()->visible() || (core::application()->connected() && chat::visible()));
audio::play("ui/console");
}
diff --git a/src/client/input.cc b/src/client/input.cc
index d2a53e1..d2c290b 100644
--- a/src/client/input.cc
+++ b/src/client/input.cc
@@ -108,7 +108,7 @@ float joystick_lastmoved_time()
void func_screenshot(std::string const & args)
{
- video::screenshot();
+ render::screenshot();
}
void func_ui_control(std::string const &args)
@@ -138,13 +138,6 @@ void func_ui_console(std::string const &args)
console()->toggle();
}
-void func_ui_chat(std::string const &args)
-{
- if (core::application()->connected()) {
- chat::toggle();
- }
-}
-
void func_view_next(std::string const &args)
{
if (core::application()->connected() && core::localcontrol()) {
@@ -256,8 +249,6 @@ void init()
keyboard = new Keyboard();
- client::setkeyboardmode(false);
-
SDL_ShowCursor(SDL_DISABLE);
SDL_WM_GrabInput(SDL_GRAB_ON);
// SDL_EnableUNICODE(1);
@@ -280,8 +271,8 @@ void init()
func = core::Func::add("ui_console", func_ui_console);
func->set_info("toggle console on or off");
- func = core::Func::add("ui_chat", func_ui_chat);
- func->set_info("toggle chatbox on or of");
+ //func = core::Func::add("ui_chat", func_ui_chat);
+ //func->set_info("toggle chatbox on or of");
func = core::Func::add("ui_control",func_ui_control);
func->set_info("toggle mouse control");
@@ -333,8 +324,8 @@ void shutdown()
core::Func::remove("screenshot");
core::Func::remove("ui_console");
- core::Func::remove("ui_control");
- core::Func::remove("ui_chat");
+ //core::Func::remove("ui_control");
+ //core::Func::remove("ui_chat");
core::Func::remove("ui_view");
keyboard->save_binds();
@@ -498,21 +489,37 @@ Key::Modifier convert_SDL_modifier(int const sdlmodifier)
void key_pressed(Key *key)
{
+ ui::root()->input_key(true, Keyboard::translate_keysym(key->sym(), keyboard_modifiers), keyboard_modifiers);
if (key->sym() == SDLK_ESCAPE) {
- if (chat::visible()) {
- chat::toggle();
- } else {
+
+ if (console()->visible()) {
+ console()->toggle();
local_direction = 0.0f;
local_pitch = 0.0f;
local_roll = 0.0f;
-
+
render::Camera::set_direction(0.0f);
render::Camera::set_pitch(0.0f);
- console()->toggle();
+ } else {
+ if (ui::root()->active()) {
+ ui::root()->hide_window();
+ local_direction = 0.0f;
+ local_pitch = 0.0f;
+ local_roll = 0.0f;
+
+ render::Camera::set_direction(0.0f);
+ render::Camera::set_pitch(0.0f);
+ } else {
+ if (core::application()->connected()) {
+ ui::root()->show_window("game");
+ } else {
+ ui::root()->show_window("main");
+ }
+ }
}
-
+
} else if (key->bind(Key::None).compare("ui_console") == 0) {
local_direction = 0.0f;
local_pitch = 0.0f;
@@ -526,16 +533,16 @@ void key_pressed(Key *key)
} else if (console()->visible()) {
// send key events to the console
if (key->sym() < 512)
- console()->keypressed(translate_keysym(key->sym(), keyboard_modifiers));
+ console()->keypressed(Keyboard::translate_keysym(key->sym(), keyboard_modifiers));
} else if (ui::root()->active()) {
- ui::root()->input_key(true, key->sym(), keyboard_modifiers);
-
- } else if (chat::visible()) {
+/* ui::root()->input_key(true, key->sym(), keyboard_modifiers);
+*/
+/* } else if (chat::visible()) {
// send key events to the chat box
if (key->sym() < 512)
chat::keypressed(translate_keysym(key->sym(), keyboard_modifiers));
-
+*/
} else if (core::application()->connected() && core::localcontrol()) {
char c = key->bind(convert_SDL_modifier(keyboard_modifiers)).c_str()[0];
@@ -559,9 +566,7 @@ void key_pressed(Key *key)
void key_released(Key *key)
{
- if (ui::root()->active()) {
- ui::root()->input_key(false, key->sym(), keyboard_modifiers);
- }
+ ui::root()->input_key(false, Keyboard::translate_keysym(key->sym(), keyboard_modifiers), keyboard_modifiers);
if (core::application()->connected() && core::localcontrol()) {
diff --git a/src/client/keyboard.cc b/src/client/keyboard.cc
index b420fb8..80e0d5c 100644
--- a/src/client/keyboard.cc
+++ b/src/client/keyboard.cc
@@ -515,16 +515,7 @@ void Keyboard::list_binds()
con_print << n << " registered binds" << std::endl;
}
-void setkeyboardmode(bool input)
-{
- /* if(input)
- SDL_EnableKeyRepeat(250, SDL_DEFAULT_REPEAT_INTERVAL);
- else
- SDL_EnableKeyRepeat(10, SDL_DEFAULT_REPEAT_INTERVAL);
- */
-}
-
-unsigned int translate_keysym(int keysym, int modifier)
+unsigned int Keyboard::translate_keysym(int keysym, int modifier)
{
bool shift = false;
@@ -715,4 +706,14 @@ unsigned int translate_keysym(int keysym, int modifier)
return keysym;
}
+/*
+void setkeyboardmode(bool input)
+{
+ if(input)
+ SDL_EnableKeyRepeat(250, SDL_DEFAULT_REPEAT_INTERVAL);
+ else
+ SDL_EnableKeyRepeat(10, SDL_DEFAULT_REPEAT_INTERVAL);
+
+}
+*/
} // namespace client
diff --git a/src/client/keyboard.h b/src/client/keyboard.h
index 87a67c4..f63bce1 100644
--- a/src/client/keyboard.h
+++ b/src/client/keyboard.h
@@ -69,6 +69,9 @@ public:
inline iterator end() { return keys.end(); }
+ /// convert SDL_keysym to a keystroke
+ static unsigned int translate_keysym(int keysym, int modifier);
+
private:
Key *add_key(const char *name, const unsigned int keysym, const char ascii=0, const char *bind=0);
@@ -81,13 +84,10 @@ private:
bool capslock;
};
-/// convert SDL_keysym to a keystroke
-unsigned int translate_keysym(int keysym, int modifier);
-
/// set the keyboard input mode
/** @param input true for console input, false for game input
*/
-void setkeyboardmode(bool input);
+//void setkeyboardmode(bool input);
}
diff --git a/src/client/video.cc b/src/client/video.cc
index 123bd88..7338d70 100644
--- a/src/client/video.cc
+++ b/src/client/video.cc
@@ -4,10 +4,6 @@
the terms and conditions of the GNU General Public License version 2
*/
-#include <fstream>
-#include <sstream>
-
-#include "auxiliary/functions.h"
#include "client/video.h"
#include "client/input.h"
#include "client/view.h"
@@ -38,49 +34,15 @@ int height = 0;
int width_prev = 0;
int height_prev = 0;
-int screenshot_number = 0;
-
const int width_default = 1024;
const int height_default = 768;
-//--- cvars -------------------------------------------------------
+/* -- engine variables --------------------------------------------- */
core::Cvar *r_width;
core::Cvar *r_height;
core::Cvar *r_fullscreen;
-core::Cvar *screenshotformat;
-core::Cvar *screenshotquality;
-
-void restart()
-{
- shutdown();
-
- if (!init()) {
- client()->quit(1);
- }
-
- input::reset();
-}
-
-void reset()
-{
- // setup our viewport.
- gl::viewport(0, 0, width, height );
-
- // recalculate the video aspect
- render::Camera::set_aspect(width, height);
-
- // resize user interface
- if (ui::root()) {
- ui::root()->set_size((float) width, (float) height);
- ui::root()->event_resize();
- }
-
- // reset the view
- view::reset();
-}
-
bool init()
{
con_print << "^BInitializing video..." << std::endl;
@@ -95,12 +57,6 @@ bool init()
r_fullscreen = core::Cvar::get("r_fullscreen", "0", core::Cvar::Archive);
r_fullscreen->set_info("[bool] enable or disable fullscreen video");
- screenshotformat = core::Cvar::get("screenshotformat", "jpg", core::Cvar::Archive);
- screenshotformat->set_info("[string] screenshot format: jpg png tga");
-
- screenshotquality = core::Cvar::get("screenshotquality", "85", core::Cvar::Archive);
- screenshotquality->set_info("[int] screenshot jpg quality");
-
int bpp = 0;
int flags = 0;
@@ -162,7 +118,7 @@ bool init()
} else
return false;
}
- con_print << " video mode " << width << "x" << height << "x" << bpp << "bpp" << std::endl;
+ con_print << " video mode " << width << "x" << height << "x" << bpp << "bpp " << (fullscreen ? "fullscreen " : "window") << std::endl;
#ifdef HAVE_DEBUG_MESSAGES
@@ -178,24 +134,40 @@ bool init()
#endif // HAVE_DEBUG_MESSAGES
- render::Camera::set_aspect(width, height);
+ // save r_width and r_height variables
(*r_width) = width;
(*r_height) = height;
+ // set window caption
std::string version(core::name());
version += ' ';
version.append(core::version());
SDL_WM_SetCaption(version.c_str(), 0);
- render::init();
+ // resize user interface
+ ui::root()->set_size((float) width, (float) height);
+ ui::root()->event_resize();
- video::reset();
+ // initialize renderer
+ render::Camera::resize(width, height);
+ render::init();
+ render::Camera::resize(width, height); // yes twice, bug
view::init();
return true;
}
+void restart()
+{
+ shutdown();
+ if (!init()) {
+ client()->quit(1);
+ }
+
+ input::reset();
+}
+
void frame(float seconds)
{
// detect fullscreen/windowed mode switch
@@ -222,84 +194,6 @@ void shutdown()
SDL_QuitSubSystem(SDL_INIT_VIDEO);
}
-void screenshot()
-{
- bool available = false;
- std::string shortname;
- std::string filename;
- const int TYPETGA = 0;
- const int TYPEPNG = 1;
- const int TYPEJPG = 2;
- int filetype = TYPETGA;
-
- // make sure the screenshots folder exists
- filename.assign(filesystem::writedir());
- filename.append("screenshots/");
- sys::mkdir(filename);
-
- aux::lowercase(screenshotformat->str());
-
- if ((screenshotformat->str().compare("jpg") == 0) || (screenshotformat->str().compare("jpeg") == 0)) {
- filetype = TYPEJPG;
- if (screenshotquality->value() < 10) {
- (*screenshotquality) = 10;
- } else if (screenshotquality->value() > 100) {
- (*screenshotquality) = 100;
- }
-
- } else if (screenshotformat->str().compare("png") == 0) {
- filetype = TYPEPNG;
-
- } else if (screenshotformat->str().compare("tga") == 0) {
- filetype = TYPETGA;
-
- } else {
- filetype = TYPETGA;
- (*screenshotformat) = "tga";
- }
-
- // find the first available screenshotxxxx
- do {
- std::stringstream nstr;
- nstr << screenshot_number;
- shortname.assign(nstr.str());
-
- while(shortname.size() < 4)
- shortname.insert(0, 1, '0');
-
- shortname.insert(0, "screenshots/osirion");
- shortname.append(".");
- shortname.append(screenshotformat->str());
-
- filename.assign(filesystem::writedir());
- filename.append(shortname);
-
- FILE *handle = fopen(filename.c_str(), "r");
- if (handle) {
- fclose(handle);
- } else {
- available = true;
- }
- screenshot_number++;
- } while (!available);
-
- render::Image image((unsigned int)video::width, (unsigned int)video::height, 3);
-
- glReadPixels(0, 0, (GLsizei) video::width, (GLsizei) video::height,
- GL_RGB, GL_UNSIGNED_BYTE, (void *) image.data());
-
- image.flip();
-
- if (filetype == TYPEPNG) {
- render::PNG::save(filename.c_str(), image);
- } else if (filetype == TYPEJPG) {
- render::JPG::save(filename.c_str(), image, (int) screenshotquality->value());
- } else if (filetype == TYPETGA) {
- render::TGA::save(filename.c_str(), image);
- }
-}
-
-
} // namespace video
} // namespace client
diff --git a/src/client/video.h b/src/client/video.h
index 59939e6..daa136c 100644
--- a/src/client/video.h
+++ b/src/client/video.h
@@ -9,31 +9,28 @@
namespace client {
-/// the client video subsystem
+/// the video subsystem
namespace video
{
- /// initialize the client video subsystem
+ /// initialize the video subsystem
bool init();
- /// shutdown the client video subsystem
+ /// shutdown the video subsystem
void shutdown();
- /// draw the next client video frame
- void frame(float seconds);
-
- /// reset and clear the viewport
- void reset();
-
- /// restart the video subsystem
+ /// re-initialize the video subsystems
+ /** the restart functions performs a full shutdown
+ * and re-initializes the video subsystem
+ */
void restart();
- /// make a screenshot
- void screenshot();
+ /// draw the next client video frame
+ void frame(float seconds);
- /// width of the window in pixels
+ /// width of the application window in pixels
extern int width;
- /// height of the window in pixels
+ /// height of the application window in pixels
extern int height;
} // namespace video
diff --git a/src/client/view.cc b/src/client/view.cc
index 15f70bc..463d254 100644
--- a/src/client/view.cc
+++ b/src/client/view.cc
@@ -38,6 +38,15 @@ core::Cvar *draw_keypress = 0;
core::Cvar *ui_pointercolor = 0;
core::Cvar *ui_pointerhovercolor = 0;
+const float pointer_size = 48.0f;
+
+void time_to_stream(std::stringstream &str, float time)
+{
+ int minutes = (int) floorf(time / 60.0f);
+ int seconds = (int) floorf( time - (float) minutes* 60.0f);
+ str << std::setfill(' ') << std::setw(4) << minutes << ":" << std::setfill('0') << std::setw(2) << seconds;
+}
+
/* -- DevInfo------------------------------------------------------- */
DevInfo::DevInfo(ui::Widget *parent) : ui::Widget(parent)
@@ -54,24 +63,27 @@ void DevInfo::draw()
core::Entity *target = targets::current();
float d = 0;
- textstream << "^Ntime: ^B" << std::fixed << std::setprecision(4) << client()->time() << '\n';
+ textstream << "^Ncore ^B";
+ time_to_stream(textstream, core::application()->time());
+ textstream << '\n';
if (core::game()) {
- textstream << "^Ngame: ^B" << core::game()->time();
+ textstream << "^Ntime ^B";
+ time_to_stream(textstream, core::game()->time());
}
textstream << '\n';
if (core::localcontrol()) {
textstream << std::fixed << std::setprecision(2)
- << "^Nx:^B" << core::localcontrol()->location().x << " "
- << "^Ny:^B" << core::localcontrol()->location().y << " "
- << "^Nz:^B" << core::localcontrol()->location().z << '\n';
+ << "^Nx ^B" << core::localcontrol()->location().x << " "
+ << "^Ny ^B" << core::localcontrol()->location().y << " "
+ << "^Nz ^B" << core::localcontrol()->location().z << '\n';
- textstream << "^Nthurst:^B " << core::localcontrol()->thrust() << " "
- << "^Nspeed:^B " << core::localcontrol()->speed() << '\n';
+ textstream << "^Nthurst ^B" << core::localcontrol()->thrust() << " "
+ << "^Nspeed ^B" << core::localcontrol()->speed() << '\n';
if (target) {
d = math::distance(core::localcontrol()->location(), target->state()->location()) - target->radius() - core::localcontrol()->radius();
- textstream << "^Ndist:^B " << d << '\n';
+ textstream << "^Ndist ^B" << d << '\n';
}
}
@@ -114,10 +126,8 @@ void Stats::draw()
std::stringstream textstream;
if (core::game()) {
- int minutes = (int) floorf(core::game()->clientframetime() / 60.0f);
- int seconds = (int) floorf( core::game()->clientframetime() - (float) minutes* 60.0f);
-
- textstream << "^Ntime ^B" << std::setfill(' ') << std::setw(3) << minutes << ":" << std::setfill('0') << std::setw(2) << seconds;
+ textstream << "^Ntime ^B";
+ time_to_stream(textstream, core::game()->clientframetime());
}
textstream << std::setfill(' ') << "\n";
@@ -183,10 +193,13 @@ View::View(ui::Widget *parent) : ui::Widget(parent)
draw_keypress->set_info("[bool] draw keypress key names");
// add child widgets
+ view_center = new ui::Bitmap(this, "pointers/center");
view_devinfo = new DevInfo(this);
view_stats = new Stats(this);
view_keypress = new KeyPress(this);
+ view_chat = new Chat(this);
+
// make sure the view is at the bottom of the draw stack
lower();
}
@@ -195,6 +208,10 @@ void View::resize()
{
set_size(parent()->size());
+ // reposition chat widget
+ view_chat->set_size(font()->width()*64, font()->height()*5);
+ view_chat->set_location(font()->width() * 0.5f, height() *0.5f);
+
// reposition devinfo widget
view_devinfo->set_size(font()->width()*32, font()->height()*5);
view_devinfo->set_location(font()->width() * 0.5f, font()->height() * 0.5f);
@@ -207,6 +224,11 @@ void View::resize()
view_keypress->set_size(font()->width()*12, font()->height()*1);
view_keypress->set_location(width() - view_keypress->width() - font()->width() * 0.5,
height() - view_keypress->height() - font()->height() * 0.5f);
+
+ // reposition center
+ view_center->set_size(pointer_size, pointer_size);
+ view_center->set_location((size() - view_center->size()) * 0.5f);
+ view_center->set_color(palette()->pointer());
}
void View::draw()
@@ -214,8 +236,19 @@ void View::draw()
view_devinfo->set_visible(draw_devinfo->value() ? true : false);
view_stats->set_visible(draw_stats->value() ? true : false);
view_keypress->set_visible(draw_keypress->value() ? true : false);
+
+ if (core::localcontrol() && (input::mouse_control || input::joystick_control) &&
+ (render::Camera::mode() == render::Camera::Cockpit || render::Camera::mode() == render::Camera::Track)) {
+ view_center->set_visible(true);
+ } else {
+ view_center->set_visible(false);
+ }
+
+ if (!ui::root()->active() && !has_input_focus()) {
+ set_focus();
+ }
+
- //draw_world();
}
/* -- namespace view ----------------------------------------------- */
@@ -599,7 +632,7 @@ void draw_cursor()
return;
float angle = 0;
- const float pointer_size = 48.0f;
+
float x = (float) input::mouse_position_x() - (pointer_size / 2.0f);
float y = (float) input::mouse_position_y() - (pointer_size / 2.0f);
bool cursor_animated = false;
@@ -614,37 +647,6 @@ void draw_cursor()
render::Textures::bind("bitmaps/pointers/aim");
} else {
- // draw center cursor in Cockpit and Track mode
- if ((input::mouse_control || input::joystick_control) &&
- (render::Camera::mode() == render::Camera::Cockpit || render::Camera::mode() == render::Camera::Track)) {
-
- if (ui_pointercolor) {
- std::stringstream colorstr(ui_pointercolor->str());
- colorstr >> color;
- }
-
- render::Textures::bind("bitmaps/pointers/center");
- float cx = (video::width - pointer_size) /2;
- float cy = (video::height - pointer_size) /2;
-
- render::gl::color(color);
- render::gl::begin(render::gl::Quads);
-
- glTexCoord2f(0,0 );
- render::gl::vertex(cx,cy,0.0f);
-
- glTexCoord2f(1, 0);
- render::gl::vertex(cx+pointer_size, cy, 0.0f);
-
- glTexCoord2f(1, 1);
- render::gl::vertex(cx+pointer_size, cy+pointer_size, 0.0f);
-
- glTexCoord2f(0, 1);
- render::gl::vertex(cx, cy+pointer_size, 0.0f);
-
- render::gl::end();
- }
-
if (targets::hover()) {
if (ui_pointerhovercolor) {
@@ -725,63 +727,7 @@ void draw_cursor()
}
}
-void reset()
-{
- using namespace render;
-
- // set clear color
- gl::clearcolor(0.0f, 0.0f, 0.0f, 1.0f);
-
- // load identity matrices
- gl::matrixmode(GL_MODELVIEW);
- gl::loadidentity();
-
- gl::matrixmode(GL_MODELVIEW);
- gl::loadidentity();
-
- // shading model: Gouraud (smooth, the default)
- gl::shademodel(GL_SMOOTH);
- //gl::shademodel(GL_FLAT);
-
- // lighting settings for the default light GL_LIGHT0
- GLfloat light_position[] = { 0.0, 0.0, 0.0, 1.0 };
- GLfloat ambient_light[] = { 0.01f, 0.01f, 0.01f, 1.0f };
- GLfloat diffuse_light[] = { 0.2f, 0.2f, 0.2f, 1.0f };
- GLfloat specular_light[] = { 0.2f, 0.2f, 0.2f, 1.0f };
-
- glLightfv(GL_LIGHT0, GL_POSITION, light_position);
- glLightfv(GL_LIGHT0, GL_AMBIENT, ambient_light);
- glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuse_light);
- glLightfv(GL_LIGHT0, GL_SPECULAR, specular_light);
-
- // GL_LIGHT0 is always enabled
- gl::enable(GL_LIGHT0);
-
- // color tracking
- glColorMaterial(GL_FRONT, GL_AMBIENT_AND_DIFFUSE);
-
- // material settings
- GLfloat specular_reflectance[] = { 0.2f, 0.2f, 0.2f, 1.0f };
- glMaterialfv(GL_FRONT, GL_SPECULAR, specular_reflectance);
- glMateriali(GL_FRONT, GL_SHININESS, 128); // shininess 1-128
-
- // alpha blending function
- gl::blendfunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
-
- gl::disable(GL_LIGHTING);
- gl::disable(GL_COLOR_MATERIAL);
-
- gl::cullface(GL_BACK);
- gl::frontface(GL_CCW);
- gl::disable(GL_CULL_FACE);
- gl::disable(GL_DEPTH_TEST);
- gl::disable(GL_BLEND);
-
- gl::disable(GL_TEXTURE_2D);
-
-}
-
-void frame(float seconds)
+void frame(float elapsed)
{
using namespace render;
@@ -793,22 +739,21 @@ void frame(float seconds)
render::Stats::clear();
- if (core::application()->connected() && core::game()->serverframetime()) {
+ if (core::application()->connected() && core::game()->serverframetime() && core::localplayer()->zone()) {
+ render::Camera::frame(elapsed);
+ render::Camera::frustum();
- render::draw(seconds); // draw the world
+ render::draw(elapsed); // draw the world
targets::draw(); // validate current target, render sound
if (targets::current()) // draw target docks etc
draw_entity_world_target(targets::current());
- }
- // switch to orthographic projection to draw the GUI
- gl::matrixmode(GL_PROJECTION);
- gl::loadidentity();
- glOrtho(0, video::width, video::height, 0, -16.0f, 16.0f);
+ render::Camera::ortho();
- gl::matrixmode(GL_MODELVIEW);
- gl::loadidentity();
+ } else {
+ render::Camera::ortho();
+ }
// draw the user interface
gl::color(1.0f, 1.0f, 1.0f, 1.0f);
@@ -829,9 +774,6 @@ void frame(float seconds)
// draw the hud
draw_hud();
- // draw the chat box
- chat::draw();
-
// draw the mouse cursor
draw_cursor();
}
diff --git a/src/client/view.h b/src/client/view.h
index e5e42bc..dbbd7be 100644
--- a/src/client/view.h
+++ b/src/client/view.h
@@ -7,7 +7,9 @@
#define __INCLUDED_CLIENT_VIEW_H__
#include "core/zone.h"
+#include "client/chat.h"
#include "ui/widget.h"
+#include "ui/bitmap.h"
namespace client
{
@@ -68,14 +70,19 @@ class View : public ui::Widget
public:
View(ui::Widget *parent=0);
+ inline Chat *chat() { return view_chat; }
+
protected:
virtual void draw();
+
virtual void resize();
private:
+ Chat *view_chat;
DevInfo *view_devinfo;
Stats *view_stats;
KeyPress *view_keypress;
+ ui::Bitmap *view_center;
};
/// functions to draw the client view
@@ -88,7 +95,7 @@ namespace view
void shutdown();
/// draw the next frame
- void frame(float seconds);
+ void frame(float elapsed);
/// reset OpenGL state
void reset();
diff --git a/src/render/camera.cc b/src/render/camera.cc
index ae7cd43..108e4db 100644
--- a/src/render/camera.cc
+++ b/src/render/camera.cc
@@ -23,6 +23,9 @@ const float pitch_track = -15.0f;
const float pitch_overview = -5.0f;
float Camera::camera_aspect = 1.0f;
+int Camera::camera_width = 0;
+int Camera::camera_height = 0;
+
float Camera::camera_frustum_size = 0.5f;
float Camera::camera_frustum_front = 1.0f;
math::Vector3f Camera::camera_eye;
@@ -45,6 +48,8 @@ float Camera::distance;
void Camera::init()
{
camera_aspect = 1.0f;
+ camera_height = 0;
+ camera_width = 0;
camera_frustum_size = 0.5f;
camera_frustum_front = 1.0f;
@@ -72,8 +77,10 @@ void Camera::shutdown()
{
}
-void Camera::set_aspect(int width, int height)
+void Camera::resize(int width, int height)
{
+ camera_width = width;
+ camera_height = height;
camera_aspect = (float) width / (float) height;
}
@@ -303,7 +310,7 @@ void Camera::frame(float seconds)
camera_eye = camera_target - (distance * camera_axis.forward());
}
-void Camera::draw()
+void Camera::frustum()
{
// Change to the projection matrix and set our viewing volume large enough for the skysphere
gl::matrixmode(GL_PROJECTION);
@@ -325,6 +332,17 @@ void Camera::draw()
gl::translate(-1.0f * camera_eye);
}
+void Camera::ortho()
+{
+ // switch to orthographic projection
+ gl::matrixmode(GL_PROJECTION);
+ gl::loadidentity();
+ glOrtho(0, camera_width, camera_height, 0, -16.0f, 16.0f);
+
+ gl::matrixmode(GL_MODELVIEW);
+ gl::loadidentity();
+}
+
void Camera::set_direction(float direction)
{
target_direction = direction;
diff --git a/src/render/camera.h b/src/render/camera.h
index db2db42..b19521e 100644
--- a/src/render/camera.h
+++ b/src/render/camera.h
@@ -46,8 +46,15 @@ public:
/// progress the camera
static void frame(float elapsed);
- /// draw the OpenGL camera transformation
- static void draw();
+ /// enable frustum projection
+ /** The frustum projection is used to draw the world
+ */
+ static void frustum();
+
+ /// enable orthographic projection
+ /** The ortographic projetion is used to draw the user interface
+ */
+ static void ortho();
/// set target direction
static void set_direction(float direction);
@@ -64,8 +71,8 @@ public:
/// set specified camera mode
static void set_mode(Mode newmode);
- /// set camera aspect ratio
- static void set_aspect(int width, int height);
+ /// resize camera
+ static void resize(int width, int height);
/// current frustum front
static float frustum_front();
@@ -73,6 +80,10 @@ public:
/// current frustum size (height);
static float frustum_size();
+ inline static int width() { return camera_width; }
+
+ inline static int height() { return camera_height; }
+
private:
static math::Vector3f camera_eye;
static math::Vector3f camera_target;
@@ -81,6 +92,8 @@ private:
static float camera_aspect;
static float camera_frustum_size;
static float camera_frustum_front;
+ static int camera_width;
+ static int camera_height;
// current and target yaw angle in XZ plane, positive is looking left
static float direction_current;
diff --git a/src/render/draw.cc b/src/render/draw.cc
index 573587e..17c6fac 100644
--- a/src/render/draw.cc
+++ b/src/render/draw.cc
@@ -1024,11 +1024,6 @@ void draw_pass_spacegrid()
void draw(float seconds)
{
zone = core::localplayer()->zone();
- if (!zone)
- return;
-
- Camera::frame(seconds);
- Camera::draw(); // draw the current camera transformation
// calculate client state
pass_prepare(seconds);
diff --git a/src/render/render.cc b/src/render/render.cc
index 3ba7e92..fbbaba1 100644
--- a/src/render/render.cc
+++ b/src/render/render.cc
@@ -9,15 +9,15 @@
#include <sstream>
#include <iomanip>
+#include "auxiliary/functions.h"
+#include "core/core.h"
+#include "filesystem/filesystem.h"
+#include "model/model.h"
#include "render/gl.h"
#include "render/dust.h"
#include "render/textures.h"
#include "render/tga.h"
#include "render/render.h"
-#include "model/model.h"
-
-#include "core/core.h"
-#include "filesystem/filesystem.h"
#include "sys/sys.h"
namespace render {
@@ -28,6 +28,10 @@ core::Cvar *r_grid = 0;
core::Cvar *r_radius = 0;
core::Cvar *r_sky = 0;
core::Cvar *r_wireframe = 0;
+core::Cvar *screenshotformat = 0;
+core::Cvar *screenshotquality = 0;
+
+int screenshot_number = 0;
using model::VertexArray;
VertexArray *vertexarray = 0;
@@ -37,6 +41,62 @@ void func_list_textures(std::string const &args)
Textures::list();
}
+void reset_gl()
+{
+ // setup our viewport.
+ gl::viewport(0, 0, Camera::width(), Camera::height());
+
+ // set clear color
+ gl::clearcolor(0.0f, 0.0f, 0.0f, 1.0f);
+
+ // load identity matrices
+ gl::matrixmode(GL_MODELVIEW);
+ gl::loadidentity();
+
+ gl::matrixmode(GL_MODELVIEW);
+ gl::loadidentity();
+
+ // shading model: Gouraud (smooth, the default)
+ gl::shademodel(GL_SMOOTH);
+ //gl::shademodel(GL_FLAT);
+
+ // lighting settings for the default light GL_LIGHT0
+ GLfloat light_position[] = { 0.0, 0.0, 0.0, 1.0 };
+ GLfloat ambient_light[] = { 0.01f, 0.01f, 0.01f, 1.0f };
+ GLfloat diffuse_light[] = { 0.2f, 0.2f, 0.2f, 1.0f };
+ GLfloat specular_light[] = { 0.2f, 0.2f, 0.2f, 1.0f };
+
+ glLightfv(GL_LIGHT0, GL_POSITION, light_position);
+ glLightfv(GL_LIGHT0, GL_AMBIENT, ambient_light);
+ glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuse_light);
+ glLightfv(GL_LIGHT0, GL_SPECULAR, specular_light);
+
+ // GL_LIGHT0 is always enabled
+ gl::enable(GL_LIGHT0);
+
+ // color tracking
+ glColorMaterial(GL_FRONT, GL_AMBIENT_AND_DIFFUSE);
+
+ // material settings
+ GLfloat specular_reflectance[] = { 0.2f, 0.2f, 0.2f, 1.0f };
+ glMaterialfv(GL_FRONT, GL_SPECULAR, specular_reflectance);
+ glMateriali(GL_FRONT, GL_SHININESS, 128); // shininess 1-128
+
+ // alpha blending function
+ gl::blendfunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+
+ gl::disable(GL_LIGHTING);
+ gl::disable(GL_COLOR_MATERIAL);
+
+ gl::cullface(GL_BACK);
+ gl::frontface(GL_CCW);
+ gl::disable(GL_CULL_FACE);
+ gl::disable(GL_DEPTH_TEST);
+ gl::disable(GL_BLEND);
+
+ gl::disable(GL_TEXTURE_2D);
+}
+
void init()
{
con_print << "^BInitializing renderer..." << std::endl;
@@ -72,6 +132,14 @@ void init()
r_sky = core::Cvar::get("r_sky", "1", core::Cvar::Archive);
r_sky->set_info("[bool] render the sky globe");
+ screenshotformat = core::Cvar::get("screenshotformat", "jpg", core::Cvar::Archive);
+ screenshotformat->set_info("[string] screenshot format: jpg png tga");
+
+ screenshotquality = core::Cvar::get("screenshotquality", "85", core::Cvar::Archive);
+ screenshotquality->set_info("[int] screenshot jpg quality");
+
+ reset_gl();
+
Camera::init();
Textures::init();
@@ -84,6 +152,32 @@ void init()
func->set_info("list loaded textures");
}
+// unload game assets (zone change)
+void unload()
+{
+ // clear zone sky textures
+ for (core::Zone::Registry::iterator it = core::Zone::registry().begin(); it != core::Zone::registry().end(); it++) {
+ core::Zone *zone = (*it).second;
+ if (zone->sky_texture()) {
+ render::Textures::unload(zone->sky_texture());
+ zone->set_sky_texture(0);
+ }
+ }
+
+ for (core::Entity::Registry::iterator it = core::Entity::registry().begin(); it != core::Entity::registry().end(); it++) {
+ core:: Entity *entity = (*it).second;
+
+ if (entity->type() == core::Entity::Globe) {
+ core::EntityGlobe *globe = static_cast<core::EntityGlobe *>(entity);
+ if (globe->render_texture) {
+ render::Textures::unload(globe->render_texture);
+ globe->render_texture = 0;
+ }
+ }
+ }
+}
+
+// clear all assets
void clear()
{
// clear zone sky textures
@@ -113,30 +207,7 @@ void clear()
vertexarray = 0;
}
-void unload()
-{
- // clear zone sky textures
- for (core::Zone::Registry::iterator it = core::Zone::registry().begin(); it != core::Zone::registry().end(); it++) {
- core::Zone *zone = (*it).second;
- if (zone->sky_texture()) {
- render::Textures::unload(zone->sky_texture());
- zone->set_sky_texture(0);
- }
- }
-
- for (core::Entity::Registry::iterator it = core::Entity::registry().begin(); it != core::Entity::registry().end(); it++) {
- core:: Entity *entity = (*it).second;
-
- if (entity->type() == core::Entity::Globe) {
- core::EntityGlobe *globe = static_cast<core::EntityGlobe *>(entity);
- if (globe->render_texture) {
- render::Textures::unload(globe->render_texture);
- globe->render_texture = 0;
- }
- }
- }
-}
-
+// reset render subsystem
void reset()
{
clear();
@@ -151,6 +222,8 @@ void reset()
(*r_arraysize) = (float) mb;
vertexarray = new VertexArray(mb);
+ reset_gl();
+ Dust::reset();
}
void shutdown()
@@ -170,5 +243,83 @@ void shutdown()
Dust::shutdown();
}
+
+void screenshot()
+{
+ bool available = false;
+ std::string shortname;
+ std::string filename;
+ const int TYPETGA = 0;
+ const int TYPEPNG = 1;
+ const int TYPEJPG = 2;
+ int filetype = TYPETGA;
+
+ // make sure the screenshots folder exists
+ filename.assign(filesystem::writedir());
+ filename.append("screenshots/");
+ sys::mkdir(filename);
+
+ aux::lowercase(screenshotformat->str());
+
+ if ((screenshotformat->str().compare("jpg") == 0) || (screenshotformat->str().compare("jpeg") == 0)) {
+ filetype = TYPEJPG;
+ if (screenshotquality->value() < 10) {
+ (*screenshotquality) = 10;
+ } else if (screenshotquality->value() > 100) {
+ (*screenshotquality) = 100;
+ }
+
+ } else if (screenshotformat->str().compare("png") == 0) {
+ filetype = TYPEPNG;
+
+ } else if (screenshotformat->str().compare("tga") == 0) {
+ filetype = TYPETGA;
+
+ } else {
+ filetype = TYPETGA;
+ (*screenshotformat) = "tga";
+ }
+
+ // find the first available screenshotxxxx
+ do {
+ std::stringstream nstr;
+ nstr << screenshot_number;
+ shortname.assign(nstr.str());
+
+ while(shortname.size() < 4)
+ shortname.insert(0, 1, '0');
+
+ shortname.insert(0, "screenshots/osirion");
+ shortname.append(".");
+ shortname.append(screenshotformat->str());
+
+ filename.assign(filesystem::writedir());
+ filename.append(shortname);
+
+ FILE *handle = fopen(filename.c_str(), "r");
+ if (handle) {
+ fclose(handle);
+ } else {
+ available = true;
+ }
+ screenshot_number++;
+ } while (!available);
+
+ render::Image image(Camera::width(), Camera::height(), 3);
+
+ glReadPixels(0, 0, (GLsizei) Camera::width(), (GLsizei) Camera::height(),
+ GL_RGB, GL_UNSIGNED_BYTE, (void *) image.data());
+
+ image.flip();
+
+ if (filetype == TYPEPNG) {
+ render::PNG::save(filename.c_str(), image);
+ } else if (filetype == TYPEJPG) {
+ render::JPG::save(filename.c_str(), image, (int) screenshotquality->value());
+ } else if (filetype == TYPETGA) {
+ render::TGA::save(filename.c_str(), image);
+ }
+}
+
}
diff --git a/src/render/render.h b/src/render/render.h
index 3faa097..cd90953 100644
--- a/src/render/render.h
+++ b/src/render/render.h
@@ -35,6 +35,9 @@ namespace render {
/// unload game render data
void unload();
+ /// make a screenshot
+ void screenshot();
+
extern core::Cvar *r_arraysize;
extern core::Cvar *r_bbox;
extern core::Cvar *r_grid;
diff --git a/src/ui/Makefile.am b/src/ui/Makefile.am
index 5c7815b..b0f1625 100644
--- a/src/ui/Makefile.am
+++ b/src/ui/Makefile.am
@@ -7,9 +7,9 @@ else
noinst_LTLIBRARIES = libui.la
endif
-noinst_HEADERS = bitmap.h button.h definitions.h font.h label.h \
+noinst_HEADERS = bitmap.h button.h container.h definitions.h font.h input.h label.h \
menu.h paint.h palette.h ui.h widget.h window.h
-libui_la_SOURCES = bitmap.cc button.cc font.cc label.cc menu.cc paint.cc \
- palette.cc ui.cc widget.cc window.cc
+libui_la_SOURCES = bitmap.cc button.cc font.cc input.cc label.cc menu.cc \
+ paint.cc palette.cc ui.cc widget.cc window.cc
libui_la_LDFLAGS = -avoid-version -no-undefined
diff --git a/src/ui/bitmap.cc b/src/ui/bitmap.cc
index c14ccff..fcf141c 100644
--- a/src/ui/bitmap.cc
+++ b/src/ui/bitmap.cc
@@ -24,13 +24,13 @@ Bitmap::Bitmap(Widget *parent, const char *texture) : Widget(parent)
Bitmap::~Bitmap()
{}
-void Bitmap::print(size_t indent)
+void Bitmap::print(const size_t indent) const
{
std::string marker("");
con_print << aux::pad_left(marker, indent*2) << label() << " \"" << texture() << "\"" << std::endl;
}
-void Bitmap::set_texture(std::string const & texture)
+void Bitmap::set_texture(const std::string & texture)
{
bitmap_texture.assign(texture);
}
@@ -43,10 +43,15 @@ void Bitmap::set_texture(const char *texture)
bitmap_texture.clear();
}
+void Bitmap::set_color(const math::Color & color)
+{
+ bitmap_color.assign(color);
+}
+
void Bitmap::draw_background()
{
if (bitmap_texture.size()) {
- paint::color(1.0f, 1.0f, 1.0f, 1.0f);
+ paint::color(bitmap_color);
paint::bitmap(global_location(), size(), bitmap_texture);
}
}
diff --git a/src/ui/bitmap.h b/src/ui/bitmap.h
index 1f60ef9..9bc1776 100644
--- a/src/ui/bitmap.h
+++ b/src/ui/bitmap.h
@@ -9,25 +9,38 @@
#include "ui/widget.h"
-namespace ui {
+namespace ui
+{
-class Bitmap : public Widget {
+class Bitmap : public Widget
+{
public:
- Bitmap (Widget *parent, const char *texture=0);
+ Bitmap(Widget *parent, const char *texture=0);
~Bitmap();
-
- inline std::string const &texture() const { return bitmap_texture; }
- void set_texture(std::string const & texture);
+
+ inline std::string const &texture() const {
+ return bitmap_texture;
+ }
+
+ inline math::Color const &color() const {
+ return bitmap_color;
+ }
+
+ void set_texture(const std::string & texture);
void set_texture(const char *texture);
-
+
+ void set_color(const math::Color &color);
+
/// print bitmap description
- virtual void print(size_t indent);
-
+ virtual void print(const size_t indent) const;
+
protected:
+ /// draw the bitmap as background
virtual void draw_background();
-
+
private:
std::string bitmap_texture;
+ math::Color bitmap_color;
};
}
diff --git a/src/ui/button.cc b/src/ui/button.cc
index 1ac5fd8..08fd0e9 100644
--- a/src/ui/button.cc
+++ b/src/ui/button.cc
@@ -11,9 +11,10 @@
#include "ui/button.h"
#include "core/commandbuffer.h"
-namespace ui {
+namespace ui
+{
-Button::Button (Widget *parent, const char *text, const char *command) : Label(parent, text)
+Button::Button(Widget *parent, const char *text, const char *command) : Label(parent, text)
{
set_label("button");
set_command(command);
@@ -24,7 +25,7 @@ Button::~Button()
{
}
-void Button::print(size_t indent)
+void Button::print(const size_t indent) const
{
std::string marker("");
con_print << aux::pad_left(marker, indent*2) << label() << " \"" << text() << "\" \"" << command() << "\"" << std::endl;
@@ -38,7 +39,7 @@ void Button::set_command(const char *command)
button_command.clear();
}
-void Button::set_command(std::string const &command)
+void Button::set_command(const std::string &command)
{
button_command.assign(command);
}
@@ -47,12 +48,12 @@ void Button::draw_border()
{
if (!border())
return;
-
- if (has_focus())
+
+ if (has_mouse_focus())
paint::color(palette()->foreground());
else
paint::color(palette()->border());
-
+
paint::border(global_location(), size());
}
@@ -60,29 +61,34 @@ void Button::draw_text()
{
if (!text().size())
return;
-
- if (has_focus())
+
+ if (has_mouse_focus())
paint::color(palette()->highlight());
else
paint::color(palette()->foreground());
-
+
paint::text(global_location(), size(), font(), text(), alignment());
}
-bool Button::keypress(unsigned int key, unsigned int modifier)
+bool Button::on_keypress(const int key, const unsigned int modifier)
{
return false;
}
-bool Button::keyrelease(unsigned int key, unsigned int modifier)
+bool Button::on_keyrelease(const int key, const unsigned int modifier)
{
if (key == 512 + SDL_BUTTON_LEFT) {
core::cmd() << button_command << std::endl;
audio::play("ui/button");
return true;
}
-
+
return false;
}
+void Button::on_mouseover(const math::Vector2f &cursor)
+{
+ audio::play("ui/select");
+}
+
}
diff --git a/src/ui/button.h b/src/ui/button.h
index c074467..b1bb522 100644
--- a/src/ui/button.h
+++ b/src/ui/button.h
@@ -10,32 +10,45 @@
#include <string>
#include "ui/label.h"
-namespace ui {
+namespace ui
+{
-class Button : public Label {
+class Button : public Label
+{
public:
- Button (Widget *parent, const char *text=0, const char *command=0);
+ Button(Widget *parent, const char *text=0, const char *command=0);
~Button();
-
- void set_command(std::string const &command);
+
+ /// set the command this button will execute
+ void set_command(const std::string &command);
+
+ /// set the command this button will execute
void set_command(const char *command);
-
- inline std::string const & command() const { return button_command; }
-
+
+ /// the command this button executes
+ inline const std::string & command() const {
+ return button_command;
+ }
+
/// print button description
- virtual void print(size_t indent);
-
- /// handle keyboard events
- virtual bool keypress(unsigned int key, unsigned int modifier);
- virtual bool keyrelease(unsigned int key, unsigned int modifier);
-
+ virtual void print(const size_t indent) const;
+
+ /// called when the mouse enters the widget
+ virtual void on_mouseover(const math::Vector2f &cursor);
+
+ /// called when the widget receives a key press
+ virtual bool on_keypress(const int key, const unsigned int modifier);
+
+ /// called when the widget receives a key release
+ virtual bool on_keyrelease(const int key, const unsigned int modifier);
+
protected:
/// draw the button border
virtual void draw_border();
-
+
/// draw the button text
virtual void draw_text();
-
+
private:
std::string button_command;
};
diff --git a/src/ui/container.h b/src/ui/container.h
new file mode 100644
index 0000000..77e987e
--- /dev/null
+++ b/src/ui/container.h
@@ -0,0 +1,36 @@
+/*
+ ui/container.h
+ This file is part of the Osirion project and is distributed under
+ the terms of the GNU General Public License version 2
+*/
+
+/*
+#ifndef __INCLUDED_UI_CONTAINER_H__
+#define __INCLUDED_UI_CONTAINER_H__
+
+#include <string>
+#include "ui/widget.h"
+
+namespace ui {
+
+/// a widget containing childs of equal size
+class Container : public Widget {
+public:
+ Container(Widget *parent);
+ ~Container();
+
+ void set_margin(const float h, const float v);
+ void set_child_size(const float width, const float height);
+
+protected:
+ virtual void resize();
+
+private:
+ math::Vector2f container_child_size;
+};
+
+}
+
+#endif // __INCLUDED_UI_CONTAINER_H__
+*/
+
diff --git a/src/ui/definitions.h b/src/ui/definitions.h
index d5d7fe9..b9b4e3c 100644
--- a/src/ui/definitions.h
+++ b/src/ui/definitions.h
@@ -7,18 +7,19 @@
#ifndef __INCLUDED_UI_DEFINITIONS_H__
#define __INCLUDED_UI_DEFINITIONS_H__
-namespace ui {
+namespace ui
+{
enum Alignment {
AlignAuto = 0x0000,
AlignLeft = 0x0001,
AlignHCenter = 0x0002,
AlignRight = 0x0004,
-
+
AlignTop = 0x0010,
AlignVCenter = 0x0020,
AlignBottom = 0x0040,
-
+
AlignCenter = AlignHCenter | AlignVCenter
};
diff --git a/src/ui/font.cc b/src/ui/font.cc
index 26d4155..9d721fd 100644
--- a/src/ui/font.cc
+++ b/src/ui/font.cc
@@ -6,7 +6,8 @@
#include "ui/font.h"
-namespace ui {
+namespace ui
+{
Font::Font(const char *name, const float width, const float height)
{
@@ -23,17 +24,17 @@ void Font::set_size(const float width, const float height)
font_size.assign(width, height);
}
-void Font::set_size(math::Vector2f const &size)
+void Font::set_size(const math::Vector2f &size)
{
font_size.assign(size);
}
-void Font::set_width(float width)
+void Font::set_width(const float width)
{
font_size.x = width;
}
-void Font::set_height(float height)
+void Font::set_height(const float height)
{
font_size.y = height;
}
@@ -46,12 +47,10 @@ void Font::set_name(const char *name)
font_name.clear();
}
-void Font::set_name(std::string const & name)
+void Font::set_name(const std::string & name)
{
font_name.assign(name);
}
}
-
-
diff --git a/src/ui/font.h b/src/ui/font.h
index a68dec8..1261427 100644
--- a/src/ui/font.h
+++ b/src/ui/font.h
@@ -10,38 +10,47 @@
#include <string>
#include "math/vector2f.h"
-namespace ui {
+namespace ui
+{
class Font
{
public:
Font(const char *name, const float width, const float height);
~Font();
-
- inline std::string const & name() const { return font_name; }
-
- inline math::Vector2f const & size() const { return font_size; }
-
- inline float const width() const { return font_size.x; }
-
- inline float const height() const { return font_size.y; }
-
+
+ inline const std::string & name() const {
+ return font_name;
+ }
+
+ inline const math::Vector2f & size() const {
+ return font_size;
+ }
+
+ inline float width() const {
+ return font_size.x;
+ }
+
+ inline float height() const {
+ return font_size.y;
+ }
+
void set_size(const float width, const float height);
-
- void set_size(math::Vector2f const &size);
-
- void set_width(float width);
-
- void set_height(float height);
-
+
+ void set_size(const math::Vector2f &size);
+
+ void set_width(const float width);
+
+ void set_height(const float height);
+
void set_name(const char *name);
-
- void set_name(std::string const & name);
-
+
+ void set_name(const std::string & name);
+
private:
std::string font_name;
-
+
math::Vector2f font_size;
};
diff --git a/src/ui/input.cc b/src/ui/input.cc
new file mode 100644
index 0000000..0c4ea32
--- /dev/null
+++ b/src/ui/input.cc
@@ -0,0 +1,174 @@
+/*
+ ui/input.cc
+ This file is part of the Osirion project and is distributed under
+ the terms of the GNU General Public License version 2
+*/
+
+#include "ui/input.h"
+#include "ui/paint.h"
+#include "auxiliary/functions.h"
+#include "core/core.h"
+#include "render/render.h"
+
+namespace ui
+{
+
+Input::Input(Widget *parent) : Widget(parent)
+{
+ input_text.clear();
+ input_pos = 0;
+
+ set_label("input");
+ set_background(false);
+ set_border(false);
+}
+
+Input::~Input()
+{
+}
+
+void Input::clear()
+{
+ input_text.clear();
+ input_pos = 0;
+}
+void Input::set_text(std::string const &text)
+{
+ input_text.assign(text);
+ input_pos = input_text.size();
+}
+
+void Input::set_text(const char *text)
+{
+ if (text)
+ input_text.assign(text);
+ else
+ input_text.clear();
+ input_pos = input_text.size();
+}
+
+void Input::draw()
+{
+ draw_background();
+ draw_border();
+
+ using namespace render;
+ size_t text_width = (size_t) width() / font()->width();
+ math::Vector2f v(global_location());
+ paint::color(palette()->foreground());
+
+ std::string firstpart(input_text.substr(0, input_pos));
+ size_t draw_width = 0;
+ const char *c = firstpart.c_str();
+
+ while (*c) {
+ if (aux::is_color_code(c)) {
+ c++;
+ } else {
+ draw_width++;
+ }
+ c++;
+ }
+
+ c = firstpart.c_str();
+ while (*c && draw_width > text_width - 2) {
+ if (aux::is_color_code(c)) {
+ c++;
+ Text::setcolor(*c);
+ } else {
+ draw_width--;
+ }
+ c++;
+ }
+
+ // draw the part before the cursor
+ if (*c) {
+ paint::text(v, size(), font(), std::string(c), AlignLeft | AlignVCenter);
+ }
+
+ // draw the part behind the cursor
+ v.x += draw_width * font()->width();
+ if (input_pos < input_text.size()) {
+ // FIXME limit to width
+ if (input_pos > 1 && aux::is_color_code(input_text.c_str() + input_pos -1)) {
+ Text::setcolor(input_text[input_pos]);
+ }
+ c = input_text.c_str() + input_pos;
+ paint::text(v, size(), font(), std::string(c), AlignLeft | AlignVCenter);
+ }
+
+ // draw cursor
+ if (has_input_focus() && (core::application()->time() - ::floorf(core::application()->time())) < 0.5f) {
+ std::string cursor("^B");
+ cursor += (char) 11;
+ paint::text(v, size(), font(), cursor, AlignLeft | AlignVCenter);
+ }
+}
+
+bool Input::on_keypress(const int key, const unsigned int modifier)
+{
+ switch (key) {
+ case SDLK_TAB:
+ core::CommandBuffer::complete(input_text, input_pos);
+ return true;
+ break;
+
+ case SDLK_HOME:
+ input_pos = 0;
+ return true;
+ break;
+
+ case SDLK_END:
+ input_pos = input_text.size();
+ return true;
+ break;
+
+ case SDLK_LEFT:
+ if (input_pos > 0)
+ input_pos--;
+ return true;
+ break;
+
+ case SDLK_RIGHT:
+ if (input_pos < input_text.size())
+ input_pos++;
+ return true;
+ break;
+
+ case SDLK_DELETE:
+ if (input_text.size() && input_pos < input_text.size()) {
+ input_text.erase(input_pos, 1);
+ }
+ return true;
+ break;
+
+ case SDLK_BACKSPACE:
+ if (input_text.size() && input_pos) {
+ input_text.erase(input_pos-1, 1);
+ input_pos--;
+ }
+ return true;
+ break;
+
+ default:
+ if ((key >= 32) && (key <175)) {
+ if (input_pos == input_text.size())
+ input_text += (char)key;
+ else
+ input_text.insert(input_pos, 1, (char)key);
+ input_pos++;
+ return true;
+ }
+ break;
+ }
+
+ return false;
+}
+bool Input::on_keyrelease(const int key, const unsigned int modifier)
+{
+ return false;
+}
+
+}
+
+
diff --git a/src/ui/input.h b/src/ui/input.h
new file mode 100644
index 0000000..214f63e
--- /dev/null
+++ b/src/ui/input.h
@@ -0,0 +1,55 @@
+/*
+ ui/input.h
+ This file is part of the Osirion project and is distributed under
+ the terms of the GNU General Public License version 2
+*/
+
+#ifndef __INCLUDED_UI_INPUT_H__
+#define __INCLUDED_UI_INPUT_H__
+
+#include "ui/widget.h"
+
+namespace ui
+{
+
+/// text input widget
+class Input : public Widget
+{
+public:
+ Input(Widget *parent);
+ ~Input();
+
+ /// set the text displayed by the label
+ void set_text(std::string const &text);
+
+ /// set the text displayed by the label
+ void set_text(const char *text);
+
+ /// return the text displayed by the label
+ inline std::string const &text() const {
+ return input_text;
+ }
+
+ /// clear the text
+ void clear();
+
+protected:
+ /// draw the widget
+ virtual void draw();
+
+ /// called when the widget receives a key press
+ virtual bool on_keypress(const int key, const unsigned int modifier);
+
+ /// called when the widget receives a key release
+ virtual bool on_keyrelease(const int key, const unsigned int modifier);
+
+private:
+
+ std::string input_text;
+ size_t input_pos;
+};
+
+}
+
+#endif // __INCLUDED_UI_INPUT_H__
+
diff --git a/src/ui/label.cc b/src/ui/label.cc
index 6f496fc..80e493e 100644
--- a/src/ui/label.cc
+++ b/src/ui/label.cc
@@ -10,7 +10,8 @@
using math::Vector2f;
-namespace ui {
+namespace ui
+{
Label::Label(Widget *parent, const char *text) : Widget(parent)
{
@@ -23,7 +24,7 @@ Label::~Label()
{
}
-void Label::print(size_t indent)
+void Label::print(const size_t indent) const
{
std::string marker("");
con_print << aux::pad_left(marker, indent*2) << label() << " \"" << text() << "\"" << std::endl;
@@ -37,12 +38,12 @@ void Label::set_text(const char *text)
label_text.clear();
}
-void Label::set_text(std::string const &text)
+void Label::set_text(const std::string &text)
{
label_text.assign(text);
}
-void Label::set_alignment(unsigned int alignment)
+void Label::set_alignment(const unsigned int alignment)
{
label_alignment = alignment;
}
@@ -50,7 +51,7 @@ void Label::set_alignment(unsigned int alignment)
void Label::draw()
{
Widget::draw();
-
+
draw_text();
}
@@ -58,7 +59,7 @@ void Label::draw_text()
{
if (!label_text.size())
return;
-
+
paint::color(palette()->foreground());
paint::text(global_location(), size(), font(), text(), alignment());
}
diff --git a/src/ui/label.h b/src/ui/label.h
index 45171b2..b7925c7 100644
--- a/src/ui/label.h
+++ b/src/ui/label.h
@@ -10,39 +10,45 @@
#include <string>
#include "ui/widget.h"
-namespace ui {
+namespace ui
+{
/// a widget displaying centered text
-class Label : public Widget {
+class Label : public Widget
+{
public:
Label(Widget *parent, const char *text=0);
~Label();
-
+
/// set the text displayed by the label
- void set_text(std::string const &text);
-
+ void set_text(const std::string &text);
+
/// set the text displayed by the label
void set_text(const char *text);
-
+
/// set the text alignment
- void set_alignment(unsigned int alignment);
-
+ void set_alignment(const unsigned int alignment);
+
/// return the text displayed by the label
- inline std::string const &text() const { return label_text; }
-
+ inline const std::string &text() const {
+ return label_text;
+ }
+
/// text alignment
- inline unsigned int alignment() const { return label_alignment; }
-
+ inline unsigned int alignment() const {
+ return label_alignment;
+ }
+
/// print label description
- virtual void print(size_t indent);
-
+ virtual void print(const size_t indent) const;
+
protected:
/// draw the label
virtual void draw();
-
+
/// draw the label text
virtual void draw_text();
-
+
private:
std::string label_text;
unsigned int label_alignment;
diff --git a/src/ui/menu.cc b/src/ui/menu.cc
index af9929c..2a1829f 100644
--- a/src/ui/menu.cc
+++ b/src/ui/menu.cc
@@ -10,22 +10,23 @@
#include "ui/menu.h"
#include "ui/ui.h"
-namespace ui {
+namespace ui
+{
Menu::Menu(Window *parent, const char *label) : Window(parent)
{
set_label(label);
set_border(false);
-
+
menu_element_width = 256.0f;
menu_element_height = 48.0f;
menu_element_margin = 24.0f;
-
+
menu_background = new Bitmap(this);
menu_container = new Window(this);
menu_container->set_border(true);
menu_container->set_background(true);
-
+
menu_container->set_label("container");
}
@@ -38,41 +39,41 @@ void Menu::load()
{
std::string filename("menus/");
filename.append(label());
-
+
filesystem::IniFile ini;
-
+
ini.open(filename);
-
+
if (!ini.is_open()) {
con_error << "Could not open " << ini.name() << std::endl;
return;
}
-
+
std::string strval;
Button *button = 0;
Label *label = 0;
while (ini.getline()) {
if (ini.got_section()) {
-
+
//con_debug << " " << ini.name() << " [" << ini.section() << "]" << std::endl;
-
+
if (ini.got_section("menu")) {
} else if (ini.got_section("button")) {
button = add_button();
-
+
} else if (ini.got_section("label")) {
label = add_label();
-
+
} else if (ini.got_section()) {
ini.unknown_section();
}
-
+
} else if (ini.got_key()) {
-
+
//con_debug << " " << ini.name() << " " << ini.key() << "=" << ini.value() << std::endl;
-
+
if (ini.in_section("menu")) {
if (ini.got_key_string("background", strval)) {
set_background(strval.c_str());
@@ -88,10 +89,10 @@ void Menu::load()
} else if (ini.in_section("button")) {
if (ini.got_key_string("text", strval)) {
button->set_text(strval);
-
+
} else if (ini.got_key_string("command", strval)) {
button->set_command(strval);
-
+
} else if (ini.got_key_string("align", strval)) {
aux::to_label(strval);
if (strval.compare("left") == 0) {
@@ -99,7 +100,7 @@ void Menu::load()
} else if (strval.compare("center") == 0) {
button->set_alignment(AlignCenter);
} else if (strval.compare("right") == 0) {
- button->set_alignment(AlignRight | AlignVCenter);
+ button->set_alignment(AlignRight | AlignVCenter);
} else {
ini.unknown_value();
}
@@ -124,10 +125,10 @@ void Menu::load()
ini.unkown_key();
}
}
-
+
}
}
-
+
con_debug << " " << ini.name() << " " << children().size() << " widgets" << std::endl;
ini.close();
}
@@ -153,9 +154,9 @@ Button *Menu::add_button(char const *text, char const *command)
void Menu::resize()
{
- size().assign(parent()->size());
- menu_background->size().assign(size());
-
+ set_size(parent()->size());
+ menu_background->set_size(size());
+
float n = (float) menu_container->children().size();
menu_container->set_size(1.5f * menu_element_width, n * (menu_element_height + menu_element_margin) + menu_element_height);
menu_container->set_location(menu_element_width * 0.25, (height() - menu_container->height()) / 2.0f);
diff --git a/src/ui/menu.h b/src/ui/menu.h
index 376e069..1b4f17e 100644
--- a/src/ui/menu.h
+++ b/src/ui/menu.h
@@ -12,36 +12,38 @@
#include "ui/label.h"
#include "ui/window.h"
-namespace ui {
+namespace ui
+{
/// a menu container
-class Menu : public Window {
+class Menu : public Window
+{
public:
/// create a new menu
Menu(Window *parent, const char * label);
~Menu();
-
+
/// load a menu from ini/menus/label.ini
void load();
-
+
void set_background(const char *texture);
-
+
Label *add_label(char const * text=0);
-
+
Button *add_button(char const *text=0, char const *command=0);
-
+
protected:
virtual void resize();
-
+
private:
float menu_element_width;
float menu_element_height;
float menu_element_margin;
-
+
Bitmap *menu_background;
Window *menu_container;
-
+
};
}
diff --git a/src/ui/paint.cc b/src/ui/paint.cc
index ce5a5c2..33ee54f 100644
--- a/src/ui/paint.cc
+++ b/src/ui/paint.cc
@@ -11,7 +11,8 @@
#include "render/textures.h"
#include "ui/paint.h"
-namespace ui {
+namespace ui
+{
// contains the interface between the user interface and the render library
namespace paint {
@@ -26,10 +27,15 @@ void color(math::Color const & color)
render::gl::color(color);
}
+void color_code(const char *c)
+{
+ render::Text::setcolor(*c);
+}
+
void border(math::Vector2f const &location, math::Vector2f const &size)
{
using namespace render::gl;
-
+
begin(LineLoop);
vertex(location.x +1 , location.y);
vertex(location.x + size.x, location.y);
@@ -41,7 +47,7 @@ void border(math::Vector2f const &location, math::Vector2f const &size)
void rectangle(math::Vector2f const &location, math::Vector2f const &size)
{
using namespace render::gl;
-
+
begin(Quads);
vertex(location.x +1 , location.y);
vertex(location.x + size.x, location.y);
@@ -57,39 +63,39 @@ void bitmap(math::Vector2f const &location, math::Vector2f const &size, std::str
render::Textures::bind("bitmaps/" + texture);
enable(GL_TEXTURE_2D);
-
+
begin(Quads);
-
+
glTexCoord2f(0.0f, 0.0f);
vertex(location.x +1 , location.y);
-
+
glTexCoord2f(1.0f, 0.0f);
vertex(location.x + size.x, location.y);
-
+
glTexCoord2f(1.0f, 1.0f);
vertex(location.x + size.x, location.y + size.y -1);
-
+
glTexCoord2f(0.0f, 1.0f);
vertex(location.x +1, location.y + size.y - 1);
end();
-
+
disable(GL_TEXTURE_2D);
}
void text_centered(math::Vector2f const &location, math::Vector2f const &size, std::string const &text, Font const *font)
{
using namespace render::gl;
-
+
render::Text::setfont(font->name().c_str(), font->width(), font->height());
enable(GL_TEXTURE_2D);
math::Vector2f v(location);
-
+
v.x += (size.x - aux::text_strip(text).size() * font->width()) /2.0f;
v.y += (size.y - font->height()) / 2.0f;
-
+
render::Text::draw(v.x, v.y, text);
-
+
disable(GL_TEXTURE_2D);
}
@@ -97,45 +103,45 @@ void text(math::Vector2f const &location, Font const *font, std::stringstream &
{
using namespace render::gl;
render::Text::setfont(font->name().c_str(), font->width(), font->height());
-
+
// enable OpenGL textures
enable(GL_TEXTURE_2D);
-
+
render::Text::draw(location.x, location.y, textstream);
-
+
// disable texturing
disable(GL_TEXTURE_2D);
}
void text(math::Vector2f const &location, math::Vector2f const &size,
- Font const *font,
- std::string const &text,
- unsigned int align)
+ Font const *font,
+ std::string const &text,
+ unsigned int align)
{
unsigned int align_horizontal = (align & 0x000F);
if (!align_horizontal)
align_horizontal = AlignLeft;
-
+
unsigned int align_vertical = (align & 0x00F0);
if (!align_vertical)
align_vertical = AlignTop;
-
+
// apply text font
using namespace render::gl;
render::Text::setfont(font->name().c_str(), font->width(), font->height());
-
+
// enable OpenGL textures
enable(GL_TEXTURE_2D);
-
+
// determine the width and height of the text
// FIXME support multiline text
float text_height = 1.0f * font->height();
float text_width = (float) aux::text_strip(text).size() * font->width();
-
+
// calculate drawing position
math::Vector2f v(location);
-
- switch(align_horizontal) {
+
+ switch (align_horizontal) {
case AlignLeft:
v.x += font->width();
break;
@@ -147,7 +153,7 @@ void text(math::Vector2f const &location, math::Vector2f const &size,
break;
}
- switch(align_vertical) {
+ switch (align_vertical) {
case AlignTop:
v.y += font->height()*0.5f;
break;
@@ -158,12 +164,12 @@ void text(math::Vector2f const &location, math::Vector2f const &size,
v.y += size.y - text_height - font->height()*0.5f;
break;
}
-
+
render::Text::draw(v.x, v.y, text);
-
+
// disable texturing
disable(GL_TEXTURE_2D);
-
+
}
}
diff --git a/src/ui/paint.h b/src/ui/paint.h
index 3128481..367b001 100644
--- a/src/ui/paint.h
+++ b/src/ui/paint.h
@@ -9,7 +9,8 @@
#include "ui/widget.h"
-namespace ui {
+namespace ui
+{
/// low-level widget paint functions
namespace paint {
@@ -20,6 +21,9 @@ void color(float r=0.0f, float g=0.0f, float b=0.0f, float a=1.0f);
/// set paint color
void color(math::Color const & color);
+/// set paint color
+void color_code(const char *c);
+
/// draw a border
void border(math::Vector2f const &location, math::Vector2f const &size);
@@ -30,9 +34,9 @@ void rectangle(math::Vector2f const &location, math::Vector2f const &size);
void bitmap(math::Vector2f const &location, math::Vector2f const &size, std::string const &texture);
/// draw text
-void text(math::Vector2f const &location, math::Vector2f const &size, Font const *font, std::string const &text,
- unsigned int align = AlignCenter);
-
+void text(math::Vector2f const &location, math::Vector2f const &size, Font const *font,
+ std::string const &text, unsigned int align = AlignCenter);
+
/// draw textstream
void text(math::Vector2f const &location, Font const *font, std::stringstream & textstream);
diff --git a/src/ui/palette.cc b/src/ui/palette.cc
index cb6ee91..20d1e93 100644
--- a/src/ui/palette.cc
+++ b/src/ui/palette.cc
@@ -7,14 +7,17 @@
#include "ui/palette.h"
#include "sys/sys.h"
-namespace ui {
+namespace ui
+{
Palette::Palette()
{
palette_foreground.assign(0.8f, 1.0f);
palette_highlight.assign(1.0f, 1.0f);
palette_background.assign(0.5f, 0.5f);
- palette_border.assign(0.0f, 8.0f, 0.0f);
+ palette_border.assign(0.0f, 0.8f, 0.0f);
+ palette_pointer.assign(0.0f, 0.5f, 0.0f);
+ palette_active.assign(0.0f, 1.0f, 0.0f);
}
Palette::~Palette()
@@ -41,6 +44,15 @@ void Palette::set_border(math::Color const &color)
palette_border.assign(color);
}
+void Palette::set_pointer(math::Color const &color)
+{
+ palette_pointer.assign(color);
+}
+
+void Palette::set_active(math::Color const &color)
+{
+ palette_active.assign(color);
}
+}
diff --git a/src/ui/palette.h b/src/ui/palette.h
index edd738f..9d27f95 100644
--- a/src/ui/palette.h
+++ b/src/ui/palette.h
@@ -9,7 +9,8 @@
#include "math/color.h"
-namespace ui {
+namespace ui
+{
class Palette
{
@@ -17,28 +18,50 @@ class Palette
public:
Palette();
~Palette();
-
+
void set_foreground(math::Color const &color);
-
+
void set_highlight(math::Color const &color);
-
+
void set_background(math::Color const &color);
-
+
void set_border(math::Color const &color);
-
- inline math::Color const &foreground() const { return palette_foreground; }
-
- inline math::Color const &highlight() const { return palette_highlight; }
-
- inline math::Color const &background() const { return palette_background; }
-
- inline math::Color const &border() const { return palette_border; }
-
+
+ void set_pointer(math::Color const &color);
+
+ void set_active(math::Color const &color);
+
+ inline math::Color const &foreground() const {
+ return palette_foreground;
+ }
+
+ inline math::Color const &highlight() const {
+ return palette_highlight;
+ }
+
+ inline math::Color const &background() const {
+ return palette_background;
+ }
+
+ inline math::Color const &border() const {
+ return palette_border;
+ }
+
+ inline math::Color const &pointer() const {
+ return palette_pointer;
+ }
+
+ inline math::Color const &active() const {
+ return palette_active;
+ }
+
private:
math::Color palette_foreground;
math::Color palette_highlight;
math::Color palette_background;
+ math::Color palette_pointer;
+ math::Color palette_active;
math::Color palette_border;
};
diff --git a/src/ui/ui.cc b/src/ui/ui.cc
index 8242381..8d60543 100644
--- a/src/ui/ui.cc
+++ b/src/ui/ui.cc
@@ -18,7 +18,10 @@
#include "ui/widget.h"
#include "ui/window.h"
-namespace ui {
+namespace ui
+{
+
+/* -- static functions --------------------------------------------- */
UI *global_ui = 0;
@@ -59,7 +62,7 @@ void func_ui(std::string const &args)
con_warn << "User Interface not available!" << std::endl;
return;
}
-
+
if (!args.size()) {
help();
return;
@@ -68,7 +71,7 @@ void func_ui(std::string const &args)
std::string command;
argstr >> command;
aux::to_label(command);
-
+
if (command.compare("help") == 0) {
help();
} else if (command.compare("list") == 0) {
@@ -103,28 +106,28 @@ void func_menu(std::string const &args)
con_warn << "User Interface not available!" << std::endl;
return;
}
-
+
if (!args.size()) {
return;
}
std::stringstream argstr(args);
std::string command;
argstr >> command;
-
+
aux::to_label(command);
-
+
if (command.compare("hide") == 0) {
root()->hide_window();
-
+
} else if (command.compare("close") == 0) {
root()->hide_window();
-
+
} else if (command.compare("back") == 0) {
root()->previous_window();
-
+
} else if (command.compare("previous") == 0) {
root()->previous_window();
-
+
} else if (command.compare("list") == 0) {
root()->list_menus();
} else {
@@ -132,6 +135,8 @@ void func_menu(std::string const &args)
}
}
+/* -- class UI ----------------------------------------------------- */
+
UI *root()
{
return global_ui;
@@ -140,28 +145,28 @@ UI *root()
void init()
{
con_print << "^BInitializing user interface..." << std::endl;
-
+
if (!global_ui) {
global_ui = new UI();
} else {
con_warn << "User interface already initialized!" << std::endl;
return;
}
-
+
global_ui->load();
-
+
core::Func *func = core::Func::add("list_ui", func_list_ui);
func->set_info("list user interface widgets");
-
+
func = core::Func::add("list_menu", func_list_menu);
func->set_info("list available menus");
-
+
func = core::Func::add("ui", func_ui);
func->set_info("[command] user interface functions");
-
+
func = core::Func::add("ui_restart", func_ui_restart);
func->set_info("[command] [options] reload user interface files");
-
+
func = core::Func::add("menu", func_menu);
func->set_info("[command] menu functions");
}
@@ -169,42 +174,51 @@ void init()
void shutdown()
{
con_print << "^BShutting down user interface..." << std::endl;
-
+
core::Func::remove("list_ui");
core::Func::remove("list_menu");
core::Func::remove("menu");
core::Func::remove("ui");
-
+
if (global_ui) {
delete global_ui;
global_ui = 0;
}
}
+/* -- class UI ----------------------------------------------------- */
+
UI::UI() : Window(0)
{
set_label("root");
set_size(1024, 768);
set_border(false);
-
+
// default palette
ui_palette = new Palette();
set_palette(ui_palette);
-
+
// default fonts
ui_font_small = new Font("gui", 12, 18);
ui_font_large = new Font("gui", 14, 24);
set_font(ui_font_small);
+
+ ui_mouse_focus = this;
+ ui_input_focus = this;
+ set_focus();
}
UI::~UI()
{
delete ui_palette;
-
+
delete ui_font_small;
delete ui_font_large;
}
+/*
+ remove all existing child windows and load ini/ui.ini
+*/
void UI::load()
{
Windows::iterator it;
@@ -213,47 +227,47 @@ void UI::load()
remove_child(window);
}
window_children.clear();
- ui_focus = this;
+ ui_mouse_focus = this;
ui_active_window = 0;
-
+
std::string filename("ui");
-
+
filesystem::IniFile ini;
-
+
ini.open(filename);
-
+
if (!ini.is_open()) {
con_error << "Could not open " << ini.name() << std::endl;
return;
}
-
+
std::string strval;
math::Color color;
Menu *menu = 0;
while (ini.getline()) {
-
+
if (ini.got_section()) {
-
+
//con_debug << " " << ini.name() << " [" << ini.section() << "]" << std::endl;
-
+
if (ini.got_section("ui")) {
continue;
-
+
} else if (ini.got_section("colors")) {
continue;
-
- } else {
+
+ } else {
ini.unknown_section();
continue;
}
-
+
} else if (ini.got_key()) {
-
+
//con_debug << " " << ini.name() << " " << ini.key() << "=" << ini.value() << std::endl;
-
+
if (ini.in_section("ui")) {
-
+
if (ini.got_key_string("menu", strval)) {
aux::to_label(strval);
menu = new Menu(this, strval.c_str());
@@ -262,9 +276,9 @@ void UI::load()
} else {
ini.unkown_key();
}
-
+
} else if (ini.in_section("colors")) {
-
+
if (ini.got_key_color("foreground", color)) {
ui_palette->set_foreground(color);
continue;
@@ -277,6 +291,10 @@ void UI::load()
} else if (ini.got_key_color("border", color)) {
ui_palette->set_border(color);
continue;
+ } else if (ini.got_key_color("pointer", color)) {
+ ui_palette->set_pointer(color);
+ } else if (ini.got_key_color("active", color)) {
+ ui_palette->set_active(color);
} else {
ini.unkown_key();
}
@@ -286,7 +304,7 @@ void UI::load()
con_debug << " " << ini.name() << " " << window_children.size() << " menus" << std::endl;
ini.close();
-
+
// fallback main menu
if (!find_window("main")) {
con_warn << "menu 'main' not found, using default" << std::endl;
@@ -295,7 +313,7 @@ void UI::load()
menu->add_button("Connect", "connect");
menu->add_button("Quit", "quit");
}
-
+
// fallback game menu
if (!find_window("game")) {
con_warn << "menu 'game' not found, using default" << std::endl;
@@ -306,17 +324,16 @@ void UI::load()
}
}
-void UI::list()
+void UI::list() const
{
size_t n = Widget::list(0);
con_print << n << " user interface widgets" << std::endl;
}
-void UI::list_menus()
+void UI::list_menus() const
{
- Windows::iterator it;
- for (it = window_children.begin(); it != window_children.end(); it++) {
- Window *window = (*it);
+ for (Windows::const_iterator it = window_children.begin(); it != window_children.end(); it++) {
+ const Window *window = (*it);
con_print << " " << window->label() << std::endl;
}
con_print << window_children.size() << " menus" << std::endl;
@@ -332,15 +349,16 @@ void UI::remove_window(Window *window)
{
if (ui_active_window == window) {
ui_active_window = 0;
- ui_focus = this;
+ ui_mouse_focus = this;
+ ui_input_focus = this;
}
-
+
Window::remove_window(window);
}
-Window *UI::find_window(const char *label)
+Window *UI::find_window(const char *label) const
{
- for (Windows::iterator it = window_children.begin(); it != window_children.end(); it++) {
+ for (Windows::const_iterator it = window_children.begin(); it != window_children.end(); it++) {
if ((*it)->label().compare(label) == 0) {
return (*it);
}
@@ -351,19 +369,21 @@ Window *UI::find_window(const char *label)
void UI::show_window(const char *label)
{
Window *window = find_window(label);
-
+
if (window) {
- if (ui_active_window) {
- ui_active_window->hide();
- window->set_previous(ui_active_window);
- } else {
- window->clear_previous();
- }
- ui_active_window = window;
- ui_active_window->event_resize();
- ui_active_window->raise();
- ui_active_window->show();
- ui_focus = window;
+ if (ui_active_window) {
+ ui_active_window->hide();
+ window->set_previous(ui_active_window);
+ } else {
+ window->clear_previous();
+ }
+ ui_active_window = window;
+ ui_active_window->event_resize();
+ ui_active_window->raise();
+ ui_active_window->show();
+ ui_active_window->set_focus();
+ ui_mouse_focus = this;
+ ui_input_focus = this;
} else {
con_warn << "Unknown window '" << label << "'" << std::endl;
}
@@ -390,28 +410,57 @@ void UI::previous_window()
void UI::frame()
{
- ui_focus = event_focus(mouse_cursor);
+ if (ui_active_window && !ui_active_window->visible()) {
+ ui_active_window = 0;
+ }
+
event_draw();
}
-void UI::input_mouse(float x, float y)
+/* -- global event handlers ---------------------------------------- */
+/*
+ These functions receive input events from the client input
+ subsystem and distributes them to the widget hierarchy
+*/
+void UI::input_mouse(const float x, const float y)
{
mouse_cursor.assign(x, y);
+ Widget *f = find_mouse_focus(mouse_cursor);
+ if (f) {
+ f->event_mouse(mouse_cursor);
+ }
+ ui_mouse_focus = f;
}
-void UI::input_key(bool pressed, unsigned int key, unsigned int modifier)
+void UI::input_key(const bool pressed, const int key, const unsigned int modifier)
{
- ui_focus->event_key(pressed, key, modifier);
+ if (key < 512) {
+ // keyboard keys
+ Widget *f = find_input_focus();
+ if (f) {
+ f->event_key(pressed, key, modifier);
+ }
+ ui_input_focus = f;
+ } else {
+ // mosue buttons
+ if (ui_mouse_focus)
+ ui_mouse_focus->event_key(pressed, key, modifier);
+ }
}
-bool UI::keypress(unsigned int key, unsigned int modifier)
+/* -- event handlers ----------------------------------------------- */
+/*
+ These functions handle events for this widget only. They are
+ the fallback input handlers
+*/
+bool UI::on_keypress(const int key, const unsigned int modifier)
{
- return true;
+ return true;
}
-bool UI::keyrelease(unsigned int key, unsigned int modifier)
+bool UI::on_keyrelease(const int key, const unsigned int modifier)
{
- return true;
+ return true;
}
}
diff --git a/src/ui/ui.h b/src/ui/ui.h
index a555e97..eb2d4e0 100644
--- a/src/ui/ui.h
+++ b/src/ui/ui.h
@@ -12,73 +12,96 @@
#include "ui/widget.h"
#include "ui/window.h"
-namespace ui {
+namespace ui
+{
-class UI : public Window {
+class UI : public Window
+{
public:
/// constructor
UI();
-
+
/// destructor
~UI();
-
+
/// list widgets
- void list();
-
+ void list() const;
+
/// list meus
- void list_menus();
-
+ void list_menus() const;
+
/// reload menu files
void load();
-
+
/// make a window the active window
void show_window(const char *label);
-
+
/// hide the active window
void hide_window();
-
+
/// show previous window
void previous_window();
-
+
/// return the active window
- Window *active() { return ui_active_window; }
-
- /// mouse cursor input
- void input_mouse(float x, float y);
-
- /// keyboard input
- void input_key(bool pressed, unsigned int key, unsigned int modifier);
-
+ Window *active() {
+ return ui_active_window;
+ }
+
+ /// return the widget with global mouse focus
+ inline Widget *mouse_focus() const {
+ return ui_mouse_focus;
+ }
+
+ /// return the widget with global input focus
+ inline Widget *input_focus() const {
+ return ui_input_focus;
+ }
+
+ /// receive global mouse movement
+ void input_mouse(const float x, const float y);
+
+ /// receive global key input
+ void input_key(const bool pressed, const int key, const unsigned int modifier);
+
/// run a user interface frame
void frame();
-
- /// return the widget which has the focus
- inline Widget *focus() { return ui_focus; }
-
- /* -- Fonts ------------------------------------------------ */
+
+ /* -- fonts ------------------------------------------------ */
+
/// default small font
- inline Font *font_small() { return ui_font_small; }
-
+ inline const Font *font_small() const {
+ return ui_font_small;
+ }
+
/// default medium font
- inline Font *font_large() { return ui_font_large; }
-
+ inline const Font *font_large() const {
+ return ui_font_large;
+ }
+
protected:
- Window *find_window(const char *label);
-
+ Window *find_window(const char *label) const;
+
virtual void add_window(Window *window);
virtual void remove_window(Window *window);
-
- /// handle keyboard input
- virtual bool keypress(unsigned int key, unsigned int modifier);
- virtual bool keyrelease(unsigned int key, unsigned int modifier);
-
+
+ /* -- event handlers --------------------------------------- */
+
+ /// handle keypress events
+ virtual bool on_keypress(const int key, const unsigned int modifier);
+
+ /// handle key release events
+ virtual bool on_keyrelease(const int key, const unsigned int modifier);
+
private:
Palette *ui_palette;
Font *ui_font_small;
Font *ui_font_large;
-
+
Window *ui_active_window;
- Widget *ui_focus;
+ Widget *ui_mouse_focus;
+ Widget *ui_input_focus;
+
+ /// TODO move to separate object to handle mouse cursor drawing
math::Vector2f mouse_cursor;
};
diff --git a/src/ui/widget.cc b/src/ui/widget.cc
index b2c436d..e17e5ab 100644
--- a/src/ui/widget.cc
+++ b/src/ui/widget.cc
@@ -10,22 +10,25 @@
#include "ui/ui.h"
#include "ui/widget.h"
-namespace ui {
+namespace ui
+{
-Widget::Widget(Widget *parent) {
+Widget::Widget(Widget *parent)
+{
+ widget_focus = false;
widget_visible = true;
widget_border = true;
widget_background = false;
widget_palette = 0;
widget_font = 0;
widget_label.assign("widget");
-
+
if (!parent) {
widget_parent = root();
} else {
widget_parent = parent;
}
-
+
if (widget_parent)
widget_parent->add_child(this);
}
@@ -33,39 +36,47 @@ Widget::Widget(Widget *parent) {
Widget::~Widget()
{
for (Children::iterator it = widget_children.begin(); it != widget_children.end(); it++) {
- delete (*it);
+ delete(*it);
(*it) = 0;
}
widget_children.clear();
}
-size_t Widget::list(size_t indent)
+size_t Widget::list(const size_t indent) const
{
print(indent);
size_t n = 1;
- for (Children::iterator it = widget_children.begin(); it != widget_children.end(); it++) {
+ for (Children::const_iterator it = widget_children.begin(); it != widget_children.end(); it++) {
n += (*it)->list(indent+1);
}
return n;
}
-void Widget::print(size_t indent)
+void Widget::print(const size_t indent) const
{
- std::string marker("");
- con_print << aux::pad_left(marker, indent*2) << label() << std::endl;
+ if (indent) {
+ std::string marker;
+ if (widget_focus)
+ marker.assign("^B* ^N");
+ else
+ marker.assign(" ");
+ con_print << aux::pad_left(marker, indent*2) << label() << std::endl;
+ }
}
-Palette const *Widget::palette() const {
+const Palette *Widget::palette() const
+{
if (widget_palette) {
- return widget_palette;
+ return widget_palette;
} else {
return parent()->palette();
}
}
-Font const *Widget::font() const {
+const Font *Widget::font() const
+{
if (widget_font) {
- return widget_font;
+ return widget_font;
} else {
return parent()->font();
}
@@ -75,7 +86,7 @@ void Widget::lower()
{
if (!parent())
return;
-
+
Children::iterator it = parent()->find_child(this);
if (it != parent()->children().end()) {
parent()->children().erase(it);
@@ -87,7 +98,7 @@ void Widget::raise()
{
if (!parent())
return;
-
+
Children::iterator it = parent()->find_child(this);
if (it != parent()->children().end()) {
parent()->children().erase(it);
@@ -95,6 +106,20 @@ void Widget::raise()
}
}
+void Widget::set_focus()
+{
+ if (!parent()) {
+ widget_focus = true;
+ return;
+ }
+
+ for (Children::iterator it = parent()->children().begin(); it != parent()->children().end(); it++) {
+ (*it)->widget_focus = false;
+ }
+
+ widget_focus = true;
+}
+
void Widget::show()
{
widget_visible = true;
@@ -108,7 +133,10 @@ void Widget::hide()
void Widget::set_visible(bool visible)
{
- widget_visible = visible;
+ if (visible)
+ show();
+ else
+ hide();
}
void Widget::set_border(bool border)
@@ -133,20 +161,26 @@ void Widget::set_label(char const *label)
aux::to_label(widget_label);
}
-void Widget::set_palette(Palette *palette)
+void Widget::set_palette(const Palette *palette)
{
widget_palette = palette;
}
-void Widget::set_font(Font *font)
+void Widget::set_font(const Font *font)
{
widget_font = font;
}
-void Widget::set_location(float const x, float const y) {
+void Widget::set_location(float const x, float const y)
+{
widget_location.assign(x, y);
}
+void Widget::set_location(const math::Vector2f &location)
+{
+ widget_location.assign(location);
+}
+
void Widget::set_size(float const w, float const h)
{
widget_size.assign(w, h);
@@ -173,7 +207,7 @@ Widget::Children::iterator Widget::find_child(Widget *child)
if ((*it) == child)
return it;
}
-
+
return it;
}
@@ -184,118 +218,167 @@ void Widget::add_child(Widget *child)
widget_children.push_back(child);
}
}
-
+
void Widget::remove_child(Widget *child)
{
Children::iterator it = find_child(child);
if (it != widget_children.end()) {
- delete (*it);
+ delete(*it);
widget_children.erase(it);
}
}
-void Widget::event_resize()
+Widget *Widget::find_input_focus()
{
- resize();
- for (Children::iterator it = widget_children.begin(); it != widget_children.end(); it++) {
- (*it)->event_resize();
+ if (!visible() || !widget_focus)
+ return 0;
+
+ for (Children::const_reverse_iterator rit = widget_children.rbegin(); rit != widget_children.rend(); ++rit) {
+ Widget *w = (*rit);
+ if (w->visible() && w->widget_focus) {
+ Widget *f = w->find_input_focus();
+ if (f)
+ return f;
+ }
}
+
+ // no child with input focus
+ return this;
}
-void Widget::resize()
+Widget *Widget::find_mouse_focus(const math::Vector2f & pos)
{
+ // this widget is not visible
+ if (!visible() || !size().contains(pos))
+ return 0;
+
+ // reverse-iterate children
+ for (Children::const_reverse_iterator rit = widget_children.rbegin(); rit != widget_children.rend(); ++rit) {
+ Widget *w = (*rit);
+ if (w->visible()) {
+ Widget *f = w->find_mouse_focus(pos - w->location());
+ if (f)
+ return f;
+ }
+
+ }
+
+ // no child with mouse focus
+ return this;
}
-void Widget::event_draw()
+bool Widget::has_mouse_focus() const
{
- if (!widget_visible)
- return;
-
- draw();
- for (Children::iterator it = widget_children.begin(); it != widget_children.end(); it++) {
- if ((*it)->visible())
- (*it)->event_draw();
- }
+ return (root()->mouse_focus() == this);
}
-void Widget::draw()
+bool Widget::has_input_focus() const
{
- draw_background();
- draw_border();
+ return (root()->input_focus() == this);
}
-void Widget::draw_background()
+/* -- event distributors ------------------------------------------- */
+
+bool Widget::event_key(const bool pressed, const int key, const unsigned int modifier)
{
- if (!widget_background)
- return;
+ bool handled = false;
+
+ if (pressed) {
+ handled = on_keypress(key, modifier);
+ } else {
+ handled = on_keyrelease(key, modifier);
+ }
+
+ if (!handled && parent())
+ handled = parent()->event_key(pressed, key, modifier);
+
+ return handled;
+}
- paint::color(palette()->background());
- paint::rectangle(global_location(), size());
+bool Widget::event_mouse(const math::Vector2f &cursor)
+{
+ math::Vector2f local_cursor = to_local_coords(cursor);
+ bool handled = false;
+
+ if (root()->mouse_focus() != this) {
+ on_mouseover(local_cursor);
+ }
+
+ on_mousemove(local_cursor);
+ return handled;
}
-void Widget::draw_border()
+void Widget::event_draw()
{
- if (!widget_border)
+ if (!visible())
return;
-
- paint::color(palette()->border());
- paint::border(global_location(), size());
+
+ draw();
+
+ for (Children::iterator it = widget_children.begin(); it != widget_children.end(); it++) {
+ if ((*it)->visible())
+ (*it)->event_draw();
+ }
}
-Widget *Widget::event_focus(math::Vector2f const & pos)
+void Widget::event_resize()
{
- // this widget is not visible
- if (!visible())
- return 0;
+ resize();
+ for (Children::iterator it = widget_children.begin(); it != widget_children.end(); it++) {
+ (*it)->event_resize();
+ }
+}
- // pos is outside this
- if ((pos.x < 0) || (pos.y < 0) || (pos.x > size().x) || (pos.y > size().y))
- return 0;
+/* -- event handlers ----------------------------------------------- */
- // reverse-iterate children
- for (Children::reverse_iterator rit = widget_children.rbegin(); rit != widget_children.rend(); ++rit) {
- Widget *w = (*rit);
- if (w->visible()) {
- Widget *f = w->event_focus(pos - w->location());
- if (f)
- return f;
- }
+void Widget::on_mouseover(const math::Vector2f &cursor)
+{
+ return;
+}
- }
-
- // no child has focus
- return this;
+void Widget::on_mousemove(const math::Vector2f &cursor)
+{
+ return;
}
-bool Widget::has_focus() const
+bool Widget::on_keypress(const int key, const unsigned int modifier)
{
- return (root()->focus() == this);
+ return false;
}
-bool Widget::event_key(bool pressed, unsigned int key, unsigned int modifier)
+bool Widget::on_keyrelease(const int key, const unsigned int modifier)
{
- bool handled;
+ return false;
+}
- if (pressed) {
- handled = keypress(key, modifier);
- } else {
- handled = keyrelease(key, modifier);
- }
+/* -- draw functions ----------------------------------------------- */
- if (!handled && parent())
- handled = parent()->event_key(pressed, key, modifier);
+void Widget::resize()
+{
+}
- return handled;
+void Widget::draw()
+{
+ draw_background();
+ draw_border();
}
-bool Widget::keypress(unsigned int key, unsigned int modifier)
+void Widget::draw_background()
{
- return false;
+ if (!widget_background)
+ return;
+
+ paint::color(palette()->background());
+ paint::rectangle(global_location(), size());
}
-bool Widget::keyrelease(unsigned int key, unsigned int modifier)
+void Widget::draw_border()
{
- return false;
+ if (!widget_border)
+ return;
+
+ paint::color(palette()->border());
+ paint::border(global_location(), size());
}
}
diff --git a/src/ui/widget.h b/src/ui/widget.h
index 2078134..e069220 100644
--- a/src/ui/widget.h
+++ b/src/ui/widget.h
@@ -20,199 +20,283 @@
#include "ui/definitions.h"
#include "sys/sys.h"
-namespace ui {
+namespace ui
+{
-class Widget {
+class Widget
+{
public:
/// type definition for child widgets
typedef std::list<Widget *> Children;
-
+
/// create a new widget
Widget(Widget *parent=0);
-
+
/// destroy a widget
virtual ~Widget();
-
+
+ /// parent widget this widget belongs to
+ inline Widget *parent() const {
+ return widget_parent;
+ }
+
/* -- inspectors -------------------------------------------- */
- inline math::Vector2f &location() { return widget_location; }
-
- inline math::Vector2f &size() { return widget_size; }
-
- inline float const left() const { return widget_location.x; }
-
- inline float const top() const { return widget_location.y; }
- inline float const width() const { return widget_size.x; }
-
- inline float const height() const { return widget_size.y; }
-
-
- inline std::string const &label() const { return widget_label; }
-
- inline bool border() const { return widget_border; }
-
- inline bool background() const { return widget_background; }
-
- inline Widget *parent() const { return widget_parent; }
-
- inline bool visible() const { return widget_visible; }
-
- Palette const *palette() const;
-
- Font const *font() const;
-
- bool has_focus() const;
-
-
+ /// pixel coordinates of the top-left corner of this widget within its parent
+ inline const math::Vector2f &location() const {
+ return widget_location;
+ }
+
+ /// size of this widget in pixels
+ inline const math::Vector2f &size() const {
+ return widget_size;
+ }
+
+ /// left coordinate of location()
+ /**
+ * @see location
+ */
+ inline float left() const {
+ return widget_location.x;
+ }
+
+ /// top coordinate of location()
+ /**
+ * @see location
+ */
+ inline float top() const {
+ return widget_location.y;
+ }
+
+ /// width of the widget in pixels
+ /**
+ * @see size()
+ */
+ inline float width() const {
+ return widget_size.x;
+ }
+
+ /// height of the widget in pixels
+ /**
+ * @see size()
+ */
+ inline float height() const {
+ return widget_size.y;
+ }
+
+ /// widget label
+ inline const std::string &label() const {
+ return widget_label;
+ }
+
+ /// true if this widget will draw a background
+ inline bool background() const {
+ return widget_background;
+ }
+
+ /// true if this widget will draw a border
+ inline bool border() const {
+ return widget_border;
+ }
+
+ /// true if this widget is visible
+ inline bool visible() const {
+ return widget_visible;
+ }
+
+ /// true if this widget is not visible
+ inline bool hidden() const {
+ return !widget_visible;
+ }
+
+ /// the palette used to draw this widget
+ const Palette *palette() const;
+
+ /// the font used to draw this widget
+ const Font *font() const;
+
+ /// return true if the widget has input focus
+ bool has_input_focus() const;
+
+ /// returns true if the widget has mouse focus
+ bool has_mouse_focus() const;
+
/* -- mutators --------------------------------------------- */
-
+
/// raise the widget to the top of the widget stack
void raise();
-
+
/// lower the widget to the bottom of the widget stack
void lower();
-
+
/// show the widget
- void show();
-
+ virtual void show();
+
/// hide the widget
- void hide();
-
+ virtual void hide();
+
/// set visibility
void set_visible(bool visible = true);
-
- /// set location of the top-left corner
+
+ /// set input focus
+ void set_focus();
+
+ /// set location of the top-left corner, relative to the parent
void set_location(float const x, float const y);
-
+
+ /// set location of the top-left corner, relative to the parent
+ void set_location(const math::Vector2f &location);
+
/// set the widgets width and height
void set_size(float const w, float const h);
-
+
/// set the widgets width and height
void set_size(math::Vector2f const &size);
-
+
/// set the widgets width
void set_width(float const w);
-
+
/// set the widgets height
void set_height(float const h);
-
+
/// set the widgets palette
- void set_palette(Palette *palette);
-
+ void set_palette(const Palette *palette);
+
/// set the widgets font
- void set_font(Font *font);
-
+ void set_font(const Font *font);
+
/// set the widgets label
void set_label(std::string const &label);
/// set the widgets label
- void set_label(char const *label);
-
- void set_border(bool border);
-
- void set_background(bool background);
-
- /// resize event
+ void set_label(const char *label);
+
+ /// enable or disable widget border
+ void set_border(bool border = true);
+
+ ///enable or disable widget background
+ void set_background(bool background = true);
+
+ /// child widgets
+ inline Children &children() {
+ return widget_children;
+ }
+
+
+ /* -- event distributors ----------------------------------- */
+
+ /// distribute resize event
virtual void event_resize();
-
- /// draw event
+
+ /// distribute draw event
virtual void event_draw();
-
- /// keyboard event
- virtual bool event_key(bool pressed, unsigned int key, unsigned int modifier);
-
- /// find the child widget with focus
- /** @param pos local position within the widget
- */
- Widget *event_focus(math::Vector2f const & pos);
-
- /// child widgets
- inline Children &children() { return widget_children; }
-
+
+ /// distribute keyboard events
+ virtual bool event_key(const bool pressed, const int key, const unsigned int modifier);
+
+ /// distribute mouse movement events
+ virtual bool event_mouse(const math::Vector2f &cursor);
+
protected:
- /// handle keyboard events
- /** returns true if the event was handled by this widget
- */
- virtual bool keypress(unsigned int key, unsigned int modifier);
-
- /// handle keyboard events
- /** returns true if the event was handled by this widget
- */
- virtual bool keyrelease(unsigned int key, unsigned int modifier);
-
- /// draw the widget
- virtual void draw();
-
- /// resize the widget
- virtual void resize();
-
- /// draw the widget background
- virtual void draw_background();
-
- /// draw the widget border
- virtual void draw_border();
-
+ /// find the widget that has input focus
+ virtual Widget *find_input_focus();
+
+ /// find widget that has mosue focus
+ /** @param cursor mouse cursor position relative to this widget's location
+ */
+ Widget *find_mouse_focus(const math::Vector2f & cursor);
+
/// list widget content
- size_t list(size_t indent);
-
+ size_t list(const size_t indent) const;
+
/// print widget description
- virtual void print(size_t indent);
-
+ virtual void print(const size_t indent) const;
+
+ /* -- coordinate mapping ----------------------------------- */
+
/// map local coordinates to global coordinates
- inline math::Vector2f to_global_coords(math::Vector2f const &local)
- {
+ inline math::Vector2f to_global_coords(const math::Vector2f &local) {
math::Vector2f v(local);
Widget *parent = widget_parent;
do {
v -= parent->location();
- parent = parent->widget_parent;
- } while(parent);
+ parent = parent->parent();
+ } while (parent);
return v;
}
-
+
/// map global coordinates to local coordinates
- inline math::Vector2f to_local_coords(math::Vector2f const &global) {
+ inline math::Vector2f to_local_coords(const math::Vector2f &global) {
math::Vector2f v(global);
Widget *parent = this;
while (parent) {
v += parent->location();
- parent = parent->widget_parent;
+ parent = parent->parent();
}
return v;
}
-
+
/// map local widget location to global location
- inline math::Vector2f global_location() const {
+ inline math::Vector2f global_location() {
math::Vector2f v(widget_location);
Widget *parent = widget_parent;
while (parent) {
v += parent->location();
- parent = parent->widget_parent;
+ parent = parent->parent();
}
return v;
}
-
- /// remove a child widget
+
+ /* -- event handlers --------------------------------------- */
+
+ /// called when the mouse receives mouse movement
+ virtual void on_mousemove(const math::Vector2f &cursor);
+
+ /// called when the mouse enters the widget
+ virtual void on_mouseover(const math::Vector2f &cursor);
+
+ /// called when the widget receives a key press
+ virtual bool on_keypress(const int key, const unsigned int modifier);
+
+ /// called when the widget receives a key release
+ virtual bool on_keyrelease(const int key, const unsigned int modifier);
+
+ /* -- draw functions --------------------------------------- */
+
+ /// resize event
+ virtual void resize();
+
+ /// draw the widget
+ virtual void draw();
+
+ /// draw the widget background
+ virtual void draw_background();
+
+ /// draw the widget border
+ virtual void draw_border();
+
+ void add_child(Widget *child);
void remove_child(Widget *child);
-
+
private:
- bool widget_visible;
- bool widget_background;
- bool widget_border;
- math::Vector2f widget_location;
- math::Vector2f widget_size;
- std::string widget_label;
+ bool widget_visible;
+ bool widget_background;
+ bool widget_border;
+ bool widget_focus;
+
+ math::Vector2f widget_location;
+ math::Vector2f widget_size;
+ std::string widget_label;
Children widget_children;
-
- Palette *widget_palette;
- Font *widget_font;
+
+ const Palette *widget_palette;
+ const Font *widget_font;
Widget *widget_parent;
Children::iterator find_child(Widget *child);
-
- void add_child(Widget *child);
+
};
}
diff --git a/src/ui/window.cc b/src/ui/window.cc
index cc9f3b5..4a60056 100644
--- a/src/ui/window.cc
+++ b/src/ui/window.cc
@@ -7,7 +7,8 @@
#include "ui/paint.h"
#include "ui/window.h"
-namespace ui {
+namespace ui
+{
Window::Window(Window *parent) : Widget(static_cast<Widget *>(parent))
{
@@ -38,7 +39,7 @@ void Window::draw_border()
{
if (!border())
return;
-
+
paint::color(palette()->foreground());
paint::border(global_location(), size());
}
@@ -50,7 +51,7 @@ Window::Windows::iterator Window::find_window(Window *window)
if ((*it) == window)
return it;
}
-
+
return it;
}
@@ -61,7 +62,7 @@ void Window::add_window(Window *window)
window_children.push_back(window);
}
}
-
+
void Window::remove_window(Window *window)
{
Windows::iterator it = find_window(window);
diff --git a/src/ui/window.h b/src/ui/window.h
index a134f04..919559f 100644
--- a/src/ui/window.h
+++ b/src/ui/window.h
@@ -9,32 +9,36 @@
#include "ui/widget.h"
-namespace ui {
+namespace ui
+{
-class Window : public Widget {
+class Window : public Widget
+{
public:
Window(Window *parent=0);
~Window();
-
+
virtual void draw_border();
-
+
/// set the label of the previous window
void set_previous(Window *previous);
/// clear the label of the previous window
void clear_previous();
-
- inline std::string const &previous() const { return window_previous; }
-
+
+ inline const std::string &previous() const {
+ return window_previous;
+ }
+
protected:
typedef std::list<Window *> Windows;
Windows window_children;
-
+
Windows::iterator find_window(Window *window);
-
+
virtual void add_window(Window *window);
virtual void remove_window(Window *window);
-
+
/// label of the previous window that got activated
/** This label is used to implement the 'menu previous'
* command