Script v1.7.1.0
- AI
- Animals
- Contracts
- Debug
- Economy
- Effects
- Events
- Farms
- GUI
- AnimalScreen
- AnimationElement
- BitmapElement
- BoxLayoutElement
- BreadcrumbsElement
- ButtonElement
- ButtonOverlay
- ChatWindow
- CheckedOptionElement
- ClearElement
- ContextActionDisplay
- DialogElement
- FieldInfoDisplay
- FillLevelsDisplay
- FlowLayoutElement
- FocusManager
- FrameElement
- FrameReferenceElement
- GameInfoDisplay
- GamePausedDisplay
- Gui
- GuiDataSource
- GuiElement
- GuiMixin
- GuiOverlay
- GuiProfile
- GuiSoundPlayer
- GuiTopDownCamera
- GuiUtils
- HUDDisplayElement
- HUDElement
- HUDFrameElement
- HUDPopupMessage
- HUDTextDisplay
- IndexChangeSubjectMixin
- IndexStateElement
- InGameIcon
- IngameMap
- IngameMapElement
- InputGlyphElement
- InputHelpDisplay
- ListElement
- ListItemElement
- MapHotspot
- MapOverlayGenerator
- MixerWagonHUDExtension
- MultiTextOptionElement
- MultiValueTween
- Overlay
- PagingElement
- PlaySampleMixin
- RenderElement
- RoundStatusBar
- ScreenElement
- SettingsModel
- SideNotification
- SliderElement
- SpeakerDisplay
- SpeedMeterDisplay
- StableListElement
- StatusBar
- TabbedMenu
- TabbedMenuFrameElement
- TabbedMenuWithDetails
- TableElement
- TableHeaderElement
- TextElement
- TextInputElement
- TimerElement
- ToggleButtonElement
- TopNotification
- Tween
- TweenSequence
- VehicleHUDExtension
- VehicleSchemaDisplay
- VideoElement
- Handtools
- I3d
- Materials
- Misc
- Objects
- Placeables
- Player
- Shop
- Sounds
- Specializations
- Triggers
- Utils
- Vehicles
- Weather
Engine v1.7.1.0
- AI
- Animation
- Camera
- Entity
- Fillplanes
- General
- I3D
- Input
- Lighting
- Math
- Network
- Node
- Overlays
- Particle System
- Physics
- Rendering
- Scenegraph
- Shape
- Sound
- Spline
- String
- Terrain Detail
- Text Rendering
- Tire Track
- XML
- general
Foundation Reference
StableListElement
DescriptionDisplays variable data with a stable number of child elements, swapping data between existing elements as needed. Use this element instead of ListElement when the changing nature of underlying data requires regular visual updates, modifying the displayed list item count or when the performance cost of rebuilding a list becomes too high. Usage: A view which uses this list should provide a GuiDataSource instance via StableListElement:setDataSource() and an item assignment function via StableListElement:setAssignItemDataFunction() which uses a data item from the data source to change the view state of a list item. Whenever the data source is changed (or gets an external call to GuiDataSource:notifyChange(), this list will also be notified to change its focus state and any slider coupled to the list. A view should add itself as a listener to data source changes to then update this list's display by calling StableListElement:updateItemPositions(). The list display is not updated automatically to allow views to have full control over the timing of the update and to perform other actions around the view update in arbitrary order.Parent
ListElementXML Configuration Parameters
GuiElement#itemTemplateId | string ID of list item template which is replicated on creation as many times as visible items are configured. |
Functions
- addElement
- buildListItems
- clone
- copyAttributes
- delete
- getItemCount
- getSelectedDataIndex
- getSelectedElementIndex
- loadFromXML
- new
- notifyClick
- notifyDoubleClick
- onDataSourceChanged
- onGuiSetupFinished
- removeElement
- setAssignItemDataFunction
- setDataSource
- setSelectedIndex
- updateItemPositionsInRange
addElement
DescriptionDefinitionaddElement()Code
182 | function StableListElement:addElement(element) |
183 | if self.allowChildModification then |
184 | -- only support adding elements during initialization or deletion |
185 | StableListElement:superClass().addElement(self, element) |
186 | end |
187 | end |
buildListItems
DescriptionBuild the stable list items which are modified instead of rebuilt on each visual update.Definition
buildListItems()Code
93 | function StableListElement:buildListItems() |
94 | local itemTemplate = self:getDescendantById(self.itemTemplateId) |
95 | |
96 | if itemTemplate ~= nil then |
97 | self:removeElement(itemTemplate) |
98 | |
99 | self:deleteListItems() |
100 | self.selectedIndex = 0 -- set selection to zero to avoid updating it while creating elements |
101 | for i = 1, self.visibleItems do |
102 | local listItem = itemTemplate:clone() |
103 | self:addElement(listItem) |
104 | end |
105 | |
106 | itemTemplate:delete() |
107 | |
108 | -- run the parent class layout |
109 | StableListElement:superClass().updateItemPositionsInRange(self, 1, #self.elements) |
110 | else |
111 | g_logManager:devWarning("Cannot find StableListElement item template with ID '%s', check configuration.", self.itemTemplateId) |
112 | end |
113 | end |
clone
DescriptionCreate a deep copy clone of this StableListElement. Override from GuiElement to handle list element addition and layout in cloned element.Definition
clone(parent Target, includeId [optional,, suppressOnCreate [optional,)Arguments
parent | Target | parent element of the cloned element |
includeId | [optional, | default=false] If true, will also clone ID values |
suppressOnCreate | [optional, | default=false] If true, will not trigger the "onCreate" callback |
57 | function StableListElement:clone(parent, includeId, suppressOnCreate) |
58 | local cloned = StableListElement:superClass().clone(self, parent, includeId, suppressOnCreate) |
59 | -- apply alternating background profiles with a forced load to update list item aspect scaling |
60 | cloned:updateAlternatingBackground(true) |
61 | -- run the parent class layout on the clone |
62 | StableListElement:superClass().updateItemPositionsInRange(cloned, 1, #cloned.elements) |
63 | -- set the child modification flag after cloning, otherwise the list items cannot be added |
64 | cloned.allowChildModification = cloned.allowChildModification or self.allowChildModification |
65 | return cloned |
66 | end |
copyAttributes
DescriptionDefinitioncopyAttributes()Code
70 | function StableListElement:copyAttributes(src) |
71 | StableListElement:superClass().copyAttributes(self, src) |
72 | |
73 | self.dataSource = src.dataSource |
74 | self.assignItemDataFunction = src.assignItemDataFunction |
75 | |
76 | self.isLoaded = src.isLoaded |
77 | end |
delete
DescriptionDefinitiondelete()Code
117 | function StableListElement:delete() |
118 | self.allowChildModification = true -- enable removal of child elements |
119 | self.dataSource:removeChangeListener(self) |
120 | StableListElement:superClass().delete(self) |
121 | end |
getItemCount
DescriptionGet the number of list items in the list's data source.Definition
getItemCount()Return Values
Number | of | list items in data source |
142 | function StableListElement:getItemCount() |
143 | return self.dataSource:getCount() |
144 | end |
getSelectedDataIndex
DescriptionGet the index of the currently selected data item.Definition
getSelectedDataIndex()Code
148 | function StableListElement:getSelectedDataIndex() |
149 | return self.selectedIndex |
150 | end |
getSelectedElementIndex
DescriptionGet the currently selected list element's index. This shadows the parent's implementation to compensate for the different internal usage of self.selectedIndex.Definition
getSelectedElementIndex()Code
176 | function StableListElement:getSelectedElementIndex() |
177 | return self.selectedIndex - self.firstVisibleItem + 1 |
178 | end |
loadFromXML
DescriptionDefinitionloadFromXML()Code
45 | function StableListElement:loadFromXML(xmlFile, key) |
46 | StableListElement:superClass().loadFromXML(self, xmlFile, key) |
47 | |
48 | self.itemTemplateId = getXMLString(xmlFile, key .. "#itemTemplateId") or "" |
49 | end |
new
DescriptionDefinitionnew()Code
30 | function StableListElement:new(target, custom_mt) |
31 | local self = ListElement:new(target, custom_mt or StableListElement_mt) |
32 | self:include(IndexChangeSubjectMixin) -- add index change subject mixin for index state observers |
33 | |
34 | self.dataSource = GuiDataSource.EMPTY_SOURCE |
35 | self.assignItemDataFunction = NO_ASSIGNMENT_FUNCTION |
36 | self.allowChildModification = true |
37 | |
38 | self.isLoaded = false |
39 | |
40 | return self |
41 | end |
notifyClick
DescriptionDefinitionnotifyClick()Code
322 | function StableListElement:notifyClick(clickedElementIndex) |
323 | self:raiseCallback("onClickCallback", self.selectedIndex, self.elements[clickedElementIndex]) |
324 | end |
notifyDoubleClick
DescriptionDefinitionnotifyDoubleClick()Code
316 | function StableListElement:notifyDoubleClick(clickedElementIndex) |
317 | self:raiseCallback("onDoubleClickCallback", self.selectedIndex, self.elements[clickedElementIndex]) |
318 | end |
onDataSourceChanged
DescriptionCalled when the data source changes. Update list properties based on data source.Definition
onDataSourceChanged()Code
164 | function StableListElement:onDataSourceChanged() |
165 | self.handleFocus = self.dataSource:getCount() > 0 |
166 | self:raiseSliderUpdateEvent() |
167 | end |
onGuiSetupFinished
DescriptionDefinitiononGuiSetupFinished()Code
81 | function StableListElement:onGuiSetupFinished() |
82 | StableListElement:superClass().onGuiSetupFinished(self) |
83 | |
84 | if self.itemTemplateId ~= "" and not self.isLoaded then |
85 | self:buildListItems() |
86 | self.allowChildModification = false |
87 | self.isLoaded = true |
88 | end |
89 | end |
removeElement
DescriptionDefinitionremoveElement()Code
191 | function StableListElement:removeElement(element) |
192 | if self.allowChildModification then |
193 | -- only support removing elements during initialization or deletion |
194 | StableListElement:superClass().removeElement(self, element) |
195 | end |
196 | end |
setAssignItemDataFunction
DescriptionSet the reference to a data assignment function which takes data from a data source and applies it to list items. When updating this list's view, this function is run for each list element and assigns selected data according to the current view position.Definition
setAssignItemDataFunction(function assignItemDataFunction)Arguments
function | assignItemDataFunction | Assignment function, signature: function(guiElement, dataItem) |
157 | function StableListElement:setAssignItemDataFunction(assignItemDataFunction) |
158 | self.assignItemDataFunction = assignItemDataFunction or NO_ASSIGNMENT_FUNCTION |
159 | end |
setDataSource
DescriptionSet the data source for this list.Definition
setDataSource(table guiDataSource)Arguments
table | guiDataSource | GuiDataSource instance |
130 | function StableListElement:setDataSource(guiDataSource) |
131 | self.dataSource:removeChangeListener(self) |
132 | |
133 | self.dataSource = guiDataSource or GuiDataSource.EMPTY_SOURCE |
134 | self.dataSource:addChangeListener(self, self.onDataSourceChanged) |
135 | |
136 | self:raiseSliderUpdateEvent() |
137 | end |
setSelectedIndex
DescriptionSet the selected data index. Shadows parent ListElement implementation to work on the underlying data source.Definition
setSelectedIndex()Code
207 | function StableListElement:setSelectedIndex(index, forceChangeEvent, direction) |
208 | local numItems = self.dataSource:getCount() |
209 | local newIndex = MathUtil.clamp(index, 0, numItems) |
210 | |
211 | if newIndex ~= self.selectedIndex then |
212 | self.lastClickTime = nil |
213 | end |
214 | |
215 | -- skip non-selectable items |
216 | local nextItem = self.elements[newIndex - self.firstVisibleItem + 1] |
217 | |
218 | if nextItem ~= nil then |
219 | if nextItem.disabled or not nextItem.allowFocus then |
220 | -- check if any list item is selectable at all, otherwise we risk an endless recursion |
221 | local anySelectable = false |
222 | for _, element in pairs(self.elements) do |
223 | if not element.disabled and element.allowFocus then |
224 | anySelectable = true |
225 | break |
226 | end |
227 | end |
228 | |
229 | if anySelectable then |
230 | newIndex = newIndex + (direction or 1) |
231 | |
232 | -- If we can't, stay where we are |
233 | if newIndex > numItems or newIndex < 1 then |
234 | if newIndex == 0 then |
235 | -- make sure we are scrolled to the top |
236 | self:scrollTo(1) |
237 | end |
238 | |
239 | return |
240 | end |
241 | |
242 | -- Force no change when direction is explicitly absent (mouse clicks on an item) |
243 | if direction == 0 then |
244 | return |
245 | end |
246 | |
247 | return self:setSelectedIndex(newIndex, forceChangeEvent, direction or 1) |
248 | end |
249 | end |
250 | end |
251 | |
252 | local hasChanged = self.selectedIndex ~= newIndex |
253 | self.selectedIndex = newIndex |
254 | |
255 | local newFirstVisibleItem = self:calculateFirstVisibleItem(newIndex) |
256 | if hasChanged or newFirstVisibleItem ~= self.firstVisibleItem then |
257 | self:scrollTo(newFirstVisibleItem) |
258 | end |
259 | |
260 | if hasChanged and self.isLoaded or forceChangeEvent then |
261 | self:notifyIndexChange(newIndex, numItems) |
262 | self:raiseCallback("onSelectionChangedCallback", newIndex) |
263 | end |
264 | |
265 | self:applyElementSelection() |
266 | end |
updateItemPositionsInRange
DescriptionUpdate list items using data within the given range. Shadows ListElement parent's implementation with data-swapping instead of UI element moving.Definition
updateItemPositionsInRange()Code
271 | function StableListElement:updateItemPositionsInRange(startIndex, endIndex) |
272 | local topPos = self.size[2] - self.listItemStartYOffset - self.listItemHeight |
273 | local leftPos = self.listItemStartXOffset |
274 | |
275 | for i, element in pairs(self.elements) do |
276 | element:setVisible(false) |
277 | end |
278 | |
279 | local dataStartIndex = self.firstVisibleItem |
280 | local dataEndIndex = self.firstVisibleItem + (endIndex - startIndex) |
281 | local elementIndex = 1 |
282 | for _, dataEntry in self.dataSource:iterateRange(dataStartIndex, dataEndIndex) do |
283 | local element = self.elements[elementIndex] |
284 | if element == nil then |
285 | break |
286 | end |
287 | |
288 | element:reset() |
289 | element:setVisible(true) |
290 | element:fadeIn() |
291 | self.assignItemDataFunction(element, dataEntry) |
292 | |
293 | elementIndex = elementIndex + 1 |
294 | end |
295 | |
296 | if self.dataSource:getCount() > 0 then |
297 | self:updateAlternatingBackground() |
298 | |
299 | local selectedElement = self:getSelectedElement() |
300 | if selectedElement ~= nil and (selectedElement.disabled or not selectedElement.allowFocus) then |
301 | self:setSelectedIndex(self.selectedIndex) -- re-apply selection to be able to skip newly non-selectable items |
302 | end |
303 | |
304 | self:applyElementSelection() -- apply visual selection |
305 | |
306 | -- restore element positions after data and alternating background profile assignments |
307 | for i, element in ipairs(self.elements) do |
308 | local xPos, yPos = self:getItemPosition(leftPos, topPos, i - 1, element) |
309 | element:setPosition(xPos, yPos) |
310 | end |
311 | end |
312 | end |