New Mouse Icons for Mac!

Co-Authored-By: Mihai Alexandru <77043862+MAJigsaw77@users.noreply.github.com>
This commit is contained in:
NeeEoo
2024-04-15 14:01:04 +02:00
co-authored by Mihai Alexandru
parent 4285307d70
commit a8997daecb
25 changed files with 387 additions and 30 deletions
@@ -0,0 +1,40 @@
package funkin.backend.system.macros;
import haxe.io.Path;
import haxe.macro.Expr;
import haxe.macro.Context;
import haxe.xml.Printer;
import sys.FileSystem;
class LinkerMacro
{
public static macro function xml(filename:String = 'Build.xml'):Array<Field>
{
var pos:Position = Context.currentPos();
var sourcePath:String = Path.directory(Context.getPosInfos(pos).file);
if (!Path.isAbsolute(sourcePath))
sourcePath = FileSystem.absolutePath(sourcePath);
sourcePath = Path.removeTrailingSlashes(Path.normalize(sourcePath));
var includeElement:Xml = Xml.createElement('include');
includeElement.set('name', Path.join([sourcePath, filename]));
@:privateAccess
{
var printer:Printer = new Printer(true);
printer.writeNode(includeElement, '\n');
Context.getLocalClass().get().meta.add(':buildXml', [{
expr: EConst(CString(printer.output.toString())),
pos: pos
}], pos);
}
return Context.getBuildFields();
}
}
+105
View File
@@ -1,5 +1,8 @@
package funkin.backend.utils;
import haxe.macro.Expr.Case;
import openfl.ui.Mouse;
import openfl.ui.MouseCursor;
import funkin.backend.utils.native.*;
/**
@@ -72,6 +75,17 @@ class NativeAPI {
#end
}
/**
* Set cursor icon.
**/
public static function setCursorIcon(icon:CodeCursor) {
#if mac
Mac.setMouseCursorIcon(cast icon);
#else
Mouse.cursor = icon.toOpenFL();
#end
}
public static function consoleColorToANSI(color:ConsoleColor) {
return switch(color) {
case BLACK: 30;
@@ -141,4 +155,95 @@ enum abstract MessageBoxIcon(Int) {
var MSG_QUESTION = 0x00000020;
var MSG_WARNING = 0x00000030;
var MSG_INFORMATION = 0x00000040;
}
enum abstract CodeCursor(String) {
var CUSTOM;// = "arrow";
var ARROW;// = "arrow";
var CLICK;// = "click";
var CROSSHAIR;// = "crosshair";
var HAND;// = "hand";
var IBEAM;// = "ibeam";
var MOVE;// = "move";
var RESIZE_H;// = "resize_we";
var RESIZE_V;// = "resize_ns";
var RESIZE_TL;// = "resize_nw";
var RESIZE_TR;// = "resize_ne";
var RESIZE_BL;// = "resize_sw";
var RESIZE_BR;// = "resize_se";
var RESIZE_T;// = "resize_n";
var RESIZE_B;// = "resize_b";
var RESIZE_L;// = "resize_w";
var RESIZE_R;// = "resize_e";
var WAIT;// = "wait";
var WAIT_ARROW;// = "waitarrow";
var DISABLED;// = "disabled";
var DRAG;// = "drag";
var DRAG_OPEN;// = "dragopen";
@:to public function toOpenFL():MouseCursor {
return @:privateAccess switch(cast this) {
case ARROW: MouseCursor.ARROW;
case CROSSHAIR: MouseCursor.__CROSSHAIR;
case CLICK: MouseCursor.BUTTON;
case IBEAM: MouseCursor.IBEAM;
case MOVE: MouseCursor.__MOVE;
case HAND: MouseCursor.HAND;
case DRAG: MouseCursor.HAND;
case DRAG_OPEN: MouseCursor.HAND;
case WAIT: MouseCursor.__WAIT;
case WAIT_ARROW: MouseCursor.__WAIT_ARROW;
case DISABLED: MouseCursor.ARROW;
case RESIZE_TR: MouseCursor.__RESIZE_NESW;
case RESIZE_BL: MouseCursor.__RESIZE_NESW;
case RESIZE_TL: MouseCursor.__RESIZE_NWSE;
case RESIZE_BR: MouseCursor.__RESIZE_NWSE;
case RESIZE_H: MouseCursor.__RESIZE_WE;
case RESIZE_V: MouseCursor.__RESIZE_NS;
case RESIZE_T: MouseCursor.__RESIZE_NS;
case RESIZE_B: MouseCursor.__RESIZE_NS;
case RESIZE_L: MouseCursor.__RESIZE_WE;
case RESIZE_R: MouseCursor.__RESIZE_WE;
case CUSTOM: MouseCursor.__CUSTOM;
//default: ARROW;
}
}
@:to public function toInt():Int {
return switch(cast this) {
case ARROW: 0;
case CROSSHAIR: 1;
case CLICK: 2;
case IBEAM: 3;
case MOVE: 4;
case HAND: 5;
case DRAG: 6;
case DRAG_OPEN: 7;
case WAIT: 8;
case WAIT_ARROW: 9;
case DISABLED: 10;
case RESIZE_TR: 11;
case RESIZE_BL: 12;
case RESIZE_TL: 13;
case RESIZE_BR: 14;
case RESIZE_H: 15;
case RESIZE_V: 16;
case RESIZE_T: 17;
case RESIZE_B: 18;
case RESIZE_L: 19;
case RESIZE_R: 20;
case CUSTOM: -1;
}
}
}
+48 -2
View File
@@ -1,7 +1,11 @@
package funkin.backend.utils.native;
#if mac
@:cppFileCode("#include <sys/sysctl.h>")
import funkin.backend.utils.NativeAPI.CodeCursor;
import openfl.ui.Mouse;
@:build(funkin.backend.system.macros.LinkerMacro.xml('external/external_code.xml'))
@:headerInclude('sys/sysctl.h')
class Mac {
@:functionCode('
int mib [] = { CTL_HW, HW_MEMSIZE };
@@ -17,5 +21,47 @@ class Mac {
{
return 0;
}
public static function setMouseCursorIcon(icon:CodeCursor):Void
{
final valid:Bool = ExternalMac.setCursorIcon(icon.toInt());
if(!valid) {
Mouse.cursor = icon.toOpenFL();
}
}
}
#end
@:build(funkin.backend.system.macros.LinkerMacro.xml('external/external_code.xml'))
@:native("ExternalMac")
@:include('Mac.h')
extern class ExternalMac {
@:native("ExternalMac::setCursorIcon")
public static function setCursorIcon(icon:Int):Bool;
}
#end
/*
Cursor
Description
The arrow cursor (arrow)
The I-beam cursor for indicating insertion points (iBeam)
The cross-hair cursor (crosshair)
The closed-hand cursor (closedHand)
The open-hand cursor (openHand)
The pointing-hand cursor (pointingHand)
The resize-left cursor (resizeLeft)
The resize-right cursor (resizeRight)
The resize-left-and-right cursor (resizeLeftRight)
The resize-up cursor (resizeUp)
The resize-down cursor (resizeDown)
The resize-up-and-down cursor (resizeUpDown)
The disappearing item cursor (disappearingItem)
The I-Beam text cursor for vertical layout (iBeamCursorForVerticalLayout).
The not allowed cursor (operationNotAllowed).
The drag link cursor (dragLink).
The drag copy cursor (dragCopy).
The contextual menu cursor (contextualMenu).
*/
@@ -0,0 +1,32 @@
<?xml version="1.0" encoding="UTF-8"?>
<xml>
<pragma once="true" />
<files id="haxe">
<compilerflag value="-I${this_dir}/include/mac" if="macos" />
</files>
<files id="__main__">
<compilerflag value="-I${this_dir}/include/mac" if="macos" />
</files>
<files id="external-code">
<section if="macos">
<compilerflag value="-I${this_dir}/include/mac" />
<file name="${this_dir}/src/mac/CursorHelper.mm" />
<file name="${this_dir}/src/mac/Mac.mm" />
</section>
</files>
<target id="haxe">
<section if="macos">
<vflag name="-framework" value="IOKit" />
<vflag name="-framework" value="AppKit" />
<vflag name="-framework" value="Cocoa" />
<vflag name="-framework" value="Foundation" />
</section>
<files id="external-code" />
</target>
</xml>
@@ -0,0 +1,7 @@
#import <Foundation/Foundation.h>
@interface CursorHelper : NSObject
+ (NSCursor *)getCursorForSelector:(SEL)selector defaultCursor:(NSCursor *)defaultCursor;
@end
@@ -0,0 +1,13 @@
#ifndef MAC_H
#define MAC_H
#if defined(__APPLE__)
namespace ExternalMac
{
bool setCursorIcon(int icon);
}
#endif
#endif
@@ -0,0 +1,21 @@
#import <Cocoa/Cocoa.h>
#import "CursorHelper.h"
@implementation CursorHelper
+ (NSCursor *)getCursorForSelector:(SEL)selector defaultCursor:(NSCursor *)defaultCursor {
NSCursor *cursor = nil;
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wundeclared-selector"
if ([NSCursor respondsToSelector:selector]) {
cursor = [NSCursor performSelector:selector];
} else {
cursor = defaultCursor;
}
#pragma clang diagnostic pop
return cursor;
}
@end
@@ -0,0 +1,80 @@
#import <Cocoa/Cocoa.h>
#import "CursorHelper.h"
#define ARROW 0
#define CROSSHAIR 1
#define CLICK 2
#define IBEAM 3
#define MOVE 4
#define HAND 5
#define DRAG 6
#define DRAG_OPEN 7
#define WAIT 8
#define WAIT_ARROW 9
#define DISABLED 10
#define RESIZE_TR 11
#define RESIZE_BL 12
#define RESIZE_TL 13
#define RESIZE_BR 14
#define RESIZE_H 15
#define RESIZE_V 16
#define RESIZE_T 17
#define RESIZE_B 18
#define RESIZE_L 19
#define RESIZE_R 20
#define CUSTOM -1
namespace ExternalMac {
bool setCursorIcon(int icon/*, const char *customCursor, float customX, float customY*/) {
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wundeclared-selector"
NSCursor *cursor = nil;
switch(icon) {
case ARROW: cursor = [NSCursor arrowCursor]; break;
case CLICK: cursor = [NSCursor pointingHandCursor]; break;
case CROSSHAIR: cursor = [NSCursor crosshairCursor]; break;
case HAND: cursor = [NSCursor closedHandCursor]; break;
case IBEAM: cursor = [NSCursor IBeamCursor]; break;
//case MOVE: cursor = [NSCursor moveCursor]; break;
case RESIZE_H: cursor = [NSCursor resizeLeftRightCursor]; break;
case RESIZE_V: cursor = [NSCursor resizeUpDownCursor]; break;
// TODO: DEFAULTS
case RESIZE_TL: cursor = [CursorHelper getCursorForSelector:@selector(_windowResizeNorthWestCursor) defaultCursor:[NSCursor arrowCursor]]; break;
case RESIZE_TR: cursor = [CursorHelper getCursorForSelector:@selector(_windowResizeNorthEastCursor) defaultCursor:[NSCursor arrowCursor]]; break;
case RESIZE_BL: cursor = [CursorHelper getCursorForSelector:@selector(_windowResizeSouthWestCursor) defaultCursor:[NSCursor arrowCursor]]; break;
case RESIZE_BR: cursor = [CursorHelper getCursorForSelector:@selector(_windowResizeSouthEastCursor) defaultCursor:[NSCursor arrowCursor]]; break;
case RESIZE_T: cursor = [CursorHelper getCursorForSelector:@selector(_windowResizeNorthCursor) defaultCursor:[NSCursor arrowCursor]]; break;
case RESIZE_B: cursor = [CursorHelper getCursorForSelector:@selector(_windowResizeSouthCursor) defaultCursor:[NSCursor arrowCursor]]; break;
case RESIZE_L: cursor = [CursorHelper getCursorForSelector:@selector(_windowResizeWestCursor) defaultCursor:[NSCursor arrowCursor]]; break;
case RESIZE_R: cursor = [CursorHelper getCursorForSelector:@selector(_windowResizeEastCursor) defaultCursor:[NSCursor arrowCursor]]; break;
case WAIT: cursor = [CursorHelper getCursorForSelector:@selector(_waitCursor) defaultCursor:[NSCursor arrowCursor]]; break;
case WAIT_ARROW: cursor = [CursorHelper getCursorForSelector:@selector(_waitCursor) defaultCursor:[NSCursor arrowCursor]]; break;
case DISABLED: cursor = [NSCursor operationNotAllowedCursor]; break;
case DRAG: cursor = [NSCursor closedHandCursor]; break;
case DRAG_OPEN: cursor = [NSCursor openHandCursor]; break;
/*case CUSTOM: {
// TODO: CACHING
NSString *cursorImageName = [NSString stringWithUTF8String:customCursor];
NSImage *tmpImage = [NSImage imageNamed:cursorImageName];
NSCursor *pointer = [[NSCursor alloc] initWithImage:tmpImage hotSpot:NSMakePoint(customX, customY)];
cursor = [NSCursor pointer]
break;
}*/
case CUSTOM: cursor = [NSCursor arrowCursor]; break;
}
#pragma clang diagnostic pop
if(cursor != nil) {
[cursor set];
return true;
}
return false;
}
}
+2 -2
View File
@@ -804,7 +804,7 @@ class Charter extends UIState {
}
if (s is CharterNote) cast(s, CharterNote).snappedToStrumline = true;
if (s is UISprite) cast(s, UISprite).cursor = BUTTON;
if (s is UISprite) cast(s, UISprite).cursor = CLICK;
}
if (!(verticalChange == 0 && horizontalChange == 0)) {
notesGroup.sortNotes(); eventsGroup.sortEvents();
@@ -866,7 +866,7 @@ class Charter extends UIState {
case SUSTAIN_DRAG:
selectionDragging = FlxG.mouse.pressed;
if (selectionDragging) {
currentCursor = BUTTON;
currentCursor = CLICK;
selection.loop(function (n:CharterNote) {
var change:Float = Math.max((mousePos.y-(FlxG.keys.pressed.SHIFT ? dragStartPos.y : quantStep(dragStartPos.y))) / 40, -n.susLength);
n.tempSusLength = change;
@@ -23,7 +23,7 @@ class CharterEvent extends UISliceSprite implements ICharterSelectable {
this.step = step;
this.events = events.getDefault([]);
cursor = BUTTON;
cursor = CLICK;
}
public override function update(elapsed:Float) {
@@ -13,7 +13,7 @@ class CharterEventAdd extends UISliceSprite {
text = new UIText(0, 0, 0, "");
members.push(text);
cursor = BUTTON;
cursor = CLICK;
}
public override function onHovered() {
+1 -1
View File
@@ -44,7 +44,7 @@ class CharterNote extends UISprite implements ICharterSelectable {
typeText = new UIText(x, y, 0, Std.string(type));
cursor = sustainSpr.cursor = BUTTON;
cursor = sustainSpr.cursor = CLICK;
moves = false;
}
@@ -64,7 +64,7 @@ class CharterStrumline extends UISprite {
draggingSprite.alpha = 0.4;
draggingSprite.y = 9;
draggingSprite.antialiasing = true;
draggingSprite.cursor = BUTTON;
draggingSprite.cursor = CLICK;
members.push(draggingSprite);
button = new CharterStrumlineOptions(this);
@@ -24,7 +24,7 @@ class CharterStrumlineButton extends UISprite {
button.scale.set(0.85,0.85);
button.updateHitbox();
button.antialiasing = true;
button.cursor = BUTTON;
button.cursor = CLICK;
members.push(button);
this.text = new UIText(0,0, 160, text);
+15 -6
View File
@@ -749,10 +749,19 @@ class StageEditor extends UIState {
if(checkDot(buttonBoxes[i])) {
currentCursor = switch(edge) {
// RESIZE_NESW; //RESIZE_NS; //RESIZE_NWSE; //RESIZE_WE;
case TOP_LEFT | BOTTOM_RIGHT: MouseCursor.RESIZE_NWSE;
case TOP_MIDDLE | BOTTOM_MIDDLE: MouseCursor.RESIZE_NS;
case TOP_RIGHT | BOTTOM_LEFT: MouseCursor.RESIZE_NESW;
case MIDDLE_LEFT | MIDDLE_RIGHT: MouseCursor.RESIZE_WE;
case TOP_LEFT: RESIZE_TL;
case TOP_MIDDLE: RESIZE_T;
case TOP_RIGHT: RESIZE_TR;
case MIDDLE_LEFT: RESIZE_L;
//case MIDDLE_MIDDLE: RESIZE_H;
case MIDDLE_RIGHT: RESIZE_R;
case BOTTOM_LEFT: RESIZE_BL;
case BOTTOM_MIDDLE: RESIZE_B;
case BOTTOM_RIGHT: RESIZE_BR;
//case TOP_LEFT | BOTTOM_RIGHT: MouseCursor.RESIZE_NWSE;
//case TOP_MIDDLE | BOTTOM_MIDDLE: MouseCursor.RESIZE_NS;
//case TOP_RIGHT | BOTTOM_LEFT: MouseCursor.RESIZE_NESW;
//case MIDDLE_LEFT | MIDDLE_RIGHT: MouseCursor.RESIZE_WE;
default: ARROW;
}
break;
@@ -873,7 +882,7 @@ enum abstract StageEditorEdge(Int) {
var TOP_MIDDLE;
var TOP_RIGHT;
var MIDDLE_LEFT;
var MIDDLE_MIDDLE;
//var MIDDLE_MIDDLE;
var MIDDLE_RIGHT;
var BOTTOM_LEFT;
var BOTTOM_MIDDLE;
@@ -886,7 +895,7 @@ enum abstract StageEditorEdge(Int) {
case TOP_MIDDLE: "TOP_MIDDLE";
case TOP_RIGHT: "TOP_RIGHT";
case MIDDLE_LEFT: "MIDDLE_LEFT";
case MIDDLE_MIDDLE: "MIDDLE_MIDDLE";
//case MIDDLE_MIDDLE: "MIDDLE_MIDDLE";
case MIDDLE_RIGHT: "MIDDLE_RIGHT";
case BOTTOM_LEFT: "BOTTOM_LEFT";
case BOTTOM_MIDDLE: "BOTTOM_MIDDLE";
+2 -2
View File
@@ -57,7 +57,7 @@ class UIAudioPlayer extends UIButton {
members.push(timeBarPlayer);
timeBarSpr = cast new UISprite(timeBar.x, timeBar.y).makeSolid(timeBar.barWidth, timeBar.barHeight, 0x00FFFFFF);
timeBarSpr.cursor = BUTTON;
timeBarSpr.cursor = CLICK;
members.push(timeBarSpr);
volumeBar = new FlxBar(timeBar.x + timeBar.barWidth - 56, y + 6, LEFT_TO_RIGHT, 56, 10, sound, "volume", 0, 1);
@@ -67,7 +67,7 @@ class UIAudioPlayer extends UIButton {
members.push(volumeBar);
volumeBarSpr = cast new UISprite(volumeBar.x, volumeBar.y).makeSolid(volumeBar.barWidth, volumeBar.barHeight, 0x00FFFFFF);
volumeBarSpr.cursor = BUTTON;
volumeBarSpr.cursor = CLICK;
members.push(volumeBarSpr);
volumeIcon = new FlxSprite(volumeBar.x - 12 - 8, volumeBar.y-1).loadGraphic(Paths.image('editors/ui/audio-icon'));
+1 -1
View File
@@ -13,7 +13,7 @@ class UIButton extends UISliceSprite {
field.alignment = CENTER;
field.fieldWidth = w;
cursor = BUTTON;
cursor = CLICK;
}
public override function resize(w:Int, h:Int) {
+1 -1
View File
@@ -22,7 +22,7 @@ class UICheckbox extends UISprite {
members.push(check);
members.push(field);
cursor = BUTTON;
cursor = CLICK;
}
public override function update(elapsed:Float) {
+1 -1
View File
@@ -43,7 +43,7 @@ class UIDropDown extends UISliceSprite {
this.options = [for(o in _items) o.label]; // backwards compatibility
this.index = index;
cursor = BUTTON;
cursor = CLICK;
label = new UIText(0, 0, width - height, items[index].label);
members.push(label);
+1 -1
View File
@@ -24,7 +24,7 @@ class UIScrollBar extends UISprite {
this.length = length;
thumb = new UISliceSprite(0, 0, w, h, 'editors/ui/scrollbar');
thumb.cursor = BUTTON;
thumb.cursor = CLICK;
members.push(thumb);
thumbIcon = new FlxSprite(0, 0, Paths.image('editors/ui/scrollbar-icon'));
+3 -3
View File
@@ -45,7 +45,7 @@ class UISlider extends UISprite {
makeGraphic(barWidth, 12, 0x00000000, true);
this.drawRoundRect(0, 0, barWidth, 12, 8, 6, 0xFFC0C0C0);
this.drawRoundRect(1, 1, barWidth-2, 12-2, 8, 5, 0xFF140013);
cursor = BUTTON;
cursor = CLICK;
progressbar = new UISprite(centered ? barWidth/2 : 0);
progressbar.makeGraphic(barWidth, 8, 0x00000000, true);
@@ -63,7 +63,7 @@ class UISlider extends UISprite {
var selectableBar:UISprite = new UISprite(x,y);
selectableBar.loadGraphic(Paths.image("editors/ui/slider"));
selectableBar.antialiasing = true;
selectableBar.cursor = BUTTON;
selectableBar.cursor = CLICK;
members.push(selectableBar);
switch (i) {
@@ -74,7 +74,7 @@ class UISlider extends UISprite {
selectableHitbox = new UISprite(x,y);
selectableHitbox.makeSolid(barWidth, 18, -1);
selectableHitbox.cursor = BUTTON;
selectableHitbox.cursor = CLICK;
selectableHitbox.alpha = 0;
members.push(selectableHitbox);
+2 -1
View File
@@ -1,6 +1,7 @@
package funkin.editors.ui;
import flixel.math.FlxRect;
import funkin.backend.utils.NativeAPI.CodeCursor;
import openfl.ui.MouseCursor;
@:allow(funkin.editors.ui.UIState)
@@ -21,7 +22,7 @@ class UISprite extends FlxSprite {
public var hoverCallback:Void->Void = null;
public var cursor:MouseCursor = ARROW;
public var cursor:CodeCursor = ARROW;
public var focused(get, set):Bool;
public var selectable:Bool = true;
+6 -3
View File
@@ -3,6 +3,7 @@ package funkin.editors.ui;
import flixel.math.FlxPoint;
import flixel.math.FlxRect;
import funkin.backend.system.framerate.Framerate;
import funkin.backend.utils.NativeAPI.CodeCursor;
import funkin.editors.ui.UIContextMenu.UIContextMenuCallback;
import funkin.editors.ui.UIContextMenu.UIContextMenuOption;
import lime.ui.KeyCode;
@@ -19,7 +20,7 @@ class UIState extends MusicBeatState {
public var hoveredSprite:UISprite = null;
public var currentFocus:IUIFocusable = null;
public var currentCursor:MouseCursor = ARROW;
public var currentCursor:CodeCursor = ARROW;
private var __rect:FlxRect;
private var __mousePos:FlxPoint;
@@ -105,10 +106,12 @@ class UIState extends MusicBeatState {
FlxG.sound.keysAllowed = currentFocus != null ? !(currentFocus is UITextBox) : true;
if (hoveredSprite != null) {
Mouse.cursor = hoveredSprite.cursor;
NativeAPI.setCursorIcon(hoveredSprite.cursor);
//Mouse.cursor = hoveredSprite.cursor;
hoveredSprite = null;
} else {
Mouse.cursor = currentCursor;
NativeAPI.setCursorIcon(currentCursor);
//Mouse.cursor = currentCursor;
}
}
+1 -1
View File
@@ -43,7 +43,7 @@ class UITopMenuButton extends UISliceSprite {
super(x, y, 0, 23, "editors/ui/menu-item");
this.contextMenu = contextMenu;
this.parent = parent;
cursor = BUTTON;
cursor = CLICK;
this.label = new UIText(4, 0, 0, label);
this.label.alignment = CENTER;
+1 -1
View File
@@ -25,7 +25,7 @@ class UIWindow extends UISliceSprite {
__rect.width = bWidth; __rect.height = topHeight;
if(UIState.state.isOverlapping(this, __rect)) {
cursor = BUTTON;
cursor = CLICK;
if(FlxG.mouse.justPressed) {
content.exists = !content.exists;
drawMiddle = !drawMiddle;