Remake cursors, closes #219 and #237

This commit is contained in:
Eduardo Bart 2013-01-25 11:17:51 -02:00
parent 0a91fff82a
commit 3a47c4f2e1
23 changed files with 217 additions and 112 deletions

13
data/cursors/cursors.otml Normal file
View File

@ -0,0 +1,13 @@
Cursors
target:
image: targetcursor
hot-spot: 9 9
horizontal:
image: horizontalcursor
hot-spot: 9 4
vertical:
image: verticalcursor
hot-spot: 4 9
text:
image: textcursor
hot-spot: 4 9

View File

Before

Width:  |  Height:  |  Size: 230 B

After

Width:  |  Height:  |  Size: 230 B

View File

Before

Width:  |  Height:  |  Size: 266 B

After

Width:  |  Height:  |  Size: 266 B

View File

Before

Width:  |  Height:  |  Size: 198 B

After

Width:  |  Height:  |  Size: 198 B

View File

Before

Width:  |  Height:  |  Size: 238 B

After

Width:  |  Height:  |  Size: 238 B

View File

@ -19,6 +19,8 @@ function init()
g_particles.importParticle('/particles/' .. particle)
end
end
g_mouse.loadCursors('/cursors/cursors')
end
function terminate()

View File

@ -27,10 +27,10 @@ function UIResizeBorder:onHoverChange(hovered)
if hovered then
if g_mouse.isCursorChanged() or g_mouse.isPressed() then return end
if self:getWidth() > self:getHeight() then
g_mouse.setVerticalCursor()
g_mouse.setCursor('vertical')
self.vertical = true
else
g_mouse.setHorizontalCursor()
g_mouse.setCursor('horizontal')
self.vertical = false
end
self.hovering = true

View File

@ -14,10 +14,10 @@ function UISplitter:onHoverChange(hovered)
if hovered and (self:canUpdateMargin(margin + 1) ~= margin or self:canUpdateMargin(margin - 1) ~= margin) then
if g_mouse.isCursorChanged() or g_mouse.isPressed() then return end
if self:getWidth() > self:getHeight() then
g_mouse.setVerticalCursor()
g_mouse.setCursor('vertical')
self.vertical = true
else
g_mouse.setHorizontalCursor()
g_mouse.setCursor('horizontal')
self.vertical = false
end
self.hovering = true

View File

@ -235,7 +235,7 @@ function startChooseItem()
connect(mouseGrabberWidget, { onMouseRelease = onChooseItemMouseRelease })
mouseGrabberWidget:grabMouse()
g_mouse.setTargetCursor()
g_mouse.setCursor('target-cursor')
hide()
end

View File

@ -331,14 +331,14 @@ function startUseWith(thing)
selectedType = 'use'
selectedThing = thing
mouseGrabberWidget:grabMouse()
g_mouse.setTargetCursor()
g_mouse.setCursor('target')
end
function startTradeWith(thing)
selectedType = 'trade'
selectedThing = thing
mouseGrabberWidget:grabMouse()
g_mouse.setTargetCursor()
g_mouse.setCursor('target')
end
function createThingMenu(menuPosition, lookThing, useThing, creatureThing)

View File

@ -16,7 +16,8 @@ function UIGameMap:onDragEnter(mousePos)
if not thing then return false end
self.currentDragThing = thing
g_mouse.setTargetCursor()
g_mouse.setCursor('target')
self.allowNextRelease = false
return true
end

View File

@ -6,7 +6,7 @@ function UIItem:onDragEnter(mousePos)
self:setBorderWidth(1)
self.currentDragThing = item
g_mouse.setTargetCursor()
g_mouse.setCursor('target')
return true
end

View File

@ -33,6 +33,7 @@
#ifdef FW_SOUND
#include <framework/sound/soundmanager.h>
#include <framework/input/mouse.h>
#endif
GraphicalApplication g_app;
@ -48,6 +49,8 @@ void GraphicalApplication::init(std::vector<std::string>& args)
g_window.setOnInputEvent(std::bind(&GraphicalApplication::inputEvent, this, std::placeholders::_1));
g_window.setOnClose(std::bind(&GraphicalApplication::close, this));
g_mouse.init();
// initialize ui
g_ui.init();
@ -87,6 +90,8 @@ void GraphicalApplication::terminate()
g_sounds.terminate();
#endif
g_mouse.terminate();
// terminate graphics
m_foreground = nullptr;
g_graphics.terminate();

View File

@ -23,46 +23,82 @@
#include "mouse.h"
#include <framework/ui/uiwidget.h>
#include <framework/platform/platformwindow.h>
#include <framework/core/resourcemanager.h>
Mouse g_mouse;
void Mouse::setTargetCursor()
void Mouse::init()
{
//TODO: configure this in lua
g_window.setMouseCursor("/images/cursors/targetcursor", Point(9, 9));
m_cursorChanged = true;
}
void Mouse::setHorizontalCursor()
void Mouse::terminate()
{
g_window.setMouseCursor("/images/cursors/horizontal", Point(9, 4));
m_cursorChanged = true;
m_cursors.clear();
}
void Mouse::setVerticalCursor()
void Mouse::loadCursors(std::string filename)
{
g_window.setMouseCursor("/images/cursors/vertical", Point(4, 9));
m_cursorChanged = true;
filename = g_resources.guessFileType(filename, "otml");
try {
OTMLDocumentPtr doc = OTMLDocument::parse(filename);
OTMLNodePtr cursorsNode = doc->at("Cursors");
for(const OTMLNodePtr& cursorNode : cursorsNode->children())
addCursor(cursorNode->tag(),
stdext::resolve_path(cursorNode->valueAt("image"), cursorNode->source()),
cursorNode->valueAt<Point>("hot-spot"));
} catch(stdext::exception& e) {
g_logger.error(stdext::format("unable to load cursors file: %s", e.what()));
}
}
void Mouse::setTextCursor()
void Mouse::addCursor(const std::string& name, const std::string& file, const Point& hotSpot)
{
g_window.setMouseCursor("/images/cursors/text", Point(4, 9));
m_cursorChanged = true;
int cursorId = g_window.loadMouseCursor(file, hotSpot);
if(cursorId >= 0) {
m_cursors[name] = cursorId;
} else
g_logger.error(stdext::format("unable to load cursor %s", name));
}
bool Mouse::setCursor(const std::string& name)
{
auto it = m_cursors.find(name);
if(it == m_cursors.end())
return false;
int cursorId = it->second;
g_window.setMouseCursor(cursorId);
m_cursorStack.push_back(cursorId);
return true;
}
void Mouse::restoreCursor()
{
g_window.restoreMouseCursor();
m_cursorChanged = false;
if(m_cursorStack.size() == 0)
return;
m_cursorStack.pop_back();
if(m_cursorStack.size() > 0)
g_window.setMouseCursor(m_cursorStack.back());
else
g_window.restoreMouseCursor();
}
bool Mouse::isCursorChanged()
{
return m_cursorChanged;
return m_cursorStack.size() > 0;
}
bool Mouse::isPressed(Fw::MouseButton mouseButton)
{
return g_window.isMouseButtonPressed(mouseButton);
}
void Mouse::checkStackSize()
{
if(m_cursorStack.size() > 5) {
g_logger.error("mouse cursor stack is too long");
m_cursorStack.resize(5);
}
}

View File

@ -25,16 +25,21 @@
class Mouse
{
public:
void setTargetCursor();
void setHorizontalCursor();
void setVerticalCursor();
void setTextCursor();
void init();
void terminate();
void loadCursors(std::string filename);
void addCursor(const std::string& name, const std::string& file, const Point& hotSpot);
bool setCursor(const std::string& name);
void restoreCursor();
bool isCursorChanged();
bool isPressed(Fw::MouseButton mouseButton);
private:
bool m_cursorChanged;
void checkStackSize();
std::map<std::string, int> m_cursors;
std::vector<int> m_cursorStack;
};
extern Mouse g_mouse;

View File

@ -270,10 +270,9 @@ void Application::registerLuaFunctions()
// Input
g_lua.registerSingletonClass("g_mouse");
g_lua.bindSingletonFunction("g_mouse", "setTargetCursor", &Mouse::setTargetCursor, &g_mouse);
g_lua.bindSingletonFunction("g_mouse", "setHorizontalCursor", &Mouse::setHorizontalCursor, &g_mouse);
g_lua.bindSingletonFunction("g_mouse", "setVerticalCursor", &Mouse::setVerticalCursor, &g_mouse);
g_lua.bindSingletonFunction("g_mouse", "setTextCursor", &Mouse::setTextCursor, &g_mouse);
g_lua.bindSingletonFunction("g_mouse", "loadCursors", &Mouse::loadCursors, &g_mouse);
g_lua.bindSingletonFunction("g_mouse", "addCursor", &Mouse::addCursor, &g_mouse);
g_lua.bindSingletonFunction("g_mouse", "setCursor", &Mouse::setCursor, &g_mouse);
g_lua.bindSingletonFunction("g_mouse", "restoreCursor", &Mouse::restoreCursor, &g_mouse);
g_lua.bindSingletonFunction("g_mouse", "isCursorChanged", &Mouse::isCursorChanged, &g_mouse);
g_lua.bindSingletonFunction("g_mouse", "isPressed", &Mouse::isPressed, &g_mouse);

View File

@ -32,9 +32,32 @@ X11Window window;
#endif
#include <framework/core/clock.h>
#include <framework/graphics/image.h>
PlatformWindow& g_window = window;
int PlatformWindow::loadMouseCursor(const std::string& file, const Point& hotSpot)
{
ImagePtr image = Image::load(file);
if(!image) {
g_logger.traceError(stdext::format("unable to load cursor image file %s", file));
return -1;
}
if(image->getBpp() != 4) {
g_logger.error("the cursor image must have 4 channels");
return -1;
}
if(image->getWidth() != 32 || image->getHeight() != 32) {
g_logger.error("the cursor image must have 32x32 dimension");
return -1;
}
return internalLoadMouseCursor(image, hotSpot);
}
void PlatformWindow::updateUnmaximizedCoords()
{
if(!isMaximized() && !isFullscreen()) {

View File

@ -26,6 +26,7 @@
#include <framework/global.h>
#include <framework/core/inputevent.h>
#include <framework/core/timer.h>
#include <framework/graphics/declarations.h>
//@bindsingleton g_window
class PlatformWindow
@ -48,12 +49,14 @@ public:
virtual void maximize() = 0;
virtual void poll() = 0;
virtual void swapBuffers() = 0;
virtual void restoreMouseCursor() = 0;
virtual void showMouse() = 0;
virtual void hideMouse() = 0;
virtual void displayFatalError(const std::string& message) { }
virtual void setMouseCursor(const std::string& file, const Point& hotSpot) = 0;
int loadMouseCursor(const std::string& file, const Point& hotSpot);
virtual void setMouseCursor(int cursorId) = 0;
virtual void restoreMouseCursor() = 0;
virtual void setTitle(const std::string& title) = 0;
virtual void setMinimumSize(const Size& minimumSize) = 0;
virtual void setFullscreen(bool fullscreen) = 0;
@ -92,6 +95,8 @@ public:
void setOnInputEvent(const OnInputEventCallback& onInputEvent) { m_onInputEvent = onInputEvent; }
protected:
virtual int internalLoadMouseCursor(const ImagePtr& image, const Point& hotSpot) = 0;
void updateUnmaximizedCoords();
void processKeyDown(Fw::Key keyCode);

View File

@ -211,6 +211,16 @@ void WIN32Window::init()
void WIN32Window::terminate()
{
SetCursor(NULL);
if(m_defaultCursor) {
DestroyCursor(m_defaultCursor);
m_defaultCursor = NULL;
}
for(HCURSOR& cursor : m_cursors)
DestroyCursor(cursor);
m_cursors.clear();
internalDestroyGLContext();
if(m_deviceContext) {
@ -219,11 +229,6 @@ void WIN32Window::terminate()
m_deviceContext = NULL;
}
if(m_cursor) {
DestroyCursor(m_cursor);
m_cursor = NULL;
}
if(m_window) {
if(!DestroyWindow(m_window))
g_logger.error("ERROR: Destroy window failed.");
@ -744,16 +749,6 @@ void WIN32Window::swapBuffers()
#endif
}
void WIN32Window::restoreMouseCursor()
{
if(m_cursor) {
DestroyCursor(m_cursor);
m_cursor = NULL;
SetCursor(m_defaultCursor);
ShowCursor(true);
}
}
void WIN32Window::showMouse()
{
ShowCursor(true);
@ -769,28 +764,8 @@ void WIN32Window::displayFatalError(const std::string& message)
MessageBoxW(m_window, stdext::latin1_to_utf16(message).c_str(), L"FATAL ERROR", MB_OK | MB_ICONERROR);
}
void WIN32Window::setMouseCursor(const std::string& file, const Point& hotSpot)
int WIN32Window::internalLoadMouseCursor(const ImagePtr& image, const Point& hotSpot)
{
ImagePtr image = Image::load(file);
if(!image) {
g_logger.traceError(stdext::format("unable to load cursor image file %s", file));
return;
}
if(image->getBpp() != 4) {
g_logger.error("the cursor image must have 4 channels");
return;
}
if(image->getWidth() != 32 || image->getHeight() != 32) {
g_logger.error("the cursor image must have 32x32 dimension");
return;
}
if(m_cursor != NULL)
DestroyCursor(m_cursor);
int width = image->getWidth();
int height = image->getHeight();
int numbits = width * height;
@ -808,8 +783,28 @@ void WIN32Window::setMouseCursor(const std::string& file, const Point& hotSpot)
} // otherwise 0xff000000 => black
}
m_cursor = CreateCursor(m_instance, hotSpot.x, hotSpot.y, width, height, &andMask[0], &xorMask[0]);
HCURSOR cursor = CreateCursor(m_instance, hotSpot.x, hotSpot.y, width, height, &andMask[0], &xorMask[0]);
m_cursors.push_back(cursor);
return m_cursors.size()-1;
}
void WIN32Window::setMouseCursor(int cursorId)
{
if(cursorId >= (int)m_cursors.size() || cursorId < 0)
return;
m_cursor = m_cursors[cursorId];
SetCursor(m_cursor);
ShowCursor(true);
}
void WIN32Window::restoreMouseCursor()
{
if(m_cursor) {
m_cursor = NULL;
SetCursor(m_defaultCursor);
ShowCursor(true);
}
}
void WIN32Window::setTitle(const std::string& title)

View File

@ -61,12 +61,13 @@ public:
void maximize();
void poll();
void swapBuffers();
void restoreMouseCursor();
void showMouse();
void hideMouse();
void displayFatalError(const std::string& message);
void setMouseCursor(const std::string& file, const Point& hotSpot);
void setMouseCursor(int cursorId);
void restoreMouseCursor();
void setTitle(const std::string& title);
void setMinimumSize(const Size& minimumSize);
void setFullscreen(bool fullscreen);
@ -78,11 +79,15 @@ public:
std::string getClipboardText();
std::string getPlatformType();
protected:
int internalLoadMouseCursor(const ImagePtr& image, const Point& hotSpot);
private:
Rect getClientRect();
Rect getWindowRect();
Rect adjustWindowRect(const Rect& rect);
std::vector<HCURSOR> m_cursors;
HWND m_window;
HINSTANCE m_instance;
HDC m_deviceContext;

View File

@ -37,6 +37,7 @@ X11Window::X11Window()
m_rootWindow = 0;
m_colormap = 0;
m_cursor = 0;
m_hiddenCursor = 0;
m_xim = 0;
m_xic = 0;
m_screen = 0;
@ -218,6 +219,20 @@ void X11Window::init()
void X11Window::terminate()
{
if(m_cursor != None) {
XUndefineCursor(m_display, m_window);
m_cursor = None;
}
if(m_hiddenCursor) {
XFreeCursor(m_display, m_hiddenCursor);
m_hiddenCursor = 0;
}
for(Cursor cursor : m_cursors)
XFreeCursor(m_display, cursor);
m_cursors.clear();
if(m_window) {
XDestroyWindow(m_display, m_window);
m_window = 0;
@ -842,47 +857,40 @@ void X11Window::hideMouse()
if(m_cursor != None)
restoreMouseCursor();
char bm[] = { 0, 0, 0, 0, 0, 0, 0, 0 };
Pixmap pix = XCreateBitmapFromData(m_display, m_window, bm, 8, 8);
XColor black;
memset(&black, 0, sizeof(black));
black.flags = DoRed | DoGreen | DoBlue;
m_cursor = XCreatePixmapCursor(m_display, pix, pix, &black, &black, 0, 0);
XFreePixmap(m_display, pix);
if(m_hiddenCursor == None) {
char bm[] = { 0, 0, 0, 0, 0, 0, 0, 0 };
Pixmap pix = XCreateBitmapFromData(m_display, m_window, bm, 8, 8);
XColor black;
memset(&black, 0, sizeof(black));
black.flags = DoRed | DoGreen | DoBlue;
m_hiddenCursor = XCreatePixmapCursor(m_display, pix, pix, &black, &black, 0, 0);
XFreePixmap(m_display, pix);
}
m_cursor = m_hiddenCursor;
XDefineCursor(m_display, m_window, m_cursor);
}
void X11Window::setMouseCursor(int cursorId)
{
if(cursorId >= (int)m_cursors.size() || cursorId < 0)
return;
if(m_cursor != None)
restoreMouseCursor();
m_cursor = m_cursors[cursorId];
XDefineCursor(m_display, m_window, m_cursor);
}
void X11Window::restoreMouseCursor()
{
XUndefineCursor(m_display, m_window);
if(m_cursor != None) {
XFreeCursor(m_display, m_cursor);
m_cursor = None;
}
m_cursor = None;
}
void X11Window::setMouseCursor(const std::string& file, const Point& hotSpot)
int X11Window::internalLoadMouseCursor(const ImagePtr& image, const Point& hotSpot)
{
ImagePtr image = Image::load(file);
if(!image) {
g_logger.traceError(stdext::format("unable to load image file %s", file));
return;
}
if(image->getBpp() != 4) {
g_logger.error("the cursor image must have 4 channels");
return;
}
if(image->getWidth() != 32 || image->getHeight() != 32) {
g_logger.error("the cursor image must have 32x32 dimension");
return;
}
if(m_cursor != None)
restoreMouseCursor();
int width = image->getWidth();
int height = image->getHeight();
int numbits = width * height;
@ -911,10 +919,12 @@ void X11Window::setMouseCursor(const std::string& file, const Point& hotSpot)
Pixmap cp = XCreateBitmapFromData(m_display, m_window, (char*)&mapBits[0], width, height);
Pixmap mp = XCreateBitmapFromData(m_display, m_window, (char*)&maskBits[0], width, height);
m_cursor = XCreatePixmapCursor(m_display, cp, mp, &fg, &bg, hotSpot.x, hotSpot.y);
XDefineCursor(m_display, m_window, m_cursor);
Cursor cursor = XCreatePixmapCursor(m_display, cp, mp, &fg, &bg, hotSpot.x, hotSpot.y);
XFreePixmap(m_display, cp);
XFreePixmap(m_display, mp);
m_cursors.push_back(cursor);
return m_cursors.size()-1;
}
void X11Window::setTitle(const std::string& title)

View File

@ -63,11 +63,12 @@ public:
void maximize();
void poll();
void swapBuffers();
void restoreMouseCursor();
void showMouse();
void hideMouse();
void setMouseCursor(const std::string& file, const Point& hotSpot);
void setMouseCursor(int cursorId);
void restoreMouseCursor();
void setTitle(const std::string& title);
void setMinimumSize(const Size& minimumSize);
void setFullscreen(bool fullscreen);
@ -79,13 +80,18 @@ public:
std::string getClipboardText();
std::string getPlatformType();
protected:
int internalLoadMouseCursor(const ImagePtr& image, const Point& hotSpot);
private:
Display *m_display;
XVisualInfo *m_visual;
Window m_window;
Window m_rootWindow;
Colormap m_colormap;
std::vector<Cursor> m_cursors;
Cursor m_cursor;
Cursor m_hiddenCursor;
XIM m_xim;
XIC m_xic;
int m_screen;

View File

@ -590,7 +590,7 @@ void UITextEdit::onHoverChange(bool hovered)
{
if(m_changeCursorImage) {
if(hovered)
g_mouse.setTextCursor();
g_mouse.setCursor("text");
else
g_mouse.restoreCursor();
}