diff --git a/src/Autoload/Global.gd b/src/Autoload/Global.gd index 972c0ab8b..01c288bba 100644 --- a/src/Autoload/Global.gd +++ b/src/Autoload/Global.gd @@ -337,55 +337,8 @@ var default_height := 64 ## Found in Preferences. The default height of startup var default_fill_color := Color(0, 0, 0, 0) ## Found in Preferences. The distance to the guide or grig below which cursor snapping activates. var snapping_distance := 32.0 -## Found in Preferences. The grid type defined by [enum GridTypes] enum. -var grid_type := GridTypes.CARTESIAN: - set(value): - if value == grid_type: - return - grid_type = value - if is_instance_valid(canvas.grid): - canvas.grid.queue_redraw() -## Found in Preferences. The size of rectangular grid. -var grid_size := Vector2i(2, 2): - set(value): - if value == grid_size: - return - grid_size = value - if is_instance_valid(canvas.grid): - canvas.grid.queue_redraw() -## Found in Preferences. The size of isometric grid. -var isometric_grid_size := Vector2i(16, 8): - set(value): - if value == isometric_grid_size: - return - isometric_grid_size = value - if is_instance_valid(canvas.grid): - canvas.grid.queue_redraw() -## Found in Preferences. The grid offset from top-left corner of the canvas. -var grid_offset := Vector2i.ZERO: - set(value): - if value == grid_offset: - return - grid_offset = value - if is_instance_valid(canvas.grid): - canvas.grid.queue_redraw() -## Found in Preferences. If [code]true[/code], The grid draws over the area extended by -## tile-mode as well. -var grid_draw_over_tile_mode := false: - set(value): - if value == grid_draw_over_tile_mode: - return - grid_draw_over_tile_mode = value - if is_instance_valid(canvas.grid): - canvas.grid.queue_redraw() -## Found in Preferences. The color of grid. -var grid_color := Color.BLACK: - set(value): - if value == grid_color: - return - grid_color = value - if is_instance_valid(canvas.grid): - canvas.grid.queue_redraw() +## Contains dictionaries of individual grids. +var grids: Array[Grid] = [] ## Found in Preferences. The minimum zoom after which pixel grid gets drawn if enabled. var pixel_grid_show_at_zoom := 1500.0: # percentage set(value): @@ -677,6 +630,62 @@ var cel_button_scene: PackedScene = load("res://src/UI/Timeline/CelButton.tscn") @onready var error_dialog: AcceptDialog = control.find_child("ErrorDialog") +class Grid: + var grid_type := GridTypes.CARTESIAN: + set(value): + if value == grid_type: + return + grid_type = value + if is_instance_valid(Global.canvas.grid): + Global.canvas.grid.queue_redraw() + ## Found in Preferences. The size of rectangular grid. + var grid_size := Vector2i(2, 2): + set(value): + if value == grid_size: + return + grid_size = value + if is_instance_valid(Global.canvas.grid): + Global.canvas.grid.queue_redraw() + ## Found in Preferences. The size of isometric grid. + var isometric_grid_size := Vector2i(16, 8): + set(value): + if value == isometric_grid_size: + return + isometric_grid_size = value + if is_instance_valid(Global.canvas.grid): + Global.canvas.grid.queue_redraw() + ## Found in Preferences. The grid offset from top-left corner of the canvas. + var grid_offset := Vector2i.ZERO: + set(value): + if value == grid_offset: + return + grid_offset = value + if is_instance_valid(Global.canvas.grid): + Global.canvas.grid.queue_redraw() + ## Found in Preferences. If [code]true[/code], The grid draws over the area extended by + ## tile-mode as well. + var grid_draw_over_tile_mode := false: + set(value): + if value == grid_draw_over_tile_mode: + return + grid_draw_over_tile_mode = value + if is_instance_valid(Global.canvas.grid): + Global.canvas.grid.queue_redraw() + ## Found in Preferences. The color of grid. + var grid_color := Color.BLACK: + set(value): + if value == grid_color: + return + grid_color = value + if is_instance_valid(Global.canvas.grid): + Global.canvas.grid.queue_redraw() + + func _init(properties := {}) -> void: + Global.grids.append(self) + for prop in properties.keys(): + set(prop, properties[prop]) + + func _init() -> void: # Load settings from the config file config_cache.load(CONFIG_PATH) @@ -713,6 +722,8 @@ func _init() -> void: func _ready() -> void: + # Initialize Grid + Grid.new() # gets auto added to grids array _initialize_keychain() default_width = config_cache.get_value("preferences", "default_width", default_width) default_height = config_cache.get_value("preferences", "default_height", default_height) @@ -729,13 +740,23 @@ func _ready() -> void: if get(pref) == null: continue var value = config_cache.get_value("preferences", pref) - set(pref, value) + if pref == "grids": + if value: + update_grids(value) + else: + set(pref, value) if OS.is_sandboxed(): Global.use_native_file_dialogs = true await get_tree().process_frame project_switched.emit() +func update_grids(grids_data: Dictionary): + grids.clear() + for grid_idx in grids_data.size(): + Grid.new(grids_data[grid_idx]) # gets auto added to grids array + + func _initialize_keychain() -> void: Keychain.config_file = config_cache Keychain.actions = { diff --git a/src/Preferences/GridPreferences.gd b/src/Preferences/GridPreferences.gd new file mode 100644 index 000000000..2997222a1 --- /dev/null +++ b/src/Preferences/GridPreferences.gd @@ -0,0 +1,163 @@ +extends GridContainer + +var grid_preferences: Array[GridPreference] = [ + GridPreference.new("grid_type", "GridType", "selected", Global.GridTypes.CARTESIAN), + GridPreference.new("grid_size", "GridSizeValue", "value", Vector2i(2, 2)), + GridPreference.new("isometric_grid_size", "IsometricGridSizeValue", "value", Vector2i(16, 8)), + GridPreference.new("grid_offset", "GridOffsetValue", "value", Vector2i.ZERO), + GridPreference.new("grid_draw_over_tile_mode", "GridDrawOverTileMode", "button_pressed", false), + GridPreference.new("grid_color", "GridColor", "color", Color.BLACK), +] + +var grid_selected: int = 0: + set(key): + grid_selected = key + for child: BaseButton in grids_select_container.get_children(): + if child.get_index() == grid_selected: + child.self_modulate = Color.WHITE + else: + child.self_modulate = Color.DIM_GRAY + var grids: Dictionary = Global.config_cache.get_value( + "preferences", "grids", {0: create_default_properties()} + ) + if grids.has(key): + update_pref_ui(grids[key]) + +@onready var grids_select_container: HFlowContainer = $GridsSelectContainer + + +class GridPreference: + var prop_name: String + var node_path: String + var value_type: String + var default_value + + func _init( + _prop_name: String, + _node_path: String, + _value_type: String, + _default_value = null, + _require_restart := false + ) -> void: + prop_name = _prop_name + node_path = _node_path + value_type = _value_type + if _default_value != null: + default_value = _default_value + + +func _ready() -> void: + var grids = Global.config_cache.get_value( + "preferences", "grids", {0: create_default_properties()} + ) + Global.config_cache.set_value("preferences", "grids", grids) + $GridsCount.value = grids.size() + if grids.size() == 1: + add_remove_select_button(0) + for pref in grid_preferences: + if not has_node(pref.node_path): + continue + var node := get_node(pref.node_path) + var restore_default_button := RestoreDefaultButton.new() + restore_default_button.pressed.connect( + _on_grid_pref_value_changed.bind(pref.default_value, pref, restore_default_button) + ) + restore_default_button.setting_name = pref.prop_name + restore_default_button.value_type = pref.value_type + restore_default_button.default_value = pref.default_value + restore_default_button.node = node + + var node_position := node.get_index() + node.get_parent().add_child(restore_default_button) + node.get_parent().move_child(restore_default_button, node_position) + + match pref.value_type: + "button_pressed": + node.toggled.connect(_on_grid_pref_value_changed.bind(pref, restore_default_button)) + "value": + node.value_changed.connect( + _on_grid_pref_value_changed.bind(pref, restore_default_button) + ) + "color": + node.get_picker().presets_visible = false + node.color_changed.connect( + _on_grid_pref_value_changed.bind(pref, restore_default_button) + ) + "selected": + node.item_selected.connect( + _on_grid_pref_value_changed.bind(pref, restore_default_button) + ) + grid_selected = 0 + + +func _on_grid_pref_value_changed(value, pref: GridPreference, button: RestoreDefaultButton) -> void: + var grids: Dictionary = Global.config_cache.get_value( + "preferences", "grids", {0: create_default_properties()} + ) + if grids.has(grid_selected): # Failsafe (Always true) + var grid_info: Dictionary = grids[grid_selected] + var prop := pref.prop_name + grid_info[prop] = value + grids[grid_selected] = grid_info + Global.update_grids(grids) + var default_value = pref.default_value + var disable: bool = Global.grids[grid_selected].get(prop) == default_value + if typeof(value) == TYPE_COLOR: + disable = value.is_equal_approx(default_value) + disable_restore_default_button(button, disable) + Global.config_cache.set_value("preferences", "grids", grids) + + +func _on_grids_count_value_changed(value: float) -> void: + var grid_idx = int(value - 1) + var grids: Dictionary = Global.config_cache.get_value( + "preferences", "grids", {0: create_default_properties()} + ) + if grid_idx >= grids_select_container.get_child_count(): + for key in range(grids_select_container.get_child_count(), grid_idx + 1): + if not grids.has(key): + grids[key] = create_default_properties() + add_remove_select_button(key) + else: + for key: int in range(grid_idx + 1, grids.size()): + grids.erase(key) + add_remove_select_button(key, true) + Global.update_grids(grids) + Global.config_cache.set_value("preferences", "grids", grids) + + +func create_default_properties() -> Dictionary: + var grid_info = {} + for pref in grid_preferences: + grid_info[pref.prop_name] = pref.default_value + return grid_info + + +func disable_restore_default_button(button: RestoreDefaultButton, disable: bool) -> void: + button.disabled = disable + if disable: + button.mouse_default_cursor_shape = Control.CURSOR_ARROW + button.tooltip_text = "" + else: + button.mouse_default_cursor_shape = Control.CURSOR_POINTING_HAND + button.tooltip_text = "Restore default value" + + +func add_remove_select_button(grid_idx: int, remove := false): + if not remove: + var select_button = Button.new() + select_button.text = str(grid_idx) + grids_select_container.add_child(select_button) + select_button.pressed.connect(func(): grid_selected = grid_idx) + else: + if grid_idx < grids_select_container.get_child_count(): + grids_select_container.get_child(grid_idx).queue_free() + grid_selected = min(grid_selected, grid_idx - 1) + + +func update_pref_ui(grid_data: Dictionary): + for pref in grid_preferences: + var key = pref.prop_name + if grid_data.has(key): + var node := get_node(pref.node_path) + node.set(pref.value_type, grid_data[key]) diff --git a/src/Preferences/PreferencesDialog.gd b/src/Preferences/PreferencesDialog.gd index 5ba2f37d6..86085fb54 100644 --- a/src/Preferences/PreferencesDialog.gd +++ b/src/Preferences/PreferencesDialog.gd @@ -94,21 +94,6 @@ var preferences: Array[Preference] = [ Preference.new("smooth_zoom", "Canvas/ZoomOptions/SmoothZoom", "button_pressed", true), Preference.new("integer_zoom", "Canvas/ZoomOptions/IntegerZoom", "button_pressed", false), Preference.new("snapping_distance", "Canvas/SnappingOptions/DistanceValue", "value", 32.0), - Preference.new( - "grid_type", "Canvas/GridOptions/GridType", "selected", Global.GridTypes.CARTESIAN - ), - Preference.new("grid_size", "Canvas/GridOptions/GridSizeValue", "value", Vector2i(2, 2)), - Preference.new( - "isometric_grid_size", "Canvas/GridOptions/IsometricGridSizeValue", "value", Vector2i(16, 8) - ), - Preference.new("grid_offset", "Canvas/GridOptions/GridOffsetValue", "value", Vector2i.ZERO), - Preference.new( - "grid_draw_over_tile_mode", - "Canvas/GridOptions/GridDrawOverTileMode", - "button_pressed", - false - ), - Preference.new("grid_color", "Canvas/GridOptions/GridColor", "color", Color.BLACK), Preference.new( "pixel_grid_show_at_zoom", "Canvas/PixelGridOptions/ShowAtZoom", "value", 1500.0 ), diff --git a/src/Preferences/PreferencesDialog.tscn b/src/Preferences/PreferencesDialog.tscn index 411e305ad..7b79c020e 100644 --- a/src/Preferences/PreferencesDialog.tscn +++ b/src/Preferences/PreferencesDialog.tscn @@ -1,8 +1,10 @@ -[gd_scene load_steps=9 format=3 uid="uid://b3hkjj3s6pe4x"] +[gd_scene load_steps=11 format=3 uid="uid://b3hkjj3s6pe4x"] [ext_resource type="Script" path="res://src/Preferences/PreferencesDialog.gd" id="1"] [ext_resource type="PackedScene" uid="uid://bq7ibhm0txl5p" path="res://addons/keychain/ShortcutEdit.tscn" id="3"] [ext_resource type="Script" path="res://src/Preferences/ThemesPreferences.gd" id="3_nvl8k"] +[ext_resource type="Script" path="res://src/Preferences/GridPreferences.gd" id="4_76iff"] +[ext_resource type="PackedScene" uid="uid://yjhp0ssng2mp" path="res://src/UI/Nodes/ValueSlider.tscn" id="5_rlmsh"] [ext_resource type="PackedScene" path="res://src/UI/Nodes/ValueSliderV2.tscn" id="7"] [ext_resource type="Script" path="res://src/Preferences/ExtensionsPreferences.gd" id="7_8ume5"] [ext_resource type="Script" path="res://src/UI/Nodes/ValueSlider.gd" id="8"] @@ -482,6 +484,30 @@ layout_mode = 2 theme_override_constants/h_separation = 4 theme_override_constants/v_separation = 4 columns = 3 +script = ExtResource("4_76iff") + +[node name="GridsCountLabel" type="Label" parent="HSplitContainer/VBoxContainer/ScrollContainer/RightSide/Canvas/GridOptions"] +layout_mode = 2 +text = "Grids Visible:" + +[node name="Spacer" type="Control" parent="HSplitContainer/VBoxContainer/ScrollContainer/RightSide/Canvas/GridOptions"] +layout_mode = 2 + +[node name="GridsCount" parent="HSplitContainer/VBoxContainer/ScrollContainer/RightSide/Canvas/GridOptions" instance=ExtResource("5_rlmsh")] +layout_mode = 2 +min_value = 1.0 +max_value = 10.0 +value = 1.0 + +[node name="GridsSelectLabel" type="Label" parent="HSplitContainer/VBoxContainer/ScrollContainer/RightSide/Canvas/GridOptions"] +layout_mode = 2 +text = "Editing Grid:" + +[node name="Spacer2" type="Control" parent="HSplitContainer/VBoxContainer/ScrollContainer/RightSide/Canvas/GridOptions"] +layout_mode = 2 + +[node name="GridsSelectContainer" type="HFlowContainer" parent="HSplitContainer/VBoxContainer/ScrollContainer/RightSide/Canvas/GridOptions"] +layout_mode = 2 [node name="GridTypeLabel" type="Label" parent="HSplitContainer/VBoxContainer/ScrollContainer/RightSide/Canvas/GridOptions"] layout_mode = 2 @@ -1478,6 +1504,7 @@ dialog_text = "Are you sure you want to reset the selected options? There will b [connection signal="pressed" from="HSplitContainer/VBoxContainer/ScrollContainer/RightSide/Language/System Language" to="." method="_on_language_pressed" binds= [1]] [connection signal="pressed" from="HSplitContainer/VBoxContainer/ScrollContainer/RightSide/Interface/InterfaceOptions/ShrinkContainer/ShrinkApplyButton" to="." method="_on_shrink_apply_button_pressed"] [connection signal="pressed" from="HSplitContainer/VBoxContainer/ScrollContainer/RightSide/Interface/InterfaceOptions/FontSizeContainer/FontSizeApplyButton" to="." method="_on_font_size_apply_button_pressed"] +[connection signal="value_changed" from="HSplitContainer/VBoxContainer/ScrollContainer/RightSide/Canvas/GridOptions/GridsCount" to="HSplitContainer/VBoxContainer/ScrollContainer/RightSide/Canvas/GridOptions" method="_on_grids_count_value_changed"] [connection signal="pressed" from="HSplitContainer/VBoxContainer/ScrollContainer/RightSide/Extensions/ExtensionsHeader/Explore" to="Store" method="_on_explore_pressed"] [connection signal="empty_clicked" from="HSplitContainer/VBoxContainer/ScrollContainer/RightSide/Extensions/InstalledExtensions" to="HSplitContainer/VBoxContainer/ScrollContainer/RightSide/Extensions" method="_on_InstalledExtensions_empty_clicked"] [connection signal="item_selected" from="HSplitContainer/VBoxContainer/ScrollContainer/RightSide/Extensions/InstalledExtensions" to="HSplitContainer/VBoxContainer/ScrollContainer/RightSide/Extensions" method="_on_InstalledExtensions_item_selected"] diff --git a/src/Tools/BaseSelectionTool.gd b/src/Tools/BaseSelectionTool.gd index af279f60a..8ed365050 100644 --- a/src/Tools/BaseSelectionTool.gd +++ b/src/Tools/BaseSelectionTool.gd @@ -159,16 +159,17 @@ func draw_move(pos: Vector2i) -> void: else: pos.x = _start_pos.x if Input.is_action_pressed("transform_snap_grid"): - _offset = _offset.snapped(Global.grid_size) + _offset = _offset.snapped(Global.grids[0].grid_size) var prev_pos: Vector2i = selection_node.big_bounding_rectangle.position - selection_node.big_bounding_rectangle.position = prev_pos.snapped(Global.grid_size) + selection_node.big_bounding_rectangle.position = prev_pos.snapped(Global.grids[0].grid_size) selection_node.marching_ants_outline.offset += Vector2( selection_node.big_bounding_rectangle.position - prev_pos ) - pos = pos.snapped(Global.grid_size) - var grid_offset := Global.grid_offset + pos = pos.snapped(Global.grids[0].grid_size) + var grid_offset := Global.grids[0].grid_offset grid_offset = Vector2i( - fmod(grid_offset.x, Global.grid_size.x), fmod(grid_offset.y, Global.grid_size.y) + fmod(grid_offset.x, Global.grids[0].grid_size.x), + fmod(grid_offset.y, Global.grids[0].grid_size.y) ) pos += grid_offset diff --git a/src/Tools/BaseTool.gd b/src/Tools/BaseTool.gd index b3d93064c..27fbf48e3 100644 --- a/src/Tools/BaseTool.gd +++ b/src/Tools/BaseTool.gd @@ -129,19 +129,20 @@ func draw_preview() -> void: func snap_position(pos: Vector2) -> Vector2: var snapping_distance := Global.snapping_distance / Global.camera.zoom.x if Global.snap_to_rectangular_grid_boundary: - var grid_pos := pos.snapped(Global.grid_size) - grid_pos += Vector2(Global.grid_offset) + var grid_pos := pos.snapped(Global.grids[0].grid_size) + grid_pos += Vector2(Global.grids[0].grid_offset) # keeping grid_pos as is would have been fine but this adds extra accuracy as to # which snap point (from the list below) is closest to mouse and occupy THAT point - var t_l := grid_pos + Vector2(-Global.grid_size.x, -Global.grid_size.y) - var t_c := grid_pos + Vector2(0, -Global.grid_size.y) # t_c is for "top centre" and so on - var t_r := grid_pos + Vector2(Global.grid_size.x, -Global.grid_size.y) - var m_l := grid_pos + Vector2(-Global.grid_size.x, 0) + # t_l is for "top left" and so on + var t_l := grid_pos + Vector2(-Global.grids[0].grid_size.x, -Global.grids[0].grid_size.y) + var t_c := grid_pos + Vector2(0, -Global.grids[0].grid_size.y) + var t_r := grid_pos + Vector2(Global.grids[0].grid_size.x, -Global.grids[0].grid_size.y) + var m_l := grid_pos + Vector2(-Global.grids[0].grid_size.x, 0) var m_c := grid_pos - var m_r := grid_pos + Vector2(Global.grid_size.x, 0) - var b_l := grid_pos + Vector2(-Global.grid_size.x, Global.grid_size.y) - var b_c := grid_pos + Vector2(0, Global.grid_size.y) - var b_r := grid_pos + Vector2(Global.grid_size) + var m_r := grid_pos + Vector2(Global.grids[0].grid_size.x, 0) + var b_l := grid_pos + Vector2(-Global.grids[0].grid_size.x, Global.grids[0].grid_size.y) + var b_c := grid_pos + Vector2(0, Global.grids[0].grid_size.y) + var b_r := grid_pos + Vector2(Global.grids[0].grid_size) var vec_arr: PackedVector2Array = [t_l, t_c, t_r, m_l, m_c, m_r, b_l, b_c, b_r] for vec in vec_arr: if vec.distance_to(pos) < grid_pos.distance_to(pos): @@ -152,19 +153,22 @@ func snap_position(pos: Vector2) -> Vector2: pos = grid_point.floor() if Global.snap_to_rectangular_grid_center: - var grid_center := pos.snapped(Global.grid_size) + Vector2(Global.grid_size / 2) - grid_center += Vector2(Global.grid_offset) + var grid_center := ( + pos.snapped(Global.grids[0].grid_size) + Vector2(Global.grids[0].grid_size / 2) + ) + grid_center += Vector2(Global.grids[0].grid_offset) # keeping grid_center as is would have been fine but this adds extra accuracy as to # which snap point (from the list below) is closest to mouse and occupy THAT point - var t_l := grid_center + Vector2(-Global.grid_size.x, -Global.grid_size.y) - var t_c := grid_center + Vector2(0, -Global.grid_size.y) # t_c is for "top centre" and so on - var t_r := grid_center + Vector2(Global.grid_size.x, -Global.grid_size.y) - var m_l := grid_center + Vector2(-Global.grid_size.x, 0) + # t_l is for "top left" and so on + var t_l := grid_center + Vector2(-Global.grids[0].grid_size.x, -Global.grids[0].grid_size.y) + var t_c := grid_center + Vector2(0, -Global.grids[0].grid_size.y) + var t_r := grid_center + Vector2(Global.grids[0].grid_size.x, -Global.grids[0].grid_size.y) + var m_l := grid_center + Vector2(-Global.grids[0].grid_size.x, 0) var m_c := grid_center - var m_r := grid_center + Vector2(Global.grid_size.x, 0) - var b_l := grid_center + Vector2(-Global.grid_size.x, Global.grid_size.y) - var b_c := grid_center + Vector2(0, Global.grid_size.y) - var b_r := grid_center + Vector2(Global.grid_size) + var m_r := grid_center + Vector2(Global.grids[0].grid_size.x, 0) + var b_l := grid_center + Vector2(-Global.grids[0].grid_size.x, Global.grids[0].grid_size.y) + var b_c := grid_center + Vector2(0, Global.grids[0].grid_size.y) + var b_r := grid_center + Vector2(Global.grids[0].grid_size) var vec_arr := [t_l, t_c, t_r, m_l, m_c, m_r, b_l, b_c, b_r] for vec in vec_arr: if vec.distance_to(pos) < grid_center.distance_to(pos): diff --git a/src/Tools/UtilityTools/Move.gd b/src/Tools/UtilityTools/Move.gd index 76a53e523..247ab85de 100644 --- a/src/Tools/UtilityTools/Move.gd +++ b/src/Tools/UtilityTools/Move.gd @@ -16,17 +16,17 @@ func _input(event: InputEvent) -> void: return if event.is_action_pressed("transform_snap_grid"): _snap_to_grid = true - _offset = _offset.snapped(Global.grid_size) + _offset = _offset.snapped(Global.grids[0].grid_size) if Global.current_project.has_selection and selection_node.is_moving_content: var prev_pos: Vector2i = selection_node.big_bounding_rectangle.position selection_node.big_bounding_rectangle.position = Vector2i( - prev_pos.snapped(Global.grid_size) + prev_pos.snapped(Global.grids[0].grid_size) ) # The first time transform_snap_grid is enabled then _snap_position() is not called # and the selection had wrong offset, so do selection offsetting here var grid_offset := Vector2i( - fmod(Global.grid_offset.x, Global.grid_size.x), - fmod(Global.grid_offset.y, Global.grid_size.y) + fmod(Global.grids[0].grid_offset.x, Global.grids[0].grid_size.x), + fmod(Global.grids[0].grid_offset.y, Global.grids[0].grid_size.y) ) selection_node.big_bounding_rectangle.position += grid_offset selection_node.marching_ants_outline.offset += Vector2( @@ -110,16 +110,18 @@ func _snap_position(pos: Vector2) -> Vector2: else: pos.x = _start_pos.x if _snap_to_grid: # Snap to grid - pos = pos.snapped(Global.grid_size) + pos = pos.snapped(Global.grids[0].grid_size) # The part below only corrects the offset for situations when there is no selection # Offsets when there is selection is controlled in _input() function if !Global.current_project.has_selection: var move_offset := Vector2.ZERO move_offset.x = ( - _start_pos.x - (_start_pos.x / Global.grid_size.x) * Global.grid_size.x + _start_pos.x + - (_start_pos.x / Global.grids[0].grid_size.x) * Global.grids[0].grid_size.x ) move_offset.y = ( - _start_pos.y - (_start_pos.y / Global.grid_size.y) * Global.grid_size.y + _start_pos.y + - (_start_pos.y / Global.grids[0].grid_size.y) * Global.grids[0].grid_size.y ) pos += move_offset diff --git a/src/UI/Canvas/Grid.gd b/src/UI/Canvas/Grid.gd index 123c1bafe..7090bbd60 100644 --- a/src/UI/Canvas/Grid.gd +++ b/src/UI/Canvas/Grid.gd @@ -1,5 +1,8 @@ extends Node2D +var unique_rect_lines := PackedVector2Array() +var unique_iso_lines := PackedVector2Array() + func _ready() -> void: Global.project_switched.connect(queue_redraw) @@ -10,54 +13,60 @@ func _draw() -> void: return var target_rect: Rect2i - if Global.grid_draw_over_tile_mode: - target_rect = Global.current_project.tiles.get_bounding_rect() - else: - target_rect = Rect2i(Vector2i.ZERO, Global.current_project.size) - if not target_rect.has_area(): - return + unique_rect_lines.clear() + unique_iso_lines.clear() + for grid_idx in range(Global.grids.size() - 1, -1, -1): + if Global.grids[grid_idx].grid_draw_over_tile_mode: + target_rect = Global.current_project.tiles.get_bounding_rect() + else: + target_rect = Rect2i(Vector2i.ZERO, Global.current_project.size) + if not target_rect.has_area(): + return - var grid_type := Global.grid_type - if grid_type == Global.GridTypes.CARTESIAN || grid_type == Global.GridTypes.ALL: - _draw_cartesian_grid(target_rect) + var grid_type := Global.grids[grid_idx].grid_type + if grid_type == Global.GridTypes.CARTESIAN || grid_type == Global.GridTypes.ALL: + _draw_cartesian_grid(grid_idx, target_rect) - if grid_type == Global.GridTypes.ISOMETRIC || grid_type == Global.GridTypes.ALL: - _draw_isometric_grid(target_rect) + if grid_type == Global.GridTypes.ISOMETRIC || grid_type == Global.GridTypes.ALL: + _draw_isometric_grid(grid_idx, target_rect) -func _draw_cartesian_grid(target_rect: Rect2i) -> void: +func _draw_cartesian_grid(grid_index: int, target_rect: Rect2i) -> void: + var grid = Global.grids[grid_index] var grid_multiline_points := PackedVector2Array() var x: float = ( target_rect.position.x - + fposmod(Global.grid_offset.x - target_rect.position.x, Global.grid_size.x) + + fposmod(grid.grid_offset.x - target_rect.position.x, grid.grid_size.x) ) while x <= target_rect.end.x: - grid_multiline_points.push_back(Vector2(x, target_rect.position.y)) - grid_multiline_points.push_back(Vector2(x, target_rect.end.y)) - x += Global.grid_size.x + if not Vector2(x, target_rect.position.y) in unique_rect_lines: + grid_multiline_points.push_back(Vector2(x, target_rect.position.y)) + grid_multiline_points.push_back(Vector2(x, target_rect.end.y)) + x += grid.grid_size.x var y: float = ( target_rect.position.y - + fposmod(Global.grid_offset.y - target_rect.position.y, Global.grid_size.y) + + fposmod(grid.grid_offset.y - target_rect.position.y, grid.grid_size.y) ) while y <= target_rect.end.y: - grid_multiline_points.push_back(Vector2(target_rect.position.x, y)) - grid_multiline_points.push_back(Vector2(target_rect.end.x, y)) - y += Global.grid_size.y + if not Vector2(target_rect.position.x, y) in unique_rect_lines: + grid_multiline_points.push_back(Vector2(target_rect.position.x, y)) + grid_multiline_points.push_back(Vector2(target_rect.end.x, y)) + y += grid.grid_size.y + unique_rect_lines.append_array(grid_multiline_points) if not grid_multiline_points.is_empty(): - draw_multiline(grid_multiline_points, Global.grid_color) + draw_multiline(grid_multiline_points, grid.grid_color) -func _draw_isometric_grid(target_rect: Rect2i) -> void: +func _draw_isometric_grid(grid_index: int, target_rect: Rect2i) -> void: + var grid = Global.grids[grid_index] var grid_multiline_points := PackedVector2Array() - var cell_size: Vector2 = Global.isometric_grid_size + var cell_size: Vector2 = grid.isometric_grid_size var max_cell_count: Vector2 = Vector2(target_rect.size) / cell_size - var origin_offset: Vector2 = Vector2(Global.grid_offset - target_rect.position).posmodv( - cell_size - ) + var origin_offset: Vector2 = Vector2(grid.grid_offset - target_rect.position).posmodv(cell_size) # lines ↗↗↗ (from bottom-left to top-right) var per_cell_offset: Vector2 = cell_size * Vector2(1, -1) @@ -70,8 +79,9 @@ func _draw_isometric_grid(target_rect: Rect2i) -> void: var start: Vector2 = Vector2(target_rect.position) + Vector2(0, y) var cells_to_rect_bounds: float = minf(max_cell_count.x, y / cell_size.y) var end := start + cells_to_rect_bounds * per_cell_offset - grid_multiline_points.push_back(start) - grid_multiline_points.push_back(end) + if not start in unique_iso_lines: + grid_multiline_points.push_back(start) + grid_multiline_points.push_back(end) y += cell_size.y # lines ↗↗↗ starting from the rect's bottom side (left to right): @@ -80,8 +90,9 @@ func _draw_isometric_grid(target_rect: Rect2i) -> void: var start: Vector2 = Vector2(target_rect.position) + Vector2(x, target_rect.size.y) var cells_to_rect_bounds: float = minf(max_cell_count.y, max_cell_count.x - x / cell_size.x) var end: Vector2 = start + cells_to_rect_bounds * per_cell_offset - grid_multiline_points.push_back(start) - grid_multiline_points.push_back(end) + if not start in unique_iso_lines: + grid_multiline_points.push_back(start) + grid_multiline_points.push_back(end) x += cell_size.x # lines ↘↘↘ (from top-left to bottom-right) @@ -93,8 +104,9 @@ func _draw_isometric_grid(target_rect: Rect2i) -> void: var start: Vector2 = Vector2(target_rect.position) + Vector2(0, y) var cells_to_rect_bounds: float = minf(max_cell_count.x, max_cell_count.y - y / cell_size.y) var end: Vector2 = start + cells_to_rect_bounds * per_cell_offset - grid_multiline_points.push_back(start) - grid_multiline_points.push_back(end) + if not start in unique_iso_lines: + grid_multiline_points.push_back(start) + grid_multiline_points.push_back(end) y += cell_size.y # lines ↘↘↘ starting from the rect's top side (left to right): @@ -103,9 +115,11 @@ func _draw_isometric_grid(target_rect: Rect2i) -> void: var start: Vector2 = Vector2(target_rect.position) + Vector2(x, 0) var cells_to_rect_bounds: float = minf(max_cell_count.y, max_cell_count.x - x / cell_size.x) var end: Vector2 = start + cells_to_rect_bounds * per_cell_offset - grid_multiline_points.push_back(start) - grid_multiline_points.push_back(end) + if not start in unique_iso_lines: + grid_multiline_points.push_back(start) + grid_multiline_points.push_back(end) x += cell_size.x + grid_multiline_points.append_array(grid_multiline_points) if not grid_multiline_points.is_empty(): - draw_multiline(grid_multiline_points, Global.grid_color) + draw_multiline(grid_multiline_points, grid.grid_color) diff --git a/src/UI/Canvas/Selection.gd b/src/UI/Canvas/Selection.gd index 1301d1e4e..f28fd7cd7 100644 --- a/src/UI/Canvas/Selection.gd +++ b/src/UI/Canvas/Selection.gd @@ -214,7 +214,7 @@ func _move_with_arrow_keys(event: InputEvent) -> void: if _is_action_direction(event) and arrow_key_move: var step := Vector2.ONE if Input.is_key_pressed(KEY_CTRL): - step = Global.grid_size + step = Global.grids[0].grid_size var input := Input.get_vector("ui_left", "ui_right", "ui_up", "ui_down") var move := input.rotated(snappedf(Global.camera.rotation, PI / 2)) # These checks are needed to fix a bug where the selection got stuck