GuiElement#focusScrollsList | bool [optional] If false, changing the current focus does not affect scrolling. |
GuiElement#updateSelectionOnOpen | bool [optional] If false, will not re-select the currently selected item when the list is opened. |
GuiElement#useSelectionOnLeave | bool [optional] If true, will force selection on the last selected list item when the list loses focus. |
GuiElement#selectOnScroll | bool [optional] If true, will move the current selection when scrolling. |
GuiElement#maxNumItems | int [optional] Maximum number of list items, defaults to no limit. Adding any more elements than this value will have no effect. |
GuiElement#doubleClickInterval | int [optional] Maximum time in milliseconds between consecutive clicks to interpret them as one double click. |
GuiElement#selectOnClick | bool [optional] If true, mouse clicks will only select a list item and not trigger the onClick callback. |
GuiElement#ignoreMouse | bool [optional] If true, will ignore all mouse interactions (clicking, scrolling) |
GuiElement#keepSelectedInView | bool [optional] If true, will make sure a selected item is always visible after scrolling |
GuiElement#isPaginated | bool [optional] If true, can scroll towards last item filling the screen with whitespace. If false, last item is always there if enough list items are available. |
GuiElement#itemsPerRow | int [optional] Number of items laid out horizontally per row, defaults to 1. |
GuiElement#itemsPerCol | int [optional] Number of items laid out vertically per column, defaults to 1. |
GuiElement#listItemStartXOffset | string [optional] Pixel X offset from this list's origin for list items, defaults to 0. Format: "[x]px" |
GuiElement#listItemStartYOffset | string [optional] Pixel Y offset from this list's origin for list items, defaults to 0. Format: "[y]px" |
GuiElement#listItemWidth | string [optional] Pixel width of list items in reference resolution. Format: "[width]px" |
GuiElement#listItemHeight | string [optional] Pixel height of list items in reference resolution. Format: "[height]px" |
GuiElement#listItemAutoSize | bool [optional, default=false] If true, will set listItemWidth and listItemHeight automatically to the dimensions of the first child ListElement instance. |
GuiElement#listItemPadding | string [optional] Pixel size of horizontal space between list items in reference resolution, defaults to 0. This space will be added after each item. Format: "[padding]px" |
GuiElement#listItemSpacing | string [optional] Pixel size of vertical space between list items in reference resolution, defaults to 0. This space will be added after each item. Format: "[spacing]px" |
GuiElement#rowBackgroundProfile | string [optional] Profile identifier for the default row background element. |
GuiElement#rowBackgroundProfileAlternate | string [optional] Profile identifier for an alternating row background element. If both this and rowBackgroundProfile are specified, table row backgrounds alternate between these profiles for visibility. |
GuiElement#onSelectionChanged | callback [optional] onSelectionChanged(newIndex) Called when list item selection changes. Receives new item index. |
GuiElement#onScroll | callback [optional] onScroll(firstVisibleItemIndex) Called when the list is being scrolled by user input. |
GuiElement#onDoubleClick | callback [optional] onDoubleClick(selectedIndex, selectedElement) Called when a list item is double-clicked. Receives the clicked item index and the item itself. |
GuiElement#onClick | callback [optional] onClick(selectedIndex, selectedElement) Called when a list item is clicked / activated. Receives the clicked item index and the item itself. |
483 | function ListElement:addElementAtPosition(element, position) |
484 | ListElement:superClass().addElement(self, element) |
485 | |
486 | if self.maxNumItems == nil or #self.listItems <= self.maxNumItems then |
487 | table.insert(self.listItems, position, element) |
488 | |
489 | element:fadeOut() |
490 | self:setDisabled(self.disabled) |
491 | |
492 | self:updateAlternatingBackground() |
493 | |
494 | if self.selectedIndex >= position then |
495 | self:setSelectedIndex(self.selectedIndex + 1) |
496 | if #self.listItems == 1 then |
497 | self:updateItemPositions() |
498 | end |
499 | else |
500 | self:updateItemPositions() |
501 | end |
502 | |
503 | self:raiseSliderUpdateEvent() |
504 | if not element.focusId then |
505 | FocusManager:loadElementFromCustomValues(element, nil, element.focusChangeData, element.focusActive, element.isAlwaysFocusedOnOpen) |
506 | end |
507 | end |
508 | |
509 | self:notifyIndexChange(self.selectedIndex, #self.listItems) |
510 | end |
342 | function ListElement:calculateFirstVisibleItem(index) |
343 | local newFirstVisibleItem = self.firstVisibleItem |
344 | local itemFactor = self:getItemFactor() |
345 | local count = self:getItemCount() |
346 | |
347 | -- only change firstVisibleItem if index is out of visible range |
348 | if index < self.firstVisibleItem then |
349 | newFirstVisibleItem = math.ceil(index/itemFactor) * itemFactor - (itemFactor - 1) |
350 | elseif index >= self.firstVisibleItem+self.visibleItems then |
351 | -- With pagination, we need to stick to page alignment |
352 | if self.isPaginated then |
353 | local page = math.ceil(index / self.visibleItems) |
354 | newFirstVisibleItem = (page - 1) * self.visibleItems + 1 |
355 | |
356 | -- Otherwise, just put the item inside (as last item) |
357 | else |
358 | newFirstVisibleItem = math.ceil(index/itemFactor) * itemFactor - self.visibleItems + 1 |
359 | end |
360 | elseif count == 0 then |
361 | newFirstVisibleItem = 0 |
362 | end |
363 | |
364 | return MathUtil.clamp(newFirstVisibleItem, 1, count) |
365 | end |
199 | function ListElement:copyAttributes(src) |
200 | ListElement:superClass().copyAttributes(self, src) |
201 | |
202 | self.doesFocusScrollList = src.doesFocusScrollList |
203 | self.isHorizontalList = src.isHorizontalList |
204 | self.updateSelectionOnOpen = src.updateSelectionOnOpen |
205 | self.useSelectionOnLeave = src.useSelectionOnLeave |
206 | self.selectOnScroll = src.selectOnScroll |
207 | self.supportsMouseScrolling = src.supportsMouseScrolling |
208 | self.doubleClickInterval = src.doubleClickInterval |
209 | self.selectOnClick = src.selectOnClick |
210 | self.ignoreMouse = src.ignoreMouse |
211 | self.maxNumItems = src.maxNumItems |
212 | self.keepSelectedInView = src.keepSelectedInView |
213 | self.isPaginated = src.isPaginated |
214 | |
215 | self.visibleItems = src.visibleItems |
216 | self.itemsPerRow = src.itemsPerRow |
217 | self.itemsPerCol = src.itemsPerCol |
218 | |
219 | self.listItemStartXOffset = src.listItemStartXOffset |
220 | self.listItemStartYOffset = src.listItemStartYOffset |
221 | self.listItemWidth = src.listItemWidth |
222 | self.listItemHeight = src.listItemHeight |
223 | self.listItemPadding = src.listItemPadding |
224 | self.listItemSpacing = src.listItemSpacing |
225 | self.listItemAutoSize = src.listItemAutoSize |
226 | |
227 | self.rowBackgroundProfile = src.rowBackgroundProfile |
228 | self.rowBackgroundProfileAlternate = src.rowBackgroundProfileAlternate |
229 | |
230 | self.onSelectionChangedCallback = src.onSelectionChangedCallback |
231 | self.onScrollCallback = src.onScrollCallback |
232 | self.onDoubleClickCallback = src.onDoubleClickCallback |
233 | self.onClickCallback = src.onClickCallback |
234 | self.onItemAppearCallback = src.onItemAppearCallback |
235 | self.onItemDisappearCallback = src.onItemDisappearCallback |
236 | |
237 | GuiMixin.cloneMixin(IndexChangeSubjectMixin, src, self) |
238 | end |
122 | function ListElement:loadFromXML(xmlFile, key) |
123 | ListElement:superClass().loadFromXML(self, xmlFile, key) |
124 | |
125 | self.doesFocusScrollList = Utils.getNoNil(getXMLBool(xmlFile, key.."#focusScrollsList"), self.doesFocusScrollList) |
126 | self.isHorizontalList = Utils.getNoNil(getXMLBool(xmlFile, key.."#isHorizontalList"), self.isHorizontalList) |
127 | self.updateSelectionOnOpen = Utils.getNoNil(getXMLBool(xmlFile, key.."#updateSelectionOnOpen"), self.updateSelectionOnOpen) |
128 | self.useSelectionOnLeave = Utils.getNoNil(getXMLBool(xmlFile, key.."#useSelectionOnLeave"), self.useSelectionOnLeave) |
129 | self.selectOnScroll = Utils.getNoNil(getXMLBool(xmlFile, key.."#selectOnScroll"), self.selectOnScroll) |
130 | self.supportsMouseScrolling = Utils.getNoNil(getXMLBool(xmlFile, key.."#supportsMouseScrolling"), self.supportsMouseScrolling) |
131 | self.maxNumItems = Utils.getNoNil(getXMLInt(xmlFile, key.."#maxNumItems"), self.maxNumItems) |
132 | self.doubleClickInterval = Utils.getNoNil(getXMLInt(xmlFile, key.."#doubleClickInterval"), self.doubleClickInterval) |
133 | self.selectOnClick = Utils.getNoNil(getXMLBool(xmlFile, key .. "#selectOnClick"), self.selectOnClick) |
134 | self.ignoreMouse = Utils.getNoNil(getXMLBool(xmlFile, key .. "#ignoreMouse"), self.ignoreMouse) |
135 | self.keepSelectedInView = Utils.getNoNil(getXMLBool(xmlFile, key .. "#keepSelectedInView"), self.keepSelectedInView) |
136 | self.isPaginated = Utils.getNoNil(getXMLBool(xmlFile, key .. "#isPaginated"), self.isPaginated) |
137 | |
138 | self.itemsPerRow = Utils.getNoNil(getXMLInt(xmlFile, key.."#itemsPerRow"), self.itemsPerRow) |
139 | self.itemsPerCol = Utils.getNoNil(getXMLInt(xmlFile, key.."#itemsPerCol"), self.itemsPerCol) |
140 | self.visibleItems = self.itemsPerRow * self.itemsPerCol |
141 | |
142 | self.listItemStartXOffset = unpack(GuiUtils.getNormalizedValues(getXMLString(xmlFile, key.."#listItemStartXOffset"), {self.outputSize[1]}, {self.listItemStartXOffset})) |
143 | self.listItemStartYOffset = unpack(GuiUtils.getNormalizedValues(getXMLString(xmlFile, key.."#listItemStartYOffset"), {self.outputSize[2]}, {self.listItemStartYOffset})) |
144 | self.listItemWidth = unpack(GuiUtils.getNormalizedValues(getXMLString(xmlFile, key.."#listItemWidth"), {self.outputSize[1]}, {self.listItemWidth})) |
145 | self.listItemHeight = unpack(GuiUtils.getNormalizedValues(getXMLString(xmlFile, key.."#listItemHeight"), {self.outputSize[2]}, {self.listItemHeight})) |
146 | self.listItemPadding = unpack(GuiUtils.getNormalizedValues(getXMLString(xmlFile, key.."#listItemPadding"), {self.outputSize[1]}, {self.listItemPadding})) |
147 | self.listItemSpacing = unpack(GuiUtils.getNormalizedValues(getXMLString(xmlFile, key.."#listItemSpacing"), {self.outputSize[2]}, {self.listItemSpacing})) |
148 | self.listItemAutoSize = getXMLBool(xmlFile, key .. "#listItemAutoSize") or self.listItemAutoSize |
149 | |
150 | self.rowBackgroundProfile = Utils.getNoNil(getXMLString(xmlFile, key.."#rowBackgroundProfile"), self.rowBackgroundProfile) |
151 | self.rowBackgroundProfileAlternate = Utils.getNoNil(getXMLString(xmlFile, key.."#rowBackgroundProfileAlternate"), self.rowBackgroundProfileAlternate) |
152 | |
153 | self:addCallback(xmlFile, key.."#onSelectionChanged", "onSelectionChangedCallback") |
154 | self:addCallback(xmlFile, key.."#onScroll", "onScrollCallback") |
155 | self:addCallback(xmlFile, key.."#onDoubleClick", "onDoubleClickCallback") |
156 | self:addCallback(xmlFile, key.."#onClick", "onClickCallback") |
157 | self:addCallback(xmlFile, key.."#onItemAppear", "onItemAppearCallback") |
158 | self:addCallback(xmlFile, key.."#onItemDisappear", "onItemDisappearCallback") |
159 | end |
163 | function ListElement:loadProfile(profile, applyProfile) |
164 | ListElement:superClass().loadProfile(self, profile, applyProfile) |
165 | |
166 | self.doesFocusScrollList = profile:getBool("focusScrollsList", self.doesFocusScrollList) |
167 | self.isHorizontalList = profile:getBool("isHorizontalList", self.isHorizontalList) |
168 | self.updateSelectionOnOpen = profile:getBool("updateSelectionOnOpen", self.updateSelectionOnOpen) |
169 | self.useSelectionOnLeave = profile:getBool("useSelectionOnLeave", self.useSelectionOnLeave) |
170 | self.selectOnScroll = profile:getBool("selectOnScroll", self.selectOnScroll) |
171 | self.supportsMouseScrolling = profile:getBool("supportsMouseScrolling", self.supportsMouseScrolling) |
172 | self.maxNumItems = profile:getNumber("maxNumItems", self.maxNumItems) |
173 | self.itemsPerRow = profile:getNumber("itemsPerRow", self.itemsPerRow) |
174 | self.itemsPerCol = profile:getNumber("itemsPerCol", self.itemsPerCol) |
175 | self.doubleClickInterval = profile:getNumber("doubleClickInterval", self.doubleClickInterval) |
176 | self.selectOnClick = profile:getBool("selectOnClick", self.selectOnClick) |
177 | self.ignoreMouse = profile:getBool("ignoreMouse", self.ignoreMouse) |
178 | self.keepSelectedInView = profile:getBool("keepSelectedInView", self.keepSelectedInView) |
179 | self.isPaginated = profile:getBool("isPaginated", self.isPaginated) |
180 | |
181 | self.rowBackgroundProfile = profile:getValue("rowBackgroundProfile", self.rowBackgroundProfile) |
182 | self.rowBackgroundProfileAlternate = profile:getValue("rowBackgroundProfileAlternate", self.rowBackgroundProfileAlternate) |
183 | |
184 | self.listItemStartXOffset = unpack(GuiUtils.getNormalizedValues(profile:getValue("listItemStartXOffset"), {self.outputSize[1]}, {self.listItemStartXOffset})) |
185 | self.listItemStartYOffset = unpack(GuiUtils.getNormalizedValues(profile:getValue("listItemStartYOffset"), {self.outputSize[2]}, {self.listItemStartYOffset})) |
186 | self.listItemWidth = unpack(GuiUtils.getNormalizedValues(profile:getValue("listItemWidth"), {self.outputSize[1]}, {self.listItemWidth})) |
187 | self.listItemHeight = unpack(GuiUtils.getNormalizedValues(profile:getValue("listItemHeight"), {self.outputSize[2]}, {self.listItemHeight})) |
188 | self.listItemPadding = unpack(GuiUtils.getNormalizedValues(profile:getValue("listItemPadding"), {self.outputSize[1]}, {self.listItemPadding})) |
189 | self.listItemSpacing = unpack(GuiUtils.getNormalizedValues(profile:getValue("listItemSpacing"), {self.outputSize[2]}, {self.listItemSpacing})) |
190 | self.listItemAutoSize = profile:getBool("listItemAutoSize", self.listItemAutoSize) |
191 | |
192 | if applyProfile then |
193 | self:applyListAspectScale() |
194 | end |
195 | end |
654 | function ListElement:mouseEvent(posX, posY, isDown, isUp, button, eventUsed) |
655 | if self:getIsActive() and not self.ignoreMouse then |
656 | if ListElement:superClass().mouseEvent(self, posX, posY, isDown, isUp, button, eventUsed) then |
657 | eventUsed = true |
658 | end |
659 | |
660 | self.mouseRow = 0 |
661 | self.mouseCol = 0 |
662 | if not eventUsed and GuiUtils.checkOverlayOverlap(posX, posY, self.absPosition[1], self.absPosition[2], self.absSize[1], self.absSize[2]) then |
663 | self.mouseRow, self.mouseCol = self:getRowColumnForScreenPosition(posX, posY) |
664 | |
665 | if isDown then |
666 | if button == Input.MOUSE_BUTTON_LEFT then |
667 | self:onMouseDown() |
668 | eventUsed = true |
669 | end |
670 | |
671 | if self.supportsMouseScrolling then |
672 | local deltaIndex = 0 |
673 | if Input.isMouseButtonPressed(Input.MOUSE_BUTTON_WHEEL_UP) then |
674 | deltaIndex = -1 |
675 | elseif Input.isMouseButtonPressed(Input.MOUSE_BUTTON_WHEEL_DOWN) then |
676 | deltaIndex = 1 |
677 | end |
678 | |
679 | if deltaIndex ~= 0 then |
680 | eventUsed = true |
681 | |
682 | if self.selectOnScroll then |
683 | -- clamp the new index to an always valid range for scrolling, setSelectedIndex would also |
684 | -- allow an index value of 0 meaning "no selection" |
685 | local newIndex = MathUtil.clamp(self.selectedIndex + deltaIndex, 1, self:getItemCount()) |
686 | self:setSelectedIndex(newIndex, nil, deltaIndex) |
687 | else |
688 | self:scrollList(deltaIndex) |
689 | end |
690 | end |
691 | end |
692 | end |
693 | |
694 | if isUp and button == Input.MOUSE_BUTTON_LEFT and self.mouseDown then |
695 | self:onMouseUp() |
696 | eventUsed = true |
697 | end |
698 | end |
699 | end |
700 | |
701 | return eventUsed |
702 | end |
56 | function ListElement.new(target, custom_mt) |
57 | local self = GuiElement.new(target, custom_mt or ListElement_mt) |
58 | self:include(IndexChangeSubjectMixin) -- add index change subject mixin for index state observers |
59 | |
60 | self.doesFocusScrollList = true |
61 | self.isHorizontalList = false |
62 | self.useSelectionOnLeave = false |
63 | self.selectOnScroll = false |
64 | self.updateSelectionOnOpen = true |
65 | self.supportsMouseScrolling = true |
66 | self.ignoreMouse = false |
67 | self.keepSelectedInView = false |
68 | |
69 | self.maxNumItems = nil |
70 | self.visibleItems = 5 |
71 | self.doubleClickInterval = 400 |
72 | |
73 | self.listItems = {} |
74 | self.listItemStartXOffset = 0.00 |
75 | self.listItemStartYOffset = 0.00 |
76 | self.listItemWidth = 0 |
77 | self.listItemHeight = 0 |
78 | self.listItemPadding = 0 |
79 | self.listItemSpacing = 0 |
80 | self.listItemAutoSize = false |
81 | |
82 | self.firstVisibleItem = 1 |
83 | self.lastFirstVisibleItem = 1 |
84 | self.selectedIndex = 1 |
85 | self.mouseRow = 0 |
86 | self.mouseCol = 0 |
87 | self.lastClickTime = nil |
88 | self.selectOnClick = false |
89 | |
90 | self.isPaginated = false |
91 | |
92 | self.rowBackgroundProfile = "" -- default row background profile, overrides configured profile if specified |
93 | self.rowBackgroundProfileAlternate = "" -- alternating row background profile |
94 | |
95 | self.itemsPerRow = 1 |
96 | self.itemsPerCol = 1 |
97 | |
98 | self.currentRow = 1 |
99 | self.currentCol = 1 |
100 | |
101 | self.sliderElement = nil -- sliders register themselves with lists in this field if they point at them via configuration |
102 | |
103 | return self |
104 | end |
514 | function ListElement:removeElement(element) |
515 | -- Do not do fancy selection stuff when we are destroying this list |
516 | if not self.deletingAllListItems then |
517 | for i = 1, #self.listItems do |
518 | local v = self.listItems[i] |
519 | if v == element then |
520 | table.remove(self.listItems, i) |
521 | FocusManager:removeElement(element) |
522 | self:setDisabled(self.disabled) |
523 | |
524 | if self.selectedIndex >= #self.listItems then |
525 | self:setSelectedIndex(self.selectedIndex - 1) |
526 | end |
527 | |
528 | self:raiseSliderUpdateEvent() |
529 | break |
530 | end |
531 | end |
532 | |
533 | -- shift visible part of list if possible and needed |
534 | if (self.firstVisibleItem > 1 and (self.firstVisibleItem > (#self.listItems - self.visibleItems))) then |
535 | if self.selectedIndex > #self.listItems then |
536 | self:setSelectedIndex(#self.listItems) |
537 | else |
538 | self:scrollTo(#self.listItems) |
539 | end |
540 | end |
541 | end |
542 | |
543 | ListElement:superClass().removeElement(self, element) |
544 | end |
300 | function ListElement:scrollTo(index, updateSlider) |
301 | local itemFactor = self:getItemFactor() |
302 | |
303 | -- convert to valid firstVisibleItem (always has to be: n*itemFactor + 1 ) |
304 | index = math.ceil(index / itemFactor) * itemFactor - (itemFactor - 1) |
305 | |
306 | if not self.isPaginated then |
307 | -- clamp index to valid range |
308 | index = math.max(math.min(index, math.ceil(self:getItemCount() / itemFactor) * itemFactor - self.visibleItems + 1), 1) |
309 | end |
310 | |
311 | if index ~= self.firstVisibleItem then |
312 | self.firstVisibleItem = index |
313 | self:updateItemPositions() |
314 | |
315 | if self.keepSelectedInView then |
316 | -- Check if visible |
317 | if self.selectedIndex < self.firstVisibleItem or self.selectedIndex > self.firstVisibleItem + self.visibleItems - 1 then |
318 | local direction = MathUtil.sign(index - self.selectedIndex) |
319 | |
320 | -- Find if at top or bottom |
321 | if self.selectedIndex < self.firstVisibleItem then |
322 | self:setSelectedIndex(self.firstVisibleItem, nil, direction) |
323 | else |
324 | self:setSelectedIndex(self.firstVisibleItem + self.visibleItems - 1, nil, direction) |
325 | end |
326 | end |
327 | end |
328 | |
329 | -- update scrolling |
330 | if updateSlider == nil or updateSlider then |
331 | if self.sliderElement ~= nil then |
332 | self.sliderElement:setValue(math.ceil(index / itemFactor), true) |
333 | end |
334 | end |
335 | |
336 | self:raiseCallback("onScrollCallback") |
337 | end |
338 | end |
394 | function ListElement:setSelectedIndex(index, force, direction) |
395 | local numItems = #self.listItems |
396 | local newIndex = MathUtil.clamp(index, 0, numItems) |
397 | |
398 | if newIndex ~= self.selectedIndex then |
399 | self.lastClickTime = nil |
400 | end |
401 | |
402 | -- Try to scroll over disabled items |
403 | if self.listItems[newIndex] ~= nil and self.listItems[newIndex].disabled then |
404 | newIndex = newIndex + (direction or 1) |
405 | |
406 | -- If we can't, stay where we are |
407 | if newIndex > #self.listItems or newIndex < 1 then |
408 | if newIndex == 0 then |
409 | -- make sure we are scrolled to the top |
410 | self:scrollTo(1) |
411 | end |
412 | |
413 | return |
414 | end |
415 | |
416 | -- Force no change when direction is explicitly absent (mouse clicks on an item) |
417 | if direction == 0 then |
418 | return |
419 | end |
420 | |
421 | return self:setSelectedIndex(newIndex, force, direction or 1) |
422 | end |
423 | |
424 | local hasChanged = self.selectedIndex ~= newIndex |
425 | self.selectedIndex = newIndex |
426 | |
427 | local newFirstVisibleItem = self:calculateFirstVisibleItem(newIndex) |
428 | |
429 | -- do we need to scroll? |
430 | if hasChanged or newFirstVisibleItem ~= self.firstVisibleItem then |
431 | self:scrollTo(newFirstVisibleItem) |
432 | end |
433 | |
434 | if hasChanged or force then |
435 | self:notifyIndexChange(newIndex, numItems) |
436 | self:raiseCallback("onSelectionChangedCallback", newIndex) |
437 | end |
438 | |
439 | -- update selection state |
440 | if self.firstVisibleItem > 0 then |
441 | for i = 1, self.visibleItems do |
442 | index = self.firstVisibleItem + i - 1 |
443 | if index > numItems then |
444 | break |
445 | end |
446 | local listItem = self.listItems[index] |
447 | if listItem.setSelected ~= nil then |
448 | listItem:setSelected(newIndex == index) |
449 | end |
450 | end |
451 | end |
452 | end |
708 | function ListElement:updateItemPositionsInRange(startIndex, endIndex) |
709 | local topPos = self.absSize[2] - self.listItemStartYOffset - self.listItemHeight |
710 | local leftPos = self.listItemStartXOffset |
711 | |
712 | for i = startIndex, endIndex do |
713 | local elem = self.listItems[i] |
714 | local index = i - self.firstVisibleItem |
715 | |
716 | --#debug assertWithCallstack(elem ~= nil) |
717 | local wasVisible = elem:getIsVisible() |
718 | |
719 | local xPos, yPos = self:getItemPosition(leftPos, topPos, index, elem) |
720 | elem:setPosition(xPos, yPos) |
721 | |
722 | if i >= self.firstVisibleItem and i < self.firstVisibleItem + self.visibleItems then |
723 | -- make items visible in the designated range |
724 | elem:fadeIn() |
725 | |
726 | if not wasVisible then |
727 | self:raiseCallback("onItemAppearCallback", elem) |
728 | end |
729 | else |
730 | -- make all others invisible |
731 | elem:fadeOut() |
732 | |
733 | if wasVisible then |
734 | self:raiseCallback("onItemDisappearCallback", elem) |
735 | end |
736 | end |
737 | |
738 | elem:reset() |
739 | if elem.setSelected ~= nil then |
740 | elem:setSelected(i == self.selectedIndex) |
741 | end |
742 | end |
743 | end |