Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion luaui/Include/keybind_dropdown.lua
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,13 @@ function Dropdown:draw()
-- A profile name is free text and can outrun the control, which is fixed width so the
-- header does not reflow every time the selection changes.
local labelW = (arrowX - arrowH) - (x1 + inset) - inset * 2
font:Print(fittedLabel(fitted, 0, font, label, labelW, self.fontSize), x1 + inset, (y1 + y2) * 0.5, self.fontSize, "ov")
font:Print(
fittedLabel(fitted, 0, font, label, labelW, self.fontSize),
x1 + inset,
(y1 + y2) * 0.5,
self.fontSize,
"ov"
)
font:End()

if self.open and #self.optRects > 0 then
Expand Down
57 changes: 54 additions & 3 deletions luaui/Include/keybind_editbox.lua
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,24 @@
local colorText = "\255\235\235\235"
local colorDim = "\255\160\160\160"

-- Caret look and blink taken from gui_chat's input, so the two fields read as the same
-- control: a sharp bar that starts bright on a keystroke and fades over a second before
-- snapping back, rather than a hard on/off blink.
local cursorBlinkDuration = 1
local cursorGrey = 0.7

-- Font is fetched per draw; it does not exist when this file is included.
local function getFont()
return WG["fonts"].getFont()
end

-- Restarts the fade, so the caret is at its brightest right after an edit.
local function resetBlink(self)
self.blinkStart = Spring.GetTimer()
self.blinkText = self.text
self.blinkCaret = self.caret
end

-- Single-line text field with a caret, selection and word motion.
function Editbox.new(opts)
opts = opts or {}
Expand Down Expand Up @@ -62,6 +75,11 @@
-- SDL text input is owned by the panel, not by this field: blurring the search box to
-- click a keybind must not stop text events while the editor is still open.
function Editbox:focus()
-- A field that just took focus shows a bright caret, not whatever phase the fade
-- happened to be in when it was last used.
if not self.focused then
resetBlink(self)
end
self.focused = true
end

Expand Down Expand Up @@ -270,11 +288,37 @@
self.dragging = false
end
end

-- Watched here rather than reset from each editing path: every way the caret can move
-- (typing, deleting, arrows, a click, a drag, setText) shows up as one of these two
-- changing, so none of them can be missed.
if not self.blinkStart or self.text ~= self.blinkText or self.caret ~= self.blinkCaret then
resetBlink(self)
end
end

-- Alpha of the caret this frame: full brightness at the last edit, fading to 0.15 over
-- the blink duration, then starting over. Matches gui_chat's sawtooth exactly.
local function caretAlpha(self)
local elapsed = Spring.DiffTimers(Spring.GetTimer(), self.blinkStart) % cursorBlinkDuration

return 1 - (elapsed * (1 / cursorBlinkDuration)) + 0.15
end

-- How far into the text the caret sits, in pixels. Measured only when the text, the caret
-- or the size moved: the field is drawn live every frame so the blink can animate, and
-- measuring the leading substring each of those frames is the one real cost in here.
local function caretOffset(self, font)
if self.caretPxAt ~= self.caret or self.caretPxText ~= self.text or self.caretPxFs ~= self.fontSize then
self.caretPxAt, self.caretPxText, self.caretPxFs = self.caret, self.text, self.fontSize
self.caretPx = font:GetTextWidth(utf8.sub(self.text, 1, self.caret)) * self.fontSize
end

return self.caretPx
end

-- Held rather than built per draw: a colour table a frame is an allocation a frame.
local fieldFill = { 0, 0, 0, 0.35 }
local caretFill = { 1, 1, 1, 0.85 }

function Editbox:draw()
update(self)
Expand Down Expand Up @@ -302,7 +346,7 @@

-- The coloured string is kept until the text changes, not rebuilt every frame.
local shown
if self.text == "" and not self.focused then

Check warning on line 349 in luaui/Include/keybind_editbox.lua

View workflow job for this annotation

GitHub Actions / emmylua_check

unnecessary-if

Impossible `if` statement: this condition is always falsy
shown = self.placeholderShown
if not shown then
shown = colorDim .. self.placeholder
Expand All @@ -321,8 +365,15 @@
font:End()

if self.focused then
local cw = font:GetTextWidth(utf8.sub(self.text, 1, self.caret)) * self.fontSize
R(tx + cw, y1 + inset, tx + cw + math.max(1, floor(inset * 0.5)), y2 - inset, 0, 0, 0, 0, 0, caretFill)
-- Sharp bar rather than a rounded one, sized and placed off the font like chat's:
-- a fixed span around the text's middle, so it does not stretch with the field.
local cx = tx + caretOffset(self, font)
local cWidth = 1 + floor(self.fontSize / 14)
local cy1 = math.max(y1 + 1, ty - self.fontSize * 0.6)
local cy2 = math.min(y2 - 1, ty + self.fontSize * 0.64)
gl.Color(cursorGrey, cursorGrey, cursorGrey, caretAlpha(self))
gl.Rect(cx, cy1, cx + cWidth, cy2)
gl.Color(1, 1, 1, 1)
end
end

Expand Down
70 changes: 56 additions & 14 deletions luaui/Include/keybind_editor_view.lua
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,8 @@
local UiElement
---@type function
local Highlight
---@type function
local UiButton

local colorAction = "\255\210\210\205"
local colorKey = "\255\235\185\070"
Expand All @@ -127,14 +129,16 @@
local confirmFillMuted = { 0.11, 0.20, 0.13, 1 }
local pillFill = { 0.22, 0.22, 0.22, 1 }
local sheenTop = { 1, 1, 1, 0.05 }
local sheenNone = { 1, 1, 1, 0 }
-- Fills and captions the list is painted with, in one table for the same reason as
-- metrics above.
local look = {
chipFill = { 0, 0, 0, 0.35 },
chipFillHover = { 0, 0, 0, 0.45 },
addFill = { 0.2, 0.45, 0.25, 0.4 },
addFillHover = { 0.2, 0.45, 0.25, 0.55 },
-- Lit rather than nudged: hovering used to lift the alpha alone, which on a green this
-- soft was hard to tell from resting. A tinted element brightens its own fill instead
-- of taking the white overlay, which would wash the green out to grey.
addFillHover = { 0.32, 0.74, 0.4, 0.6 },
selectedFill = { 1, 1, 1, 0.13 },
-- The category column sits on its own darker card, so it reads apart from the list.
sidebarFill = { 0, 0, 0, 0.24 },
Expand All @@ -146,9 +150,28 @@
removeHot = colorDanger .. "x",
removeCold = colorDim .. "x",
plusText = colorText .. "+",
-- The glyph goes to full white with it, the way a chip's key does under the cursor.
plusTextHover = "\255\255\255\255" .. "+",
arrow = colorKey .. string.char(226, 128, 186),
}

-- FlowUI's Button gradients from a bottom stop to a top one. Left to its defaults it
-- fades black up to near-transparent white, which washes a tinted button out to grey, so
-- each fill becomes a darker bottom and itself on top - the same shape gui_pregameui
-- gives its ready button. Derived once per fill and kept, since the pair is passed every
-- draw and a table per button per frame is what the rest of this file avoids.
look.gradients = setmetatable({}, {
__index = function(self, fill)
local pair = {
{ fill[1] * 0.55, fill[2] * 0.55, fill[3] * 0.55, fill[4] or 1 },
{ fill[1], fill[2], fill[3], fill[4] or 1 },
}
self[fill] = pair

return pair
end,
})

---@type table
local searchBox
---@type table
Expand Down Expand Up @@ -897,6 +920,9 @@
openDialog({
title = L.reset,
message = L.resetConfirm,
-- Named for what it does. Without this it falls back to the generic "Accept", which
-- says nothing about the edits being thrown away.
acceptLabel = L.discard,
accept = function()
discardStaged()
end,
Expand Down Expand Up @@ -1119,6 +1145,7 @@
Scroller = WG.FlowUI.Draw.Scroller
UiElement = WG.FlowUI.Draw.Element
Highlight = WG.FlowUI.Draw.SelectHighlight
UiButton = WG.FlowUI.Draw.Button
ensureControls()
end

Expand Down Expand Up @@ -1156,7 +1183,7 @@

local pad = floor(6 * scale)

sidebarW = floor(260 * scale)
sidebarW = floor(240 * scale)
listX1 = area.x1 + sidebarW + floor(12 * scale)

layoutHeader()
Expand Down Expand Up @@ -1771,7 +1798,8 @@
lay.arrow = look.arrow
lay.arrowX = listX1 + metrics.rowPad * 5 + floor(font:GetTextWidth(row.label) * metrics.rowFs) + metrics.rowPad * 2
else
lay.text = colorAction .. text.fit(font, row.label, keyAreaX1 - (listX1 + metrics.rowPad) - metrics.rowPad, metrics.rowFs)
local labelW = keyAreaX1 - (listX1 + metrics.rowPad) - metrics.rowPad
lay.text = colorAction .. text.fit(font, row.label, labelW, metrics.rowFs)
local mets, cx, addW, rightGap = rowChipBand(row.action, metrics.rowFs, metrics.rowPad)
for i = 1, #mets do
local m = mets[i]
Expand Down Expand Up @@ -1941,15 +1969,32 @@
return cx, cy, cx + cell, cy + cell
end

-- Through FlowUI's Button so these carry the same border, gloss and corner as every other
-- button in the UI. It serves a repeated draw from a display-list cache; the cached form
-- was checked against the immediate one and is identical, so a button does not change as
-- the cache takes over.
local function drawButtonFace(r, base)
RectRound(r[1], r[2], r[3], r[4], metrics.csButton, 1, 1, 1, 1, base, base)
RectRound(r[1], r[2], r[3], (r[2] + r[4]) * 0.5, metrics.csButton, 0, 0, 1, 1, sheenTop, sheenNone)
local pair = look.gradients[base]

UiButton(r[1], r[2], r[3], r[4], 1, 1, 1, 1, 1, 1, 1, 1, nil, pair[1], pair[2])
end

-- The category column: its own card under the title, then one entry per category, with
-- hoverIdx the entry under the cursor.
local function drawSidebar(hoverIdx)
RectRound(area.x1, area.y1, area.x1 + sidebarW, area.y2 - floor(33 * scale), metrics.csPanel, 1, 1, 1, 1, look.sidebarFill, look.sidebarFillTop)
RectRound(
area.x1,
area.y1,
area.x1 + sidebarW,
area.y2 - floor(33 * scale),
metrics.csPanel,
1,
1,
1,
1,
look.sidebarFill,
look.sidebarFillTop
)
queueText(L.titleText, area.x1 + metrics.sidePad, area.y2 - floor(17 * scale), floor(rowHeight * 0.85), "ov")

-- Laid out before the font existed, so the labels are still waiting to be fitted.
Expand All @@ -1968,7 +2013,7 @@
elseif i == hoverIdx then
Highlight(x1 + metrics.catInset, y1, x2 - metrics.catInset, y2, metrics.csSmall, look.rowHoverOpacity, look.white)
end
queueText((selected and c.textSel or c.textDim) or c.label, x1 + metrics.sidePad, (y1 + y2) * 0.5, fs, "ov")
queueText((selected and c.textSel or c.textDim) or c.label, x1 + metrics.sidePad, (y1 + y2) * 0.5, fs*0.85, "ov")

Check failure on line 2016 in luaui/Include/keybind_editor_view.lua

View workflow job for this annotation

GitHub Actions / stylua

Not formatted

7 line(s) would change. Run stylua 2.5.2 on this file and commit the result.
end
end
end
Expand Down Expand Up @@ -2212,8 +2257,9 @@

if lay.showAdd then
local cx = lay.cx
RectRound(cx, c1, cx + lay.addW, c2, metrics.csSmall, 1, 1, 1, 1, zone == "add" and look.addFillHover or look.addFill)
queueText(look.plusText, (cx + cx + lay.addW) * 0.5, cyc, fs, "cov")
local overAdd = zone == "add"
RectRound(cx, c1, cx + lay.addW, c2, metrics.csSmall, 1, 1, 1, 1, overAdd and look.addFillHover or look.addFill)
queueText(overAdd and look.plusTextHover or look.plusText, (cx + cx + lay.addW) * 0.5, cyc, fs, "cov")
end
end

Expand Down Expand Up @@ -2417,10 +2463,6 @@
-- A tinted button loses its colour under the usual white hover overlay, so it
-- brightens its own fill instead.
local fill = b.fill and ((not enabled and b.fillMuted) or (hovered and b.fillHover) or b.fill)
-- Drawn here rather than through Draw.Button: that caches each distinct button
-- into a display list compiled mid-frame on a budget, and the immediate and
-- replayed forms do not match, so a button sized to its own label visibly
-- alternates between them.
drawButtonFace(r, fill or buttonFill)

if b.icon then
Expand Down
4 changes: 2 additions & 2 deletions luaui/Widgets/gui_keybind_info.lua
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,8 @@ local doUpdate

local vsx, vsy = spGetViewGeometry()

local screenHeightOrg = 760
local screenWidthOrg = 1180
local screenHeightOrg = 640
local screenWidthOrg = 1100
local screenHeight = screenHeightOrg
local screenWidth = screenWidthOrg

Expand Down
2 changes: 1 addition & 1 deletion recoil-lua-library
Loading