@@ -9,6 +9,7 @@ local t_insert = table.insert
9
9
local RowListClass = newClass (" RowListControl" , " ListControl" , function (self , anchor , rect )
10
10
self .ListControl (anchor , rect , 14 , " HORIZONTAL" , false , { })
11
11
self .colLabels = true
12
+ self ._autoSizeToggleState = {} -- internal toggle memory, not saved to spec
12
13
end )
13
14
14
15
function RowListClass :BuildRows (filter )
44
45
45
46
function RowListClass :BuildColumns ()
46
47
wipeTable (self .colList )
47
- self .colList [1 ] = { width = 50 , label = " #" , font = " FIXED" }
48
+ self .colList [1 ] = { width = 50 , label = " #" , font = " FIXED" , sortable = true }
48
49
for _ , specCol in ipairs (main .curDatFile .spec ) do
49
- t_insert (self .colList , { width = specCol .width , label = specCol .name , font = function () return IsKeyDown (" CTRL" ) and " FIXED" or " VAR" end })
50
+ t_insert (self .colList , {
51
+ width = specCol .width ,
52
+ specColRef = specCol , -- Link to the original data
53
+ label = specCol .name ,
54
+ font = function () return IsKeyDown (" ALT" ) and " FIXED" or " VAR" end ,
55
+ sortable = true
56
+ })
50
57
end
51
58
local short = main .curDatFile .rowSize - main .curDatFile .specSize
52
59
if short > 0 then
53
- t_insert (self .colList , { width = short * DrawStringWidth (self .rowHeight , " FIXED" , " 00 " ), font = " FIXED" })
60
+ t_insert (self .colList , { width = short * DrawStringWidth (self .rowHeight , " FIXED" , " 00 " ), font = " FIXED" , sortable = true })
54
61
end
55
62
end
56
63
57
64
function RowListClass :GetRowValue (column , index , row )
58
65
if column == 1 then
59
66
return string.format (" %5d" , row )
60
67
end
61
- if not main .curDatFile .spec [column - 1 ] or IsKeyDown (" CTRL " ) then
68
+ if not main .curDatFile .spec [column - 1 ] or IsKeyDown (" ALT " ) then
62
69
local out = { main .curDatFile :ReadCellRaw (row , column - 1 ) }
63
70
for i , b in ipairs (out ) do
64
71
out [i ] = string.format (" %02X" , b )
@@ -76,3 +83,280 @@ function RowListClass:GetRowValue(column, index, row)
76
83
end
77
84
end
78
85
end
86
+
87
+ function RowListClass :Draw (viewPort )
88
+ local x , y = self :GetPos ()
89
+ local width , height = self :GetSize ()
90
+ local rowHeight = self .rowHeight
91
+ local list = self .list
92
+
93
+ local colOffset = 0
94
+ for index , column in ipairs (self .colList ) do
95
+ column ._offset = colOffset
96
+ column ._width = self :GetColumnProperty (column , " width" ) or (index == # self .colList and self .scroll and width - 20 or width - colOffset ) or 0
97
+ colOffset = colOffset + column ._width
98
+ end
99
+
100
+ local scrollBarV = self .controls .scrollBarV
101
+ local rowRegion = self :GetRowRegion ()
102
+ scrollBarV :SetContentDimension (# list * rowHeight , rowRegion .height )
103
+ local scrollOffsetV = scrollBarV .offset
104
+ local scrollBarH = self .controls .scrollBarH
105
+ local lastCol = self .colList [# self .colList ]
106
+ scrollBarH :SetContentDimension (lastCol ._offset + lastCol ._width , rowRegion .width )
107
+ local scrollOffsetH = scrollBarH .offset
108
+
109
+ local cursorX , cursorY = GetCursorPos ()
110
+
111
+ local label = self :GetProperty (" label" )
112
+ if label then
113
+ DrawString (x + self .labelPositionOffset [1 ], y - 20 + self .labelPositionOffset [2 ], " LEFT" , 16 , self .font , label )
114
+ end
115
+ if self .hasFocus then
116
+ SetDrawColor (1 , 1 , 1 )
117
+ else
118
+ SetDrawColor (0.5 , 0.5 , 0.5 )
119
+ end
120
+ DrawImage (nil , x , y , width , height )
121
+ SetDrawColor (0 , 0 , 0 )
122
+ DrawImage (nil , x + 1 , y + 1 , width - 2 , height - 2 )
123
+ self :DrawControls (viewPort )
124
+
125
+ SetViewport (x + 2 , y + 2 , self .scroll and width - 20 or width , height - 4 - (self .scroll and self .scrollH and 16 or 0 ))
126
+ local textOffsetY = self .showRowSeparators and 2 or 0
127
+ local textHeight = rowHeight - textOffsetY * 2
128
+ local minIndex = math.floor (scrollOffsetV / rowHeight + 1 )
129
+ local maxIndex = math.min (math.floor ((scrollOffsetV + height ) / rowHeight + 1 ), # list )
130
+ for colIndex , column in ipairs (self .colList ) do
131
+ local colFont = self :GetColumnProperty (column , " font" ) or " VAR"
132
+ local clipWidth = DrawStringWidth (textHeight , colFont , " ..." )
133
+ colOffset = column ._offset - scrollOffsetH
134
+ local colWidth = column ._width
135
+ local relX = cursorX - (x + 2 )
136
+ local relY = cursorY - (y + 2 )
137
+ for index = minIndex , maxIndex do
138
+ local lineY = rowHeight * (index - 1 ) - scrollOffsetV + (self .colLabels and 18 or 0 )
139
+ local value = list [index ]
140
+ local text = self :GetRowValue (colIndex , index , value )
141
+ local textWidth = DrawStringWidth (textHeight , colFont , text )
142
+ if textWidth > colWidth - 2 then
143
+ local clipIndex = DrawStringCursorIndex (textHeight , colFont , text , colWidth - clipWidth - 2 , 0 )
144
+ text = text :sub (1 , clipIndex - 1 ) .. " ..."
145
+ textWidth = DrawStringWidth (textHeight , colFont , text )
146
+ end
147
+ if self .showRowSeparators then
148
+ if self .hasFocus and value == self .selValue then
149
+ SetDrawColor (1 , 1 , 1 )
150
+ else
151
+ SetDrawColor (0.5 , 0.5 , 0.5 )
152
+ end
153
+ DrawImage (nil , colOffset , lineY , not self .scroll and colWidth - 4 or colWidth , rowHeight )
154
+ if index % 2 == 0 then
155
+ SetDrawColor (0.05 , 0.05 , 0.05 )
156
+ else
157
+ SetDrawColor (0 , 0 , 0 )
158
+ end
159
+ DrawImage (nil , colOffset , lineY + 1 , not self .scroll and colWidth - 4 or colWidth , rowHeight - 2 )
160
+ elseif value == self .selValue then
161
+ if self .hasFocus and value == self .selValue then
162
+ SetDrawColor (1 , 1 , 1 )
163
+ else
164
+ SetDrawColor (0.5 , 0.5 , 0.5 )
165
+ end
166
+ DrawImage (nil , colOffset , lineY , not self .scroll and colWidth - 4 or colWidth , rowHeight )
167
+ SetDrawColor (0.15 , 0.15 , 0.15 )
168
+ DrawImage (nil , colOffset , lineY + 1 , not self .scroll and colWidth - 4 or colWidth , rowHeight - 2 )
169
+ end
170
+ if not self .SetHighlightColor or not self :SetHighlightColor (index , value ) then
171
+ SetDrawColor (1 , 1 , 1 )
172
+ end
173
+ DrawString (colOffset , lineY + textOffsetY , " LEFT" , textHeight , colFont , text )
174
+ end
175
+ if self .colLabels then
176
+ local mOver = relX >= colOffset and relX <= colOffset + colWidth and relY >= 0 and relY <= 18
177
+
178
+ local isSelected = (colIndex - 1 ) == main .curSpecColIndex
179
+ local outerColor
180
+ if mOver then
181
+ outerColor = {1 , 1 , 1 }
182
+ elseif isSelected then
183
+ outerColor = {1 , 0.3 , 0.2 }
184
+ else
185
+ outerColor = {0.5 , 0.5 , 0.5 }
186
+ end
187
+ local innerColor = isSelected and {0.6 , 0.25 , 0.2 } or (mOver and self :GetColumnProperty (column , " sortable" ) and {0.33 , 0.33 , 0.33 } or {0.15 , 0.15 , 0.15 })
188
+
189
+ SetDrawColor (unpack (outerColor ))
190
+ DrawImage (nil , colOffset , 1 , colWidth , 18 )
191
+ SetDrawColor (unpack (innerColor ))
192
+ DrawImage (nil , colOffset + 1 , 2 , colWidth - 2 , 16 )
193
+
194
+ local label = self :GetColumnProperty (column , " label" )
195
+ if label and # label > 0 then
196
+ SetDrawColor (1 , 1 , 1 )
197
+ DrawString (colOffset + colWidth / 2 , 4 , " CENTER_X" , 12 , " VAR" , label )
198
+ end
199
+ end
200
+ end
201
+ if # self .list == 0 and self .defaultText then
202
+ SetDrawColor (1 , 1 , 1 )
203
+ DrawString (2 , 2 , " LEFT" , 14 , self .font , self .defaultText )
204
+ end
205
+ SetViewport ()
206
+ end
207
+
208
+ function RowListClass :ReSort (colIndex )
209
+ local asc = true
210
+ if self .lastSortedCol == colIndex then
211
+ asc = not self .sortAsc
212
+ end
213
+
214
+ table.sort (self .list , function (a , b )
215
+ local valA = self :GetRowValue (colIndex , nil , a )
216
+ local valB = self :GetRowValue (colIndex , nil , b )
217
+
218
+ local isBlankA = valA == nil or valA == " " or tostring (valA ):match (" ^%s*$" )
219
+ local isBlankB = valB == nil or valB == " " or tostring (valB ):match (" ^%s*$" )
220
+
221
+ -- Always put blank items at the bottom
222
+ if isBlankA and not isBlankB then
223
+ return false
224
+ elseif not isBlankA and isBlankB then
225
+ return true
226
+ elseif isBlankA and isBlankB then
227
+ return false
228
+ end
229
+
230
+ local numA = tonumber (valA )
231
+ local numB = tonumber (valB )
232
+
233
+ if numA and numB then
234
+ if asc then
235
+ return numA < numB
236
+ else
237
+ return numA > numB
238
+ end
239
+ else
240
+ valA = tostring (valA or " " )
241
+ valB = tostring (valB or " " )
242
+ if asc then
243
+ return valA < valB
244
+ else
245
+ return valA > valB
246
+ end
247
+ end
248
+ end )
249
+
250
+ self .lastSortedCol = colIndex
251
+ self .sortAsc = asc
252
+ end
253
+
254
+ function RowListClass :OnKeyUp (key , doubleClick )
255
+ if not self :IsShown () or not self :IsEnabled () then
256
+ return
257
+ end
258
+
259
+ local function isScrollKey (k )
260
+ if k == " WHEELUP" then return true , - 1 , 10 end
261
+ if k == " WHEELDOWN" then return true , 1 , - 10 end
262
+ return false , 0 , 0
263
+ end
264
+
265
+ local mOverControl = self :GetMouseOverControl ()
266
+ if mOverControl and mOverControl .OnKeyDown then
267
+ return mOverControl :OnKeyDown (key )
268
+ end
269
+
270
+ if not self :IsMouseOver () and key :match (" BUTTON" ) then
271
+ return
272
+ end
273
+
274
+ -- Get cursor info
275
+ local x , y = self :GetPos ()
276
+ local cursorX , cursorY = GetCursorPos ()
277
+ local scrollOffsetH = self .controls .scrollBarH and self .controls .scrollBarH .offset or 0
278
+ local relX = cursorX - (x + 2 )
279
+ local relY = cursorY - (y + 2 )
280
+ local adjustedRelX = relX + scrollOffsetH
281
+
282
+ -- Middle-click resets column width
283
+ if key == " MIDDLEBUTTON" then
284
+ for colIndex , column in ipairs (self .colList ) do
285
+ local colOffset = column ._offset
286
+ local colWidth = column .width or column ._width
287
+ if colOffset and colWidth then
288
+ local mOver = adjustedRelX >= colOffset and adjustedRelX <= colOffset + colWidth and relY >= 0 and relY <= 18
289
+ if mOver then
290
+ -- Initialize if not present
291
+ self ._autoSizeToggleState [colIndex ] = not self ._autoSizeToggleState [colIndex ]
292
+
293
+ local newWidth
294
+ if self ._autoSizeToggleState [colIndex ] then
295
+ -- First toggle: size to contents
296
+ local maxWidth = 0
297
+ for _ , rowIndex in ipairs (self .list ) do
298
+ local val = self :GetRowValue (colIndex , nil , rowIndex )
299
+ if val ~= nil then
300
+ local width = DrawStringWidth (self .rowHeight , " FIXED" , tostring (val ))
301
+ maxWidth = math.max (maxWidth , width )
302
+ end
303
+ end
304
+ local labelWidth = DrawStringWidth (self .rowHeight , " FIXED" , tostring (column .label or " " ))
305
+ newWidth = math.max (40 , math.max (maxWidth , labelWidth ) + 10 )
306
+ else
307
+ -- Second toggle: reset to label or 150, whichever is greater
308
+ local labelWidth = DrawStringWidth (self .rowHeight , " FIXED" , tostring (column .label or " " ))
309
+ newWidth = math.max (150 , labelWidth + 10 )
310
+ end
311
+
312
+ column .width = newWidth
313
+
314
+ if column .specColRef then
315
+ column .specColRef .width = newWidth
316
+ main .curSpecCol = column .specColRef
317
+ main .controls .colWidth :SetText (newWidth )
318
+ end
319
+
320
+ self :BuildColumns ()
321
+ return self
322
+ end
323
+ end
324
+ end
325
+ return self
326
+ end
327
+ -- Scroll behavior
328
+ local isScroll , scrollStep , colDelta = isScrollKey (key )
329
+ if isScroll then
330
+ local overColumnHeader = false
331
+ for _ , column in ipairs (self .colList ) do
332
+ local colOffset = column ._offset
333
+ local colWidth = column .width or column ._width
334
+ if colOffset and colWidth then
335
+ local mOver = adjustedRelX >= colOffset and adjustedRelX <= colOffset + colWidth and relY >= 0 and relY <= 18
336
+ if mOver then
337
+ -- Widen column if hovering over it
338
+ overColumnHeader = true
339
+ local newWidth = math.max (40 , colWidth + colDelta )
340
+ column .width = newWidth
341
+ if column .specColRef then
342
+ column .specColRef .width = newWidth
343
+ main .curSpecCol = column .specColRef
344
+ main .controls .colWidth :SetText (newWidth )
345
+ end
346
+ self :BuildColumns ()
347
+ break
348
+ end
349
+ end
350
+ end
351
+ -- Scroll vertically or horizontally if not resizing column
352
+ if not overColumnHeader then
353
+ if self .scroll and self .scrollH and IsKeyDown (" SHIFT" ) then
354
+ self .controls .scrollBarH :Scroll (scrollStep )
355
+ else
356
+ self .controls .scrollBarV :Scroll (scrollStep )
357
+ end
358
+ end
359
+ return self
360
+ end
361
+ return self
362
+ end
0 commit comments