Skip to content

Commit d89ae32

Browse files
committed
Merge pull request #50 from yglukhov/listview
Listview
2 parents d0d84ae + 9d48e61 commit d89ae32

File tree

2 files changed

+202
-0
lines changed

2 files changed

+202
-0
lines changed

nimx/horizontal_list_view.nim

Lines changed: 198 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,198 @@
1+
import view
2+
export view
3+
4+
import view_event_handling
5+
import nimx.gesture_detector
6+
import types
7+
import event
8+
import context
9+
import clip_view
10+
11+
import system_logger
12+
import app
13+
14+
type
15+
16+
Adapter* = ref object of RootObj
17+
18+
ListScrollListener = ref object of OnScrollListener
19+
start : Point
20+
view : HorizontalListView
21+
22+
ViewWrapper = ref object
23+
v : View
24+
pos : int
25+
26+
HorizontalListView* = ref object of ClipView
27+
adapter: Adapter
28+
items : seq[ViewWrapper]
29+
cleared : seq[ViewWrapper]
30+
dirty : bool
31+
dirtyBoundsOrigin : Point
32+
33+
proc newViewWrapper(view : View, pos: int): ViewWrapper =
34+
result.new
35+
result.v = view
36+
result.pos = pos
37+
38+
method getCount*(a : Adapter): int {.base.} = discard
39+
method getView*(a: Adapter, position: int, convertView : View): View {.base.} = discard
40+
41+
proc newHorListView*(r: Rect): HorizontalListView =
42+
result.new()
43+
result.items = @[]
44+
result.cleared = @[]
45+
result.init(r)
46+
47+
method init*(v: HorizontalListView, r: Rect) =
48+
procCall v.View.init(r)
49+
v.backgroundColor = newGrayColor(0.89)
50+
var sl : ListScrollListener
51+
new(sl)
52+
sl.view = v
53+
v.addGestureDetector(newScrollGestureDetector(sl))
54+
55+
var offs = newPoint(0,0)
56+
57+
proc getMinPos(v : HorizontalListView):ViewWrapper =
58+
if v.items.len > 0:
59+
var pos = v.items[0].pos
60+
result = v.items[0]
61+
for w in v.items:
62+
if w.pos < pos:
63+
result = w
64+
pos = w.pos
65+
66+
proc getMaxPos(v : HorizontalListView):ViewWrapper =
67+
if v.items.len > 0:
68+
var pos = v.items[0].pos
69+
result = v.items[0]
70+
for w in v.items:
71+
if w.pos > pos:
72+
result = w
73+
pos = w.pos
74+
75+
proc getClearedWrapper(v : HorizontalListView):ViewWrapper =
76+
if v.cleared.len>0:
77+
result = v.cleared[0]
78+
v.cleared.delete(0)
79+
80+
proc populateLeft(v : HorizontalListView, edgeLeft : ViewWrapper) =
81+
var sx = v.bounds.origin.x
82+
var cx = edgeLeft.v.frame.origin.x
83+
var pos : int = edgeLeft.pos - 1
84+
while cx > sx:
85+
if pos < 0:
86+
break
87+
var convert : View = nil
88+
var wr = v.getClearedWrapper()
89+
if not wr.isNil:
90+
convert = wr.v
91+
let view = v.adapter.getView(pos,convert)
92+
cx = cx - view.bounds.size.width
93+
view.setFrameOrigin(newPoint(cx,0))
94+
v.addSubview(view)
95+
if not wr.isNil:
96+
wr.v = view
97+
wr.pos = pos
98+
else:
99+
wr = newViewWrapper(view,pos)
100+
v.items.add(wr)
101+
pos = pos - 1
102+
103+
proc populateRight(v : HorizontalListView, edgeRight : ViewWrapper) =
104+
var cx = v.bounds.origin.x
105+
var fx = v.bounds.origin.x + v.bounds.size.width
106+
var pos = 0
107+
if not edgeRight.isNil:
108+
cx = edgeRight.v.frame.origin.x + edgeRight.v.frame.size.width
109+
pos = edgeRight.pos+1
110+
while cx < fx:
111+
if pos >= v.adapter.getCount():
112+
break
113+
var convert : View = nil
114+
var wr = v.getClearedWrapper()
115+
if not wr.isNil:
116+
convert = wr.v
117+
let view = v.adapter.getView(pos,convert)
118+
view.setFrameOrigin(newPoint(cx,0))
119+
cx = cx + view.bounds.size.width
120+
v.addSubview(view)
121+
if not wr.isNil:
122+
wr.v = view
123+
wr.pos = pos
124+
else:
125+
wr = newViewWrapper(view,pos)
126+
v.items.add(wr)
127+
pos = pos + 1
128+
129+
proc checkEdges(v : HorizontalListView, orig : Point) : Point =
130+
let o = orig
131+
result = o
132+
if o.x < 0:
133+
result = newPoint(0,0)
134+
if not v.adapter.isNil:
135+
let max = v.getMaxPos()
136+
let min = v.getMinPos()
137+
if (not max.isNil) and (not min.isNil):
138+
# echo "check 1"
139+
if max.pos >= v.adapter.getCount()-1:
140+
let vo = max.v.frame.origin
141+
let s = max.v.frame.size
142+
if vo.x < o.x + v.frame.size.width - s.width:
143+
# echo "check 2 ",vo.x
144+
if min.pos > 0:
145+
result = newPoint(vo.x + s.width - v.frame.size.width,0)
146+
else:
147+
result = newPoint(0,0)
148+
149+
150+
proc syncAdapterOnView(v : HorizontalListView) =
151+
var sx = v.bounds.origin.x
152+
let fx = v.bounds.size.width + sx
153+
# echo "x port is: ", sx, " ", fx
154+
var i : int = 0
155+
while i < v.items.len:
156+
let vi = v.items[i]
157+
if vi.v.frame.intersect(v.bounds):
158+
# echo vi.pos," intersect "
159+
i = i+1
160+
else:
161+
vi.v.removeFromSuperview()
162+
v.items.delete(i)
163+
v.cleared.add(vi)
164+
let minPos = v.getMinPos()
165+
if not minPos.isNil:
166+
v.populateLeft(minPos)
167+
let maxPos = v.getMaxPos()
168+
v.populateRight(maxPos)
169+
# echo "cleared: ",v.cleared.len, " items: ", v.items.len
170+
171+
method setAdapter*(v : HorizontalListView, a : Adapter) {.base.} =
172+
v.adapter = a
173+
v.syncAdapterOnView
174+
175+
method onMouseDown*(v: HorizontalListView, e: var Event): bool =
176+
e.kind = etTouch
177+
result = v.handleTouchEvent(e)
178+
179+
method draw*(view: HorizontalListView, rect: Rect) =
180+
procCall view.View.draw(rect)
181+
if view.dirty:
182+
let bo = view.checkEdges(view.dirtyBoundsOrigin)
183+
view.setBoundsOrigin(bo)
184+
view.syncAdapterOnView()
185+
view.dirty = false
186+
view.setNeedsDisplay()
187+
188+
method onTapDown*(lis : ListScrollListener, e : var Event) =
189+
lis.start = lis.view.bounds.origin
190+
191+
method onScrollProgress*(lis: ListScrollListener, dx, dy : float32, e : var Event) =
192+
let inv = newPoint(lis.start.x-dx,0)
193+
lis.view.dirtyBoundsOrigin = inv
194+
lis.view.dirty = true
195+
lis.view.setNeedsDisplay()
196+
197+
method onTapUp*(lis: ListScrollListener, dx, dy : float32, e : var Event) =
198+
echo "list onTapUp "

nimx/types.nim

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,3 +139,7 @@ proc centerInRect*(s: Size, r: Rect): Point =
139139
# The result may be outside of rect r, if s is bigger than size of r.
140140
result.x = r.origin.x + (r.width - s.width) / 2
141141
result.y = r.origin.y + (r.height - s.height) / 2
142+
143+
proc intersect*(r: Rect, c: Rect): bool =
144+
if r.minX < c.maxX and c.minX < r.maxX and r.minY < c.maxY and c.minY < r.maxY:
145+
result = true

0 commit comments

Comments
 (0)