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