summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/gui/gui.cpp231
-rw-r--r--src/gui/gui.h31
-rw-r--r--src/resources/resourcemanager.cpp15
-rw-r--r--src/resources/resourcemanager.h34
-rw-r--r--src/resources/theme.cpp4
5 files changed, 194 insertions, 121 deletions
diff --git a/src/gui/gui.cpp b/src/gui/gui.cpp
index ae74cab2..dd637170 100644
--- a/src/gui/gui.cpp
+++ b/src/gui/gui.cpp
@@ -32,18 +32,17 @@
#include "client.h"
#include "configuration.h"
-#include "eventlistener.h"
#include "graphics.h"
#include "log.h"
-#include "resources/image.h"
-#include "resources/imageset.h"
#include "resources/resourcemanager.h"
#include "resources/theme.h"
#include <guichan/exception.hpp>
#include <guichan/image.hpp>
+#include <SDL_image.h>
+
// Guichan stuff
Gui *gui = nullptr;
SDLInput *guiInput = nullptr;
@@ -54,30 +53,8 @@ gcn::Font *boldFont = nullptr;
// Mono font
gcn::Font *monoFont = nullptr;
-class GuiConfigListener : public EventListener
-{
- public:
- GuiConfigListener(Gui *g):
- mGui(g)
- {}
-
- void event(Event::Channel channel, const Event &event) override
- {
- if (channel == Event::ConfigChannel)
- {
- if (event.getType() == Event::ConfigOptionChanged &&
- event.getString("option") == "customcursor")
- {
- bool bCustomCursor = config.getBoolValue("customcursor");
- mGui->setUseCustomCursor(bCustomCursor);
- }
- }
- }
- private:
- Gui *mGui;
-};
-
Gui::Gui(Graphics *graphics)
+ : mCustomCursorScale(graphics->getScale())
{
logger->log("Initializing GUI...");
// Set graphics
@@ -146,20 +123,24 @@ Gui::Gui(Graphics *graphics)
std::string("': ") + e.getMessage());
}
+ loadCustomCursors();
+ loadSystemCursors();
+
gcn::Widget::setGlobalFont(mGuiFont);
// Initialize mouse cursor and listen for changes to the option
setUseCustomCursor(config.getBoolValue("customcursor"));
- mConfigListener = new GuiConfigListener(this);
- mConfigListener->listen(Event::ConfigChannel);
+
+ listen(Event::ConfigChannel);
}
Gui::~Gui()
{
- delete mConfigListener;
+ for (auto cursor : mSystemMouseCursors)
+ SDL_FreeCursor(cursor);
- if (mMouseCursors)
- mMouseCursors->decRef();
+ for (auto cursor : mCustomMouseCursors)
+ SDL_FreeCursor(cursor);
delete mGuiFont;
delete boldFont;
@@ -174,14 +155,9 @@ Gui::~Gui()
void Gui::logic()
{
- // Fade out mouse cursor after extended inactivity
- if (mMouseInactivityTimer < 100 * 15)
- {
- ++mMouseInactivityTimer;
- mMouseCursorAlpha = std::min(1.0f, mMouseCursorAlpha + 0.05f);
- }
- else
- mMouseCursorAlpha = std::max(0.0f, mMouseCursorAlpha - 0.005f);
+ // Hide mouse cursor after extended inactivity
+ if (get_elapsed_time(mLastMouseActivityTime) > 15000)
+ SDL_ShowCursor(SDL_DISABLE);
Palette::advanceGradients();
@@ -194,40 +170,30 @@ void Gui::logic()
}
}
-void Gui::draw()
+void Gui::event(Event::Channel channel, const Event &event)
{
- mGraphics->_beginDraw();
-
- mGraphics->pushClipArea(mTop->getDimension());
- mTop->draw(mGraphics);
- mGraphics->popClipArea();
-
- int mouseX;
- int mouseY;
- Uint8 button = SDL_GetMouseState(&mouseX, &mouseY);
- float logicalX;
- float logicalY;
- graphics->windowToLogical(mouseX, mouseY, logicalX, logicalY);
-
- if ((Client::hasMouseFocus() || button & SDL_BUTTON(1))
- && mCustomCursor
- && mMouseCursorAlpha > 0.0f)
+ if (channel == Event::ConfigChannel)
{
- Image *mouseCursor = mMouseCursors->get(static_cast<size_t>(mCursorType));
- mouseCursor->setAlpha(mMouseCursorAlpha);
-
- static_cast<Graphics*>(mGraphics)->drawImageF(
- mouseCursor,
- logicalX - 15,
- logicalY - 17);
+ if (event.getType() == Event::ConfigOptionChanged &&
+ event.getString("option") == "customcursor")
+ {
+ setUseCustomCursor(config.getBoolValue("customcursor"));
+ }
}
-
- mGraphics->_endDraw();
}
bool Gui::videoResized(int width, int height)
{
- TrueTypeFont::updateFontScale(static_cast<Graphics*>(mGraphics)->getScale());
+ const float scale = static_cast<Graphics*>(mGraphics)->getScale();
+
+ TrueTypeFont::updateFontScale(scale);
+
+ if (mCustomCursorScale != scale)
+ {
+ mCustomCursorScale = scale;
+ loadCustomCursors();
+ updateCursor();
+ }
auto *top = static_cast<WindowContainer*>(getTop());
@@ -247,36 +213,33 @@ void Gui::setUseCustomCursor(bool customCursor)
return;
mCustomCursor = customCursor;
+ updateCursor();
+}
- if (mCustomCursor)
- {
- // Hide the SDL mouse cursor
- SDL_ShowCursor(SDL_DISABLE);
+void Gui::setCursorType(Cursor cursor)
+{
+ if (mCursorType == cursor)
+ return;
- // Load the mouse cursor
- mMouseCursors = Theme::getImageSetFromTheme("mouse.png", 40, 40);
+ mCursorType = cursor;
+ updateCursor();
+}
- if (!mMouseCursors)
- logger->error("Unable to load mouse cursors.");
- }
+void Gui::updateCursor()
+{
+ if (mCustomCursor && !mCustomMouseCursors.empty())
+ SDL_SetCursor(mCustomMouseCursors[static_cast<int>(mCursorType)]);
else
- {
- // Show the SDL mouse cursor
- SDL_ShowCursor(SDL_ENABLE);
-
- // Unload the mouse cursor
- if (mMouseCursors)
- {
- mMouseCursors->decRef();
- mMouseCursors = nullptr;
- }
- }
+ SDL_SetCursor(mSystemMouseCursors[static_cast<int>(mCursorType)]);
}
void Gui::handleMouseMoved(const gcn::MouseInput &mouseInput)
{
gcn::Gui::handleMouseMoved(mouseInput);
- mMouseInactivityTimer = 0;
+ mLastMouseActivityTime = tick_time;
+
+ // Make sure the cursor is visible
+ SDL_ShowCursor(SDL_ENABLE);
}
void Gui::handleTextInput(const TextInput &textInput)
@@ -289,3 +252,97 @@ void Gui::handleTextInput(const TextInput &textInput)
}
}
}
+
+static SDL_Surface *loadSurface(const std::string &path)
+{
+ if (SDL_RWops *file = ResourceManager::getInstance()->open(path))
+ return IMG_Load_RW(file, 1);
+ return nullptr;
+}
+
+void Gui::loadCustomCursors()
+{
+ for (auto cursor : mCustomMouseCursors)
+ SDL_FreeCursor(cursor);
+
+ mCustomMouseCursors.clear();
+
+ const std::string cursorPath = Theme::resolveThemePath("mouse.png");
+ SDL_Surface *mouseSurface = loadSurface(cursorPath);
+ if (!mouseSurface)
+ {
+ logger->log("Warning: Unable to load mouse cursor file (%s): %s",
+ cursorPath.c_str(), SDL_GetError());
+ return;
+ }
+
+ SDL_SetSurfaceBlendMode(mouseSurface, SDL_BLENDMODE_NONE);
+
+#if SDL_BYTEORDER == SDL_BIG_ENDIAN
+ const Uint32 rmask = 0xff000000;
+ const Uint32 gmask = 0x00ff0000;
+ const Uint32 bmask = 0x0000ff00;
+ const Uint32 amask = 0x000000ff;
+#else
+ const Uint32 rmask = 0x000000ff;
+ const Uint32 gmask = 0x0000ff00;
+ const Uint32 bmask = 0x00ff0000;
+ const Uint32 amask = 0xff000000;
+#endif
+
+ constexpr int cursorSize = 40;
+ const int targetCursorSize = cursorSize * mCustomCursorScale;
+ const int columns = mouseSurface->w / cursorSize;
+
+ SDL_Surface *cursorSurface = SDL_CreateRGBSurface(
+ 0, targetCursorSize, targetCursorSize, 32,
+ rmask, gmask, bmask, amask);
+
+ for (int i = 0; i <= static_cast<int>(Cursor::DOWN); ++i)
+ {
+ int x = i % columns * cursorSize;
+ int y = i / columns * cursorSize;
+
+ SDL_Rect srcrect = { x, y, cursorSize, cursorSize };
+ SDL_Rect dstrect = { 0, 0, targetCursorSize, targetCursorSize };
+ SDL_BlitScaled(mouseSurface, &srcrect, cursorSurface, &dstrect);
+
+ SDL_Cursor *cursor = SDL_CreateColorCursor(cursorSurface,
+ 15 * mCustomCursorScale,
+ 17 * mCustomCursorScale);
+ if (!cursor)
+ {
+ logger->log("Warning: Unable to create cursor: %s", SDL_GetError());
+ }
+
+ mCustomMouseCursors.push_back(cursor);
+ }
+
+ SDL_FreeSurface(cursorSurface);
+ SDL_FreeSurface(mouseSurface);
+}
+
+void Gui::loadSystemCursors()
+{
+ constexpr struct {
+ Cursor cursor;
+ SDL_SystemCursor systemCursor;
+ } cursors[] = {
+ { Cursor::POINTER, SDL_SYSTEM_CURSOR_ARROW },
+ { Cursor::RESIZE_ACROSS, SDL_SYSTEM_CURSOR_SIZEWE },
+ { Cursor::RESIZE_DOWN, SDL_SYSTEM_CURSOR_SIZENS },
+ { Cursor::RESIZE_DOWN_LEFT, SDL_SYSTEM_CURSOR_SIZENESW },
+ { Cursor::RESIZE_DOWN_RIGHT, SDL_SYSTEM_CURSOR_SIZENWSE },
+ { Cursor::FIGHT, SDL_SYSTEM_CURSOR_HAND },
+ { Cursor::PICKUP, SDL_SYSTEM_CURSOR_HAND },
+ { Cursor::TALK, SDL_SYSTEM_CURSOR_HAND },
+ { Cursor::ACTION, SDL_SYSTEM_CURSOR_HAND },
+ { Cursor::LEFT, SDL_SYSTEM_CURSOR_ARROW },
+ { Cursor::UP, SDL_SYSTEM_CURSOR_ARROW },
+ { Cursor::RIGHT, SDL_SYSTEM_CURSOR_ARROW },
+ { Cursor::DOWN, SDL_SYSTEM_CURSOR_ARROW }
+ };
+
+ for (auto cursor : cursors)
+ mSystemMouseCursors.push_back(SDL_CreateSystemCursor(cursor.systemCursor));
+}
diff --git a/src/gui/gui.h b/src/gui/gui.h
index 29dcdef2..e5f5149a 100644
--- a/src/gui/gui.h
+++ b/src/gui/gui.h
@@ -22,14 +22,17 @@
#ifndef GUI_H
#define GUI_H
+#include "eventlistener.h"
#include "guichanfwd.h"
#include <guichan/gui.hpp>
+#include <SDL.h>
+
+#include <vector>
+
class TextInput;
class Graphics;
-class GuiConfigListener;
-class ImageSet;
class SDLInput;
/**
@@ -65,7 +68,7 @@ enum class Cursor {
*
* \ingroup GUI
*/
-class Gui : public gcn::Gui
+class Gui : public gcn::Gui, public EventListener
{
public:
Gui(Graphics *screen);
@@ -78,11 +81,7 @@ class Gui : public gcn::Gui
*/
void logic() override;
- /**
- * Draws the whole Gui by calling draw functions down in the
- * Gui hierarchy. It also draws the mouse pointer.
- */
- void draw() override;
+ void event(Event::Channel channel, const Event &event) override;
/**
* Called when the application window has been resized.
@@ -115,21 +114,25 @@ class Gui : public gcn::Gui
/**
* Sets which cursor should be used.
*/
- void setCursorType(Cursor index)
- { mCursorType = index; }
+ void setCursorType(Cursor cursor);
protected:
void handleMouseMoved(const gcn::MouseInput &mouseInput) override;
void handleTextInput(const TextInput &textInput);
private:
- GuiConfigListener *mConfigListener;
+ void updateCursor();
+
+ void loadCustomCursors();
+ void loadSystemCursors();
+
gcn::Font *mGuiFont; /**< The global GUI font */
gcn::Font *mInfoParticleFont; /**< Font for Info Particles*/
bool mCustomCursor = false; /**< Show custom cursor */
- ImageSet *mMouseCursors = nullptr; /**< Mouse cursor images */
- float mMouseCursorAlpha = 1.0f;
- int mMouseInactivityTimer = 0;
+ float mCustomCursorScale = 1.0f;
+ std::vector<SDL_Cursor *> mSystemMouseCursors;
+ std::vector<SDL_Cursor *> mCustomMouseCursors;
+ int mLastMouseActivityTime = 0;
Cursor mCursorType = Cursor::POINTER;
};
diff --git a/src/resources/resourcemanager.cpp b/src/resources/resourcemanager.cpp
index e2979f06..f43aea41 100644
--- a/src/resources/resourcemanager.cpp
+++ b/src/resources/resourcemanager.cpp
@@ -230,6 +230,11 @@ std::string ResourceManager::getPath(const std::string &file)
return path;
}
+SDL_RWops *ResourceManager::open(const std::string &path)
+{
+ return PHYSFSRWOPS_openRead(path.c_str());
+}
+
Resource *ResourceManager::get(const std::string &idPath,
const std::function<Resource *()> &generator)
{
@@ -265,10 +270,10 @@ Resource *ResourceManager::get(const std::string &idPath,
return resource;
}
-Resource *ResourceManager::load(const std::string &path, loader fun)
+Resource *ResourceManager::get(const std::string &path, loader fun)
{
return get(path, [&] () -> Resource * {
- if (SDL_RWops *rw = PHYSFSRWOPS_openRead(path.c_str()))
+ if (SDL_RWops *rw = open(path))
return fun(rw);
return nullptr;
});
@@ -276,12 +281,12 @@ Resource *ResourceManager::load(const std::string &path, loader fun)
Music *ResourceManager::getMusic(const std::string &idPath)
{
- return static_cast<Music*>(load(idPath, Music::load));
+ return static_cast<Music*>(get(idPath, Music::load));
}
SoundEffect *ResourceManager::getSoundEffect(const std::string &idPath)
{
- return static_cast<SoundEffect*>(load(idPath, SoundEffect::load));
+ return static_cast<SoundEffect*>(get(idPath, SoundEffect::load));
}
Image *ResourceManager::getImage(const std::string &idPath)
@@ -295,7 +300,7 @@ Image *ResourceManager::getImage(const std::string &idPath)
d = std::make_unique<Dye>(path.substr(p + 1));
path = path.substr(0, p);
}
- SDL_RWops *rw = PHYSFSRWOPS_openRead(path.c_str());
+ SDL_RWops *rw = open(path);
if (!rw)
return nullptr;
diff --git a/src/resources/resourcemanager.h b/src/resources/resourcemanager.h
index 7a92818f..6694321c 100644
--- a/src/resources/resourcemanager.h
+++ b/src/resources/resourcemanager.h
@@ -105,6 +105,16 @@ class ResourceManager
std::string getPath(const std::string &file);
/**
+ * Opens a file for reading. The caller is responsible for closing the
+ * file.
+ *
+ * @param path The file name.
+ * @return A valid SDL_RWops pointer or <code>NULL</code> if the file
+ * could not be opened.
+ */
+ SDL_RWops *open(const std::string &path);
+
+ /**
* Creates a resource and adds it to the resource map.
*
* @param idPath The resource identifier path.
@@ -124,18 +134,7 @@ class ResourceManager
* @return A valid resource or <code>NULL</code> if the resource could
* not be loaded.
*/
- Resource *load(const std::string &path, loader fun);
-
- /**
- * Copies a file from one place to another (useful for extracting
- * raw files from a zip archive, for example)
- *
- * @param src Source file name
- * @param dst Destination file name
- * @return true on success, false on failure. An error message should be
- * in the log file.
- */
- bool copyFile(const std::string &src, const std::string &dst);
+ Resource *get(const std::string &path, loader fun);
/**
* Convenience wrapper around ResourceManager::get for loading
@@ -183,6 +182,17 @@ class ResourceManager
bool inflate = true);
/**
+ * Copies a file from one place to another (useful for extracting
+ * raw files from a zip archive, for example)
+ *
+ * @param src Source file name
+ * @param dst Destination file name
+ * @return true on success, false on failure. An error message should be
+ * in the log file.
+ */
+ bool copyFile(const std::string &src, const std::string &dst);
+
+ /**
* Retrieves the contents of a text file.
*/
std::vector<std::string> loadTextFile(const std::string &fileName);
diff --git a/src/resources/theme.cpp b/src/resources/theme.cpp
index 1db92feb..67cd6650 100644
--- a/src/resources/theme.cpp
+++ b/src/resources/theme.cpp
@@ -49,9 +49,7 @@ static void initDefaultThemePath()
ResourceManager *resman = ResourceManager::getInstance();
defaultThemePath = branding.getStringValue("guiThemePath");
- if (!defaultThemePath.empty() && resman->isDirectory(defaultThemePath))
- return;
- else
+ if (defaultThemePath.empty() || !resman->isDirectory(defaultThemePath))
defaultThemePath = "graphics/gui/";
}