xref: /haiku/src/apps/haikudepot/ui/FeaturedPackagesView.cpp (revision 0b69420bc8fbb47f594b5eb9aa4e5e87476f0ee9)
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>.
4d75b4d61SAndrew Lindesay  * Copyright 2020-2021, 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>
15f545fe6aSStephan Aßmus #include <Font.h>
16f545fe6aSStephan Aßmus #include <LayoutBuilder.h>
179883929bSAndrew Lindesay #include <LayoutItem.h>
18f545fe6aSStephan Aßmus #include <Message.h>
19f545fe6aSStephan Aßmus #include <ScrollView.h>
20f545fe6aSStephan Aßmus #include <StringView.h>
21f545fe6aSStephan Aßmus #include <SpaceLayoutItem.h>
22f545fe6aSStephan Aßmus 
23f545fe6aSStephan Aßmus #include "BitmapView.h"
24a9edb9bfSAndrew Lindesay #include "HaikuDepotConstants.h"
25f96d1f4dSAndrew Lindesay #include "Logger.h"
261f3c1ef1SStephan Aßmus #include "MainWindow.h"
276f6ad915SStephan Aßmus #include "MarkupTextView.h"
28f545fe6aSStephan Aßmus #include "MessagePackageListener.h"
299883929bSAndrew Lindesay #include "RatingUtils.h"
30f545fe6aSStephan Aßmus #include "RatingView.h"
31f545fe6aSStephan Aßmus #include "ScrollableGroupView.h"
329883929bSAndrew Lindesay #include "SharedBitmap.h"
33f545fe6aSStephan Aßmus 
34f545fe6aSStephan Aßmus 
35f545fe6aSStephan Aßmus #undef B_TRANSLATION_CONTEXT
36f545fe6aSStephan Aßmus #define B_TRANSLATION_CONTEXT "FeaturedPackagesView"
37f545fe6aSStephan Aßmus 
38f545fe6aSStephan Aßmus 
399883929bSAndrew Lindesay #define HEIGHT_PACKAGE 84.0f
409883929bSAndrew Lindesay #define SIZE_ICON 64.0f
419883929bSAndrew Lindesay #define X_POSITION_RATING 350.0f
429883929bSAndrew Lindesay #define X_POSITION_SUMMARY 500.0f
439883929bSAndrew Lindesay #define WIDTH_RATING 100.0f
449883929bSAndrew Lindesay #define Y_PROPORTION_TITLE 0.4f
459883929bSAndrew Lindesay #define Y_PROPORTION_PUBLISHER 0.7f
469883929bSAndrew Lindesay #define PADDING 8.0f
479883929bSAndrew Lindesay 
489883929bSAndrew Lindesay 
49a9edb9bfSAndrew Lindesay static BitmapRef sInstalledIcon(new(std::nothrow)
50a9edb9bfSAndrew Lindesay 	SharedBitmap(RSRC_INSTALLED), true);
51056d423cSStephan Aßmus 
52f545fe6aSStephan Aßmus 
53f545fe6aSStephan Aßmus // #pragma mark - PackageView
54f545fe6aSStephan Aßmus 
55f545fe6aSStephan Aßmus 
569883929bSAndrew Lindesay class StackedFeaturedPackagesView : public BView {
57f545fe6aSStephan Aßmus public:
58f0e491d3SAndrew Lindesay 	StackedFeaturedPackagesView(Model& model)
59f545fe6aSStephan Aßmus 		:
609883929bSAndrew Lindesay 		BView("stacked featured packages view", B_WILL_DRAW | B_FRAME_EVENTS),
61f0e491d3SAndrew Lindesay 		fModel(model),
62f0e491d3SAndrew Lindesay 		fSelectedIndex(-1),
633d869af5SStephan Aßmus 		fPackageListener(
64*0b69420bSAndrew Lindesay 			new(std::nothrow) OnePackageMessagePackageListener(this)),
65*0b69420bSAndrew Lindesay 		fLowestIndexAddedOrRemoved(-1)
66f545fe6aSStephan Aßmus 	{
671f3c1ef1SStephan Aßmus 		SetEventMask(B_POINTER_EVENTS);
68f545fe6aSStephan Aßmus 		Clear();
69f545fe6aSStephan Aßmus 	}
70f545fe6aSStephan Aßmus 
719883929bSAndrew Lindesay 
729883929bSAndrew Lindesay 	virtual ~StackedFeaturedPackagesView()
73f545fe6aSStephan Aßmus 	{
74f545fe6aSStephan Aßmus 		fPackageListener->SetPackage(PackageInfoRef(NULL));
751f3909adSAndrew Lindesay 		fPackageListener->ReleaseReference();
76f545fe6aSStephan Aßmus 	}
77f545fe6aSStephan Aßmus 
789883929bSAndrew Lindesay // #pragma mark - message handling and events
79fa19dd44Slooncraz 
80f545fe6aSStephan Aßmus 	virtual void MessageReceived(BMessage* message)
81f545fe6aSStephan Aßmus 	{
82f545fe6aSStephan Aßmus 		switch (message->what) {
83f545fe6aSStephan Aßmus 			case MSG_UPDATE_PACKAGE:
84d45104b1SJulian Harnath 			{
859883929bSAndrew Lindesay 				BString name;
86fa5c8097SAndrew Lindesay 				if (message->FindString("name", &name) != B_OK)
87fa5c8097SAndrew Lindesay 					HDINFO("expected 'name' key on package update message");
889883929bSAndrew Lindesay 				else
899883929bSAndrew Lindesay 					_HandleUpdatePackage(name);
90d45104b1SJulian Harnath 				break;
91d45104b1SJulian Harnath 			}
92fa19dd44Slooncraz 
93fa19dd44Slooncraz 			case B_COLORS_UPDATED:
94fa19dd44Slooncraz 			{
959883929bSAndrew Lindesay 				Invalidate();
96fa19dd44Slooncraz 				break;
97fa19dd44Slooncraz 			}
981187e806SAndrew Lindesay 
991187e806SAndrew Lindesay 			default:
1001187e806SAndrew Lindesay 				BView::MessageReceived(message);
1011187e806SAndrew Lindesay 				break;
102f545fe6aSStephan Aßmus 		}
103f545fe6aSStephan Aßmus 	}
104f545fe6aSStephan Aßmus 
1059883929bSAndrew Lindesay 
1061f3c1ef1SStephan Aßmus 	virtual void MouseDown(BPoint where)
1071f3c1ef1SStephan Aßmus 	{
1089883929bSAndrew Lindesay 		if (Window()->IsActive() && !IsHidden()) {
109dfbf4d38SStephan Aßmus 			BRect bounds = Bounds();
110dfbf4d38SStephan Aßmus 			BRect parentBounds = Parent()->Bounds();
111dfbf4d38SStephan Aßmus 			ConvertFromParent(&parentBounds);
112dfbf4d38SStephan Aßmus 			bounds = bounds & parentBounds;
1139883929bSAndrew Lindesay 			if (bounds.Contains(where)) {
1149883929bSAndrew Lindesay 				_MessageSelectIndex(_IndexOfY(where.y));
1159883929bSAndrew Lindesay 				MakeFocus();
1169883929bSAndrew Lindesay 			}
1179883929bSAndrew Lindesay 		}
1189883929bSAndrew Lindesay 	}
119dfbf4d38SStephan Aßmus 
1209883929bSAndrew Lindesay 
1219883929bSAndrew Lindesay 	virtual void KeyDown(const char* bytes, int32 numBytes)
1229883929bSAndrew Lindesay 	{
1239883929bSAndrew Lindesay 		char key = bytes[0];
1249883929bSAndrew Lindesay 
1259883929bSAndrew Lindesay 		switch (key) {
1269883929bSAndrew Lindesay 			case B_RIGHT_ARROW:
1279883929bSAndrew Lindesay 			case B_DOWN_ARROW:
128d75b4d61SAndrew Lindesay 			{
129d75b4d61SAndrew Lindesay 				int32 lastIndex = static_cast<int32>(fPackages.size()) - 1;
1309883929bSAndrew Lindesay 				if (!IsEmpty() && fSelectedIndex != -1
131d75b4d61SAndrew Lindesay 						&& fSelectedIndex < lastIndex) {
1329883929bSAndrew Lindesay 					_MessageSelectIndex(fSelectedIndex + 1);
1339883929bSAndrew Lindesay 				}
1349883929bSAndrew Lindesay 				break;
135d75b4d61SAndrew Lindesay 			}
1369883929bSAndrew Lindesay 			case B_LEFT_ARROW:
1379883929bSAndrew Lindesay 			case B_UP_ARROW:
1389883929bSAndrew Lindesay 				if (fSelectedIndex > 0)
1399883929bSAndrew Lindesay 					_MessageSelectIndex( fSelectedIndex - 1);
1409883929bSAndrew Lindesay 				break;
1419883929bSAndrew Lindesay 			case B_PAGE_UP:
1429883929bSAndrew Lindesay 			{
1439883929bSAndrew Lindesay 				BRect bounds = Bounds();
1449883929bSAndrew Lindesay 				ScrollTo(0, fmaxf(0, bounds.top - bounds.Height()));
1459883929bSAndrew Lindesay 				break;
1469883929bSAndrew Lindesay 			}
1479883929bSAndrew Lindesay 			case B_PAGE_DOWN:
1489883929bSAndrew Lindesay 			{
1499883929bSAndrew Lindesay 				BRect bounds = Bounds();
1509883929bSAndrew Lindesay 				float height = fPackages.size() * HEIGHT_PACKAGE;
1519883929bSAndrew Lindesay 				float maxScrollY = height - bounds.Height();
1529883929bSAndrew Lindesay 				float pageDownScrollY = bounds.top + bounds.Height();
1539883929bSAndrew Lindesay 				ScrollTo(0, fminf(maxScrollY, pageDownScrollY));
1549883929bSAndrew Lindesay 				break;
1559883929bSAndrew Lindesay 			}
1569883929bSAndrew Lindesay 			default:
1579883929bSAndrew Lindesay 				BView::KeyDown(bytes, numBytes);
1589883929bSAndrew Lindesay 				break;
1599883929bSAndrew Lindesay 		}
1609883929bSAndrew Lindesay 	}
1619883929bSAndrew Lindesay 
1629883929bSAndrew Lindesay 
1639883929bSAndrew Lindesay 	/*!	This method will send a message to the Window so that it can signal
1649883929bSAndrew Lindesay 		back to this and other views that a package has been selected.  This
1659883929bSAndrew Lindesay 		method won't actually change the state of this view directly.
1669883929bSAndrew Lindesay 	*/
1679883929bSAndrew Lindesay 
1689883929bSAndrew Lindesay 	void _MessageSelectIndex(int32 index) const
1699883929bSAndrew Lindesay 	{
1709883929bSAndrew Lindesay 		if (index != -1) {
1711f3c1ef1SStephan Aßmus 			BMessage message(MSG_PACKAGE_SELECTED);
172d75b4d61SAndrew Lindesay 			BString packageName = fPackages[index]->Name();
173d75b4d61SAndrew Lindesay 			message.AddString("name", packageName);
1741f3c1ef1SStephan Aßmus 			Window()->PostMessage(&message);
1751f3c1ef1SStephan Aßmus 		}
1761f3c1ef1SStephan Aßmus 	}
1771f3c1ef1SStephan Aßmus 
1789883929bSAndrew Lindesay 
1799883929bSAndrew Lindesay 	virtual void FrameResized(float width, float height)
180f545fe6aSStephan Aßmus 	{
1819883929bSAndrew Lindesay 		BView::FrameResized(width, height);
182f545fe6aSStephan Aßmus 
1839883929bSAndrew Lindesay 		// because the summary text will wrap, a resize of the frame will
1849883929bSAndrew Lindesay 		// result in all of the summary area needing to be redrawn.
185056d423cSStephan Aßmus 
1869883929bSAndrew Lindesay 		BRect rectToInvalidate = Bounds();
1879883929bSAndrew Lindesay 		rectToInvalidate.left = X_POSITION_SUMMARY;
1889883929bSAndrew Lindesay 		Invalidate(rectToInvalidate);
189f545fe6aSStephan Aßmus 	}
190f545fe6aSStephan Aßmus 
1919883929bSAndrew Lindesay 
1929883929bSAndrew Lindesay // #pragma mark - update / add / remove / clear data
1939883929bSAndrew Lindesay 
1949883929bSAndrew Lindesay 
195d45104b1SJulian Harnath 	void UpdatePackage(uint32 changeMask, const PackageInfoRef& package)
196d45104b1SJulian Harnath 	{
1979883929bSAndrew Lindesay 		// TODO; could optimize the invalidation?
1989883929bSAndrew Lindesay 		int32 index = _IndexOfPackage(package);
1999883929bSAndrew Lindesay 		if (index >= 0) {
2009883929bSAndrew Lindesay 			fPackages[index] = package;
2019883929bSAndrew Lindesay 			Invalidate(_RectOfIndex(index));
202d45104b1SJulian Harnath 		}
2039883929bSAndrew Lindesay 	}
2049883929bSAndrew Lindesay 
205d45104b1SJulian Harnath 
206f545fe6aSStephan Aßmus 	void Clear()
207f545fe6aSStephan Aßmus 	{
208c4199192SAndrew Lindesay 		for (std::vector<PackageInfoRef>::iterator it = fPackages.begin();
209c4199192SAndrew Lindesay 				it != fPackages.end(); it++) {
210c4199192SAndrew Lindesay 			(*it)->RemoveListener(fPackageListener);
211c4199192SAndrew Lindesay 		}
2129883929bSAndrew Lindesay 		fPackages.clear();
2139883929bSAndrew Lindesay 		fSelectedIndex = -1;
2149883929bSAndrew Lindesay 		Invalidate();
215f545fe6aSStephan Aßmus 	}
216f545fe6aSStephan Aßmus 
2179883929bSAndrew Lindesay 
2189883929bSAndrew Lindesay 	bool IsEmpty() const
2194b930ccaSStephan Aßmus 	{
2209883929bSAndrew Lindesay 		return fPackages.size() == 0;
2214b930ccaSStephan Aßmus 	}
2224b930ccaSStephan Aßmus 
2239883929bSAndrew Lindesay 
2249883929bSAndrew Lindesay 	void _HandleUpdatePackage(const BString& name)
22572992391SStephan Aßmus 	{
2269883929bSAndrew Lindesay 		int32 index = _IndexOfName(name);
2279883929bSAndrew Lindesay 		if (index != -1)
2289883929bSAndrew Lindesay 			Invalidate(_RectOfIndex(index));
22972992391SStephan Aßmus 	}
23072992391SStephan Aßmus 
2319883929bSAndrew Lindesay 
2324af3fbf9SAndrew Lindesay 	static int _CmpProminences(int64 a, int64 b)
2334af3fbf9SAndrew Lindesay 	{
2344af3fbf9SAndrew Lindesay 		if (a <= 0)
2354af3fbf9SAndrew Lindesay 			a = PROMINANCE_ORDERING_MAX;
2364af3fbf9SAndrew Lindesay 		if (b <= 0)
2374af3fbf9SAndrew Lindesay 			b = PROMINANCE_ORDERING_MAX;
2384af3fbf9SAndrew Lindesay 		if (a == b)
2394af3fbf9SAndrew Lindesay 			return 0;
2404af3fbf9SAndrew Lindesay 		if (a > b)
2414af3fbf9SAndrew Lindesay 			return 1;
2424af3fbf9SAndrew Lindesay 		return -1;
2434af3fbf9SAndrew Lindesay 	}
2444af3fbf9SAndrew Lindesay 
2454af3fbf9SAndrew Lindesay 
2469883929bSAndrew Lindesay 	/*! This method will return true if the packageA is ordered before
2479883929bSAndrew Lindesay 		packageB.
2489883929bSAndrew Lindesay 	*/
2499883929bSAndrew Lindesay 
2509883929bSAndrew Lindesay 	static bool _IsPackageBefore(const PackageInfoRef& packageA,
2519883929bSAndrew Lindesay 		const PackageInfoRef& packageB)
252664372abSStephan Aßmus 	{
253779ab335SX512 		if (!packageA.IsSet() || !packageB.IsSet())
254a5e4976dSAndrew Lindesay 			HDFATAL("unexpected NULL reference in a referencable");
2554af3fbf9SAndrew Lindesay 		int c = _CmpProminences(packageA->Prominence(), packageB->Prominence());
2564af3fbf9SAndrew Lindesay 		if (c == 0)
2574af3fbf9SAndrew Lindesay 			c = packageA->Title().ICompare(packageB->Title());
2589883929bSAndrew Lindesay 		if (c == 0)
2599883929bSAndrew Lindesay 			c = packageA->Name().Compare(packageB->Name());
2609883929bSAndrew Lindesay 		return c < 0;
261fa19dd44Slooncraz 	}
262fa19dd44Slooncraz 
2634af3fbf9SAndrew Lindesay 
264*0b69420bSAndrew Lindesay 	void BeginAddRemove()
265*0b69420bSAndrew Lindesay 	{
266*0b69420bSAndrew Lindesay 		fLowestIndexAddedOrRemoved = INT32_MAX;
267*0b69420bSAndrew Lindesay 	}
268*0b69420bSAndrew Lindesay 
269*0b69420bSAndrew Lindesay 
270*0b69420bSAndrew Lindesay 	void EndAddRemove()
271*0b69420bSAndrew Lindesay 	{
272*0b69420bSAndrew Lindesay 		if (fLowestIndexAddedOrRemoved < INT32_MAX) {
273*0b69420bSAndrew Lindesay 			if (fPackages.empty())
274*0b69420bSAndrew Lindesay 				Invalidate();
275*0b69420bSAndrew Lindesay 			else {
276*0b69420bSAndrew Lindesay 				BRect invalidRect = Bounds();
277*0b69420bSAndrew Lindesay 				invalidRect.top = _YOfIndex(fLowestIndexAddedOrRemoved);
278*0b69420bSAndrew Lindesay 				Invalidate(invalidRect);
279*0b69420bSAndrew Lindesay 			}
280*0b69420bSAndrew Lindesay 		}
281*0b69420bSAndrew Lindesay 	}
282*0b69420bSAndrew Lindesay 
283*0b69420bSAndrew Lindesay 
2849883929bSAndrew Lindesay 	void AddPackage(const PackageInfoRef& package)
285fa19dd44Slooncraz 	{
2869883929bSAndrew Lindesay 		// fPackages is sorted and for this reason it is possible to find the
2879883929bSAndrew Lindesay 		// insertion point by identifying the first item in fPackages that does
2889883929bSAndrew Lindesay 		// not return true from the method '_IsPackageBefore'.
289fa19dd44Slooncraz 
2904d2de4eaSAugustin Cavalier 		std::vector<PackageInfoRef>::iterator itInsertionPt
2919883929bSAndrew Lindesay 			= std::lower_bound(fPackages.begin(), fPackages.end(), package,
2929883929bSAndrew Lindesay 				&_IsPackageBefore);
2939883929bSAndrew Lindesay 
2949883929bSAndrew Lindesay 		if (itInsertionPt == fPackages.end()
2959883929bSAndrew Lindesay 				|| package->Name() != (*itInsertionPt)->Name()) {
2969883929bSAndrew Lindesay 			int32 insertionIndex =
2979883929bSAndrew Lindesay 				std::distance<std::vector<PackageInfoRef>::const_iterator>(
2989883929bSAndrew Lindesay 					fPackages.begin(), itInsertionPt);
2999883929bSAndrew Lindesay 			if (fSelectedIndex >= insertionIndex)
3009883929bSAndrew Lindesay 				fSelectedIndex++;
3019883929bSAndrew Lindesay 			fPackages.insert(itInsertionPt, package);
302c4199192SAndrew Lindesay 			package->AddListener(fPackageListener);
303*0b69420bSAndrew Lindesay 			if (insertionIndex < fLowestIndexAddedOrRemoved)
304*0b69420bSAndrew Lindesay 				fLowestIndexAddedOrRemoved = insertionIndex;
3059883929bSAndrew Lindesay 		}
306fa19dd44Slooncraz 	}
307664372abSStephan Aßmus 
308664372abSStephan Aßmus 
3099883929bSAndrew Lindesay 	void RemovePackage(const PackageInfoRef& package)
310d45104b1SJulian Harnath 	{
3119883929bSAndrew Lindesay 		int32 index = _IndexOfPackage(package);
3129883929bSAndrew Lindesay 		if (index >= 0) {
3139883929bSAndrew Lindesay 			if (fSelectedIndex == index)
3149883929bSAndrew Lindesay 				fSelectedIndex = -1;
3159883929bSAndrew Lindesay 			if (fSelectedIndex > index)
3169883929bSAndrew Lindesay 				fSelectedIndex--;
317c4199192SAndrew Lindesay 			fPackages[index]->RemoveListener(fPackageListener);
3189883929bSAndrew Lindesay 			fPackages.erase(fPackages.begin() + index);
319*0b69420bSAndrew Lindesay 			if (index < fLowestIndexAddedOrRemoved)
320*0b69420bSAndrew Lindesay 				fLowestIndexAddedOrRemoved = index;
3219883929bSAndrew Lindesay 		}
3229883929bSAndrew Lindesay 	}
323d45104b1SJulian Harnath 
324d45104b1SJulian Harnath 
3259883929bSAndrew Lindesay // #pragma mark - selection and index handling
326d45104b1SJulian Harnath 
327d45104b1SJulian Harnath 
3289883929bSAndrew Lindesay 	void SelectPackage(const PackageInfoRef& package)
3299883929bSAndrew Lindesay 	{
3309883929bSAndrew Lindesay 		_SelectIndex(_IndexOfPackage(package));
3319883929bSAndrew Lindesay 	}
3329883929bSAndrew Lindesay 
3339883929bSAndrew Lindesay 
3349883929bSAndrew Lindesay 	void _SelectIndex(int32 index)
3359883929bSAndrew Lindesay 	{
3369883929bSAndrew Lindesay 		if (index != fSelectedIndex) {
3379883929bSAndrew Lindesay 			int32 previousSelectedIndex = fSelectedIndex;
3389883929bSAndrew Lindesay 			fSelectedIndex = index;
3399883929bSAndrew Lindesay 			if (fSelectedIndex >= 0)
3409883929bSAndrew Lindesay 				Invalidate(_RectOfIndex(fSelectedIndex));
3419883929bSAndrew Lindesay 			if (previousSelectedIndex >= 0)
3429883929bSAndrew Lindesay 				Invalidate(_RectOfIndex(previousSelectedIndex));
3439883929bSAndrew Lindesay 			_EnsureIndexVisible(index);
3449883929bSAndrew Lindesay 		}
3459883929bSAndrew Lindesay 	}
3469883929bSAndrew Lindesay 
3479883929bSAndrew Lindesay 
3489883929bSAndrew Lindesay 	int32 _IndexOfPackage(PackageInfoRef package) const
3499883929bSAndrew Lindesay 	{
350c4199192SAndrew Lindesay 		std::vector<PackageInfoRef>::const_iterator it
351c4199192SAndrew Lindesay 			= std::lower_bound(fPackages.begin(), fPackages.end(), package,
352c4199192SAndrew Lindesay 				&_IsPackageBefore);
353c4199192SAndrew Lindesay 
354c4199192SAndrew Lindesay 		return (it == fPackages.end() || (*it)->Name() != package->Name())
355c4199192SAndrew Lindesay 			? -1 : it - fPackages.begin();
3569883929bSAndrew Lindesay 	}
3579883929bSAndrew Lindesay 
3589883929bSAndrew Lindesay 
3599883929bSAndrew Lindesay 	int32 _IndexOfName(const BString& name) const
3609883929bSAndrew Lindesay 	{
3619883929bSAndrew Lindesay 		// TODO; slow linear search.
3629883929bSAndrew Lindesay 		// the fPackages is not sorted on name and for this reason it is not
3639883929bSAndrew Lindesay 		// possible to do a binary search.
3649883929bSAndrew Lindesay 		for (uint32 i = 0; i < fPackages.size(); i++) {
3659883929bSAndrew Lindesay 			if (fPackages[i]->Name() == name)
3669883929bSAndrew Lindesay 				return i;
3679883929bSAndrew Lindesay 		}
3689883929bSAndrew Lindesay 		return -1;
3699883929bSAndrew Lindesay 	}
3709883929bSAndrew Lindesay 
3719883929bSAndrew Lindesay 
3729883929bSAndrew Lindesay // #pragma mark - drawing and rendering
3739883929bSAndrew Lindesay 
3749883929bSAndrew Lindesay 
3759883929bSAndrew Lindesay 	virtual void Draw(BRect updateRect)
3769883929bSAndrew Lindesay 	{
3779883929bSAndrew Lindesay 		SetHighUIColor(B_LIST_BACKGROUND_COLOR);
3789883929bSAndrew Lindesay 		FillRect(updateRect);
3799883929bSAndrew Lindesay 
3809883929bSAndrew Lindesay 		int32 iStart = _IndexRoundedOfY(updateRect.top);
3819883929bSAndrew Lindesay 
3829883929bSAndrew Lindesay 		if (iStart != -1) {
3839883929bSAndrew Lindesay 			int32 iEnd = _IndexRoundedOfY(updateRect.bottom);
3849883929bSAndrew Lindesay 			for (int32 i = iStart; i <= iEnd; i++)
3859883929bSAndrew Lindesay 				_DrawPackageAtIndex(updateRect, i);
3869883929bSAndrew Lindesay 		}
3879883929bSAndrew Lindesay 	}
3889883929bSAndrew Lindesay 
3899883929bSAndrew Lindesay 
3909883929bSAndrew Lindesay 	void _DrawPackageAtIndex(BRect updateRect, int32 index)
3919883929bSAndrew Lindesay 	{
3929883929bSAndrew Lindesay 		_DrawPackage(updateRect, fPackages[index], index, _YOfIndex(index),
3939883929bSAndrew Lindesay 			index == fSelectedIndex);
3949883929bSAndrew Lindesay 	}
3959883929bSAndrew Lindesay 
3969883929bSAndrew Lindesay 
3979883929bSAndrew Lindesay 	void _DrawPackage(BRect updateRect, PackageInfoRef pkg, int index, float y,
3989883929bSAndrew Lindesay 		bool selected)
3999883929bSAndrew Lindesay 	{
4009883929bSAndrew Lindesay 		if (selected) {
4019883929bSAndrew Lindesay 			SetLowUIColor(B_LIST_SELECTED_BACKGROUND_COLOR);
4029883929bSAndrew Lindesay 			FillRect(_RectOfY(y), B_SOLID_LOW);
403d45104b1SJulian Harnath 		} else {
4049883929bSAndrew Lindesay 			SetLowUIColor(B_LIST_BACKGROUND_COLOR);
405d45104b1SJulian Harnath 		}
4069883929bSAndrew Lindesay 		// TODO; optimization; the updateRect may only cover some of this?
4079883929bSAndrew Lindesay 		_DrawPackageIcon(updateRect, pkg, y, selected);
4089883929bSAndrew Lindesay 		_DrawPackageTitle(updateRect, pkg, y, selected);
4099883929bSAndrew Lindesay 		_DrawPackagePublisher(updateRect, pkg, y, selected);
4109883929bSAndrew Lindesay 		_DrawPackageRating(updateRect, pkg, y, selected);
4119883929bSAndrew Lindesay 		_DrawPackageSummary(updateRect, pkg, y, selected);
412d45104b1SJulian Harnath 	}
413d45104b1SJulian Harnath 
414d45104b1SJulian Harnath 
4159883929bSAndrew Lindesay 	void _DrawPackageIcon(BRect updateRect, PackageInfoRef pkg, float y,
4169883929bSAndrew Lindesay 		bool selected)
417d45104b1SJulian Harnath 	{
418f0e491d3SAndrew Lindesay 		BitmapRef icon;
419f0e491d3SAndrew Lindesay 		status_t iconResult = fModel.GetPackageIconRepository().GetIcon(
420f0e491d3SAndrew Lindesay 			pkg->Name(), BITMAP_SIZE_64, icon);
4219883929bSAndrew Lindesay 
422f0e491d3SAndrew Lindesay 		if (iconResult == B_OK) {
423779ab335SX512 			if (icon.IsSet()) {
4249883929bSAndrew Lindesay 				float inset = (HEIGHT_PACKAGE - SIZE_ICON) / 2.0;
4259883929bSAndrew Lindesay 				BRect targetRect = BRect(inset, y + inset, SIZE_ICON + inset,
4269883929bSAndrew Lindesay 					y + SIZE_ICON + inset);
427f0e491d3SAndrew Lindesay 				const BBitmap* bitmap = icon->Bitmap(BITMAP_SIZE_64);
4289883929bSAndrew Lindesay 				SetDrawingMode(B_OP_ALPHA);
4299883929bSAndrew Lindesay 				DrawBitmap(bitmap, bitmap->Bounds(), targetRect,
4309883929bSAndrew Lindesay 					B_FILTER_BITMAP_BILINEAR);
431d45104b1SJulian Harnath 			}
4329883929bSAndrew Lindesay 		}
433f0e491d3SAndrew Lindesay 	}
4349883929bSAndrew Lindesay 
4359883929bSAndrew Lindesay 
4369883929bSAndrew Lindesay 	void _DrawPackageTitle(BRect updateRect, PackageInfoRef pkg, float y,
4379883929bSAndrew Lindesay 		bool selected)
4389883929bSAndrew Lindesay 	{
4399883929bSAndrew Lindesay 		static BFont* sFont = NULL;
4409883929bSAndrew Lindesay 
4419883929bSAndrew Lindesay 		if (sFont == NULL) {
4429883929bSAndrew Lindesay 			sFont = new BFont(be_plain_font);
4439883929bSAndrew Lindesay 			GetFont(sFont);
4449883929bSAndrew Lindesay   			font_family family;
4459883929bSAndrew Lindesay 			font_style style;
4469883929bSAndrew Lindesay 			sFont->SetSize(ceilf(sFont->Size() * 1.8f));
4479883929bSAndrew Lindesay 			sFont->GetFamilyAndStyle(&family, &style);
4489883929bSAndrew Lindesay 			sFont->SetFamilyAndStyle(family, "Bold");
4499883929bSAndrew Lindesay 		}
4509883929bSAndrew Lindesay 
4519883929bSAndrew Lindesay 		SetDrawingMode(B_OP_COPY);
4529883929bSAndrew Lindesay 		SetHighUIColor(selected ? B_LIST_SELECTED_ITEM_TEXT_COLOR
4539883929bSAndrew Lindesay 			: B_LIST_ITEM_TEXT_COLOR);
4549883929bSAndrew Lindesay 		SetFont(sFont);
4559883929bSAndrew Lindesay 		BPoint pt(HEIGHT_PACKAGE, y + (HEIGHT_PACKAGE * Y_PROPORTION_TITLE));
4569883929bSAndrew Lindesay 		DrawString(pkg->Title(), pt);
4579883929bSAndrew Lindesay 
4589883929bSAndrew Lindesay 		if (pkg->State() == ACTIVATED) {
4599883929bSAndrew Lindesay 			const BBitmap* bitmap = sInstalledIcon->Bitmap(
460f0e491d3SAndrew Lindesay 				BITMAP_SIZE_16);
4619883929bSAndrew Lindesay 			float stringWidth = StringWidth(pkg->Title());
4629883929bSAndrew Lindesay 			float offsetX = pt.x + stringWidth + PADDING;
4639883929bSAndrew Lindesay 			BRect targetRect(offsetX, pt.y - 16, offsetX + 16, pt.y);
4649883929bSAndrew Lindesay 			SetDrawingMode(B_OP_ALPHA);
4659883929bSAndrew Lindesay 			DrawBitmap(bitmap, bitmap->Bounds(), targetRect,
4669883929bSAndrew Lindesay 				B_FILTER_BITMAP_BILINEAR);
4679883929bSAndrew Lindesay 		}
4689883929bSAndrew Lindesay 	}
4699883929bSAndrew Lindesay 
4709883929bSAndrew Lindesay 
4719883929bSAndrew Lindesay 	void _DrawPackagePublisher(BRect updateRect, PackageInfoRef pkg, float y,
4729883929bSAndrew Lindesay 		bool selected)
4739883929bSAndrew Lindesay 	{
4749883929bSAndrew Lindesay 		static BFont* sFont = NULL;
4759883929bSAndrew Lindesay 
4769883929bSAndrew Lindesay 		if (sFont == NULL) {
4779883929bSAndrew Lindesay 			sFont = new BFont(be_plain_font);
4789883929bSAndrew Lindesay 			font_family family;
4799883929bSAndrew Lindesay 			font_style style;
4809883929bSAndrew Lindesay 			sFont->SetSize(std::max(9.0f, floorf(sFont->Size() * 0.92f)));
4819883929bSAndrew Lindesay 			sFont->GetFamilyAndStyle(&family, &style);
4829883929bSAndrew Lindesay 			sFont->SetFamilyAndStyle(family, "Italic");
4839883929bSAndrew Lindesay 		}
4849883929bSAndrew Lindesay 
4859883929bSAndrew Lindesay 		SetDrawingMode(B_OP_COPY);
4869883929bSAndrew Lindesay 		SetHighUIColor(selected ? B_LIST_SELECTED_ITEM_TEXT_COLOR
4879883929bSAndrew Lindesay 			: B_LIST_ITEM_TEXT_COLOR);
4889883929bSAndrew Lindesay 		SetFont(sFont);
4899883929bSAndrew Lindesay 
4909883929bSAndrew Lindesay 		float maxTextWidth = (X_POSITION_RATING - HEIGHT_PACKAGE) - PADDING;
4919883929bSAndrew Lindesay 		BString publisherName(pkg->Publisher().Name());
4929883929bSAndrew Lindesay 		TruncateString(&publisherName, B_TRUNCATE_END, maxTextWidth);
4939883929bSAndrew Lindesay 
4949883929bSAndrew Lindesay 		DrawString(publisherName, BPoint(HEIGHT_PACKAGE,
4959883929bSAndrew Lindesay 			y + (HEIGHT_PACKAGE * Y_PROPORTION_PUBLISHER)));
4969883929bSAndrew Lindesay 	}
4979883929bSAndrew Lindesay 
4989883929bSAndrew Lindesay 
4999883929bSAndrew Lindesay 	// TODO; show the sample size
5009883929bSAndrew Lindesay 	void _DrawPackageRating(BRect updateRect, PackageInfoRef pkg, float y,
5019883929bSAndrew Lindesay 		bool selected)
5029883929bSAndrew Lindesay 	{
5039883929bSAndrew Lindesay 		BPoint at(X_POSITION_RATING,
5049883929bSAndrew Lindesay 			y + (HEIGHT_PACKAGE - SIZE_RATING_STAR) / 2.0f);
5059883929bSAndrew Lindesay 		RatingUtils::Draw(this, at,
5069883929bSAndrew Lindesay 			pkg->CalculateRatingSummary().averageRating);
5079883929bSAndrew Lindesay 	}
5089883929bSAndrew Lindesay 
5099883929bSAndrew Lindesay 
5109883929bSAndrew Lindesay 	// TODO; handle multi-line rendering of the text
5119883929bSAndrew Lindesay 	void _DrawPackageSummary(BRect updateRect, PackageInfoRef pkg, float y,
5129883929bSAndrew Lindesay 		bool selected)
5139883929bSAndrew Lindesay 	{
5149883929bSAndrew Lindesay 		BRect bounds = Bounds();
5159883929bSAndrew Lindesay 
5169883929bSAndrew Lindesay 		SetDrawingMode(B_OP_COPY);
5179883929bSAndrew Lindesay 		SetHighUIColor(selected ? B_LIST_SELECTED_ITEM_TEXT_COLOR
5189883929bSAndrew Lindesay 			: B_LIST_ITEM_TEXT_COLOR);
5199883929bSAndrew Lindesay 		SetFont(be_plain_font);
5209883929bSAndrew Lindesay 
5219883929bSAndrew Lindesay 		float maxTextWidth = bounds.Width() - X_POSITION_SUMMARY - PADDING;
5229883929bSAndrew Lindesay 		BString summary(pkg->ShortDescription());
5239883929bSAndrew Lindesay 		TruncateString(&summary, B_TRUNCATE_END, maxTextWidth);
5249883929bSAndrew Lindesay 
5259883929bSAndrew Lindesay 		DrawString(summary, BPoint(X_POSITION_SUMMARY,
5269883929bSAndrew Lindesay 			y + (HEIGHT_PACKAGE * 0.5)));
5279883929bSAndrew Lindesay 	}
5289883929bSAndrew Lindesay 
5299883929bSAndrew Lindesay 
5309883929bSAndrew Lindesay // #pragma mark - geometry and scrolling
5319883929bSAndrew Lindesay 
5329883929bSAndrew Lindesay 
5339883929bSAndrew Lindesay 	/*!	This method will make sure that the package at the given index is
5349883929bSAndrew Lindesay 		visible.  If the whole of the package can be seen already then it will
5359883929bSAndrew Lindesay 		do nothing.  If the package is located above the visible region then it
5369883929bSAndrew Lindesay 		will scroll up to it.  If the package is located below the visible
5379883929bSAndrew Lindesay 		region then it will scroll down to it.
5389883929bSAndrew Lindesay 	*/
5399883929bSAndrew Lindesay 
5409883929bSAndrew Lindesay 	void _EnsureIndexVisible(int32 index)
5419883929bSAndrew Lindesay 	{
5429883929bSAndrew Lindesay 		if (!_IsIndexEntirelyVisible(index)) {
5439883929bSAndrew Lindesay 			BRect bounds = Bounds();
5449883929bSAndrew Lindesay 			int32 indexOfCentreVisible = _IndexOfY(
5459883929bSAndrew Lindesay 				bounds.top + bounds.Height() / 2);
5469883929bSAndrew Lindesay 			if (index < indexOfCentreVisible)
5479883929bSAndrew Lindesay 				ScrollTo(0, _YOfIndex(index));
5489883929bSAndrew Lindesay 			else {
5499883929bSAndrew Lindesay 				float scrollPointY = (_YOfIndex(index) + HEIGHT_PACKAGE)
5509883929bSAndrew Lindesay 					- bounds.Height();
5519883929bSAndrew Lindesay 				ScrollTo(0, scrollPointY);
5529883929bSAndrew Lindesay 			}
5539883929bSAndrew Lindesay 		}
5549883929bSAndrew Lindesay 	}
5559883929bSAndrew Lindesay 
5569883929bSAndrew Lindesay 
5579883929bSAndrew Lindesay 	/*!	This method will return true if the package at the supplied index is
5589883929bSAndrew Lindesay 		entirely visible.
5599883929bSAndrew Lindesay 	*/
5609883929bSAndrew Lindesay 
5619883929bSAndrew Lindesay 	bool _IsIndexEntirelyVisible(int32 index)
5629883929bSAndrew Lindesay 	{
5639883929bSAndrew Lindesay 		BRect bounds = Bounds();
5649883929bSAndrew Lindesay 		return bounds == (bounds | _RectOfIndex(index));
5659883929bSAndrew Lindesay 	}
5669883929bSAndrew Lindesay 
5679883929bSAndrew Lindesay 
5689883929bSAndrew Lindesay 	BRect _RectOfIndex(int32 index) const
5699883929bSAndrew Lindesay 	{
5709883929bSAndrew Lindesay 		if (index < 0)
5719883929bSAndrew Lindesay 			return BRect(0, 0, 0, 0);
5729883929bSAndrew Lindesay 		return _RectOfY(_YOfIndex(index));
5739883929bSAndrew Lindesay 	}
5749883929bSAndrew Lindesay 
5759883929bSAndrew Lindesay 
5769883929bSAndrew Lindesay 	/*!	Provides the top coordinate (offset from the top of view) of the package
5779883929bSAndrew Lindesay 		supplied.  If the package does not exist in the view then the coordinate
5789883929bSAndrew Lindesay 		returned will be B_SIZE_UNSET.
5799883929bSAndrew Lindesay 	*/
5809883929bSAndrew Lindesay 
5819883929bSAndrew Lindesay 	float TopOfPackage(const PackageInfoRef& package)
5829883929bSAndrew Lindesay 	{
583779ab335SX512 		if (package.IsSet()) {
5849883929bSAndrew Lindesay 			int index = _IndexOfPackage(package);
5859883929bSAndrew Lindesay 			if (-1 != index)
5869883929bSAndrew Lindesay 				return _YOfIndex(index);
5879883929bSAndrew Lindesay 		}
5889883929bSAndrew Lindesay 		return B_SIZE_UNSET;
5899883929bSAndrew Lindesay 	}
5909883929bSAndrew Lindesay 
5919883929bSAndrew Lindesay 
5929883929bSAndrew Lindesay 	BRect _RectOfY(float y) const
5939883929bSAndrew Lindesay 	{
5949883929bSAndrew Lindesay 		return BRect(0, y, Bounds().Width(), y + HEIGHT_PACKAGE);
5959883929bSAndrew Lindesay 	}
5969883929bSAndrew Lindesay 
5979883929bSAndrew Lindesay 
5989883929bSAndrew Lindesay 	float _YOfIndex(int32 i) const
5999883929bSAndrew Lindesay 	{
6009883929bSAndrew Lindesay 		return i * HEIGHT_PACKAGE;
6019883929bSAndrew Lindesay 	}
6029883929bSAndrew Lindesay 
6039883929bSAndrew Lindesay 
6049883929bSAndrew Lindesay 	/*! Finds the offset into the list of packages for the y-coord in the view's
6059883929bSAndrew Lindesay 		coordinate space.  If the y is above or below the list of packages then
6069883929bSAndrew Lindesay 		this will return -1 to signal this.
6079883929bSAndrew Lindesay 	*/
6089883929bSAndrew Lindesay 
6099883929bSAndrew Lindesay 	int32 _IndexOfY(float y) const
6109883929bSAndrew Lindesay 	{
6119883929bSAndrew Lindesay 		if (fPackages.empty())
6129883929bSAndrew Lindesay 			return -1;
613d75b4d61SAndrew Lindesay 		int32 i = static_cast<int32>(y / HEIGHT_PACKAGE);
614d75b4d61SAndrew Lindesay 		if (i < 0 || i >= static_cast<int32>(fPackages.size()))
6159883929bSAndrew Lindesay 			return -1;
6169883929bSAndrew Lindesay 		return i;
6179883929bSAndrew Lindesay 	}
6189883929bSAndrew Lindesay 
6199883929bSAndrew Lindesay 
6209883929bSAndrew Lindesay 	/*! Find the offset into the list of packages for the y-coord in the view's
6219883929bSAndrew Lindesay 		coordinate space.  If the y is above or below the list of packages then
6229883929bSAndrew Lindesay 		this will return the first or last package index respectively.  If there
6239883929bSAndrew Lindesay 		are no packages then this will return -1;
6249883929bSAndrew Lindesay 	*/
6259883929bSAndrew Lindesay 
6269883929bSAndrew Lindesay 	int32 _IndexRoundedOfY(float y) const
6279883929bSAndrew Lindesay 	{
6289883929bSAndrew Lindesay 		if (fPackages.empty())
6299883929bSAndrew Lindesay 			return -1;
630d75b4d61SAndrew Lindesay 		int32 i = static_cast<int32>(y / HEIGHT_PACKAGE);
6319883929bSAndrew Lindesay 		if (i < 0)
6329883929bSAndrew Lindesay 			return 0;
6339883929bSAndrew Lindesay 		return std::min(i, (int32) (fPackages.size() - 1));
6349883929bSAndrew Lindesay 	}
6359883929bSAndrew Lindesay 
6369883929bSAndrew Lindesay 
6379883929bSAndrew Lindesay 	virtual BSize PreferredSize()
6389883929bSAndrew Lindesay 	{
6399883929bSAndrew Lindesay 		return BSize(B_SIZE_UNLIMITED, HEIGHT_PACKAGE * fPackages.size());
6409883929bSAndrew Lindesay 	}
6419883929bSAndrew Lindesay 
642d45104b1SJulian Harnath 
643f545fe6aSStephan Aßmus private:
644f0e491d3SAndrew Lindesay 			Model&				fModel;
6459883929bSAndrew Lindesay 			std::vector<PackageInfoRef>
6469883929bSAndrew Lindesay 								fPackages;
6479883929bSAndrew Lindesay 			int32				fSelectedIndex;
6489883929bSAndrew Lindesay 			OnePackageMessagePackageListener*
6499883929bSAndrew Lindesay 								fPackageListener;
650*0b69420bSAndrew Lindesay 			int32				fLowestIndexAddedOrRemoved;
651f545fe6aSStephan Aßmus };
652f545fe6aSStephan Aßmus 
653f545fe6aSStephan Aßmus 
654f545fe6aSStephan Aßmus // #pragma mark - FeaturedPackagesView
655f545fe6aSStephan Aßmus 
656f545fe6aSStephan Aßmus 
657f0e491d3SAndrew Lindesay FeaturedPackagesView::FeaturedPackagesView(Model& model)
658f545fe6aSStephan Aßmus 	:
659f0e491d3SAndrew Lindesay 	BView(B_TRANSLATE("Featured packages"), 0),
660f0e491d3SAndrew Lindesay 	fModel(model)
661f545fe6aSStephan Aßmus {
662f0e491d3SAndrew Lindesay 	fPackagesView = new StackedFeaturedPackagesView(fModel);
663f545fe6aSStephan Aßmus 
6649883929bSAndrew Lindesay 	fScrollView = new BScrollView("featured packages scroll view",
665494bd147SAugustin Cavalier 		fPackagesView, 0, false, true, B_FANCY_BORDER);
6668507d262SStephan Aßmus 
667f545fe6aSStephan Aßmus 	BLayoutBuilder::Group<>(this)
6689883929bSAndrew Lindesay 		.Add(fScrollView, 1.0f);
669f545fe6aSStephan Aßmus }
670f545fe6aSStephan Aßmus 
671f545fe6aSStephan Aßmus 
672f545fe6aSStephan Aßmus FeaturedPackagesView::~FeaturedPackagesView()
673f545fe6aSStephan Aßmus {
674f545fe6aSStephan Aßmus }
675f545fe6aSStephan Aßmus 
676f545fe6aSStephan Aßmus 
677*0b69420bSAndrew Lindesay void
678*0b69420bSAndrew Lindesay FeaturedPackagesView::BeginAddRemove()
679*0b69420bSAndrew Lindesay {
680*0b69420bSAndrew Lindesay 	fPackagesView->BeginAddRemove();
681*0b69420bSAndrew Lindesay }
682*0b69420bSAndrew Lindesay 
683*0b69420bSAndrew Lindesay 
684*0b69420bSAndrew Lindesay void
685*0b69420bSAndrew Lindesay FeaturedPackagesView::EndAddRemove()
686*0b69420bSAndrew Lindesay {
687*0b69420bSAndrew Lindesay 	fPackagesView->EndAddRemove();
688*0b69420bSAndrew Lindesay 	_AdjustViews();
689*0b69420bSAndrew Lindesay }
690*0b69420bSAndrew Lindesay 
691*0b69420bSAndrew Lindesay 
692ccf707d0SAndrew Lindesay /*! This method will add the package into the list to be displayed.  The
693ccf707d0SAndrew Lindesay     insertion will occur in alphabetical order.
694ccf707d0SAndrew Lindesay */
695ccf707d0SAndrew Lindesay 
696f545fe6aSStephan Aßmus void
697f545fe6aSStephan Aßmus FeaturedPackagesView::AddPackage(const PackageInfoRef& package)
698f545fe6aSStephan Aßmus {
6999883929bSAndrew Lindesay 	fPackagesView->AddPackage(package);
700ccf707d0SAndrew Lindesay }
701f545fe6aSStephan Aßmus 
702f545fe6aSStephan Aßmus 
703f545fe6aSStephan Aßmus void
70418b941b4SStephan Aßmus FeaturedPackagesView::RemovePackage(const PackageInfoRef& package)
70518b941b4SStephan Aßmus {
7069883929bSAndrew Lindesay 	fPackagesView->RemovePackage(package);
70718b941b4SStephan Aßmus }
70818b941b4SStephan Aßmus 
70918b941b4SStephan Aßmus 
71018b941b4SStephan Aßmus void
711f545fe6aSStephan Aßmus FeaturedPackagesView::Clear()
712f545fe6aSStephan Aßmus {
713fa5c8097SAndrew Lindesay 	HDINFO("did clear the featured packages view");
7149883929bSAndrew Lindesay 	fPackagesView->Clear();
7159883929bSAndrew Lindesay 	_AdjustViews();
716f545fe6aSStephan Aßmus }
717f545fe6aSStephan Aßmus 
718664372abSStephan Aßmus 
719664372abSStephan Aßmus void
72072fff6d3SJulian Harnath FeaturedPackagesView::SelectPackage(const PackageInfoRef& package,
72172fff6d3SJulian Harnath 	bool scrollToEntry)
722664372abSStephan Aßmus {
7239883929bSAndrew Lindesay 	fPackagesView->SelectPackage(package);
724ede65a8fSStephan Aßmus 
7259883929bSAndrew Lindesay 	if (scrollToEntry) {
7269883929bSAndrew Lindesay 		float offset = fPackagesView->TopOfPackage(package);
7279883929bSAndrew Lindesay 		if (offset != B_SIZE_UNSET)
7289883929bSAndrew Lindesay 			fPackagesView->ScrollTo(0, offset);
72972fff6d3SJulian Harnath 	}
730664372abSStephan Aßmus }
7319883929bSAndrew Lindesay 
7329883929bSAndrew Lindesay 
7339883929bSAndrew Lindesay void
7349883929bSAndrew Lindesay FeaturedPackagesView::DoLayout()
7359883929bSAndrew Lindesay {
7369883929bSAndrew Lindesay 	BView::DoLayout();
7379883929bSAndrew Lindesay 	_AdjustViews();
7389883929bSAndrew Lindesay }
7399883929bSAndrew Lindesay 
7409883929bSAndrew Lindesay 
7419883929bSAndrew Lindesay void
7429883929bSAndrew Lindesay FeaturedPackagesView::_AdjustViews()
7439883929bSAndrew Lindesay {
744494bd147SAugustin Cavalier 	fScrollView->FrameResized(fScrollView->Frame().Width(),
745494bd147SAugustin Cavalier 		fScrollView->Frame().Height());
746664372abSStephan Aßmus }
747664372abSStephan Aßmus 
748056d423cSStephan Aßmus 
749056d423cSStephan Aßmus void
750056d423cSStephan Aßmus FeaturedPackagesView::CleanupIcons()
751056d423cSStephan Aßmus {
752056d423cSStephan Aßmus 	sInstalledIcon.Unset();
753056d423cSStephan Aßmus }
754