StudioMouse.cs
namespace PixelPusher;

public static class StudioMouse
{
	static float _wheelAt;

	public static void Wheel( int dir, int vx, int vy )
	{
		if ( dir == 0 )
			return;
		_wheelAt = Time.Now;
		dir = dir > 0 ? 1 : -1;

		switch ( GameFlow.Screen )
		{
			case GameScreen.Pixel:
				if ( Ctrl() ) PixelStudio.SetBrush( PixelStudio.Brush + dir );
				else if ( Shift() ) { if ( dir > 0 ) PixelStudio.NextFrame(); else PixelStudio.PrevFrame(); }
				else if ( Alt() ) CycleColor( dir );
				else PixelStudio.ZoomAt( vx, vy, dir );
				break;
			case GameScreen.Stage:
			case GameScreen.Library:
				if ( Ctrl() ) StageStudio.SelectTile( StageStudio.TileId + dir );
				else if ( Shift() ) StageStudio.CycleStamp( dir );
				else StageStudio.ZoomAt( vx, vy, dir );
				break;
			case GameScreen.World:
				WorldStudio.SetZoom( WorldStudio.Zoom + dir );
				break;
			case GameScreen.Chip:
				if ( Ctrl() ) ChipStudio.SetBpm( (Desk.Chip?.Bpm ?? 112) + dir * 8 );
				else ChipStudio.NudgeCursor( dir );
				break;
		}
	}

	public static void Back()
	{
		switch ( GameFlow.Screen )
		{
			case GameScreen.Pixel:
				PixelStudio.Undo();
				break;
			case GameScreen.Stage:
				StageStudio.Undo();
				break;
			case GameScreen.Chip:
				ChipStudio.StepCursor( -1 );
				break;
		}
	}

	public static void Forward()
	{
		switch ( GameFlow.Screen )
		{
			case GameScreen.Pixel:
				PixelStudio.Redo();
				break;
			case GameScreen.Stage:
				StageStudio.Redo();
				break;
			case GameScreen.Chip:
				ChipStudio.StepCursor( 1 );
				break;
		}
	}

	public static void Pan( int dx, int dy )
	{
		if ( dx == 0 && dy == 0 )
			return;
		switch ( GameFlow.Screen )
		{
			case GameScreen.Pixel:
				PixelStudio.PanX -= dx;
				PixelStudio.PanY -= dy;
				GameFlow.Bump();
				break;
			case GameScreen.Stage:
			case GameScreen.Library:
			{
				var z = Math.Max( 1, StageStudio.Zoom );
				StageStudio.Pan( -dx / (float)z, -dy / (float)z );
				GameFlow.Bump();
				break;
			}
			case GameScreen.World:
				WorldStudio.Pan( -dx, -dy );
				GameFlow.Bump();
				break;
		}
	}

	public static void Tick()
	{
		if ( !GameFlow.InStudio && GameFlow.Screen != GameScreen.Library )
			return;
		if ( Input.Pressed( "EditorBack" ) )
			Back();
		if ( Input.Pressed( "EditorForward" ) )
			Forward();

		if ( Time.Now - _wheelAt < 0.02f || !CrtView.PointerOn )
			return;
		try
		{
			var w = Input.MouseWheel.y;
			if ( MathF.Abs( w ) > 0.01f )
				Wheel( w > 0 ? 1 : -1, CrtView.HoverX, CrtView.HoverY );
		}
		catch
		{
			// no wheel
		}
	}

	static void CycleColor( int dir )
	{
		var n = Desk.Sprite?.Palette?.Length ?? 16;
		if ( n <= 0 )
			return;
		var next = PixelStudio.Fg + dir;
		while ( next < 0 ) next += n;
		PixelStudio.SelectColor( (byte)(next % n) );
	}

	public static bool AltHeld => Alt();
	public static bool CtrlHeld => Ctrl();

	static bool Ctrl()
	{
		try
		{
			if ( Input.Keyboard.Down( "CTRL" ) || Input.Keyboard.Down( "RCTRL" ) )
				return true;
		}
		catch
		{
			// ignore
		}
		return Input.Down( "Duck" );
	}

	static bool Shift()
	{
		try
		{
			if ( Input.Keyboard.Down( "SHIFT" ) || Input.Keyboard.Down( "RSHIFT" ) )
				return true;
		}
		catch
		{
			// ignore
		}
		return Input.Down( "Run" );
	}

	static bool Alt()
	{
		try
		{
			if ( Input.Keyboard.Down( "ALT" ) || Input.Keyboard.Down( "RALT" ) )
				return true;
		}
		catch
		{
			// ignore
		}
		return Input.Down( "Walk" );
	}
}