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