xref: /haiku/src/apps/haikudepot/ui/FeaturedPackagesView.cpp (revision 0de25abadc86e260328c6f7c4255acbee8f70d4e)
1 /*
2  * Copyright 2013-214, Stephan Aßmus <superstippi@gmx.de>.
3  * All rights reserved. Distributed under the terms of the MIT License.
4  */
5 
6 #include "FeaturedPackagesView.h"
7 
8 #include <stdio.h>
9 
10 #include <Catalog.h>
11 #include <Font.h>
12 #include <LayoutBuilder.h>
13 #include <Message.h>
14 #include <ScrollView.h>
15 #include <StringView.h>
16 #include <SpaceLayoutItem.h>
17 
18 #include "BitmapView.h"
19 #include "MainWindow.h"
20 #include "MarkupTextView.h"
21 #include "MessagePackageListener.h"
22 #include "RatingView.h"
23 #include "ScrollableGroupView.h"
24 
25 
26 #undef B_TRANSLATION_CONTEXT
27 #define B_TRANSLATION_CONTEXT "FeaturedPackagesView"
28 
29 
30 static const rgb_color kLightBlack = (rgb_color){ 60, 60, 60, 255 };
31 
32 static BitmapRef sInstalledIcon(new(std::nothrow) SharedBitmap(504), true);
33 
34 
35 // #pragma mark - PackageView
36 
37 
38 class PackageView : public BGroupView {
39 public:
40 	PackageView()
41 		:
42 		BGroupView("package view", B_HORIZONTAL),
43 		fPackageListener(
44 			new(std::nothrow) OnePackageMessagePackageListener(this)),
45 		fSelected(false)
46 	{
47 		SetViewColor(255, 255, 255);
48 		SetEventMask(B_POINTER_EVENTS);
49 
50 		fIconView = new BitmapView("package icon view");
51 		fInstalledIconView = new BitmapView("installed icon view");
52 		fTitleView = new BStringView("package title view", "");
53 		fPublisherView = new BStringView("package publisher view", "");
54 
55 		// Title font
56 		BFont font;
57 		GetFont(&font);
58 		font_family family;
59 		font_style style;
60 		font.SetSize(ceilf(font.Size() * 1.8f));
61 		font.GetFamilyAndStyle(&family, &style);
62 		font.SetFamilyAndStyle(family, "Bold");
63 		fTitleView->SetFont(&font);
64 
65 		// Publisher font
66 		GetFont(&font);
67 		font.SetSize(std::max(9.0f, floorf(font.Size() * 0.92f)));
68 		font.SetFamilyAndStyle(family, "Italic");
69 		fPublisherView->SetFont(&font);
70 		fPublisherView->SetHighColor(kLightBlack);
71 
72 		// Summary text view
73 		fSummaryView = new MarkupTextView("package summary");
74 		fSummaryView->SetSelectionEnabled(false);
75 
76 		// Rating view
77 		fRatingView = new RatingView("package rating view");
78 
79 		fAvgRating = new BStringView("package average rating", "");
80 		fAvgRating->SetFont(&font);
81 		fAvgRating->SetHighColor(kLightBlack);
82 
83 		fVoteInfo = new BStringView("package vote info", "");
84 		// small font
85 		GetFont(&font);
86 		font.SetSize(std::max(9.0f, floorf(font.Size() * 0.85f)));
87 		fVoteInfo->SetFont(&font);
88 		fVoteInfo->SetHighColor(kLightBlack);
89 
90 		BLayoutBuilder::Group<>(this)
91 			.Add(fIconView)
92 			.AddGroup(B_VERTICAL, 1.0f, 2.2f)
93 				.AddGroup(B_HORIZONTAL)
94 					.Add(fTitleView)
95 					.Add(fInstalledIconView)
96 					.AddGlue()
97 				.End()
98 				.Add(fPublisherView)
99 				.SetExplicitMaxSize(BSize(B_SIZE_UNLIMITED, B_SIZE_UNSET))
100 			.End()
101 			.AddGlue(0.1f)
102 			.AddGroup(B_HORIZONTAL, 0.8f)
103 				.Add(fRatingView)
104 				.Add(fAvgRating)
105 				.Add(fVoteInfo)
106 			.End()
107 			.AddGlue(0.2f)
108 			.Add(fSummaryView, 2.0f)
109 
110 			.SetInsets(B_USE_WINDOW_INSETS)
111 		;
112 
113 		Clear();
114 	}
115 
116 	virtual ~PackageView()
117 	{
118 		fPackageListener->SetPackage(PackageInfoRef(NULL));
119 		delete fPackageListener;
120 	}
121 
122 	virtual void MessageReceived(BMessage* message)
123 	{
124 		switch (message->what) {
125 			case B_MOUSE_WHEEL_CHANGED:
126 				Window()->PostMessage(message, Parent());
127 				break;
128 
129 			case MSG_UPDATE_PACKAGE:
130 				SetPackage(fPackageListener->Package());
131 				break;
132 		}
133 	}
134 
135 	virtual void MouseDown(BPoint where)
136 	{
137 		BRect bounds = Bounds();
138 		BRect parentBounds = Parent()->Bounds();
139 		ConvertFromParent(&parentBounds);
140 		bounds = bounds & parentBounds;
141 
142 		if (bounds.Contains(where) && Window()->IsActive()) {
143 			BMessage message(MSG_PACKAGE_SELECTED);
144 			message.AddString("title", PackageTitle());
145 			Window()->PostMessage(&message);
146 		}
147 	}
148 
149 	void SetPackage(const PackageInfoRef& package)
150 	{
151 		fPackageListener->SetPackage(package);
152 
153 		if (package->Icon().Get() != NULL) {
154 			fIconView->SetBitmap(
155 				package->Icon()->Bitmap(SharedBitmap::SIZE_64));
156 		} else
157 			fIconView->SetBitmap(NULL);
158 
159 		if (package->State() == ACTIVATED) {
160 			fInstalledIconView->SetBitmap(
161 				sInstalledIcon->Bitmap(SharedBitmap::SIZE_16));
162 		} else
163 			fInstalledIconView->SetBitmap(NULL);
164 
165 		fTitleView->SetText(package->Title());
166 
167 		BString publisher = package->Publisher().Name();
168 		fPublisherView->SetText(publisher);
169 
170 		BString summary = package->ShortDescription();
171 		fSummaryView->SetText(summary);
172 
173 		RatingSummary ratingSummary = package->CalculateRatingSummary();
174 
175 		fRatingView->SetRating(ratingSummary.averageRating);
176 
177 		if (ratingSummary.ratingCount > 0) {
178 			BString avgRating;
179 			avgRating.SetToFormat("%.1f", ratingSummary.averageRating);
180 			fAvgRating->SetText(avgRating);
181 
182 			BString votes;
183 			votes.SetToFormat("%d", ratingSummary.ratingCount);
184 
185 			BString voteInfo(B_TRANSLATE("(%Votes%)"));
186 			voteInfo.ReplaceAll("%Votes%", votes);
187 
188 			fVoteInfo->SetText(voteInfo);
189 		} else {
190 			fAvgRating->SetText("");
191 			fVoteInfo->SetText("");
192 		}
193 
194 		InvalidateLayout();
195 		Invalidate();
196 	}
197 
198 	void Clear()
199 	{
200 		fPackageListener->SetPackage(PackageInfoRef(NULL));
201 
202 		fIconView->SetBitmap(NULL);
203 		fInstalledIconView->SetBitmap(NULL);
204 		fTitleView->SetText("");
205 		fPublisherView->SetText("");
206 		fSummaryView->SetText("");
207 		fRatingView->SetRating(-1.0f);
208 		fAvgRating->SetText("");
209 		fVoteInfo->SetText("");
210 	}
211 
212 	const char* PackageTitle() const
213 	{
214 		return fTitleView->Text();
215 	}
216 
217 	void SetSelected(bool selected)
218 	{
219 		if (fSelected == selected)
220 			return;
221 		fSelected = selected;
222 
223 		rgb_color bgColor;
224 		if (fSelected)
225 			bgColor = ui_color(B_LIST_SELECTED_BACKGROUND_COLOR);
226 		else
227 			bgColor = (rgb_color){ 255, 255, 255, 255 };
228 
229 		List<BView*, true> views;
230 
231 		views.Add(this);
232 		views.Add(fIconView);
233 		views.Add(fInstalledIconView);
234 		views.Add(fTitleView);
235 		views.Add(fPublisherView);
236 		views.Add(fSummaryView);
237 		views.Add(fRatingView);
238 		views.Add(fAvgRating);
239 		views.Add(fVoteInfo);
240 
241 		for (int32 i = 0; i < views.CountItems(); i++) {
242 			BView* view = views.ItemAtFast(i);
243 
244 			view->SetViewColor(bgColor);
245 			view->SetLowColor(bgColor);
246 			view->Invalidate();
247 		}
248 	}
249 
250 private:
251 	OnePackageMessagePackageListener* fPackageListener;
252 
253 	BitmapView*						fIconView;
254 	BitmapView*						fInstalledIconView;
255 
256 	BStringView*					fTitleView;
257 	BStringView*					fPublisherView;
258 
259 	MarkupTextView*					fSummaryView;
260 
261 	RatingView*						fRatingView;
262 	BStringView*					fAvgRating;
263 	BStringView*					fVoteInfo;
264 
265 	bool							fSelected;
266 
267 };
268 
269 
270 // #pragma mark - FeaturedPackagesView
271 
272 
273 FeaturedPackagesView::FeaturedPackagesView()
274 	:
275 	BView("featured package view", 0)
276 {
277 	BGroupLayout* layout = new BGroupLayout(B_VERTICAL);
278 	SetLayout(layout);
279 
280 	ScrollableGroupView* containerView = new ScrollableGroupView();
281 	containerView->SetViewColor(255, 255, 255);
282 	fPackageListLayout = containerView->GroupLayout();
283 
284 	BScrollView* scrollView = new BScrollView(
285 		"featured packages scroll view", containerView,
286 		0, false, true, B_FANCY_BORDER);
287 
288 	BScrollBar* scrollBar = scrollView->ScrollBar(B_VERTICAL);
289 	if (scrollBar != NULL)
290 		scrollBar->SetSteps(10.0f, 20.0f);
291 
292 	BLayoutBuilder::Group<>(this)
293 		.Add(scrollView, 1.0f)
294 	;
295 }
296 
297 
298 FeaturedPackagesView::~FeaturedPackagesView()
299 {
300 }
301 
302 
303 void
304 FeaturedPackagesView::AddPackage(const PackageInfoRef& package)
305 {
306 	// Find insertion index (alphabetical)
307 	int32 index = 0;
308 	for (int32 i = 0; BLayoutItem* item = fPackageListLayout->ItemAt(i); i++) {
309 		PackageView* view = dynamic_cast<PackageView*>(item->View());
310 		if (view == NULL)
311 			break;
312 
313 		BString title = view->PackageTitle();
314 		if (title == package->Title()) {
315 			// Don't add packages more than once
316 			return;
317 		}
318 
319 		if (title.Compare(package->Title()) < 0)
320 			index++;
321 	}
322 
323 	PackageView* view = new PackageView();
324 	view->SetPackage(package);
325 
326 	fPackageListLayout->AddView(index, view);
327 }
328 
329 
330 void
331 FeaturedPackagesView::Clear()
332 {
333 	for (int32 i = fPackageListLayout->CountItems() - 1;
334 			BLayoutItem* item = fPackageListLayout->ItemAt(i); i--) {
335 		BView* view = dynamic_cast<PackageView*>(item->View());
336 		if (view != NULL) {
337 			view->RemoveSelf();
338 			delete view;
339 		}
340 	}
341 }
342 
343 
344 void
345 FeaturedPackagesView::SelectPackage(const PackageInfoRef& package)
346 {
347 	BString selectedTitle;
348 	if (package.Get() != NULL)
349 		selectedTitle = package->Title();
350 
351 	for (int32 i = 0; BLayoutItem* item = fPackageListLayout->ItemAt(i); i++) {
352 		PackageView* view = dynamic_cast<PackageView*>(item->View());
353 		if (view == NULL)
354 			break;
355 
356 		BString title = view->PackageTitle();
357 		view->SetSelected(title == selectedTitle);
358 	}
359 }
360 
361 
362 void
363 FeaturedPackagesView::CleanupIcons()
364 {
365 	sInstalledIcon.Unset();
366 }
367