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