191 | function SmoothListElement:copyAttributes(src) |
192 | SmoothListElement:superClass().copyAttributes(self, src) |
193 | |
194 | self.dataSource = src.dataSource |
195 | self.delegate = src.delegate |
196 | |
197 | self.singularCellName = src.singularCellName |
198 | |
199 | self.sectionHeaderCellName = src.sectionHeaderCellName |
200 | self.startClipperElementName = src.startClipperElementName |
201 | self.endClipperElementName = src.endClipperElementName |
202 | |
203 | self.isHorizontalList = src.isHorizontalList |
204 | self.numLateralItems = src.numLateralItems |
205 | self.listItemSpacing = src.listItemSpacing |
206 | self.listItemLateralSpacing = src.listItemLateralSpacing |
207 | |
208 | self.supportsMouseScrolling = src.supportsMouseScrolling |
209 | self.doubleClickInterval = src.doubleClickInterval |
210 | self.selectOnClick = src.selectOnClick |
211 | self.ignoreMouse = src.ignoreMouse |
212 | self.showHighlights = src.showHighlights |
213 | self.itemizedScrollDelta = src.itemizedScrollDelta |
214 | self.selectOnScroll = src.selectOnScroll |
215 | self.listSmoothingDisabled = src.listSmoothingDisabled |
216 | self.selectedWithoutFocus = src.selectedWithoutFocus |
217 | |
218 | self.lengthAxis = src.lengthAxis |
219 | self.widthAxis = src.widthAxis |
220 | |
221 | self.onScrollCallback = src.onScrollCallback |
222 | self.onDoubleClickCallback = src.onDoubleClickCallback |
223 | self.onClickCallback = src.onClickCallback |
224 | |
225 | self.supportsTouchScrolling = src.supportsTouchScrolling |
226 | |
227 | self.isLoaded = src.isLoaded |
228 | |
229 | GuiMixin.cloneMixin(PlaySampleMixin, src, self) |
230 | end |
83 | function SmoothListElement:loadFromXML(xmlFile, key) |
84 | SmoothListElement:superClass().loadFromXML(self, xmlFile, key) |
85 | |
86 | self:addCallback(xmlFile, key.."#onScroll", "onScrollCallback") |
87 | self:addCallback(xmlFile, key.."#onDoubleClick", "onDoubleClickCallback") |
88 | self:addCallback(xmlFile, key.."#onClick", "onClickCallback") |
89 | |
90 | self.isHorizontalList = Utils.getNoNil(getXMLBool(xmlFile, key.."#isHorizontalList"), self.isHorizontalList) |
91 | self.lengthAxis = self.isHorizontalList and 1 or 2 |
92 | self.widthAxis = self.isHorizontalList and 2 or 1 |
93 | |
94 | self.numLateralItems = Utils.getNoNil(getXMLInt(xmlFile, key.."#numLateralItems"), self.numLateralItems) |
95 | self.listItemSpacing = unpack(GuiUtils.getNormalizedValues(getXMLString(xmlFile, key.."#listItemSpacing"), {self.outputSize[self.lengthAxis]}, {self.listItemSpacing})) |
96 | self.listItemLateralSpacing = unpack(GuiUtils.getNormalizedValues(getXMLString(xmlFile, key.."#listItemLateralSpacing"), {self.outputSize[self.widthAxis]}, {self.listItemLateralSpacing})) |
97 | |
98 | self.supportsMouseScrolling = Utils.getNoNil(getXMLBool(xmlFile, key.."#supportsMouseScrolling"), self.supportsMouseScrolling) |
99 | self.supportsTouchScrolling = Utils.getNoNil(getXMLBool(xmlFile, key.."#supportsTouchScrolling"), self.supportsTouchScrolling) |
100 | self.doubleClickInterval = Utils.getNoNil(getXMLInt(xmlFile, key.."#doubleClickInterval"), self.doubleClickInterval) |
101 | self.selectOnClick = Utils.getNoNil(getXMLBool(xmlFile, key .. "#selectOnClick"), self.selectOnClick) |
102 | self.ignoreMouse = Utils.getNoNil(getXMLBool(xmlFile, key .. "#ignoreMouse"), self.ignoreMouse) |
103 | self.showHighlights = Utils.getNoNil(getXMLBool(xmlFile, key .. "#showHighlights"), self.showHighlights) |
104 | self.selectOnScroll = Utils.getNoNil(getXMLBool(xmlFile, key .. "#selectOnScroll"), self.selectOnScroll) |
105 | self.itemizedScrollDelta = Utils.getNoNil(getXMLBool(xmlFile, key .. "#itemizedScrollDelta"), self.itemizedScrollDelta) |
106 | self.listSmoothingDisabled = Utils.getNoNil(getXMLBool(xmlFile, key .. "#listSmoothingDisabled"), self.listSmoothingDisabled) |
107 | self.selectedWithoutFocus = Utils.getNoNil(getXMLBool(xmlFile, key .. "#selectedWithoutFocus"), self.selectedWithoutFocus) |
108 | |
109 | local delegateName = getXMLString(xmlFile, key .. "#listDelegate") |
110 | if delegateName == "self" then |
111 | self.delegate = self.target |
112 | elseif delegateName ~= "nil" then |
113 | self.delegate = self.target[delegateName] |
114 | end |
115 | |
116 | local dataSourceName = getXMLString(xmlFile, key .. "#listDataSource") |
117 | if dataSourceName == "self" then |
118 | self.dataSource = self.target |
119 | elseif delegateName ~= "nil" then |
120 | self.dataSource = self.target[dataSourceName] |
121 | end |
122 | |
123 | self.sectionHeaderCellName = getXMLString(xmlFile, key .. "#listSectionHeader") |
124 | self.startClipperElementName = getXMLString(xmlFile, key.."#startClipperElementName") |
125 | self.endClipperElementName = getXMLString(xmlFile, key.."#endClipperElementName") |
126 | |
127 | self.updateChildrenOverlayState = false |
128 | end |
132 | function SmoothListElement:loadProfile(profile, applyProfile) |
133 | SmoothListElement:superClass().loadProfile(self, profile, applyProfile) |
134 | |
135 | self.isHorizontalList = profile:getBool("isHorizontalList", self.isHorizontalList) |
136 | self.lengthAxis = self.isHorizontalList and 1 or 2 |
137 | self.widthAxis = self.isHorizontalList and 2 or 1 |
138 | |
139 | self.numLateralItems = profile:getNumber("numLateralItems", self.numLateralItems) |
140 | self.listItemSpacing = unpack(GuiUtils.getNormalizedValues(profile:getValue("listItemSpacing"), {self.outputSize[self.lengthAxis]}, {self.listItemSpacing})) |
141 | self.listItemLateralSpacing = unpack(GuiUtils.getNormalizedValues(profile:getValue("listItemLateralSpacing"), {self.outputSize[self.widthAxis]}, {self.listItemLateralSpacing})) |
142 | |
143 | self.supportsMouseScrolling = profile:getBool("supportsMouseScrolling", self.supportsMouseScrolling) |
144 | self.doubleClickInterval = profile:getNumber("doubleClickInterval", self.doubleClickInterval) |
145 | self.selectOnClick = profile:getBool("selectOnClick", self.selectOnClick) |
146 | self.ignoreMouse = profile:getBool("ignoreMouse", self.ignoreMouse) |
147 | self.showHighlights = profile:getBool("showHighlights", self.showHighlights) |
148 | self.selectOnScroll = profile:getBool("selectOnScroll", self.selectOnScroll) |
149 | self.itemizedScrollDelta = profile:getBool("itemizedScrollDelta", self.itemizedScrollDelta) |
150 | self.listSmoothingDisabled = profile:getBool("listSmoothingDisabled", self.listSmoothingDisabled) |
151 | self.selectedWithoutFocus = profile:getBool("selectedWithoutFocus", self.selectedWithoutFocus) |
152 | self.supportsTouchScrolling = profile:getBool("supportsTouchScrolling", self.supportsTouchScrolling) |
153 | end |
1250 | function SmoothListElement:mouseEvent(posX, posY, isDown, isUp, button, eventUsed) |
1251 | if self:getIsActive() and not self.ignoreMouse then |
1252 | if SmoothListElement:superClass().mouseEvent(self, posX, posY, isDown, isUp, button, eventUsed) then |
1253 | eventUsed = true |
1254 | end |
1255 | |
1256 | if not eventUsed and GuiUtils.checkOverlayOverlap(posX, posY, self.absPosition[1], self.absPosition[2], self.absSize[1], self.absSize[2]) then |
1257 | local mouseOverElement = self:getElementAtScreenPosition(posX, posY) |
1258 | if mouseOverElement ~= nil and mouseOverElement.indexInSection == 0 then |
1259 | mouseOverElement = nil |
1260 | end |
1261 | |
1262 | -- Mouse over changed |
1263 | if self.mouseOverElement ~= mouseOverElement then |
1264 | self:setHighlightedItem(mouseOverElement) |
1265 | self.mouseOverElement = mouseOverElement |
1266 | end |
1267 | |
1268 | if isDown then |
1269 | if button == Input.MOUSE_BUTTON_LEFT then |
1270 | self:onMouseDown() |
1271 | eventUsed = true |
1272 | end |
1273 | |
1274 | if self.supportsMouseScrolling then |
1275 | local deltaIndex = 0 |
1276 | if Input.isMouseButtonPressed(Input.MOUSE_BUTTON_WHEEL_UP) then |
1277 | deltaIndex = -1 |
1278 | elseif Input.isMouseButtonPressed(Input.MOUSE_BUTTON_WHEEL_DOWN) then |
1279 | deltaIndex = 1 |
1280 | end |
1281 | |
1282 | if deltaIndex ~= 0 then |
1283 | if self.selectOnScroll then |
1284 | -- Fast code for just 1 section as it is easy. If need arises we can expand to support multiple sections |
1285 | if #self.sections == 1 then |
1286 | local newIndex = math.max(1, math.min(self.sections[1].numItems, self.selectedIndex + deltaIndex)) |
1287 | self:setSelectedItem(1, newIndex) |
1288 | end |
1289 | else |
1290 | self:smoothScrollTo(self.targetViewOffset + deltaIndex * self.scrollViewOffsetDelta) |
1291 | end |
1292 | |
1293 | eventUsed = true |
1294 | end |
1295 | end |
1296 | end |
1297 | |
1298 | if isUp and button == Input.MOUSE_BUTTON_LEFT and self.mouseDown then |
1299 | self:onMouseUp() |
1300 | eventUsed = true |
1301 | end |
1302 | elseif self.mouseOverElement ~= nil then |
1303 | self.mouseOverElement = nil |
1304 | self:setHighlightedItem(self.mouseOverElement) |
1305 | end |
1306 | end |
1307 | |
1308 | return eventUsed |
1309 | end |
23 | function SmoothListElement.new(target, custom_mt) |
24 | local self = SmoothListElement:superClass().new(target, custom_mt or SmoothListElement_mt) |
25 | self:include(IndexChangeSubjectMixin) -- add index change subject mixin for index state observers |
26 | self:include(PlaySampleMixin) -- add sound playing |
27 | |
28 | self.dataSource = nil |
29 | self.delegate = nil |
30 | |
31 | self.cellCache = {} |
32 | self.sections = {} |
33 | |
34 | self.isLoaded = false |
35 | |
36 | self.clipping = true |
37 | |
38 | self.sectionHeaderCellName = nil |
39 | self.isHorizontalList = false |
40 | self.numLateralItems = 1 |
41 | self.listItemSpacing = 0 |
42 | self.listItemLateralSpacing = 0 |
43 | |
44 | self.lengthAxis = 2 |
45 | self.widthAxis = 1 |
46 | |
47 | self.viewOffset = 0 |
48 | self.targetViewOffset = 0 |
49 | self.contentSize = 0 |
50 | self.totalItemCount = 0 |
51 | self.scrollViewOffsetDelta = 0 |
52 | self.selectedIndex = 1 |
53 | self.selectedSectionIndex = 1 |
54 | |
55 | self.supportsMouseScrolling = true |
56 | self.doubleClickInterval = 400 |
57 | self.selectOnClick = false |
58 | self.ignoreMouse = false |
59 | self.showHighlights = false |
60 | self.selectOnScroll = false |
61 | self.itemizedScrollDelta = false |
62 | self.listSmoothingDisabled = false |
63 | self.selectedWithoutFocus = true -- whether selection is visible even without focus |
64 | |
65 | self.lastTouchPos = nil |
66 | self.usedTouchId = nil |
67 | self.currentTouchDelta = 0 |
68 | self.scrollSpeed = 0 |
69 | self.initialScrollSpeed = 0 |
70 | self.scrollSpeedPixelPerMS = 0.005 |
71 | if self.isHorizontalList then |
72 | self.scrollSpeedInterval = self.scrollSpeedPixelPerMS / g_screenWidth |
73 | else |
74 | self.scrollSpeedInterval = self.scrollSpeedPixelPerMS / g_screenHeight |
75 | end |
76 | self.supportsTouchScrolling = false |
77 | |
78 | return self |
79 | end |
1207 | function SmoothListElement:onMouseUp() |
1208 | if self.mouseOverElement ~= nil then |
1209 | local previousSection, previousIndex = self.selectedSectionIndex, self.selectedIndex |
1210 | local clickedSection, clickedIndex = self.mouseOverElement.sectionIndex, self.mouseOverElement.indexInSection |
1211 | local notified = false |
1212 | |
1213 | self:setSelectedItem(clickedSection, clickedIndex, nil, 0) |
1214 | |
1215 | if self.lastClickTime ~= nil and self.lastClickTime > self.target.time - self.doubleClickInterval then |
1216 | -- -- Only activate click if the target was hit |
1217 | if clickedSection == previousSection and clickedIndex == previousIndex then |
1218 | self:notifyDoubleClick(clickedSection, clickedIndex, self.mouseOverElement) |
1219 | notified = true |
1220 | end |
1221 | self.lastClickTime = nil |
1222 | else |
1223 | self.lastClickTime = self.target.time |
1224 | end |
1225 | |
1226 | if not self.selectOnClick and not notified then |
1227 | self:notifyClick(clickedSection, clickedIndex, self.mouseOverElement) |
1228 | end |
1229 | else |
1230 | self.lastClickTime = nil |
1231 | end |
1232 | |
1233 | self.mouseDown = false |
1234 | end |