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. |
212 | function TableElement:copyAttributes(src) |
213 | TableElement:superClass().copyAttributes(self, src); |
214 | |
215 | self.columnNames = src.columnNames; |
216 | self.rowTemplateName = src.rowTemplateName; |
217 | self.navigationMode = src.navigationMode; |
218 | |
219 | self.periodicUpdate = src.periodicUpdate; |
220 | self.updateInterval = src.updateInterval; |
221 | |
222 | self.markRows = src.markRows; |
223 | |
224 | self.onUpdateCallback = src.onUpdateCallback; |
225 | |
226 | self.lateInitialization = src.lateInitialization; |
227 | self.isInitialized = src.isInitialized; -- copy initialization flag for cloned tables |
228 | end |
242 | function TableElement:initialize() |
243 | if not self.isInitialized then |
244 | -- find and store headers, start search at parent (headers must be defined outside of table) |
245 | local onlyMyHeaders = function(element) |
246 | return element.targetTableId and element.targetTableId == self.id |
247 | end; |
248 | self.headersList = self.parent:getDescendants(onlyMyHeaders) |
249 | |
250 | -- populate reverse hash of header list |
251 | for i, header in ipairs(self.headersList) do |
252 | self.headersHash[header] = i |
253 | end; |
254 | |
255 | self:buildTableRows() |
256 | self:applyAlternatingBackgroundsToRows() |
257 | |
258 | -- invalidate layout to position row elements |
259 | self:invalidateLayout() |
260 | end |
261 | |
262 | self.isInitialized = true |
263 | end |
172 | function TableElement:loadFromXML(xmlFile, key) |
173 | TableElement:superClass().loadFromXML(self, xmlFile, key); |
174 | |
175 | local colNames = Utils.getNoNil(getXMLString(xmlFile, key.."#columnNames"), ""); |
176 | for i, name in ipairs(StringUtil.splitString(" ", colNames)) do |
177 | self.columnNames[name] = name; -- make it a hash set |
178 | end; |
179 | |
180 | self.rowTemplateName = Utils.getNoNil(getXMLString(xmlFile, key.."#rowTemplateName"), self.rowTemplateName); |
181 | local navMode = getXMLString(xmlFile, key.."#navigationMode") or self.navigationMode; |
182 | self.navigationMode = NAV_MODES[navMode] or self.navigationMode; |
183 | |
184 | self.periodicUpdate = Utils.getNoNil(getXMLBool(xmlFile, key.."#periodicUpdate"), self.periodicUpdate); |
185 | local updateSeconds = Utils.getNoNil(getXMLFloat(xmlFile, key.."#updateInterval"), self.updateInterval / 1000); |
186 | self.updateInterval = updateSeconds * 1000; -- convert to ms |
187 | |
188 | self.markRows = Utils.getNoNil(getXMLBool(xmlFile, key.."#markRows"), self.markRows); |
189 | self.lateInitialization = Utils.getNoNil(getXMLBool(xmlFile, key.."#lateInitialization"), self.lateInitialization); |
190 | |
191 | self:addCallback(xmlFile, key.."#onUpdate", "onUpdateCallback"); |
192 | end |
196 | function TableElement:loadProfile(profile, applyProfile) |
197 | TableElement:superClass().loadProfile(self, profile, applyProfile); |
198 | |
199 | local navMode = profile:getValue("navigationMode", self.navigationMode); |
200 | self.navigationMode = NAV_MODES[navMode] or self.navigationMode; |
201 | |
202 | self.periodicUpdate = profile:getBool("periodicUpdate", self.periodicUpdate); |
203 | local updateSeconds = profile:getNumber("updateInterval", self.updateInterval / 1000); |
204 | self.updateInterval = updateSeconds * 1000; -- convert to ms |
205 | |
206 | self.markRows = profile:getBool("markRows", self.markRows); |
207 | self.lateInitialization = profile:getBool("lateInitialization", self.lateInitialization); |
208 | end |
125 | function TableElement:new(target, custom_mt) |
126 | if custom_mt == nil then |
127 | custom_mt = TableElement_mt; |
128 | end; |
129 | local self = ListElement:new(target, custom_mt); |
130 | |
131 | -- override defaults from ListElement |
132 | self.doesFocusScrollList = true; |
133 | self.isHorizontalList = false; |
134 | self.useSelectionOnLeave = false; |
135 | self.updateSelectionOnOpen = true; |
136 | |
137 | self.periodicUpdate = false; |
138 | self.updateInterval = 5000; -- update interval, internally stored as ms |
139 | self.timeSinceLastUpdate = 0; |
140 | self.timeSinceLastInput = 0; -- ms since last scrolling action, if this exceeds a threshold, allow automatic refocusing on selected table item |
141 | self.columnNames = {}; |
142 | self.rowTemplateName = ""; -- Name of row template |
143 | self.markRows = true; |
144 | |
145 | self.headersList = {}; -- ordered TableHeaderElement references |
146 | self.headersHash = {}; -- reverse mapping of headersList |
147 | |
148 | -- sort state fields for intermittent invalidate calls outside of onClickHeader(): |
149 | self.sortingOrder = TableHeaderElement.SORTING_OFF; |
150 | self.sortingColumn = nil; |
151 | self.sortingAscending = false; |
152 | |
153 | self.customSortFunction = nil |
154 | self.customSortBeforeData = false |
155 | self.customSortIsFilter = false |
156 | |
157 | self.data = {}; -- stores table data in the format given by the table's row template, using element names as keys if defined |
158 | self.tableRows = {}; -- visible GUI element rows of the table, replicated from a template |
159 | self.dataView = {}; -- same as self.data but using ordered integer keys instead of arbitrary row identifiers |
160 | self.selectedId = ""; -- currently selected row ID, separate from selected index |
161 | |
162 | self.navigationMode = TableElement.NAV_MODE_ROWS; |
163 | |
164 | self.lateInitialization = false; |
165 | self.isInitialized = false -- intialization flag |
166 | |
167 | return self; |
168 | end |
1092 | function TableElement:update(dt) |
1093 | TableElement:superClass().update(self, dt); |
1094 | |
1095 | self.timeSinceLastInput = self.timeSinceLastInput + dt; |
1096 | |
1097 | if self.periodicUpdate then |
1098 | self.timeSinceLastUpdate = self.timeSinceLastUpdate + dt; |
1099 | if self.timeSinceLastUpdate >= self.updateInterval then |
1100 | self:raiseCallback("onUpdateCallback", self); |
1101 | self.timeSinceLastUpdate = 0; |
1102 | end; |
1103 | end; |
1104 | end |
851 | function TableElement:updateRowSelection() |
852 | local selectedTableRowIndex = 0; |
853 | if self.selectedIndex ~= 0 and #self.dataView > 0 then |
854 | for i, tableRow in ipairs(self.tableRows) do |
855 | local selected = self.selectedIndex == tableRow.dataRowIndex and self.markRows; |
856 | if tableRow.rowElement.setSelected then |
857 | tableRow.rowElement:setSelected(selected); |
858 | end; |
859 | if selected then |
860 | selectedTableRowIndex = i; |
861 | end; |
862 | end; |
863 | end; |
864 | return selectedTableRowIndex; |
865 | end |