Nice! ;)
However, you should use another namespace than sf for StandardCursor. Just to differentiate what is from SFML and what comes from addons. Also there are a few indentation issues : mixing tabs and spaces is usually no good.
Now the interesting comment begins :
Apple's cursor API is quite a mess. I did success to make it work but there is one big constraint (I really don't like it) ! You have to wait some amount of time (100 ms should be enough) before setting the cursor in the application otherwise it won't work.
Here is a sample code :
#include <SFML/Graphics.hpp>
#include "ResourcePath.hpp"
#include "ChangeCursor.h"
int main (int argc, const char * argv[])
{
// Create the main window
sf::RenderWindow window(sf::VideoMode(800, 600), "SFML window");
// Load a sprite to display
sf::Texture texture;
if (!texture.loadFromFile(resourcePath() + "cute_image.jpg"))
return EXIT_FAILURE;
sf::Sprite sprite(texture);
// Create a graphical text to display
sf::Font font;
if (!font.loadFromFile(resourcePath() + "sansation.ttf"))
return EXIT_FAILURE;
sf::Text text("Hello SFML", font, 50);
text.setColor(sf::Color::Black);
sf::Clock cursorClock;
bool cursorSet = false;
// Start the game loop
while (window.isOpen())
{
if (!cursorSet and cursorClock.getElapsedTime() > sf::microseconds(100)) {
ChangeCursor(window);
cursorSet = true;
}
// Process events
sf::Event event;
while (window.pollEvent(event))
{
// Close window : exit
if (event.type == sf::Event::Closed)
window.close();
// Escape pressed : exit
if (event.type == sf::Event::KeyPressed && event.key.code == sf::Keyboard::Escape)
window.close();
}
// Clear screen
window.clear();
// Draw the sprite
window.draw(sprite);
// Draw the string
window.draw(text);
// Update the window
window.display();
}
return EXIT_SUCCESS;
}
Note that if you don't use the cursorClock then it won't work and if you remove also boolean cursorSet and call each time ChangeCursor the application will be less responsive when you switch from one application to another and come back.
Here is my implementation :
#import "ChangeCursor.h"
#import <SFML/Window.hpp>
#import <Cocoa/Cocoa.h>
void ChangeCursor(sf::Window& window)
{
id handle = (id)window.getSystemHandle();
// Get the content view of the handle
NSView* view = nil;
if ([handle isKindOfClass:[NSView class]]) {
view = handle;
} else {
NSWindow* nswindow = handle;
view = nswindow.contentView;
}
NSCursor* defaultCursor = [NSCursor currentCursor];
NSCursor* cursor = [NSCursor pointingHandCursor];
NSRect rect = view.frame;
[view addCursorRect:rect cursor:cursor];
[cursor setOnMouseEntered:YES];
[view addCursorRect:rect cursor:defaultCursor];
[defaultCursor setOnMouseExited:YES];
NSPoint mousePositionInWindow = [[view window] mouseLocationOutsideOfEventStream];
NSPoint mousePositionInView = [view convertPoint:mousePositionInWindow
fromView:nil]; // i.e. from the window.
if ([view mouse:mousePositionInView inRect:view.frame]) {
[cursor set];
}
}
It's Objective-C++ so it must be inside a .mm file.
There is one known bug : when switching back to your application the cursor is not set back unless you put the cursor outside the window; then if you put the mouse in the window the cursor will be set as expected.
Is it even possible to change it to a user-supplied sprite? Just curious
Yes, that's what I intend to do in the implementation later next month.
I beg to differ. At least with tabs, you can set the indentation width to your own liking, regardless of what other developers used. With spaces, you're forcing people that browse your code to use your specific indentation preference.
In a perfect world I would totally agree with you.
BUT : if you write something on two lines and need some specific alignment then you can't use tabs. It just won't work nicely if someone has tab=8spaces if you have tab=4spaces.
NSPoint mousePositionInView = [view convertPoint:mousePositionInWindow
fromView:nil]; // i.e. from the window.
Ok, here is the implementation : https://gist.github.com/3076898
What I did was :
- use .mm implementation file in order to let the compile know that the code is written in Objective-C++; I can't do the same as you did for Linux and Windows (i.e. use one file for both and play with macro directives).
- In the header I changed some #if defined to make it work on Mac OS X and the previously supported OSes.
- In order to use TYPE as a field of the class I switched private & public in class declaration.
- I substituted sf with sfp in order to make it clear that this code is an add-on and not part of SFML itself (you can of couse change sfp with whatever you want).
I let you update the wiki page.
I also have two suggestion for you :
First, instead of a class why not using a simple free function ? e.g. void sfp::ChangeCursor(Type type, sf::Window const& window) You could use a singleton object for implementation like this :
namespace /* anonymous */
{
struct {
#ifdef SFML_SYSTEM_WINDOWS
// blabla
:
:
} impl;
}
Secondly, you should probably add some license to your source file like we do with SFML.