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