mirror of
				https://github.com/JHDev2006/Super-Mario-Bros.-Remastered-Public.git
				synced 2025-11-04 08:35:41 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			940 lines
		
	
	
		
			33 KiB
		
	
	
	
		
			GDScript
		
	
	
		
			Executable File
		
	
	
	
	
			
		
		
	
	
			940 lines
		
	
	
		
			33 KiB
		
	
	
	
		
			GDScript
		
	
	
		
			Executable File
		
	
	
	
	
@tool
 | 
						|
extends Control
 | 
						|
 | 
						|
signal update_overlay
 | 
						|
signal force_show_terrains
 | 
						|
 | 
						|
# The maximum individual tiles the overlay will draw before shortcutting the display
 | 
						|
# To prevent editor lag when drawing large rectangles or filling large areas
 | 
						|
const MAX_CANVAS_RENDER_TILES = 1500
 | 
						|
const TERRAIN_PROPERTIES_SCENE := preload("res://addons/better-terrain/editor/TerrainProperties.tscn")
 | 
						|
const TERRAIN_ENTRY_SCENE := preload("res://addons/better-terrain/editor/TerrainEntry.tscn")
 | 
						|
const MIN_ZOOM_SETTING := "editor/better_terrain/min_zoom_amount"
 | 
						|
const MAX_ZOOM_SETTING := "editor/better_terrain/max_zoom_amount"
 | 
						|
 | 
						|
 | 
						|
# Buttons
 | 
						|
@onready var draw_button: Button = $VBox/Toolbar/Draw
 | 
						|
@onready var line_button: Button = $VBox/Toolbar/Line
 | 
						|
@onready var rectangle_button: Button = $VBox/Toolbar/Rectangle
 | 
						|
@onready var fill_button: Button = $VBox/Toolbar/Fill
 | 
						|
@onready var replace_button: Button = $VBox/Toolbar/Replace
 | 
						|
 | 
						|
@onready var paint_type: Button = $VBox/Toolbar/PaintType
 | 
						|
@onready var paint_terrain: Button = $VBox/Toolbar/PaintTerrain
 | 
						|
@onready var select_tiles: Button = $VBox/Toolbar/SelectTiles
 | 
						|
 | 
						|
@onready var paint_symmetry: Button = $VBox/Toolbar/PaintSymmetry
 | 
						|
@onready var symmetry_options: OptionButton = $VBox/Toolbar/SymmetryOptions
 | 
						|
 | 
						|
@onready var shuffle_random: Button = $VBox/Toolbar/ShuffleRandom
 | 
						|
@onready var zoom_slider_container: VBoxContainer = $VBox/Toolbar/ZoomContainer
 | 
						|
 | 
						|
@onready var source_selector: MenuBar = $VBox/Toolbar/Sources
 | 
						|
@onready var source_selector_popup: PopupMenu = $VBox/Toolbar/Sources/Sources
 | 
						|
 | 
						|
@onready var clean_button: Button = $VBox/Toolbar/Clean
 | 
						|
@onready var layer_up: Button = $VBox/Toolbar/LayerUp
 | 
						|
@onready var layer_down: Button = $VBox/Toolbar/LayerDown
 | 
						|
@onready var layer_highlight: Button = $VBox/Toolbar/LayerHighlight
 | 
						|
@onready var layer_grid: Button = $VBox/Toolbar/LayerGrid
 | 
						|
 | 
						|
@onready var grid_mode_button: Button = $VBox/HSplit/Terrains/LowerToolbar/GridMode
 | 
						|
@onready var quick_mode_button: Button = $VBox/HSplit/Terrains/LowerToolbar/QuickMode
 | 
						|
 | 
						|
@onready var edit_tool_buttons: HBoxContainer = $VBox/HSplit/Terrains/LowerToolbar/EditTools
 | 
						|
@onready var add_terrain_button: Button = $VBox/HSplit/Terrains/LowerToolbar/EditTools/AddTerrain
 | 
						|
@onready var edit_terrain_button: Button = $VBox/HSplit/Terrains/LowerToolbar/EditTools/EditTerrain
 | 
						|
@onready var pick_icon_button: Button = $VBox/HSplit/Terrains/LowerToolbar/EditTools/PickIcon
 | 
						|
@onready var move_up_button: Button = $VBox/HSplit/Terrains/LowerToolbar/EditTools/MoveUp
 | 
						|
@onready var move_down_button: Button = $VBox/HSplit/Terrains/LowerToolbar/EditTools/MoveDown
 | 
						|
@onready var remove_terrain_button: Button = $VBox/HSplit/Terrains/LowerToolbar/EditTools/RemoveTerrain
 | 
						|
 | 
						|
@onready var scroll_container: ScrollContainer = $VBox/HSplit/Terrains/Panel/ScrollContainer
 | 
						|
@onready var terrain_list: HFlowContainer = $VBox/HSplit/Terrains/Panel/ScrollContainer/TerrainList
 | 
						|
@onready var tile_view: Control = $VBox/HSplit/Panel/ScrollArea/TileView
 | 
						|
 | 
						|
 | 
						|
var selected_entry := -2
 | 
						|
 | 
						|
var tilemap : TileMapLayer
 | 
						|
var tileset : TileSet
 | 
						|
 | 
						|
var undo_manager : EditorUndoRedoManager
 | 
						|
var terrain_undo
 | 
						|
 | 
						|
var draw_overlay := false
 | 
						|
var initial_click : Vector2i
 | 
						|
var prev_position : Vector2i
 | 
						|
var current_position : Vector2i
 | 
						|
var tileset_dirty := false
 | 
						|
var zoom_slider : HSlider
 | 
						|
 | 
						|
enum PaintMode {
 | 
						|
	NO_PAINT,
 | 
						|
	PAINT,
 | 
						|
	ERASE
 | 
						|
}
 | 
						|
 | 
						|
enum PaintAction {
 | 
						|
	NO_ACTION,
 | 
						|
	LINE,
 | 
						|
	RECT
 | 
						|
}
 | 
						|
 | 
						|
enum SourceSelectors {
 | 
						|
	ALL = 1000000,
 | 
						|
	NONE = 1000001,
 | 
						|
}
 | 
						|
 | 
						|
var paint_mode := PaintMode.NO_PAINT
 | 
						|
 | 
						|
var paint_action := PaintAction.NO_ACTION
 | 
						|
 | 
						|
 | 
						|
# Called when the node enters the scene tree for the first time.
 | 
						|
func _ready() -> void:
 | 
						|
	draw_button.icon = get_theme_icon("Edit", "EditorIcons")
 | 
						|
	line_button.icon = get_theme_icon("Line", "EditorIcons")
 | 
						|
	rectangle_button.icon = get_theme_icon("Rectangle", "EditorIcons")
 | 
						|
	fill_button.icon = get_theme_icon("Bucket", "EditorIcons")
 | 
						|
	select_tiles.icon = get_theme_icon("ToolSelect", "EditorIcons")
 | 
						|
	add_terrain_button.icon = get_theme_icon("Add", "EditorIcons")
 | 
						|
	edit_terrain_button.icon = get_theme_icon("Tools", "EditorIcons")
 | 
						|
	pick_icon_button.icon = get_theme_icon("ColorPick", "EditorIcons")
 | 
						|
	move_up_button.icon = get_theme_icon("ArrowUp", "EditorIcons")
 | 
						|
	move_down_button.icon = get_theme_icon("ArrowDown", "EditorIcons")
 | 
						|
	remove_terrain_button.icon = get_theme_icon("Remove", "EditorIcons")
 | 
						|
	grid_mode_button.icon = get_theme_icon("FileThumbnail", "EditorIcons")
 | 
						|
	quick_mode_button.icon = get_theme_icon("GuiVisibilityVisible", "EditorIcons")
 | 
						|
	layer_up.icon = get_theme_icon("MoveUp", "EditorIcons")
 | 
						|
	layer_down.icon = get_theme_icon("MoveDown", "EditorIcons")
 | 
						|
	layer_highlight.icon = get_theme_icon("TileMapHighlightSelected", "EditorIcons")
 | 
						|
	layer_grid.icon = get_theme_icon("Grid", "EditorIcons")
 | 
						|
	
 | 
						|
	select_tiles.button_group.pressed.connect(_on_bit_button_pressed)
 | 
						|
	
 | 
						|
	terrain_undo = load("res://addons/better-terrain/editor/TerrainUndo.gd").new()
 | 
						|
	add_child(terrain_undo)
 | 
						|
	tile_view.undo_manager = undo_manager
 | 
						|
	tile_view.terrain_undo = terrain_undo
 | 
						|
	
 | 
						|
	tile_view.paste_occurred.connect(_on_paste_occurred)
 | 
						|
	tile_view.change_zoom_level.connect(_on_change_zoom_level)
 | 
						|
	tile_view.terrain_updated.connect(_on_terrain_updated)
 | 
						|
	
 | 
						|
	# Zoom slider is manipulated by settings, make it at runtime
 | 
						|
	zoom_slider = HSlider.new()
 | 
						|
	zoom_slider.custom_minimum_size = Vector2(100, 0)
 | 
						|
	zoom_slider.value_changed.connect(tile_view._on_zoom_value_changed)
 | 
						|
	zoom_slider_container.add_child(zoom_slider)
 | 
						|
	
 | 
						|
	# Init settings if needed
 | 
						|
	if !ProjectSettings.has_setting(MIN_ZOOM_SETTING):
 | 
						|
		ProjectSettings.set(MIN_ZOOM_SETTING, 1.0)
 | 
						|
	ProjectSettings.add_property_info({
 | 
						|
		"name": MIN_ZOOM_SETTING,
 | 
						|
		"type": TYPE_FLOAT,
 | 
						|
		"hint": PROPERTY_HINT_RANGE,
 | 
						|
		"hint_string": "0.1,1.0,0.1"
 | 
						|
	})
 | 
						|
	ProjectSettings.set_initial_value(MIN_ZOOM_SETTING, 1.0)
 | 
						|
	ProjectSettings.set_as_basic(MIN_ZOOM_SETTING, true)
 | 
						|
	
 | 
						|
	if !ProjectSettings.has_setting(MAX_ZOOM_SETTING):
 | 
						|
		ProjectSettings.set(MAX_ZOOM_SETTING, 8.0)
 | 
						|
	ProjectSettings.add_property_info({
 | 
						|
		"name": MAX_ZOOM_SETTING,
 | 
						|
		"type": TYPE_FLOAT,
 | 
						|
		"hint": PROPERTY_HINT_RANGE,
 | 
						|
		"hint_string": "2.0,32.0,1.0"
 | 
						|
	})
 | 
						|
	ProjectSettings.set_initial_value(MAX_ZOOM_SETTING, 8.0)
 | 
						|
	ProjectSettings.set_as_basic(MAX_ZOOM_SETTING, true)
 | 
						|
	ProjectSettings.set_order(MAX_ZOOM_SETTING, ProjectSettings.get_order(MIN_ZOOM_SETTING) + 1)
 | 
						|
	
 | 
						|
	ProjectSettings.settings_changed.connect(_on_adjust_settings)
 | 
						|
	_on_adjust_settings()
 | 
						|
	zoom_slider.value = 1.0
 | 
						|
 | 
						|
 | 
						|
func _process(delta):
 | 
						|
	scroll_container.scroll_horizontal = 0
 | 
						|
 | 
						|
 | 
						|
func _on_adjust_settings():
 | 
						|
	zoom_slider.min_value = ProjectSettings.get_setting(MIN_ZOOM_SETTING, 1.0)
 | 
						|
	zoom_slider.max_value = ProjectSettings.get_setting(MAX_ZOOM_SETTING, 8.0)
 | 
						|
	zoom_slider.step = (zoom_slider.max_value - zoom_slider.min_value) / 100.0
 | 
						|
 | 
						|
 | 
						|
func _get_fill_cells(target: Vector2i) -> Array:
 | 
						|
	var pick := BetterTerrain.get_cell(tilemap, target)
 | 
						|
	var bounds := tilemap.get_used_rect()
 | 
						|
	var neighbors = BetterTerrain.data.cells_adjacent_for_fill(tileset)
 | 
						|
	
 | 
						|
	# No sets yet, so use a dictionary
 | 
						|
	var checked := {}
 | 
						|
	var pending := [target]
 | 
						|
	var goal := []
 | 
						|
	
 | 
						|
	while !pending.is_empty():
 | 
						|
		var p = pending.pop_front()
 | 
						|
		if checked.has(p):
 | 
						|
			continue
 | 
						|
		checked[p] = true
 | 
						|
		if !bounds.has_point(p) or BetterTerrain.get_cell(tilemap, p) != pick:
 | 
						|
			continue
 | 
						|
		
 | 
						|
		goal.append(p)
 | 
						|
		pending.append_array(BetterTerrain.data.neighboring_coords(tilemap, p, neighbors))
 | 
						|
	
 | 
						|
	return goal
 | 
						|
 | 
						|
 | 
						|
func tiles_about_to_change() -> void:
 | 
						|
	if tileset and tileset.changed.is_connected(queue_tiles_changed):
 | 
						|
		tileset.changed.disconnect(queue_tiles_changed)
 | 
						|
 | 
						|
 | 
						|
func tiles_changed() -> void:
 | 
						|
	# ensure up to date
 | 
						|
	BetterTerrain._update_terrain_data(tileset)
 | 
						|
	
 | 
						|
	# clear terrains
 | 
						|
	for c in terrain_list.get_children():
 | 
						|
		terrain_list.remove_child(c)
 | 
						|
		c.queue_free()
 | 
						|
	
 | 
						|
	# load terrains from tileset
 | 
						|
	var terrain_count := BetterTerrain.terrain_count(tileset)
 | 
						|
	var item_count = terrain_count + 1
 | 
						|
	for i in terrain_count:
 | 
						|
		var terrain := BetterTerrain.get_terrain(tileset, i)
 | 
						|
		if i >= terrain_list.get_child_count():
 | 
						|
			add_terrain_entry(terrain, i)
 | 
						|
	
 | 
						|
	if item_count > terrain_list.get_child_count():
 | 
						|
		var terrain := BetterTerrain.get_terrain(tileset, BetterTerrain.TileCategory.EMPTY)
 | 
						|
		if terrain.valid:
 | 
						|
			add_terrain_entry(terrain, item_count - 1)
 | 
						|
	
 | 
						|
	while item_count < terrain_list.get_child_count():
 | 
						|
		var child = terrain_list.get_child(terrain_list.get_child_count() - 1)
 | 
						|
		terrain_list.remove_child(child)
 | 
						|
		child.free()
 | 
						|
	
 | 
						|
	source_selector_popup.clear()
 | 
						|
	source_selector_popup.add_item("All", SourceSelectors.ALL)
 | 
						|
	source_selector_popup.add_item("None", SourceSelectors.NONE)
 | 
						|
	var source_count = tileset.get_source_count() if tileset else 0
 | 
						|
	for s in source_count:
 | 
						|
		var source_id = tileset.get_source_id(s)
 | 
						|
		var source := tileset.get_source(source_id)
 | 
						|
		if !(source is TileSetAtlasSource):
 | 
						|
			continue
 | 
						|
		
 | 
						|
		var name := source.resource_name
 | 
						|
		if name.is_empty():
 | 
						|
			var texture := (source as TileSetAtlasSource).texture
 | 
						|
			var texture_name := texture.resource_name if texture else ""
 | 
						|
			if !texture_name.is_empty():
 | 
						|
				name = texture_name
 | 
						|
			else:
 | 
						|
				var texture_path := texture.resource_path if texture else ""
 | 
						|
				if !texture_path.is_empty():
 | 
						|
					name = texture_path.get_file()
 | 
						|
		
 | 
						|
		if !name.is_empty():
 | 
						|
			name += " "
 | 
						|
		name += " (ID: %d)" % source_id
 | 
						|
		
 | 
						|
		source_selector_popup.add_check_item(name, source_id)
 | 
						|
		source_selector_popup.set_item_checked(source_selector_popup.get_item_index(source_id), true)
 | 
						|
	source_selector.visible = source_selector_popup.item_count > 3 # All, None and more than one source
 | 
						|
	
 | 
						|
	update_tile_view_paint()
 | 
						|
	tile_view.refresh_tileset(tileset)
 | 
						|
	
 | 
						|
	if tileset and !tileset.changed.is_connected(queue_tiles_changed):
 | 
						|
		tileset.changed.connect(queue_tiles_changed)
 | 
						|
	
 | 
						|
	clean_button.visible = BetterTerrain._has_invalid_peering_types(tileset)
 | 
						|
	
 | 
						|
	tileset_dirty = false
 | 
						|
	_on_grid_mode_pressed()
 | 
						|
	_on_quick_mode_pressed()
 | 
						|
 | 
						|
 | 
						|
func about_to_be_visible(visible: bool) -> void:
 | 
						|
	if !visible:
 | 
						|
		return
 | 
						|
	
 | 
						|
	if tileset != tilemap.tile_set:
 | 
						|
		tiles_about_to_change()
 | 
						|
		tileset = tilemap.tile_set
 | 
						|
		tiles_changed()
 | 
						|
	
 | 
						|
	var settings := EditorInterface.get_editor_settings()
 | 
						|
	layer_highlight.set_pressed_no_signal(settings.get_setting("editors/tiles_editor/highlight_selected_layer"))
 | 
						|
	layer_grid.set_pressed_no_signal(settings.get_setting("editors/tiles_editor/display_grid"))
 | 
						|
 | 
						|
 | 
						|
func queue_tiles_changed() -> void:
 | 
						|
	# Bring terrain data up to date with complex tileset changes
 | 
						|
	if !tileset or tileset_dirty:
 | 
						|
		return
 | 
						|
	
 | 
						|
	tileset_dirty = true
 | 
						|
	tiles_changed.call_deferred()
 | 
						|
 | 
						|
 | 
						|
func _on_entry_select(index:int):
 | 
						|
	selected_entry = index
 | 
						|
	if selected_entry >= BetterTerrain.terrain_count(tileset):
 | 
						|
		selected_entry = BetterTerrain.TileCategory.EMPTY
 | 
						|
	for i in range(terrain_list.get_child_count()):
 | 
						|
		if i != index:
 | 
						|
			terrain_list.get_child(i).set_selected(false)
 | 
						|
	update_tile_view_paint()
 | 
						|
 | 
						|
 | 
						|
func _on_clean_pressed() -> void:
 | 
						|
	var confirmed := [false]
 | 
						|
	var popup := ConfirmationDialog.new()
 | 
						|
	popup.dialog_text = tr("Tile set changes have caused terrain to become invalid. Remove invalid terrain data?")
 | 
						|
	popup.dialog_hide_on_ok = false
 | 
						|
	popup.confirmed.connect(func():
 | 
						|
		confirmed[0] = true
 | 
						|
		popup.hide()
 | 
						|
	)
 | 
						|
	EditorInterface.popup_dialog_centered(popup)
 | 
						|
	await popup.visibility_changed
 | 
						|
	popup.queue_free()
 | 
						|
	
 | 
						|
	if confirmed[0]:
 | 
						|
		undo_manager.create_action("Clean invalid terrain peering data", UndoRedo.MERGE_DISABLE, tileset)
 | 
						|
		undo_manager.add_do_method(BetterTerrain, &"_clear_invalid_peering_types", tileset)
 | 
						|
		undo_manager.add_do_method(self, &"tiles_changed")
 | 
						|
		terrain_undo.create_peering_restore_point(undo_manager, tileset)
 | 
						|
		undo_manager.add_undo_method(self, &"tiles_changed")
 | 
						|
		undo_manager.commit_action()
 | 
						|
 | 
						|
 | 
						|
func _on_grid_mode_pressed() -> void:
 | 
						|
	for c in terrain_list.get_children():
 | 
						|
		c.grid_mode = grid_mode_button.button_pressed
 | 
						|
		c.update_style()
 | 
						|
 | 
						|
 | 
						|
func _on_quick_mode_pressed() -> void:
 | 
						|
	edit_tool_buttons.visible = !quick_mode_button.button_pressed
 | 
						|
	for c in terrain_list.get_children():
 | 
						|
		c.visible = !quick_mode_button.button_pressed or c.terrain.type in [BetterTerrain.TerrainType.MATCH_TILES, BetterTerrain.TerrainType.MATCH_VERTICES]
 | 
						|
 | 
						|
 | 
						|
func update_tile_view_paint() -> void:
 | 
						|
	tile_view.paint = selected_entry
 | 
						|
	tile_view.queue_redraw()
 | 
						|
	
 | 
						|
	var editable = tile_view.paint != BetterTerrain.TileCategory.EMPTY
 | 
						|
	edit_terrain_button.disabled = !editable
 | 
						|
	move_up_button.disabled = !editable or tile_view.paint == 0
 | 
						|
	move_down_button.disabled = !editable or tile_view.paint == BetterTerrain.terrain_count(tileset) - 1
 | 
						|
	remove_terrain_button.disabled = !editable
 | 
						|
	pick_icon_button.disabled = !editable
 | 
						|
 | 
						|
 | 
						|
func _on_add_terrain_pressed() -> void:
 | 
						|
	if !tileset:
 | 
						|
		return
 | 
						|
	
 | 
						|
	var popup := TERRAIN_PROPERTIES_SCENE.instantiate()
 | 
						|
	popup.set_category_data(BetterTerrain.get_terrain_categories(tileset))
 | 
						|
	popup.terrain_name = "New terrain"
 | 
						|
	popup.terrain_color = Color.from_hsv(randf(), 0.3 + 0.7 * randf(), 0.6 + 0.4 * randf())
 | 
						|
	popup.terrain_icon = ""
 | 
						|
	popup.terrain_type = 0
 | 
						|
	EditorInterface.popup_dialog_centered(popup)
 | 
						|
	await popup.visibility_changed
 | 
						|
	if popup.accepted:
 | 
						|
		undo_manager.create_action("Add terrain type", UndoRedo.MERGE_DISABLE, tileset)
 | 
						|
		undo_manager.add_do_method(self, &"perform_add_terrain", popup.terrain_name, popup.terrain_color, popup.terrain_type, popup.terrain_categories, {path = popup.terrain_icon})
 | 
						|
		undo_manager.add_undo_method(self, &"perform_remove_terrain", terrain_list.get_child_count() - 1)
 | 
						|
		undo_manager.commit_action()
 | 
						|
	popup.queue_free()
 | 
						|
 | 
						|
 | 
						|
func _on_edit_terrain_pressed() -> void:
 | 
						|
	if !tileset:
 | 
						|
		return
 | 
						|
	
 | 
						|
	if selected_entry < 0:
 | 
						|
		return
 | 
						|
	
 | 
						|
	var t := BetterTerrain.get_terrain(tileset, selected_entry)
 | 
						|
	var categories = BetterTerrain.get_terrain_categories(tileset)
 | 
						|
	categories = categories.filter(func(x): return x.id != selected_entry)
 | 
						|
	
 | 
						|
	var popup := TERRAIN_PROPERTIES_SCENE.instantiate()
 | 
						|
	popup.set_category_data(categories)
 | 
						|
	
 | 
						|
	t.icon = t.icon.duplicate()
 | 
						|
	
 | 
						|
	popup.terrain_name = t.name
 | 
						|
	popup.terrain_type = t.type
 | 
						|
	popup.terrain_color = t.color
 | 
						|
	if t.has("icon") and t.icon.has("path"):
 | 
						|
		popup.terrain_icon = t.icon.path
 | 
						|
	popup.terrain_categories = t.categories
 | 
						|
	EditorInterface.popup_dialog_centered(popup)
 | 
						|
	await popup.visibility_changed
 | 
						|
	if popup.accepted:
 | 
						|
		undo_manager.create_action("Edit terrain details", UndoRedo.MERGE_DISABLE, tileset)
 | 
						|
		undo_manager.add_do_method(self, &"perform_edit_terrain", selected_entry, popup.terrain_name, popup.terrain_color, popup.terrain_type, popup.terrain_categories, {path = popup.terrain_icon})
 | 
						|
		undo_manager.add_undo_method(self, &"perform_edit_terrain", selected_entry, t.name, t.color, t.type, t.categories, t.icon)
 | 
						|
		if t.type != popup.terrain_type:
 | 
						|
			terrain_undo.create_terrain_type_restore_point(undo_manager, tileset)
 | 
						|
			terrain_undo.create_peering_restore_point_specific(undo_manager, tileset, selected_entry)
 | 
						|
		undo_manager.commit_action()
 | 
						|
	popup.queue_free()
 | 
						|
 | 
						|
 | 
						|
func _on_pick_icon_pressed():
 | 
						|
	if selected_entry < 0:
 | 
						|
		return
 | 
						|
	tile_view.pick_icon_terrain = selected_entry
 | 
						|
 | 
						|
 | 
						|
func _on_pick_icon_focus_exited():
 | 
						|
	tile_view.pick_icon_terrain_cancel = true
 | 
						|
	pick_icon_button.button_pressed = false
 | 
						|
 | 
						|
 | 
						|
func _on_move_pressed(down: bool) -> void:
 | 
						|
	if !tileset:
 | 
						|
		return
 | 
						|
	
 | 
						|
	if selected_entry < 0:
 | 
						|
		return
 | 
						|
	
 | 
						|
	var index1 = selected_entry
 | 
						|
	var index2 = index1 + (1 if down else -1)
 | 
						|
	if index2 < 0 or index2 >= terrain_list.get_child_count():
 | 
						|
		return
 | 
						|
	
 | 
						|
	undo_manager.create_action("Reorder terrains", UndoRedo.MERGE_DISABLE, tileset)
 | 
						|
	undo_manager.add_do_method(self, &"perform_swap_terrain", index1, index2)
 | 
						|
	undo_manager.add_undo_method(self, &"perform_swap_terrain", index1, index2)
 | 
						|
	undo_manager.commit_action()
 | 
						|
 | 
						|
 | 
						|
func _on_remove_terrain_pressed() -> void:
 | 
						|
	if !tileset:
 | 
						|
		return
 | 
						|
	
 | 
						|
	if selected_entry < 0:
 | 
						|
		return
 | 
						|
	
 | 
						|
	# store confirmation in array to pass by ref
 | 
						|
	var t := BetterTerrain.get_terrain(tileset, selected_entry)
 | 
						|
	var confirmed := [false]
 | 
						|
	var popup := ConfirmationDialog.new()
 | 
						|
	popup.dialog_text = tr("Are you sure you want to remove {0}?").format([t.name])
 | 
						|
	popup.dialog_hide_on_ok = false
 | 
						|
	popup.confirmed.connect(func():
 | 
						|
		confirmed[0] = true
 | 
						|
		popup.hide()
 | 
						|
	)
 | 
						|
	EditorInterface.popup_dialog_centered(popup)
 | 
						|
	await popup.visibility_changed
 | 
						|
	popup.queue_free()
 | 
						|
	
 | 
						|
	if confirmed[0]:
 | 
						|
		undo_manager.create_action("Remove terrain type", UndoRedo.MERGE_DISABLE, tileset)
 | 
						|
		undo_manager.add_do_method(self, &"perform_remove_terrain", selected_entry)
 | 
						|
		undo_manager.add_undo_method(self, &"perform_add_terrain", t.name, t.color, t.type, t.categories, t.icon)
 | 
						|
		for n in range(terrain_list.get_child_count() - 2, selected_entry, -1):
 | 
						|
			undo_manager.add_undo_method(self, &"perform_swap_terrain", n, n - 1)
 | 
						|
		if t.type == BetterTerrain.TerrainType.CATEGORY:
 | 
						|
			terrain_undo.create_terrain_type_restore_point(undo_manager, tileset)
 | 
						|
		terrain_undo.create_peering_restore_point_specific(undo_manager, tileset, selected_entry)
 | 
						|
		undo_manager.commit_action()
 | 
						|
 | 
						|
 | 
						|
func add_terrain_entry(terrain:Dictionary, index:int = -1):
 | 
						|
	if index < 0:
 | 
						|
		index = terrain_list.get_child_count()
 | 
						|
	
 | 
						|
	var entry = TERRAIN_ENTRY_SCENE.instantiate()
 | 
						|
	entry.tileset = tileset
 | 
						|
	entry.terrain = terrain
 | 
						|
	entry.grid_mode = grid_mode_button.button_pressed
 | 
						|
	entry.select.connect(_on_entry_select)
 | 
						|
	
 | 
						|
	terrain_list.add_child(entry)
 | 
						|
	terrain_list.move_child(entry, index)
 | 
						|
 | 
						|
 | 
						|
func remove_terrain_entry(index: int):
 | 
						|
	terrain_list.get_child(index).free()
 | 
						|
	for i in range(index, terrain_list.get_child_count()):
 | 
						|
		var child = terrain_list.get_child(i)
 | 
						|
		child.terrain = BetterTerrain.get_terrain(tileset, i)
 | 
						|
		child.update()
 | 
						|
 | 
						|
 | 
						|
func perform_add_terrain(name: String, color: Color, type: int, categories: Array, icon:Dictionary = {}) -> void:
 | 
						|
	if BetterTerrain.add_terrain(tileset, name, color, type, categories, icon):
 | 
						|
		var index = BetterTerrain.terrain_count(tileset) - 1
 | 
						|
		var terrain = BetterTerrain.get_terrain(tileset, index)
 | 
						|
		add_terrain_entry(terrain, index)
 | 
						|
 | 
						|
 | 
						|
func perform_remove_terrain(index: int) -> void:
 | 
						|
	if index >= BetterTerrain.terrain_count(tileset):
 | 
						|
		return
 | 
						|
	if BetterTerrain.remove_terrain(tileset, index):
 | 
						|
		remove_terrain_entry(index)
 | 
						|
		update_tile_view_paint()
 | 
						|
 | 
						|
 | 
						|
func perform_swap_terrain(index1: int, index2: int) -> void:
 | 
						|
	var lower := min(index1, index2)
 | 
						|
	var higher := max(index1, index2)
 | 
						|
	if lower >= terrain_list.get_child_count() or higher >= terrain_list.get_child_count():
 | 
						|
		return
 | 
						|
	var item1 = terrain_list.get_child(lower)
 | 
						|
	var item2 = terrain_list.get_child(higher)
 | 
						|
	if BetterTerrain.swap_terrains(tileset, lower, higher):
 | 
						|
		terrain_list.move_child(item1, higher)
 | 
						|
		item1.terrain = BetterTerrain.get_terrain(tileset, higher)
 | 
						|
		item1.update()
 | 
						|
		item2.terrain = BetterTerrain.get_terrain(tileset, lower)
 | 
						|
		item2.update()
 | 
						|
		selected_entry = index2
 | 
						|
		terrain_list.get_child(index2).set_selected(true)
 | 
						|
		update_tile_view_paint()
 | 
						|
 | 
						|
 | 
						|
func perform_edit_terrain(index: int, name: String, color: Color, type: int, categories: Array, icon: Dictionary = {}) -> void:
 | 
						|
	if index >= terrain_list.get_child_count():
 | 
						|
		return
 | 
						|
	var entry = terrain_list.get_child(index)
 | 
						|
	# don't overwrite empty icon
 | 
						|
	var valid_icon = icon
 | 
						|
	if icon.has("path") and icon.path.is_empty():
 | 
						|
		var terrain = BetterTerrain.get_terrain(tileset, index)
 | 
						|
		valid_icon = terrain.icon
 | 
						|
	if BetterTerrain.set_terrain(tileset, index, name, color, type, categories, valid_icon):
 | 
						|
		entry.terrain = BetterTerrain.get_terrain(tileset, index)
 | 
						|
		entry.update()
 | 
						|
		tile_view.queue_redraw()
 | 
						|
 | 
						|
 | 
						|
func _on_shuffle_random_pressed():
 | 
						|
	BetterTerrain.use_seed = !shuffle_random.button_pressed 
 | 
						|
 | 
						|
 | 
						|
func _on_bit_button_pressed(button: BaseButton) -> void:
 | 
						|
	match select_tiles.button_group.get_pressed_button():
 | 
						|
		select_tiles: tile_view.paint_mode = tile_view.PaintMode.SELECT
 | 
						|
		paint_type: tile_view.paint_mode = tile_view.PaintMode.PAINT_TYPE
 | 
						|
		paint_terrain: tile_view.paint_mode = tile_view.PaintMode.PAINT_PEERING
 | 
						|
		paint_symmetry: tile_view.paint_mode = tile_view.PaintMode.PAINT_SYMMETRY
 | 
						|
		_: tile_view.paint_mode = tile_view.PaintMode.NO_PAINT
 | 
						|
	tile_view.queue_redraw()
 | 
						|
	
 | 
						|
	symmetry_options.visible = paint_symmetry.button_pressed
 | 
						|
 | 
						|
 | 
						|
func _on_symmetry_selected(index):
 | 
						|
	tile_view.paint_symmetry = index
 | 
						|
 | 
						|
 | 
						|
func _on_paste_occurred():
 | 
						|
	select_tiles.button_pressed = true
 | 
						|
 | 
						|
 | 
						|
func _on_change_zoom_level(value):
 | 
						|
	zoom_slider.value = value
 | 
						|
 | 
						|
 | 
						|
func _on_terrain_updated(index):
 | 
						|
	var entry = terrain_list.get_child(index)
 | 
						|
	entry.terrain = BetterTerrain.get_terrain(tileset, index)
 | 
						|
	entry.update()
 | 
						|
 | 
						|
 | 
						|
func canvas_tilemap_transform() -> Transform2D:
 | 
						|
	var transform := tilemap.get_viewport_transform() * tilemap.global_transform
 | 
						|
	
 | 
						|
	# Handle subviewport
 | 
						|
	var editor_viewport := EditorInterface.get_editor_viewport_2d()
 | 
						|
	if tilemap.get_viewport() != editor_viewport:
 | 
						|
		var container = tilemap.get_viewport().get_parent() as SubViewportContainer
 | 
						|
		if container:
 | 
						|
			transform = editor_viewport.global_canvas_transform * container.get_transform() * transform
 | 
						|
	
 | 
						|
	return transform
 | 
						|
 | 
						|
 | 
						|
func canvas_draw(overlay: Control) -> void:
 | 
						|
	if !draw_overlay:
 | 
						|
		return
 | 
						|
	
 | 
						|
	if selected_entry < 0:
 | 
						|
		return
 | 
						|
	
 | 
						|
	var type = selected_entry
 | 
						|
	var terrain := BetterTerrain.get_terrain(tileset, type)
 | 
						|
	if !terrain.valid:
 | 
						|
		return
 | 
						|
	
 | 
						|
	var tiles := []
 | 
						|
	var transform := canvas_tilemap_transform()
 | 
						|
	
 | 
						|
	if paint_action == PaintAction.RECT and paint_mode != PaintMode.NO_PAINT:
 | 
						|
		var area := Rect2i(initial_click, current_position - initial_click).abs()
 | 
						|
 | 
						|
		# Shortcut fill for large areas
 | 
						|
		if area.size.x > 1 and area.size.y > 1 and area.size.x * area.size.y > MAX_CANVAS_RENDER_TILES:
 | 
						|
			var shortcut := PackedVector2Array([
 | 
						|
				tilemap.map_to_local(area.position),
 | 
						|
				tilemap.map_to_local(Vector2i(area.end.x, area.position.y)),
 | 
						|
				tilemap.map_to_local(area.end),
 | 
						|
				tilemap.map_to_local(Vector2i(area.position.x, area.end.y))
 | 
						|
			])
 | 
						|
			overlay.draw_colored_polygon(transform * shortcut, Color(terrain.color, 0.5))
 | 
						|
			return
 | 
						|
		
 | 
						|
		for y in range(area.position.y, area.end.y + 1):
 | 
						|
			for x in range(area.position.x, area.end.x + 1):
 | 
						|
				tiles.append(Vector2i(x, y))
 | 
						|
	elif paint_action == PaintAction.LINE and paint_mode != PaintMode.NO_PAINT:
 | 
						|
		var cells := _get_tileset_line(initial_click, current_position, tileset)
 | 
						|
		var shape = BetterTerrain.data.cell_polygon(tileset)
 | 
						|
		for c in cells:
 | 
						|
			var tile_transform := Transform2D(0.0, tilemap.tile_set.tile_size, 0.0, tilemap.map_to_local(c))
 | 
						|
			overlay.draw_colored_polygon(transform * tile_transform * shape, Color(terrain.color, 0.5))
 | 
						|
	elif fill_button.button_pressed:
 | 
						|
		tiles = _get_fill_cells(current_position)
 | 
						|
		if tiles.size() > MAX_CANVAS_RENDER_TILES:
 | 
						|
			tiles.resize(MAX_CANVAS_RENDER_TILES)
 | 
						|
	else:
 | 
						|
		tiles.append(current_position)
 | 
						|
	
 | 
						|
	var shape = BetterTerrain.data.cell_polygon(tileset)
 | 
						|
	for t in tiles:
 | 
						|
		var tile_transform := Transform2D(0.0, tilemap.tile_set.tile_size, 0.0, tilemap.map_to_local(t))
 | 
						|
		overlay.draw_colored_polygon(transform * tile_transform * shape, Color(terrain.color, 0.5))
 | 
						|
 | 
						|
 | 
						|
func canvas_input(event: InputEvent) -> bool:
 | 
						|
	if selected_entry < 0:
 | 
						|
		return false
 | 
						|
	
 | 
						|
	draw_overlay = true
 | 
						|
	if event is InputEventMouseMotion:
 | 
						|
		var tr := canvas_tilemap_transform()
 | 
						|
		var pos := tr.affine_inverse() * Vector2(event.position)
 | 
						|
		var event_position := tilemap.local_to_map(pos)
 | 
						|
		prev_position = current_position
 | 
						|
		if event_position == current_position:
 | 
						|
			return false
 | 
						|
		current_position = event_position
 | 
						|
		update_overlay.emit()
 | 
						|
	
 | 
						|
	var replace_mode = replace_button.button_pressed
 | 
						|
	
 | 
						|
	var released : bool = event is InputEventMouseButton and !event.pressed
 | 
						|
	if released:
 | 
						|
		terrain_undo.finish_action()
 | 
						|
		var type = selected_entry
 | 
						|
		if paint_action == PaintAction.RECT and paint_mode != PaintMode.NO_PAINT:
 | 
						|
			var area := Rect2i(initial_click, current_position - initial_click).abs()
 | 
						|
			# Fill from initial_target to target
 | 
						|
			undo_manager.create_action(tr("Draw terrain rectangle"), UndoRedo.MERGE_DISABLE, tilemap)
 | 
						|
			for y in range(area.position.y, area.end.y + 1):
 | 
						|
				for x in range(area.position.x, area.end.x + 1):
 | 
						|
					var coord := Vector2i(x, y)
 | 
						|
					if paint_mode == PaintMode.PAINT:
 | 
						|
						if replace_mode:
 | 
						|
							undo_manager.add_do_method(BetterTerrain, &"replace_cell", tilemap, coord, type)
 | 
						|
						else:
 | 
						|
							undo_manager.add_do_method(BetterTerrain, &"set_cell", tilemap, coord, type)
 | 
						|
					else:
 | 
						|
						undo_manager.add_do_method(tilemap, &"erase_cell", coord)
 | 
						|
			
 | 
						|
			undo_manager.add_do_method(BetterTerrain, &"update_terrain_area", tilemap, area)
 | 
						|
			terrain_undo.create_tile_restore_point_area(undo_manager, tilemap, area)
 | 
						|
			undo_manager.commit_action()
 | 
						|
			update_overlay.emit()
 | 
						|
		elif paint_action == PaintAction.LINE and paint_mode != PaintMode.NO_PAINT:
 | 
						|
			undo_manager.create_action(tr("Draw terrain line"), UndoRedo.MERGE_DISABLE, tilemap)
 | 
						|
			var cells := _get_tileset_line(initial_click, current_position, tileset)
 | 
						|
			if paint_mode == PaintMode.PAINT:
 | 
						|
				if replace_mode:
 | 
						|
					undo_manager.add_do_method(BetterTerrain, &"replace_cells", tilemap, cells, type)
 | 
						|
				else:
 | 
						|
					undo_manager.add_do_method(BetterTerrain, &"set_cells", tilemap, cells, type)
 | 
						|
			elif paint_mode == PaintMode.ERASE:
 | 
						|
				for c in cells:
 | 
						|
					undo_manager.add_do_method(tilemap, &"erase_cell", c)
 | 
						|
			undo_manager.add_do_method(BetterTerrain, &"update_terrain_cells", tilemap, cells)
 | 
						|
			terrain_undo.create_tile_restore_point(undo_manager, tilemap, cells)
 | 
						|
			undo_manager.commit_action()
 | 
						|
			update_overlay.emit()
 | 
						|
		
 | 
						|
		paint_mode = PaintMode.NO_PAINT
 | 
						|
		return true
 | 
						|
	
 | 
						|
	var clicked : bool = event is InputEventMouseButton and event.pressed
 | 
						|
	if clicked:
 | 
						|
		paint_mode = PaintMode.NO_PAINT
 | 
						|
		
 | 
						|
		if (event.is_command_or_control_pressed() and !event.shift_pressed):
 | 
						|
			var pick = BetterTerrain.get_cell(tilemap, current_position)
 | 
						|
			if pick >= 0:
 | 
						|
				terrain_list.get_children()[pick]._on_focus_entered()
 | 
						|
				#_on_entry_select(pick)
 | 
						|
			return true
 | 
						|
		
 | 
						|
		paint_action = PaintAction.NO_ACTION
 | 
						|
		if rectangle_button.button_pressed:
 | 
						|
			paint_action = PaintAction.RECT
 | 
						|
		elif line_button.button_pressed:
 | 
						|
			paint_action = PaintAction.LINE
 | 
						|
		elif draw_button.button_pressed:
 | 
						|
			if event.shift_pressed:
 | 
						|
				paint_action = PaintAction.LINE
 | 
						|
				if event.is_command_or_control_pressed():
 | 
						|
					paint_action = PaintAction.RECT
 | 
						|
		
 | 
						|
		if event.button_index == MOUSE_BUTTON_LEFT:
 | 
						|
			paint_mode = PaintMode.PAINT
 | 
						|
		elif event.button_index == MOUSE_BUTTON_RIGHT:
 | 
						|
			paint_mode = PaintMode.ERASE
 | 
						|
		else:
 | 
						|
			return false
 | 
						|
	
 | 
						|
	if (clicked or event is InputEventMouseMotion) and paint_mode != PaintMode.NO_PAINT:
 | 
						|
		if clicked:
 | 
						|
			initial_click = current_position
 | 
						|
			terrain_undo.action_index += 1
 | 
						|
			terrain_undo.action_count = 0
 | 
						|
		var type = selected_entry
 | 
						|
		
 | 
						|
		if paint_action == PaintAction.LINE or paint_action == PaintAction.RECT:
 | 
						|
			# if painting as line, execution happens on release. 
 | 
						|
			# prevent other painting actions from running.
 | 
						|
			pass
 | 
						|
		elif draw_button.button_pressed:
 | 
						|
			undo_manager.create_action(tr("Draw terrain") + str(terrain_undo.action_index), UndoRedo.MERGE_ALL, tilemap, true)
 | 
						|
			var cells := _get_tileset_line(prev_position, current_position, tileset)
 | 
						|
			if paint_mode == PaintMode.PAINT:
 | 
						|
				if replace_mode:
 | 
						|
					terrain_undo.add_do_method(undo_manager, BetterTerrain, &"replace_cells", [tilemap, cells, type])
 | 
						|
				else:
 | 
						|
					terrain_undo.add_do_method(undo_manager, BetterTerrain, &"set_cells", [tilemap, cells, type])
 | 
						|
			elif paint_mode == PaintMode.ERASE:
 | 
						|
				for c in cells:
 | 
						|
					terrain_undo.add_do_method(undo_manager, tilemap, &"erase_cell", [c])
 | 
						|
			terrain_undo.add_do_method(undo_manager, BetterTerrain, &"update_terrain_cells", [tilemap, cells])
 | 
						|
			terrain_undo.create_tile_restore_point(undo_manager, tilemap, cells)
 | 
						|
			undo_manager.commit_action()
 | 
						|
			terrain_undo.action_count += 1
 | 
						|
		elif fill_button.button_pressed:
 | 
						|
			var cells := _get_fill_cells(current_position)
 | 
						|
			undo_manager.create_action(tr("Fill terrain"), UndoRedo.MERGE_DISABLE, tilemap)
 | 
						|
			if paint_mode == PaintMode.PAINT:
 | 
						|
				if replace_mode:
 | 
						|
					undo_manager.add_do_method(BetterTerrain, &"replace_cells", tilemap, cells, type)
 | 
						|
				else:
 | 
						|
					undo_manager.add_do_method(BetterTerrain, &"set_cells", tilemap, cells, type)
 | 
						|
			elif paint_mode == PaintMode.ERASE:
 | 
						|
				for c in cells:
 | 
						|
					undo_manager.add_do_method(tilemap, &"erase_cell", c)
 | 
						|
			undo_manager.add_do_method(BetterTerrain, &"update_terrain_cells", tilemap, cells)
 | 
						|
			terrain_undo.create_tile_restore_point(undo_manager, tilemap, cells)
 | 
						|
			undo_manager.commit_action()
 | 
						|
		
 | 
						|
		update_overlay.emit()
 | 
						|
		return true
 | 
						|
	
 | 
						|
	return false
 | 
						|
 | 
						|
 | 
						|
func canvas_mouse_exit() -> void:
 | 
						|
	draw_overlay = false
 | 
						|
	update_overlay.emit()
 | 
						|
 | 
						|
 | 
						|
func _shortcut_input(event) -> void:
 | 
						|
	if event is InputEventKey:
 | 
						|
		if event.keycode == KEY_C and (event.is_command_or_control_pressed() and not event.echo):
 | 
						|
			get_viewport().set_input_as_handled()
 | 
						|
			tile_view.copy_selection()
 | 
						|
		if event.keycode == KEY_V and (event.is_command_or_control_pressed() and not event.echo):
 | 
						|
			get_viewport().set_input_as_handled()
 | 
						|
			tile_view.paste_selection()
 | 
						|
 | 
						|
 | 
						|
## bresenham alg ported from Geometry2D::bresenham_line()
 | 
						|
func _get_line(from:Vector2i, to:Vector2i) -> Array[Vector2i]:
 | 
						|
	if from == to:
 | 
						|
		return [to]
 | 
						|
	
 | 
						|
	var points:Array[Vector2i] = []
 | 
						|
	var delta := (to - from).abs() * 2
 | 
						|
	var step := (to - from).sign()
 | 
						|
	var current := from
 | 
						|
	
 | 
						|
	if delta.x > delta.y:
 | 
						|
		var err:int = delta.x / 2
 | 
						|
		while current.x != to.x:
 | 
						|
			points.push_back(current);
 | 
						|
			err -= delta.y
 | 
						|
			if err < 0:
 | 
						|
				current.y += step.y
 | 
						|
				err += delta.x
 | 
						|
			current.x += step.x
 | 
						|
	else:
 | 
						|
		var err:int = delta.y / 2
 | 
						|
		while current.y != to.y:
 | 
						|
			points.push_back(current)
 | 
						|
			err -= delta.x
 | 
						|
			if err < 0:
 | 
						|
				current.x += step.x
 | 
						|
				err += delta.y
 | 
						|
			current.y += step.y
 | 
						|
	
 | 
						|
	points.push_back(current);
 | 
						|
	return points;
 | 
						|
 | 
						|
 | 
						|
## half-offset bresenham alg ported from TileMapEditor::get_line
 | 
						|
func _get_tileset_line(from:Vector2i, to:Vector2i, tileset:TileSet) -> Array[Vector2i]:
 | 
						|
	if tileset.tile_shape == TileSet.TILE_SHAPE_SQUARE:
 | 
						|
		return _get_line(from, to)
 | 
						|
	
 | 
						|
	var points:Array[Vector2i] = []
 | 
						|
	
 | 
						|
	var transposed := tileset.get_tile_offset_axis() == TileSet.TILE_OFFSET_AXIS_VERTICAL
 | 
						|
	if transposed:
 | 
						|
		from = Vector2i(from.y, from.x)
 | 
						|
		to = Vector2i(to.y, to.x)
 | 
						|
 | 
						|
	var delta:Vector2i = to - from
 | 
						|
	delta = Vector2i(2 * delta.x + abs(posmod(to.y, 2)) - abs(posmod(from.y, 2)), delta.y)
 | 
						|
	var sign:Vector2i = delta.sign()
 | 
						|
 | 
						|
	var current := from;
 | 
						|
	points.push_back(Vector2i(current.y, current.x) if transposed else current)
 | 
						|
 | 
						|
	var err := 0
 | 
						|
	if abs(delta.y) < abs(delta.x):
 | 
						|
		var err_step:Vector2i = 3 * delta.abs()
 | 
						|
		while current != to:
 | 
						|
			err += err_step.y
 | 
						|
			if err > abs(delta.x):
 | 
						|
				if sign.x == 0:
 | 
						|
					current += Vector2i(sign.y, 0)
 | 
						|
				else:
 | 
						|
					current += Vector2i(sign.x if bool(current.y % 2) != (sign.x < 0) else 0, sign.y)
 | 
						|
				err -= err_step.x
 | 
						|
			else:
 | 
						|
				current += Vector2i(sign.x, 0)
 | 
						|
				err += err_step.y
 | 
						|
			points.push_back(Vector2i(current.y, current.x) if transposed else current)
 | 
						|
	else:
 | 
						|
		var err_step:Vector2i = delta.abs()
 | 
						|
		while current != to:
 | 
						|
			err += err_step.x
 | 
						|
			if err > 0:
 | 
						|
				if sign.x == 0:
 | 
						|
					current += Vector2i(0, sign.y)
 | 
						|
				else:
 | 
						|
					current += Vector2i(sign.x if bool(current.y % 2) != (sign.x < 0) else 0, sign.y)
 | 
						|
				err -= err_step.y;
 | 
						|
			else:
 | 
						|
				if sign.x == 0:
 | 
						|
					current += Vector2i(0, sign.y)
 | 
						|
				else:
 | 
						|
					current += Vector2i(-sign.x if bool(current.y % 2) != (sign.x > 0) else 0, sign.y)
 | 
						|
				err += err_step.y
 | 
						|
			points.push_back(Vector2i(current.y, current.x) if transposed else current)
 | 
						|
	
 | 
						|
	return points
 | 
						|
 | 
						|
 | 
						|
func _on_terrain_enable_id_pressed(id):
 | 
						|
	if id in [SourceSelectors.ALL, SourceSelectors.NONE]:
 | 
						|
		for i in source_selector_popup.item_count:
 | 
						|
			if source_selector_popup.is_item_checkable(i):
 | 
						|
				source_selector_popup.set_item_checked(i, id == SourceSelectors.ALL)
 | 
						|
	else:
 | 
						|
		var index = source_selector_popup.get_item_index(id)
 | 
						|
		var checked = source_selector_popup.is_item_checked(index)
 | 
						|
		source_selector_popup.set_item_checked(index, !checked)
 | 
						|
	
 | 
						|
	var disabled_sources : Array[int]
 | 
						|
	for i in source_selector_popup.item_count:
 | 
						|
		if source_selector_popup.is_item_checkable(i) and !source_selector_popup.is_item_checked(i):
 | 
						|
			disabled_sources.append(source_selector_popup.get_item_id(i))
 | 
						|
	tile_view.disabled_sources = disabled_sources
 | 
						|
 | 
						|
 | 
						|
func corresponding_tilemap_editor_button(similar: Button) -> Button:
 | 
						|
	var editors = EditorInterface.get_base_control().find_children("*", "TileMapLayerEditor", true, false)
 | 
						|
	var tile_map_layer_editor = editors[0]
 | 
						|
	var buttons = tile_map_layer_editor.find_children("*", "Button", true, false)
 | 
						|
	for button: Button in buttons:
 | 
						|
		if button.icon == similar.icon:
 | 
						|
			return button
 | 
						|
	return null
 | 
						|
 | 
						|
 | 
						|
func _on_layer_up_or_down_pressed(button: Button) -> void:
 | 
						|
	var matching_button = corresponding_tilemap_editor_button(button)
 | 
						|
	if !matching_button:
 | 
						|
		return
 | 
						|
	
 | 
						|
	# Major hack, to reduce flicker hide the tileset editor briefly
 | 
						|
	var editors = EditorInterface.get_base_control().find_children("*", "TileSetEditor", true, false)
 | 
						|
	var tile_set_editor = editors[0]
 | 
						|
	
 | 
						|
	matching_button.pressed.emit()
 | 
						|
	tile_set_editor.modulate = Color.TRANSPARENT
 | 
						|
	await get_tree().process_frame
 | 
						|
	await get_tree().process_frame
 | 
						|
	force_show_terrains.emit()
 | 
						|
	tile_set_editor.modulate = Color.WHITE
 | 
						|
 | 
						|
 | 
						|
 | 
						|
func _on_layer_up_pressed() -> void:
 | 
						|
	_on_layer_up_or_down_pressed(layer_up)
 | 
						|
 | 
						|
 | 
						|
func _on_layer_down_pressed() -> void:
 | 
						|
	_on_layer_up_or_down_pressed(layer_down)
 | 
						|
 | 
						|
 | 
						|
func _on_layer_highlight_toggled(toggled: bool) -> void:
 | 
						|
	var settings = EditorInterface.get_editor_settings()
 | 
						|
	settings.set_setting("editors/tiles_editor/highlight_selected_layer", toggled)
 | 
						|
	
 | 
						|
	var highlight = corresponding_tilemap_editor_button(layer_highlight)
 | 
						|
	if highlight:
 | 
						|
		highlight.toggled.emit(toggled)
 | 
						|
 | 
						|
 | 
						|
func _on_layer_grid_toggled(toggled: bool) -> void:
 | 
						|
	var settings = EditorInterface.get_editor_settings()
 | 
						|
	settings.set_setting("editors/tiles_editor/display_grid", toggled)
 | 
						|
	
 | 
						|
	var grid = corresponding_tilemap_editor_button(layer_grid)
 | 
						|
	if grid:
 | 
						|
		grid.toggled.emit(toggled)
 |