Tracker: Overhaul list column size initialization and storage.

Mostly for HiDPI, but this also cleans up the code in general, too.

 * Apply a scale-factor when loading and serializing column size/offsets
   in ViewState.

 * Do not hard-code offset values for default columns but let
   BPoseView::AddColumn() compute them manually instead.

 * Change BPoseView::AddColumn() to support being called during
   early initialization and utilize it in SetUpDefaultColumns...().

 * When adding deserialized columns to a BPoseView, always realign
   the offsets instead of just doing sanity checking. The rationale here
   is that the first time the TitleView is touched, it will do this
   anyway, and cause "snapping" or drawing glitches if the alignment
   is not as expected.

   If it was actually somehow an intended feature that non-adjacent
   columns can be displayed, changes are needed in TitleView and PoseView
   to properly support this without triggering redraw glitches.

I still saw some very slight redraw glitches (e.g. column contents
shifting by 1px) at higher font sizes; however, Tracker before this
commit had far more of those glitches (this commit seems to resolve
a number of them.)

Tested with 12pt, 18pt, and 20pt font sizes; this seems to work
pretty well. But if you see strange behavior or more redraw glitches
than there were previously, please do file a ticket.
This commit is contained in:
Augustin Cavalier 2022-08-31 23:59:00 -04:00
parent 509c951d85
commit 054c1b2706
8 changed files with 90 additions and 77 deletions

View File

@ -804,18 +804,20 @@ void
OpenWithPoseView::SetUpDefaultColumnsIfNeeded()
{
// in case there were errors getting some columns
if (fColumnList->CountItems() != 0)
if (CountColumns() != 0)
return;
BColumn* nameColumn = new BColumn(B_TRANSLATE("Name"), StartOffset(), 125,
BColumn* nameColumn = new BColumn(B_TRANSLATE("Name"), 125,
B_ALIGN_LEFT, kAttrStatName, B_STRING_TYPE, true, true);
fColumnList->AddItem(nameColumn);
BColumn* relationColumn = new BColumn(B_TRANSLATE("Relation"), 180, 100,
AddColumn(nameColumn);
BColumn* relationColumn = new BColumn(B_TRANSLATE("Relation"), 100,
B_ALIGN_LEFT, kAttrOpenWithRelation, B_STRING_TYPE, false, false);
fColumnList->AddItem(relationColumn);
fColumnList->AddItem(new BColumn(B_TRANSLATE("Location"), 290, 225,
AddColumn(relationColumn);
AddColumn(new BColumn(B_TRANSLATE("Location"), 225,
B_ALIGN_LEFT, kAttrPath, B_STRING_TYPE, true, false));
fColumnList->AddItem(new BColumn(B_TRANSLATE("Version"), 525, 70,
AddColumn(new BColumn(B_TRANSLATE("Version"), 70,
B_ALIGN_LEFT, kAttrAppVersion, B_STRING_TYPE, false, false));
// sort by relation and by name

View File

@ -347,7 +347,7 @@ BPose::UpdateIcon(BPoint poseLoc, BPoseView* poseView)
BRect rect;
if (poseView->ViewMode() == kListMode) {
rect = CalcRect(poseLoc, poseView);
rect.left += kListOffset;
rect.left += poseView->ListOffset();
rect.right = rect.left + iconSize;
rect.top = rect.bottom - iconSize;
} else {
@ -980,7 +980,7 @@ BPose::_IconRect(const BPoseView* poseView, BPoint location) const
{
uint32 size = poseView->IconSizeInt();
BRect rect;
rect.left = location.x + kListOffset;
rect.left = location.x + poseView->ListOffset();
rect.right = rect.left + size;
rect.top = location.y + (poseView->ListElemHeight() - size) / 2.f;
rect.bottom = rect.top + size;

View File

@ -283,12 +283,13 @@ BPoseView::BPoseView(Model* model, uint32 viewMode)
fCachedIconSizeFrom(0)
{
fListElemHeight = ceilf(be_plain_font->Size() * 1.65f);
fListOffset = ceilf(be_control_look->DefaultLabelSpacing() * 3.3f);
fViewState->SetViewMode(viewMode);
fShowSelectionWhenInactive
= TrackerSettings().ShowSelectionWhenInactive();
fTransparentSelection = TrackerSettings().TransparentSelection();
fFilterStrings.AddItem(new BString(""));
fFilterStrings.AddItem(new BString());
}
@ -434,7 +435,6 @@ BPoseView::RestoreColumnState(AttributeStreamNode* node)
}
}
_ResetStartOffset();
SetUpDefaultColumnsIfNeeded();
if (!ColumnFor(PrimarySort())) {
fViewState->SetPrimarySort(FirstColumn()->AttrHash());
@ -462,7 +462,6 @@ BPoseView::RestoreColumnState(const BMessage &message)
AddColumnList(&tempSortedList);
_ResetStartOffset();
SetUpDefaultColumnsIfNeeded();
if (!ColumnFor(PrimarySort())) {
fViewState->SetPrimarySort(FirstColumn()->AttrHash());
@ -479,16 +478,12 @@ BPoseView::AddColumnList(BObjectList<BColumn>* list)
{
list->SortItems(&CompareColumns);
float nextLeftEdge = 0;
for (int32 columIndex = 0; columIndex < list->CountItems();
columIndex++) {
float nextLeftEdge = StartOffset();
for (int32 columIndex = 0; columIndex < list->CountItems(); columIndex++) {
BColumn* column = list->ItemAt(columIndex);
// Make sure that columns don't overlap
if (column->Offset() < nextLeftEdge) {
PRINT(("\t**Overlapped columns in archived column state\n"));
column->SetOffset(nextLeftEdge);
}
// Always realign columns, since the title-view snaps on resize anyway.
column->SetOffset(nextLeftEdge);
nextLeftEdge = column->Offset() + column->Width()
- kRoomForLine / 2.0f + kTitleColumnExtraMargin;
@ -499,6 +494,9 @@ BPoseView::AddColumnList(BObjectList<BColumn>* list)
StartWatchDateFormatChange();
}
}
if (fTitleView != NULL)
fTitleView->Reset();
}
@ -613,14 +611,14 @@ void
BPoseView::SetUpDefaultColumnsIfNeeded()
{
// in case there were errors getting some columns
if (fColumnList->CountItems() != 0)
if (CountColumns() != 0)
return;
fColumnList->AddItem(new BColumn(B_TRANSLATE("Name"), StartOffset(), 145,
AddColumn(new BColumn(B_TRANSLATE("Name"), 145,
B_ALIGN_LEFT, kAttrStatName, B_STRING_TYPE, true, true));
fColumnList->AddItem(new BColumn(B_TRANSLATE("Size"), 200, 80,
AddColumn(new BColumn(B_TRANSLATE("Size"), 80,
B_ALIGN_RIGHT, kAttrStatSize, B_OFF_T_TYPE, true, false));
fColumnList->AddItem(new BColumn(B_TRANSLATE("Modified"), 295, 150,
AddColumn(new BColumn(B_TRANSLATE("Modified"), 150,
B_ALIGN_LEFT, kAttrStatModified, B_TIME_TYPE, true, false));
if (!IsWatchingDateFormatChange())
@ -2804,7 +2802,7 @@ BPoseView::RemoveColumn(BColumn* columnToRemove, bool runAlert)
bool
BPoseView::AddColumn(BColumn* newColumn, const BColumn* after)
{
if (after == NULL)
if (after == NULL && CountColumns() > 0)
after = LastColumn();
// add new column after last column
@ -2820,7 +2818,8 @@ BPoseView::AddColumn(BColumn* newColumn, const BColumn* after)
// add the new column
fColumnList->AddItem(newColumn, afterColumnIndex + 1);
fTitleView->AddTitle(newColumn);
if (fTitleView != NULL)
fTitleView->AddTitle(newColumn);
BRect rect(Bounds());
@ -2920,7 +2919,7 @@ BPoseView::HandleAttrMenuItemSelected(BMessage* message)
const char* displayAs;
message->FindString("attr_display_as", &displayAs);
column = new BColumn(item->Label(), 0, attrWidth, attrAlign,
column = new BColumn(item->Label(), attrWidth, attrAlign,
attrName, attrType, displayAs, isStatfield, isEditable);
AddColumn(column);
if (item->Menu()->Supermenu() == NULL)
@ -6118,7 +6117,7 @@ BPoseView::MoveListToTrash(BObjectList<entry_ref>* list, bool selectNext,
BPose* pose = fSelectionList->ItemAt(0);
// find a point in the pose
BPoint pointInPose(kListOffset + 5, 5);
BPoint pointInPose(fListOffset + 5, 5);
int32 index = IndexOfPose(pose);
pointInPose.y += fListElemHeight * index;
@ -6340,7 +6339,7 @@ BPoseView::Delete(BObjectList<entry_ref>* list, bool selectNext, bool askUser)
BPose* pose = fSelectionList->ItemAt(0);
// find a point in the pose
BPoint pointInPose(kListOffset + 5, 5);
BPoint pointInPose(fListOffset + 5, 5);
int32 index = IndexOfPose(pose);
pointInPose.y += fListElemHeight * index;
@ -6383,7 +6382,7 @@ BPoseView::RestoreItemsFromTrash(BObjectList<entry_ref>* list, bool selectNext)
BPose* pose = fSelectionList->ItemAt(0);
// find a point in the pose
BPoint pointInPose(kListOffset + 5, 5);
BPoint pointInPose(fListOffset + 5, 5);
int32 index = IndexOfPose(pose);
pointInPose.y += fListElemHeight * index;
@ -8207,7 +8206,7 @@ BPose*
BPoseView::FirstVisiblePose(int32* _index) const
{
ASSERT(ViewMode() == kListMode);
return FindPose(BPoint(kListOffset,
return FindPose(BPoint(fListOffset,
Bounds().top + fListElemHeight - 1), _index);
}
@ -8216,7 +8215,7 @@ BPose*
BPoseView::LastVisiblePose(int32* _index) const
{
ASSERT(ViewMode() == kListMode);
BPose* pose = FindPose(BPoint(kListOffset, Bounds().top + Frame().Height()
BPose* pose = FindPose(BPoint(fListOffset, Bounds().top + Frame().Height()
- fListElemHeight + 2), _index);
if (pose == NULL) {
// Just get the last one
@ -8450,9 +8449,6 @@ BPoseView::SwitchDir(const entry_ref* newDirRef, AttributeStreamNode* node)
viewStateRestored = (fViewState != previousState);
}
// Make sure fTitleView is rebuilt, as fColumnList might have changed
fTitleView->Reset();
if (viewStateRestored) {
if (ViewMode() == kListMode && oldMode != kListMode) {
if (ContainerWindow() != NULL)
@ -8979,7 +8975,7 @@ BPoseView::UpdateScrollRange()
fHScrollBar->GetRange(&scrollMin, &scrollMax);
if (minVal.x != scrollMin || maxVal.x != scrollMax) {
fHScrollBar->SetRange(minVal.x, maxVal.x);
fHScrollBar->SetSteps(kSmallStep, bounds.Width());
fHScrollBar->SetSteps(fListElemHeight / 2.0f, bounds.Width());
}
}
@ -8990,7 +8986,7 @@ BPoseView::UpdateScrollRange()
if (minVal.y != scrollMin || maxVal.y != scrollMax) {
fVScrollBar->SetRange(minVal.y, maxVal.y);
fVScrollBar->SetSteps(kSmallStep, bounds.Height());
fVScrollBar->SetSteps(fListElemHeight / 2.0f, bounds.Height());
}
}
@ -10496,18 +10492,6 @@ BPoseView::ExcludeTrashFromSelection()
}
/*! Since the start offset of the first column is part of the stored
column state, it has to be corrected to match the current offset
(that depends on the font size).
*/
void
BPoseView::_ResetStartOffset()
{
if (!fColumnList->IsEmpty())
fColumnList->ItemAt(0)->SetOffset(StartOffset());
}
// #pragma mark - TScrollBar

View File

@ -72,9 +72,6 @@ class EntryListBase;
class TScrollBar;
const int32 kSmallStep = 10;
const int32 kListOffset = 20;
const uint32 kMiniIconMode = 'Tmic';
const uint32 kIconMode = 'Ticn';
const uint32 kListMode = 'Tlst';
@ -201,6 +198,7 @@ public:
// returns height, descent, etc.
float FontHeight() const;
float ListElemHeight() const;
float ListOffset() const;
void SetIconPoseHeight();
float IconPoseHeight() const;
@ -678,7 +676,6 @@ private:
void DrawOpenAnimation(BRect);
void MoveSelectionOrEntryToTrash(const entry_ref* ref, bool selectNext);
void _ResetStartOffset();
protected:
struct node_ref_key {
@ -733,6 +730,7 @@ protected:
bool fStateNeedsSaving;
BCountView* fCountView;
float fListElemHeight;
float fListOffset;
float fIconPoseHeight;
BPose* fDropTarget;
BPose* fAlreadySelectedDropTarget;
@ -880,6 +878,13 @@ BPoseView::ListElemHeight() const
}
inline float
BPoseView::ListOffset() const
{
return fListOffset;
}
inline float
BPoseView::IconPoseHeight() const
{
@ -1079,7 +1084,7 @@ BPoseView::CountColumns() const
inline float
BPoseView::StartOffset() const
{
return kListOffset + ListIconSize() + kMiniIconSeparator + 1;
return fListOffset + ListIconSize() + kMiniIconSeparator + 1;
}

View File

@ -125,16 +125,16 @@ void
BQueryPoseView::SetUpDefaultColumnsIfNeeded()
{
// in case there were errors getting some columns
if (fColumnList->CountItems() != 0)
if (CountColumns() != 0)
return;
fColumnList->AddItem(new BColumn(B_TRANSLATE("Name"), StartOffset(), 145,
AddColumn(new BColumn(B_TRANSLATE("Name"), 0,
B_ALIGN_LEFT, kAttrStatName, B_STRING_TYPE, true, true));
fColumnList->AddItem(new BColumn(B_TRANSLATE("Location"), 200, 225,
AddColumn(new BColumn(B_TRANSLATE("Location"), 225,
B_ALIGN_LEFT, kAttrPath, B_STRING_TYPE, true, false));
fColumnList->AddItem(new BColumn(B_TRANSLATE("Size"), 440, 80,
AddColumn(new BColumn(B_TRANSLATE("Size"), 80,
B_ALIGN_RIGHT, kAttrStatSize, B_OFF_T_TYPE, true, false));
fColumnList->AddItem(new BColumn(B_TRANSLATE("Modified"), 535, 150,
AddColumn(new BColumn(B_TRANSLATE("Modified"), 150,
B_ALIGN_LEFT, kAttrStatModified, B_TIME_TYPE, true, false));
}

View File

@ -226,8 +226,9 @@ mkColumnsBits(BMallocIO& stream, const ColumnData* src, int32 nelm,
for (int32 i = 0; i < nelm; i++) {
BColumn c(
B_TRANSLATE_CONTEXT(src[i].title, context),
src[i].offset, src[i].width, src[i].align, src[i].attributeName,
src[i].width, src[i].align, src[i].attributeName,
src[i].attrType, src[i].statField, src[i].editable);
c.SetOffset(src[i].offset);
c.ArchiveToStream(&stream);
}

View File

@ -81,20 +81,20 @@ static const int32 kColumnStateMinArchiveVersion = 21;
// #pragma mark - BColumn
BColumn::BColumn(const char* title, float offset, float width,
BColumn::BColumn(const char* title, float width,
alignment align, const char* attributeName, uint32 attrType,
const char* displayAs, bool statField, bool editable)
{
_Init(title, offset, width, align, attributeName, attrType, displayAs,
_Init(title, width, align, attributeName, attrType, displayAs,
statField, editable);
}
BColumn::BColumn(const char* title, float offset, float width,
BColumn::BColumn(const char* title, float width,
alignment align, const char* attributeName, uint32 attrType,
bool statField, bool editable)
{
_Init(title, offset, width, align, attributeName, attrType, NULL,
_Init(title, width, align, attributeName, attrType, NULL,
statField, editable);
}
@ -127,6 +127,9 @@ BColumn::BColumn(BMallocIO* stream, int32 version, bool endianSwap)
fAttrHash = B_SWAP_INT32(fAttrHash);
fAttrType = B_SWAP_INT32(fAttrType);
}
fOffset = ceilf(fOffset * _Scale());
fWidth = ceilf(fWidth * _Scale());
}
@ -137,9 +140,13 @@ BColumn::BColumn(const BMessage &message, int32 index)
if (message.FindFloat(kColumnOffsetName, index, &fOffset) != B_OK)
fOffset = -1.0f;
else
fOffset = ceilf(fOffset * _Scale());
if (message.FindFloat(kColumnWidthName, index, &fWidth) != B_OK)
fWidth = -1.0f;
else
fWidth = ceilf(fWidth * _Scale());
if (message.FindInt32(kColumnAlignmentName, index, (int32*)&fAlignment)
!= B_OK) {
@ -167,20 +174,19 @@ BColumn::BColumn(const BMessage &message, int32 index)
if (message.FindBool(kColumnEditableName, index, &fEditable) != B_OK)
fEditable = false;
}
void
BColumn::_Init(const char* title, float offset, float width,
BColumn::_Init(const char* title, float width,
alignment align, const char* attributeName, uint32 attrType,
const char* displayAs, bool statField, bool editable)
{
fTitle = title;
fAttrName = attributeName;
fDisplayAs = displayAs;
fOffset = offset;
fWidth = width;
fOffset = -1.0f;
fWidth = width * _Scale();
fAlignment = align;
fAttrHash = AttrHashString(attributeName, attrType);
fAttrType = attrType;
@ -189,6 +195,13 @@ BColumn::_Init(const char* title, float offset, float width,
}
/* static */ float
BColumn::_Scale()
{
return (be_plain_font->Size() / 12.0f);
}
BColumn*
BColumn::InstantiateFromStream(BMallocIO* stream, bool endianSwap)
{
@ -242,9 +255,12 @@ BColumn::ArchiveToStream(BMallocIO* stream) const
// PRINT(("ArchiveToStream column, key %x, version %d\n", key, version));
const float offset = floorf(fOffset / _Scale()),
width = floorf(fWidth / _Scale());
StringToStream(&fTitle, stream);
stream->Write(&fOffset, sizeof(float));
stream->Write(&fWidth, sizeof(float));
stream->Write(&offset, sizeof(float));
stream->Write(&width, sizeof(float));
stream->Write(&fAlignment, sizeof(alignment));
StringToStream(&fAttrName, stream);
stream->Write(&fAttrHash, sizeof(uint32));
@ -258,11 +274,14 @@ BColumn::ArchiveToStream(BMallocIO* stream) const
void
BColumn::ArchiveToMessage(BMessage &message) const
{
const float offset = floorf(fOffset / _Scale()),
width = floorf(fWidth / _Scale());
message.AddInt32(kColumnVersionName, kColumnStateArchiveVersion);
message.AddString(kColumnTitleName, fTitle);
message.AddFloat(kColumnOffsetName, fOffset);
message.AddFloat(kColumnWidthName, fWidth);
message.AddFloat(kColumnOffsetName, offset);
message.AddFloat(kColumnWidthName, width);
message.AddInt32(kColumnAlignmentName, fAlignment);
message.AddString(kColumnAttrName, fAttrName);
message.AddInt32(kColumnAttrHashName, static_cast<int32>(fAttrHash));

View File

@ -46,10 +46,10 @@ const int32 kColumnStateArchiveVersion = 22;
class BColumn {
public:
BColumn(const char* title, float offset, float width,
BColumn(const char* title, float width,
alignment align, const char* attributeName, uint32 attrType,
const char* displayAs, bool statField, bool editable);
BColumn(const char* title, float offset, float width,
BColumn(const char* title, float width,
alignment align, const char* attributeName, uint32 attrType,
bool statField, bool editable);
~BColumn();
@ -64,8 +64,6 @@ public:
void ArchiveToMessage(BMessage &) const;
const char* Title() const;
float Offset() const;
float Width() const;
alignment Alignment() const;
const char* AttrName() const;
uint32 AttrType() const;
@ -74,14 +72,18 @@ public:
bool StatField() const;
bool Editable() const;
//! These two values are automatically scaled to the font size.
float Offset() const;
float Width() const;
void SetOffset(float);
void SetWidth(float);
private:
void _Init(const char* title, float offset, float width,
void _Init(const char* title, float width,
alignment align, const char* attributeName, uint32 attrType,
const char* displayAs, bool statField, bool editable);
static BColumn* _Sanitize(BColumn* column);
static float _Scale();
BString fTitle;
float fOffset;