diff options
Diffstat (limited to 'src/ui/listwidget.c')
-rw-r--r-- | src/ui/listwidget.c | 96 |
1 files changed, 18 insertions, 78 deletions
diff --git a/src/ui/listwidget.c b/src/ui/listwidget.c index 985ba2e7..dd11b008 100644 --- a/src/ui/listwidget.c +++ b/src/ui/listwidget.c | |||
@@ -332,7 +332,8 @@ static iBool processEvent_ListWidget_(iListWidget *d, const SDL_Event *ev) { | |||
332 | 332 | ||
333 | static void allocVisBuffer_ListWidget_(iListWidget *d) { | 333 | static void allocVisBuffer_ListWidget_(iListWidget *d) { |
334 | /* Make sure two buffers cover the entire visible area. */ | 334 | /* Make sure two buffers cover the entire visible area. */ |
335 | const iInt2 size = div_I2(addY_I2(innerBounds_Widget(as_Widget(d)).size, 1), init_I2(1, 2)); | 335 | const iRect inner = innerBounds_Widget(as_Widget(d)); |
336 | const iInt2 size = init_I2(inner.size.x, (inner.size.y / 2 / d->itemHeight + 1) * d->itemHeight); | ||
336 | if (!d->visBuffers[0].texture || !isEqual_I2(size, d->visBufSize)) { | 337 | if (!d->visBuffers[0].texture || !isEqual_I2(size, d->visBufSize)) { |
337 | d->visBufSize = size; | 338 | d->visBufSize = size; |
338 | iForIndices(i, d->visBuffers) { | 339 | iForIndices(i, d->visBuffers) { |
@@ -400,17 +401,20 @@ static void draw_ListWidget_(const iListWidget *d) { | |||
400 | iListWidget *m = iConstCast(iListWidget *, d); | 401 | iListWidget *m = iConstCast(iListWidget *, d); |
401 | allocVisBuffer_ListWidget_(m); | 402 | allocVisBuffer_ListWidget_(m); |
402 | /* Update invalid regions/items. */ | 403 | /* Update invalid regions/items. */ |
404 | /* TODO: This seems to draw two items per each shift of the visible region, even though | ||
405 | one should be enough. Probably an off-by-one error in the calculation of the | ||
406 | invalid range. */ | ||
403 | if (d->visBufSize.y > 0) { | 407 | if (d->visBufSize.y > 0) { |
404 | /*if (d->visBufferValid != full_BufferValidity || !isEmpty_IntSet(&d->invalidItems)) */ | ||
405 | iAssert(d->visBuffers[0].texture); | 408 | iAssert(d->visBuffers[0].texture); |
406 | iAssert(d->visBuffers[1].texture); | 409 | iAssert(d->visBuffers[1].texture); |
407 | iAssert(d->visBuffers[2].texture); | 410 | iAssert(d->visBuffers[2].texture); |
408 | // const int vbSrc = d->visBufferIndex; | 411 | const int bg[3] = { w->bgColor, w->bgColor, w->bgColor }; |
409 | // const int vbDst = d->visBufferIndex ^ 1; | 412 | // const int bg[3] = { red_ColorId, magenta_ColorId, blue_ColorId }; |
410 | const int bottom = numItems_ListWidget(d) * d->itemHeight; | 413 | const int bottom = numItems_ListWidget(d) * d->itemHeight; |
411 | const iRangei vis = { d->scrollY, d->scrollY + bounds.size.y }; | 414 | const iRangei vis = { d->scrollY / d->itemHeight * d->itemHeight, |
415 | ((d->scrollY + bounds.size.y) / d->itemHeight + 1) * d->itemHeight }; | ||
412 | iRangei good = { 0, 0 }; | 416 | iRangei good = { 0, 0 }; |
413 | printf("visBufSize.y = %d\n", d->visBufSize.y); | 417 | // printf("visBufSize.y = %d\n", d->visBufSize.y); |
414 | size_t avail[3], numAvail = 0; | 418 | size_t avail[3], numAvail = 0; |
415 | /* Check which buffers are available for reuse. */ { | 419 | /* Check which buffers are available for reuse. */ { |
416 | iForIndices(i, d->visBuffers) { | 420 | iForIndices(i, d->visBuffers) { |
@@ -457,14 +461,14 @@ static void draw_ListWidget_(const iListWidget *d) { | |||
457 | } | 461 | } |
458 | iForIndices(i, d->visBuffers) { | 462 | iForIndices(i, d->visBuffers) { |
459 | iListVisBuffer *buf = m->visBuffers + i; | 463 | iListVisBuffer *buf = m->visBuffers + i; |
460 | printf("%zu: orig %d, invalid %d ... %d\n", i, buf->origin, invalidRange[i].start, invalidRange[i].end); | 464 | // printf("%zu: orig %d, invalid %d ... %d\n", i, buf->origin, invalidRange[i].start, invalidRange[i].end); |
461 | iRanges drawItems = { iMax(0, buf->origin) / d->itemHeight, | 465 | iRanges drawItems = { iMax(0, buf->origin) / d->itemHeight, |
462 | iMax(0, buf->origin + d->visBufSize.y) / d->itemHeight + 1 }; | 466 | iMax(0, buf->origin + d->visBufSize.y) / d->itemHeight + 1 }; |
463 | iBool isTargetSet = iFalse; | 467 | iBool isTargetSet = iFalse; |
464 | if (isEmpty_Rangei(buf->validRange)) { | 468 | if (isEmpty_Rangei(buf->validRange)) { |
465 | isTargetSet = iTrue; | 469 | isTargetSet = iTrue; |
466 | beginTarget_Paint(&p, buf->texture); | 470 | beginTarget_Paint(&p, buf->texture); |
467 | fillRect_Paint(&p, (iRect){ zero_I2(), d->visBufSize }, w->bgColor); | 471 | fillRect_Paint(&p, (iRect){ zero_I2(), d->visBufSize }, bg[i]); |
468 | } | 472 | } |
469 | iConstForEach(IntSet, v, &d->invalidItems) { | 473 | iConstForEach(IntSet, v, &d->invalidItems) { |
470 | const size_t index = *v.value; | 474 | const size_t index = *v.value; |
@@ -476,101 +480,37 @@ static void draw_ListWidget_(const iListWidget *d) { | |||
476 | beginTarget_Paint(&p, buf->texture); | 480 | beginTarget_Paint(&p, buf->texture); |
477 | isTargetSet = iTrue; | 481 | isTargetSet = iTrue; |
478 | } | 482 | } |
479 | fillRect_Paint(&p, itemRect, w->bgColor); | 483 | fillRect_Paint(&p, itemRect, bg[i]); |
480 | class_ListItem(item)->draw(item, &p, itemRect, d); | 484 | class_ListItem(item)->draw(item, &p, itemRect, d); |
481 | printf("- drawing invalid item %zu\n", index); | 485 | // printf("- drawing invalid item %zu\n", index); |
482 | } | 486 | } |
483 | } | 487 | } |
488 | /* Visible range is not fully covered. Fill in the new items. */ | ||
484 | if (!isEmpty_Rangei(invalidRange[i])) { | 489 | if (!isEmpty_Rangei(invalidRange[i])) { |
485 | if (!isTargetSet) { | 490 | if (!isTargetSet) { |
486 | beginTarget_Paint(&p, buf->texture); | 491 | beginTarget_Paint(&p, buf->texture); |
487 | isTargetSet = iTrue; | 492 | isTargetSet = iTrue; |
488 | } | 493 | } |
489 | /* Visible range is not fully covered. Fill in the new items. */ | ||
490 | // fillRect_Paint(&p, (iRect){ init_I2(0, invalidRange[i].start - buf->origin), | ||
491 | // init_I2(d->visBufSize.x, invalidRange[i].end - buf->origin) }, | ||
492 | // w->bgColor); | ||
493 | drawItems.start = invalidRange[i].start / d->itemHeight; | 494 | drawItems.start = invalidRange[i].start / d->itemHeight; |
494 | drawItems.end = invalidRange[i].end / d->itemHeight + 1; | 495 | drawItems.end = invalidRange[i].end / d->itemHeight + 1; |
495 | for (size_t j = drawItems.start; j < drawItems.end && j < size_PtrArray(&d->items); j++) { | 496 | for (size_t j = drawItems.start; j < drawItems.end && j < size_PtrArray(&d->items); j++) { |
496 | const iListItem *item = constAt_PtrArray(&d->items, j); | 497 | const iListItem *item = constAt_PtrArray(&d->items, j); |
497 | const iRect itemRect = { init_I2(0, j * d->itemHeight - buf->origin), | 498 | const iRect itemRect = { init_I2(0, j * d->itemHeight - buf->origin), |
498 | init_I2(d->visBufSize.x, d->itemHeight) }; | 499 | init_I2(d->visBufSize.x, d->itemHeight) }; |
499 | fillRect_Paint(&p, itemRect, w->bgColor); | 500 | fillRect_Paint(&p, itemRect, bg[i]); |
500 | class_ListItem(item)->draw(item, &p, itemRect, d); | 501 | class_ListItem(item)->draw(item, &p, itemRect, d); |
501 | printf("- drawing item %zu\n", j); | 502 | // printf("- drawing item %zu\n", j); |
502 | } | 503 | } |
503 | } | 504 | } |
504 | /* TODO: Redraw invalidated items. */ | ||
505 | if (isTargetSet) { | 505 | if (isTargetSet) { |
506 | endTarget_Paint(&p); | 506 | endTarget_Paint(&p); |
507 | } | 507 | } |
508 | buf->validRange = | 508 | buf->validRange = |
509 | intersect_Rangei(vis, (iRangei){ buf->origin, buf->origin + d->visBufSize.y }); | 509 | intersect_Rangei(vis, (iRangei){ buf->origin, buf->origin + d->visBufSize.y }); |
510 | fflush(stdout); | 510 | // fflush(stdout); |
511 | } | 511 | } |
512 | #if 0 | ||
513 | beginTarget_Paint(&p, d->visBuffer[vbDst]); | ||
514 | const iRect bufBounds = (iRect){ zero_I2(), bounds.size }; | ||
515 | iRanges invalidRange = { 0, 0 }; | ||
516 | if (!d->visBufferValid) { | ||
517 | fillRect_Paint(&p, bufBounds, w->bgColor); | ||
518 | } | ||
519 | else if (d->visBufferValid == partial_BufferValidity) { | ||
520 | /* Copy previous contents. */ | ||
521 | const int delta = d->scrollY - d->visBufferScrollY; | ||
522 | SDL_RenderCopy( | ||
523 | render, | ||
524 | d->visBuffer[vbSrc], | ||
525 | NULL, | ||
526 | &(SDL_Rect){ 0, -delta, bounds.size.x, bounds.size.y }); | ||
527 | if (delta > 0) { | ||
528 | /* Scrolling down. */ | ||
529 | invalidRange.start = (d->visBufferScrollY + bounds.size.y) / d->itemHeight; | ||
530 | invalidRange.end = (d->scrollY + bounds.size.y) / d->itemHeight + 1; | ||
531 | } | ||
532 | else if (delta < 0) { | ||
533 | /* Scrolling up. */ | ||
534 | invalidRange.start = d->scrollY / d->itemHeight; | ||
535 | invalidRange.end = d->visBufferScrollY / d->itemHeight + 1; | ||
536 | } | ||
537 | } | ||
538 | /* Draw items. */ { | ||
539 | const iRanges visRange = visRange_ListWidget_(d); | ||
540 | iInt2 pos = init_I2(0, -(d->scrollY % d->itemHeight)); | ||
541 | for (size_t i = visRange.start; i < visRange.end; i++) { | ||
542 | /* TODO: Refactor to loop through invalidItems only. */ | ||
543 | if (!d->visBufferValid || contains_Range(&invalidRange, i) || | ||
544 | contains_IntSet(&d->invalidItems, i)) { | ||
545 | const iListItem *item = constAt_PtrArray(&d->items, i); | ||
546 | const iRect itemRect = { pos, init_I2(width_Rect(bounds), d->itemHeight) }; | ||
547 | setClip_Paint(&p, intersect_Rect(itemRect, bufBounds)); | ||
548 | if (d->visBufferValid) { | ||
549 | fillRect_Paint(&p, itemRect, w->bgColor); | ||
550 | } | ||
551 | class_ListItem(item)->draw(item, &p, itemRect, d); | ||
552 | /* Clear under the scrollbar. */ | ||
553 | if (isVisible_Widget(d->scroll)) { | ||
554 | fillRect_Paint( | ||
555 | &p, | ||
556 | (iRect){ addX_I2(topRight_Rect(itemRect), -width_Widget(d->scroll)), | ||
557 | bottomRight_Rect(itemRect) }, | ||
558 | w->bgColor); | ||
559 | } | ||
560 | unsetClip_Paint(&p); | ||
561 | } | ||
562 | pos.y += d->itemHeight; | ||
563 | } | ||
564 | } | ||
565 | endTarget_Paint(&p); | ||
566 | /* Update state. */ | ||
567 | // m->visBufferValid = iTrue; | ||
568 | // m->visBufferScrollY = m->scrollY; | ||
569 | // m->visBufferIndex = vbDst; | ||
570 | #endif | ||
571 | clear_IntSet(&m->invalidItems); | 512 | clear_IntSet(&m->invalidItems); |
572 | } | 513 | } |
573 | //SDL_RenderCopy(render, d->visBuffer[d->visBufferIndex], NULL, (const SDL_Rect *) &bounds); | ||
574 | setClip_Paint(&p, bounds_Widget(w)); | 514 | setClip_Paint(&p, bounds_Widget(w)); |
575 | iForIndices(i, d->visBuffers) { | 515 | iForIndices(i, d->visBuffers) { |
576 | const iListVisBuffer *buf = d->visBuffers + i; | 516 | const iListVisBuffer *buf = d->visBuffers + i; |