|  | 
|  | 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 " | 
0 commit comments