49 using namespace winrt::Windows::Foundation; |
49 using namespace winrt::Windows::Foundation; |
50 using namespace winrt::Microsoft::UI::Xaml::Controls::Primitives; |
50 using namespace winrt::Microsoft::UI::Xaml::Controls::Primitives; |
51 using namespace winrt::Microsoft::UI::Xaml::Media; |
51 using namespace winrt::Microsoft::UI::Xaml::Media; |
52 using namespace winrt::Windows::UI::Xaml::Input; |
52 using namespace winrt::Windows::UI::Xaml::Input; |
53 |
53 |
|
54 static UINT ui_double_click_time = GetDoubleClickTime(); |
|
55 |
54 extern "C" void reg_table_destructor(UiContext * ctx, UiTable * table) { |
56 extern "C" void reg_table_destructor(UiContext * ctx, UiTable * table) { |
55 // TODO: |
57 // TODO: |
56 } |
58 } |
57 |
59 |
58 UIEXPORT UIWIDGET ui_table_create(UiObject* obj, UiListArgs args) { |
60 UIEXPORT UIWIDGET ui_table_create(UiObject* obj, UiListArgs args) { |
64 |
66 |
65 // create widgets and wrapper obj |
67 // create widgets and wrapper obj |
66 ScrollViewer scrollW = ScrollViewer(); |
68 ScrollViewer scrollW = ScrollViewer(); |
67 Grid grid = Grid(); |
69 Grid grid = Grid(); |
68 scrollW.Content(grid); |
70 scrollW.Content(grid); |
69 UiTable* uitable = new UiTable(scrollW, grid); |
71 UiTable* uitable = new UiTable(obj, scrollW, grid); |
70 reg_table_destructor(current->ctx, uitable); |
72 reg_table_destructor(current->ctx, uitable); |
71 |
|
72 |
73 |
73 uitable->getvalue = args.model->getvalue ? args.model->getvalue : args.getvalue; |
74 uitable->getvalue = args.model->getvalue ? args.model->getvalue : args.getvalue; |
|
75 uitable->onselection = args.onselection; |
|
76 uitable->onselectiondata = args.onselectiondata; |
|
77 uitable->onactivate = args.onactivate; |
|
78 uitable->onactivatedata = args.onactivatedata; |
74 |
79 |
75 // grid styling |
80 // grid styling |
76 winrt::Windows::UI::Color bg = { 255, 255, 255, 255 }; // test color |
81 winrt::Windows::UI::Color bg = { 255, 255, 255, 255 }; // test color |
77 SolidColorBrush brush = SolidColorBrush(bg); |
82 SolidColorBrush brush = SolidColorBrush(bg); |
78 grid.Background(brush); |
83 grid.Background(brush); |
106 UiTable* table = (UiTable*)list->obj; |
111 UiTable* table = (UiTable*)list->obj; |
107 table->clear(); |
112 table->clear(); |
108 table->update(list, i); |
113 table->update(list, i); |
109 } |
114 } |
110 |
115 |
111 UiTable::UiTable(winrt::Microsoft::UI::Xaml::Controls::ScrollViewer scrollW, winrt::Microsoft::UI::Xaml::Controls::Grid grid) { |
116 UiTable::UiTable(UiObject *obj, winrt::Microsoft::UI::Xaml::Controls::ScrollViewer scrollW, winrt::Microsoft::UI::Xaml::Controls::Grid grid) { |
|
117 this->obj = obj; |
|
118 |
112 this->scrollw = scrollw; |
119 this->scrollw = scrollw; |
113 this->grid = grid; |
120 this->grid = grid; |
114 |
121 |
115 winrt::Windows::UI::Color highlightBg = { 255, 234, 234, 234 }; |
122 winrt::Windows::UI::Color highlightBg = { 255, 234, 234, 234 }; |
116 highlightBrush = SolidColorBrush(highlightBg); |
123 highlightBrush = SolidColorBrush(highlightBg); |
194 wchar_t buf[16]; |
201 wchar_t buf[16]; |
195 swprintf(buf, 16, L"%d", i); |
202 swprintf(buf, 16, L"%d", i); |
196 t.Text(winrt::hstring(buf)); |
203 t.Text(winrt::hstring(buf)); |
197 } |
204 } |
198 |
205 |
|
206 static ULONG64 getsystime() { |
|
207 SYSTEMTIME st; |
|
208 GetSystemTime(&st); |
|
209 return st.wYear * 10000000000000 + |
|
210 st.wMonth * 100000000000 + |
|
211 st.wDay * 1000000000 + |
|
212 st.wHour * 10000000 + |
|
213 st.wMinute * 100000 + |
|
214 st.wSecond * 1000 + |
|
215 st.wMilliseconds; |
|
216 } |
|
217 |
199 void UiTable::update(UiList* list, int i) { |
218 void UiTable::update(UiList* list, int i) { |
200 if (getvalue == nullptr) { |
219 if (getvalue == nullptr) { |
201 return; |
220 return; |
202 } |
221 } |
203 |
222 |
219 maxrows = row; |
239 maxrows = row; |
220 } |
240 } |
221 |
241 |
222 Thickness cellpadding = { 10,0,4,0 }; |
242 Thickness cellpadding = { 10,0,4,0 }; |
223 |
243 |
|
244 // model column, usually the same as col, however UI_ICON_TEXT uses two columns in the model |
224 int model_col = 0; |
245 int model_col = 0; |
225 for (int col = 0; col < header.size(); col++, model_col++) { |
246 for (int col = 0; col < header.size(); col++, model_col++) { |
226 // create ui elements with the correct cell border |
247 // create ui elements with the correct cell border |
227 // dependeing on the column |
248 // dependeing on the column |
228 Border cellBorder = Border(); |
249 Border cellBorder = Border(); |
229 cellBorder.Background(defaultBrush); |
250 cellBorder.Background(defaultBrush); |
|
251 cellBorder.BorderBrush(defaultBrush); |
|
252 if (col == 0) { |
|
253 cellBorder.BorderThickness(b1); |
|
254 } |
|
255 else if (col + 1 == header.size()) { |
|
256 cellBorder.BorderThickness(b3); |
|
257 } |
|
258 else { |
|
259 cellBorder.BorderThickness(b2); |
|
260 } |
230 |
261 |
231 // set the cell value |
262 // set the cell value |
|
263 // depending on the type, we create different cell controls |
232 UiModelType type = model->types[col]; |
264 UiModelType type = model->types[col]; |
233 switch (type) { |
265 switch (type) { |
234 case UI_STRING: { |
266 case UI_STRING: { |
235 TextBlock cell = TextBlock(); |
267 TextBlock cell = TextBlock(); |
236 cell.Padding(cellpadding); |
268 cell.Padding(cellpadding); |
276 cellPanel.Children().Append(cell); |
308 cellPanel.Children().Append(cell); |
277 cellBorder.Child(cellPanel); |
309 cellBorder.Child(cellPanel); |
278 break; |
310 break; |
279 } |
311 } |
280 } |
312 } |
281 |
|
282 cellBorder.BorderBrush(defaultBrush); |
|
283 if (col == 0) { |
|
284 cellBorder.BorderThickness(b1); |
|
285 } |
|
286 else if (col + 1 == header.size()) { |
|
287 cellBorder.BorderThickness(b3); |
|
288 } |
|
289 else { |
|
290 cellBorder.BorderThickness(b2); |
|
291 } |
|
292 |
313 |
293 // event handler |
314 // event handler |
294 cellBorder.PointerPressed( |
315 cellBorder.PointerPressed( |
295 winrt::Microsoft::UI::Xaml::Input::PointerEventHandler( |
316 winrt::Microsoft::UI::Xaml::Input::PointerEventHandler( |
296 [=](IInspectable const& sender, winrt::Microsoft::UI::Xaml::Input::PointerRoutedEventArgs const& args) { |
317 [=](IInspectable const& sender, winrt::Microsoft::UI::Xaml::Input::PointerRoutedEventArgs const& args) { |
297 winrt::Windows::System::VirtualKeyModifiers modifiers = args.KeyModifiers(); |
318 winrt::Windows::System::VirtualKeyModifiers modifiers = args.KeyModifiers(); |
|
319 bool update_selection = true; |
298 |
320 |
299 if (modifiers == winrt::Windows::System::VirtualKeyModifiers::Control) { |
321 if (modifiers == winrt::Windows::System::VirtualKeyModifiers::Control) { |
300 // add/remove current row |
322 // add/remove current row |
301 if (!is_row_selected(row)) { |
323 if (!is_row_selected(row)) { |
302 row_background(row, selectedBrush, selectedBorderBrush); |
324 row_background(row, selectedBrush, selectedBorderBrush); |
313 change_rows_bg(selection, defaultBrush, defaultBrush); |
335 change_rows_bg(selection, defaultBrush, defaultBrush); |
314 } |
336 } |
315 |
337 |
316 row_background(row, selectedBrush, selectedBorderBrush); |
338 row_background(row, selectedBrush, selectedBorderBrush); |
317 selection = { row }; |
339 selection = { row }; |
|
340 if (modifiers == winrt::Windows::System::VirtualKeyModifiers::None) { |
|
341 SYSTEMTIME st; |
|
342 GetSystemTime(&st); |
|
343 |
|
344 ULONG64 now = getsystime(); |
|
345 ULONG64 tdiff = now - lastPointerPress; |
|
346 if (tdiff < ui_double_click_time && onactivate != nullptr) { |
|
347 // two pointer presse events in short time and we have an onactivate handler |
|
348 update_selection = false; // we don't want an additional selection event |
|
349 lastPointerPress = 0; // reset double-click |
|
350 |
|
351 int selectedrow = row - 1; // subtract header row |
|
352 |
|
353 UiListSelection selection; |
|
354 selection.count = 1; |
|
355 selection.rows = &selectedrow; |
|
356 |
|
357 UiEvent evt; |
|
358 evt.obj = obj; |
|
359 evt.window = obj->window; |
|
360 evt.document = obj->ctx->document; |
|
361 evt.eventdata = &selection; |
|
362 evt.intval = selectedrow; |
|
363 onactivate(&evt, onactivatedata); |
|
364 } |
|
365 else { |
|
366 lastPointerPress = now; |
|
367 } |
|
368 } |
318 } |
369 } |
319 else if (modifiers == winrt::Windows::System::VirtualKeyModifiers::Shift) { |
370 else if (modifiers == winrt::Windows::System::VirtualKeyModifiers::Shift) { |
320 // select everything between the first selection and the current row |
371 // select everything between the first selection and the current row |
321 std::sort(selection.begin(), selection.end()); |
372 std::sort(selection.begin(), selection.end()); |
322 int first = selection.front(); |
373 int first = selection.front(); |
335 newselection.push_back(s); |
386 newselection.push_back(s); |
336 } |
387 } |
337 selection = newselection; |
388 selection = newselection; |
338 change_rows_bg(selection, selectedBrush, selectedBorderBrush); |
389 change_rows_bg(selection, selectedBrush, selectedBorderBrush); |
339 } |
390 } |
|
391 |
|
392 if (update_selection) { |
|
393 call_handler(onselection, onselectiondata); |
|
394 } |
340 }) |
395 }) |
341 ); |
396 ); |
342 cellBorder.PointerReleased( |
397 cellBorder.PointerReleased( |
343 winrt::Microsoft::UI::Xaml::Input::PointerEventHandler( |
398 winrt::Microsoft::UI::Xaml::Input::PointerEventHandler( |
344 [=](IInspectable const& sender, winrt::Microsoft::UI::Xaml::Input::PointerRoutedEventArgs const& args) { |
399 [=](IInspectable const& sender, winrt::Microsoft::UI::Xaml::Input::PointerRoutedEventArgs const& args) { |
378 int child_row = grid.GetRow(elm); |
433 int child_row = grid.GetRow(elm); |
379 if (child_row > 0) { |
434 if (child_row > 0) { |
380 grid.Children().RemoveAt(i); |
435 grid.Children().RemoveAt(i); |
381 } |
436 } |
382 } |
437 } |
|
438 |
|
439 // TODO: should we clean row definitions? |
383 } |
440 } |
384 |
441 |
385 void UiTable::row_background(int row, winrt::Microsoft::UI::Xaml::Media::Brush brush, winrt::Microsoft::UI::Xaml::Media::Brush borderBrush) { |
442 void UiTable::row_background(int row, winrt::Microsoft::UI::Xaml::Media::Brush brush, winrt::Microsoft::UI::Xaml::Media::Brush borderBrush) { |
386 Thickness b1 = { 1, 1, 0, 1 }; // first col |
443 Thickness b1 = { 1, 1, 0, 1 }; // first col |
387 Thickness b2 = { 0, 1, 0, 1 }; // middle |
444 Thickness b2 = { 0, 1, 0, 1 }; // middle |
408 |
465 |
409 void UiTable::remove_from_selection(int row) { |
466 void UiTable::remove_from_selection(int row) { |
410 selection.erase(std::remove(selection.begin(), selection.end(), row), selection.end()); |
467 selection.erase(std::remove(selection.begin(), selection.end(), row), selection.end()); |
411 selection.shrink_to_fit(); |
468 selection.shrink_to_fit(); |
412 } |
469 } |
|
470 |
|
471 void UiTable::call_handler(ui_callback cb, void* cbdata) { |
|
472 if (!cb) { |
|
473 return; |
|
474 } |
|
475 |
|
476 std::sort(selection.begin(), selection.end()); |
|
477 |
|
478 UiListSelection selobj; |
|
479 selobj.count = selection.size(); |
|
480 selobj.rows = nullptr; |
|
481 if (selobj.count > 0) { |
|
482 selobj.rows = (int*)calloc(selobj.count, sizeof(int)); |
|
483 memcpy(selobj.rows, selection.data(), selobj.count * sizeof(int)); |
|
484 for (int i = 0; i < selobj.count; i++) { |
|
485 selobj.rows[i]--; |
|
486 } |
|
487 } |
|
488 |
|
489 UiEvent evt; |
|
490 evt.obj = obj; |
|
491 evt.window = obj->window; |
|
492 evt.document = obj->ctx->document; |
|
493 evt.eventdata = &selobj; |
|
494 evt.intval = 0; |
|
495 cb(&evt, cbdata); |
|
496 } |