Project::OSiRiON - Git repositories
Project::OSiRiON
News . About . Screenshots . Downloads . Forum . Wiki . Tracker . Git
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore3
-rw-r--r--Makefile.am1
-rw-r--r--Makefile.git5
-rw-r--r--configure.ac31
-rw-r--r--package/aur/PKGBUILD.osirion48
-rw-r--r--src/client/Makefile.am4
-rw-r--r--src/client/audiosettingsmenu.cc3
-rw-r--r--src/client/chat.cc3
-rw-r--r--src/client/closeiconbutton.cc22
-rw-r--r--src/client/closeiconbutton.h28
-rw-r--r--src/client/controlsettingsmenu.cc3
-rw-r--r--src/client/galaxymapwidget.cc39
-rw-r--r--src/client/gamewindow.cc24
-rw-r--r--src/client/graphicssettingsmenu.cc3
-rw-r--r--src/client/hudenginestatus.cc7
-rw-r--r--src/client/inventorywindow.cc18
-rw-r--r--src/client/keyboard.cc2
-rw-r--r--src/client/mainmenu.cc3
-rw-r--r--src/client/mapwidget.cc49
-rw-r--r--src/client/mapwindow.cc36
-rw-r--r--src/client/playersettingsmenu.cc3
-rw-r--r--src/client/reputationwindow.cc10
-rw-r--r--src/client/savegamemenu.cc57
-rw-r--r--src/client/serverlistmenu.cc173
-rw-r--r--src/client/serverlistmenu.h70
-rw-r--r--src/client/targeticonbutton.cc7
-rw-r--r--src/client/targeticonbutton.h3
-rw-r--r--src/client/testmodelwindow.cc10
-rw-r--r--src/client/trademenu.cc15
-rw-r--r--src/client/video.cc2
-rw-r--r--src/core/entity.cc33
-rw-r--r--src/model/mapfile.cc2
-rw-r--r--src/model/objfile.cc128
-rw-r--r--src/model/objfile.h7
-rw-r--r--src/model/vertexarray.h2
-rw-r--r--src/render/tgafile.cc2
-rw-r--r--src/ui/Makefile.am2
-rw-r--r--src/ui/font.h6
-rw-r--r--src/ui/iconbutton.cc7
-rw-r--r--src/ui/iconbutton.h4
-rw-r--r--src/ui/label.h3
-rw-r--r--src/ui/toolbar.h2
-rw-r--r--src/ui/tooltip.cc90
-rw-r--r--src/ui/tooltip.h80
-rw-r--r--src/ui/ui.cc69
-rw-r--r--src/ui/ui.h17
-rw-r--r--src/ui/widget.cc40
-rw-r--r--src/ui/widget.h100
48 files changed, 1032 insertions, 244 deletions
diff --git a/.gitignore b/.gitignore
index 2a5e50e..00b5bf1 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,6 +1,9 @@
# ignore build directory
/build/
+# ignore libtool's m4 directory
+/m4/
+
# ignore autoconf/automake related files
/autom4te.cache/
/aclocal.m4
diff --git a/Makefile.am b/Makefile.am
index 13a6b8e..80f061e 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -1,6 +1,7 @@
# not a GNU package. You can remove this line, if
# have all needed files, that a GNU package needs
AUTOMAKE_OPTIONS = foreign 1.4
+ACLOCAL_AMFLAGS = -I m4
SUBDIRS = src
diff --git a/Makefile.git b/Makefile.git
index d160702..8092793 100644
--- a/Makefile.git
+++ b/Makefile.git
@@ -1,8 +1,9 @@
default: all
all:
- aclocal
+ libtoolize
+ aclocal -I m4
autoheader
- automake
+ automake --add-missing
autoconf
diff --git a/configure.ac b/configure.ac
index 52fa82d..15d994c 100644
--- a/configure.ac
+++ b/configure.ac
@@ -2,15 +2,16 @@ dnl ----------------------------------------------------------------
dnl append git revision to the version number
dnl determine the git revision number
+dnl note: the configure scripts needs to be regenerated to update the version number
define([gitversion], esyscmd([sh -c "echo -n 'git'; git rev-parse --short HEAD | tr -d '\n'"]))
-AC_INIT([osirion], [0.2.8-gitversion])
-
+AC_INIT([osirion],[0.2.8-gitversion])
+AC_CONFIG_MACRO_DIRS([m4])
AC_CONFIG_HEADERS(src/config.h)
-AC_LANG_CPLUSPLUS
+AC_LANG([C++])
AC_PROG_CXX
-AC_PROG_LIBTOOL
+LT_INIT
AM_INIT_AUTOMAKE
@@ -147,7 +148,7 @@ dnl
AC_MSG_CHECKING(whether to abort on compiler warnings)
WARN_CFLAGS="$WARN_CLFAGS -Wall"
AC_ARG_ENABLE(error,
- AC_HELP_STRING([--disable-error], [do not abort on compiler warnings]),
+ AS_HELP_STRING([--disable-error],[do not abort on compiler warnings]),
AC_MSG_RESULT(no),
AC_MSG_RESULT(yes)
WARN_CFLAGS="$WARN_CFLAGS -Werror"
@@ -160,7 +161,7 @@ dnl
AC_MSG_CHECKING(whether to include debug messages)
AC_ARG_ENABLE(debug_messages,
- AC_HELP_STRING([--disable-debug-messages], [build without extra debug messages]),
+ AS_HELP_STRING([--disable-debug-messages],[build without extra debug messages]),
AC_MSG_RESULT(no),
AC_MSG_RESULT(yes)
AC_DEFINE_UNQUOTED(HAVE_DEBUG_MESSAGES, 1, [Define this to enable debug messages])
@@ -171,7 +172,7 @@ dnl static libc
dnl
AC_ARG_ENABLE(static_stdlib,
- AC_HELP_STRING([--enable-static-stdlib], [staticly link with libgcc and libstdc++]),
+ AS_HELP_STRING([--enable-static-stdlib],[staticly link with libgcc and libstdc++]),
AC_MSG_RESULT(yes)
STATIC_LDADD="-static-libgcc -static-libstdc++",
AC_MSG_RESULT(no)
@@ -187,9 +188,7 @@ dnl
HAVE_CURSES=no
AC_ARG_WITH(curses,
- AC_HELP_STRING([--without-curses],
- [do not include curses support]
- )
+ AS_HELP_STRING([--without-curses],[do not include curses support])
)
if test "x${with_curses}" != "xno"; then
@@ -245,15 +244,13 @@ dnl
HAVE_BULLET=no
AC_ARG_ENABLE(static_bullet,
- AC_HELP_STRING([--enable-static-bullet], [staticly link with bullet physics libraries]),
+ AS_HELP_STRING([--enable-static-bullet],[staticly link with bullet physics libraries]),
AC_MSG_RESULT(yes),
AC_MSG_RESULT(no)
)
AC_ARG_WITH(bullet,
- AC_HELP_STRING([--with-bullet=PREFIX],
- [link with bullet physics library installed in PREFIX]
- )
+ AS_HELP_STRING([--with-bullet=PREFIX],[link with bullet physics library installed in PREFIX])
)
LDFLAGS_save="$LDFLAGS"
@@ -321,7 +318,7 @@ dnl
BUILD_CLIENT=no
AC_ARG_WITH(client,
- AC_HELP_STRING([--without-client], [do not build the client application])
+ AS_HELP_STRING([--without-client],[do not build the client application])
)
AC_MSG_CHECKING(whether to build client)
@@ -491,9 +488,7 @@ dnl Installation paths
AC_MSG_CHECKING(installation type)
AC_ARG_ENABLE(single_directory,
- AC_HELP_STRING(
- [--enable-single-directory], [install everything in a single directory]
- ),
+ AS_HELP_STRING([--enable-single-directory],[install everything in a single directory]),
AC_MSG_RESULT(single directory)
INSTALLTYPE="single directory",
AC_MSG_RESULT(standard)
diff --git a/package/aur/PKGBUILD.osirion b/package/aur/PKGBUILD.osirion
new file mode 100644
index 0000000..c675e0c
--- /dev/null
+++ b/package/aur/PKGBUILD.osirion
@@ -0,0 +1,48 @@
+#
+# Maintainer: Stijn Buys <ingar@telenet.be>
+#
+
+pkgname=osirion
+pkgver=0.2.8
+pkgrel=1
+pkgdesc="A free space trading and combat simulation with open gameplay"
+url="http://osirion.org/"
+arch=('x86_64' 'armv7h')
+license=('GPL')
+depends=('zlib' 'bullet' 'libjpeg' 'libpng' 'libvorbis' 'libogg' 'flac' 'sdl2' 'libgl' 'glu' 'openal')
+makedepends=('automake' 'autoconf')
+optdepends=(i'ncurses')
+provides=('osirion')
+conflicts=('osirion-server' 'osirion-git' 'osirion-server-git')
+backup=()
+options=()
+source=("http://osirion.org/files/${pkgname}-${pkgver}-src.tar.bz2"
+ "http://osirion.org/files/${pkgname}-${pkgver}-data.zip")
+sha256sums=('2b164ad11e2907eafb2200585afd400bdfe6eacd94d4c40a29c5750e4a2ccc6d'
+ 'dfa2e9ed814c03bcc0f7b4b14f5e981a6762762306ac131adb57c6a190512c74')
+
+prepare() {
+ cd "${srcdir}/${pkgname}-${pkgver}-src"
+
+}
+
+build() {
+ cd "${srcdir}/${pkgname}-${pkgver}-src"
+
+ ./configure \
+ --prefix=/usr
+
+ ./configure \
+ --prefix=/usr \
+ --disable-debug
+ make
+}
+
+package() {
+ cd "${srcdir}/${pkgname}-${pkgver}-src"
+ make DESTDIR="${pkgdir}" install
+
+ cd "${srcdir}"
+ install -D --mode=644 --directory "${srcdir}/data" "${pkgdir}/usr/share/osirion/data"
+}
+
diff --git a/src/client/Makefile.am b/src/client/Makefile.am
index 391892a..fbb075f 100644
--- a/src/client/Makefile.am
+++ b/src/client/Makefile.am
@@ -16,6 +16,7 @@ noinst_HEADERS = \
chat.h \
client.h \
clientext.h \
+ closeiconbutton.h \
control.h \
controlsettingsmenu.h \
entitymenu.h \
@@ -42,6 +43,7 @@ noinst_HEADERS = \
playersettingsmenu.h \
reputationwindow.h \
savegamemenu.h \
+ serverlistmenu.h \
soundext.h \
targeticonbutton.h \
targets.h \
@@ -57,6 +59,7 @@ libclient_la_SOURCES = \
chat.cc \
client.cc \
clientext.cc \
+ closeiconbutton.cc \
control.cc \
controlsettingsmenu.cc \
entitymenu.cc \
@@ -83,6 +86,7 @@ libclient_la_SOURCES = \
playersettingsmenu.cc \
reputationwindow.cc \
savegamemenu.cc \
+ serverlistmenu.cc \
soundext.cc \
targeticonbutton.cc \
targets.cc \
diff --git a/src/client/audiosettingsmenu.cc b/src/client/audiosettingsmenu.cc
index b09586a..13e6d57 100644
--- a/src/client/audiosettingsmenu.cc
+++ b/src/client/audiosettingsmenu.cc
@@ -5,6 +5,7 @@
*/
#include "client/audiosettingsmenu.h"
+#include "client/closeiconbutton.h"
#include "core/cvar.h"
#include "ui/button.h"
#include "ui/checkbox.h"
@@ -36,7 +37,7 @@ AudioSettingsMenu::AudioSettingsMenu(ui::Widget *parent, const char *label) : ui
_titlelabel->set_text("AUDIO SETTINGS");
// close button
- _closebutton = new ui::IconButton(_titlelabel, "bitmaps/icons/window_close");
+ _closebutton = new CloseIconButton(_titlelabel);
// content frame
_frame = new ui::Widget(this);
diff --git a/src/client/chat.cc b/src/client/chat.cc
index dd71d57..f921e79 100644
--- a/src/client/chat.cc
+++ b/src/client/chat.cc
@@ -7,6 +7,7 @@
#include "auxiliary/functions.h"
#include "client/chat.h"
#include "client/client.h"
+#include "client/closeiconbutton.h"
#include "core/core.h"
#include "core/gameinterface.h"
#include "sys/sys.h"
@@ -35,7 +36,7 @@ Chat::Chat(ui::Widget *parent) : ui::Window(parent)
chat_titlelabel->set_text("CHAT");
// close button
- chat_closebutton = new ui::IconButton(chat_titlelabel, "bitmaps/icons/window_close");
+ chat_closebutton = new CloseIconButton(chat_titlelabel);
// player list
chat_playerlist = new ui::ListView(this);
diff --git a/src/client/closeiconbutton.cc b/src/client/closeiconbutton.cc
new file mode 100644
index 0000000..82c37f0
--- /dev/null
+++ b/src/client/closeiconbutton.cc
@@ -0,0 +1,22 @@
+/*
+ client/closeiconbutton.cc
+ This file is part of the Osirion project and is distributed under
+ the terms of the GNU General Public License version 2
+*/
+
+#include "client/closeiconbutton.h"
+
+namespace client
+{
+
+CloseIconButton::CloseIconButton(Widget *parent) : ui::IconButton(parent, "bitmaps/icons/window_close", "Close")
+{
+ set_label("close");
+}
+
+CloseIconButton::~CloseIconButton()
+{
+}
+
+}
+
diff --git a/src/client/closeiconbutton.h b/src/client/closeiconbutton.h
new file mode 100644
index 0000000..a822731
--- /dev/null
+++ b/src/client/closeiconbutton.h
@@ -0,0 +1,28 @@
+/*
+ client/closeiconbutton.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_CLIENT_CLOSEICONBUTTON_H__
+#define __INCLUDED_CLIENT_CLOSEICONBUTTON_H__
+
+#include "ui/iconbutton.h"
+
+namespace client
+{
+
+class CloseIconButton : public ui::IconButton
+{
+
+public:
+ /**
+ * @brief Default close button
+ * */
+ CloseIconButton(Widget *parent);
+ virtual ~CloseIconButton();
+};
+
+}
+
+#endif // __INCLUDED_CLIENT_CLOSEICONBUTTON_H__
diff --git a/src/client/controlsettingsmenu.cc b/src/client/controlsettingsmenu.cc
index 4417bf3..bd60fb4 100644
--- a/src/client/controlsettingsmenu.cc
+++ b/src/client/controlsettingsmenu.cc
@@ -5,6 +5,7 @@
*/
#include "client/controlsettingsmenu.h"
+#include "client/closeiconbutton.h"
#include "client/input.h"
#include "ui/button.h"
#include "ui/iconbutton.h"
@@ -278,7 +279,7 @@ ControlSettingsMenu::ControlSettingsMenu(ui::Widget *parent, const char *label)
_titlelabel->set_text("CONTROLS");
// close button
- _closebutton = new ui::IconButton(_titlelabel, "bitmaps/icons/window_close");
+ _closebutton = new CloseIconButton(_titlelabel);
// command listview
_controlslistview = new ui::ListView(this);
diff --git a/src/client/galaxymapwidget.cc b/src/client/galaxymapwidget.cc
index 25460b8..4bcf7c5 100644
--- a/src/client/galaxymapwidget.cc
+++ b/src/client/galaxymapwidget.cc
@@ -19,6 +19,9 @@ GalaxyMapWidget::GalaxyMapWidget(ui::Widget *parent) : ui::Widget(parent)
galaxymapwidget_zone = 0;
galaxymapwidget_hover_id = 0;
galaxymapwidget_zoom = 1.0f;
+
+ // make sure the map has a tooltip
+ set_tooltip();
}
GalaxyMapWidget::~GalaxyMapWidget()
@@ -112,11 +115,13 @@ void GalaxyMapWidget::draw()
// global mouse cursor location
const math::Vector2f cursor(ui::root()->global_mouse_coords());
galaxymapwidget_hover_id = 0;
+ set_tooltip();
// map center
//math::Vector2f map_center(map_location[0] + map_size / 2.0f, map_location[1] + map_size / 2.0f);
math::Vector2f icon_location;
- const float r = 12.0f; // radius of map icons
+ const float r = 12.0f; // radius of map icons
+ const float rt = 24.0f; // radius of target icons
float scale = 1024.0f; // galaxy size (in zone location units)
math::Color color(1.0f, 1.0f, 1.0f, 1.0f);
const core::Zone *zone = 0;
@@ -149,6 +154,7 @@ void GalaxyMapWidget::draw()
if (math::distancesquared(cursor, icon_location) < (r*r))
{
galaxymapwidget_hover_id = zone->id();
+ set_tooltip(zone->name());
}
if (zone == galaxymapwidget_zone)
@@ -180,6 +186,37 @@ void GalaxyMapWidget::draw()
}
gl::end();
+
+ if (galaxymapwidget_zone)
+ {
+ icon_location.assign(map_location);
+ icon_location[0] += map_size / scale * galaxymapwidget_zone->location().x();
+ icon_location[1] += map_size - map_size / scale * galaxymapwidget_zone->location().y(); // flip vertically
+
+ // draw target icon
+ const size_t texture_target = render::Textures::load("bitmaps/icons/map_target");
+ render::Textures::bind(texture_target);
+
+ gl::begin(gl::Quads);
+
+ math::Color color(1.0);
+ gl::color(color);
+
+ glTexCoord2f(0.0f, 0.0f);
+ gl::vertex(icon_location.x() - rt, icon_location.y() - rt);
+
+ glTexCoord2f(1.0f, 0.0f);
+ gl::vertex(icon_location.x() + rt, icon_location.y() - rt);
+
+ glTexCoord2f(1.0f, 1.0f);
+ gl::vertex(icon_location.x() + rt, icon_location.y() + rt);
+
+ glTexCoord2f(0.0f, 1.0f);
+ gl::vertex(icon_location.x() - rt, icon_location.y() + rt);
+
+ gl::end();
+ }
+
gl::disable(GL_TEXTURE_2D);
// if (has_mouse_focus()) {
diff --git a/src/client/gamewindow.cc b/src/client/gamewindow.cc
index 0b39cea..139755f 100644
--- a/src/client/gamewindow.cc
+++ b/src/client/gamewindow.cc
@@ -54,20 +54,20 @@ GameWindow::GameWindow(ui::Widget *parent) : ui::Window(parent)
gamewindow_chat = new Chat(this);
// icon buttons
- gamewindow_menubutton = new ui::IconButton(this, "bitmaps/icons/button_menu", "ui_menu");
-
- gamewindow_launchbutton = new ui::IconButton(this, "bitmaps/icons/button_launch", "launch");
+ gamewindow_menubutton = new ui::IconButton(this, "bitmaps/icons/button_menu", "Menu", "ui_menu");
+ gamewindow_launchbutton = new ui::IconButton(this, "bitmaps/icons/button_launch", "Launch", "launch");
+ gamewindow_freeflightbutton = new ui::IconButton(this, "bitmaps/icons/button_freeflight", "Cancel Autopilot", "freeflight");
- gamewindow_freeflightbutton = new ui::IconButton(this, "bitmaps/icons/button_freeflight", "freeflight");
- gamewindow_gotobutton = new TargetIconButton(this, "bitmaps/icons/button_goto", "goto");
- gamewindow_dockbutton = new TargetIconButton(this, "bitmaps/icons/button_dock", "dock", core::Entity::Dockable);
- gamewindow_formationbutton = new TargetIconButton(this, "bitmaps/icons/button_formation", "formation");
+ gamewindow_gotobutton = new TargetIconButton(this, "bitmaps/icons/button_goto", "Goto", "goto");
+ gamewindow_dockbutton = new TargetIconButton(this, "bitmaps/icons/button_dock", "Dock", "dock", core::Entity::Dockable);
+ gamewindow_formationbutton = new TargetIconButton(this, "bitmaps/icons/button_formation", "Formation", "formation");
+ gamewindow_formationbutton->set_tooltip("Formation");
- gamewindow_homebutton = new ui::IconButton(this, "bitmaps/icons/button_home", "view main");
- gamewindow_chatbutton = new ui::IconButton(this, "bitmaps/icons/button_chat", "ui_chat");
- gamewindow_mapbutton = new ui::IconButton(this, "bitmaps/icons/button_map", "ui_map");
- gamewindow_inventorybutton = new ui::IconButton(this, "bitmaps/icons/button_ship", "ui_inventory");
- gamewindow_reputationbutton = new ui::IconButton(this, "bitmaps/icons/button_reputation", "ui_reputation");
+ gamewindow_homebutton = new ui::IconButton(this, "bitmaps/icons/button_home", "Home", "view main");
+ gamewindow_chatbutton = new ui::IconButton(this, "bitmaps/icons/button_chat", "Chat", "ui_chat");
+ gamewindow_mapbutton = new ui::IconButton(this, "bitmaps/icons/button_map", "Map", "ui_map");
+ gamewindow_inventorybutton = new ui::IconButton(this, "bitmaps/icons/button_ship", "Inventory", "ui_inventory");
+ gamewindow_reputationbutton = new ui::IconButton(this, "bitmaps/icons/button_reputation", "Reputation", "ui_reputation");
}
GameWindow::~GameWindow()
diff --git a/src/client/graphicssettingsmenu.cc b/src/client/graphicssettingsmenu.cc
index ab05635..716570a 100644
--- a/src/client/graphicssettingsmenu.cc
+++ b/src/client/graphicssettingsmenu.cc
@@ -5,6 +5,7 @@
*/
#include "client/graphicssettingsmenu.h"
+#include "client/closeiconbutton.h"
#include "core/cvar.h"
#include "ui/button.h"
#include "ui/checkbox.h"
@@ -34,7 +35,7 @@ GraphicsSettingsMenu::GraphicsSettingsMenu(ui::Widget *parent, const char *label
_titlelabel->set_text("GRAPHICS SETTINGS");
// close button
- _closebutton = new ui::IconButton(_titlelabel, "bitmaps/icons/window_close");
+ _closebutton = new CloseIconButton(_titlelabel);
// content frame
_frame = new ui::Widget(this);
diff --git a/src/client/hudenginestatus.cc b/src/client/hudenginestatus.cc
index ab51709..bae1f3f 100644
--- a/src/client/hudenginestatus.cc
+++ b/src/client/hudenginestatus.cc
@@ -6,6 +6,7 @@
#include "client/input.h"
#include "client/hudenginestatus.h"
+#include "client/closeiconbutton.h"
#include "core/core.h"
#include "core/application.h"
#include "ui/ui.h"
@@ -24,11 +25,11 @@ HUDEngineStatus::HUDEngineStatus(ui::Widget *parent) : ui::Widget(parent)
set_background(false);
_button_auto_palette = new ui::Palette(*palette());
- _button_auto = new ui::IconButton(this, "bitmaps/hud/button_auto", "freeflight");
+ _button_auto = new ui::IconButton(this, "bitmaps/hud/button_auto", "Cancel autopilot", "freeflight");
_button_auto->set_palette(_button_auto_palette);
_button_lock_palette = new ui::Palette(*palette());
- _button_lock = new ui::IconButton(this, "bitmaps/hud/button_lock", "ui_control");
+ _button_lock = new ui::IconButton(this, "bitmaps/hud/button_lock", "Lock control", "ui_control");
_button_lock->set_palette(_button_lock_palette);
}
@@ -115,10 +116,12 @@ void HUDEngineStatus::draw()
if (control_lock)
{
_button_lock_palette->set_foreground(math::Color(1.0f, 0.0f, 0.0f));
+ _button_lock->set_tooltip("Unlock control");
} else
{
// free controls
_button_lock_palette->set_foreground(palette()->foreground());
+ _button_lock->set_tooltip("Lock control");
}
// health bar size
diff --git a/src/client/inventorywindow.cc b/src/client/inventorywindow.cc
index de27d13..09bd71e 100644
--- a/src/client/inventorywindow.cc
+++ b/src/client/inventorywindow.cc
@@ -6,6 +6,7 @@
#include "core/application.h"
#include "client/inventorywindow.h"
+#include "client/closeiconbutton.h"
#include "ui/label.h"
#include "ui/bitmap.h"
#include "ui/listitem.h"
@@ -63,9 +64,8 @@ InventoryWindow::InventoryWindow(ui::Widget *parent) : ui::Window(parent)
inventorywindow_inventorytext->set_font(ui::root()->font_small());
inventorywindow_inventorytext->set_alignment(ui::AlignLeft | ui::AlignTop);
- inventorywindow_shipbutton = new ui::IconButton(this, "bitmaps/icons/button_ship");
- inventorywindow_ejectbutton = new ui::IconButton(this, "bitmaps/icons/button_eject");
- //inventorywindow_mountbutton = new ui::IconButton(this, "bitmaps/icons/button_mount");
+ inventorywindow_shipbutton = new ui::IconButton(this, "bitmaps/icons/button_ship", "Ship info");
+ inventorywindow_ejectbutton = new ui::IconButton(this, "bitmaps/icons/button_eject", "Eject cargo");
// window title
inventorywindow_titlelabel = new ui::Label(this);
@@ -77,7 +77,7 @@ InventoryWindow::InventoryWindow(ui::Widget *parent) : ui::Window(parent)
inventorywindow_titlelabel->set_text("INVENTORY");
// close button
- inventorywindow_closebutton = new ui::IconButton(inventorywindow_titlelabel, "bitmaps/icons/window_close");
+ inventorywindow_closebutton = new CloseIconButton(inventorywindow_titlelabel);
// eject dialog
inventorywindow_ejectconfirmbutton = new ui::Button(inventorywindow_scrollpane, "Eject");
@@ -146,24 +146,26 @@ void InventoryWindow::update_inventory()
listitem->set_sortkey(sortkey);
if (item->has_flag(core::Item::Mounted)) {
- // unmount button
- ui::IconButton *ismounted_button = new ui::IconButton(listitem, "bitmaps/icons/button_mount");
+ // wepaon is mounted, show the unmount button
+ ui::IconButton *ismounted_button = new ui::IconButton(listitem, "bitmaps/icons/button_unmount");
std::ostringstream strcmd;
strcmd << "remote mount " << item->id();
ismounted_button->set_command(strcmd.str());
ismounted_button->set_background(true);
ismounted_button->set_size(icon_size, icon_size);
ismounted_button->set_location(ui::UI::elementsize.width() - icon_size - padding, padding);
+ ismounted_button->set_tooltip("Unmount weapon");
} else if (item->has_flag(core::Item::Mountable)) {
- // mount button
- ui::IconButton *isunmounted_button = new ui::IconButton(listitem, "bitmaps/icons/button_unmount");
+ // weapon is not mounted, show mount button
+ ui::IconButton *isunmounted_button = new ui::IconButton(listitem, "bitmaps/icons/button_mount");
std::ostringstream strcmd;
strcmd << "remote mount " << item->id();
isunmounted_button->set_command(strcmd.str());
isunmounted_button->set_background(true);
isunmounted_button->set_size(icon_size, icon_size);
isunmounted_button->set_location(ui::UI::elementsize.width() - icon_size - padding, padding);
+ isunmounted_button->set_tooltip("Mount weapon");
}
// preserve previous selection during update
diff --git a/src/client/keyboard.cc b/src/client/keyboard.cc
index fe6496f..37c6fc6 100644
--- a/src/client/keyboard.cc
+++ b/src/client/keyboard.cc
@@ -153,7 +153,7 @@ Keyboard::Keyboard()
add_key(SDL_SCANCODE_KP_EQUALS, "kpequal", '=');
add_key(SDL_SCANCODE_KP_LESS, "kpless", '<');
- add_key(SDL_SCANCODE_LEFT, "left", 0, "+ lookleft");
+ add_key(SDL_SCANCODE_LEFT, "left", 0, "+lookleft");
add_key(SDL_SCANCODE_RIGHT, "right", 0, "+lookright");
add_key(SDL_SCANCODE_UP, "up", 0, "+lookup");
add_key(SDL_SCANCODE_DOWN, "down", 0, "+lookdown");
diff --git a/src/client/mainmenu.cc b/src/client/mainmenu.cc
index 823ebfb..0e61655 100644
--- a/src/client/mainmenu.cc
+++ b/src/client/mainmenu.cc
@@ -11,6 +11,7 @@
#include "client/mainmenu.h"
#include "client/playersettingsmenu.h"
#include "client/savegamemenu.h"
+#include "client/serverlistmenu.h"
#include "core/core.h"
#include "core/gameinterface.h"
#include "core/application.h"
@@ -218,7 +219,7 @@ void MainMenu::load()
mainmenu_optionsmenu = 0;
// menu to connect to remote servers
- mainmenu_connectmenu = 0;
+ mainmenu_connectmenu = (ui::Widget *) new ServerListMenu(this, "connect");
// load game menu
mainmenu_loadmenu = (ui::Widget *) new SaveGameMenu(this, "load", SaveGameMenu::Load);
diff --git a/src/client/mapwidget.cc b/src/client/mapwidget.cc
index 20bb979..49100b2 100644
--- a/src/client/mapwidget.cc
+++ b/src/client/mapwidget.cc
@@ -24,6 +24,9 @@ MapWidget::MapWidget(ui::Widget *parent) : ui::Widget(parent)
mapwidget_target = 0;
mapwidget_hover_id = 0;
mapwidget_zoom = 1.0f;
+
+ // make sure the map has a tooltip
+ set_tooltip();
}
MapWidget::~MapWidget()
@@ -43,6 +46,12 @@ void MapWidget::set_target(const core::Entity *entity)
void MapWidget::set_zone(core::Zone *zone)
{
mapwidget_zone = zone;
+
+ // verify current target
+ if (mapwidget_target && (mapwidget_zone != mapwidget_target->zone()))
+ {
+ mapwidget_target = nullptr;
+ }
}
bool MapWidget::on_mousepress(const unsigned int button)
@@ -124,11 +133,13 @@ void MapWidget::draw()
// global mouse cursor location
const math::Vector2f cursor(ui::root()->global_mouse_coords());
mapwidget_hover_id = 0;
+ set_tooltip();
// map center
math::Vector2f map_center(map_location[0] + map_size / 2.0f, map_location[1] + map_size / 2.0f);
math::Vector2f icon_location;
const float r = 12.0f; // radius of map icons
+ const float rt = 24.0f; // radius of target icons
float scale = 4096.0f; // map size in game units
math::Color color;
@@ -154,6 +165,7 @@ void MapWidget::draw()
if (math::distancesquared(cursor, icon_location) < (r*r))
{
mapwidget_hover_id = entity->id();
+ set_tooltip(entity->name());
}
if (entity == mapwidget_target)
@@ -264,6 +276,43 @@ void MapWidget::draw()
}
gl::end();
+
+ if (mapwidget_target)
+ {
+ // draw target icon
+ size_t texture_target = 0;
+ if (mapwidget_target->has_flag(core::Entity::Dockable))
+ {
+ texture_target = render::Textures::load("bitmaps/icons/map_dockable");
+ } else {
+ texture_target = render::Textures::load("bitmaps/icons/map_target");
+ }
+
+ icon_location.assign(map_center);
+ icon_location[0] -= map_size / scale * mapwidget_target->location().y();
+ icon_location[1] -= map_size / scale * mapwidget_target->location().x();
+
+ texture_current = render::Textures::bind(texture_target);
+
+ gl::begin(gl::Quads);
+
+ math::Color color(1.0);
+ gl::color(color);
+
+ glTexCoord2f(0.0f, 0.0f);
+ gl::vertex(icon_location.x() - rt, icon_location.y() - rt);
+
+ glTexCoord2f(1.0f, 0.0f);
+ gl::vertex(icon_location.x() + rt, icon_location.y() - rt);
+
+ glTexCoord2f(1.0f, 1.0f);
+ gl::vertex(icon_location.x() + rt, icon_location.y() + rt);
+
+ glTexCoord2f(0.0f, 1.0f);
+ gl::vertex(icon_location.x() - rt, icon_location.y() + rt);
+
+ gl::end();
+ }
// draw localcontrol icon
// TODO draw a ship icon
diff --git a/src/client/mapwindow.cc b/src/client/mapwindow.cc
index 3dbb1fb..23620f8 100644
--- a/src/client/mapwindow.cc
+++ b/src/client/mapwindow.cc
@@ -5,18 +5,23 @@
the terms of the GNU General Public License version 2
*/
-#include "audio/audio.h"
-#include "core/application.h"
-#include "core/entity.h"
-#include "core/entityglobe.h"
#include "client/mapwindow.h"
#include "client/targets.h"
+#include "client/closeiconbutton.h"
+
#include "ui/ui.h"
#include "ui/paint.h"
+
#include "render/gl.h"
#include "render/textures.h"
#include "render/text.h"
+#include "audio/audio.h"
+
+#include "core/application.h"
+#include "core/entity.h"
+#include "core/entityglobe.h"
+
namespace client
{
@@ -82,8 +87,9 @@ MapWindow::MapWindow(ui::Widget *parent) : ui::Window(parent)
mapwindow_maplabel->set_alignment(ui::AlignCenter);
// map buttons
- mapwindow_zonebutton = new ui::IconButton(mapwindow_pane_left, "bitmaps/icons/button_map");
- mapwindow_galaxybutton = new ui::IconButton(mapwindow_pane_left, "bitmaps/icons/button_galaxy");
+ mapwindow_zonebutton = new ui::IconButton(mapwindow_pane_left, "bitmaps/icons/button_map", "Zone map");
+ mapwindow_galaxybutton = new ui::IconButton(mapwindow_pane_left, "bitmaps/icons/button_galaxy", "Galaxy map");
+ mapwindow_galaxybutton->hide();
// ---- window title
mapwindow_titlelabel = new ui::Label(this);
@@ -95,10 +101,8 @@ MapWindow::MapWindow(ui::Widget *parent) : ui::Window(parent)
mapwindow_titlelabel->set_text("STAR CHART");
// close button
- mapwindow_closebutton = new ui::IconButton(mapwindow_titlelabel, "bitmaps/icons/window_close");
+ mapwindow_closebutton = new CloseIconButton(mapwindow_titlelabel);
-
-
hide();
}
@@ -118,6 +122,8 @@ void MapWindow::show()
// show map widget
mapwindow_mode = ShowZone;
mapwindow_galaxymapwidget->hide();
+ mapwindow_galaxybutton->show();
+ mapwindow_zonebutton->hide();
mapwindow_mapwidget->show();
mapwindow_mapwidget->set_zone(core::localplayer()->zone());
mapwindow_maplabel->set_text(mapwindow_mapwidget->zone()->name());
@@ -174,10 +180,10 @@ void MapWindow::resize()
float l = (mapwindow_mapwidget->width() - math::min(mapwindow_mapwidget->width(), mapwindow_mapwidget->height())) * 0.5f;
mapwindow_zonebutton->set_size(icon_size, icon_size);
- mapwindow_zonebutton->set_location(mapwindow_maplabel->left() + l, mapwindow_mapwidget->bottom() + margin_vertical);
+ mapwindow_zonebutton->set_location(mapwindow_maplabel->right() - l - icon_size, mapwindow_mapwidget->bottom() + margin_vertical);
mapwindow_galaxybutton->set_size(icon_size, icon_size);
- mapwindow_galaxybutton->set_location(mapwindow_maplabel->right() - l - icon_size, mapwindow_mapwidget->bottom() + margin_vertical);
+ mapwindow_galaxybutton->set_location(mapwindow_zonebutton->location());
}
// resize right pane
@@ -363,8 +369,10 @@ bool MapWindow::on_emit(ui::Widget *sender, const ui::Widget::Event event, void
if (mapwindow_galaxymapwidget->zone()) {
mapwindow_mode = ShowZone;
mapwindow_galaxymapwidget->hide();
+ mapwindow_galaxybutton->show();
+ mapwindow_zonebutton->hide();
mapwindow_mapwidget->set_zone(mapwindow_galaxymapwidget->zone());
- mapwindow_mapwidget->show();
+ mapwindow_mapwidget->show();
mapwindow_maplabel->set_text(mapwindow_mapwidget->zone()->name());
show_zone_info(mapwindow_mapwidget->zone());
}
@@ -387,6 +395,8 @@ bool MapWindow::on_emit(ui::Widget *sender, const ui::Widget::Event event, void
mapwindow_galaxymapwidget->hide();
mapwindow_maplabel->set_text(mapwindow_mapwidget->zone()->name());
}
+ mapwindow_galaxybutton->show();
+ mapwindow_zonebutton->hide();
return true;
}
@@ -403,6 +413,8 @@ bool MapWindow::on_emit(ui::Widget *sender, const ui::Widget::Event event, void
show_zone_info(mapwindow_galaxymapwidget->zone());
mapwindow_maplabel->set_text("Starsystems");
}
+ mapwindow_galaxybutton->hide();
+ mapwindow_zonebutton->show();
return true;
}
}
diff --git a/src/client/playersettingsmenu.cc b/src/client/playersettingsmenu.cc
index b8992cb..d09b269 100644
--- a/src/client/playersettingsmenu.cc
+++ b/src/client/playersettingsmenu.cc
@@ -5,6 +5,7 @@
*/
#include "client/playersettingsmenu.h"
+#include "client/closeiconbutton.h"
#include "core/cvar.h"
#include "ui/button.h"
#include "ui/colorpicker.h"
@@ -34,7 +35,7 @@ PlayerSettingsMenu::PlayerSettingsMenu(ui::Widget *parent, const char *label) :
_titlelabel->set_text("PLAYER SETTINGS");
// close button
- _closebutton = new ui::IconButton(_titlelabel, "bitmaps/icons/window_close");
+ _closebutton = new CloseIconButton(_titlelabel);
// content frame
_frame = new ui::Widget(this);
diff --git a/src/client/reputationwindow.cc b/src/client/reputationwindow.cc
index e60b384..cbda138 100644
--- a/src/client/reputationwindow.cc
+++ b/src/client/reputationwindow.cc
@@ -4,14 +4,14 @@
the terms of the GNU General Public License version 2
*/
-#include <iomanip>
-
-#include "ui/paint.h"
-#include "ui/ui.h"
#include "client/client.h"
#include "client/reputationwindow.h"
+#include "client/closeiconbutton.h"
+#include "ui/paint.h"
+#include "ui/ui.h"
#include "core/reputation.h"
#include "core/range.h"
+#include <iomanip>
namespace client {
@@ -110,7 +110,7 @@ ReputationWindow::ReputationWindow(ui::Widget *parent) : ui::Window(parent)
reputationwindow_titlelabel->set_text("REPUTATION");
// close button
- reputationwindow_closebutton = new ui::IconButton(reputationwindow_titlelabel, "bitmaps/icons/window_close");
+ reputationwindow_closebutton = new CloseIconButton(reputationwindow_titlelabel);
// reputation listview
reputationwindow_listview = new ui::ListView(this);
diff --git a/src/client/savegamemenu.cc b/src/client/savegamemenu.cc
index 1b47101..aa43087 100644
--- a/src/client/savegamemenu.cc
+++ b/src/client/savegamemenu.cc
@@ -4,25 +4,31 @@
the terms of the GNU General Public License version 2
*/
-#include <iomanip>
-#include <cstdio>
-
-#include "core/application.h"
-#include "core/gameinterface.h"
-#include "core/gameserver.h"
-#include "model/material.h"
#include "client/savegamemenu.h"
+#include "client/closeiconbutton.h"
#include "client/video.h"
-#include "filesystem/filesystem.h"
+
+#include "ui/ui.h"
+
+#include "model/material.h"
+
#include "render/screenshot.h"
#include "render/camera.h"
#include "render/draw.h"
#include "render/textures.h"
#include "render/gl.h"
-#include "ui/ui.h"
+#include "filesystem/filesystem.h"
+
+#include "core/application.h"
+#include "core/gameinterface.h"
+#include "core/gameserver.h"
+
#include "sys/sys.h"
+#include <iomanip>
+#include <cstdio>
+
namespace client
{
@@ -50,9 +56,8 @@ SaveGameMenu::SaveGameMenu(ui::Widget *parent, const char *label, const Mode mod
}
// close button
- savegamemenu_closebutton = new ui::IconButton(savegamemenu_titlelabel, "bitmaps/icons/window_close");
- savegamemenu_closebutton->set_label("close");
-
+ savegamemenu_closebutton = new CloseIconButton(savegamemenu_titlelabel);
+
// file listview
savegamemenu_filelistview = new ui::ListView(this);
savegamemenu_filelistview->set_label("files");
@@ -76,14 +81,14 @@ SaveGameMenu::SaveGameMenu(ui::Widget *parent, const char *label, const Mode mod
savegamemenu_descrlabel->set_background(true);
savegamemenu_descrlabel->set_border(true);
+ // delete button is a child of description label
+ savegamemenu_deletebutton = new ui::IconButton(savegamemenu_descrlabel, "bitmaps/icons/button_delete", "Delete");
+ savegamemenu_deletebutton->set_label("delete");
+
// save button
savegamemenu_savebutton = new ui::Button(this, "Save");
savegamemenu_savebutton->set_label("save");
- // delete button
- savegamemenu_deletebutton = new ui::IconButton(this, "bitmaps/icons/button_delete");
- savegamemenu_deletebutton->set_label("delete");
-
// cancel save/load/overwrite button
savegamemenu_cancelbutton = new ui::Button(this, "Cancel");
savegamemenu_cancelbutton->set_label("cancel");
@@ -109,7 +114,7 @@ SaveGameMenu::~SaveGameMenu()
void SaveGameMenu::resize()
{
const float padding = ui::UI::padding;
- const float icon_size = 24.0f; // small icons
+ const float icon_size = ui::UI::icon_small;
// resize title label
savegamemenu_titlelabel->set_size(width() - padding * 2.0f, savegamemenu_titlelabel->font()->height());
@@ -122,20 +127,13 @@ void SaveGameMenu::resize()
// resize files listview
savegamemenu_filelistview->set_size(
ui::UI::elementsize.width(),
- height() - icon_size - padding * 3.0f - savegamemenu_titlelabel->bottom()
+ height() - 2.0f * padding - savegamemenu_titlelabel->bottom()
);
savegamemenu_filelistview->set_location(
padding,
savegamemenu_titlelabel->bottom() + padding
);
- // resize delete button
- savegamemenu_deletebutton->set_size(icon_size, icon_size);
- savegamemenu_deletebutton->set_location(
- savegamemenu_filelistview->left(),
- savegamemenu_filelistview->bottom() + padding
- );
-
// resize description title
savegamemenu_descrtitle->set_size(
width() - savegamemenu_filelistview->right() - 2.0f * padding,
@@ -149,13 +147,20 @@ void SaveGameMenu::resize()
// resize description label
savegamemenu_descrlabel->set_size(
savegamemenu_descrtitle->width(),
- savegamemenu_filelistview->bottom() - savegamemenu_descrtitle->bottom() - padding
+ savegamemenu_filelistview->bottom() - savegamemenu_descrtitle->bottom() - 2.0f * padding - ui::UI::elementsize.height()
);
savegamemenu_descrlabel->set_location(
savegamemenu_filelistview->right() + padding,
savegamemenu_descrtitle->bottom() + padding
);
+ // resize delete button
+ savegamemenu_deletebutton->set_size(icon_size, icon_size);
+ savegamemenu_deletebutton->set_location(
+ savegamemenu_descrtitle->width() - savegamemenu_deletebutton->width() - padding,
+ padding
+ );
+
// resize screenshot
const model::Material *screenshotmaterial = model::Material::find("ui/screenshot");
if (screenshotmaterial) {
diff --git a/src/client/serverlistmenu.cc b/src/client/serverlistmenu.cc
new file mode 100644
index 0000000..44bd302
--- /dev/null
+++ b/src/client/serverlistmenu.cc
@@ -0,0 +1,173 @@
+/*
+ client/serverlistmenu.cc
+ This file is part of the Osirion project and is distributed under
+ the terms of the GNU General Public License version 2
+*/
+
+#include "client/serverlistmenu.h"
+#include "client/closeiconbutton.h"
+
+#include "ui/ui.h"
+
+#include "core/commandbuffer.h"
+
+#include "sys/sys.h"
+
+
+namespace client
+{
+
+ServerListMenu::ServerListMenu(ui::Widget *parent, const char *label) :
+ ui::Window(parent)
+{
+ set_label(label);
+ set_border(true);
+ set_background(true);
+ set_font(ui::root()->font_small());
+
+ // window title
+ serverlistmenu_titlelabel = new ui::Label(this);
+ serverlistmenu_titlelabel->set_label("connect");
+ serverlistmenu_titlelabel->set_text("CONNECT");
+ serverlistmenu_titlelabel->set_background(false);
+ serverlistmenu_titlelabel->set_border(false);
+ serverlistmenu_titlelabel->set_font(ui::root()->font_large());
+ serverlistmenu_titlelabel->set_alignment(ui::AlignCenter);
+
+ // close button
+ serverlistmenu_closebutton = new CloseIconButton(serverlistmenu_titlelabel);
+
+ // server listview
+ serverlistmenu_serverlistview = new ui::ListView(this);
+ serverlistmenu_serverlistview->set_label("files");
+
+ // save button
+ serverlistmenu_connectbutton = new ui::Button(this, "Connect");
+ serverlistmenu_connectbutton->set_label("connect");
+}
+
+ServerListMenu::~ServerListMenu()
+{
+}
+
+void ServerListMenu::resize()
+{
+ const float padding = ui::UI::padding;
+
+ // resize title label
+ serverlistmenu_titlelabel->set_size(width() - padding * 2.0f, serverlistmenu_titlelabel->font()->height());
+ serverlistmenu_titlelabel->set_location(padding, padding);
+
+ // resize close button
+ serverlistmenu_closebutton->set_size(serverlistmenu_titlelabel->font()->height(), serverlistmenu_titlelabel->font()->height());
+ serverlistmenu_closebutton->set_location(serverlistmenu_titlelabel->width() - serverlistmenu_closebutton->width(), 0);
+
+ // resize files listview
+ serverlistmenu_serverlistview->set_size(
+ width() - padding * 2.0f,
+ height() - ui::UI::elementsize.height() - padding * 3.0f - serverlistmenu_titlelabel->bottom()
+ );
+ serverlistmenu_serverlistview->set_location(
+ padding,
+ serverlistmenu_titlelabel->bottom() + padding
+ );
+
+ // resize connect button
+ serverlistmenu_connectbutton->set_size(ui::UI::elementsize);
+ serverlistmenu_connectbutton->set_location(
+ (width() - padding * 2.0f - serverlistmenu_connectbutton->width()) * 0.5f,
+ height() - padding - serverlistmenu_connectbutton->height()
+ );
+}
+
+void ServerListMenu::refresh()
+{
+ const float padding = ui::UI::padding;
+
+ serverlistmenu_serverlistview->clear();
+ serverlistmenu_connectbutton->show();
+ serverlistmenu_connectbutton->disable();
+
+ // FIXME support custom port numbers
+ ui::ListItem *listitem = new ui::ListItem(serverlistmenu_serverlistview, "osirion.org development server");
+ listitem->set_value("osirion.org");
+ listitem->set_sortkey("");
+
+ listitem->set_font(ui::root()->font_tiny());
+ listitem->set_height(listitem->font()->height() + padding);
+
+ serverlistmenu_serverlistview->sort(false);
+ serverlistmenu_serverlistview->event_resize();
+
+}
+
+void ServerListMenu::hide()
+{
+ Window::hide();
+}
+
+void ServerListMenu::show()
+{
+ Window::show();
+ refresh();
+}
+
+void ServerListMenu::show_connect_info()
+{
+ if (!serverlistmenu_serverlistview->selected()) {
+ serverlistmenu_connectbutton->disable();
+ } else {
+ serverlistmenu_connectbutton->enable();
+ }
+}
+
+void ServerListMenu::connect()
+{
+ if (serverlistmenu_serverlistview->selected()) {
+ std::stringstream str;
+ str << "connect " << serverlistmenu_serverlistview->selected()->value();
+ core::CommandBuffer::exec(str.str());
+ }
+}
+
+bool ServerListMenu::on_keypress(const int key, const unsigned int modifier)
+{
+ if (key == SDLK_ESCAPE) {
+ if (visible()) {
+ // hide the parent mainwindow
+ parent()->hide();
+ return true;
+ }
+ }
+ return false;
+}
+
+bool ServerListMenu::on_emit(ui::Widget *sender, const ui::Widget::Event event, void *data)
+{
+ if (sender == serverlistmenu_closebutton) {
+ if (event == ui::Widget::EventButtonClicked) {
+ // hide the parent mainwindow
+ parent()->hide();
+ return true;
+ }
+ } else if (sender == serverlistmenu_connectbutton) {
+ if (event == ui::Widget::EventButtonClicked) {
+ // do the actual connect and close the window
+ parent()->hide();
+ connect();
+ return true;
+ }
+ } else if (sender == serverlistmenu_serverlistview) {
+ if (event == ui::Widget::EventListViewChanged) {
+ show_connect_info();
+ return true;
+ }
+ }
+
+ return Window::on_emit(sender, event, data);
+}
+
+
+} // namespace client
+
+
diff --git a/src/client/serverlistmenu.h b/src/client/serverlistmenu.h
new file mode 100644
index 0000000..6638bd4
--- /dev/null
+++ b/src/client/serverlistmenu.h
@@ -0,0 +1,70 @@
+/*
+ client/serverlistmenu.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_CLIENT_SERVERLISTMENU_H__
+#define __INCLUDED_CLIENT_SERVERLISTMENU_H__
+
+#include "ui/button.h"
+#include "ui/iconbutton.h"
+#include "ui/inputbox.h"
+#include "ui/label.h"
+#include "ui/listview.h"
+#include "ui/window.h"
+
+namespace client
+{
+
+class ServerListMenu : public ui::Window
+{
+public:
+ enum Mode { Save = 0, Load = 1 };
+
+ ServerListMenu(ui::Widget *parent = 0, const char *label = 0);
+ virtual ~ServerListMenu();
+
+protected:
+
+ /// called when the widget receives a key press
+ virtual bool on_keypress(const int key, const unsigned int modifier);
+
+ /// called if the widget receives an emit evet
+ virtual bool on_emit(ui::Widget *sender, const ui::Widget::Event event, void *data);
+
+ virtual void resize();
+
+ virtual void show();
+
+ virtual void hide();
+
+ void refresh();
+
+ /**
+ * @brief connect to the currently selected server
+ * */
+ void connect();
+
+ /**
+ * @brief show information for the currently selected server
+ * */
+ void show_connect_info();
+
+private:
+
+ ui::Label *serverlistmenu_titlelabel;
+ ui::IconButton *serverlistmenu_closebutton;
+ ui::ListView *serverlistmenu_serverlistview;
+ ui::Button *serverlistmenu_connectbutton;
+
+
+}; // class ServerListMenu
+
+
+} // namespace client
+
+
+#endif // __INCLUDED_CLIENT_SERVERLISTMENU_H__
+
+
diff --git a/src/client/targeticonbutton.cc b/src/client/targeticonbutton.cc
index ebd5ec3..27dfd0e 100644
--- a/src/client/targeticonbutton.cc
+++ b/src/client/targeticonbutton.cc
@@ -12,12 +12,17 @@
namespace client
{
-TargetIconButton::TargetIconButton(Widget *parent, const char *icon, const char *command, unsigned int flags) : IconButton(parent, icon, command)
+TargetIconButton::TargetIconButton(Widget *parent, const char *icon, const char *tooltip, const char *command, unsigned int flags) : IconButton(parent, icon, tooltip, command)
{
set_label("targeticonbutton");
entity_flags = flags;
}
+TargetIconButton::~TargetIconButton()
+{
+ entity_flags = 0;
+}
+
bool TargetIconButton::on_mousepress(const unsigned int button)
{
if (button == SDL_BUTTON_LEFT)
diff --git a/src/client/targeticonbutton.h b/src/client/targeticonbutton.h
index cb6a147..ccc3baf 100644
--- a/src/client/targeticonbutton.h
+++ b/src/client/targeticonbutton.h
@@ -17,7 +17,8 @@ class TargetIconButton : public ui::IconButton
public:
/// special icon button that sends target '@' commands.
- TargetIconButton(Widget *parent, const char *icon, const char *command, unsigned int flags = 0);
+ TargetIconButton(Widget *parent, const char *icon, const char *tooltip = 0, const char *command = 0, unsigned int flags = 0);
+ virtual ~TargetIconButton();
protected:
/**
diff --git a/src/client/testmodelwindow.cc b/src/client/testmodelwindow.cc
index d70fbbf..9778102 100644
--- a/src/client/testmodelwindow.cc
+++ b/src/client/testmodelwindow.cc
@@ -4,10 +4,14 @@
the terms and conditions of the GNU General Public License version 2
*/
+#include "client/testmodelwindow.h"
+#include "client/closeiconbutton.h"
+
#include "ui/ui.h"
#include "ui/paint.h"
-#include "client/testmodelwindow.h"
+
#include "model/model.h"
+
#include "core/gameinterface.h"
namespace client
@@ -26,9 +30,9 @@ TestModelWindow::TestModelWindow(ui::Widget *parent)
testmodelwindow_text->set_background(false);
testmodelwindow_text->set_border(false);
- testmodelwindow_wireframebutton = new ui::IconButton(this, "bitmaps/icons/button_wireframe", "toggle r_wireframe");
+ testmodelwindow_wireframebutton = new ui::IconButton(this, "bitmaps/icons/button_wireframe", "Toggle wireframe", "toggle r_wireframe");
- testmodelwindow_normalsbutton = new ui::IconButton(this, "bitmaps/icons/button_normals", "toggle r_normals");
+ testmodelwindow_normalsbutton = new ui::IconButton(this, "bitmaps/icons/button_normals", "Toggle normals", "toggle r_normals");
testmodelwindow_closebutton = new ui::Button(this);
testmodelwindow_closebutton->set_text("Close");
diff --git a/src/client/trademenu.cc b/src/client/trademenu.cc
index a16c5c4..62ad972 100644
--- a/src/client/trademenu.cc
+++ b/src/client/trademenu.cc
@@ -4,16 +4,19 @@
the terms of the GNU General Public License version 2
*/
-#include <iomanip>
+#include "client/trademenu.h"
+#include "client/closeiconbutton.h"
-#include "core/application.h"
-#include "core/info.h"
-#include "core/inventory.h"
#include "ui/button.h"
#include "ui/paint.h"
#include "ui/ui.h"
#include "ui/listitem.h"
-#include "client/trademenu.h"
+
+#include "core/application.h"
+#include "core/info.h"
+#include "core/inventory.h"
+
+#include <iomanip>
namespace client {
@@ -76,7 +79,7 @@ TradeMenu::TradeMenu(ui::Widget *parent, const char * label) : ui::Window(parent
menu_titlelabel->show();
// close button
- menu_closebutton = new ui::IconButton(menu_titlelabel, "bitmaps/icons/window_close");
+ menu_closebutton = new CloseIconButton(menu_titlelabel);
menu_inventorylistview = new InventoryListView(menu_tradewindow);
menu_inventorylistview->set_label("inventorylistview");
diff --git a/src/client/video.cc b/src/client/video.cc
index 5f8c14d..15f1c04 100644
--- a/src/client/video.cc
+++ b/src/client/video.cc
@@ -260,7 +260,7 @@ void restart()
shutdown();
// clear models and materials
- /* resetting the rednder subsystem will force a reload of all materials
+ /* resetting the render subsystem will force a reload of all materials
*/
model::Model::clear();
diff --git a/src/core/entity.cc b/src/core/entity.cc
index f7501f7..5cf1015 100644
--- a/src/core/entity.cc
+++ b/src/core/entity.cc
@@ -39,10 +39,9 @@ size_t Entity::entity_nextid = 0;
void Entity::add(Entity *ent)
{
- Registry::iterator it;
entity_nextid = (entity_nextid % MAX_ENTITY) + 1; // lowest entity-id is 1
unsigned int id = entity_nextid;
- for (it = entity_registry.begin(); it != entity_registry.end() && id == (*it).second->id(); it++) {
+ for (Registry::iterator it = entity_registry.begin(); it != entity_registry.end() && id == (*it).second->id(); ++it) {
id++;
}
ent->entity_id = id;
@@ -94,7 +93,7 @@ void Entity::erase(unsigned int id)
void Entity::clear()
{
- for (Entity::Registry::iterator it = Entity::registry().begin(); it != Entity::registry().end(); it++) {
+ for (Entity::Registry::iterator it = Entity::registry().begin(); it != Entity::registry().end(); ++it) {
delete(*it).second;
}
Entity::registry().clear();
@@ -122,7 +121,7 @@ void Entity::list(const Entity *entity)
void Entity::list()
{
list_header();
- for (Registry::iterator it = entity_registry.begin(); it != entity_registry.end(); it++) {
+ for (Registry::iterator it = entity_registry.begin(); it != entity_registry.end(); ++it) {
std::string typeindicator;
Entity *entity = (*it).second;
list(entity);
@@ -215,7 +214,7 @@ Entity::~Entity()
}
// delete entity menus
- for (Menus::iterator mit = menus().begin(); mit != menus().end(); mit++) {
+ for (Menus::iterator mit = menus().begin(); mit != menus().end(); ++mit) {
delete (*mit);
(*mit) = 0;
}
@@ -247,7 +246,7 @@ Entity::~Entity()
}
// delete child collision shapes
- for (CollisionShapes::iterator sit = entity_collision_child_shapes.begin(); sit != entity_collision_child_shapes.end(); sit++) {
+ for (CollisionShapes::iterator sit = entity_collision_child_shapes.begin(); sit != entity_collision_child_shapes.end(); ++sit) {
delete (*sit);
(*sit) = 0;
}
@@ -683,7 +682,7 @@ void Entity::add_menu(MenuDescription *menu)
MenuDescription *Entity::find_menu(std::string const &label)
{
- for (Menus::iterator it = menus().begin(); it != menus().end(); it++) {
+ for (Menus::iterator it = menus().begin(); it != menus().end(); ++it) {
if (label.compare((*it)->label()) == 0)
return (*it);
}
@@ -692,7 +691,7 @@ MenuDescription *Entity::find_menu(std::string const &label)
void Entity::remove_menu(std::string const &label)
{
- for (Menus::iterator it = menus().begin(); it != menus().end(); it++) {
+ for (Menus::iterator it = menus().begin(); it != menus().end(); ++it) {
if (label.compare((*it)->label()) == 0) {
menus().erase(it);
return;
@@ -767,8 +766,7 @@ void Entity::reset()
// a valid collision model has been found, use it to construct a compoundshape
btCompoundShape *compoundshape = new btCompoundShape();
- for (model::CollisionModel::CollisionMeshes::iterator it = model()->collisionmodel()->meshes().begin();
- it != model()->collisionmodel()->meshes().end(); it++) {
+ for (model::CollisionModel::CollisionMeshes::iterator it = model()->collisionmodel()->meshes().begin(); it != model()->collisionmodel()->meshes().end(); ++it) {
model::CollisionMesh *mesh = (*it);
@@ -780,7 +778,7 @@ void Entity::reset()
const float meshscale = mesh->scale() * modelscale;
const btVector3 meshscalevec(meshscale, meshscale, meshscale);
- // TODO
+ // FIXME
// This does not work as advertized, it is actually the underlying mesh that
// gets scaled. If there are multiple entities with the same model at a different scale,
// the scale is set per-model instead of per-entity
@@ -1006,7 +1004,7 @@ void EntityDynamic::reset()
entity_collision_shape = 0;
}
- for (CollisionShapes::iterator sit = entity_collision_child_shapes.begin(); sit != entity_collision_child_shapes.end(); sit++) {
+ for (CollisionShapes::iterator sit = entity_collision_child_shapes.begin(); sit != entity_collision_child_shapes.end(); ++sit) {
delete (*sit);
(*sit) = 0;
}
@@ -1042,8 +1040,8 @@ void EntityDynamic::reset()
if (model()->collisionmodel() && model()->collisionmodel()->size()) {
// complex collision is enabled and a valid collision model has been found
btCompoundShape *compoundshape = new btCompoundShape();
- for (model::CollisionModel::CollisionMeshes::iterator it = model()->collisionmodel()->meshes().begin();
- it != model()->collisionmodel()->meshes().end(); it++) {
+
+ for (model::CollisionModel::CollisionMeshes::iterator it = model()->collisionmodel()->meshes().begin(); it != model()->collisionmodel()->meshes().end(); ++it) {
model::CollisionMesh *mesh = (*it);
@@ -1388,7 +1386,7 @@ void EntityControlable::receive_server_create(std::istream &is)
int owner_id = 0;
is >> owner_id;
if (owner_id && !owner()) {
- for (GameInterface::Players::iterator pit = game()->players().begin();!owner() && (pit != game()->players().end()); pit++) {
+ for (GameInterface::Players::iterator pit = game()->players().begin(); !owner() && (pit != game()->players().end()); ++pit) {
Player *player = (*pit);
if (player->id() == owner_id) {
player->add_asset(this);
@@ -1595,7 +1593,7 @@ void EntityControlable::reset()
entity_collision_shape = 0;
}
- for (CollisionShapes::iterator sit = entity_collision_child_shapes.begin(); sit != entity_collision_child_shapes.end(); sit++) {
+ for (CollisionShapes::iterator sit = entity_collision_child_shapes.begin(); sit != entity_collision_child_shapes.end(); ++sit) {
delete (*sit);
(*sit) = 0;
}
@@ -1631,8 +1629,7 @@ void EntityControlable::reset()
if (model()->collisionmodel() && model()->collisionmodel()->size()) {
// a valid collision model has been found
btCompoundShape *compoundshape = new btCompoundShape();
- for (model::CollisionModel::CollisionMeshes::iterator it = model()->collisionmodel()->meshes().begin();
- it != model()->collisionmodel()->meshes().end(); it++) {
+ for (model::CollisionModel::CollisionMeshes::iterator it = model()->collisionmodel()->meshes().begin(); it != model()->collisionmodel()->meshes().end(); ++it) {
model::CollisionMesh *mesh = (*it);
diff --git a/src/model/mapfile.cc b/src/model/mapfile.cc
index 3adcbb0..99601a6 100644
--- a/src/model/mapfile.cc
+++ b/src/model/mapfile.cc
@@ -459,7 +459,7 @@ bool MapFile::read_patchdef()
// binomial coefficient
const float binom[3] = {1.0f, 2.0f, 1.0f};
- const size_t subdivide_max = 4;
+ const size_t subdivide_max = 8;
size_t subdivide_u = 0;
size_t subdivide_v = 0;
diff --git a/src/model/objfile.cc b/src/model/objfile.cc
index 49a691f..323986b 100644
--- a/src/model/objfile.cc
+++ b/src/model/objfile.cc
@@ -34,6 +34,9 @@ OBJFile::OBJFile(std::string const &name)
// reset counters
obj_normalcount = 0;
+
+ obj_collisionmodel = nullptr;
+ obj_load_clip = false;
}
OBJFile::~OBJFile()
@@ -132,9 +135,11 @@ bool OBJFile::read()
std::string materialname;
material = 0;
- if (line >> materialname) {
- for(MaterialList::iterator it = obj_materiallist.begin(); it != obj_materiallist.end(); ++it) {
- if( (*it).second->name() == materialname) {
+ if (line >> materialname)
+ {
+ for(MaterialList::iterator it = obj_materiallist.begin(); it != obj_materiallist.end(); ++it)
+ {
+ if( (*it).second->name().compare(materialname) == 0) {
material = (*it).second;
current_m = (*it).first;
break;
@@ -146,12 +151,12 @@ bool OBJFile::read()
obj_materiallist[obj_materiallist.size()] = material;
current_m = obj_materiallist.size()-1;
}
- }
- else
+ } else {
con_warn << objfile_name << " invalid material definition at line " << index_line << std::endl;
+ }
- } else if (word.compare("v") == 0) { /* new wertex */
+ } else if (word.compare("v") == 0) { /* new vertex */
float x, y, z;
line >> x >> y >> z;
@@ -159,14 +164,14 @@ bool OBJFile::read()
obj_vertexlist[obj_vertexlist.size()] = v;
obj_box.expand(*v * SCALE);
- } else if (word.compare("vt") == 0) { /* wertex texture coordinate */
+ } else if (word.compare("vt") == 0) { /* vertex texture coordinate */
float u, v;
line >> u >> v;
math::Vector2f *uv = new math::Vector2f(u, v);
obj_uvlist[obj_uvlist.size()] = uv;
- } else if (word.compare("vn") == 0) { /* wertex wormal */
+ } else if (word.compare("vn") == 0) { /* vertex normal */
float x, y, z;
line >> x >> y >> z;
@@ -352,34 +357,64 @@ bool OBJFile::read()
//Go through tri and quad lists and create fragments for each material
size_t total_m = obj_materiallist.size();
- for(size_t i = 0; i <= total_m; i++) {
+ for(size_t i = 0; i < total_m; i++)
+ {
material = obj_materiallist[i];
- fragment = new Fragment(Fragment::Triangles, material);
- for(TriList::iterator it = obj_trilist.begin(); it != obj_trilist.end(); ++it) {
- if((*it).first == i) {
- fragment->add_vertex(((*it).second->v0() * SCALE) , (*it).second->n0(), (*it).second->t0(), false);
- fragment->add_vertex(((*it).second->v1() * SCALE) , (*it).second->n1(), (*it).second->t1(), false);
- fragment->add_vertex(((*it).second->v2() * SCALE) , (*it).second->n2(), (*it).second->t2(), false);
+ if (material->has_flag_clip()) // add mesh to the collision model if the material has the Clip flag set
+ {
+ CollisionMesh *collisionmesh = new CollisionMesh();
+
+ // add triangles to the collision mesh
+ for(TriList::iterator it = obj_trilist.begin(); it != obj_trilist.end(); ++it)
+ {
+ if((*it).first == i)
+ {
+ collisionmesh->add_triangle((*it).second->v0() * SCALE, (*it).second->v1() * SCALE, (*it).second->v2() * SCALE);
+ }
}
- }
-
- if( fragment->structural_size() + fragment->detail_size() > 0 )
- obj_fragmentgroup->add_fragment(fragment);
- fragment = new Fragment(Fragment::Quads, material);
-
- for(QuadList::iterator it = obj_quadlist.begin(); it != obj_quadlist.end(); ++it) {
- if((*it).first == i) {
- fragment->add_vertex(((*it).second->v0() * SCALE) , (*it).second->n0(), (*it).second->t0(), false);
- fragment->add_vertex(((*it).second->v1() * SCALE) , (*it).second->n1(), (*it).second->t1(), false);
- fragment->add_vertex(((*it).second->v2() * SCALE) , (*it).second->n2(), (*it).second->t2(), false);
- fragment->add_vertex(((*it).second->v3() * SCALE) , (*it).second->n3(), (*it).second->t3(), false);
+ for(QuadList::iterator it = obj_quadlist.begin(); it != obj_quadlist.end(); ++it)
+ {
+ if((*it).first == i)
+ {
+ collisionmesh->add_triangle((*it).second->v0() * SCALE, (*it).second->v1() * SCALE, (*it).second->v2() * SCALE);
+ collisionmesh->add_triangle((*it).second->v2() * SCALE, (*it).second->v3() * SCALE, (*it).second->v0() * SCALE);
+ }
}
+
+ obj_collisionmodel->add_mesh(collisionmesh);
+ }
+ else if (!material->has_flag_ignore()) // do not load meshes if the material has the Ignore flag
+ {
+
+ fragment = new Fragment(Fragment::Triangles, material);
+
+ for(TriList::iterator it = obj_trilist.begin(); it != obj_trilist.end(); ++it) {
+ if((*it).first == i) {
+ fragment->add_vertex(((*it).second->v0() * SCALE) , (*it).second->n0(), (*it).second->t0(), false);
+ fragment->add_vertex(((*it).second->v1() * SCALE) , (*it).second->n1(), (*it).second->t1(), false);
+ fragment->add_vertex(((*it).second->v2() * SCALE) , (*it).second->n2(), (*it).second->t2(), false);
+ }
+ }
+
+ if( fragment->structural_size() + fragment->detail_size() > 0 )
+ obj_fragmentgroup->add_fragment(fragment);
+
+ fragment = new Fragment(Fragment::Quads, material);
+
+ for(QuadList::iterator it = obj_quadlist.begin(); it != obj_quadlist.end(); ++it) {
+ if((*it).first == i) {
+ fragment->add_vertex(((*it).second->v0() * SCALE) , (*it).second->n0(), (*it).second->t0(), false);
+ fragment->add_vertex(((*it).second->v1() * SCALE) , (*it).second->n1(), (*it).second->t1(), false);
+ fragment->add_vertex(((*it).second->v2() * SCALE) , (*it).second->n2(), (*it).second->t2(), false);
+ fragment->add_vertex(((*it).second->v3() * SCALE) , (*it).second->n3(), (*it).second->t3(), false);
+ }
+ }
+
+ if( fragment->structural_size() + fragment->detail_size() > 0 )
+ obj_fragmentgroup->add_fragment(fragment);
}
-
- if( fragment->structural_size() + fragment->detail_size() > 0 )
- obj_fragmentgroup->add_fragment(fragment);
}
return true;
@@ -387,22 +422,34 @@ bool OBJFile::read()
Model *OBJFile::load(const std::string &name)
{
+
OBJFile objfile(name);
-
if (!objfile.is_open()) {
- return 0;
+ return nullptr;
}
- if (!objfile.read()) {
- return 0;
- }
-
- if (!objfile.fragmentgroup()->size())
- return 0;
-
// create a new model
Model *model = new Model(name);
+ // load clip into collision meshes
+ // if the model has been loaded before (e.g. on r_restart), the collision model won't be reloaded
+ objfile.obj_collisionmodel = CollisionModel::find(name);
+ if (!objfile.obj_collisionmodel)
+ {
+ objfile.obj_load_clip = true;
+ objfile.obj_collisionmodel = new CollisionModel(name);
+ CollisionModel::add(objfile.obj_collisionmodel);
+ } else {
+ objfile.obj_load_clip = false;
+ }
+ model->set_collisionmodel(objfile.obj_collisionmodel);
+
+ if (!objfile.read() || !objfile.fragmentgroup()->size())
+ {
+ con_warn << " " << objfile.name() << " empty model" << std::endl;
+ return model;
+ }
+
// center model around (0,0,0) and set the bounding box
math::Vector3f obj_center((objfile.box().min() + objfile.box().max()) * 0.5f);
model->model_box.assign(
@@ -414,7 +461,8 @@ Model *OBJFile::load(const std::string &name)
objfile.fragmentgroup()->set_location(obj_center * -1.0f);
- for (FragmentGroup::Fragments::const_iterator fit = objfile.fragmentgroup()->fragments().begin(); fit != objfile.fragmentgroup()->fragments().end(); fit++) {
+ for (FragmentGroup::Fragments::const_iterator fit = objfile.fragmentgroup()->fragments().begin(); fit != objfile.fragmentgroup()->fragments().end(); ++fit)
+ {
const Fragment *fragment = (*fit);
if(fragment->type() == Fragment::Triangles)
diff --git a/src/model/objfile.h b/src/model/objfile.h
index 7db90bc..b8286dc 100644
--- a/src/model/objfile.h
+++ b/src/model/objfile.h
@@ -32,7 +32,7 @@ class OBJFile
public:
/**
* @brief load a .obj file into a Model
- * @param name name of the model to be loaded, without .obj extension or models/ prefix
+ * @param name name of the model to be loaded, without .obj extension.
* If the file can not be read, load() returns the NULL-pointer
*/
static Model *load(std::string const &name);
@@ -66,7 +66,7 @@ private:
bool read();
/**
- * @brief parse a line in the .obj file.
+ * @brief parse a line in the .obj file
*/
void readline(std::string const &line);
@@ -112,6 +112,9 @@ private:
FragmentGroup *obj_fragmentgroup;
size_t obj_normalcount;
+
+ bool obj_load_clip;
+ CollisionModel *obj_collisionmodel;
};
} // namespace model
diff --git a/src/model/vertexarray.h b/src/model/vertexarray.h
index 1474c67..5f542a8 100644
--- a/src/model/vertexarray.h
+++ b/src/model/vertexarray.h
@@ -13,7 +13,7 @@ namespace model
{
// number of segments in a sphere circle, must be uneven
-const int SPHERESEGMENTS = 65;
+const int SPHERESEGMENTS = 127;
/// global geometry vertex array
/** a VertexArray acts like a stack of model vertices, it has no knowledge of what it is holding
diff --git a/src/render/tgafile.cc b/src/render/tgafile.cc
index 15447df..ee12f8a 100644
--- a/src/render/tgafile.cc
+++ b/src/render/tgafile.cc
@@ -353,7 +353,7 @@ void TGA::save(const char *filename, Image & image)
// write footer (optional, but the specification recommends it)
char footer[26];
memset(footer, 0, sizeof(footer));
- strncpy(&footer[8] , "TRUEVISION-XFILE", 16);
+ memcpy(footer + 8 , "TRUEVISION-XFILE", 16);
footer[24] = '.';
footer[25] = 0;
ofs.write(footer, sizeof(footer));
diff --git a/src/ui/Makefile.am b/src/ui/Makefile.am
index 1485565..875ffcd 100644
--- a/src/ui/Makefile.am
+++ b/src/ui/Makefile.am
@@ -29,6 +29,7 @@ noinst_HEADERS = \
scrollpane.h \
slider.h \
toolbar.h \
+ tooltip.h \
ui.h \
widget.h \
window.h
@@ -53,6 +54,7 @@ libui_la_SOURCES = \
scrollpane.cc \
slider.cc \
toolbar.cc \
+ tooltip.cc \
ui.cc \
widget.cc \
window.cc
diff --git a/src/ui/font.h b/src/ui/font.h
index b91120e..be08cfd 100644
--- a/src/ui/font.h
+++ b/src/ui/font.h
@@ -27,10 +27,16 @@ public:
return font_size;
}
+ /**
+ * @brief width of a single character
+ * */
inline float width() const {
return font_size.width();
}
+ /**
+ * @height width of a single character
+ * */
inline float height() const {
return font_size.height();
}
diff --git a/src/ui/iconbutton.cc b/src/ui/iconbutton.cc
index 18bfb5a..c23ed66 100644
--- a/src/ui/iconbutton.cc
+++ b/src/ui/iconbutton.cc
@@ -18,14 +18,15 @@
namespace ui
{
-IconButton::IconButton(Widget *parent, const char *icon, const char *command) : Widget(parent)
+IconButton::IconButton(Widget *parent, const char *icon, const char *tooltip, const char *command) : Widget(parent)
{
set_label("iconbutton");
set_background(false);
set_border(false);
- set_command(command);
- set_icon(icon);
set_highlight(false);
+ set_icon(icon);
+ set_tooltip(tooltip);
+ set_command(command);
}
IconButton::~IconButton()
diff --git a/src/ui/iconbutton.h b/src/ui/iconbutton.h
index 92e73ee..0382e1a 100644
--- a/src/ui/iconbutton.h
+++ b/src/ui/iconbutton.h
@@ -15,8 +15,8 @@ namespace ui
class IconButton : public Widget
{
public:
- IconButton(Widget *parent, const char *icon = 0, const char *command = 0);
- ~IconButton();
+ IconButton(Widget *parent, const char *icon = 0, const char *tooltip = 0, const char *command = 0);
+ virtual ~IconButton();
/// the command this button executes
inline const std::string & command() const {
diff --git a/src/ui/label.h b/src/ui/label.h
index f187520..f187744 100644
--- a/src/ui/label.h
+++ b/src/ui/label.h
@@ -12,7 +12,6 @@
namespace ui
{
-
/**
* @brief a widget displaying a single line of text
*/
@@ -20,7 +19,7 @@ class Label : public Widget
{
public:
Label(Widget *parent, const char *text = 0);
- ~Label();
+ virtual ~Label();
/// set the text displayed by the label
void set_text(const std::string &text);
diff --git a/src/ui/toolbar.h b/src/ui/toolbar.h
index baff21b..ccb3d30 100644
--- a/src/ui/toolbar.h
+++ b/src/ui/toolbar.h
@@ -27,7 +27,7 @@ public:
protected:
/// re-arrange child widgets
- void resize();
+ virtual void resize();
};
}
diff --git a/src/ui/tooltip.cc b/src/ui/tooltip.cc
new file mode 100644
index 0000000..1777d33
--- /dev/null
+++ b/src/ui/tooltip.cc
@@ -0,0 +1,90 @@
+/*
+ ui/tooltip.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/tooltip.h"
+#include "ui/ui.h"
+#include "ui/paint.h"
+
+#include <cassert>
+
+namespace ui
+{
+
+Tooltip *Tooltip::tooltip_global = nullptr;
+
+Tooltip::Tooltip(Widget *parent) : Label(parent)
+{
+ set_label("tooltip");
+ set_alignment(AlignCenter);
+ set_background(true);
+ set_visible(false);
+}
+
+Tooltip::~Tooltip()
+{
+}
+
+void Tooltip::resize()
+{
+ set_size(font()->width() * text().size() + UI::padding, font()->height() + UI::padding);
+}
+
+void Tooltip::draw_background()
+{
+ Paint::draw_material(global_location(), size(), "ui/window");
+}
+
+void Tooltip::draw()
+{
+ if (tooltip_global != this)
+ {
+ hide();
+ } else {
+ Label::draw();
+ }
+}
+
+void Tooltip::show()
+{
+ if ((tooltip_global != nullptr) && (tooltip_global != this)) {
+ tooltip_global->hide();
+ }
+ tooltip_global = this;
+ event_resize();
+
+ Label::show();
+}
+
+void Tooltip::hide()
+{
+ if (tooltip_global == this) {
+ tooltip_global = nullptr;
+ }
+ Label::hide();
+}
+
+void Tooltip::event_draw()
+{
+}
+
+void Tooltip::event_draw_global()
+{
+ if (tooltip_global && tooltip_global->visible())
+ {
+ if (tooltip_global->background())
+ tooltip_global->draw_background();
+
+ if (tooltip_global->border())
+ tooltip_global->draw_border();
+
+ tooltip_global->draw();
+
+ if (debug())
+ tooltip_global->draw_debug();
+ }
+}
+
+}
diff --git a/src/ui/tooltip.h b/src/ui/tooltip.h
new file mode 100644
index 0000000..629863a
--- /dev/null
+++ b/src/ui/tooltip.h
@@ -0,0 +1,80 @@
+/*
+ ui/tooltip.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_TOOLTIP_H__
+#define __INCLUDED_UI_TOOLTIP_H__
+
+#include "ui/label.h"
+
+namespace ui
+{
+ /**
+ * @brief a widget displaying a tooltip.
+ * This class makes sure only one Tooltip is globally visible.
+ */
+class Tooltip : public Label
+{
+ public:
+ Tooltip(Widget *parent);
+ virtual ~Tooltip();
+
+ /**
+ * @brief resize the tooltip
+ * */
+ virtual void resize();
+
+ /**
+ * @brief show the tooltip
+ * */
+ virtual void show();
+
+ /**
+ * @brief hide the tooltip
+ * */
+ virtual void hide();
+
+ /**
+ * @brief draw event distributor
+ * The default draw event distributor is overwritten to do nothing.
+ * Tooltips are drawn separately because the need to be on top of everything else.
+ * @see event_draw_global
+ * */
+ virtual void event_draw();
+
+ /**
+ * @brief global draw event distributor
+ * This is called by the user interface to draw the tooltip after everything else.
+ * */
+ static void event_draw_global();
+
+ /**
+ * @brief the tooltip that is currently visible, nullptr if no tooltip is currently shown
+ *
+ * */
+ static inline Tooltip *global()
+ {
+ return tooltip_global;
+ }
+
+ protected:
+ /**
+ * @brief draw the tooltip
+ */
+ virtual void draw();
+
+ /**
+ * @brief draw the tooltip background
+ */
+ virtual void draw_background();
+
+ private:
+
+ static Tooltip *tooltip_global;
+};
+
+}
+
+#endif // __INCLUDED_UI_TOOLTIP_H__
diff --git a/src/ui/ui.cc b/src/ui/ui.cc
index 0877519..95b18e2 100644
--- a/src/ui/ui.cc
+++ b/src/ui/ui.cc
@@ -4,13 +4,11 @@
the terms of the GNU General Public License version 2
*/
-#include <string>
-#include <sstream>
-
#include "audio/audio.h"
#include "auxiliary/functions.h"
#include "core/core.h"
#include "core/application.h"
+#include "core/cvar.h"
#include "filesystem/filesystem.h"
#include "render/gl.h"
#include "sys/sys.h"
@@ -20,6 +18,10 @@
#include "ui/ui.h"
#include "ui/widget.h"
+#include <string>
+#include <sstream>
+#include <cassert>
+
namespace ui
{
@@ -32,8 +34,12 @@ math::Vector2f UI::elementsize(256, 32);
float UI::padding = 24.0f;
float UI::margin = 16.0f;
+float UI::icon_small = 24.0f;
+
float UI::pointer_size = 48.0f;
+core::Cvar *ui_tooltiptimeout = nullptr;
+
UI *global_ui = 0;
UI *root()
@@ -44,6 +50,9 @@ UI *root()
void init()
{
con_print << "^BInitializing user interface..." << std::endl;
+
+ ui_tooltiptimeout = core::Cvar::get("ui_tooltiptimeout", "250", core::Cvar::Archive);
+ ui_tooltiptimeout->set_info("[int] time in milliseconds before a tooltip is shown");
if (!global_ui) {
global_ui = new UI();
@@ -94,6 +103,7 @@ UI::UI() : Window(0)
mouse_pointer_bitmap.assign("pointer");
mouse_buttonleft_pressed = false;
+ ui_tooltip_timestamp = core::application()->timestamp();
}
UI::~UI()
@@ -266,7 +276,7 @@ void UI::frame()
Widget *f = 0;
if (!mouse_buttonleft_pressed) {
- f = find_mouse_focus(mouse_cursor);
+ f = find_widget_in_location(mouse_cursor);
} else {
f = find_visible_child(ui_mouse_focus);
}
@@ -275,15 +285,38 @@ void UI::frame()
}
ui_mouse_focus = f;
+ // show tooltip if the timeout has expired
+ if (ui_mouse_focus && ui_mouse_focus->tooltip() && ui_mouse_focus->tooltip()->text().size() && ui_mouse_focus->tooltip()->hidden())
+ {
+ assert(ui_tooltiptimeout != nullptr);
+ unsigned long timeout = (unsigned long) ui_tooltiptimeout->value();
+
+ if (ui_tooltip_timestamp + timeout < core::application()->timestamp()) {
+ // move the tooltip below the mouse cursor
+ math::Vector2f p(
+ ui_mouse_focus->tooltip()->parent() ?
+ ui_mouse_focus->tooltip()->parent()->to_local_coords(mouse_cursor) :
+ mouse_cursor);
+
+ ui_mouse_focus->tooltip()->set_location(p.x() - ui_mouse_focus->tooltip()->width() * 0.5f, p.y() + pointer_size);
+ ui_mouse_focus->tooltip()->resize();
+ ui_mouse_focus->tooltip()->show();
+ }
+ }
+
// reset mouse pointer
ui::root()->set_pointer("pointer");
// draw the widget stack
event_draw();
-
- // draw the mouse pointer
- if (visible())
+
+ if (visible()) {
+ // draw tooltip
+ Tooltip::event_draw_global();
+
+ // draw the mouse pointer
draw_pointer();
+ }
}
/* -- global event handlers ---------------------------------------- */
@@ -293,6 +326,13 @@ void UI::frame()
*/
void UI::input_mouse(const float x, const float y)
{
+ // hide tooltip if the mouse has been moved
+ if (Tooltip::global() && Tooltip::global()->visible())
+ {
+ Tooltip::global()->hide();
+ }
+ ui_tooltip_timestamp = core::application()->timestamp();
+
mouse_cursor.assign(x, y);
}
@@ -300,13 +340,20 @@ bool UI::input_mouse_button(const bool pressed, unsigned int button)
{
bool handled = false;
+ // hide tooltip if a mouse button has been clicked
+ if (Tooltip::global() && Tooltip::global()->visible())
+ {
+ Tooltip::global()->hide();
+ }
+ ui_tooltip_timestamp = core::application()->timestamp();
+
if (button == SDL_BUTTON_LEFT)
{
mouse_buttonleft_pressed = pressed;
}
// set mouse focus
- Widget *f = find_mouse_focus(mouse_cursor);
+ Widget *f = find_widget_in_location(mouse_cursor);
if (f)
{
f->event_mouse(mouse_cursor);
@@ -326,7 +373,7 @@ bool UI::input_mouse_wheel(const math::Vector2f & direction)
bool handled = false;
// set mouse focus
- Widget *f = find_mouse_focus(mouse_cursor);
+ Widget *f = find_widget_in_location(mouse_cursor);
if (f)
{
f->event_mouse(mouse_cursor);
@@ -399,8 +446,8 @@ void UI::draw_pointer()
gl::push();
gl::translate(mouse_cursor.x(), mouse_cursor.y(), 0);
- float angle = core::application()->time() * 0.75f - floorf(core::application()->time() * 0.75f);
- angle *= 360.0f;
+ const float t = core::application()->time() * 0.75f;
+ const float angle = (t - floorf(t)) * 360.0f;
gl::rotate(angle, math::Vector3f(0, 0, 1.0f));
gl::translate(-mouse_cursor.x(), -mouse_cursor.y(), 0);
}
diff --git a/src/ui/ui.h b/src/ui/ui.h
index aaf4acc..009bed6 100644
--- a/src/ui/ui.h
+++ b/src/ui/ui.h
@@ -10,6 +10,7 @@
#include "ui/console.h"
#include "ui/font.h"
#include "ui/palette.h"
+#include "ui/tooltip.h"
#include "ui/widget.h"
#include "ui/window.h"
@@ -64,7 +65,7 @@ public:
/// load settings from ui.ini
void load_settings();
- /* -- fonts ------------------------------------------------ */
+ /* -- font & icon sizes------------------------------------- */
/// default tiny font
inline const Font *font_tiny() const {
@@ -76,17 +77,18 @@ public:
return ui_font_small;
}
- /// default medium font
+ /// default large font
inline const Font *font_large() const {
return ui_font_large;
}
-
+
+ /* -- mouse pointer ---------------------------------------- */
+
+ /// current position of the mouse cursor in global window coordinates
inline const math::Vector2f & global_mouse_coords()
{
return mouse_cursor;
}
-
- /* -- mouse pointer ---------------------------------------- */
/// set mouse pointer bitmap
void set_pointer(const char *pointerbitmap = 0, const Palette::Color color = Palette::Highlight, const bool animated = false);
@@ -109,7 +111,8 @@ public:
static float pointer_size;
-
+ static float icon_small;
+
protected:
/* -- event handlers --------------------------------------- */
@@ -138,6 +141,8 @@ private:
Palette::Color mouse_pointer_color;
bool mouse_pointer_animated;
bool mouse_buttonleft_pressed;
+
+ unsigned long ui_tooltip_timestamp;
};
/// initialize the user interface
diff --git a/src/ui/widget.cc b/src/ui/widget.cc
index 982b792..73c454a 100644
--- a/src/ui/widget.cc
+++ b/src/ui/widget.cc
@@ -9,6 +9,7 @@
#include "ui/paint.h"
#include "ui/ui.h"
#include "ui/widget.h"
+#include "ui/tooltip.h"
#include <cassert>
@@ -22,8 +23,9 @@ Widget::Widget(Widget *parent)
widget_border = true;
widget_background = false;
widget_enabled = true;
- widget_palette = 0;
- widget_font = 0;
+ widget_palette = nullptr;
+ widget_font = nullptr;
+ widget_tooltip = nullptr;
widget_label.assign("widget");
if (!parent) {
@@ -228,17 +230,33 @@ void Widget::set_label(const std::string & label)
widget_label.assign(label);
aux::to_label(widget_label);
}
-
+
void Widget::set_label(const char *label)
{
- if (label) {
+ if (label == nullptr)
+ {
+ widget_label.clear();
+ } else {
widget_label.assign(label);
aux::to_label(widget_label);
- } else {
- widget_label.clear();
}
}
+
+void Widget::set_tooltip(const std::string &tooltip_text)
+{
+ set_tooltip(tooltip_text.c_str());
+}
+
+void Widget::set_tooltip(const char *tooltip_text)
+{
+ if (widget_tooltip == nullptr)
+ {
+ widget_tooltip = new Tooltip(this);
+ }
+ widget_tooltip->set_text(tooltip_text);
+}
+
void Widget::set_palette(const Palette *palette)
{
widget_palette = palette;
@@ -300,7 +318,7 @@ Widget *Widget::next_sibling()
// find this widget in the parent's children
Children::iterator it = parent()->children().begin();
while (it != parent()->children().end() && ((*it) != this)) {
- it++;
+ it++;
}
// assert this widget is a child of its parent
@@ -384,17 +402,17 @@ Widget *Widget::find_visible_child(const Widget *widget)
return 0;
}
-Widget *Widget::find_mouse_focus(const math::Vector2f & pos)
+Widget *Widget::find_widget_in_location(const math::Vector2f & location)
{
// this widget is not visible
- if (!visible() || !size().contains(pos))
- return 0;
+ if (!visible() || !size().contains(location))
+ return nullptr;
// reverse-iterate children
for (Children::reverse_iterator rit = widget_children.rbegin(); rit != widget_children.rend(); ++rit) {
Widget *w = (*rit);
if (w->visible() && w->enabled()) {
- Widget *f = w->find_mouse_focus(pos - w->location());
+ Widget *f = w->find_widget_in_location(location - w->location());
if (f)
return f;
}
diff --git a/src/ui/widget.h b/src/ui/widget.h
index 14bea7b..9c7871f 100644
--- a/src/ui/widget.h
+++ b/src/ui/widget.h
@@ -23,6 +23,8 @@
namespace ui
{
+class Tooltip;
+
class Widget
{
@@ -129,6 +131,11 @@ public:
inline const std::string &label() const {
return widget_label;
}
+
+ /// widget tooltip
+ inline Tooltip *tooltip() {
+ return widget_tooltip;
+ }
/// true if this widget will draw a background
inline const bool background() const {
@@ -220,29 +227,35 @@ public:
/// set location of the top-left corner, relative to the parent
void set_location(const math::Vector2f &location);
- /// set the widgets width and height
+ /// set the widget's width and height
void set_size(const float w, const float h);
- /// set the widgets width and height
+ /// set the widget's width and height
void set_size(const math::Vector2f &size);
- /// set the widgets width
+ /// set the widget's width
void set_width(const float w);
- /// set the widgets height
+ /// set the widget's height
void set_height(const float h);
- /// set the widgets palette
+ /// set the widget's palette
void set_palette(const Palette *palette);
- /// set the widgets font
+ /// set the widget's font
void set_font(const Font *font);
- /// set the widgets label
+ /// set the widget's label
void set_label(const std::string &label);
- /// set the widgets label
- void set_label(const char *label);
+ /// set the widget's label
+ void set_label(const char *label = nullptr);
+
+ /// set the wdiget's tooltip text
+ void set_tooltip(const std::string &tooltip_text);
+
+ /// set the wdiget's tooltip text
+ void set_tooltip(const char *tooltip_text = nullptr);
/// enable or disable widget border
void set_border(const bool border = true);
@@ -262,7 +275,7 @@ public:
* @brief calls the draw event handler and sends the event to all child widgets
* @see draw
**/
- void event_draw();
+ virtual void event_draw();
/**
* @brief calls the key event handlers and sends unhandled keys to the parent widget
@@ -303,37 +316,14 @@ public:
inline void emit(const Event event, void *data=0) {
event_emit(this, event, data);
}
-
-protected:
-
- /// find the widget that has input focus
- virtual Widget *find_input_focus();
-
- /// find widget that has mouse focus
- /** @param cursor mouse cursor position relative to this widget's location
- */
- Widget *find_mouse_focus(const math::Vector2f & cursor);
- /// find a visible widget
- Widget *find_visible_child(const Widget *widget);
-
- /// list widget content
- size_t list(const size_t indent, const bool visible_only = false) const;
-
- /// print widget description
- virtual void print(const size_t indent) const;
-
- /// true of this sibling has local focus
- inline bool focus() const {
- return widget_focus;
- }
-
+
/* -- coordinate mapping ----------------------------------- */
/// map local widget location to global location
- inline math::Vector2f global_location() {
+ inline const math::Vector2f global_location() const {
math::Vector2f v(widget_location);
- Widget *parent = widget_parent;
+ const Widget *parent = widget_parent;
while (parent) {
v += parent->location();
parent = parent->parent();
@@ -342,9 +332,9 @@ protected:
}
/// map local coordinates to global coordinates
- inline math::Vector2f to_global_coords(const math::Vector2f &local) {
+ inline const math::Vector2f to_global_coords(const math::Vector2f &local) const {
math::Vector2f v(local);
- Widget *parent = widget_parent;
+ const Widget *parent = widget_parent;
do {
v += parent->location();
parent = parent->parent();
@@ -353,9 +343,9 @@ protected:
}
/// map global coordinates to local coordinates
- inline math::Vector2f to_local_coords(const math::Vector2f &global) {
+ inline const math::Vector2f to_local_coords(const math::Vector2f &global) const {
math::Vector2f v(global);
- Widget *parent = this;
+ const Widget *parent = this;
while (parent) {
v -= parent->location();
parent = parent->parent();
@@ -363,6 +353,34 @@ protected:
return v;
}
+protected:
+
+ /// find the widget that has input focus
+ virtual Widget *find_input_focus();
+
+ /**
+ * @brief find the widget in a given location
+ * Searches the widget's children tree for the leaf widget visible in a given location.
+ * If no child contains the location, the widget itself is tested. Returns a nullptr ig
+ * the location is not within the widget's boundries.
+ * @param location search position, relative to this widget's location
+ **/
+ Widget *find_widget_in_location(const math::Vector2f &location);
+
+ /// find a visible widget
+ Widget *find_visible_child(const Widget *widget);
+
+ /// list widget content
+ size_t list(const size_t indent, const bool visible_only = false) const;
+
+ /// print widget description
+ virtual void print(const size_t indent) const;
+
+ /// true of this sibling has local focus
+ inline bool focus() const {
+ return widget_focus;
+ }
+
/* -- event handlers --------------------------------------- */
/// called when the mouse receives mouse movement
@@ -437,6 +455,8 @@ private:
const Palette *widget_palette;
const Font *widget_font;
Widget *widget_parent;
+
+ Tooltip *widget_tooltip;
Children::iterator find_child(Widget *child);