xref: /haiku/src/apps/haikudepot/ui/FeaturedPackagesView.cpp (revision a3e794ae459fec76826407f8ba8c94cd3535f128)
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 		SetViewUIColor(B_LIST_BACKGROUND_COLOR);
48 		SetHighUIColor(B_LIST_ITEM_TEXT_COLOR);
49 		SetEventMask(B_POINTER_EVENTS);
50 
51 		fIconView = new BitmapView("package icon view");
52 		fInstalledIconView = new BitmapView("installed icon view");
53 		fTitleView = new BStringView("package title view", "");
54 		fPublisherView = new BStringView("package publisher view", "");
55 
56 		// Title font
57 		BFont font;
58 		GetFont(&font);
59 		font_family family;
60 		font_style style;
61 		font.SetSize(ceilf(font.Size() * 1.8f));
62 		font.GetFamilyAndStyle(&family, &style);
63 		font.SetFamilyAndStyle(family, "Bold");
64 		fTitleView->SetFont(&font);
65 
66 		// Publisher font
67 		GetFont(&font);
68 		font.SetSize(std::max(9.0f, floorf(font.Size() * 0.92f)));
69 		font.SetFamilyAndStyle(family, "Italic");
70 		fPublisherView->SetFont(&font);
71 
72 		// Summary text view
73 		fSummaryView = new BTextView("package summary");
74 		fSummaryView->MakeSelectable(false);
75 		fSummaryView->MakeEditable(false);
76 		font = BFont(be_plain_font);
77 		rgb_color color = HighColor();
78 		fSummaryView->SetFontAndColor(&font, B_FONT_ALL, &color);
79 
80 		// Rating view
81 		fRatingView = new RatingView("package rating view");
82 
83 		fAvgRating = new BStringView("package average rating", "");
84 		fAvgRating->SetFont(&font);
85 
86 		fVoteInfo = new BStringView("package vote info", "");
87 		// small font
88 		GetFont(&font);
89 		font.SetSize(std::max(9.0f, floorf(font.Size() * 0.85f)));
90 		fVoteInfo->SetFont(&font);
91 		fVoteInfo->SetHighUIColor(HighUIColor());
92 
93 		BLayoutBuilder::Group<>(this)
94 			.Add(fIconView)
95 			.AddGroup(B_VERTICAL, 1.0f, 2.2f)
96 				.AddGroup(B_HORIZONTAL)
97 					.Add(fTitleView)
98 					.Add(fInstalledIconView)
99 					.AddGlue()
100 				.End()
101 				.Add(fPublisherView)
102 				.SetExplicitMaxSize(BSize(B_SIZE_UNLIMITED, B_SIZE_UNSET))
103 			.End()
104 			.AddGlue(0.1f)
105 			.AddGroup(B_HORIZONTAL, 0.8f)
106 				.Add(fRatingView)
107 				.Add(fAvgRating)
108 				.Add(fVoteInfo)
109 			.End()
110 			.AddGlue(0.2f)
111 			.Add(fSummaryView, 2.0f)
112 
113 			.SetInsets(B_USE_WINDOW_INSETS)
114 		;
115 
116 		Clear();
117 	}
118 
119 	virtual ~PackageView()
120 	{
121 		fPackageListener->SetPackage(PackageInfoRef(NULL));
122 		delete fPackageListener;
123 	}
124 
125 	virtual void AllAttached()
126 	{
127 		for (int32 index = 0; index < CountChildren(); ++index) {
128 			ChildAt(index)->SetViewUIColor(ViewUIColor());
129 			ChildAt(index)->SetLowUIColor(ViewUIColor());
130 			ChildAt(index)->SetHighUIColor(HighUIColor());
131 		}
132 	}
133 
134 	virtual void MessageReceived(BMessage* message)
135 	{
136 		switch (message->what) {
137 			case B_MOUSE_WHEEL_CHANGED:
138 				Window()->PostMessage(message, Parent());
139 				break;
140 
141 			case MSG_UPDATE_PACKAGE:
142 				SetPackage(fPackageListener->Package());
143 				break;
144 
145 			case B_COLORS_UPDATED:
146 			{
147 				if (message->HasColor(ui_color_name(B_LIST_ITEM_TEXT_COLOR)))
148 					_UpdateColors();
149 				break;
150 			}
151 		}
152 	}
153 
154 	virtual void MouseDown(BPoint where)
155 	{
156 		BRect bounds = Bounds();
157 		BRect parentBounds = Parent()->Bounds();
158 		ConvertFromParent(&parentBounds);
159 		bounds = bounds & parentBounds;
160 
161 		if (bounds.Contains(where) && Window()->IsActive()) {
162 			BMessage message(MSG_PACKAGE_SELECTED);
163 			message.AddString("name", PackageName());
164 			Window()->PostMessage(&message);
165 		}
166 	}
167 
168 	void SetPackage(const PackageInfoRef& package)
169 	{
170 		fPackageListener->SetPackage(package);
171 
172 		if (package->Icon().Get() != NULL) {
173 			fIconView->SetBitmap(package->Icon(), SharedBitmap::SIZE_64);
174 		} else
175 			fIconView->UnsetBitmap();
176 
177 		if (package->State() == ACTIVATED) {
178 			fInstalledIconView->SetBitmap(sInstalledIcon,
179 				SharedBitmap::SIZE_16);
180 		} else
181 			fInstalledIconView->UnsetBitmap();
182 
183 		fTitleView->SetText(package->Title());
184 
185 		BString publisher = package->Publisher().Name();
186 		fPublisherView->SetText(publisher);
187 
188 		BString summary = package->ShortDescription();
189 		fSummaryView->SetText(summary);
190 
191 		RatingSummary ratingSummary = package->CalculateRatingSummary();
192 
193 		fRatingView->SetRating(ratingSummary.averageRating);
194 
195 		if (ratingSummary.ratingCount > 0) {
196 			BString avgRating;
197 			avgRating.SetToFormat("%.1f", ratingSummary.averageRating);
198 			fAvgRating->SetText(avgRating);
199 
200 			BString votes;
201 			votes.SetToFormat("%d", ratingSummary.ratingCount);
202 
203 			BString voteInfo(B_TRANSLATE("(%Votes%)"));
204 			voteInfo.ReplaceAll("%Votes%", votes);
205 
206 			fVoteInfo->SetText(voteInfo);
207 		} else {
208 			fAvgRating->SetText("");
209 			fVoteInfo->SetText("");
210 		}
211 
212 		InvalidateLayout();
213 		Invalidate();
214 	}
215 
216 	void Clear()
217 	{
218 		fPackageListener->SetPackage(PackageInfoRef(NULL));
219 
220 		fIconView->UnsetBitmap();
221 		fInstalledIconView->UnsetBitmap();
222 		fTitleView->SetText("");
223 		fPublisherView->SetText("");
224 		fSummaryView->SetText("");
225 		fRatingView->SetRating(-1.0f);
226 		fAvgRating->SetText("");
227 		fVoteInfo->SetText("");
228 	}
229 
230 	const char* PackageTitle() const
231 	{
232 		return fTitleView->Text();
233 	}
234 
235 	const char* PackageName() const
236 	{
237 		if (fPackageListener->Package().Get() != NULL)
238 			return fPackageListener->Package()->Name();
239 		else
240 			return "";
241 	}
242 
243 	void SetSelected(bool selected)
244 	{
245 		if (fSelected == selected)
246 			return;
247 		fSelected = selected;
248 
249 		_UpdateColors();
250 	}
251 
252 	void _UpdateColors()
253 	{
254 		color_which bgColor = B_LIST_BACKGROUND_COLOR;
255 		color_which textColor = B_LIST_ITEM_TEXT_COLOR;
256 
257 		if (fSelected) {
258 			bgColor = B_LIST_SELECTED_BACKGROUND_COLOR;
259 			textColor = B_LIST_SELECTED_ITEM_TEXT_COLOR;
260 		}
261 
262 		List<BView*, true> views;
263 
264 		views.Add(this);
265 		views.Add(fIconView);
266 		views.Add(fInstalledIconView);
267 		views.Add(fTitleView);
268 		views.Add(fPublisherView);
269 		views.Add(fSummaryView);
270 		views.Add(fRatingView);
271 		views.Add(fAvgRating);
272 		views.Add(fVoteInfo);
273 
274 		for (int32 i = 0; i < views.CountItems(); i++) {
275 			BView* view = views.ItemAtFast(i);
276 
277 			view->SetViewUIColor(bgColor);
278 			view->SetLowUIColor(bgColor);
279 			view->SetHighUIColor(textColor);
280 			view->Invalidate();
281 		}
282 
283 		BFont font(be_plain_font);
284 		rgb_color color = HighColor();
285 		fSummaryView->SetFontAndColor(&font, B_FONT_ALL, &color);
286 	}
287 
288 private:
289 	OnePackageMessagePackageListener* fPackageListener;
290 
291 	BitmapView*						fIconView;
292 	BitmapView*						fInstalledIconView;
293 
294 	BStringView*					fTitleView;
295 	BStringView*					fPublisherView;
296 
297 	BTextView*						fSummaryView;
298 
299 	RatingView*						fRatingView;
300 	BStringView*					fAvgRating;
301 	BStringView*					fVoteInfo;
302 
303 	bool							fSelected;
304 
305 	BString							fPackageName;
306 };
307 
308 
309 // #pragma mark - FeaturedPackagesView
310 
311 
312 FeaturedPackagesView::FeaturedPackagesView()
313 	:
314 	BView("featured package view", 0)
315 {
316 	BGroupLayout* layout = new BGroupLayout(B_VERTICAL);
317 	SetLayout(layout);
318 
319 	ScrollableGroupView* containerView = new ScrollableGroupView();
320 	containerView->SetViewUIColor(B_LIST_BACKGROUND_COLOR);
321 	fPackageListLayout = containerView->GroupLayout();
322 
323 	BScrollView* scrollView = new BScrollView(
324 		"featured packages scroll view", containerView,
325 		0, false, true, B_FANCY_BORDER);
326 
327 	BScrollBar* scrollBar = scrollView->ScrollBar(B_VERTICAL);
328 	if (scrollBar != NULL)
329 		scrollBar->SetSteps(10.0f, 20.0f);
330 
331 	BLayoutBuilder::Group<>(this)
332 		.Add(scrollView, 1.0f)
333 	;
334 }
335 
336 
337 FeaturedPackagesView::~FeaturedPackagesView()
338 {
339 }
340 
341 
342 void
343 FeaturedPackagesView::AddPackage(const PackageInfoRef& package)
344 {
345 	// Find insertion index (alphabetical)
346 	int32 index = 0;
347 	for (int32 i = 0; BLayoutItem* item = fPackageListLayout->ItemAt(i); i++) {
348 		PackageView* view = dynamic_cast<PackageView*>(item->View());
349 		if (view == NULL)
350 			break;
351 
352 		BString name = view->PackageName();
353 		if (name == package->Name()) {
354 			// Don't add packages more than once
355 			return;
356 		}
357 
358 		BString title = view->PackageTitle();
359 		if (title.Compare(package->Title()) < 0)
360 			index++;
361 	}
362 
363 	PackageView* view = new PackageView();
364 	view->SetPackage(package);
365 
366 	fPackageListLayout->AddView(index, view);
367 }
368 
369 
370 void
371 FeaturedPackagesView::RemovePackage(const PackageInfoRef& package)
372 {
373 	// Find the package
374 	for (int32 i = 0; BLayoutItem* item = fPackageListLayout->ItemAt(i); i++) {
375 		PackageView* view = dynamic_cast<PackageView*>(item->View());
376 		if (view == NULL)
377 			break;
378 
379 		BString name = view->PackageName();
380 		if (name == package->Name()) {
381 			view->RemoveSelf();
382 			delete view;
383 			break;
384 		}
385 	}
386 }
387 
388 
389 void
390 FeaturedPackagesView::Clear()
391 {
392 	for (int32 i = fPackageListLayout->CountItems() - 1;
393 			BLayoutItem* item = fPackageListLayout->ItemAt(i); i--) {
394 		BView* view = dynamic_cast<PackageView*>(item->View());
395 		if (view != NULL) {
396 			view->RemoveSelf();
397 			delete view;
398 		}
399 	}
400 }
401 
402 
403 void
404 FeaturedPackagesView::SelectPackage(const PackageInfoRef& package)
405 {
406 	BString selectedName;
407 	if (package.Get() != NULL)
408 		selectedName = package->Name();
409 
410 	for (int32 i = 0; BLayoutItem* item = fPackageListLayout->ItemAt(i); i++) {
411 		PackageView* view = dynamic_cast<PackageView*>(item->View());
412 		if (view == NULL)
413 			break;
414 
415 		BString name = view->PackageName();
416 		view->SetSelected(name == selectedName);
417 	}
418 }
419 
420 
421 void
422 FeaturedPackagesView::CleanupIcons()
423 {
424 	sInstalledIcon.Unset();
425 }
426