Skip to content

Commit

Permalink
cursor style fixup
Browse files Browse the repository at this point in the history
  • Loading branch information
Nemrav committed Dec 11, 2024
1 parent b5cd887 commit 502df1c
Show file tree
Hide file tree
Showing 4 changed files with 115 additions and 55 deletions.
66 changes: 66 additions & 0 deletions extension/doc_classes/CursorSingleton.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="CursorSingleton" inherits="Object" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="https://raw.githubusercontent.com/godotengine/godot/master/doc/class.xsd">
<brief_description>
</brief_description>
<description>
</description>
<tutorials>
</tutorials>
<methods>
<method name="generate_resolution">
<return type="void" />
<param index="0" name="cursor name" type="String" default="&quot;normal&quot;" />
<param index="1" name="base resolution index" type="int" default="0" />
<param index="2" name="target resolution" type="Vector2i" default="Vector2i(64, 64)" />
<description>
</description>
</method>
<method name="get_animationLength">
<return type="int" />
<param index="0" name="cursor name" type="String" default="&quot;normal&quot;" />
<description>
</description>
</method>
<method name="get_displayRates">
<return type="PackedFloat32Array" />
<param index="0" name="cursor name" type="String" default="&quot;normal&quot;" />
<description>
</description>
</method>
<method name="get_frames">
<return type="Array" />
<param index="0" name="cursor name" type="String" default="&quot;normal&quot;" />
<param index="1" name="resolution index" type="int" default="0" />
<description>
</description>
</method>
<method name="get_hotspots">
<return type="Vector2i[]" />
<param index="0" name="cursor name" type="String" default="&quot;normal&quot;" />
<param index="1" name="resolution index" type="int" default="0" />
<description>
</description>
</method>
<method name="get_resolutions">
<return type="Vector2i[]" />
<param index="0" name="cursor name" type="String" default="&quot;normal&quot;" />
<description>
</description>
</method>
<method name="get_sequence">
<return type="PackedInt32Array" />
<param index="0" name="cursor name" type="String" default="&quot;normal&quot;" />
<description>
</description>
</method>
<method name="load_cursors">
<return type="bool" />
<description>
</description>
</method>
</methods>
<members>
<member name="cursor_names" type="Array" setter="" getter="get_cursor_names" default="[]">
</member>
</members>
</class>
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@
#include <godot_cpp/variant/string.hpp>
#include <godot_cpp/variant/string_name.hpp>

#include <openvic-simulation/dataloader/Dataloader.hpp>
#include <openvic-extension/singletons/GameSingleton.hpp>
#include <openvic-simulation/dataloader/Dataloader.hpp>
#include <openvic-simulation/types/OrderedContainers.hpp>
#include <openvic-simulation/types/IdentifierRegistry.hpp>

Expand Down
86 changes: 47 additions & 39 deletions game/src/Game/Autoload/CursorManager.gd
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,17 @@ extends Node

#NOTE: See GameStart.gd for example usage

class compat_Cursor:
class CompatCursor:
#cursor properties
var cursor_name:String
var shape:Input.CursorShape = Input.CURSOR_ARROW
var cursor_name : String
var shape : Input.CursorShape = Input.CURSOR_ARROW

var resolutions:Array[Vector2i]
var frames:Array
var hotspots:Array[Vector2i]
var is_animated:bool = false
var sequence:PackedInt32Array = [0]
var timings:PackedFloat32Array = [1.0]
var resolutions : Array[Vector2i]
var frames : Array
var hotspots : Array[Vector2i]
var is_animated : bool = false
var sequence : PackedInt32Array = [0]
var timings : PackedFloat32Array = [1.0]

#Cursor state
var currentFrame : int = 0
Expand All @@ -32,24 +32,24 @@ class compat_Cursor:
self.timings = CursorSingleton.get_displayRates(self.cursor_name)
self.timeToFrame = self.timings[self.sequence[currentFrame]]

func reset():
func reset() -> void:
currentFrame = 0
timeToFrame = self.timings[self.sequence[0]]

func set_resolution(resolution : Vector2i) -> void:
var index = resolutions.find(resolution)
var index : int = resolutions.find(resolution)
if index != -1:
frames = CursorSingleton.get_frames(cursor_name,index)
return

#couldnt find it, so generate it based on the highest res available
var highest_res_ind:int = 0
var highest_res_x = 0
for i in range(len(resolutions)):
var highest_res_index : int = 0
var highest_res_x : int = 0
for i : int in range(len(resolutions)):
if resolutions[i].x > highest_res_x:
highest_res_x = resolutions[i].x
highest_res_ind = i
generate_new_res(highest_res_ind,resolution)
highest_res_index = i
generate_new_res(highest_res_index,resolution)

self.resolutions = CursorSingleton.get_resolutions(self.cursor_name)
self.frames = CursorSingleton.get_frames(self.cursor_name,len(self.resolutions)-1)
Expand All @@ -71,9 +71,8 @@ class compat_Cursor:
set_hardware_cursor(currentFrame)

func set_hardware_cursor(frame:int=0) -> void:
var texture = frames[sequence[frame]]
var hotspot = hotspots[sequence[frame]]
print("name: %s shape: %s" % [cursor_name,shape])
var texture : ImageTexture = frames[sequence[frame]]
var hotspot : Vector2i = hotspots[sequence[frame]]
Input.set_custom_mouse_cursor(texture,shape,hotspot)


Expand All @@ -82,36 +81,32 @@ class compat_Cursor:

var mouseOverWindow : bool = false
var windowFocused : bool = false
var activeCursor : compat_Cursor
var activeCursor : CompatCursor

#TODO: This is set on game start, but we probably want this to be a video setting
var preferred_res : Vector2i = Vector2i(32,32)

#Shape > Cursor dictionnaries
#NOTE: In terms of V2, this is unnecessary, as the only cursor that isn't of shape
#"arrow" in v2 is "busy", which needs to be manually triggered anyways like arrow.
# and so could be just left as an "arrow"
#This would be necessary for shapes like IBEAM which get switched to automatically
#NOTE: In terms of V2, this could be replaced by switching the arrow cursor
# to busy ourselves, rather than relying on godot to switch to CURSOR_BUSY.
var currentCursors : Dictionary = {
Input.CURSOR_ARROW:null,
Input.CURSOR_BUSY:null,
Input.CURSOR_IBEAM:null
Input.CURSOR_BUSY:null
}
var queuedCursors : Dictionary = {
Input.CURSOR_ARROW:null,
Input.CURSOR_BUSY:null,
Input.CURSOR_IBEAM:null
Input.CURSOR_BUSY:null
}

var loaded_cursors : Dictionary = {}

func load_cursors() -> void:
CursorSingleton.load_cursors()
for cursor_name in CursorSingleton.cursor_names:
var shape:Input.CursorShape = Input.CURSOR_ARROW
for cursor_name : StringName in CursorSingleton.cursor_names:
var shape : Input.CursorShape = Input.CURSOR_ARROW
if cursor_name == &"busy":
shape = Input.CURSOR_BUSY
var cursor = compat_Cursor.new(cursor_name,shape)
var cursor : CompatCursor = CompatCursor.new(cursor_name,shape)
cursor.set_resolution(preferred_res)
loaded_cursors[cursor_name] = cursor

Expand All @@ -120,8 +115,8 @@ func load_cursors() -> void:
func _process(delta) -> void:
#only attempt to update the mouse when this wont crash anything
if mouseOverWindow:
var advanceFrame = true #dont go to next frame if we just switched cursors
var mouseShape:Input.CursorShape = Input.get_current_cursor_shape()
var advanceFrame : bool = true #dont go to next frame if we just switched cursors
var mouseShape : Input.CursorShape = Input.get_current_cursor_shape()

for shape in currentCursors.keys():
if currentCursors[shape] != queuedCursors[shape] and queuedCursors[shape] != null:
Expand All @@ -138,10 +133,7 @@ func _process(delta) -> void:
# reset the current cursor's frame, then switch the active cursor
if activeCursor != null and mouseShape != activeCursor.shape:
#Current mouse type changed, need to make sure that if the cursor of this new type
# is animated, we are providing its frames instead of the frames of the previous active cursor
#activeCursor.reset() # reset the frame in the sequence to use
#activeCursor.set_hardware_cursor()

# is animated, we are providing its frames instead of the frames of the previous active cursor
if mouseShape in currentCursors and currentCursors[mouseShape] != null:
activeCursor = currentCursors[mouseShape]
activeCursor.reset()
Expand All @@ -159,7 +151,7 @@ func set_prefered_res(res_in:Vector2i) -> void:
#a cursor switch
func set_compat_cursor(cursor_name:String) -> void:
if cursor_name in loaded_cursors:
var cursor = loaded_cursors[cursor_name]
var cursor : CompatCursor = loaded_cursors[cursor_name]
cursor.set_resolution(preferred_res)
queuedCursors[cursor.shape] = cursor
else:
Expand All @@ -171,9 +163,25 @@ func set_cursor_shape(cursor_name:String, cursor_shape:Input.CursorShape) -> voi
else:
push_warning("Cursor name %s is not among loaded cursors" % cursor_name)

func initial_cursor_setup() -> void:
set_prefered_res(Vector2i(48,48))
load_cursors()

#NOTE: Each cursor hasa corresponding "shape"
# to indicate when window is busy, normal, doing a drag
# select, etc. You can set this per Control Node under
# Mouse > Default Cursor Shape
# set_cursor_shape associates a shape with a cursor loaded
# from vic2 (name matches the vic2 file name w/o the extension)
# though load_cursors should handle that for you...
# set_compat_cursor makes the named vic2 cursor the presently active
# one for the shape it is currently associated with
set_compat_cursor(&"normal")
set_compat_cursor(&"busy")

# To safely change the mouse cursor, the mouse must be over the window
# this function helps ensure we do it safely
func _notification(what):
func _notification(what) -> void:
match(what):
NOTIFICATION_WM_MOUSE_ENTER:
mouseOverWindow = true
Expand Down
16 changes: 1 addition & 15 deletions game/src/Game/GameStart.gd
Original file line number Diff line number Diff line change
Expand Up @@ -108,21 +108,7 @@ func _load_compatibility_mode() -> void:
if GameSingleton.set_compatibility_mode_roots(_compatibility_path_list) != OK:
push_error("Errors setting game roots!")

CursorManager.set_prefered_res(Vector2i(48,48))
CursorManager.load_cursors()

#NOTE: Each cursor hasa corresponding "shape"
# to indicate when window is busy, normal, doing a drag
# select, etc. You can set this per Control Node under
# Mouse > Default Cursor Shape
# set_cursor_shape associates a shape with a cursor loaded
# from vic2 (name matches the vic2 file name w/o the extension)
# though load_cursors should handle that for you...
# set_compat_cursor makes the named vic2 cursor the presently active
# one for the shape it is currently associated with
CursorManager.set_compat_cursor(&"normal")
CursorManager.set_compat_cursor(&"busy")

CursorManager.initial_cursor_setup()
setup_title_theme()

if GameSingleton.load_defines_compatibility_mode() != OK:
Expand Down

0 comments on commit 502df1c

Please sign in to comment.