xref: /haiku/src/apps/haikudepot/ui/FeaturedPackagesView.cpp (revision 6afa94a0896259ded7b5b5fc27180f44196c2eca)
1f545fe6aSStephan Aßmus /*
2f545fe6aSStephan Aßmus  * Copyright 2013-214, Stephan Aßmus <superstippi@gmx.de>.
3d45104b1SJulian Harnath  * Copyright 2017, Julian Harnath <julian.harnath@rwth-aachen.de>.
466ee6532SAndrew Lindesay  * Copyright 2020-2024, Andrew Lindesay <apl@lindesay.co.nz>.
5f545fe6aSStephan Aßmus  * All rights reserved. Distributed under the terms of the MIT License.
6f545fe6aSStephan Aßmus  */
7f545fe6aSStephan Aßmus 
8f545fe6aSStephan Aßmus #include "FeaturedPackagesView.h"
9f545fe6aSStephan Aßmus 
109883929bSAndrew Lindesay #include <algorithm>
119883929bSAndrew Lindesay #include <vector>
12f545fe6aSStephan Aßmus 
139883929bSAndrew Lindesay #include <Bitmap.h>
14f545fe6aSStephan Aßmus #include <Catalog.h>
15c3cad236SAndrew Lindesay #include <ControlLook.h>
16f545fe6aSStephan Aßmus #include <Font.h>
17f545fe6aSStephan Aßmus #include <LayoutBuilder.h>
189883929bSAndrew Lindesay #include <LayoutItem.h>
19f545fe6aSStephan Aßmus #include <Message.h>
20f545fe6aSStephan Aßmus #include <ScrollView.h>
21f545fe6aSStephan Aßmus #include <StringView.h>
22f545fe6aSStephan Aßmus 
23f545fe6aSStephan Aßmus #include "BitmapView.h"
24a9edb9bfSAndrew Lindesay #include "HaikuDepotConstants.h"
250d4fa3e5SAndrew Lindesay #include "LocaleUtils.h"
26f96d1f4dSAndrew Lindesay #include "Logger.h"
271f3c1ef1SStephan Aßmus #include "MainWindow.h"
286f6ad915SStephan Aßmus #include "MarkupTextView.h"
29f545fe6aSStephan Aßmus #include "MessagePackageListener.h"
30c65ff9f1SAndrew Lindesay #include "PackageUtils.h"
319883929bSAndrew Lindesay #include "RatingUtils.h"
32f545fe6aSStephan Aßmus #include "RatingView.h"
3366ee6532SAndrew Lindesay #include "SharedIcons.h"
34f545fe6aSStephan Aßmus 
35f545fe6aSStephan Aßmus 
36f545fe6aSStephan Aßmus #undef B_TRANSLATION_CONTEXT
37f545fe6aSStephan Aßmus #define B_TRANSLATION_CONTEXT "FeaturedPackagesView"
38f545fe6aSStephan Aßmus 
399883929bSAndrew Lindesay #define SIZE_ICON 64.0f
40c3cad236SAndrew Lindesay 
41c3cad236SAndrew Lindesay // If the space for the summary has less than this many "M" characters then the summary will not be
42c3cad236SAndrew Lindesay // displayed.
43c3cad236SAndrew Lindesay #define MINIMUM_M_COUNT_SUMMARY 10.0f
44c3cad236SAndrew Lindesay 
45c3cad236SAndrew Lindesay // The title area will be this many times the width of an "M".
46c3cad236SAndrew Lindesay #define M_COUNT_TITLE 10
479883929bSAndrew Lindesay 
48*6afa94a0SAndrew Lindesay // The fraction of the icon width that is left of the trailing icon
49*6afa94a0SAndrew Lindesay #define TRAILING_ICON_PADDING_LEFT_FACTOR 0.1
50*6afa94a0SAndrew Lindesay 
51*6afa94a0SAndrew Lindesay // The faction of an M-space that is left between the title and the first trailing icon.
52*6afa94a0SAndrew Lindesay #define TITLE_RIGHT_TRAILING_ICON_PADDING_M_FACTOR 0.1
53*6afa94a0SAndrew Lindesay 
549883929bSAndrew Lindesay 
55f545fe6aSStephan Aßmus // #pragma mark - PackageView
56f545fe6aSStephan Aßmus 
57f545fe6aSStephan Aßmus 
58c3cad236SAndrew Lindesay class StackedFeaturesPackageBandMetrics
59c3cad236SAndrew Lindesay {
60c3cad236SAndrew Lindesay public:
StackedFeaturesPackageBandMetrics(float width,BFont * titleFont,BFont * metadataFont)61c3cad236SAndrew Lindesay 	StackedFeaturesPackageBandMetrics(float width, BFont* titleFont, BFont* metadataFont)
62c3cad236SAndrew Lindesay 	{
63c3cad236SAndrew Lindesay 		float padding = be_control_look->DefaultItemSpacing();
64c3cad236SAndrew Lindesay 		BSize iconSize = BControlLook::ComposeIconSize(SIZE_ICON);
65c3cad236SAndrew Lindesay 
66c3cad236SAndrew Lindesay 		font_height titleFontHeight;
67c3cad236SAndrew Lindesay 		font_height metadataFontHeight;
68c3cad236SAndrew Lindesay 		titleFont->GetHeight(&titleFontHeight);
69c3cad236SAndrew Lindesay 		metadataFont->GetHeight(&metadataFontHeight);
70c3cad236SAndrew Lindesay 
71c3cad236SAndrew Lindesay 		float totalTitleAndMetadataHeight = titleFontHeight.ascent + titleFontHeight.descent
72c3cad236SAndrew Lindesay 			+ titleFontHeight.leading
73c3cad236SAndrew Lindesay 			+ metadataFontHeight.leading
74c3cad236SAndrew Lindesay 			+ 2.0 * (metadataFontHeight.ascent + metadataFontHeight.descent);
75c3cad236SAndrew Lindesay 
76c3cad236SAndrew Lindesay 		fHeight = fmaxf(totalTitleAndMetadataHeight, iconSize.Height()) + 2.0 * padding;
77c3cad236SAndrew Lindesay 
78c3cad236SAndrew Lindesay 		{
79c3cad236SAndrew Lindesay 			float iconInset = (fHeight - iconSize.Width()) / 2.0;
80c3cad236SAndrew Lindesay 			fIconRect = BRect(padding, iconInset, iconSize.Width() + padding,
81c3cad236SAndrew Lindesay 				iconSize.Height() + iconInset);
82c3cad236SAndrew Lindesay 		}
83c3cad236SAndrew Lindesay 
84c3cad236SAndrew Lindesay 		{
85c3cad236SAndrew Lindesay 			float titleWidthM = titleFont->StringWidth("M");
86c3cad236SAndrew Lindesay 
87c3cad236SAndrew Lindesay 			float leftTitlePublisherAndChronologicalInfo = fIconRect.right + padding;
88c3cad236SAndrew Lindesay 			float rightTitlePublisherAndChronologicalInfo = fminf(width, fIconRect.Size().Width()
89c3cad236SAndrew Lindesay 				+ (2.0 * padding) + (titleWidthM * M_COUNT_TITLE));
90c3cad236SAndrew Lindesay 
91c3cad236SAndrew Lindesay // left, top, right bottom
92c3cad236SAndrew Lindesay 			fTitleRect = BRect(leftTitlePublisherAndChronologicalInfo,
93c3cad236SAndrew Lindesay 				(fHeight - totalTitleAndMetadataHeight) / 2.0,
94c3cad236SAndrew Lindesay 				rightTitlePublisherAndChronologicalInfo,
95c3cad236SAndrew Lindesay 				((fHeight - totalTitleAndMetadataHeight) / 2.0)
96c3cad236SAndrew Lindesay 					+ titleFontHeight.ascent + titleFontHeight.descent);
97c3cad236SAndrew Lindesay 
98c3cad236SAndrew Lindesay 			fPublisherRect = BRect(leftTitlePublisherAndChronologicalInfo,
99c3cad236SAndrew Lindesay 				fTitleRect.bottom + titleFontHeight.leading,
100c3cad236SAndrew Lindesay 				rightTitlePublisherAndChronologicalInfo,
101c3cad236SAndrew Lindesay 				fTitleRect.bottom + titleFontHeight.leading
102c3cad236SAndrew Lindesay 					+ metadataFontHeight.ascent + metadataFontHeight.descent);
103c3cad236SAndrew Lindesay 
104c3cad236SAndrew Lindesay 			fChronologicalInfoRect = BRect(leftTitlePublisherAndChronologicalInfo,
105c3cad236SAndrew Lindesay 				fPublisherRect.bottom + metadataFontHeight.leading,
106c3cad236SAndrew Lindesay 				rightTitlePublisherAndChronologicalInfo,
107c3cad236SAndrew Lindesay 				fPublisherRect.bottom + metadataFontHeight.leading
108c3cad236SAndrew Lindesay 					+ metadataFontHeight.ascent + metadataFontHeight.descent);
109c3cad236SAndrew Lindesay         }
110c3cad236SAndrew Lindesay 
111c3cad236SAndrew Lindesay         // sort out the ratings display
112c3cad236SAndrew Lindesay 
113c3cad236SAndrew Lindesay 		{
114c3cad236SAndrew Lindesay 			BSize ratingStarSize = SharedIcons::IconStarBlue16Scaled()->Bitmap()->Bounds().Size();
115c3cad236SAndrew Lindesay 			RatingStarsMetrics ratingStarsMetrics(ratingStarSize);
116c3cad236SAndrew Lindesay 
117c3cad236SAndrew Lindesay 			fRatingStarsRect = BRect(BPoint(fTitleRect.right + padding,
118c3cad236SAndrew Lindesay 				(fHeight - ratingStarsMetrics.Size().Height()) / 2), ratingStarsMetrics.Size());
119c3cad236SAndrew Lindesay 
120c3cad236SAndrew Lindesay 			if (fRatingStarsRect.right > width)
121c3cad236SAndrew Lindesay 				fRatingStarsRect = BRect();
122c3cad236SAndrew Lindesay 			else {
123c3cad236SAndrew Lindesay 				// Now sort out the position for the summary. This is reckoned as a container
124c3cad236SAndrew Lindesay 				// rect because it would be nice to layout the text with newlines and not just a
125c3cad236SAndrew Lindesay 				// single line.
126c3cad236SAndrew Lindesay 
127c3cad236SAndrew Lindesay 				fSummaryContainerRect = BRect(fRatingStarsRect.right + (padding * 2.0), padding,
128c3cad236SAndrew Lindesay 					width - padding, fHeight - (padding * 2.0));
129c3cad236SAndrew Lindesay 
130c3cad236SAndrew Lindesay 				float metadataWidthM = metadataFont->StringWidth("M");
131c3cad236SAndrew Lindesay 
132c3cad236SAndrew Lindesay 				if (fSummaryContainerRect.Size().Width() < MINIMUM_M_COUNT_SUMMARY * metadataWidthM)
133c3cad236SAndrew Lindesay 					fSummaryContainerRect = BRect();
134c3cad236SAndrew Lindesay 			}
135c3cad236SAndrew Lindesay 		}
136c3cad236SAndrew Lindesay 	}
137c3cad236SAndrew Lindesay 
Height()138c3cad236SAndrew Lindesay 	float Height()
139c3cad236SAndrew Lindesay 	{
140c3cad236SAndrew Lindesay 		return fHeight;
141c3cad236SAndrew Lindesay 	}
142c3cad236SAndrew Lindesay 
IconRect()143c3cad236SAndrew Lindesay 	BRect IconRect()
144c3cad236SAndrew Lindesay 	{
145c3cad236SAndrew Lindesay 		return fIconRect;
146c3cad236SAndrew Lindesay 	}
147c3cad236SAndrew Lindesay 
TitleRect()148c3cad236SAndrew Lindesay 	BRect TitleRect()
149c3cad236SAndrew Lindesay 	{
150c3cad236SAndrew Lindesay 		return fTitleRect;
151c3cad236SAndrew Lindesay 	}
152c3cad236SAndrew Lindesay 
PublisherRect()153c3cad236SAndrew Lindesay 	BRect PublisherRect()
154c3cad236SAndrew Lindesay 	{
155c3cad236SAndrew Lindesay 		return fPublisherRect;
156c3cad236SAndrew Lindesay 	}
157c3cad236SAndrew Lindesay 
ChronologicalInfoRect()158c3cad236SAndrew Lindesay 	BRect ChronologicalInfoRect()
159c3cad236SAndrew Lindesay 	{
160c3cad236SAndrew Lindesay 		return fChronologicalInfoRect;
161c3cad236SAndrew Lindesay 	}
162c3cad236SAndrew Lindesay 
RatingStarsRect()163c3cad236SAndrew Lindesay 	BRect RatingStarsRect()
164c3cad236SAndrew Lindesay 	{
165c3cad236SAndrew Lindesay 		return fRatingStarsRect;
166c3cad236SAndrew Lindesay 	}
167c3cad236SAndrew Lindesay 
SummaryContainerRect()168c3cad236SAndrew Lindesay 	BRect SummaryContainerRect()
169c3cad236SAndrew Lindesay 	{
170c3cad236SAndrew Lindesay 		return fSummaryContainerRect;
171c3cad236SAndrew Lindesay 	}
172c3cad236SAndrew Lindesay 
173c3cad236SAndrew Lindesay private:
174c3cad236SAndrew Lindesay 			float 				fHeight;
175c3cad236SAndrew Lindesay 
176c3cad236SAndrew Lindesay 			BRect				fIconRect;
177c3cad236SAndrew Lindesay 			BRect				fTitleRect;
178c3cad236SAndrew Lindesay 			BRect				fPublisherRect;
179c3cad236SAndrew Lindesay 			BRect				fChronologicalInfoRect;
180c3cad236SAndrew Lindesay 
181c3cad236SAndrew Lindesay 			BRect				fRatingStarsRect;
182c3cad236SAndrew Lindesay 
183c3cad236SAndrew Lindesay 			BRect				fSummaryContainerRect;
184c3cad236SAndrew Lindesay };
185c3cad236SAndrew Lindesay 
186c3cad236SAndrew Lindesay 
1879883929bSAndrew Lindesay class StackedFeaturedPackagesView : public BView {
188f545fe6aSStephan Aßmus public:
StackedFeaturedPackagesView(Model & model)189f0e491d3SAndrew Lindesay 	StackedFeaturedPackagesView(Model& model)
190f545fe6aSStephan Aßmus 		:
1919883929bSAndrew Lindesay 		BView("stacked featured packages view", B_WILL_DRAW | B_FRAME_EVENTS),
192f0e491d3SAndrew Lindesay 		fModel(model),
193f0e491d3SAndrew Lindesay 		fSelectedIndex(-1),
1943d869af5SStephan Aßmus 		fPackageListener(
1950b69420bSAndrew Lindesay 			new(std::nothrow) OnePackageMessagePackageListener(this)),
1960b69420bSAndrew Lindesay 		fLowestIndexAddedOrRemoved(-1)
197f545fe6aSStephan Aßmus 	{
1981f3c1ef1SStephan Aßmus 		SetEventMask(B_POINTER_EVENTS);
199c3cad236SAndrew Lindesay 
200c3cad236SAndrew Lindesay 		fTitleFont = StackedFeaturedPackagesView::CreateTitleFont();
201c3cad236SAndrew Lindesay 		fMetadataFont = StackedFeaturedPackagesView::CreateMetadataFont();
202c3cad236SAndrew Lindesay 		fSummaryFont = StackedFeaturedPackagesView::CreateSummaryFont();
203c3cad236SAndrew Lindesay 		fBandMetrics = CreateBandMetrics();
204c3cad236SAndrew Lindesay 
205f545fe6aSStephan Aßmus 		Clear();
206f545fe6aSStephan Aßmus 	}
207f545fe6aSStephan Aßmus 
2089883929bSAndrew Lindesay 
~StackedFeaturedPackagesView()2099883929bSAndrew Lindesay 	virtual ~StackedFeaturedPackagesView()
210f545fe6aSStephan Aßmus 	{
211f545fe6aSStephan Aßmus 		fPackageListener->SetPackage(PackageInfoRef(NULL));
2121f3909adSAndrew Lindesay 		fPackageListener->ReleaseReference();
213c3cad236SAndrew Lindesay 		delete fBandMetrics;
214c3cad236SAndrew Lindesay 		delete fTitleFont;
215c3cad236SAndrew Lindesay 		delete fMetadataFont;
216c3cad236SAndrew Lindesay 		delete fSummaryFont;
217f545fe6aSStephan Aßmus 	}
218f545fe6aSStephan Aßmus 
2199883929bSAndrew Lindesay // #pragma mark - message handling and events
220fa19dd44Slooncraz 
MessageReceived(BMessage * message)221f545fe6aSStephan Aßmus 	virtual void MessageReceived(BMessage* message)
222f545fe6aSStephan Aßmus 	{
223f545fe6aSStephan Aßmus 		switch (message->what) {
224f545fe6aSStephan Aßmus 			case MSG_UPDATE_PACKAGE:
225d45104b1SJulian Harnath 			{
2269883929bSAndrew Lindesay 				BString name;
227fa5c8097SAndrew Lindesay 				if (message->FindString("name", &name) != B_OK)
228fa5c8097SAndrew Lindesay 					HDINFO("expected 'name' key on package update message");
2299883929bSAndrew Lindesay 				else
2309883929bSAndrew Lindesay 					_HandleUpdatePackage(name);
231d45104b1SJulian Harnath 				break;
232d45104b1SJulian Harnath 			}
233fa19dd44Slooncraz 
234fa19dd44Slooncraz 			case B_COLORS_UPDATED:
235fa19dd44Slooncraz 			{
2369883929bSAndrew Lindesay 				Invalidate();
237fa19dd44Slooncraz 				break;
238fa19dd44Slooncraz 			}
2391187e806SAndrew Lindesay 
2401187e806SAndrew Lindesay 			default:
2411187e806SAndrew Lindesay 				BView::MessageReceived(message);
2421187e806SAndrew Lindesay 				break;
243f545fe6aSStephan Aßmus 		}
244f545fe6aSStephan Aßmus 	}
245f545fe6aSStephan Aßmus 
2469883929bSAndrew Lindesay 
MouseDown(BPoint where)2471f3c1ef1SStephan Aßmus 	virtual void MouseDown(BPoint where)
2481f3c1ef1SStephan Aßmus 	{
2499883929bSAndrew Lindesay 		if (Window()->IsActive() && !IsHidden()) {
250dfbf4d38SStephan Aßmus 			BRect bounds = Bounds();
251dfbf4d38SStephan Aßmus 			BRect parentBounds = Parent()->Bounds();
252dfbf4d38SStephan Aßmus 			ConvertFromParent(&parentBounds);
253dfbf4d38SStephan Aßmus 			bounds = bounds & parentBounds;
2549883929bSAndrew Lindesay 			if (bounds.Contains(where)) {
2559883929bSAndrew Lindesay 				_MessageSelectIndex(_IndexOfY(where.y));
2569883929bSAndrew Lindesay 				MakeFocus();
2579883929bSAndrew Lindesay 			}
2589883929bSAndrew Lindesay 		}
2599883929bSAndrew Lindesay 	}
260dfbf4d38SStephan Aßmus 
2619883929bSAndrew Lindesay 
KeyDown(const char * bytes,int32 numBytes)2629883929bSAndrew Lindesay 	virtual void KeyDown(const char* bytes, int32 numBytes)
2639883929bSAndrew Lindesay 	{
2649883929bSAndrew Lindesay 		char key = bytes[0];
2659883929bSAndrew Lindesay 
2669883929bSAndrew Lindesay 		switch (key) {
2679883929bSAndrew Lindesay 			case B_RIGHT_ARROW:
2689883929bSAndrew Lindesay 			case B_DOWN_ARROW:
269d75b4d61SAndrew Lindesay 			{
270d75b4d61SAndrew Lindesay 				int32 lastIndex = static_cast<int32>(fPackages.size()) - 1;
2719883929bSAndrew Lindesay 				if (!IsEmpty() && fSelectedIndex != -1
272d75b4d61SAndrew Lindesay 						&& fSelectedIndex < lastIndex) {
2739883929bSAndrew Lindesay 					_MessageSelectIndex(fSelectedIndex + 1);
2749883929bSAndrew Lindesay 				}
2759883929bSAndrew Lindesay 				break;
276d75b4d61SAndrew Lindesay 			}
2779883929bSAndrew Lindesay 			case B_LEFT_ARROW:
2789883929bSAndrew Lindesay 			case B_UP_ARROW:
2799883929bSAndrew Lindesay 				if (fSelectedIndex > 0)
2809883929bSAndrew Lindesay 					_MessageSelectIndex( fSelectedIndex - 1);
2819883929bSAndrew Lindesay 				break;
2829883929bSAndrew Lindesay 			case B_PAGE_UP:
2839883929bSAndrew Lindesay 			{
2849883929bSAndrew Lindesay 				BRect bounds = Bounds();
2859883929bSAndrew Lindesay 				ScrollTo(0, fmaxf(0, bounds.top - bounds.Height()));
2869883929bSAndrew Lindesay 				break;
2879883929bSAndrew Lindesay 			}
2889883929bSAndrew Lindesay 			case B_PAGE_DOWN:
2899883929bSAndrew Lindesay 			{
2909883929bSAndrew Lindesay 				BRect bounds = Bounds();
291c3cad236SAndrew Lindesay 				float height = fPackages.size() * fBandMetrics->Height();
2929883929bSAndrew Lindesay 				float maxScrollY = height - bounds.Height();
2939883929bSAndrew Lindesay 				float pageDownScrollY = bounds.top + bounds.Height();
2949883929bSAndrew Lindesay 				ScrollTo(0, fminf(maxScrollY, pageDownScrollY));
2959883929bSAndrew Lindesay 				break;
2969883929bSAndrew Lindesay 			}
2979883929bSAndrew Lindesay 			default:
2989883929bSAndrew Lindesay 				BView::KeyDown(bytes, numBytes);
2999883929bSAndrew Lindesay 				break;
3009883929bSAndrew Lindesay 		}
3019883929bSAndrew Lindesay 	}
3029883929bSAndrew Lindesay 
3039883929bSAndrew Lindesay 
3049883929bSAndrew Lindesay 	/*!	This method will send a message to the Window so that it can signal
3059883929bSAndrew Lindesay 		back to this and other views that a package has been selected.  This
3069883929bSAndrew Lindesay 		method won't actually change the state of this view directly.
3079883929bSAndrew Lindesay 	*/
3089883929bSAndrew Lindesay 
_MessageSelectIndex(int32 index) const3099883929bSAndrew Lindesay 	void _MessageSelectIndex(int32 index) const
3109883929bSAndrew Lindesay 	{
3119883929bSAndrew Lindesay 		if (index != -1) {
3121f3c1ef1SStephan Aßmus 			BMessage message(MSG_PACKAGE_SELECTED);
313d75b4d61SAndrew Lindesay 			BString packageName = fPackages[index]->Name();
314d75b4d61SAndrew Lindesay 			message.AddString("name", packageName);
3151f3c1ef1SStephan Aßmus 			Window()->PostMessage(&message);
3161f3c1ef1SStephan Aßmus 		}
3171f3c1ef1SStephan Aßmus 	}
3181f3c1ef1SStephan Aßmus 
3199883929bSAndrew Lindesay 
FrameResized(float width,float height)3209883929bSAndrew Lindesay 	virtual void FrameResized(float width, float height)
321f545fe6aSStephan Aßmus 	{
3229883929bSAndrew Lindesay 		BView::FrameResized(width, height);
323f545fe6aSStephan Aßmus 
324c3cad236SAndrew Lindesay 		delete fBandMetrics;
325c3cad236SAndrew Lindesay 		fBandMetrics = CreateBandMetrics();
326056d423cSStephan Aßmus 
327c3cad236SAndrew Lindesay 		Invalidate();
328f545fe6aSStephan Aßmus 	}
329f545fe6aSStephan Aßmus 
3309883929bSAndrew Lindesay 
3319883929bSAndrew Lindesay // #pragma mark - update / add / remove / clear data
3329883929bSAndrew Lindesay 
3339883929bSAndrew Lindesay 
UpdatePackage(uint32 changeMask,const PackageInfoRef & package)334d45104b1SJulian Harnath 	void UpdatePackage(uint32 changeMask, const PackageInfoRef& package)
335d45104b1SJulian Harnath 	{
3369883929bSAndrew Lindesay 		// TODO; could optimize the invalidation?
3379883929bSAndrew Lindesay 		int32 index = _IndexOfPackage(package);
3389883929bSAndrew Lindesay 		if (index >= 0) {
3399883929bSAndrew Lindesay 			fPackages[index] = package;
3409883929bSAndrew Lindesay 			Invalidate(_RectOfIndex(index));
341d45104b1SJulian Harnath 		}
3429883929bSAndrew Lindesay 	}
3439883929bSAndrew Lindesay 
344d45104b1SJulian Harnath 
Clear()345f545fe6aSStephan Aßmus 	void Clear()
346f545fe6aSStephan Aßmus 	{
347c4199192SAndrew Lindesay 		for (std::vector<PackageInfoRef>::iterator it = fPackages.begin();
348c4199192SAndrew Lindesay 				it != fPackages.end(); it++) {
349c4199192SAndrew Lindesay 			(*it)->RemoveListener(fPackageListener);
350c4199192SAndrew Lindesay 		}
3519883929bSAndrew Lindesay 		fPackages.clear();
3529883929bSAndrew Lindesay 		fSelectedIndex = -1;
353c3cad236SAndrew Lindesay 
3549883929bSAndrew Lindesay 		Invalidate();
355f545fe6aSStephan Aßmus 	}
356f545fe6aSStephan Aßmus 
3579883929bSAndrew Lindesay 
CreateTitleFont()358c3cad236SAndrew Lindesay 	static BFont* CreateTitleFont()
359c3cad236SAndrew Lindesay 	{
360c3cad236SAndrew Lindesay 		BFont* font = new BFont(be_plain_font);
361c3cad236SAndrew Lindesay 		font_family family;
362c3cad236SAndrew Lindesay 		font_style style;
363c3cad236SAndrew Lindesay 		font->SetSize(ceilf(font->Size() * 1.8f));
364c3cad236SAndrew Lindesay 		font->GetFamilyAndStyle(&family, &style);
365c3cad236SAndrew Lindesay 		font->SetFamilyAndStyle(family, "Bold");
366c3cad236SAndrew Lindesay 		return font;
367c3cad236SAndrew Lindesay 	}
368c3cad236SAndrew Lindesay 
369c3cad236SAndrew Lindesay 
CreateMetadataFont()370c3cad236SAndrew Lindesay     static BFont* CreateMetadataFont()
371c3cad236SAndrew Lindesay     {
372c3cad236SAndrew Lindesay 		BFont* font = new BFont(be_plain_font);
373c3cad236SAndrew Lindesay 		font_family family;
374c3cad236SAndrew Lindesay 		font_style style;
375c3cad236SAndrew Lindesay 		font->GetFamilyAndStyle(&family, &style);
376c3cad236SAndrew Lindesay 		font->SetFamilyAndStyle(family, "Italic");
377c3cad236SAndrew Lindesay 		return font;
378c3cad236SAndrew Lindesay 	}
379c3cad236SAndrew Lindesay 
380c3cad236SAndrew Lindesay 
CreateSummaryFont()381c3cad236SAndrew Lindesay 	static BFont* CreateSummaryFont()
382c3cad236SAndrew Lindesay 	{
383c3cad236SAndrew Lindesay 		return new BFont(be_plain_font);
384c3cad236SAndrew Lindesay 	}
385c3cad236SAndrew Lindesay 
386c3cad236SAndrew Lindesay 
CreateBandMetrics()387c3cad236SAndrew Lindesay 	StackedFeaturesPackageBandMetrics* CreateBandMetrics()
388c3cad236SAndrew Lindesay 	{
389c3cad236SAndrew Lindesay 		return new StackedFeaturesPackageBandMetrics(Bounds().Width(), fTitleFont, fMetadataFont);
390c3cad236SAndrew Lindesay 	}
391c3cad236SAndrew Lindesay 
392c3cad236SAndrew Lindesay 
IsEmpty() const3939883929bSAndrew Lindesay 	bool IsEmpty() const
3944b930ccaSStephan Aßmus 	{
3959883929bSAndrew Lindesay 		return fPackages.size() == 0;
3964b930ccaSStephan Aßmus 	}
3974b930ccaSStephan Aßmus 
3989883929bSAndrew Lindesay 
_HandleUpdatePackage(const BString & name)3999883929bSAndrew Lindesay 	void _HandleUpdatePackage(const BString& name)
40072992391SStephan Aßmus 	{
4019883929bSAndrew Lindesay 		int32 index = _IndexOfName(name);
4029883929bSAndrew Lindesay 		if (index != -1)
4039883929bSAndrew Lindesay 			Invalidate(_RectOfIndex(index));
40472992391SStephan Aßmus 	}
40572992391SStephan Aßmus 
4069883929bSAndrew Lindesay 
_CmpProminences(int64 a,int64 b)4074af3fbf9SAndrew Lindesay 	static int _CmpProminences(int64 a, int64 b)
4084af3fbf9SAndrew Lindesay 	{
4094af3fbf9SAndrew Lindesay 		if (a <= 0)
4104af3fbf9SAndrew Lindesay 			a = PROMINANCE_ORDERING_MAX;
4114af3fbf9SAndrew Lindesay 		if (b <= 0)
4124af3fbf9SAndrew Lindesay 			b = PROMINANCE_ORDERING_MAX;
4134af3fbf9SAndrew Lindesay 		if (a == b)
4144af3fbf9SAndrew Lindesay 			return 0;
4154af3fbf9SAndrew Lindesay 		if (a > b)
4164af3fbf9SAndrew Lindesay 			return 1;
4174af3fbf9SAndrew Lindesay 		return -1;
4184af3fbf9SAndrew Lindesay 	}
4194af3fbf9SAndrew Lindesay 
4204af3fbf9SAndrew Lindesay 
4219883929bSAndrew Lindesay 	/*! This method will return true if the packageA is ordered before
4229883929bSAndrew Lindesay 		packageB.
4239883929bSAndrew Lindesay 	*/
4249883929bSAndrew Lindesay 
_IsPackageBefore(const PackageInfoRef & packageA,const PackageInfoRef & packageB)4258cc3ed34SAndrew Lindesay 	static bool _IsPackageBefore(const PackageInfoRef& packageA, const PackageInfoRef& packageB)
426664372abSStephan Aßmus 	{
427779ab335SX512 		if (!packageA.IsSet() || !packageB.IsSet())
428a5e4976dSAndrew Lindesay 			HDFATAL("unexpected NULL reference in a referencable");
4298cc3ed34SAndrew Lindesay 
4308cc3ed34SAndrew Lindesay 		uint32 prominenceA = 0;
4318cc3ed34SAndrew Lindesay 		uint32 prominenceB = 0;
4328cc3ed34SAndrew Lindesay 
4338cc3ed34SAndrew Lindesay 		PackageClassificationInfoRef classificationInfoA = packageA->PackageClassificationInfo();
4348cc3ed34SAndrew Lindesay 		PackageClassificationInfoRef classificationInfoB = packageB->PackageClassificationInfo();
4358cc3ed34SAndrew Lindesay 
4368cc3ed34SAndrew Lindesay 		if (classificationInfoA.IsSet())
4378cc3ed34SAndrew Lindesay 			prominenceA = classificationInfoA->Prominence();
4388cc3ed34SAndrew Lindesay 
4398cc3ed34SAndrew Lindesay 		if (classificationInfoB.IsSet())
4408cc3ed34SAndrew Lindesay 			prominenceB = classificationInfoB->Prominence();
4418cc3ed34SAndrew Lindesay 
4428cc3ed34SAndrew Lindesay 		int c = static_cast<int>(prominenceA) - static_cast<int>(prominenceB);
4438cc3ed34SAndrew Lindesay 
444c65ff9f1SAndrew Lindesay 		if (c == 0) {
445c65ff9f1SAndrew Lindesay 			BString titleA;
446c65ff9f1SAndrew Lindesay 			BString titleB;
447c65ff9f1SAndrew Lindesay 			PackageUtils::Title(packageA, titleA);
448c65ff9f1SAndrew Lindesay 			PackageUtils::Title(packageB, titleB);
449c65ff9f1SAndrew Lindesay 			c = titleA.ICompare(titleB);
450c65ff9f1SAndrew Lindesay 		}
4518cc3ed34SAndrew Lindesay 
4529883929bSAndrew Lindesay 		if (c == 0)
4539883929bSAndrew Lindesay 			c = packageA->Name().Compare(packageB->Name());
4548cc3ed34SAndrew Lindesay 
4559883929bSAndrew Lindesay 		return c < 0;
456fa19dd44Slooncraz 	}
457fa19dd44Slooncraz 
4584af3fbf9SAndrew Lindesay 
BeginAddRemove()4590b69420bSAndrew Lindesay 	void BeginAddRemove()
4600b69420bSAndrew Lindesay 	{
4610b69420bSAndrew Lindesay 		fLowestIndexAddedOrRemoved = INT32_MAX;
4620b69420bSAndrew Lindesay 	}
4630b69420bSAndrew Lindesay 
4640b69420bSAndrew Lindesay 
EndAddRemove()4650b69420bSAndrew Lindesay 	void EndAddRemove()
4660b69420bSAndrew Lindesay 	{
4670b69420bSAndrew Lindesay 		if (fLowestIndexAddedOrRemoved < INT32_MAX) {
4680b69420bSAndrew Lindesay 			if (fPackages.empty())
4690b69420bSAndrew Lindesay 				Invalidate();
4700b69420bSAndrew Lindesay 			else {
4710b69420bSAndrew Lindesay 				BRect invalidRect = Bounds();
4720b69420bSAndrew Lindesay 				invalidRect.top = _YOfIndex(fLowestIndexAddedOrRemoved);
4730b69420bSAndrew Lindesay 				Invalidate(invalidRect);
4740b69420bSAndrew Lindesay 			}
4750b69420bSAndrew Lindesay 		}
4760b69420bSAndrew Lindesay 	}
4770b69420bSAndrew Lindesay 
4780b69420bSAndrew Lindesay 
AddPackage(const PackageInfoRef & package)4799883929bSAndrew Lindesay 	void AddPackage(const PackageInfoRef& package)
480fa19dd44Slooncraz 	{
4819883929bSAndrew Lindesay 		// fPackages is sorted and for this reason it is possible to find the
4829883929bSAndrew Lindesay 		// insertion point by identifying the first item in fPackages that does
4839883929bSAndrew Lindesay 		// not return true from the method '_IsPackageBefore'.
484fa19dd44Slooncraz 
4854d2de4eaSAugustin Cavalier 		std::vector<PackageInfoRef>::iterator itInsertionPt
4869883929bSAndrew Lindesay 			= std::lower_bound(fPackages.begin(), fPackages.end(), package,
4879883929bSAndrew Lindesay 				&_IsPackageBefore);
4889883929bSAndrew Lindesay 
4899883929bSAndrew Lindesay 		if (itInsertionPt == fPackages.end()
4909883929bSAndrew Lindesay 				|| package->Name() != (*itInsertionPt)->Name()) {
4919883929bSAndrew Lindesay 			int32 insertionIndex =
4929883929bSAndrew Lindesay 				std::distance<std::vector<PackageInfoRef>::const_iterator>(
4939883929bSAndrew Lindesay 					fPackages.begin(), itInsertionPt);
4949883929bSAndrew Lindesay 			if (fSelectedIndex >= insertionIndex)
4959883929bSAndrew Lindesay 				fSelectedIndex++;
4969883929bSAndrew Lindesay 			fPackages.insert(itInsertionPt, package);
497c4199192SAndrew Lindesay 			package->AddListener(fPackageListener);
4980b69420bSAndrew Lindesay 			if (insertionIndex < fLowestIndexAddedOrRemoved)
4990b69420bSAndrew Lindesay 				fLowestIndexAddedOrRemoved = insertionIndex;
5009883929bSAndrew Lindesay 		}
501fa19dd44Slooncraz 	}
502664372abSStephan Aßmus 
503664372abSStephan Aßmus 
RemovePackage(const PackageInfoRef & package)5049883929bSAndrew Lindesay 	void RemovePackage(const PackageInfoRef& package)
505d45104b1SJulian Harnath 	{
5069883929bSAndrew Lindesay 		int32 index = _IndexOfPackage(package);
5079883929bSAndrew Lindesay 		if (index >= 0) {
5089883929bSAndrew Lindesay 			if (fSelectedIndex == index)
5099883929bSAndrew Lindesay 				fSelectedIndex = -1;
5109883929bSAndrew Lindesay 			if (fSelectedIndex > index)
5119883929bSAndrew Lindesay 				fSelectedIndex--;
512c4199192SAndrew Lindesay 			fPackages[index]->RemoveListener(fPackageListener);
5139883929bSAndrew Lindesay 			fPackages.erase(fPackages.begin() + index);
5140b69420bSAndrew Lindesay 			if (index < fLowestIndexAddedOrRemoved)
5150b69420bSAndrew Lindesay 				fLowestIndexAddedOrRemoved = index;
5169883929bSAndrew Lindesay 		}
5179883929bSAndrew Lindesay 	}
518d45104b1SJulian Harnath 
519d45104b1SJulian Harnath 
5209883929bSAndrew Lindesay // #pragma mark - selection and index handling
521d45104b1SJulian Harnath 
522d45104b1SJulian Harnath 
SelectPackage(const PackageInfoRef & package)5239883929bSAndrew Lindesay 	void SelectPackage(const PackageInfoRef& package)
5249883929bSAndrew Lindesay 	{
5259883929bSAndrew Lindesay 		_SelectIndex(_IndexOfPackage(package));
5269883929bSAndrew Lindesay 	}
5279883929bSAndrew Lindesay 
5289883929bSAndrew Lindesay 
_SelectIndex(int32 index)5299883929bSAndrew Lindesay 	void _SelectIndex(int32 index)
5309883929bSAndrew Lindesay 	{
5319883929bSAndrew Lindesay 		if (index != fSelectedIndex) {
5329883929bSAndrew Lindesay 			int32 previousSelectedIndex = fSelectedIndex;
5339883929bSAndrew Lindesay 			fSelectedIndex = index;
5349883929bSAndrew Lindesay 			if (fSelectedIndex >= 0)
5359883929bSAndrew Lindesay 				Invalidate(_RectOfIndex(fSelectedIndex));
5369883929bSAndrew Lindesay 			if (previousSelectedIndex >= 0)
5379883929bSAndrew Lindesay 				Invalidate(_RectOfIndex(previousSelectedIndex));
5389883929bSAndrew Lindesay 			_EnsureIndexVisible(index);
5399883929bSAndrew Lindesay 		}
5409883929bSAndrew Lindesay 	}
5419883929bSAndrew Lindesay 
5429883929bSAndrew Lindesay 
_IndexOfPackage(PackageInfoRef package) const5439883929bSAndrew Lindesay 	int32 _IndexOfPackage(PackageInfoRef package) const
5449883929bSAndrew Lindesay 	{
545c4199192SAndrew Lindesay 		std::vector<PackageInfoRef>::const_iterator it
546c4199192SAndrew Lindesay 			= std::lower_bound(fPackages.begin(), fPackages.end(), package,
547c4199192SAndrew Lindesay 				&_IsPackageBefore);
548c4199192SAndrew Lindesay 
549c4199192SAndrew Lindesay 		return (it == fPackages.end() || (*it)->Name() != package->Name())
550c4199192SAndrew Lindesay 			? -1 : it - fPackages.begin();
5519883929bSAndrew Lindesay 	}
5529883929bSAndrew Lindesay 
5539883929bSAndrew Lindesay 
_IndexOfName(const BString & name) const5549883929bSAndrew Lindesay 	int32 _IndexOfName(const BString& name) const
5559883929bSAndrew Lindesay 	{
5569883929bSAndrew Lindesay 		// TODO; slow linear search.
5579883929bSAndrew Lindesay 		// the fPackages is not sorted on name and for this reason it is not
5589883929bSAndrew Lindesay 		// possible to do a binary search.
5599883929bSAndrew Lindesay 		for (uint32 i = 0; i < fPackages.size(); i++) {
5609883929bSAndrew Lindesay 			if (fPackages[i]->Name() == name)
5619883929bSAndrew Lindesay 				return i;
5629883929bSAndrew Lindesay 		}
5639883929bSAndrew Lindesay 		return -1;
5649883929bSAndrew Lindesay 	}
5659883929bSAndrew Lindesay 
5669883929bSAndrew Lindesay 
5679883929bSAndrew Lindesay // #pragma mark - drawing and rendering
5689883929bSAndrew Lindesay 
5699883929bSAndrew Lindesay 
Draw(BRect updateRect)5709883929bSAndrew Lindesay 	virtual void Draw(BRect updateRect)
5719883929bSAndrew Lindesay 	{
5729883929bSAndrew Lindesay 		SetHighUIColor(B_LIST_BACKGROUND_COLOR);
5739883929bSAndrew Lindesay 		FillRect(updateRect);
5749883929bSAndrew Lindesay 
5759883929bSAndrew Lindesay 		int32 iStart = _IndexRoundedOfY(updateRect.top);
5769883929bSAndrew Lindesay 
5779883929bSAndrew Lindesay 		if (iStart != -1) {
5789883929bSAndrew Lindesay 			int32 iEnd = _IndexRoundedOfY(updateRect.bottom);
5799883929bSAndrew Lindesay 			for (int32 i = iStart; i <= iEnd; i++)
5809883929bSAndrew Lindesay 				_DrawPackageAtIndex(updateRect, i);
5819883929bSAndrew Lindesay 		}
5829883929bSAndrew Lindesay 	}
5839883929bSAndrew Lindesay 
5849883929bSAndrew Lindesay 
_DrawPackageAtIndex(BRect updateRect,int32 index)5859883929bSAndrew Lindesay 	void _DrawPackageAtIndex(BRect updateRect, int32 index)
5869883929bSAndrew Lindesay 	{
587c3cad236SAndrew Lindesay 		_DrawPackage(updateRect, fPackages[index], _YOfIndex(index), index == fSelectedIndex);
5889883929bSAndrew Lindesay 	}
5899883929bSAndrew Lindesay 
5909883929bSAndrew Lindesay 
_DrawPackage(BRect updateRect,PackageInfoRef pkg,float y,bool selected)591c3cad236SAndrew Lindesay 	void _DrawPackage(BRect updateRect, PackageInfoRef pkg, float y, bool selected)
5929883929bSAndrew Lindesay 	{
5939883929bSAndrew Lindesay 		if (selected) {
5949883929bSAndrew Lindesay 			SetLowUIColor(B_LIST_SELECTED_BACKGROUND_COLOR);
5959883929bSAndrew Lindesay 			FillRect(_RectOfY(y), B_SOLID_LOW);
596d45104b1SJulian Harnath 		} else {
5979883929bSAndrew Lindesay 			SetLowUIColor(B_LIST_BACKGROUND_COLOR);
598d45104b1SJulian Harnath 		}
599c3cad236SAndrew Lindesay 
600c3cad236SAndrew Lindesay 		BRect iconRect = fBandMetrics->IconRect();
601c3cad236SAndrew Lindesay 		BRect titleRect = fBandMetrics->TitleRect();
602c3cad236SAndrew Lindesay 		BRect publisherRect = fBandMetrics->PublisherRect();
603c3cad236SAndrew Lindesay 		BRect chronologicalInfoRect = fBandMetrics->ChronologicalInfoRect();
604c3cad236SAndrew Lindesay 		BRect ratingStarsRect = fBandMetrics->RatingStarsRect();
605c3cad236SAndrew Lindesay 		BRect summaryContainerRect = fBandMetrics->SummaryContainerRect();
606c3cad236SAndrew Lindesay 
607c3cad236SAndrew Lindesay 		iconRect.OffsetBy(0.0, y);
608c3cad236SAndrew Lindesay 		titleRect.OffsetBy(0.0, y);
609c3cad236SAndrew Lindesay 		publisherRect.OffsetBy(0.0, y);
610c3cad236SAndrew Lindesay 		chronologicalInfoRect.OffsetBy(0.0, y);
611c3cad236SAndrew Lindesay 		ratingStarsRect.OffsetBy(0.0, y);
612c3cad236SAndrew Lindesay 		summaryContainerRect.OffsetBy(0.0, y);
613c3cad236SAndrew Lindesay 
6149883929bSAndrew Lindesay 		// TODO; optimization; the updateRect may only cover some of this?
615c3cad236SAndrew Lindesay 		_DrawPackageIcon(iconRect, pkg, selected);
616c3cad236SAndrew Lindesay 		_DrawPackageTitle(titleRect, pkg, selected);
617c3cad236SAndrew Lindesay 		_DrawPackagePublisher(publisherRect, pkg, selected);
618c3cad236SAndrew Lindesay 		_DrawPackageChronologicalInfo(chronologicalInfoRect, pkg, selected);
619c3cad236SAndrew Lindesay 		_DrawPackageRating(ratingStarsRect, pkg);
620c3cad236SAndrew Lindesay 		_DrawPackageSummary(summaryContainerRect, pkg, selected);
621d45104b1SJulian Harnath 	}
622d45104b1SJulian Harnath 
623d45104b1SJulian Harnath 
_DrawPackageIcon(BRect iconRect,PackageInfoRef pkg,bool selected)624c3cad236SAndrew Lindesay 	void _DrawPackageIcon(BRect iconRect, PackageInfoRef pkg, bool selected)
625d45104b1SJulian Harnath 	{
626c3cad236SAndrew Lindesay 		if (!iconRect.IsValid())
627c3cad236SAndrew Lindesay 			return;
628c3cad236SAndrew Lindesay 
62966ee6532SAndrew Lindesay 		BitmapHolderRef icon;
630c3cad236SAndrew Lindesay 		status_t iconResult = fModel.GetPackageIconRepository().GetIcon(pkg->Name(),
631c3cad236SAndrew Lindesay 			iconRect.Width(), icon);
6329883929bSAndrew Lindesay 
633f0e491d3SAndrew Lindesay 		if (iconResult == B_OK) {
634779ab335SX512 			if (icon.IsSet()) {
63566ee6532SAndrew Lindesay 				const BBitmap* bitmap = icon->Bitmap();
6368d18358cSAndrew Lindesay 
6378d18358cSAndrew Lindesay 				if (bitmap != NULL && bitmap->IsValid()) {
6389883929bSAndrew Lindesay 					SetDrawingMode(B_OP_ALPHA);
639c3cad236SAndrew Lindesay 					DrawBitmap(bitmap, bitmap->Bounds(), iconRect, B_FILTER_BITMAP_BILINEAR);
640d45104b1SJulian Harnath 				}
6419883929bSAndrew Lindesay 			}
642f0e491d3SAndrew Lindesay 		}
6438d18358cSAndrew Lindesay 	}
6449883929bSAndrew Lindesay 
6459883929bSAndrew Lindesay 
_DrawPackageTitle(BRect textRect,PackageInfoRef pkg,bool selected)646c3cad236SAndrew Lindesay 	void _DrawPackageTitle(BRect textRect, PackageInfoRef pkg, bool selected)
6479883929bSAndrew Lindesay 	{
648c3cad236SAndrew Lindesay 		if (!textRect.IsValid())
649c3cad236SAndrew Lindesay 			return;
6509883929bSAndrew Lindesay 
651*6afa94a0SAndrew Lindesay 		std::vector<BitmapHolderRef> trailingIconBitmaps;
652*6afa94a0SAndrew Lindesay 
653*6afa94a0SAndrew Lindesay 		if (PackageUtils::State(pkg) == ACTIVATED)
654*6afa94a0SAndrew Lindesay 			trailingIconBitmaps.push_back(SharedIcons::IconInstalled16Scaled());
655*6afa94a0SAndrew Lindesay 
656*6afa94a0SAndrew Lindesay 		if (PackageUtils::IsNativeDesktop(pkg))
657*6afa94a0SAndrew Lindesay 			trailingIconBitmaps.push_back(SharedIcons::IconNative16Scaled());
658*6afa94a0SAndrew Lindesay 
659*6afa94a0SAndrew Lindesay 		float trailingIconsWidth = 0.0f;
660*6afa94a0SAndrew Lindesay 
661*6afa94a0SAndrew Lindesay 		for (std::vector<BitmapHolderRef>::iterator it = trailingIconBitmaps.begin();
662*6afa94a0SAndrew Lindesay 				it != trailingIconBitmaps.end(); it++) {
663*6afa94a0SAndrew Lindesay 			trailingIconsWidth += (*it)->Bitmap()->Bounds().Width()
664*6afa94a0SAndrew Lindesay 				* (1.0 + TRAILING_ICON_PADDING_LEFT_FACTOR);
665*6afa94a0SAndrew Lindesay 		}
6669883929bSAndrew Lindesay 
6679883929bSAndrew Lindesay 		SetDrawingMode(B_OP_COPY);
668c3cad236SAndrew Lindesay 		SetHighUIColor(selected ? B_LIST_SELECTED_ITEM_TEXT_COLOR : B_LIST_ITEM_TEXT_COLOR);
669c3cad236SAndrew Lindesay 		SetFont(fTitleFont);
670c3cad236SAndrew Lindesay 
671*6afa94a0SAndrew Lindesay 		float titleRightTrailingIconsPadding = 0.0f;
672*6afa94a0SAndrew Lindesay 
673*6afa94a0SAndrew Lindesay 		if (!trailingIconBitmaps.empty()) {
674*6afa94a0SAndrew Lindesay 			titleRightTrailingIconsPadding = StringWidth("M")
675*6afa94a0SAndrew Lindesay 				* TITLE_RIGHT_TRAILING_ICON_PADDING_M_FACTOR;
676*6afa94a0SAndrew Lindesay 		}
677*6afa94a0SAndrew Lindesay 
678c3cad236SAndrew Lindesay 		font_height fontHeight;
679c3cad236SAndrew Lindesay 		fTitleFont->GetHeight(&fontHeight);
680c3cad236SAndrew Lindesay 		BPoint pt = textRect.LeftTop() + BPoint(0.0, + fontHeight.ascent);
681c3cad236SAndrew Lindesay 
682c65ff9f1SAndrew Lindesay 		BString title;
683c65ff9f1SAndrew Lindesay 		PackageUtils::TitleOrName(pkg, title);
684c65ff9f1SAndrew Lindesay 
685c65ff9f1SAndrew Lindesay 		BString renderedText = title;
686*6afa94a0SAndrew Lindesay 		TruncateString(&renderedText, B_TRUNCATE_END, textRect.Width()
687*6afa94a0SAndrew Lindesay 			- (titleRightTrailingIconsPadding + trailingIconsWidth));
688c3cad236SAndrew Lindesay 
689c3cad236SAndrew Lindesay 		DrawString(renderedText, pt);
6909883929bSAndrew Lindesay 
691*6afa94a0SAndrew Lindesay 		// now draw the trailing icons.
692*6afa94a0SAndrew Lindesay 
693c65ff9f1SAndrew Lindesay 		float stringWidth = StringWidth(title);
694*6afa94a0SAndrew Lindesay 		float trailingIconX = textRect.left + stringWidth + titleRightTrailingIconsPadding;
695*6afa94a0SAndrew Lindesay 		float trailingIconMidY = textRect.top + (textRect.Height() / 2.0);
696*6afa94a0SAndrew Lindesay 
6979883929bSAndrew Lindesay 		SetDrawingMode(B_OP_ALPHA);
698*6afa94a0SAndrew Lindesay 
699*6afa94a0SAndrew Lindesay 		for (std::vector<BitmapHolderRef>::iterator it = trailingIconBitmaps.begin();
700*6afa94a0SAndrew Lindesay 				it != trailingIconBitmaps.end(); it++) {
701*6afa94a0SAndrew Lindesay 			const BBitmap* bitmap = (*it)->Bitmap();
702*6afa94a0SAndrew Lindesay 			BRect bitmapBounds = bitmap->Bounds();
703*6afa94a0SAndrew Lindesay 
704*6afa94a0SAndrew Lindesay             float trailingIconTopLeftPtX = ceilf(
705*6afa94a0SAndrew Lindesay             	trailingIconX + (bitmapBounds.Width() * TRAILING_ICON_PADDING_LEFT_FACTOR)) + 0.5;
706*6afa94a0SAndrew Lindesay             float trailingIconTopLeftPtY = ceilf(
707*6afa94a0SAndrew Lindesay             	trailingIconMidY - (bitmapBounds.Height() / 2.0)) + 0.5;
708*6afa94a0SAndrew Lindesay 
709*6afa94a0SAndrew Lindesay 			BRect trailingIconRect(BPoint(trailingIconTopLeftPtX, trailingIconTopLeftPtY),
710*6afa94a0SAndrew Lindesay 				bitmap->Bounds().Size());
711*6afa94a0SAndrew Lindesay 
712*6afa94a0SAndrew Lindesay 			DrawBitmap(bitmap, bitmapBounds, trailingIconRect, B_FILTER_BITMAP_BILINEAR);
713*6afa94a0SAndrew Lindesay 
714*6afa94a0SAndrew Lindesay 			trailingIconX = trailingIconRect.right;
7159883929bSAndrew Lindesay 		}
7169883929bSAndrew Lindesay 	}
7179883929bSAndrew Lindesay 
7189883929bSAndrew Lindesay 
_DrawPackageGenericTextSlug(BRect textRect,const BString & text,bool selected)719c3cad236SAndrew Lindesay 	void _DrawPackageGenericTextSlug(BRect textRect, const BString& text, bool selected)
7209883929bSAndrew Lindesay 	{
721c3cad236SAndrew Lindesay 		if (!textRect.IsValid())
722c3cad236SAndrew Lindesay 			return;
7239883929bSAndrew Lindesay 
7249883929bSAndrew Lindesay 		SetDrawingMode(B_OP_COPY);
725c3cad236SAndrew Lindesay 		SetHighUIColor(selected ? B_LIST_SELECTED_ITEM_TEXT_COLOR : B_LIST_ITEM_TEXT_COLOR);
726c3cad236SAndrew Lindesay 		SetFont(fMetadataFont);
7279883929bSAndrew Lindesay 
728c3cad236SAndrew Lindesay 		font_height fontHeight;
729c3cad236SAndrew Lindesay 		fMetadataFont->GetHeight(&fontHeight);
730c3cad236SAndrew Lindesay 		BPoint pt = textRect.LeftTop() + BPoint(0.0, + fontHeight.ascent);
731c3cad236SAndrew Lindesay 
7320d4fa3e5SAndrew Lindesay 		BString renderedText(text);
733c3cad236SAndrew Lindesay 		TruncateString(&renderedText, B_TRUNCATE_END, textRect.Width());
7349883929bSAndrew Lindesay 
735c3cad236SAndrew Lindesay 		DrawString(renderedText, pt);
7360d4fa3e5SAndrew Lindesay 	}
7370d4fa3e5SAndrew Lindesay 
7380d4fa3e5SAndrew Lindesay 
_DrawPackagePublisher(BRect textRect,PackageInfoRef pkg,bool selected)739c3cad236SAndrew Lindesay 	void _DrawPackagePublisher(BRect textRect, PackageInfoRef pkg, bool selected)
7400d4fa3e5SAndrew Lindesay 	{
741c3cad236SAndrew Lindesay 		_DrawPackageGenericTextSlug(textRect, pkg->Publisher().Name(), selected);
7420d4fa3e5SAndrew Lindesay 	}
7430d4fa3e5SAndrew Lindesay 
7440d4fa3e5SAndrew Lindesay 
_DrawPackageChronologicalInfo(BRect textRect,PackageInfoRef pkg,bool selected)745c3cad236SAndrew Lindesay 	void _DrawPackageChronologicalInfo(BRect textRect, PackageInfoRef pkg, bool selected)
7460d4fa3e5SAndrew Lindesay 	{
7470d4fa3e5SAndrew Lindesay 		BString versionCreateTimestampPresentation
7487dd47034SHumdinger 			= LocaleUtils::TimestampToDateString(pkg->VersionCreateTimestamp());
749c3cad236SAndrew Lindesay 		_DrawPackageGenericTextSlug(textRect, versionCreateTimestampPresentation, selected);
7509883929bSAndrew Lindesay 	}
7519883929bSAndrew Lindesay 
7529883929bSAndrew Lindesay 
7539883929bSAndrew Lindesay 	// TODO; show the sample size
_DrawPackageRating(BRect ratingRect,PackageInfoRef pkg)754c3cad236SAndrew Lindesay 	void _DrawPackageRating(BRect ratingRect, PackageInfoRef pkg)
7559883929bSAndrew Lindesay 	{
756c3cad236SAndrew Lindesay 		if (!ratingRect.IsValid())
757c3cad236SAndrew Lindesay 			return;
7584b3c808eSAndrew Lindesay 
7594b3c808eSAndrew Lindesay 		UserRatingInfoRef userRatingInfo = pkg->UserRatingInfo();
7604b3c808eSAndrew Lindesay 
7614b3c808eSAndrew Lindesay 		if (userRatingInfo.IsSet()) {
7624b3c808eSAndrew Lindesay 			UserRatingSummaryRef userRatingSummary = userRatingInfo->Summary();
7634b3c808eSAndrew Lindesay 
7644b3c808eSAndrew Lindesay 			if (userRatingSummary.IsSet())
7654b3c808eSAndrew Lindesay 				RatingUtils::Draw(this, ratingRect.LeftTop(), userRatingSummary->AverageRating());
7664b3c808eSAndrew Lindesay 		}
7679883929bSAndrew Lindesay 	}
7689883929bSAndrew Lindesay 
7699883929bSAndrew Lindesay 
7709883929bSAndrew Lindesay 	// TODO; handle multi-line rendering of the text
_DrawPackageSummary(BRect textRect,PackageInfoRef pkg,bool selected)771c3cad236SAndrew Lindesay 	void _DrawPackageSummary(BRect textRect, PackageInfoRef pkg, bool selected)
7729883929bSAndrew Lindesay 	{
773c3cad236SAndrew Lindesay 		if (!textRect.IsValid())
774c3cad236SAndrew Lindesay 			return;
7759883929bSAndrew Lindesay 
7769883929bSAndrew Lindesay 		SetDrawingMode(B_OP_COPY);
777c3cad236SAndrew Lindesay 		SetHighUIColor(selected ? B_LIST_SELECTED_ITEM_TEXT_COLOR : B_LIST_ITEM_TEXT_COLOR);
778c3cad236SAndrew Lindesay 		SetFont(fSummaryFont);
7799883929bSAndrew Lindesay 
780c3cad236SAndrew Lindesay 		font_height fontHeight;
781c3cad236SAndrew Lindesay 		fSummaryFont->GetHeight(&fontHeight);
782c3cad236SAndrew Lindesay 
783c3cad236SAndrew Lindesay 		// The text rect is a container into which later text can be made to flow multi-line. For
784c3cad236SAndrew Lindesay 		// now just draw one line of the summary.
785c3cad236SAndrew Lindesay 
786c3cad236SAndrew Lindesay 		BPoint pt = textRect.LeftTop() + BPoint(0.0,
787c3cad236SAndrew Lindesay 			(textRect.Size().Height() / 2.0) - ((fontHeight.ascent + fontHeight.descent) / 2.0)
788c3cad236SAndrew Lindesay 				+ fontHeight.ascent);
789c3cad236SAndrew Lindesay 
790c65ff9f1SAndrew Lindesay 		BString summary;
791c65ff9f1SAndrew Lindesay 		PackageUtils::Summary(pkg, summary);
792c3cad236SAndrew Lindesay 		TruncateString(&summary, B_TRUNCATE_END, textRect.Width());
7939883929bSAndrew Lindesay 
794c3cad236SAndrew Lindesay 		DrawString(summary, pt);
7959883929bSAndrew Lindesay 	}
7969883929bSAndrew Lindesay 
7979883929bSAndrew Lindesay 
7989883929bSAndrew Lindesay // #pragma mark - geometry and scrolling
7999883929bSAndrew Lindesay 
8009883929bSAndrew Lindesay 
8019883929bSAndrew Lindesay 	/*!	This method will make sure that the package at the given index is
8029883929bSAndrew Lindesay 		visible.  If the whole of the package can be seen already then it will
8039883929bSAndrew Lindesay 		do nothing.  If the package is located above the visible region then it
8049883929bSAndrew Lindesay 		will scroll up to it.  If the package is located below the visible
8059883929bSAndrew Lindesay 		region then it will scroll down to it.
8069883929bSAndrew Lindesay 	*/
8079883929bSAndrew Lindesay 
_EnsureIndexVisible(int32 index)8089883929bSAndrew Lindesay 	void _EnsureIndexVisible(int32 index)
8099883929bSAndrew Lindesay 	{
8109883929bSAndrew Lindesay 		if (!_IsIndexEntirelyVisible(index)) {
8119883929bSAndrew Lindesay 			BRect bounds = Bounds();
812c3cad236SAndrew Lindesay 			int32 indexOfCentreVisible = _IndexOfY(bounds.top + bounds.Height() / 2);
8139883929bSAndrew Lindesay 			if (index < indexOfCentreVisible)
8149883929bSAndrew Lindesay 				ScrollTo(0, _YOfIndex(index));
8159883929bSAndrew Lindesay 			else {
816c3cad236SAndrew Lindesay 				float scrollPointY = (_YOfIndex(index) + fBandMetrics->Height()) - bounds.Height();
8179883929bSAndrew Lindesay 				ScrollTo(0, scrollPointY);
8189883929bSAndrew Lindesay 			}
8199883929bSAndrew Lindesay 		}
8209883929bSAndrew Lindesay 	}
8219883929bSAndrew Lindesay 
8229883929bSAndrew Lindesay 
8239883929bSAndrew Lindesay 	/*!	This method will return true if the package at the supplied index is
8249883929bSAndrew Lindesay 		entirely visible.
8259883929bSAndrew Lindesay 	*/
8269883929bSAndrew Lindesay 
_IsIndexEntirelyVisible(int32 index)8279883929bSAndrew Lindesay 	bool _IsIndexEntirelyVisible(int32 index)
8289883929bSAndrew Lindesay 	{
8299883929bSAndrew Lindesay 		BRect bounds = Bounds();
8309883929bSAndrew Lindesay 		return bounds == (bounds | _RectOfIndex(index));
8319883929bSAndrew Lindesay 	}
8329883929bSAndrew Lindesay 
8339883929bSAndrew Lindesay 
_RectOfIndex(int32 index) const8349883929bSAndrew Lindesay 	BRect _RectOfIndex(int32 index) const
8359883929bSAndrew Lindesay 	{
8369883929bSAndrew Lindesay 		if (index < 0)
8379883929bSAndrew Lindesay 			return BRect(0, 0, 0, 0);
8389883929bSAndrew Lindesay 		return _RectOfY(_YOfIndex(index));
8399883929bSAndrew Lindesay 	}
8409883929bSAndrew Lindesay 
8419883929bSAndrew Lindesay 
8429883929bSAndrew Lindesay 	/*!	Provides the top coordinate (offset from the top of view) of the package
8439883929bSAndrew Lindesay 		supplied.  If the package does not exist in the view then the coordinate
8449883929bSAndrew Lindesay 		returned will be B_SIZE_UNSET.
8459883929bSAndrew Lindesay 	*/
8469883929bSAndrew Lindesay 
TopOfPackage(const PackageInfoRef & package)8479883929bSAndrew Lindesay 	float TopOfPackage(const PackageInfoRef& package)
8489883929bSAndrew Lindesay 	{
849779ab335SX512 		if (package.IsSet()) {
8509883929bSAndrew Lindesay 			int index = _IndexOfPackage(package);
8519883929bSAndrew Lindesay 			if (-1 != index)
8529883929bSAndrew Lindesay 				return _YOfIndex(index);
8539883929bSAndrew Lindesay 		}
8549883929bSAndrew Lindesay 		return B_SIZE_UNSET;
8559883929bSAndrew Lindesay 	}
8569883929bSAndrew Lindesay 
8579883929bSAndrew Lindesay 
_RectOfY(float y) const8589883929bSAndrew Lindesay 	BRect _RectOfY(float y) const
8599883929bSAndrew Lindesay 	{
860c3cad236SAndrew Lindesay 		return BRect(0, y, Bounds().Width(), y + fBandMetrics->Height());
8619883929bSAndrew Lindesay 	}
8629883929bSAndrew Lindesay 
8639883929bSAndrew Lindesay 
_YOfIndex(int32 i) const8649883929bSAndrew Lindesay 	float _YOfIndex(int32 i) const
8659883929bSAndrew Lindesay 	{
866c3cad236SAndrew Lindesay 		return i * fBandMetrics->Height();
8679883929bSAndrew Lindesay 	}
8689883929bSAndrew Lindesay 
8699883929bSAndrew Lindesay 
8709883929bSAndrew Lindesay 	/*! Finds the offset into the list of packages for the y-coord in the view's
8719883929bSAndrew Lindesay 		coordinate space.  If the y is above or below the list of packages then
8729883929bSAndrew Lindesay 		this will return -1 to signal this.
8739883929bSAndrew Lindesay 	*/
8749883929bSAndrew Lindesay 
_IndexOfY(float y) const8759883929bSAndrew Lindesay 	int32 _IndexOfY(float y) const
8769883929bSAndrew Lindesay 	{
8779883929bSAndrew Lindesay 		if (fPackages.empty())
8789883929bSAndrew Lindesay 			return -1;
879c3cad236SAndrew Lindesay 		int32 i = static_cast<int32>(y / fBandMetrics->Height());
880d75b4d61SAndrew Lindesay 		if (i < 0 || i >= static_cast<int32>(fPackages.size()))
8819883929bSAndrew Lindesay 			return -1;
8829883929bSAndrew Lindesay 		return i;
8839883929bSAndrew Lindesay 	}
8849883929bSAndrew Lindesay 
8859883929bSAndrew Lindesay 
8869883929bSAndrew Lindesay 	/*! Find the offset into the list of packages for the y-coord in the view's
8879883929bSAndrew Lindesay 		coordinate space.  If the y is above or below the list of packages then
8889883929bSAndrew Lindesay 		this will return the first or last package index respectively.  If there
8899883929bSAndrew Lindesay 		are no packages then this will return -1;
8909883929bSAndrew Lindesay 	*/
8919883929bSAndrew Lindesay 
_IndexRoundedOfY(float y) const8929883929bSAndrew Lindesay 	int32 _IndexRoundedOfY(float y) const
8939883929bSAndrew Lindesay 	{
8949883929bSAndrew Lindesay 		if (fPackages.empty())
8959883929bSAndrew Lindesay 			return -1;
896c3cad236SAndrew Lindesay 		int32 i = static_cast<int32>(y / fBandMetrics->Height());
8979883929bSAndrew Lindesay 		if (i < 0)
8989883929bSAndrew Lindesay 			return 0;
8999883929bSAndrew Lindesay 		return std::min(i, (int32) (fPackages.size() - 1));
9009883929bSAndrew Lindesay 	}
9019883929bSAndrew Lindesay 
9029883929bSAndrew Lindesay 
PreferredSize()9039883929bSAndrew Lindesay 	virtual BSize PreferredSize()
9049883929bSAndrew Lindesay 	{
905c3cad236SAndrew Lindesay 		return BSize(B_SIZE_UNLIMITED,
906c3cad236SAndrew Lindesay 			fBandMetrics->Height() * static_cast<float>(fPackages.size()));
9079883929bSAndrew Lindesay 	}
9089883929bSAndrew Lindesay 
909d45104b1SJulian Harnath 
910f545fe6aSStephan Aßmus private:
911f0e491d3SAndrew Lindesay 			Model&				fModel;
9129883929bSAndrew Lindesay 			std::vector<PackageInfoRef>
9139883929bSAndrew Lindesay 								fPackages;
9149883929bSAndrew Lindesay 			int32				fSelectedIndex;
9159883929bSAndrew Lindesay 			OnePackageMessagePackageListener*
9169883929bSAndrew Lindesay 								fPackageListener;
9170b69420bSAndrew Lindesay 			int32				fLowestIndexAddedOrRemoved;
918c3cad236SAndrew Lindesay 			StackedFeaturesPackageBandMetrics*
919c3cad236SAndrew Lindesay 								fBandMetrics;
920c3cad236SAndrew Lindesay 
921c3cad236SAndrew Lindesay 			BFont*				fTitleFont;
922c3cad236SAndrew Lindesay 			BFont*				fMetadataFont;
923c3cad236SAndrew Lindesay 			BFont*				fSummaryFont;
924f545fe6aSStephan Aßmus };
925f545fe6aSStephan Aßmus 
926f545fe6aSStephan Aßmus 
927f545fe6aSStephan Aßmus // #pragma mark - FeaturedPackagesView
928f545fe6aSStephan Aßmus 
929f545fe6aSStephan Aßmus 
FeaturedPackagesView(Model & model)930f0e491d3SAndrew Lindesay FeaturedPackagesView::FeaturedPackagesView(Model& model)
931f545fe6aSStephan Aßmus 	:
932f0e491d3SAndrew Lindesay 	BView(B_TRANSLATE("Featured packages"), 0),
933f0e491d3SAndrew Lindesay 	fModel(model)
934f545fe6aSStephan Aßmus {
935f0e491d3SAndrew Lindesay 	fPackagesView = new StackedFeaturedPackagesView(fModel);
936f545fe6aSStephan Aßmus 
9379883929bSAndrew Lindesay 	fScrollView = new BScrollView("featured packages scroll view",
938494bd147SAugustin Cavalier 		fPackagesView, 0, false, true, B_FANCY_BORDER);
9398507d262SStephan Aßmus 
940f545fe6aSStephan Aßmus 	BLayoutBuilder::Group<>(this)
9419883929bSAndrew Lindesay 		.Add(fScrollView, 1.0f);
942f545fe6aSStephan Aßmus }
943f545fe6aSStephan Aßmus 
944f545fe6aSStephan Aßmus 
~FeaturedPackagesView()945f545fe6aSStephan Aßmus FeaturedPackagesView::~FeaturedPackagesView()
946f545fe6aSStephan Aßmus {
947f545fe6aSStephan Aßmus }
948f545fe6aSStephan Aßmus 
949f545fe6aSStephan Aßmus 
9500b69420bSAndrew Lindesay void
BeginAddRemove()9510b69420bSAndrew Lindesay FeaturedPackagesView::BeginAddRemove()
9520b69420bSAndrew Lindesay {
9530b69420bSAndrew Lindesay 	fPackagesView->BeginAddRemove();
9540b69420bSAndrew Lindesay }
9550b69420bSAndrew Lindesay 
9560b69420bSAndrew Lindesay 
9570b69420bSAndrew Lindesay void
EndAddRemove()9580b69420bSAndrew Lindesay FeaturedPackagesView::EndAddRemove()
9590b69420bSAndrew Lindesay {
9600b69420bSAndrew Lindesay 	fPackagesView->EndAddRemove();
9610b69420bSAndrew Lindesay 	_AdjustViews();
9620b69420bSAndrew Lindesay }
9630b69420bSAndrew Lindesay 
9640b69420bSAndrew Lindesay 
965ccf707d0SAndrew Lindesay /*! This method will add the package into the list to be displayed.  The
966ccf707d0SAndrew Lindesay     insertion will occur in alphabetical order.
967ccf707d0SAndrew Lindesay */
968ccf707d0SAndrew Lindesay 
969f545fe6aSStephan Aßmus void
AddPackage(const PackageInfoRef & package)970f545fe6aSStephan Aßmus FeaturedPackagesView::AddPackage(const PackageInfoRef& package)
971f545fe6aSStephan Aßmus {
9729883929bSAndrew Lindesay 	fPackagesView->AddPackage(package);
973ccf707d0SAndrew Lindesay }
974f545fe6aSStephan Aßmus 
975f545fe6aSStephan Aßmus 
976f545fe6aSStephan Aßmus void
RemovePackage(const PackageInfoRef & package)97718b941b4SStephan Aßmus FeaturedPackagesView::RemovePackage(const PackageInfoRef& package)
97818b941b4SStephan Aßmus {
9799883929bSAndrew Lindesay 	fPackagesView->RemovePackage(package);
98018b941b4SStephan Aßmus }
98118b941b4SStephan Aßmus 
98218b941b4SStephan Aßmus 
98318b941b4SStephan Aßmus void
Clear()984f545fe6aSStephan Aßmus FeaturedPackagesView::Clear()
985f545fe6aSStephan Aßmus {
986fa5c8097SAndrew Lindesay 	HDINFO("did clear the featured packages view");
9879883929bSAndrew Lindesay 	fPackagesView->Clear();
9889883929bSAndrew Lindesay 	_AdjustViews();
989f545fe6aSStephan Aßmus }
990f545fe6aSStephan Aßmus 
991664372abSStephan Aßmus 
992664372abSStephan Aßmus void
SelectPackage(const PackageInfoRef & package,bool scrollToEntry)99372fff6d3SJulian Harnath FeaturedPackagesView::SelectPackage(const PackageInfoRef& package,
99472fff6d3SJulian Harnath 	bool scrollToEntry)
995664372abSStephan Aßmus {
9969883929bSAndrew Lindesay 	fPackagesView->SelectPackage(package);
997ede65a8fSStephan Aßmus 
9989883929bSAndrew Lindesay 	if (scrollToEntry) {
9999883929bSAndrew Lindesay 		float offset = fPackagesView->TopOfPackage(package);
10009883929bSAndrew Lindesay 		if (offset != B_SIZE_UNSET)
10019883929bSAndrew Lindesay 			fPackagesView->ScrollTo(0, offset);
100272fff6d3SJulian Harnath 	}
1003664372abSStephan Aßmus }
10049883929bSAndrew Lindesay 
10059883929bSAndrew Lindesay 
10069883929bSAndrew Lindesay void
DoLayout()10079883929bSAndrew Lindesay FeaturedPackagesView::DoLayout()
10089883929bSAndrew Lindesay {
10099883929bSAndrew Lindesay 	BView::DoLayout();
10109883929bSAndrew Lindesay 	_AdjustViews();
10119883929bSAndrew Lindesay }
10129883929bSAndrew Lindesay 
10139883929bSAndrew Lindesay 
10149883929bSAndrew Lindesay void
_AdjustViews()10159883929bSAndrew Lindesay FeaturedPackagesView::_AdjustViews()
10169883929bSAndrew Lindesay {
1017494bd147SAugustin Cavalier 	fScrollView->FrameResized(fScrollView->Frame().Width(),
1018494bd147SAugustin Cavalier 		fScrollView->Frame().Height());
1019664372abSStephan Aßmus }
1020