Blame view

build4/epsilon-master/escher/src/table_view.cpp 8.4 KB
6663b6c9   adorian   projet complet av...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
  #include <escher/table_view.h>
  #include <escher/metric.h>
  
  extern "C" {
  #include <assert.h>
  }
  
  #define MIN(x,y) ((x)<(y) ? (x) : (y))
  
  TableView::TableView(TableViewDataSource * dataSource, ScrollViewDataSource * scrollDataSource) :
    ScrollView(&m_contentView, scrollDataSource),
    m_contentView(this, dataSource, 0, 1)
  {
  }
  
  KDSize TableView::minimalSizeForOptimalDisplay() const {
    return m_contentView.minimalSizeForOptimalDisplay();
  }
  
  TableViewDataSource * TableView::dataSource() {
    return m_contentView.dataSource();
  }
  
  // This method computes the minimal scrolling needed to properly display the
  // requested cell.
  void TableView::scrollToCell(int i, int j) {
    m_contentView.scrollToCell(i, j);
  }
  
  HighlightCell * TableView::cellAtLocation(int i, int j) {
    return m_contentView.cellAtLocation(i, j);
  }
  
  #if ESCHER_VIEW_LOGGING
  const char * TableView::className() const {
    return "TableView";
  }
  #endif
  
  void TableView::layoutSubviews() {
    // We only have to layout our contentView.
    // We will size it here, and ScrollView::layoutSubviews will position it.
  
    m_contentView.resizeToFitContent();
  
    ScrollView::layoutSubviews();
  }
  
  void TableView::reloadCellAtLocation(int i, int j) {
    m_contentView.reloadCellAtLocation(i, j);
  }
  
  /* TableView::ContentView */
  
  TableView::ContentView::ContentView(TableView * tableView, TableViewDataSource * dataSource, KDCoordinate horizontalCellOverlap, KDCoordinate verticalCellOverlap) :
    View(),
    m_tableView(tableView),
    m_dataSource(dataSource),
    m_horizontalCellOverlap(horizontalCellOverlap),
    m_verticalCellOverlap(verticalCellOverlap)
  {
  }
  
  KDSize TableView::ContentView::minimalSizeForOptimalDisplay() const {
    return KDSize(width(), height());
  }
  
  TableViewDataSource * TableView::ContentView::dataSource() {
    return m_dataSource;
  }
  
  KDCoordinate TableView::ContentView::columnWidth(int i) const {
    int columnWidth = m_dataSource->columnWidth(i);
    columnWidth = columnWidth ? columnWidth : m_tableView->maxContentWidthDisplayableWithoutScrolling();
    return columnWidth;
  }
  
  void TableView::ContentView::resizeToFitContent() {
    layoutSubviews();
    setSize(KDSize(width(), height()));
  }
  
  KDCoordinate TableView::ContentView::height() const {
    return m_dataSource->cumulatedHeightFromIndex(m_dataSource->numberOfRows())+m_verticalCellOverlap;
  }
  
  KDCoordinate TableView::ContentView::width() const {
    int result = m_dataSource->cumulatedWidthFromIndex(m_dataSource->numberOfColumns())+m_horizontalCellOverlap;
    // handle the case of list: cumulatedWidthFromIndex() = 0
    return result ? result : m_tableView->maxContentWidthDisplayableWithoutScrolling();
  }
  
  void TableView::ContentView::scrollToCell(int x, int y) const {
    KDRect cellRect = KDRect(m_dataSource->cumulatedWidthFromIndex(x), m_dataSource->cumulatedHeightFromIndex(y), columnWidth(x), m_dataSource->rowHeight(y));
    m_tableView->scrollToContentRect(cellRect, true);
  }
  
  void TableView::ContentView::reloadCellAtLocation(int i, int j) {
    m_dataSource->willDisplayCellAtLocation(cellAtLocation(i, j), i, j);
  }
  
  int TableView::ContentView::typeOfSubviewAtIndex(int index) const {
    assert(index >= 0);
    int i = absoluteColumnNumberFromSubviewIndex(index);
    int j = absoluteRowNumberFromSubviewIndex(index);
    int type = m_dataSource->typeAtLocation(i, j);
    return type;
  }
  
  int TableView::ContentView::typeIndexFromSubviewIndex(int index, int type) const {
    int typeIndex = 0;
    for (int k = 0; k < index; k++) {
      if (typeOfSubviewAtIndex(k) == type) {
        typeIndex++;
      }
    }
    assert(typeIndex < m_dataSource->reusableCellCount(type));
    return typeIndex;
  }
  
  HighlightCell * TableView::ContentView::cellAtLocation(int x, int y) {
    int relativeX = x-columnsScrollingOffset();
    int relativeY = y-rowsScrollingOffset();
    int type = m_dataSource->typeAtLocation(x, y);
    int index = relativeY*numberOfDisplayableColumns()+relativeX;
    int typeIndex = typeIndexFromSubviewIndex(index, type);
    return m_dataSource->reusableCell(typeIndex, type);
  }
  
  #if ESCHER_VIEW_LOGGING
  const char * TableView::ContentView::className() const {
    return "TableView::ContentView";
  }
  #endif
  
  int TableView::ContentView::numberOfSubviews() const {
    int result = numberOfDisplayableRows() * numberOfDisplayableColumns();
    return result;
  }
  
  int TableView::ContentView::absoluteColumnNumberFromSubviewIndex(int index) const {
    /* "x = i % columns" but we avoid a call to modulo not to implement
    * "__aeabi_idivmod" */
    int j = index / numberOfDisplayableColumns();
    int i = index - j * numberOfDisplayableColumns();
    int columnOffset = columnsScrollingOffset();
    return i + columnOffset;
  }
  
  int TableView::ContentView::absoluteRowNumberFromSubviewIndex(int index) const {
    int j = index / numberOfDisplayableColumns();
    int rowOffset = rowsScrollingOffset();
    return j + rowOffset;
  }
  
  View * TableView::ContentView::subviewAtIndex(int index) {
    int type = typeOfSubviewAtIndex(index);
    int typeIndex = typeIndexFromSubviewIndex(index, type);
    return m_dataSource->reusableCell(typeIndex, type);
  }
  
  void TableView::ContentView::layoutSubviews() {
    /* The number of subviews might change during the layouting so it needs to be
     * recomputed at each step of the for loop. */
    for (int index = 0; index < numberOfSubviews(); index++) {
      View * cell = subview(index);
      int i = absoluteColumnNumberFromSubviewIndex(index);
      int j = absoluteRowNumberFromSubviewIndex(index);
      m_dataSource->willDisplayCellAtLocation((HighlightCell *)cell, i, j);
  
      KDCoordinate rowHeight = m_dataSource->rowHeight(j);
      KDCoordinate columnWidth = this->columnWidth(i);
      KDCoordinate verticalOffset = m_dataSource->cumulatedHeightFromIndex(j);
      KDCoordinate horizontalOffset = m_dataSource->cumulatedWidthFromIndex(i);
      KDRect cellFrame(horizontalOffset, verticalOffset,
        columnWidth+m_horizontalCellOverlap, rowHeight+m_verticalCellOverlap);
      cell->setFrame(cellFrame);
    }
  }
  
  
  int TableView::ContentView::numberOfFullyDisplayableRows() const {
    // The number of displayable rows taking into accounts margins
    int rowOffsetWithMargin = m_dataSource->indexFromCumulatedHeight(m_tableView->contentOffset().y() +
      m_tableView->topMargin());
    int displayedHeightWithOffsetAndMargin = m_dataSource->indexFromCumulatedHeight(m_tableView->maxContentHeightDisplayableWithoutScrolling() +
      m_tableView->contentOffset().y() + m_tableView->topMargin());
    return displayedHeightWithOffsetAndMargin - rowOffsetWithMargin;
  }
  
  int TableView::ContentView::numberOfFullyDisplayableColumns() const {
    // The number of displayable rows taking into accounts margins
    int columnOffsetWithMargin = m_dataSource->indexFromCumulatedWidth(m_tableView->contentOffset().x() +
      m_tableView->leftMargin());
    int displayedWidthWithOffsetAndMargin = m_dataSource->indexFromCumulatedWidth(m_tableView->maxContentWidthDisplayableWithoutScrolling() +
      m_tableView->contentOffset().x() + m_tableView->leftMargin());
    return displayedWidthWithOffsetAndMargin - columnOffsetWithMargin;
  }
  
  int TableView::ContentView::numberOfDisplayableRows() const {
    int rowOffset = rowsScrollingOffset();
    int displayedHeightWithOffset = m_dataSource->indexFromCumulatedHeight(m_tableView->bounds().height() + m_tableView->contentOffset().y());
    return MIN(
      m_dataSource->numberOfRows(),
      displayedHeightWithOffset + 1
    )  - rowOffset;
  }
  
  int TableView::ContentView::numberOfDisplayableColumns() const {
    int columnOffset = columnsScrollingOffset();
    int displayedWidthWithOffset = m_dataSource->indexFromCumulatedWidth(m_tableView->bounds().width() + m_tableView->contentOffset().x());
    return MIN(
      m_dataSource->numberOfColumns(),
      displayedWidthWithOffset + 1
    )  - columnOffset;
  }
  
  int TableView::ContentView::rowsScrollingOffset() const {
    /* Here, we want to translate the offset at which our tableView is displaying
     * us into an integer offset we can use to ask cells to our data source. */
    KDCoordinate invisibleHeight = m_tableView->contentOffset().y()-m_tableView->topMargin();
    invisibleHeight = invisibleHeight < 0 ? 0 : invisibleHeight;
    return m_dataSource->indexFromCumulatedHeight(invisibleHeight);
  }
  
  int TableView::ContentView::columnsScrollingOffset() const {
    /* Here, we want to translate the offset at which our tableView is displaying
     * us into an integer offset we can use to ask cells to our data source. */
    KDCoordinate invisibleWidth = m_tableView->contentOffset().x()-m_tableView->leftMargin();
    invisibleWidth = invisibleWidth < 0 ? 0 : invisibleWidth;
    return m_dataSource->indexFromCumulatedWidth(invisibleWidth);
  }