HaikuDepot: UI Scaling

Fix aspects of HaikuDepot's UI that do not scale when
the font size changes to accommodate a high resolution
monitor.

Change-Id: I105ebfe5a8f501cd7ffc22822438147ba07382a3
Reviewed-on: https://review.haiku-os.org/c/haiku/+/7844
Reviewed-by: waddlesplash <waddlesplash@gmail.com>
Haiku-Format: Haiku-format Bot <no-reply+haikuformatbot@haiku-os.org>
This commit is contained in:
Andrew Lindesay 2024-07-05 21:49:07 +12:00 committed by waddlesplash
parent 987a1436b3
commit c3cad23617
11 changed files with 440 additions and 194 deletions

View File

@ -89,35 +89,32 @@ IconTarPtrEntryListener::Handle(const TarArchiveHeader& header,
fileName.CopyInto(packageName, 5, secondSlashIdx - 5);
fileName.CopyInto(leafName, secondSlashIdx + 1,
fileName.Length() - (secondSlashIdx + 1));
BitmapSize bitmapSize;
BitmapSize storedSize;
if (_LeafNameToBitmapSize(leafName, &bitmapSize) == B_OK) {
fPackageIconTarRepository->AddIconTarPtr(packageName, bitmapSize,
offset);
}
if (_LeafNameToBitmapSize(leafName, &storedSize) == B_OK)
fPackageIconTarRepository->AddIconTarPtr(packageName, storedSize, offset);
return B_OK;
}
status_t
IconTarPtrEntryListener::_LeafNameToBitmapSize(BString& leafName,
BitmapSize* bitmapSize)
IconTarPtrEntryListener::_LeafNameToBitmapSize(BString& leafName, BitmapSize* storedSize)
{
if (leafName == "icon.hvif") {
*bitmapSize = BITMAP_SIZE_ANY;
*storedSize = BITMAP_SIZE_ANY;
return B_OK;
}
if (leafName == "64.png") {
*bitmapSize = BITMAP_SIZE_64;
*storedSize = BITMAP_SIZE_64;
return B_OK;
}
if (leafName == "32.png") {
*bitmapSize = BITMAP_SIZE_32;
*storedSize = BITMAP_SIZE_32;
return B_OK;
}
if (leafName == "16.png") {
*bitmapSize = BITMAP_SIZE_16;
*storedSize = BITMAP_SIZE_16;
return B_OK;
}
return B_BAD_VALUE;
@ -230,11 +227,11 @@ PackageIconTarRepository::_Close()
the parsing of the tar headers. It is called from the listener above.
*/
void
PackageIconTarRepository::AddIconTarPtr(const BString& packageName, BitmapSize bitmapSize,
PackageIconTarRepository::AddIconTarPtr(const BString& packageName, BitmapSize storedSize,
off_t offset)
{
IconTarPtrRef tarPtrRef = _GetOrCreateIconTarPtr(packageName);
tarPtrRef->SetOffset(bitmapSize, offset);
tarPtrRef->SetOffset(storedSize, offset);
}
@ -263,20 +260,20 @@ PackageIconTarRepository::GetIcon(const BString& pkgName, uint32 size,
status_t result = B_OK;
off_t iconDataTarOffset = -1;
const IconTarPtrRef tarPtrRef = _GetIconTarPtr(pkgName);
BitmapSize bitmapSize;
BitmapSize storedSize;
if (tarPtrRef.IsSet()) {
bitmapSize = _BestStoredSize(tarPtrRef, size);
iconDataTarOffset = tarPtrRef->Offset(bitmapSize);
storedSize = _BestStoredSize(tarPtrRef, size);
iconDataTarOffset = tarPtrRef->Offset(storedSize);
}
if (iconDataTarOffset >= 0) {
HashString key = _ToIconCacheKey(pkgName, bitmapSize);
HashString key = _ToIconCacheKey(pkgName, storedSize, size);
if (fIconCache.ContainsKey(key)) {
bitmapHolderRef.SetTo(fIconCache.Get(key).Get());
} else {
result = _CreateIconFromTarOffset(iconDataTarOffset, bitmapHolderRef);
result = _CreateIconFromTarOffset(iconDataTarOffset, storedSize, size, bitmapHolderRef);
if (result == B_OK) {
HDTRACE("loaded package icon [%s] of size %" B_PRId32, pkgName.String(), size);
fIconCache.Put(key, bitmapHolderRef);
@ -303,10 +300,9 @@ PackageIconTarRepository::_GetIconTarPtr(const BString& pkgName) const
const char*
PackageIconTarRepository::_ToIconCacheKeySuffix(BitmapSize size)
PackageIconTarRepository::_ToIconCacheKeyPart(BitmapSize storedSize)
{
switch (size)
{
switch (storedSize) {
case BITMAP_SIZE_16:
return "16";
// note that size 22 is not supported.
@ -324,16 +320,19 @@ PackageIconTarRepository::_ToIconCacheKeySuffix(BitmapSize size)
const HashString
PackageIconTarRepository::_ToIconCacheKey(const BString& pkgName, BitmapSize size)
PackageIconTarRepository::_ToIconCacheKey(const BString& pkgName, BitmapSize storedSize,
uint32 size)
{
return HashString(BString(pkgName) << "__x" << _ToIconCacheKeySuffix(size));
return HashString(
BString(pkgName) << "__s" << _ToIconCacheKeyPart(storedSize) << "__x" << size);
}
/*! This method must only be invoked with the class locked.
*/
status_t
PackageIconTarRepository::_CreateIconFromTarOffset(off_t offset, BitmapHolderRef& bitmapHolderRef)
PackageIconTarRepository::_CreateIconFromTarOffset(off_t offset, BitmapSize storedSize, uint32 size,
BitmapHolderRef& bitmapHolderRef)
{
fTarIo->Seek(offset, SEEK_SET);
fIconDataBuffer->Seek(0, SEEK_SET);
@ -365,17 +364,29 @@ PackageIconTarRepository::_CreateIconFromTarOffset(off_t offset, BitmapHolderRef
fIconDataBuffer->Seek(0, SEEK_SET);
if (result == B_OK) {
BBitmap* bitmap = BTranslationUtils::GetBitmap(fIconDataBuffer);
BBitmap* bitmap = NULL;
if (bitmap == NULL) {
HDERROR("unable to decode data from tar for icon image");
result = B_ERROR;
if (result == B_OK) {
if (BITMAP_SIZE_ANY == storedSize) {
bitmap = new BBitmap(BRect(0, 0, size - 1, size - 1), 0, B_RGBA32);
result = bitmap->InitCheck();
result = BIconUtils::GetVectorIcon(
reinterpret_cast<const uint8*>(fIconDataBuffer->Buffer()), header.Length(), bitmap);
} else {
bitmapHolderRef.SetTo(new(std::nothrow) BitmapHolder(bitmap), true);
bitmap = BTranslationUtils::GetBitmap(fIconDataBuffer);
if (bitmap == NULL) {
HDERROR("unable to decode data from tar for icon image");
result = B_ERROR;
}
}
}
if (result != B_OK)
delete bitmap;
else
bitmapHolderRef.SetTo(new(std::nothrow) BitmapHolder(bitmap), true);
return result;
}

View File

@ -38,15 +38,15 @@ public:
private:
void _Close();
const char* _ToIconCacheKeySuffix(BitmapSize size);
const HashString _ToIconCacheKey(const BString& pkgName,
BitmapSize size);
const char* _ToIconCacheKeyPart(BitmapSize size);
const HashString _ToIconCacheKey(const BString& pkgName, BitmapSize storedSize,
uint32 size);
IconTarPtrRef _GetOrCreateIconTarPtr(const BString& pkgName);
IconTarPtrRef _GetIconTarPtr(const BString& pkgName) const;
status_t _CreateIconFromTarOffset(off_t offset,
BitmapHolderRef& bitmapHolderRef);
status_t _CreateIconFromTarOffset(off_t offset, BitmapSize bitmapSize,
uint32 size, BitmapHolderRef& bitmapHolderRef);
status_t _GetDefaultIcon(uint32 size, BitmapHolderRef& bitmapHolderRef);

View File

@ -22,12 +22,12 @@ ScreenshotCoordinate::ScreenshotCoordinate()
ScreenshotCoordinate::ScreenshotCoordinate(const BMessage* from)
{
from->FindString(kCodeKey, &fCode);
from->FindUInt16(kWidthKey, &fWidth);
from->FindUInt16(kHeightKey, &fHeight);
from->FindUInt32(kWidthKey, &fWidth);
from->FindUInt32(kHeightKey, &fHeight);
}
ScreenshotCoordinate::ScreenshotCoordinate(BString code, uint16 width, uint16 height)
ScreenshotCoordinate::ScreenshotCoordinate(BString code, uint32 width, uint32 height)
:
fCode(code),
fWidth(width),
@ -48,14 +48,14 @@ ScreenshotCoordinate::Code() const
}
uint16
uint32
ScreenshotCoordinate::Width() const
{
return fWidth;
}
uint16
uint32
ScreenshotCoordinate::Height() const
{
return fHeight;
@ -80,7 +80,7 @@ const BString
ScreenshotCoordinate::Key() const
{
BString result;
result.SetToFormat("%s_%" B_PRIu16 "x%" B_PRIu16 , fCode.String(), fWidth, fHeight);
result.SetToFormat("%s_%" B_PRIu32 "x%" B_PRIu32, fCode.String(), fWidth, fHeight);
return result;
}
@ -99,8 +99,8 @@ ScreenshotCoordinate::Archive(BMessage* into, bool deep) const
if (result == B_OK)
result = into->AddString(kCodeKey, fCode);
if (result == B_OK)
result = into->AddUInt16(kWidthKey, fWidth);
result = into->AddUInt32(kWidthKey, fWidth);
if (result == B_OK)
result = into->AddUInt16(kHeightKey, fHeight);
result = into->AddUInt32(kHeightKey, fHeight);
return result;
}

View File

@ -18,13 +18,13 @@
class ScreenshotCoordinate : public BArchivable {
public:
ScreenshotCoordinate(const BMessage* from);
ScreenshotCoordinate(BString code, uint16 width, uint16 height);
ScreenshotCoordinate(BString code, uint32 width, uint32 height);
ScreenshotCoordinate();
virtual ~ScreenshotCoordinate();
const BString Code() const;
uint16 Width() const;
uint16 Height() const;
uint32 Width() const;
uint32 Height() const;
bool operator==(const ScreenshotCoordinate& other) const;
@ -36,8 +36,8 @@ public:
private:
BString fCode;
uint16 fWidth;
uint16 fHeight;
uint32 fWidth;
uint32 fHeight;
};

View File

@ -12,13 +12,13 @@
#include <Bitmap.h>
#include <Catalog.h>
#include <ControlLook.h>
#include <Font.h>
#include <LayoutBuilder.h>
#include <LayoutItem.h>
#include <Message.h>
#include <ScrollView.h>
#include <StringView.h>
#include <SpaceLayoutItem.h>
#include "BitmapView.h"
#include "HaikuDepotConstants.h"
@ -35,21 +35,148 @@
#undef B_TRANSLATION_CONTEXT
#define B_TRANSLATION_CONTEXT "FeaturedPackagesView"
#define HEIGHT_PACKAGE 84.0f
#define SIZE_ICON 64.0f
#define X_POSITION_RATING 350.0f
#define X_POSITION_SUMMARY 500.0f
#define WIDTH_RATING 100.0f
#define Y_PROPORTION_TITLE 0.35f
#define Y_PROPORTION_PUBLISHER 0.60f
#define Y_PROPORTION_CHRONOLOGICAL_DATA 0.75f
#define PADDING 8.0f
// If the space for the summary has less than this many "M" characters then the summary will not be
// displayed.
#define MINIMUM_M_COUNT_SUMMARY 10.0f
// The title area will be this many times the width of an "M".
#define M_COUNT_TITLE 10
// #pragma mark - PackageView
class StackedFeaturesPackageBandMetrics
{
public:
StackedFeaturesPackageBandMetrics(float width, BFont* titleFont, BFont* metadataFont)
{
float padding = be_control_look->DefaultItemSpacing();
BSize iconSize = BControlLook::ComposeIconSize(SIZE_ICON);
font_height titleFontHeight;
font_height metadataFontHeight;
titleFont->GetHeight(&titleFontHeight);
metadataFont->GetHeight(&metadataFontHeight);
float totalTitleAndMetadataHeight = titleFontHeight.ascent + titleFontHeight.descent
+ titleFontHeight.leading
+ metadataFontHeight.leading
+ 2.0 * (metadataFontHeight.ascent + metadataFontHeight.descent);
fHeight = fmaxf(totalTitleAndMetadataHeight, iconSize.Height()) + 2.0 * padding;
{
float iconInset = (fHeight - iconSize.Width()) / 2.0;
fIconRect = BRect(padding, iconInset, iconSize.Width() + padding,
iconSize.Height() + iconInset);
}
{
float titleWidthM = titleFont->StringWidth("M");
float leftTitlePublisherAndChronologicalInfo = fIconRect.right + padding;
float rightTitlePublisherAndChronologicalInfo = fminf(width, fIconRect.Size().Width()
+ (2.0 * padding) + (titleWidthM * M_COUNT_TITLE));
// left, top, right bottom
fTitleRect = BRect(leftTitlePublisherAndChronologicalInfo,
(fHeight - totalTitleAndMetadataHeight) / 2.0,
rightTitlePublisherAndChronologicalInfo,
((fHeight - totalTitleAndMetadataHeight) / 2.0)
+ titleFontHeight.ascent + titleFontHeight.descent);
fPublisherRect = BRect(leftTitlePublisherAndChronologicalInfo,
fTitleRect.bottom + titleFontHeight.leading,
rightTitlePublisherAndChronologicalInfo,
fTitleRect.bottom + titleFontHeight.leading
+ metadataFontHeight.ascent + metadataFontHeight.descent);
fChronologicalInfoRect = BRect(leftTitlePublisherAndChronologicalInfo,
fPublisherRect.bottom + metadataFontHeight.leading,
rightTitlePublisherAndChronologicalInfo,
fPublisherRect.bottom + metadataFontHeight.leading
+ metadataFontHeight.ascent + metadataFontHeight.descent);
}
// sort out the ratings display
{
BSize ratingStarSize = SharedIcons::IconStarBlue16Scaled()->Bitmap()->Bounds().Size();
RatingStarsMetrics ratingStarsMetrics(ratingStarSize);
fRatingStarsRect = BRect(BPoint(fTitleRect.right + padding,
(fHeight - ratingStarsMetrics.Size().Height()) / 2), ratingStarsMetrics.Size());
if (fRatingStarsRect.right > width)
fRatingStarsRect = BRect();
else {
// Now sort out the position for the summary. This is reckoned as a container
// rect because it would be nice to layout the text with newlines and not just a
// single line.
fSummaryContainerRect = BRect(fRatingStarsRect.right + (padding * 2.0), padding,
width - padding, fHeight - (padding * 2.0));
float metadataWidthM = metadataFont->StringWidth("M");
if (fSummaryContainerRect.Size().Width() < MINIMUM_M_COUNT_SUMMARY * metadataWidthM)
fSummaryContainerRect = BRect();
}
}
}
float Height()
{
return fHeight;
}
BRect IconRect()
{
return fIconRect;
}
BRect TitleRect()
{
return fTitleRect;
}
BRect PublisherRect()
{
return fPublisherRect;
}
BRect ChronologicalInfoRect()
{
return fChronologicalInfoRect;
}
BRect RatingStarsRect()
{
return fRatingStarsRect;
}
BRect SummaryContainerRect()
{
return fSummaryContainerRect;
}
private:
float fHeight;
BRect fIconRect;
BRect fTitleRect;
BRect fPublisherRect;
BRect fChronologicalInfoRect;
BRect fRatingStarsRect;
BRect fSummaryContainerRect;
};
class StackedFeaturedPackagesView : public BView {
public:
StackedFeaturedPackagesView(Model& model)
@ -62,6 +189,12 @@ public:
fLowestIndexAddedOrRemoved(-1)
{
SetEventMask(B_POINTER_EVENTS);
fTitleFont = StackedFeaturedPackagesView::CreateTitleFont();
fMetadataFont = StackedFeaturedPackagesView::CreateMetadataFont();
fSummaryFont = StackedFeaturedPackagesView::CreateSummaryFont();
fBandMetrics = CreateBandMetrics();
Clear();
}
@ -70,6 +203,10 @@ public:
{
fPackageListener->SetPackage(PackageInfoRef(NULL));
fPackageListener->ReleaseReference();
delete fBandMetrics;
delete fTitleFont;
delete fMetadataFont;
delete fSummaryFont;
}
// #pragma mark - message handling and events
@ -144,7 +281,7 @@ public:
case B_PAGE_DOWN:
{
BRect bounds = Bounds();
float height = fPackages.size() * HEIGHT_PACKAGE;
float height = fPackages.size() * fBandMetrics->Height();
float maxScrollY = height - bounds.Height();
float pageDownScrollY = bounds.top + bounds.Height();
ScrollTo(0, fminf(maxScrollY, pageDownScrollY));
@ -177,12 +314,10 @@ public:
{
BView::FrameResized(width, height);
// because the summary text will wrap, a resize of the frame will
// result in all of the summary area needing to be redrawn.
delete fBandMetrics;
fBandMetrics = CreateBandMetrics();
BRect rectToInvalidate = Bounds();
rectToInvalidate.left = X_POSITION_SUMMARY;
Invalidate(rectToInvalidate);
Invalidate();
}
@ -208,10 +343,46 @@ public:
}
fPackages.clear();
fSelectedIndex = -1;
Invalidate();
}
static BFont* CreateTitleFont()
{
BFont* font = new BFont(be_plain_font);
font_family family;
font_style style;
font->SetSize(ceilf(font->Size() * 1.8f));
font->GetFamilyAndStyle(&family, &style);
font->SetFamilyAndStyle(family, "Bold");
return font;
}
static BFont* CreateMetadataFont()
{
BFont* font = new BFont(be_plain_font);
font_family family;
font_style style;
font->GetFamilyAndStyle(&family, &style);
font->SetFamilyAndStyle(family, "Italic");
return font;
}
static BFont* CreateSummaryFont()
{
return new BFont(be_plain_font);
}
StackedFeaturesPackageBandMetrics* CreateBandMetrics()
{
return new StackedFeaturesPackageBandMetrics(Bounds().Width(), fTitleFont, fMetadataFont);
}
bool IsEmpty() const
{
return fPackages.size() == 0;
@ -386,13 +557,11 @@ public:
void _DrawPackageAtIndex(BRect updateRect, int32 index)
{
_DrawPackage(updateRect, fPackages[index], index, _YOfIndex(index),
index == fSelectedIndex);
_DrawPackage(updateRect, fPackages[index], _YOfIndex(index), index == fSelectedIndex);
}
void _DrawPackage(BRect updateRect, PackageInfoRef pkg, int index, float y,
bool selected)
void _DrawPackage(BRect updateRect, PackageInfoRef pkg, float y, bool selected)
{
if (selected) {
SetLowUIColor(B_LIST_SELECTED_BACKGROUND_COLOR);
@ -400,152 +569,155 @@ public:
} else {
SetLowUIColor(B_LIST_BACKGROUND_COLOR);
}
BRect iconRect = fBandMetrics->IconRect();
BRect titleRect = fBandMetrics->TitleRect();
BRect publisherRect = fBandMetrics->PublisherRect();
BRect chronologicalInfoRect = fBandMetrics->ChronologicalInfoRect();
BRect ratingStarsRect = fBandMetrics->RatingStarsRect();
BRect summaryContainerRect = fBandMetrics->SummaryContainerRect();
iconRect.OffsetBy(0.0, y);
titleRect.OffsetBy(0.0, y);
publisherRect.OffsetBy(0.0, y);
chronologicalInfoRect.OffsetBy(0.0, y);
ratingStarsRect.OffsetBy(0.0, y);
summaryContainerRect.OffsetBy(0.0, y);
// TODO; optimization; the updateRect may only cover some of this?
_DrawPackageIcon(updateRect, pkg, y, selected);
_DrawPackageTitle(updateRect, pkg, y, selected);
_DrawPackagePublisher(updateRect, pkg, y, selected);
_DrawPackageCronologicalInfo(updateRect, pkg, y, selected);
_DrawPackageRating(updateRect, pkg, y, selected);
_DrawPackageSummary(updateRect, pkg, y, selected);
_DrawPackageIcon(iconRect, pkg, selected);
_DrawPackageTitle(titleRect, pkg, selected);
_DrawPackagePublisher(publisherRect, pkg, selected);
_DrawPackageChronologicalInfo(chronologicalInfoRect, pkg, selected);
_DrawPackageRating(ratingStarsRect, pkg);
_DrawPackageSummary(summaryContainerRect, pkg, selected);
}
void _DrawPackageIcon(BRect updateRect, PackageInfoRef pkg, float y,
bool selected)
void _DrawPackageIcon(BRect iconRect, PackageInfoRef pkg, bool selected)
{
if (!iconRect.IsValid())
return;
BitmapHolderRef icon;
status_t iconResult = fModel.GetPackageIconRepository().GetIcon(
pkg->Name(), 64, icon);
status_t iconResult = fModel.GetPackageIconRepository().GetIcon(pkg->Name(),
iconRect.Width(), icon);
if (iconResult == B_OK) {
if (icon.IsSet()) {
float inset = (HEIGHT_PACKAGE - SIZE_ICON) / 2.0;
BRect targetRect = BRect(inset, y + inset, SIZE_ICON + inset,
y + SIZE_ICON + inset);
const BBitmap* bitmap = icon->Bitmap();
if (bitmap != NULL && bitmap->IsValid()) {
SetDrawingMode(B_OP_ALPHA);
DrawBitmap(bitmap, bitmap->Bounds(), targetRect,
B_FILTER_BITMAP_BILINEAR);
DrawBitmap(bitmap, bitmap->Bounds(), iconRect, B_FILTER_BITMAP_BILINEAR);
}
}
}
}
void _DrawPackageTitle(BRect updateRect, PackageInfoRef pkg, float y,
bool selected)
void _DrawPackageTitle(BRect textRect, PackageInfoRef pkg, bool selected)
{
static BFont* sFont = NULL;
if (!textRect.IsValid())
return;
if (sFont == NULL) {
sFont = new BFont(be_plain_font);
GetFont(sFont);
font_family family;
font_style style;
sFont->SetSize(ceilf(sFont->Size() * 1.8f));
sFont->GetFamilyAndStyle(&family, &style);
sFont->SetFamilyAndStyle(family, "Bold");
}
const BBitmap* installedIconBitmap = SharedIcons::IconInstalled16Scaled()->Bitmap();
SetDrawingMode(B_OP_COPY);
SetHighUIColor(selected ? B_LIST_SELECTED_ITEM_TEXT_COLOR
: B_LIST_ITEM_TEXT_COLOR);
SetFont(sFont);
BPoint pt(HEIGHT_PACKAGE, y + (HEIGHT_PACKAGE * Y_PROPORTION_TITLE));
DrawString(pkg->Title(), pt);
SetHighUIColor(selected ? B_LIST_SELECTED_ITEM_TEXT_COLOR : B_LIST_ITEM_TEXT_COLOR);
SetFont(fTitleFont);
font_height fontHeight;
fTitleFont->GetHeight(&fontHeight);
BPoint pt = textRect.LeftTop() + BPoint(0.0, + fontHeight.ascent);
BString renderedText = pkg->Title();
float installedIconAllowance = installedIconBitmap->Bounds().Width() * 1.5;
TruncateString(&renderedText, B_TRUNCATE_END, textRect.Width() - installedIconAllowance);
DrawString(renderedText, pt);
if (pkg->State() == ACTIVATED) {
const BBitmap* bitmap = SharedIcons::IconInstalled16Scaled()->Bitmap();
if (bitmap != NULL && bitmap->IsValid()) {
float stringWidth = StringWidth(pkg->Title());
float offsetX = pt.x + stringWidth + PADDING;
BRect targetRect(offsetX, pt.y - 16,
offsetX + 16, pt.y);
SetDrawingMode(B_OP_ALPHA);
DrawBitmap(bitmap, bitmap->Bounds(), targetRect,
B_FILTER_BITMAP_BILINEAR);
}
float stringWidth = StringWidth(pkg->Title());
BRect iconRect = BRect(
BPoint(textRect.left + stringWidth + (installedIconBitmap->Bounds().Width() / 2.0),
textRect.top + (textRect.Height() / 2.0)
- (installedIconBitmap->Bounds().Height() / 2.0)),
installedIconBitmap->Bounds().Size());
SetDrawingMode(B_OP_ALPHA);
DrawBitmap(installedIconBitmap, installedIconBitmap->Bounds(), iconRect,
B_FILTER_BITMAP_BILINEAR);
}
}
void _DrawPackageGenericTextSlug(BRect updateRect, PackageInfoRef pkg,
const BString& text, float y, float yProportion, bool selected)
void _DrawPackageGenericTextSlug(BRect textRect, const BString& text, bool selected)
{
static BFont* sFont = NULL;
if (sFont == NULL) {
sFont = new BFont(be_plain_font);
font_family family;
font_style style;
sFont->SetSize(std::max(9.0f, floorf(sFont->Size() * 0.92f)));
sFont->GetFamilyAndStyle(&family, &style);
sFont->SetFamilyAndStyle(family, "Italic");
}
if (!textRect.IsValid())
return;
SetDrawingMode(B_OP_COPY);
SetHighUIColor(selected ? B_LIST_SELECTED_ITEM_TEXT_COLOR
: B_LIST_ITEM_TEXT_COLOR);
SetFont(sFont);
SetHighUIColor(selected ? B_LIST_SELECTED_ITEM_TEXT_COLOR : B_LIST_ITEM_TEXT_COLOR);
SetFont(fMetadataFont);
font_height fontHeight;
fMetadataFont->GetHeight(&fontHeight);
BPoint pt = textRect.LeftTop() + BPoint(0.0, + fontHeight.ascent);
float maxTextWidth = (X_POSITION_RATING - HEIGHT_PACKAGE) - PADDING;
BString renderedText(text);
TruncateString(&renderedText, B_TRUNCATE_END, maxTextWidth);
TruncateString(&renderedText, B_TRUNCATE_END, textRect.Width());
DrawString(renderedText, BPoint(HEIGHT_PACKAGE,
y + (HEIGHT_PACKAGE * yProportion)));
DrawString(renderedText, pt);
}
void _DrawPackagePublisher(BRect updateRect, PackageInfoRef pkg, float y,
bool selected)
void _DrawPackagePublisher(BRect textRect, PackageInfoRef pkg, bool selected)
{
_DrawPackageGenericTextSlug(updateRect, pkg, pkg->Publisher().Name(), y,
Y_PROPORTION_PUBLISHER, selected);
_DrawPackageGenericTextSlug(textRect, pkg->Publisher().Name(), selected);
}
void _DrawPackageCronologicalInfo(BRect updateRect, PackageInfoRef pkg,
float y, bool selected)
void _DrawPackageChronologicalInfo(BRect textRect, PackageInfoRef pkg, bool selected)
{
BString versionCreateTimestampPresentation
= LocaleUtils::TimestampToDateString(pkg->VersionCreateTimestamp());
_DrawPackageGenericTextSlug(updateRect, pkg,
versionCreateTimestampPresentation, y,
Y_PROPORTION_CHRONOLOGICAL_DATA, selected);
_DrawPackageGenericTextSlug(textRect, versionCreateTimestampPresentation, selected);
}
// TODO; show the sample size
void _DrawPackageRating(BRect updateRect, PackageInfoRef pkg, float y,
bool selected)
void _DrawPackageRating(BRect ratingRect, PackageInfoRef pkg)
{
BPoint at(X_POSITION_RATING,
y + (HEIGHT_PACKAGE - SIZE_RATING_STAR) / 2.0f);
RatingUtils::Draw(this, at,
pkg->CalculateRatingSummary().averageRating);
if (!ratingRect.IsValid())
return;
RatingUtils::Draw(this, ratingRect.LeftTop(), pkg->CalculateRatingSummary().averageRating);
}
// TODO; handle multi-line rendering of the text
void _DrawPackageSummary(BRect updateRect, PackageInfoRef pkg, float y,
bool selected)
void _DrawPackageSummary(BRect textRect, PackageInfoRef pkg, bool selected)
{
BRect bounds = Bounds();
if (!textRect.IsValid())
return;
SetDrawingMode(B_OP_COPY);
SetHighUIColor(selected ? B_LIST_SELECTED_ITEM_TEXT_COLOR
: B_LIST_ITEM_TEXT_COLOR);
SetFont(be_plain_font);
SetHighUIColor(selected ? B_LIST_SELECTED_ITEM_TEXT_COLOR : B_LIST_ITEM_TEXT_COLOR);
SetFont(fSummaryFont);
font_height fontHeight;
fSummaryFont->GetHeight(&fontHeight);
// The text rect is a container into which later text can be made to flow multi-line. For
// now just draw one line of the summary.
BPoint pt = textRect.LeftTop() + BPoint(0.0,
(textRect.Size().Height() / 2.0) - ((fontHeight.ascent + fontHeight.descent) / 2.0)
+ fontHeight.ascent);
float maxTextWidth = bounds.Width() - X_POSITION_SUMMARY - PADDING;
BString summary(pkg->ShortDescription());
TruncateString(&summary, B_TRUNCATE_END, maxTextWidth);
TruncateString(&summary, B_TRUNCATE_END, textRect.Width());
DrawString(summary, BPoint(X_POSITION_SUMMARY,
y + (HEIGHT_PACKAGE * 0.5)));
DrawString(summary, pt);
}
@ -563,13 +735,11 @@ public:
{
if (!_IsIndexEntirelyVisible(index)) {
BRect bounds = Bounds();
int32 indexOfCentreVisible = _IndexOfY(
bounds.top + bounds.Height() / 2);
int32 indexOfCentreVisible = _IndexOfY(bounds.top + bounds.Height() / 2);
if (index < indexOfCentreVisible)
ScrollTo(0, _YOfIndex(index));
else {
float scrollPointY = (_YOfIndex(index) + HEIGHT_PACKAGE)
- bounds.Height();
float scrollPointY = (_YOfIndex(index) + fBandMetrics->Height()) - bounds.Height();
ScrollTo(0, scrollPointY);
}
}
@ -613,13 +783,13 @@ public:
BRect _RectOfY(float y) const
{
return BRect(0, y, Bounds().Width(), y + HEIGHT_PACKAGE);
return BRect(0, y, Bounds().Width(), y + fBandMetrics->Height());
}
float _YOfIndex(int32 i) const
{
return i * HEIGHT_PACKAGE;
return i * fBandMetrics->Height();
}
@ -632,7 +802,7 @@ public:
{
if (fPackages.empty())
return -1;
int32 i = static_cast<int32>(y / HEIGHT_PACKAGE);
int32 i = static_cast<int32>(y / fBandMetrics->Height());
if (i < 0 || i >= static_cast<int32>(fPackages.size()))
return -1;
return i;
@ -649,7 +819,7 @@ public:
{
if (fPackages.empty())
return -1;
int32 i = static_cast<int32>(y / HEIGHT_PACKAGE);
int32 i = static_cast<int32>(y / fBandMetrics->Height());
if (i < 0)
return 0;
return std::min(i, (int32) (fPackages.size() - 1));
@ -658,7 +828,8 @@ public:
virtual BSize PreferredSize()
{
return BSize(B_SIZE_UNLIMITED, HEIGHT_PACKAGE * fPackages.size());
return BSize(B_SIZE_UNLIMITED,
fBandMetrics->Height() * static_cast<float>(fPackages.size()));
}
@ -670,6 +841,12 @@ private:
OnePackageMessagePackageListener*
fPackageListener;
int32 fLowestIndexAddedOrRemoved;
StackedFeaturesPackageBandMetrics*
fBandMetrics;
BFont* fTitleFont;
BFont* fMetadataFont;
BFont* fSummaryFont;
};

View File

@ -14,6 +14,7 @@
#include <CardLayout.h>
#include <Catalog.h>
#include <ColumnListView.h>
#include <ControlLook.h>
#include <Font.h>
#include <GridView.h>
#include <LayoutBuilder.h>
@ -64,7 +65,7 @@ enum {
static const float kContentTint = (B_NO_TINT + B_LIGHTEN_1_TINT) / 2.0f;
static const uint16 kScreenshotSize = 320;
static const uint32 kScreenshotSize = 320;
class RatingsScrollView : public GeneralContentScrollView {
@ -361,8 +362,9 @@ public:
void SetPackage(const PackageInfoRef package)
{
BitmapHolderRef bitmapHolderRef;
status_t iconResult = fPackageIconRepository.GetIcon(
package->Name(), 32, bitmapHolderRef);
BSize iconSize = BControlLook::ComposeIconSize(32.0);
status_t iconResult = fPackageIconRepository.GetIcon(package->Name(), iconSize.Width() + 1,
bitmapHolderRef);
if (iconResult == B_OK)
fIconView->SetBitmap(bitmapHolderRef);
@ -1402,7 +1404,13 @@ PackageInfoView::_ScreenshotThumbCoordinate(const PackageInfoRef& package)
return ScreenshotCoordinate();
if (package->CountScreenshotInfos() == 0)
return ScreenshotCoordinate();
return ScreenshotCoordinate(package->ScreenshotInfoAtIndex(0)->Code(), kScreenshotSize, kScreenshotSize);
uint32 screenshotSizeScaled
= MAX(static_cast<uint32>(BControlLook::ComposeIconSize(kScreenshotSize).Width()),
MAX_IMAGE_SIZE);
return ScreenshotCoordinate(package->ScreenshotInfoAtIndex(0)->Code(), screenshotSizeScaled + 1,
screenshotSizeScaled + 1);
}

View File

@ -386,8 +386,8 @@ PackageColumn::DrawField(BField* field, BRect rect, BView* parent)
RatingField* ratingField = dynamic_cast<RatingField*>(field);
if (packageIconAndTitleField != NULL) {
// Scale the bitmap to 16x16
BRect r = BRect(0, 0, 15, 15);
BSize iconSize = BControlLook::ComposeIconSize(16);
BRect r(BPoint(0, 0), iconSize);
// figure out the placement
float x = 0.0;
@ -422,14 +422,14 @@ PackageColumn::DrawField(BField* field, BRect rect, BView* parent)
status_t bitmapResult;
bitmapResult = fModel->GetPackageIconRepository().GetIcon(
packageIconAndTitleField->PackageName(), 16, bitmapHolderRef);
packageIconAndTitleField->PackageName(), iconSize.Width() + 1, bitmapHolderRef);
if (bitmapResult == B_OK) {
if (bitmapHolderRef.IsSet()) {
const BBitmap* bitmap = bitmapHolderRef->Bitmap();
if (bitmap != NULL && bitmap->IsValid()) {
parent->SetDrawingMode(B_OP_ALPHA);
BRect viewRect(x, y, x + 15, y + 15);
BRect viewRect(BPoint(x, y), iconSize);
parent->DrawBitmap(bitmap, bitmap->Bounds(), viewRect);
parent->SetDrawingMode(B_OP_OVER);
}

View File

@ -5,6 +5,7 @@
#include "SharedIcons.h"
#include <ControlLook.h>
#include <IconUtils.h>
#include <Resources.h>
@ -150,7 +151,8 @@ SharedIcons::_CreateIconForResourceChecked(int32 resourceID, uint32 size,
status = B_ERROR;
}
BBitmap* bitmap = new BBitmap(BRect(0, 0, size - 1, size - 1), 0, B_RGBA32);
BSize iconSize = BControlLook::ComposeIconSize(size);
BBitmap* bitmap = new BBitmap(BRect(BPoint(0, 0), iconSize), 0, B_RGBA32);
status = bitmap->InitCheck();
if (status == B_OK)
@ -187,7 +189,8 @@ SharedIcons::_CreateIconForMimeTypeChecked(const char* mimeTypeStr, uint32 size,
BBitmap* bitmap = NULL;
if (status == B_OK) {
bitmap = new BBitmap(BRect(0, 0, size - 1, size - 1), 0, B_RGBA32);
BSize iconSize = BControlLook::ComposeIconSize(size);
bitmap = new BBitmap(BRect(BPoint(0, 0), iconSize), 0, B_RGBA32);
status = bitmap->InitCheck();
}

View File

@ -61,8 +61,8 @@ RatingView::Draw(BRect updateRect)
BSize
RatingView::MinSize()
{
BSize size(16 * 5 + 2 * 4, 16 + 2);
return BLayoutUtils::ComposeSize(ExplicitMinSize(), size);
RatingStarsMetrics metrics(StarBitmap()->Bounds().Size());
return BLayoutUtils::ComposeSize(ExplicitMinSize(), metrics.Size());
}

View File

@ -7,10 +7,47 @@
#include "HaikuDepotConstants.h"
#include "Logger.h"
#include "RatingUtils.h"
#include "SharedIcons.h"
RatingStarsMetrics::RatingStarsMetrics(BSize starSize)
:
fStarSize(starSize)
{
}
const BSize
RatingStarsMetrics::StarSize() const
{
return fStarSize;
}
float
RatingStarsMetrics::SpacingBetweenStars() const
{
return 2.0 * fStarSize.Width() / 16.0;
}
const BPoint
RatingStarsMetrics::LocationOfStarAtIndex(int index) const
{
float indexf = static_cast<float>(index);
return BPoint(indexf * (fStarSize.Width() + SpacingBetweenStars()), 0.0);
}
const BSize
RatingStarsMetrics::Size() const
{
return BSize((fStarSize.Width() * 5) + (SpacingBetweenStars() * 4), fStarSize.Height());
}
/*static*/ void
RatingUtils::Draw(BView* target, BPoint at, float value)
{
@ -34,38 +71,32 @@ RatingUtils::Draw(BView* target, BPoint at, float value)
RatingUtils::Draw(BView* target, BPoint at, float value,
const BBitmap* star)
{
BRect rect = BOUNDS_RATING;
rect.OffsetBy(at);
// a rectangle covering the whole area of the stars
target->FillRect(rect, B_SOLID_LOW);
if (star == NULL) {
debugger("no star icon found in application resources.");
HDFATAL("no star icon found in application resources.");
return;
}
RatingStarsMetrics metrics(star->Bounds().Size());
BRect rect(at, metrics.Size());
target->FillRect(rect, B_SOLID_LOW);
// a rectangle covering the whole area of the stars
target->SetDrawingMode(B_OP_OVER);
float x = 0;
for (int i = 0; i < 5; i++) {
target->DrawBitmap(star, at + BPoint(x, 0));
x += SIZE_RATING_STAR + WIDTH_RATING_STAR_SPACING;
}
for (int i = 0; i < 5; i++)
target->DrawBitmap(star, rect.LeftTop() + metrics.LocationOfStarAtIndex(i));
if (value >= RATING_MIN && value < 5.0f) {
target->SetDrawingMode(B_OP_OVER);
rect = BOUNDS_RATING;
rect.right = x - 2;
rect.left = ceilf(rect.left + (value / 5.0f) * rect.Width());
rect.OffsetBy(at);
BRect shadeOverRect = rect;
shadeOverRect.left = ceilf(rect.right - (1.0 - (value / 5.0f)) * rect.Width());
rgb_color color = target->LowColor();
color.alpha = 190;
target->SetHighColor(color);
target->SetDrawingMode(B_OP_ALPHA);
target->FillRect(rect, B_SOLID_HIGH);
target->FillRect(shadeOverRect, B_SOLID_HIGH);
}
}

View File

@ -13,7 +13,23 @@ class BView;
class BBitmap;
class RatingUtils {
class RatingStarsMetrics
{
public:
RatingStarsMetrics(BSize starSize);
const BSize StarSize() const;
float SpacingBetweenStars() const;
const BPoint LocationOfStarAtIndex(int index) const;
const BSize Size() const;
private:
BSize fStarSize;
};
class RatingUtils
{
public:
static void Draw(BView* target, BPoint at, float value,
const BBitmap* star);