Repository navigation
Expand file tree
/
Copy pathdisplay_utils.lua
More file actions
203 lines (171 loc) · 6.84 KB
/
Copy pathdisplay_utils.lua
File metadata and controls
203 lines (171 loc) · 6.84 KB
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
--- A simple library containing various display utilities.
local _expect = require "cc.expect"
local expect, field = _expect.expect, _expect.field
---@class display_utils-hfpb_options High Fidelity Percentage Bar Options
---@field x integer The X position of the left of the percentage bar.
---@field y integer The Y position of the top of the percentage bar.
---@field w integer The width of the percentage bar.
---@field h integer The height of the percentage bar.
---@field background ccTweaked.colors.color The color to be used for the unfilled parts of the bar.
---@field filled ccTweaked.colors.color The color to be used for the filled parts of the bar.
---@field current ccTweaked.colors.color The color to be used for the current fill position in the bar. This should be `value / max`.
---@field allow_overflow boolean? Whether or not to allow the bar to fill beyond its maximum point.
---@field win ccTweaked.term.Redirect? The window to render the bar to. If nil, renders to the terminal.
---@class display_utils-hfpb High Fidelity Percentage Bar
---@field x integer The X position of the left of the percentage bar.
---@field y integer The Y position of the top of the percentage bar.
---@field w integer The width of the percentage bar.
---@field h integer The height of the percentage bar.
---@field background ccTweaked.colors.color The color to be used for the unfilled parts of the bar.
---@field filled ccTweaked.colors.color The color to be used for the filled parts of the bar.
---@field current ccTweaked.colors.color The color to be used for the current fill position in the bar.
---@field percent number A value between 0 and 1 representing how full the bar should be. This should be `value / max`.
---@field allow_overflow boolean Whether or not to allow the bar to fill beyond its maximum point.
---@field win ccTweaked.term.Redirect? The window to render the bar to.
---@field draw fun() Draw this percent bar.
local half_char = '\x95'
local BLIT_CONVERT = {
[1] = '0',
[2] = '1',
[4] = '2',
[8] = '3',
[16] = '4',
[32] = '5',
[64] = '6',
[128] = '7',
[256] = '8',
[512] = '9',
[1024] = 'a',
[2048] = 'b',
[4096] = 'c',
[8192] = 'd',
[16384] = 'e',
[32768] = 'f',
}
---@class display_utils-display_utils
local dutil = {}
--- Create a percentage bar which uses drawing characters to be higher fidelity.
---@param options display_utils-hfpb_options The options for the percentage bar.
---@return display_utils-hfpb percent_bar The bar object. Use .Draw() to draw this.
function dutil.high_fidelity_percent_bar(options, win)
expect(1, options, "table")
field(options, "x", "number")
field(options, "y", "number")
field(options, "w", "number")
field(options, "h", "number")
field(options, "background", "number")
field(options, "filled", "number")
field(options, "current", "number")
field(options, "allow_overflow", "boolean", "nil")
field(options, "win", "table", "nil")
-- woah, this is one easy bodge.
local term = options.win or term
local bar = {
x = options.x,
y = options.y,
w = options.w,
h = options.h,
background = options.background,
filled = options.filled,
current = options.current,
allow_overflow = options.allow_overflow or false,
percent = 0,
win = term,
}
local function replace_char_at(str, x, new)
if x <= 1 then
return new .. str:sub(2)
elseif x == #str then
return str:sub(1, -2) .. new
elseif x > #str then
return str
end
return str:sub(1, x - 1) .. new .. str:sub(x + 1)
end
function bar.draw()
local fill = math.floor(bar.percent * (bar.w * 2) + 0.5) -- this should mark how many half_chars are needed
if not bar.allow_overflow then
fill = math.min(bar.w * 2, fill)
end
local first_half = fill % 2 == 1
local zero = fill == 0
fill = math.floor(fill / 2 + 0.5)
local fill_str = string.rep(' ', bar.w)
local bg = BLIT_CONVERT[bar.filled]:rep(fill) .. BLIT_CONVERT[bar.background]:rep(bar.w - fill)
local txt = BLIT_CONVERT[bar.filled]:rep(bar.w)
if not zero then
if first_half then
fill_str = replace_char_at(fill_str, fill, half_char)
txt = replace_char_at(txt, fill, BLIT_CONVERT[bar.current])
bg = replace_char_at(bg, fill, BLIT_CONVERT[bar.background])
else -- second half
fill_str = replace_char_at(fill_str, fill, half_char)
bg = replace_char_at(bg, fill, BLIT_CONVERT[bar.current])
end
end
if #txt ~= #bg or #bg ~= #fill_str or #txt ~= bar.w then
printError("Incorrect lengths for writing bar:", #fill_str, #txt, #bg, bar.w)
print((" \"%s\""):format(fill_str))
print((" \"%s\""):format(txt))
print((" \"%s\""):format(bg))
error("", 0)
end
for y = bar.y, bar.y + bar.h - 1 do
term.setCursorPos(bar.x, y)
term.blit(fill_str, txt, bg)
end
end
return bar --[[@as display_utils-hfpb]]
end
--- Create a box filled with color.
---@param x integer The X position of the top left of the box.
---@param y integer The Y position of the top left of the box.
---@param w integer The width of the box.
---@param h integer The height of the box.
---@param color ccTweaked.colors.color The color of the box.
---@param char string? The character to be drawn. Defaults to a space.
---@param text_color ccTweaked.colors.color? The text color to be used (useful if using `char`).
---@param win ccTweaked.term.Redirect? The window to render the box to. If nil, renders to the terminal.
function dutil.fast_box(x, y, w, h, color, char, text_color, win)
expect(1, x, "number")
expect(2, y, "number")
expect(3, w, "number")
expect(4, h, "number")
expect(5, color, "number")
expect(6, char, "string", "nil")
expect(7, text_color, "number", "nil")
expect(8, win, "table", "nil")
local term = win or term
local txt = (char or ' '):rep(w)
local fg = (text_color and BLIT_CONVERT[text_color] or 'f'):rep(w)
local bg = BLIT_CONVERT[color]:rep(w)
for _y = y, y + h - 1 do
term.setCursorPos(x, _y)
term.blit(txt, fg, bg)
end
end
--- Write text centered at the given position, or centered on the current terminal line.
---@param text string The text to be written.
---@param x integer? The x position to write at.
---@param y integer? The y position to write at.
---@param win ccTweaked.term.Redirect? The window to write to. If nil, writes to the terminal.
function dutil.write_centered(text, x, y, win)
expect(1, text, "string")
if x then
expect(2, x, "number")
expect(3, y, "number")
end
expect(4, win, "table", "nil")
local term = win or term
if not x then
local w = term.getSize()
local _, _y = term.getCursorPos()
y = _y
x = w / 2 -- Don't round here - we may add up .5 and .5 later.
end
---@cast y number Confirmed a number at this point.
local start_x = math.ceil(x - #text / 2)
term.setCursorPos(start_x, y)
term.write(text)
end
return dutil