Repository navigation
gui/liquids - Add brush radius and shape mode #1649
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -18,6 +18,11 @@ local SpawnLiquidPaintMode = { | |||||
| AREA = 3, | ||||||
| } | ||||||
|
|
||||||
| local SpawnLiquidPaintShape = { | ||||||
| SQUARE = 1, | ||||||
| ROUND = 2, | ||||||
| } | ||||||
|
|
||||||
| local SpawnLiquidCursor = { | ||||||
| [df.tile_liquid.Water] = dfhack.screen.findGraphicsTile('MINING_INDICATORS', 0, 0), | ||||||
| [df.tile_liquid.Magma] = dfhack.screen.findGraphicsTile('MINING_INDICATORS', 1, 0), | ||||||
|
|
@@ -30,11 +35,35 @@ SpawnLiquid.ATTRS { | |||||
| frame={b = 4, r = 4, w = 50, h = 12}, | ||||||
| } | ||||||
|
|
||||||
|
|
||||||
| function SpawnLiquid:preUpdateLayout() | ||||||
| local level_change_position = 1 | ||||||
| local brush_mode_position = 2 | ||||||
|
|
||||||
| if self:useBrushSize() then | ||||||
| level_change_position = level_change_position + 1 | ||||||
| brush_mode_position = brush_mode_position + 1 | ||||||
| end | ||||||
|
|
||||||
| for k, v in pairs(self.subviews) do | ||||||
| if type(k) == "string" then | ||||||
| if k:startswith("level_increase") or k:startswith("level_decrease") then | ||||||
| v.frame.b = level_change_position | ||||||
| elseif k:startswith("brush") then | ||||||
| v.frame.b = brush_mode_position | ||||||
| end | ||||||
| end | ||||||
| end | ||||||
| end | ||||||
|
|
||||||
|
|
||||||
| function SpawnLiquid:init() | ||||||
| self.type = df.tile_liquid.Water | ||||||
| self.mode = SpawnLiquidMode.SET | ||||||
| self.level = 3 | ||||||
| self.paint_mode = SpawnLiquidPaintMode.AREA | ||||||
| self.paint_mode = SpawnLiquidPaintMode.DRAG | ||||||
| self.paint_shape = SpawnLiquidPaintShape.SQUARE | ||||||
| self.brush_radius = 0 | ||||||
| self.tile = SpawnLiquidCursor[self.type] | ||||||
|
|
||||||
| self:addviews{ | ||||||
|
|
@@ -43,6 +72,7 @@ function SpawnLiquid:init() | |||||
| text = {{ text = self:callback('getLabel') }} | ||||||
| }, | ||||||
| widgets.HotkeyLabel{ | ||||||
| view_id = "level_decrease", | ||||||
| frame = {l = 0, b = 1}, | ||||||
| label = 'Decrease level', | ||||||
| auto_width = true, | ||||||
|
|
@@ -51,11 +81,13 @@ function SpawnLiquid:init() | |||||
| disabled = function() return self.level == 1 end | ||||||
| }, | ||||||
| widgets.Label{ | ||||||
| view_id = "level_decrease_glyph", | ||||||
| frame = { l = 0, b = 1, w = 1}, | ||||||
| text_pen=COLOR_LIGHTGREEN, | ||||||
| text=string.char(27), | ||||||
| }, | ||||||
| widgets.HotkeyLabel{ | ||||||
| view_id = "level_increase", | ||||||
| frame = { l = 19, b = 1}, | ||||||
| label = 'Increase level', | ||||||
| auto_width = true, | ||||||
|
|
@@ -64,12 +96,44 @@ function SpawnLiquid:init() | |||||
| disabled = function() return self.level == 7 end | ||||||
| }, | ||||||
| widgets.Label{ | ||||||
| view_id = "level_increase_glyph", | ||||||
| frame = { l = 19, b = 1, w = 1}, | ||||||
| text_pen=COLOR_LIGHTGREEN, | ||||||
| text=string.char(26), | ||||||
| }, | ||||||
| widgets.HotkeyLabel{ | ||||||
| frame = {l = 0, b = 1}, | ||||||
| label = 'Decrease radius', | ||||||
| auto_width = true, | ||||||
| key = 'KEYBOARD_CURSOR_DOWN', | ||||||
| on_activate = self:callback('decreaseBrushSize'), | ||||||
| visible = self:callback("useBrushSize"), | ||||||
| disabled = function() return self.brush_radius <= 0 end | ||||||
| }, | ||||||
| widgets.Label{ | ||||||
| frame = { l = 0, b = 1, w = 1}, | ||||||
| text_pen=COLOR_LIGHTGREEN, | ||||||
| text=string.char(25), | ||||||
| visible = self:callback("useBrushSize"), | ||||||
| }, | ||||||
| widgets.HotkeyLabel{ | ||||||
| frame = { l = 19, b = 1}, | ||||||
| label = 'Increase radius', | ||||||
| auto_width = true, | ||||||
| key = 'KEYBOARD_CURSOR_UP', | ||||||
| on_activate = self:callback('increaseBrushSize'), | ||||||
| visible = self:callback("useBrushSize"), | ||||||
| disabled = function() return self.brush_radius >= 10 end | ||||||
| }, | ||||||
| widgets.Label{ | ||||||
| frame = { l = 19, b = 1, w = 1}, | ||||||
| text_pen=COLOR_LIGHTGREEN, | ||||||
| text=string.char(24), | ||||||
| visible = self:callback("useBrushSize"), | ||||||
| }, | ||||||
| widgets.CycleHotkeyLabel{ | ||||||
| frame = {l = 0, b = 2}, | ||||||
| view_id = "brush", | ||||||
| frame = {l = 0, b = 3}, | ||||||
| label = 'Brush:', | ||||||
| auto_width = true, | ||||||
| key = 'CUSTOM_Q', | ||||||
|
|
@@ -95,11 +159,30 @@ function SpawnLiquid:init() | |||||
| { label = "Drag ", value = SpawnLiquidPaintMode.DRAG, pen = COLOR_WHITE }, | ||||||
| }, | ||||||
| initial_option = SpawnLiquidPaintMode.DRAG, | ||||||
| on_change = function(new, _) self.paint_mode = new end, | ||||||
| on_change = function(new, _) | ||||||
| self.paint_mode = new | ||||||
| self:updateLayout() | ||||||
| end, | ||||||
| }, | ||||||
| widgets.CycleHotkeyLabel{ | ||||||
| view_id = 'mode1', | ||||||
| frame = {l = 18, b = 2}, | ||||||
| frame = {l = 21, b = 0}, | ||||||
| label = 'Paint Shape:', | ||||||
| auto_width = true, | ||||||
| key = 'CUSTOM_V', | ||||||
| options = { | ||||||
| { label = "Square", value = SpawnLiquidPaintShape.SQUARE, pen = COLOR_WHITE }, | ||||||
| { label = "Round", value = SpawnLiquidPaintShape.ROUND, pen = COLOR_WHITE }, | ||||||
| }, | ||||||
| initial_option = SpawnLiquidPaintMode.SQUARE, | ||||||
| visible = self:callback("useBrushSize"), | ||||||
| on_change = function(new, _) | ||||||
| self.paint_shape = new | ||||||
| self:updateLayout() | ||||||
| end, | ||||||
| }, | ||||||
| widgets.CycleHotkeyLabel{ | ||||||
| view_id = 'brush_mode1', | ||||||
| frame = {l = 18, b = 3}, | ||||||
| label = 'Mode:', | ||||||
| auto_width = true, | ||||||
| key = 'CUSTOM_X', | ||||||
|
|
@@ -112,13 +195,13 @@ function SpawnLiquid:init() | |||||
| initial_option = SpawnLiquidMode.SET, | ||||||
| on_change = function(new, _) | ||||||
| self.mode = new | ||||||
| self.subviews.mode2:setOption(new) | ||||||
| self.subviews.brush_mode2:setOption(new) | ||||||
| end, | ||||||
| visible = function() return self.type ~= df.tiletype.RiverSource end | ||||||
| }, | ||||||
| widgets.CycleHotkeyLabel{ | ||||||
| view_id = 'mode2', | ||||||
| frame = {l = 18, b = 2}, | ||||||
| view_id = 'brush_mode2', | ||||||
| frame = {l = 18, b = 3}, | ||||||
| label = 'Mode:', | ||||||
| auto_width = true, | ||||||
| key = 'CUSTOM_X', | ||||||
|
|
@@ -128,7 +211,7 @@ function SpawnLiquid:init() | |||||
| }, | ||||||
| on_change = function(new, _) | ||||||
| self.mode = new | ||||||
| self.subviews.mode1:setOption(new) | ||||||
| self.subviews.brush_mode1:setOption(new) | ||||||
| end, | ||||||
| visible = function() return self.type == df.tiletype.RiverSource end | ||||||
| }, | ||||||
|
|
@@ -137,9 +220,27 @@ end | |||||
|
|
||||||
| -- TODO: More reactive label dependant on options selected. | ||||||
| function SpawnLiquid:getLabel() | ||||||
| return ([[Click on a tile to spawn a %s/7 level of %s]]):format( | ||||||
| local tile_string = "a tile" | ||||||
| local liquid_string | ||||||
|
|
||||||
| if self.type == 0 then | ||||||
| liquid_string = "Water" | ||||||
| elseif self.type == 1 then | ||||||
| liquid_string = "Magma" | ||||||
| else | ||||||
| liquid_string = "River" | ||||||
| end | ||||||
|
|
||||||
| if self:useBrushSize() and self.brush_radius > 0 then | ||||||
| local brush_size = self.brush_radius*2 | ||||||
| tile_string = string.format("%dx%d tiles", brush_size, brush_size) | ||||||
| end | ||||||
|
|
||||||
|
|
||||||
| return ([[Click to spawn %s with %s/7 %s]]):format( | ||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Tip There's no need for this to use
Suggested change
|
||||||
| tile_string, | ||||||
| self.level, | ||||||
| self.type == 0 and "Water" or self.type == 1 and "Magma" or "River" | ||||||
| liquid_string | ||||||
| ) | ||||||
| end | ||||||
|
|
||||||
|
|
@@ -163,6 +264,15 @@ function SpawnLiquid:decreaseLiquidLevel() | |||||
| self.level = math.max(self.level - 1, 1) | ||||||
| end | ||||||
|
|
||||||
| function SpawnLiquid:increaseBrushSize() | ||||||
| self.brush_radius = math.min(self.brush_radius + 1, 10) | ||||||
| end | ||||||
|
|
||||||
| function SpawnLiquid:decreaseBrushSize() | ||||||
| self.brush_radius = math.max(self.brush_radius - 1, 0) | ||||||
| end | ||||||
|
|
||||||
|
|
||||||
|
Comment on lines
+267
to
+275
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Note setting the brush radius to 1, 2, 3, 4, etc. results in brush sizes of 1x1, 3x3, 5x5, 7x7, etc. |
||||||
| local function isFlowPassable(pos) | ||||||
| local tt = dfhack.maps.getTileType(pos) | ||||||
| local tile = dfhack.maps.getTileFlags(pos) | ||||||
|
|
@@ -203,10 +313,61 @@ function SpawnLiquid:spawn(pos) | |||||
| end | ||||||
| end | ||||||
|
|
||||||
| function SpawnLiquid:paintLiquid(pos, bounds) | ||||||
| if not bounds then | ||||||
| local start_position, end_position = self:getBrushSizeBounds(pos) | ||||||
|
|
||||||
| bounds = self:getBounds(start_position, end_position) | ||||||
| end | ||||||
|
|
||||||
| for x = bounds.x1, bounds.x2 do | ||||||
| for y = bounds.y1, bounds.y2 do | ||||||
| if self:inBounds(pos, {x=x, y=y}) then | ||||||
| self:spawn({x=x, y=y, z=pos.z}) | ||||||
| end | ||||||
| end | ||||||
| end | ||||||
| end | ||||||
|
|
||||||
|
|
||||||
| function SpawnLiquid:getPen() | ||||||
| return self.type == df.tile_liquid.Water and COLOR_BLUE or COLOR_RED, "X", self.tile | ||||||
| end | ||||||
|
|
||||||
| function SpawnLiquid:inBounds(mouse_pos, pos) | ||||||
| if not self:useBrushSize() or self.paint_shape ~= SpawnLiquidPaintShape.ROUND then | ||||||
| return true | ||||||
| end | ||||||
|
|
||||||
| local diff = { | ||||||
| x=mouse_pos.x - pos.x, | ||||||
| y=mouse_pos.y - pos.y | ||||||
| } | ||||||
| local dist = diff.x*diff.x+diff.y*diff.y | ||||||
|
|
||||||
| return dist <= self.brush_radius*self.brush_radius | ||||||
| end | ||||||
|
|
||||||
|
|
||||||
| function SpawnLiquid:getBrushSizeBounds(mouse_pos) | ||||||
| local start_position = xyz2pos( | ||||||
| mouse_pos.x - self.brush_radius, | ||||||
| mouse_pos.y - self.brush_radius, | ||||||
| mouse_pos.z) | ||||||
|
|
||||||
| local end_position = xyz2pos( | ||||||
| mouse_pos.x + self.brush_radius, | ||||||
| mouse_pos.y + self.brush_radius, | ||||||
| mouse_pos.z) | ||||||
|
|
||||||
| return start_position, end_position | ||||||
| end | ||||||
|
|
||||||
|
|
||||||
| function SpawnLiquid:useBrushSize() | ||||||
| return self.paint_mode ~= SpawnLiquidPaintMode.AREA | ||||||
| end | ||||||
|
|
||||||
| function SpawnLiquid:getBounds(start_position, end_position) | ||||||
| return { | ||||||
| x1=math.min(start_position.x, end_position.x), | ||||||
|
|
@@ -221,22 +382,38 @@ end | |||||
| function SpawnLiquid:onRenderFrame(dc, rect) | ||||||
| SpawnLiquid.super.onRenderFrame(self, dc, rect) | ||||||
|
|
||||||
| if self.is_dragging and df.global.enabler.mouse_lbut_down == 0 then | ||||||
| self.is_dragging = false | ||||||
| end | ||||||
|
|
||||||
| local mouse_pos = dfhack.gui.getMousePos() | ||||||
|
|
||||||
| if self.is_dragging then | ||||||
| if df.global.enabler.mouse_lbut_down == 0 then | ||||||
| self.is_dragging = false | ||||||
| elseif mouse_pos and not self:getMouseFramePos() then | ||||||
| self:spawn(mouse_pos) | ||||||
| end | ||||||
| if not mouse_pos then | ||||||
| return | ||||||
| end | ||||||
|
|
||||||
| local start_position = copyall(mouse_pos) | ||||||
| local end_position = copyall(mouse_pos) | ||||||
|
|
||||||
| if self.is_dragging_area then | ||||||
| start_position = self.area_first_pos or mouse_pos | ||||||
| end | ||||||
|
|
||||||
| if mouse_pos then | ||||||
| guidm.renderMapOverlay(self:callback('getPen'), self:getBounds( | ||||||
| self.is_dragging_area and self.area_first_pos or mouse_pos, | ||||||
| mouse_pos | ||||||
| )) | ||||||
| if self:useBrushSize() then | ||||||
| start_position, end_position = self:getBrushSizeBounds(mouse_pos) | ||||||
| end | ||||||
|
|
||||||
| local bounds = self:getBounds(start_position, end_position) | ||||||
|
|
||||||
| if self.is_dragging and not self:getMouseFramePos() then | ||||||
| self:paintLiquid(mouse_pos, bounds) | ||||||
| end | ||||||
|
|
||||||
| guidm.renderMapOverlay(function(pos, _) | ||||||
| if self:inBounds(mouse_pos, pos) then | ||||||
| return self:getPen() | ||||||
| end | ||||||
| end, bounds) | ||||||
| end | ||||||
|
|
||||||
| function SpawnLiquid:onInput(keys) | ||||||
|
|
@@ -246,7 +423,7 @@ function SpawnLiquid:onInput(keys) | |||||
| local mouse_pos = dfhack.gui.getMousePos() | ||||||
|
|
||||||
| if self.paint_mode == SpawnLiquidPaintMode.CLICK and mouse_pos then | ||||||
| self:spawn(mouse_pos) | ||||||
| self:paintLiquid(mouse_pos) | ||||||
| return true | ||||||
| elseif self.paint_mode == SpawnLiquidPaintMode.AREA and mouse_pos then | ||||||
| if self.is_dragging_area then | ||||||
|
|
||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
hmm, okay, why are we doing this?
A: seems to be because we we want to adjust both
level_decreaseandlevel_decrease_glyph, an dthe same forlevel_increaseandlevel_increase_glyph.not sure I like this. I guess it's no worse than the other layout elements, which are also hardcoded.I'm tempted to say 'use a callback to calculate this dynamically' but that is kind of advanced.so the effect of this code is to hide the "Decrease radius" and "Increase radius" labels if the Paint mode is Area.
this is opposed to just graying out both labels, the way that "Increase level" is grayed out when the liquid level is 7/7.
the effect here is that UI elements appear and disappear as modes change.
(later) Okay, I've been thinking about this off-and-on for most of a day. I don't like hiding those labels. I strongly believe menu-like UI elements should gray out when they are not valid input.
Important
Please change the label code so that the Increase radius and Decrease radius labels gray out when not valid.
I think that means this entire function can be deleted.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i'm going to agree with Silas on this point: i generally don't like UI elements that appear and disappear as modes change. there are times when this is appropriate, but i don't think this is one of them. making those controls inactive, instead of hiding them, is less intrusive to the user's experience