GuiElement#rowTemplateName | string Element Name of row template. The template will be replicated to fill the table's view and then discarded during initialization. |
GuiElement#columnNames | string Whitespace-separated list of column names. Table child elements with the same name are considered to be data elements for those columns. |
GuiElement#periodicUpdate | bool [optional, default=false] If set to true, will update the row order periodically based on changed data. |
GuiElement#updateInterval | float [optional] Time in seconds inbetween table data updates. Only used if periodicUpdate is enabled. |
GuiElement#navigationMode | string [optional] Determines how navigation is handled when the table receives navigation input. Defaults to "rows". Valid values are "rows" and "cells" (individual cell navigation) |
GuiElement#markRows | bool [optional] If false, rows will not visually marked when they are selected. |
GuiElement#lateInitialization | bool [optional] If true, the table requires an explicit call to initialize() before usage. This is necessary whenever the table is used as a template. |
GuiElement#onUpdate | callback [optional] onUpdate(self, state): Callback for periodic updates, sends the TableElement instance as the only argument. |
217 | function TableElement:copyAttributes(src) |
218 | TableElement:superClass().copyAttributes(self, src) |
219 | |
220 | self.columnNames = src.columnNames |
221 | self.rowTemplateName = src.rowTemplateName |
222 | self.navigationMode = src.navigationMode |
223 | |
224 | self.periodicUpdate = src.periodicUpdate |
225 | self.updateInterval = src.updateInterval |
226 | |
227 | self.markRows = src.markRows |
228 | |
229 | self.onUpdateCallback = src.onUpdateCallback |
230 | |
231 | self.lateInitialization = src.lateInitialization |
232 | self.isInitialized = src.isInitialized -- copy initialization flag for cloned tables |
233 | end |
247 | function TableElement:initialize() |
248 | if not self.isInitialized then |
249 | -- find and store headers, start search at parent (headers must be defined outside of table) |
250 | local onlyMyHeaders = function(element) |
251 | return element.targetTableId and element.targetTableId == self.id |
252 | end |
253 | self.headersList = self.parent:getDescendants(onlyMyHeaders) |
254 | |
255 | -- populate reverse hash of header list |
256 | for i, header in ipairs(self.headersList) do |
257 | self.headersHash[header] = i |
258 | end |
259 | |
260 | self:buildTableRows() |
261 | self:applyAlternatingBackgroundsToRows() |
262 | |
263 | -- invalidate layout to position row elements |
264 | self:invalidateLayout() |
265 | end |
266 | |
267 | self.isInitialized = true |
268 | end |
177 | function TableElement:loadFromXML(xmlFile, key) |
178 | TableElement:superClass().loadFromXML(self, xmlFile, key) |
179 | |
180 | local colNames = Utils.getNoNil(getXMLString(xmlFile, key.."#columnNames"), "") |
181 | for i, name in ipairs(colNames:split(" ")) do |
182 | self.columnNames[name] = name -- make it a hash set |
183 | end |
184 | |
185 | self.rowTemplateName = Utils.getNoNil(getXMLString(xmlFile, key.."#rowTemplateName"), self.rowTemplateName) |
186 | local navMode = getXMLString(xmlFile, key.."#navigationMode") or self.navigationMode |
187 | self.navigationMode = NAV_MODES[navMode] or self.navigationMode |
188 | |
189 | self.periodicUpdate = Utils.getNoNil(getXMLBool(xmlFile, key.."#periodicUpdate"), self.periodicUpdate) |
190 | local updateSeconds = Utils.getNoNil(getXMLFloat(xmlFile, key.."#updateInterval"), self.updateInterval / 1000) |
191 | self.updateInterval = updateSeconds * 1000 -- convert to ms |
192 | |
193 | self.markRows = Utils.getNoNil(getXMLBool(xmlFile, key.."#markRows"), self.markRows) |
194 | self.lateInitialization = Utils.getNoNil(getXMLBool(xmlFile, key.."#lateInitialization"), self.lateInitialization) |
195 | |
196 | self:addCallback(xmlFile, key.."#onUpdate", "onUpdateCallback") |
197 | end |
201 | function TableElement:loadProfile(profile, applyProfile) |
202 | TableElement:superClass().loadProfile(self, profile, applyProfile) |
203 | |
204 | local navMode = profile:getValue("navigationMode", self.navigationMode) |
205 | self.navigationMode = NAV_MODES[navMode] or self.navigationMode |
206 | |
207 | self.periodicUpdate = profile:getBool("periodicUpdate", self.periodicUpdate) |
208 | local updateSeconds = profile:getNumber("updateInterval", self.updateInterval / 1000) |
209 | self.updateInterval = updateSeconds * 1000 -- convert to ms |
210 | |
211 | self.markRows = profile:getBool("markRows", self.markRows) |
212 | self.lateInitialization = profile:getBool("lateInitialization", self.lateInitialization) |
213 | end |
128 | function TableElement.new(target, custom_mt) |
129 | if custom_mt == nil then |
130 | custom_mt = TableElement_mt |
131 | end |
132 | local self = ListElement.new(target, custom_mt) |
133 | |
134 | -- override defaults from ListElement |
135 | self.doesFocusScrollList = true |
136 | self.isHorizontalList = false |
137 | self.useSelectionOnLeave = false |
138 | self.updateSelectionOnOpen = true |
139 | |
140 | self.periodicUpdate = false |
141 | self.updateInterval = 5000 -- update interval, internally stored as ms |
142 | self.timeSinceLastUpdate = 0 |
143 | self.timeSinceLastInput = 0 -- ms since last scrolling action, if this exceeds a threshold, allow automatic refocusing on selected table item |
144 | self.columnNames = {} |
145 | self.rowTemplateName = "" -- Name of row template |
146 | self.markRows = true |
147 | |
148 | self.headersList = {} -- ordered TableHeaderElement references |
149 | self.headersHash = {} -- reverse mapping of headersList |
150 | |
151 | -- sort state fields for intermittent invalidate calls outside of onClickHeader(): |
152 | self.sortingOrder = TableHeaderElement.SORTING_OFF |
153 | self.sortingColumn = nil |
154 | self.sortingAscending = false |
155 | |
156 | self.numActiveRows = 0 |
157 | |
158 | self.customSortFunction = nil |
159 | self.customSortBeforeData = false |
160 | self.customSortIsFilter = false |
161 | |
162 | self.data = {} -- stores table data in the format given by the table's row template, using element names as keys if defined |
163 | self.tableRows = {} -- visible GUI element rows of the table, replicated from a template |
164 | self.dataView = {} -- same as self.data but using ordered integer keys instead of arbitrary row identifiers |
165 | self.selectedId = "" -- currently selected row ID, separate from selected index |
166 | |
167 | self.navigationMode = TableElement.NAV_MODE_ROWS |
168 | |
169 | self.lateInitialization = false |
170 | self.isInitialized = false -- intialization flag |
171 | |
172 | return self |
173 | end |
1144 | function TableElement:update(dt) |
1145 | TableElement:superClass().update(self, dt) |
1146 | |
1147 | self.timeSinceLastInput = self.timeSinceLastInput + dt |
1148 | |
1149 | if self.periodicUpdate then |
1150 | self.timeSinceLastUpdate = self.timeSinceLastUpdate + dt |
1151 | if self.timeSinceLastUpdate >= self.updateInterval then |
1152 | self:raiseCallback("onUpdateCallback", self) |
1153 | self.timeSinceLastUpdate = 0 |
1154 | end |
1155 | end |
1156 | end |
876 | function TableElement:updateRowSelection() |
877 | local selectedTableRowIndex = 0 |
878 | if self.selectedIndex ~= 0 and #self.dataView > 0 then |
879 | for i, tableRow in ipairs(self.tableRows) do |
880 | local selected = self.selectedIndex == tableRow.dataRowIndex and self.markRows |
881 | if tableRow.rowElement.setSelected then |
882 | tableRow.rowElement:setSelected(selected) |
883 | end |
884 | if selected then |
885 | selectedTableRowIndex = i |
886 | end |
887 | end |
888 | end |
889 | return selectedTableRowIndex |
890 | end |