File size: 6,559 Bytes
b6a38d7
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
-- Override this class to create editor brushes for grids defined with DefineMapGrid

DefineClass.XMapGridAreaBrush = {
	__parents = { "XEditorBrushTool" },
	properties = {
		auto_select_all = true,
		{	id = "TerrainDebugAlphaPerc", name = "Opacity", editor = "number",
			default = 50, min = 0, max = 100, slider = true,
		},
		{	id = "WriteValue", name = "Value", editor = "texture_picker", default = "Blank",
			thumb_width = 101, thumb_height = 35, small_font = true, items = function(self) return self:GetGridPaletteItems() end,
		},
		{	id = "mask_help", editor = "help", help = "<center><style GedHighlight>You can only draw outside the grey mask.</style>\n",
			no_edit = function(self) return not self.selection_available end,
		},
		{	id = "mask_buttons", editor = "buttons", default = false,
			buttons = {
				{ name = "Clear (Esc)", func = "ClearSelection" },
				{ name = "Invert (I)", func = "InvertSelection" },
				{ name = "Fill area (F)", func = "FillSelection" },
			},
			no_edit = function(self) return not self.selection_available end,
		},
	},
	
	-- settings
	GridName = false, -- grid name, as defined with DefineMapGrid
	GridTileSize = false,
	Grid = false,
	
	-- state
	saved_alpha = false,
	add_connected_area = false,
	add_every_tile = false,
	selection_grid = false,
	selection_available = false,
	
	-- overrides
	CreateBrushGrid = empty_func,
	GetGridPaletteItems = empty_func,
	GetPalette = empty_func,
}

function XMapGridAreaBrush:Init()
	self:Initialize()
end

function XMapGridAreaBrush:Initialize()
	if (not self.GridName or not _G[self.GridName]) and not self.Grid and not self:CreateBrushGrid() then
		assert(false, "Grid area brush has no configured grid or configured grid was not found")
		return
	end
		
	local items = self:GetGridPaletteItems()
	if not table.find(items, "value", self:GetWriteValue()) then
		self:SetWriteValue(items[1].value)
	end
	
	local grid = self.Grid or _G[self.GridName]
	local w, h = grid:size()
	self.selection_grid = NewHierarchicalGrid(w, h, 64, 1)
	self:SelectionOp("clear")
	
	self:UpdateItems()
	self.saved_alpha = hr.TerrainDebugAlphaPerc
	hr.TerrainDebugDraw = 1
	hr.TerrainDebugAlphaPerc = self:GetTerrainDebugAlphaPerc()
end

function XMapGridAreaBrush:Done()
	if (not self.GridName and not self.Grid) or not self.selection_grid then return	end
	
	hr.TerrainDebugDraw = 0
	hr.TerrainDebugAlphaPerc = self.saved_alpha
	DbgSetTerrainOverlay("") -- prevent further access to self.selection_grid (which is getting freed) from C++
	self.selection_grid:free()
end

function XMapGridAreaBrush:UpdateItems()
	-- Upload new palette to the debug overlay
	DbgSetTerrainOverlay("grid", self:GetPalette(), self.Grid or _G[self.GridName], self.selection_grid)
	-- Update UI
	ObjModified(self)
end

function XMapGridAreaBrush:HideDebugOverlay()
	DbgSetTerrainOverlay("")
end

function XMapGridAreaBrush:StartDraw(pt)
	XEditorUndo:BeginOp{[self.GridName] = true, name = string.format("Edited grid - %s", self.GridName)}
end
 
function XMapGridAreaBrush:Draw(pt1, pt2)
	local tile_size = MapGridTileSize(self.GridName) or self.GridTileSize
	local bbox = editor.SetGridSegment(self.Grid or _G[self.GridName], tile_size, pt1, pt2, self:GetSize() / 2, self:GetWriteValue(), self.selection_grid)
	Msg("OnMapGridChanged", self.GridName, bbox)
end

function XMapGridAreaBrush:EndDraw(pt1, pt2, invalid_box)
	XEditorUndo:EndOp(nil, invalid_box)
	self.start_pt = false
	ObjModified(self) -- update palette items
end

function XMapGridAreaBrush:SelectionOp(op, param)
	local tile_size = MapGridTileSize(self.GridName) or self.GridTileSize
	local bbox = editor.GridSelectionOp(self.Grid or _G[self.GridName], self.selection_grid, tile_size, op, param)
	if bbox and not bbox:IsEmpty() then
		Msg("OnMapGridChanged", self.GridName, bbox)
	end
end

function XMapGridAreaBrush:ClearSelection()
	self:SelectionOp("clear")
	self.selection_available = false
	ObjModified(self)
end

function XMapGridAreaBrush:InvertSelection()
	self:SelectionOp("invert")
end

function XMapGridAreaBrush:FillSelection()
	XEditorUndo:BeginOp{[self.GridName] = true, name = string.format("Edited grid - %s", self.GridName)}
	
	if not self.selection_available then
		self:SelectionOp("invert") -- select entire map
	end
	self:SelectionOp("fill", self:GetWriteValue())
	self:SelectionOp("clear")
	self.selection_available = false
	ObjModified(self)
	
	XEditorUndo:EndOp()
end

function XMapGridAreaBrush:OnMouseButtonDown(pt, button)
	if button == "L" then
		local selecting = self.add_connected_area or self.add_every_tile
		if selecting then
			local world_pt = self:GetWorldMousePos()
			if self.add_every_tile then
				self:SelectionOp("add every tile", world_pt)
			elseif self.add_connected_area then
				self:SelectionOp("add connected area", world_pt)
			end
			self.selection_available = true
			ObjModified(self)
			return "break"
		elseif terminal.IsKeyPressed(const.vkAlt) then
			local tile_size = MapGridTileSize(self.GridName)
			local value = self.Grid or _G[self.GridName]:get(GetTerrainCursor() / tile_size)
			self:SetWriteValue(value)
			ObjModified(self)
			return "break"
		end
	elseif button == "R" then
		if self.selection_available then
			self:ClearSelection()
			return "break"
		end
	end
	
	return XEditorBrushTool.OnMouseButtonDown(self, pt, button)
end

function XMapGridAreaBrush:OnKbdKeyDown(vkey)
	local result
	if vkey == const.vkControl then
		self.add_connected_area = true
		result = "break"
	elseif vkey == const.vkShift then
		self.add_every_tile = true
		result = "break"
	end
	return result or XEditorBrushTool.OnKbdKeyDown(self, vkey)
end

function XMapGridAreaBrush:OnKbdKeyUp(vkey)
	local result
	if vkey == const.vkControl then
		self.add_connected_area = false
		result = "break"
	elseif vkey == const.vkShift then
		self.add_every_tile = false
		result = "break"
	end
	return result or XEditorBrushTool.OnKbdKeyDown(self, vkey)
end

function XMapGridAreaBrush:OnShortcut(shortcut, source, ...)
	if shortcut == "Escape" and self.selection_available then
		self:ClearSelection()
		return "break"
	elseif shortcut == "I" then
		self:InvertSelection()
		return "break"
	elseif shortcut == "F" then
		self:FillSelection()
		return "break"
	end
	return XEditorBrushTool.OnShortcut(self, shortcut, source, ...)
end

function XMapGridAreaBrush:GetCursorRadius()
	local radius = self:GetSize() / 2
	return radius, radius
end

function XMapGridAreaBrush:OnEditorSetProperty(prop_id)
	if prop_id == "TerrainDebugAlphaPerc" then
		hr.TerrainDebugAlphaPerc = self:GetTerrainDebugAlphaPerc()
	end
end