diff options
author | Jaakko Keränen <jaakko.keranen@iki.fi> | 2021-09-24 07:36:08 +0300 |
---|---|---|
committer | Jaakko Keränen <jaakko.keranen@iki.fi> | 2021-09-24 07:36:08 +0300 |
commit | 446df26adb969dcb4dd9cf5e171fbb9453a8e27c (patch) | |
tree | 562c647f7c9dc907d34e263d44c9a414a80a8017 /src/ui/listwidget.c | |
parent | 27ebfc904b9b3eac3ef5479ed0d0ba166fac1543 (diff) |
SidebarWidget: Reordering bookmarks manually
One can now drag and drop bookmarks to change their order in the list.
Diffstat (limited to 'src/ui/listwidget.c')
-rw-r--r-- | src/ui/listwidget.c | 53 |
1 files changed, 37 insertions, 16 deletions
diff --git a/src/ui/listwidget.c b/src/ui/listwidget.c index 6a1372ab..a34f3d03 100644 --- a/src/ui/listwidget.c +++ b/src/ui/listwidget.c | |||
@@ -277,7 +277,7 @@ size_t hoverItemIndex_ListWidget(const iListWidget *d) { | |||
277 | return d->hoverItem; | 277 | return d->hoverItem; |
278 | } | 278 | } |
279 | 279 | ||
280 | static void setHoverItem_ListWidget_(iListWidget *d, size_t index) { | 280 | void setHoverItem_ListWidget(iListWidget *d, size_t index) { |
281 | if (index < size_PtrArray(&d->items)) { | 281 | if (index < size_PtrArray(&d->items)) { |
282 | const iListItem *item = at_PtrArray(&d->items, index); | 282 | const iListItem *item = at_PtrArray(&d->items, index); |
283 | if (item->isSeparator) { | 283 | if (item->isSeparator) { |
@@ -294,7 +294,7 @@ static void setHoverItem_ListWidget_(iListWidget *d, size_t index) { | |||
294 | 294 | ||
295 | void updateMouseHover_ListWidget(iListWidget *d) { | 295 | void updateMouseHover_ListWidget(iListWidget *d) { |
296 | const iInt2 mouse = mouseCoord_Window(get_Window(), 0); | 296 | const iInt2 mouse = mouseCoord_Window(get_Window(), 0); |
297 | setHoverItem_ListWidget_(d, itemIndex_ListWidget(d, mouse)); | 297 | setHoverItem_ListWidget(d, itemIndex_ListWidget(d, mouse)); |
298 | } | 298 | } |
299 | 299 | ||
300 | void sort_ListWidget(iListWidget *d, int (*cmp)(const iListItem **item1, const iListItem **item2)) { | 300 | void sort_ListWidget(iListWidget *d, int (*cmp)(const iListItem **item1, const iListItem **item2)) { |
@@ -318,19 +318,18 @@ static void updateHover_ListWidget_(iListWidget *d, const iInt2 mouse) { | |||
318 | contains_Widget(constAs_Widget(d), mouse)) { | 318 | contains_Widget(constAs_Widget(d), mouse)) { |
319 | hover = itemIndex_ListWidget(d, mouse); | 319 | hover = itemIndex_ListWidget(d, mouse); |
320 | } | 320 | } |
321 | setHoverItem_ListWidget_(d, hover); | 321 | setHoverItem_ListWidget(d, hover); |
322 | } | 322 | } |
323 | 323 | ||
324 | static size_t resolveDragDestination_ListWidget_(const iListWidget *d, iInt2 dstPos, iBool *isOnto) { | 324 | static size_t resolveDragDestination_ListWidget_(const iListWidget *d, iInt2 dstPos, iBool *isOnto) { |
325 | size_t index = itemIndex_ListWidget(d, dstPos); | 325 | size_t index = itemIndex_ListWidget(d, dstPos); |
326 | const iRect rect = itemRect_ListWidget(d, index); | ||
327 | const iListItem *item = constItem_ListWidget(d, index); | 326 | const iListItem *item = constItem_ListWidget(d, index); |
328 | const iRangei span = ySpan_Rect(rect); | ||
329 | if (!item) { | 327 | if (!item) { |
330 | item = constItem_ListWidget( | 328 | index = (dstPos.y < mid_Rect(bounds_Widget(constAs_Widget(d))).y ? 0 : (numItems_ListWidget(d) - 1)); |
331 | d, | 329 | item = constItem_ListWidget(d, index); |
332 | dstPos.y < mid_Rect(bounds_Widget(constAs_Widget(d))).y ? 0 : (numItems_ListWidget(d) - 1)); | ||
333 | } | 330 | } |
331 | const iRect rect = itemRect_ListWidget(d, index); | ||
332 | const iRangei span = ySpan_Rect(rect); | ||
334 | if (item->isDropTarget) { | 333 | if (item->isDropTarget) { |
335 | const int pad = size_Range(&span) / 4; | 334 | const int pad = size_Range(&span) / 4; |
336 | if (dstPos.y >= span.start + pad && dstPos.y < span.end) { | 335 | if (dstPos.y >= span.start + pad && dstPos.y < span.end) { |
@@ -350,6 +349,7 @@ static iBool endDrag_ListWidget_(iListWidget *d, iInt2 endPos) { | |||
350 | if (d->dragItem == iInvalidPos) { | 349 | if (d->dragItem == iInvalidPos) { |
351 | return iFalse; | 350 | return iFalse; |
352 | } | 351 | } |
352 | stop_Anim(&d->scrollY.pos); | ||
353 | iBool isOnto; | 353 | iBool isOnto; |
354 | const size_t index = resolveDragDestination_ListWidget_(d, endPos, &isOnto); | 354 | const size_t index = resolveDragDestination_ListWidget_(d, endPos, &isOnto); |
355 | if (isOnto) { | 355 | if (isOnto) { |
@@ -385,14 +385,34 @@ static iBool processEvent_ListWidget_(iListWidget *d, const SDL_Event *ev) { | |||
385 | d->noHoverWhileScrolling = iFalse; | 385 | d->noHoverWhileScrolling = iFalse; |
386 | } | 386 | } |
387 | if (ev->type == SDL_MOUSEMOTION) { | 387 | if (ev->type == SDL_MOUSEMOTION) { |
388 | const iInt2 mousePos = init_I2(ev->motion.x, ev->motion.y); | ||
388 | if (ev->motion.state == 0 /* not dragging */) { | 389 | if (ev->motion.state == 0 /* not dragging */) { |
389 | if (ev->motion.which != SDL_TOUCH_MOUSEID) { | 390 | if (ev->motion.which != SDL_TOUCH_MOUSEID) { |
390 | d->noHoverWhileScrolling = iFalse; | 391 | d->noHoverWhileScrolling = iFalse; |
391 | } | 392 | } |
392 | updateHover_ListWidget_(d, init_I2(ev->motion.x, ev->motion.y)); | 393 | updateHover_ListWidget_(d, mousePos); |
393 | } | 394 | } |
394 | else if (d->dragItem != iInvalidPos) { | 395 | else if (d->dragItem != iInvalidPos) { |
395 | refresh_Widget(d); | 396 | /* Start scrolling if near the ends. */ |
397 | const int zone = d->itemHeight; | ||
398 | const iRect bounds = bounds_Widget(w); | ||
399 | float scrollSpeed = 0.0f; | ||
400 | if (mousePos.y > bottom_Rect(bounds) - zone) { | ||
401 | scrollSpeed = (mousePos.y - bottom_Rect(bounds) + zone) / (float) zone; | ||
402 | } | ||
403 | else if (mousePos.y < top_Rect(bounds) + zone) { | ||
404 | scrollSpeed = -(top_Rect(bounds) + zone - mousePos.y) / (float) zone; | ||
405 | } | ||
406 | scrollSpeed = iClamp(scrollSpeed, -1.0f, 1.0f); | ||
407 | if (iAbs(scrollSpeed) < 0.001f) { | ||
408 | stop_Anim(&d->scrollY.pos); | ||
409 | refresh_Widget(d); | ||
410 | } | ||
411 | else { | ||
412 | setValueSpeed_Anim(&d->scrollY.pos, scrollSpeed < 0 ? 0 : scrollMax_ListWidget_(d), | ||
413 | iAbs(scrollSpeed * gap_UI * 100)); | ||
414 | refreshWhileScrolling_ListWidget_(d); | ||
415 | } | ||
396 | } | 416 | } |
397 | } | 417 | } |
398 | if (ev->type == SDL_MOUSEWHEEL && isHover_Widget(w)) { | 418 | if (ev->type == SDL_MOUSEWHEEL && isHover_Widget(w)) { |
@@ -416,7 +436,12 @@ static iBool processEvent_ListWidget_(iListWidget *d, const SDL_Event *ev) { | |||
416 | redrawHoverItem_ListWidget_(d); | 436 | redrawHoverItem_ListWidget_(d); |
417 | return iTrue; | 437 | return iTrue; |
418 | case aborted_ClickResult: | 438 | case aborted_ClickResult: |
419 | endDrag_ListWidget_(d, pos_Click(&d->click)); | 439 | // endDrag_ListWidget_(d, pos_Click(&d->click)); |
440 | if (d->dragItem != iInvalidPos) { | ||
441 | stop_Anim(&d->scrollY.pos); | ||
442 | invalidateItem_ListWidget(d, d->dragItem); | ||
443 | d->dragItem = iInvalidPos; | ||
444 | } | ||
420 | redrawHoverItem_ListWidget_(d); | 445 | redrawHoverItem_ListWidget_(d); |
421 | break; | 446 | break; |
422 | case drag_ClickResult: | 447 | case drag_ClickResult: |
@@ -436,7 +461,7 @@ static iBool processEvent_ListWidget_(iListWidget *d, const SDL_Event *ev) { | |||
436 | return iTrue; | 461 | return iTrue; |
437 | } | 462 | } |
438 | redrawHoverItem_ListWidget_(d); | 463 | redrawHoverItem_ListWidget_(d); |
439 | if (contains_Rect(innerBounds_Widget(w), pos_Click(&d->click)) && | 464 | if (contains_Rect(itemRect_ListWidget(d, d->hoverItem), pos_Click(&d->click)) && |
440 | d->hoverItem != iInvalidPos) { | 465 | d->hoverItem != iInvalidPos) { |
441 | postCommand_Widget(w, "list.clicked arg:%zu item:%p", | 466 | postCommand_Widget(w, "list.clicked arg:%zu item:%p", |
442 | d->hoverItem, constHoverItem_ListWidget(d)); | 467 | d->hoverItem, constHoverItem_ListWidget(d)); |
@@ -542,14 +567,10 @@ static void draw_ListWidget_(const iListWidget *d) { | |||
542 | const iListItem *item = constAt_PtrArray(&d->items, d->dragItem); | 567 | const iListItem *item = constAt_PtrArray(&d->items, d->dragItem); |
543 | const iRect itemRect = { init_I2(left_Rect(bounds), pos.y), init_I2(d->visBuf->texSize.x, d->itemHeight) }; | 568 | const iRect itemRect = { init_I2(left_Rect(bounds), pos.y), init_I2(d->visBuf->texSize.x, d->itemHeight) }; |
544 | SDL_SetRenderDrawBlendMode(renderer_Window(get_Window()), SDL_BLENDMODE_BLEND); | 569 | SDL_SetRenderDrawBlendMode(renderer_Window(get_Window()), SDL_BLENDMODE_BLEND); |
545 | // setOpacity_Text(0.25f); | ||
546 | // SDL_SetRenderDrawBlendMode(renderer_Window(get_Window()), SDL_BLENDMODE_NONE); | ||
547 | // setOpacity_Text(1.0f); | ||
548 | iBool dstOnto; | 570 | iBool dstOnto; |
549 | const size_t dstIndex = resolveDragDestination_ListWidget_(d, mousePos, &dstOnto); | 571 | const size_t dstIndex = resolveDragDestination_ListWidget_(d, mousePos, &dstOnto); |
550 | if (dstIndex != d->dragItem && dstIndex != d->dragItem + 1) { | 572 | if (dstIndex != d->dragItem && dstIndex != d->dragItem + 1) { |
551 | const iRect dstRect = itemRect_ListWidget(d, dstIndex); | 573 | const iRect dstRect = itemRect_ListWidget(d, dstIndex); |
552 | // SDL_SetRenderDrawBlendMode(renderer_Window(get_Window()), SDL_BLENDMODE_BLEND); | ||
553 | p.alpha = 0xff; | 574 | p.alpha = 0xff; |
554 | if (dstOnto) { | 575 | if (dstOnto) { |
555 | fillRect_Paint(&p, dstRect, uiTextAction_ColorId); | 576 | fillRect_Paint(&p, dstRect, uiTextAction_ColorId); |