BColumnListView: Resolve column resizing drawing glitch (wider than 600px)

* use of a shared bitmap buffer in OutlineView and TitleView
* dynamically increase of the bitmap buffer after adding a column or a row

Change-Id: I4feddf636fb1446c29e60353b8f70fc084833731
Reviewed-on: https://review.haiku-os.org/c/haiku/+/7176
Reviewed-by: John Scipione <[email protected]>
Reviewed-by: Adrien Destugues <[email protected]>
Reviewed-by: Stefano Ceccherini <[email protected]>
Tested-by: Commit checker robot <[email protected]>
This commit is contained in:
Freaxed
2023-12-11 08:19:08 +00:00
committed by Adrien Destugues
parent 4f9df95dc8
commit 5014ac9392
+167 -52
View File
@@ -144,10 +144,34 @@ static const float kDropHighlightLineHeight = 2.0;
static const uint32 kToggleColumn = 'BTCL'; static const uint32 kToggleColumn = 'BTCL';
#ifdef DOUBLE_BUFFERED_COLUMN_RESIZE
class ColumnResizeBufferView : public BView
{
public:
ColumnResizeBufferView();
virtual ~ColumnResizeBufferView();
void UpdateMaxWidth(float width);
void UpdateMaxHeight(float height);
bool Lock();
void Unlock();
const BBitmap* Bitmap();
private:
void _InitBitmap();
void _FreeBitmap();
BBitmap* fDrawBuffer;
};
#endif
class BRowContainer : public BObjectList<BRow> class BRowContainer : public BObjectList<BRow>
{ {
}; };
class TitleView : public BView { class TitleView : public BView {
typedef BView _inherited; typedef BView _inherited;
public: public:
@@ -198,10 +222,6 @@ private:
// float fColumnsWidth; // float fColumnsWidth;
BRect fVisibleRect; BRect fVisibleRect;
#if DOUBLE_BUFFERED_COLUMN_RESIZE
BBitmap* fDrawBuffer;
BView* fDrawBufferView;
#endif
enum { enum {
INACTIVE, INACTIVE,
@@ -292,6 +312,10 @@ public:
virtual void MouseUp(BPoint where); virtual void MouseUp(BPoint where);
virtual void MessageReceived(BMessage* message); virtual void MessageReceived(BMessage* message);
#if DOUBLE_BUFFERED_COLUMN_RESIZE
ColumnResizeBufferView* ResizeBufferView();
#endif
private: private:
bool SortList(BRowContainer* list, bool isVisible); bool SortList(BRowContainer* list, bool isVisible);
static int32 DeepSortThreadEntry(void* outlineView); static int32 DeepSortThreadEntry(void* outlineView);
@@ -311,8 +335,7 @@ private:
BRect fVisibleRect; BRect fVisibleRect;
#if DOUBLE_BUFFERED_COLUMN_RESIZE #if DOUBLE_BUFFERED_COLUMN_RESIZE
BBitmap* fDrawBuffer; ColumnResizeBufferView* fResizeBufferView;
BView* fDrawBufferView;
#endif #endif
BRow* fFocusRow; BRow* fFocusRow;
@@ -391,6 +414,101 @@ private:
using namespace BPrivate; using namespace BPrivate;
#ifdef DOUBLE_BUFFERED_COLUMN_RESIZE
ColumnResizeBufferView::ColumnResizeBufferView()
: BView(BRect(0, 0, 600, 35), "double_buffer_view", B_FOLLOW_ALL_SIDES, 0), fDrawBuffer(NULL)
{
_InitBitmap();
}
ColumnResizeBufferView::~ColumnResizeBufferView()
{
_FreeBitmap();
}
void
ColumnResizeBufferView::UpdateMaxWidth(float width)
{
Lock();
BRect bounds = Bounds();
Unlock();
if (width > bounds.Width()) {
Lock();
ResizeTo(width, bounds.Height());
Unlock();
_InitBitmap();
}
}
void
ColumnResizeBufferView::UpdateMaxHeight(float height)
{
Lock();
BRect bounds = Bounds();
Unlock();
if (height > bounds.Height()) {
Lock();
ResizeTo(bounds.Width(), height);
Unlock();
_InitBitmap();
}
}
bool
ColumnResizeBufferView::Lock()
{
return fDrawBuffer->Lock();
}
void
ColumnResizeBufferView::Unlock()
{
fDrawBuffer->Unlock();
}
const BBitmap*
ColumnResizeBufferView::Bitmap()
{
return fDrawBuffer;
}
void
ColumnResizeBufferView::_InitBitmap()
{
_FreeBitmap();
fDrawBuffer = new BBitmap(Bounds(), B_RGB32, true);
fDrawBuffer->Lock();
fDrawBuffer->AddChild(this);
fDrawBuffer->Unlock();
}
void
ColumnResizeBufferView::_FreeBitmap()
{
if (fDrawBuffer) {
fDrawBuffer->Lock();
fDrawBuffer->RemoveChild(this);
fDrawBuffer->Unlock();
delete fDrawBuffer;
fDrawBuffer = NULL;
}
}
#endif
BField::BField() BField::BField()
{ {
} }
@@ -2223,17 +2341,6 @@ TitleView::TitleView(BRect rect, OutlineView* horizontalSlave,
{ {
SetViewColor(B_TRANSPARENT_COLOR); SetViewColor(B_TRANSPARENT_COLOR);
#if DOUBLE_BUFFERED_COLUMN_RESIZE
// xxx this needs to be smart about the size of the backbuffer.
BRect doubleBufferRect(0, 0, 600, 35);
fDrawBuffer = new BBitmap(doubleBufferRect, B_RGB32, true);
fDrawBufferView = new BView(doubleBufferRect, "double_buffer_view",
B_FOLLOW_ALL_SIDES, 0);
fDrawBuffer->Lock();
fDrawBuffer->AddChild(fDrawBufferView);
fDrawBuffer->Unlock();
#endif
fUpSortArrow = new BBitmap(BRect(0, 0, 7, 7), B_CMAP8); fUpSortArrow = new BBitmap(BRect(0, 0, 7, 7), B_CMAP8);
fDownSortArrow = new BBitmap(BRect(0, 0, 7, 7), B_CMAP8); fDownSortArrow = new BBitmap(BRect(0, 0, 7, 7), B_CMAP8);
@@ -2254,9 +2361,6 @@ TitleView::~TitleView()
delete fColumnPop; delete fColumnPop;
fColumnPop = NULL; fColumnPop = NULL;
#if DOUBLE_BUFFERED_COLUMN_RESIZE
delete fDrawBuffer;
#endif
delete fUpSortArrow; delete fUpSortArrow;
delete fDownSortArrow; delete fDownSortArrow;
@@ -2270,6 +2374,9 @@ TitleView::~TitleView()
void void
TitleView::ColumnAdded(BColumn* column) TitleView::ColumnAdded(BColumn* column)
{ {
#ifdef DOUBLE_BUFFERED_COLUMN_RESIZE
fOutlineView->ResizeBufferView()->UpdateMaxWidth(column->MaxWidth());
#endif
// fColumnsWidth += column->Width(); // fColumnsWidth += column->Width();
FixScrollBar(false); FixScrollBar(false);
Invalidate(); Invalidate();
@@ -2481,13 +2588,14 @@ TitleView::ResizeSelectedColumn(BPoint position, bool preferred)
destRect.OffsetBy(fSelectedColumnRect.left, 0); destRect.OffsetBy(fSelectedColumnRect.left, 0);
#if DOUBLE_BUFFERED_COLUMN_RESIZE #if DOUBLE_BUFFERED_COLUMN_RESIZE
fDrawBuffer->Lock(); ColumnResizeBufferView* bufferView = fOutlineView->ResizeBufferView();
DrawTitle(fDrawBufferView, sourceRect, fSelectedColumn, false); bufferView->Lock();
fDrawBufferView->Sync(); DrawTitle(bufferView, sourceRect, fSelectedColumn, false);
fDrawBuffer->Unlock(); bufferView->Sync();
bufferView->Unlock();
CopyBits(originalRect, movedRect); CopyBits(originalRect, movedRect);
DrawBitmap(fDrawBuffer, sourceRect, destRect); DrawBitmap(bufferView->Bitmap(), sourceRect, destRect);
#else #else
CopyBits(originalRect, movedRect); CopyBits(originalRect, movedRect);
DrawTitle(this, destRect, fSelectedColumn, false); DrawTitle(this, destRect, fSelectedColumn, false);
@@ -3113,15 +3221,7 @@ OutlineView::OutlineView(BRect rect, BList* visibleColumns, BList* sortColumns,
SetViewColor(B_TRANSPARENT_COLOR); SetViewColor(B_TRANSPARENT_COLOR);
#if DOUBLE_BUFFERED_COLUMN_RESIZE #if DOUBLE_BUFFERED_COLUMN_RESIZE
// TODO: This needs to be smart about the size of the buffer. fResizeBufferView = new ColumnResizeBufferView();
// Also, the buffer can be shared with the title's buffer.
BRect doubleBufferRect(0, 0, 600, 35);
fDrawBuffer = new BBitmap(doubleBufferRect, B_RGB32, true);
fDrawBufferView = new BView(doubleBufferRect, "double_buffer_view",
B_FOLLOW_ALL_SIDES, 0);
fDrawBuffer->Lock();
fDrawBuffer->AddChild(fDrawBufferView);
fDrawBuffer->Unlock();
#endif #endif
FixScrollBar(true); FixScrollBar(true);
@@ -3133,7 +3233,7 @@ OutlineView::OutlineView(BRect rect, BList* visibleColumns, BList* sortColumns,
OutlineView::~OutlineView() OutlineView::~OutlineView()
{ {
#if DOUBLE_BUFFERED_COLUMN_RESIZE #if DOUBLE_BUFFERED_COLUMN_RESIZE
delete fDrawBuffer; delete fResizeBufferView;
#endif #endif
Clear(); Clear();
@@ -3275,15 +3375,15 @@ OutlineView::RedrawColumn(BColumn* column, float leftEdge, bool isFirstColumn)
#if DOUBLE_BUFFERED_COLUMN_RESIZE #if DOUBLE_BUFFERED_COLUMN_RESIZE
fDrawBuffer->Lock(); fResizeBufferView->Lock();
fDrawBufferView->SetHighColor(highColor); fResizeBufferView->SetHighColor(highColor);
fDrawBufferView->SetLowColor(lowColor); fResizeBufferView->SetLowColor(lowColor);
BFont font; BFont font;
GetFont(&font); GetFont(&font);
fDrawBufferView->SetFont(&font); fResizeBufferView->SetFont(&font);
fDrawBufferView->FillRect(sourceRect, B_SOLID_LOW); fResizeBufferView->FillRect(sourceRect, B_SOLID_LOW);
if (isFirstColumn) { if (isFirstColumn) {
// If this is the first column, double buffer drawing the latch // If this is the first column, double buffer drawing the latch
@@ -3299,7 +3399,7 @@ OutlineView::RedrawColumn(BColumn* column, float leftEdge, bool isFirstColumn)
BRect latchRect(sourceRect); BRect latchRect(sourceRect);
latchRect.right = latchRect.left + fMasterView->LatchWidth(); latchRect.right = latchRect.left + fMasterView->LatchWidth();
fMasterView->DrawLatch(fDrawBufferView, latchRect, pos, row); fMasterView->DrawLatch(fResizeBufferView, latchRect, pos, row);
} }
BField* field = row->GetField(column->fFieldID); BField* field = row->GetField(column->fFieldID);
@@ -3310,33 +3410,33 @@ OutlineView::RedrawColumn(BColumn* column, float leftEdge, bool isFirstColumn)
#if CONSTRAIN_CLIPPING_REGION #if CONSTRAIN_CLIPPING_REGION
BRegion clipRegion(fieldRect); BRegion clipRegion(fieldRect);
fDrawBufferView->PushState(); fResizeBufferView->PushState();
fDrawBufferView->ConstrainClippingRegion(&clipRegion); fResizeBufferView->ConstrainClippingRegion(&clipRegion);
#endif #endif
fDrawBufferView->SetHighColor(fMasterView->Color( fResizeBufferView->SetHighColor(fMasterView->Color(
row->fNextSelected ? B_COLOR_SELECTION_TEXT row->fNextSelected ? B_COLOR_SELECTION_TEXT
: B_COLOR_TEXT)); : B_COLOR_TEXT));
float baseline = floor(fieldRect.top + fh.ascent float baseline = floor(fieldRect.top + fh.ascent
+ (fieldRect.Height() + 1 - (fh.ascent+fh.descent)) / 2); + (fieldRect.Height() + 1 - (fh.ascent+fh.descent)) / 2);
fDrawBufferView->MovePenTo(fieldRect.left + 8, baseline); fResizeBufferView->MovePenTo(fieldRect.left + 8, baseline);
column->DrawField(field, fieldRect, fDrawBufferView); column->DrawField(field, fieldRect, fResizeBufferView);
#if CONSTRAIN_CLIPPING_REGION #if CONSTRAIN_CLIPPING_REGION
fDrawBufferView->PopState(); fResizeBufferView->PopState();
#endif #endif
} }
if (fFocusRow == row && !fEditMode && fMasterView->IsFocus() if (fFocusRow == row && !fEditMode && fMasterView->IsFocus()
&& Window()->IsActive()) { && Window()->IsActive()) {
fDrawBufferView->SetHighColor(fMasterView->Color( fResizeBufferView->SetHighColor(fMasterView->Color(
B_COLOR_ROW_DIVIDER)); B_COLOR_ROW_DIVIDER));
fDrawBufferView->StrokeRect(BRect(-1, sourceRect.top, fResizeBufferView->StrokeRect(BRect(-1, sourceRect.top,
10000.0, sourceRect.bottom)); 10000.0, sourceRect.bottom));
} }
fDrawBufferView->Sync(); fResizeBufferView->Sync();
fDrawBuffer->Unlock(); fResizeBufferView->Unlock();
SetDrawingMode(B_OP_COPY); SetDrawingMode(B_OP_COPY);
DrawBitmap(fDrawBuffer, sourceRect, destRect); DrawBitmap(fResizeBufferView->Bitmap(), sourceRect, destRect);
#else #else
@@ -4013,6 +4113,17 @@ OutlineView::MessageReceived(BMessage* message)
} }
#if DOUBLE_BUFFERED_COLUMN_RESIZE
ColumnResizeBufferView*
OutlineView::ResizeBufferView()
{
return fResizeBufferView;
}
#endif
void void
OutlineView::ChangeFocusRow(bool up, bool updateSelection, OutlineView::ChangeFocusRow(bool up, bool updateSelection,
bool addToCurrentSelection) bool addToCurrentSelection)
@@ -4381,6 +4492,10 @@ OutlineView::AddRow(BRow* row, int32 Index, BRow* parentRow)
} }
} }
#ifdef DOUBLE_BUFFERED_COLUMN_RESIZE
ResizeBufferView()->UpdateMaxHeight(row->Height());
#endif
if (parentRow == 0 || parentRow->fIsExpanded) if (parentRow == 0 || parentRow->fIsExpanded)
fItemsHeight += row->Height() + 1; fItemsHeight += row->Height() + 1;