@@ -37,14 +37,6 @@ public partial class FrmMapEditor : DockContent
3737 private bool mMapChanged ;
3838
3939 // MapGrid Cursor
40- private Bitmap mCurSprite ;
41-
42- private readonly string mCurFolder = "resources/cursors/" ;
43-
44- private string mCurPath ;
45-
46- private Point mCurClickPoint ;
47-
4840 private Timer cursorUpdateTimer ;
4941
5042 public struct IconInfo
@@ -2356,17 +2348,12 @@ private void pnlMapContainer_Resize(object sender, EventArgs e)
23562348
23572349 private void picMap_MouseEnter ( object sender , EventArgs e )
23582350 {
2359- var enableCursorSprites = Preferences . LoadPreference ( "EnableCursorSprites" ) ;
2360-
23612351 if ( ! Globals . MapEditorWindow . DockPanel . Focused && Globals . CurrentEditor == - 1 )
23622352 {
23632353 Globals . MapEditorWindow . DockPanel . Focus ( ) ;
23642354 }
23652355
2366- if ( ! string . IsNullOrEmpty ( enableCursorSprites ) && ! Convert . ToBoolean ( enableCursorSprites ) )
2367- {
2368- RemoveSpriteCursorInGrid ( ) ;
2369- }
2356+ RemoveSpriteCursorInGrid ( ) ;
23702357 }
23712358
23722359 private void picMap_MouseLeave ( object sender , EventArgs e )
@@ -2387,55 +2374,128 @@ private void CursorUpdateTimer_Tick(object sender, EventArgs e)
23872374
23882375 private void SetCursorSpriteInGrid ( )
23892376 {
2390- if ( ! Directory . Exists ( mCurFolder ) )
2377+ if ( ! Preferences . EnableCursorSprites )
23912378 {
23922379 return ;
23932380 }
23942381
2395- var enableCursorSprites = Preferences . LoadPreference ( "EnableCursorSprites" ) ;
2382+ var currentTool = Globals . CurrentTool ;
2383+ var toolCursor = GetOrCreateCursorForTool ( currentTool ) ;
2384+ Cursor = toolCursor ?? Cursors . Default ;
2385+ }
23962386
2397- if ( ! ( ! string . IsNullOrEmpty ( enableCursorSprites ) && Convert . ToBoolean ( enableCursorSprites ) ) )
2387+ private void RemoveSpriteCursorInGrid ( )
2388+ {
2389+ if ( ! _toolCursors . Contains ( Cursor ) )
23982390 {
2391+ // Exit instead of setting the cursor to default if it's not a custom cursor
23992392 return ;
24002393 }
2394+
2395+ Cursor = Cursors . Default ;
2396+ }
24012397
2402- mCurPath = $ "{ mCurFolder } editor_{ Globals . CurrentTool . ToString ( ) . ToLowerInvariant ( ) } .png";
2398+ private static Cursor ? GetOrCreateCursorForTool ( EditingTool editingTool )
2399+ {
2400+ if ( _toolCursorCache . TryGetValue ( editingTool , out var toolCursor ) )
2401+ {
2402+ return toolCursor ;
2403+ }
24032404
2404- if ( ! File . Exists ( mCurPath ) )
2405+ if ( ! ToolCursor . ToolCursorDict . TryGetValue ( editingTool , out var toolCursorInfo ) )
24052406 {
2406- return ;
2407+ var loadedClickPointKeys = string . Join ( ", " , ToolCursor . ToolCursorDict . Keys ) ;
2408+ Log . Error (
2409+ $ "Unable to load click point for { editingTool } , click points only exist for: { loadedClickPointKeys } "
2410+ ) ;
2411+ return null ;
24072412 }
24082413
2409- mCurClickPoint = ToolCursor . ToolCursorDict [ Globals . CurrentTool ] . CursorClickPoint ;
2410- mCurSprite = new Bitmap ( mCurPath ) ;
2411- Cursor = CreateCursorInGrid ( mCurSprite , mCurClickPoint ) ;
2412- }
2414+ if ( ! Directory . Exists ( ToolCursor . CursorsFolder ) )
2415+ {
2416+ return null ;
2417+ }
24132418
2414- private void RemoveSpriteCursorInGrid ( )
2415- {
2416- if ( mCurSprite == default )
2419+ var cursorFileName = $ "editor_{ editingTool . ToString ( ) . ToLowerInvariant ( ) } .png";
2420+ var cursorPath = Path . Combine ( ToolCursor . CursorsFolder , cursorFileName ) ;
2421+ var cursorAbsolutePath = Path . GetFullPath ( cursorPath ) ;
2422+ var loggingCursorPath = cursorPath ;
2423+ #if DEBUG
2424+ loggingCursorPath = cursorAbsolutePath ;
2425+ #endif
2426+ if ( ! File . Exists ( cursorAbsolutePath ) )
24172427 {
2418- return ;
2428+ Log . Error (
2429+ $ "Custom cursor texture '{ cursorFileName } ' does not exist in { ToolCursor . CursorsFolder } resolved to { loggingCursorPath } "
2430+ ) ;
2431+ return null ;
24192432 }
24202433
2421- mCurSprite . Dispose ( ) ;
2422- DestroyIcon ( Cursor . Handle ) ;
2423- Cursor = Cursors . Default ;
2434+ Bitmap cursorBitmap ;
2435+ try
2436+ {
2437+ cursorBitmap = new Bitmap ( cursorAbsolutePath ) ;
2438+ }
2439+ catch ( Exception exception )
2440+ {
2441+ Log . Error ( exception , $ "Failed to load custom cursor for { editingTool } resolved to { loggingCursorPath } ") ;
2442+ return null ;
2443+ }
2444+
2445+ toolCursor = CreateCursorInGrid ( cursorBitmap , toolCursorInfo . CursorClickPoint , cursorFileName ) ;
2446+ if ( toolCursor == null )
2447+ {
2448+ return null ;
2449+ }
2450+
2451+ _toolCursors . Add ( toolCursor ) ;
2452+ _toolCursorCache [ editingTool ] = toolCursor ;
2453+
2454+ return toolCursor ;
24242455 }
24252456
24262457 /// <summary>
24272458 /// Creates a cursor from a bitmap depending on the user preferences and selected tool.
24282459 /// </summary>
2429- private Cursor CreateCursorInGrid ( Bitmap bmp , Point curHotSpot )
2460+ private static Cursor ? CreateCursorInGrid ( Bitmap cursorBitmap , Point cursorClickPoint , string logName )
24302461 {
2431- DestroyIcon ( Cursor . Handle ) ;
2432- IntPtr ptr = bmp . GetHicon ( ) ;
2433- IconInfo tmp = new IconInfo ( ) ;
2434- GetIconInfo ( ptr , ref tmp ) ;
2435- tmp . XHotspot = curHotSpot . X ;
2436- tmp . YHotspot = curHotSpot . Y ;
2437- tmp . FIcon = false ;
2438- ptr = CreateIconIndirect ( ref tmp ) ;
2439- return new Cursor ( ptr ) ;
2462+ try
2463+ {
2464+ IntPtr bitmapHicon = cursorBitmap . GetHicon ( ) ;
2465+ if ( bitmapHicon == IntPtr . Zero )
2466+ {
2467+ Log . Warn ( $ "Failed to get bitmap icon handle for { logName } ") ;
2468+ return null ;
2469+ }
2470+
2471+ IconInfo cursorIconInfo = new IconInfo ( ) ;
2472+ if ( ! GetIconInfo ( bitmapHicon , ref cursorIconInfo ) )
2473+ {
2474+ Log . Warn ( $ "Failed to get icon info for { logName } ") ;
2475+ return null ;
2476+ }
2477+
2478+ cursorIconInfo . XHotspot = cursorClickPoint . X ;
2479+ cursorIconInfo . YHotspot = cursorClickPoint . Y ;
2480+ cursorIconInfo . FIcon = false ;
2481+
2482+ var cursorIcon = CreateIconIndirect ( ref cursorIconInfo ) ;
2483+ // ReSharper disable once InvertIf
2484+ if ( cursorIcon == IntPtr . Zero )
2485+ {
2486+ Log . Warn ( $ "Failed to create cursor icon for { logName } ") ;
2487+ return null ;
2488+ }
2489+
2490+ return new Cursor ( cursorIcon ) ;
2491+ }
2492+ catch ( Exception exception )
2493+ {
2494+ Log . Error ( exception , $ "Error while creating cursor for { logName } ") ;
2495+ return null ;
2496+ }
24402497 }
2498+
2499+ private static readonly HashSet < Cursor > _toolCursors = [ ] ;
2500+ private static readonly Dictionary < EditingTool , Cursor > _toolCursorCache = [ ] ;
24412501}
0 commit comments