1f545fe6aSStephan Aßmus /* 2f545fe6aSStephan Aßmus * Copyright 2013-214, Stephan Aßmus <superstippi@gmx.de>. 3f545fe6aSStephan Aßmus * All rights reserved. Distributed under the terms of the MIT License. 4f545fe6aSStephan Aßmus */ 5f545fe6aSStephan Aßmus 6f545fe6aSStephan Aßmus #include "FeaturedPackagesView.h" 7f545fe6aSStephan Aßmus 8f545fe6aSStephan Aßmus #include <stdio.h> 9f545fe6aSStephan Aßmus 10f545fe6aSStephan Aßmus #include <Catalog.h> 11f545fe6aSStephan Aßmus #include <Font.h> 12f545fe6aSStephan Aßmus #include <LayoutBuilder.h> 13f545fe6aSStephan Aßmus #include <Message.h> 14f545fe6aSStephan Aßmus #include <ScrollView.h> 15f545fe6aSStephan Aßmus #include <StringView.h> 16f545fe6aSStephan Aßmus #include <SpaceLayoutItem.h> 17f545fe6aSStephan Aßmus 18f545fe6aSStephan Aßmus #include "BitmapView.h" 191f3c1ef1SStephan Aßmus #include "MainWindow.h" 206f6ad915SStephan Aßmus #include "MarkupTextView.h" 21f545fe6aSStephan Aßmus #include "MessagePackageListener.h" 22f545fe6aSStephan Aßmus #include "RatingView.h" 23f545fe6aSStephan Aßmus #include "ScrollableGroupView.h" 24f545fe6aSStephan Aßmus 25f545fe6aSStephan Aßmus 26f545fe6aSStephan Aßmus #undef B_TRANSLATION_CONTEXT 27f545fe6aSStephan Aßmus #define B_TRANSLATION_CONTEXT "FeaturedPackagesView" 28f545fe6aSStephan Aßmus 29f545fe6aSStephan Aßmus 30f545fe6aSStephan Aßmus static const rgb_color kLightBlack = (rgb_color){ 60, 60, 60, 255 }; 31f545fe6aSStephan Aßmus 32056d423cSStephan Aßmus static BitmapRef sInstalledIcon(new(std::nothrow) SharedBitmap(504), true); 33056d423cSStephan Aßmus 34f545fe6aSStephan Aßmus 35f545fe6aSStephan Aßmus // #pragma mark - PackageView 36f545fe6aSStephan Aßmus 37f545fe6aSStephan Aßmus 38f545fe6aSStephan Aßmus class PackageView : public BGroupView { 39f545fe6aSStephan Aßmus public: 40f545fe6aSStephan Aßmus PackageView() 41f545fe6aSStephan Aßmus : 42f545fe6aSStephan Aßmus BGroupView("package view", B_HORIZONTAL), 433d869af5SStephan Aßmus fPackageListener( 44664372abSStephan Aßmus new(std::nothrow) OnePackageMessagePackageListener(this)), 45664372abSStephan Aßmus fSelected(false) 46f545fe6aSStephan Aßmus { 474b930ccaSStephan Aßmus SetViewColor(255, 255, 255); 481f3c1ef1SStephan Aßmus SetEventMask(B_POINTER_EVENTS); 494b930ccaSStephan Aßmus 50f545fe6aSStephan Aßmus fIconView = new BitmapView("package icon view"); 51056d423cSStephan Aßmus fInstalledIconView = new BitmapView("installed icon view"); 52f545fe6aSStephan Aßmus fTitleView = new BStringView("package title view", ""); 53f545fe6aSStephan Aßmus fPublisherView = new BStringView("package publisher view", ""); 54f545fe6aSStephan Aßmus 55f545fe6aSStephan Aßmus // Title font 56f545fe6aSStephan Aßmus BFont font; 57f545fe6aSStephan Aßmus GetFont(&font); 58f545fe6aSStephan Aßmus font_family family; 59f545fe6aSStephan Aßmus font_style style; 604b930ccaSStephan Aßmus font.SetSize(ceilf(font.Size() * 1.8f)); 61f545fe6aSStephan Aßmus font.GetFamilyAndStyle(&family, &style); 62f545fe6aSStephan Aßmus font.SetFamilyAndStyle(family, "Bold"); 63f545fe6aSStephan Aßmus fTitleView->SetFont(&font); 64f545fe6aSStephan Aßmus 65f545fe6aSStephan Aßmus // Publisher font 66f545fe6aSStephan Aßmus GetFont(&font); 67f545fe6aSStephan Aßmus font.SetSize(std::max(9.0f, floorf(font.Size() * 0.92f))); 68f545fe6aSStephan Aßmus font.SetFamilyAndStyle(family, "Italic"); 69f545fe6aSStephan Aßmus fPublisherView->SetFont(&font); 70f545fe6aSStephan Aßmus fPublisherView->SetHighColor(kLightBlack); 71f545fe6aSStephan Aßmus 72ef40255dSStephan Aßmus // Summary text view 736f6ad915SStephan Aßmus fSummaryView = new MarkupTextView("package summary"); 74ef40255dSStephan Aßmus fSummaryView->SetSelectionEnabled(false); 756f6ad915SStephan Aßmus 766f6ad915SStephan Aßmus // Rating view 776f6ad915SStephan Aßmus fRatingView = new RatingView("package rating view"); 786f6ad915SStephan Aßmus 796f6ad915SStephan Aßmus fAvgRating = new BStringView("package average rating", ""); 806f6ad915SStephan Aßmus fAvgRating->SetFont(&font); 816f6ad915SStephan Aßmus fAvgRating->SetHighColor(kLightBlack); 826f6ad915SStephan Aßmus 836f6ad915SStephan Aßmus fVoteInfo = new BStringView("package vote info", ""); 846f6ad915SStephan Aßmus // small font 856f6ad915SStephan Aßmus GetFont(&font); 866f6ad915SStephan Aßmus font.SetSize(std::max(9.0f, floorf(font.Size() * 0.85f))); 876f6ad915SStephan Aßmus fVoteInfo->SetFont(&font); 886f6ad915SStephan Aßmus fVoteInfo->SetHighColor(kLightBlack); 89f545fe6aSStephan Aßmus 90f545fe6aSStephan Aßmus BLayoutBuilder::Group<>(this) 91f545fe6aSStephan Aßmus .Add(fIconView) 92f545fe6aSStephan Aßmus .AddGroup(B_VERTICAL, 1.0f, 2.2f) 93056d423cSStephan Aßmus .AddGroup(B_HORIZONTAL) 94f545fe6aSStephan Aßmus .Add(fTitleView) 95056d423cSStephan Aßmus .Add(fInstalledIconView) 96056d423cSStephan Aßmus .AddGlue() 97056d423cSStephan Aßmus .End() 98f545fe6aSStephan Aßmus .Add(fPublisherView) 99f545fe6aSStephan Aßmus .SetExplicitMaxSize(BSize(B_SIZE_UNLIMITED, B_SIZE_UNSET)) 100f545fe6aSStephan Aßmus .End() 101f545fe6aSStephan Aßmus .AddGlue(0.1f) 1026f6ad915SStephan Aßmus .AddGroup(B_HORIZONTAL, 0.8f) 1036f6ad915SStephan Aßmus .Add(fRatingView) 1046f6ad915SStephan Aßmus .Add(fAvgRating) 1056f6ad915SStephan Aßmus .Add(fVoteInfo) 106f545fe6aSStephan Aßmus .End() 1076f6ad915SStephan Aßmus .AddGlue(0.2f) 1086f6ad915SStephan Aßmus .Add(fSummaryView, 2.0f) 1096f6ad915SStephan Aßmus 1104b930ccaSStephan Aßmus .SetInsets(B_USE_WINDOW_INSETS) 111f545fe6aSStephan Aßmus ; 112f545fe6aSStephan Aßmus 113f545fe6aSStephan Aßmus Clear(); 114f545fe6aSStephan Aßmus } 115f545fe6aSStephan Aßmus 116f545fe6aSStephan Aßmus virtual ~PackageView() 117f545fe6aSStephan Aßmus { 118f545fe6aSStephan Aßmus fPackageListener->SetPackage(PackageInfoRef(NULL)); 119f545fe6aSStephan Aßmus delete fPackageListener; 120f545fe6aSStephan Aßmus } 121f545fe6aSStephan Aßmus 122f545fe6aSStephan Aßmus virtual void MessageReceived(BMessage* message) 123f545fe6aSStephan Aßmus { 124f545fe6aSStephan Aßmus switch (message->what) { 1258507d262SStephan Aßmus case B_MOUSE_WHEEL_CHANGED: 1268507d262SStephan Aßmus Window()->PostMessage(message, Parent()); 1278507d262SStephan Aßmus break; 1288507d262SStephan Aßmus 129f545fe6aSStephan Aßmus case MSG_UPDATE_PACKAGE: 130f545fe6aSStephan Aßmus SetPackage(fPackageListener->Package()); 131f545fe6aSStephan Aßmus break; 132f545fe6aSStephan Aßmus } 133f545fe6aSStephan Aßmus } 134f545fe6aSStephan Aßmus 1351f3c1ef1SStephan Aßmus virtual void MouseDown(BPoint where) 1361f3c1ef1SStephan Aßmus { 137dfbf4d38SStephan Aßmus BRect bounds = Bounds(); 138dfbf4d38SStephan Aßmus BRect parentBounds = Parent()->Bounds(); 139dfbf4d38SStephan Aßmus ConvertFromParent(&parentBounds); 140dfbf4d38SStephan Aßmus bounds = bounds & parentBounds; 141dfbf4d38SStephan Aßmus 142dfbf4d38SStephan Aßmus if (bounds.Contains(where) && Window()->IsActive()) { 1431f3c1ef1SStephan Aßmus BMessage message(MSG_PACKAGE_SELECTED); 1441f3c1ef1SStephan Aßmus message.AddString("title", PackageTitle()); 1451f3c1ef1SStephan Aßmus Window()->PostMessage(&message); 1461f3c1ef1SStephan Aßmus } 1471f3c1ef1SStephan Aßmus } 1481f3c1ef1SStephan Aßmus 149f545fe6aSStephan Aßmus void SetPackage(const PackageInfoRef& package) 150f545fe6aSStephan Aßmus { 151f545fe6aSStephan Aßmus fPackageListener->SetPackage(package); 152f545fe6aSStephan Aßmus 153f545fe6aSStephan Aßmus if (package->Icon().Get() != NULL) { 154f545fe6aSStephan Aßmus fIconView->SetBitmap( 1554b930ccaSStephan Aßmus package->Icon()->Bitmap(SharedBitmap::SIZE_64)); 156f545fe6aSStephan Aßmus } else 157f545fe6aSStephan Aßmus fIconView->SetBitmap(NULL); 158f545fe6aSStephan Aßmus 159056d423cSStephan Aßmus if (package->State() == ACTIVATED) { 160056d423cSStephan Aßmus fInstalledIconView->SetBitmap( 161056d423cSStephan Aßmus sInstalledIcon->Bitmap(SharedBitmap::SIZE_16)); 162056d423cSStephan Aßmus } else 163056d423cSStephan Aßmus fInstalledIconView->SetBitmap(NULL); 164056d423cSStephan Aßmus 165f545fe6aSStephan Aßmus fTitleView->SetText(package->Title()); 166f545fe6aSStephan Aßmus 167f545fe6aSStephan Aßmus BString publisher = package->Publisher().Name(); 168f545fe6aSStephan Aßmus fPublisherView->SetText(publisher); 169f545fe6aSStephan Aßmus 1706f6ad915SStephan Aßmus BString summary = package->ShortDescription(); 1716f6ad915SStephan Aßmus fSummaryView->SetText(summary); 1726f6ad915SStephan Aßmus 1736f6ad915SStephan Aßmus RatingSummary ratingSummary = package->CalculateRatingSummary(); 1746f6ad915SStephan Aßmus 1756f6ad915SStephan Aßmus fRatingView->SetRating(ratingSummary.averageRating); 1766f6ad915SStephan Aßmus 1776f6ad915SStephan Aßmus if (ratingSummary.ratingCount > 0) { 1786f6ad915SStephan Aßmus BString avgRating; 1796f6ad915SStephan Aßmus avgRating.SetToFormat("%.1f", ratingSummary.averageRating); 1806f6ad915SStephan Aßmus fAvgRating->SetText(avgRating); 1816f6ad915SStephan Aßmus 1826f6ad915SStephan Aßmus BString votes; 1836f6ad915SStephan Aßmus votes.SetToFormat("%d", ratingSummary.ratingCount); 1846f6ad915SStephan Aßmus 1856f6ad915SStephan Aßmus BString voteInfo(B_TRANSLATE("(%Votes%)")); 1866f6ad915SStephan Aßmus voteInfo.ReplaceAll("%Votes%", votes); 1876f6ad915SStephan Aßmus 1886f6ad915SStephan Aßmus fVoteInfo->SetText(voteInfo); 1896f6ad915SStephan Aßmus } else { 1906f6ad915SStephan Aßmus fAvgRating->SetText(""); 1916f6ad915SStephan Aßmus fVoteInfo->SetText(""); 1926f6ad915SStephan Aßmus } 193f545fe6aSStephan Aßmus 194f545fe6aSStephan Aßmus InvalidateLayout(); 195f545fe6aSStephan Aßmus Invalidate(); 196f545fe6aSStephan Aßmus } 197f545fe6aSStephan Aßmus 198f545fe6aSStephan Aßmus void Clear() 199f545fe6aSStephan Aßmus { 200f545fe6aSStephan Aßmus fPackageListener->SetPackage(PackageInfoRef(NULL)); 201f545fe6aSStephan Aßmus 202f545fe6aSStephan Aßmus fIconView->SetBitmap(NULL); 203056d423cSStephan Aßmus fInstalledIconView->SetBitmap(NULL); 204f545fe6aSStephan Aßmus fTitleView->SetText(""); 205f545fe6aSStephan Aßmus fPublisherView->SetText(""); 2066f6ad915SStephan Aßmus fSummaryView->SetText(""); 2076f6ad915SStephan Aßmus fRatingView->SetRating(-1.0f); 2086f6ad915SStephan Aßmus fAvgRating->SetText(""); 2096f6ad915SStephan Aßmus fVoteInfo->SetText(""); 210f545fe6aSStephan Aßmus } 211f545fe6aSStephan Aßmus 2124b930ccaSStephan Aßmus const char* PackageTitle() const 2134b930ccaSStephan Aßmus { 2144b930ccaSStephan Aßmus return fTitleView->Text(); 2154b930ccaSStephan Aßmus } 2164b930ccaSStephan Aßmus 217664372abSStephan Aßmus void SetSelected(bool selected) 218664372abSStephan Aßmus { 219664372abSStephan Aßmus if (fSelected == selected) 220664372abSStephan Aßmus return; 221664372abSStephan Aßmus fSelected = selected; 222664372abSStephan Aßmus 223664372abSStephan Aßmus rgb_color bgColor; 224664372abSStephan Aßmus if (fSelected) 225664372abSStephan Aßmus bgColor = ui_color(B_LIST_SELECTED_BACKGROUND_COLOR); 226664372abSStephan Aßmus else 227664372abSStephan Aßmus bgColor = (rgb_color){ 255, 255, 255, 255 }; 228664372abSStephan Aßmus 229664372abSStephan Aßmus List<BView*, true> views; 230664372abSStephan Aßmus 231664372abSStephan Aßmus views.Add(this); 232664372abSStephan Aßmus views.Add(fIconView); 233056d423cSStephan Aßmus views.Add(fInstalledIconView); 234664372abSStephan Aßmus views.Add(fTitleView); 235664372abSStephan Aßmus views.Add(fPublisherView); 236664372abSStephan Aßmus views.Add(fSummaryView); 237664372abSStephan Aßmus views.Add(fRatingView); 238664372abSStephan Aßmus views.Add(fAvgRating); 239664372abSStephan Aßmus views.Add(fVoteInfo); 240664372abSStephan Aßmus 241664372abSStephan Aßmus for (int32 i = 0; i < views.CountItems(); i++) { 242664372abSStephan Aßmus BView* view = views.ItemAtFast(i); 243664372abSStephan Aßmus 244664372abSStephan Aßmus view->SetViewColor(bgColor); 245664372abSStephan Aßmus view->SetLowColor(bgColor); 246664372abSStephan Aßmus view->Invalidate(); 247664372abSStephan Aßmus } 248664372abSStephan Aßmus } 249664372abSStephan Aßmus 250f545fe6aSStephan Aßmus private: 2513d869af5SStephan Aßmus OnePackageMessagePackageListener* fPackageListener; 252f545fe6aSStephan Aßmus 253f545fe6aSStephan Aßmus BitmapView* fIconView; 254056d423cSStephan Aßmus BitmapView* fInstalledIconView; 255f545fe6aSStephan Aßmus 256f545fe6aSStephan Aßmus BStringView* fTitleView; 257f545fe6aSStephan Aßmus BStringView* fPublisherView; 258f545fe6aSStephan Aßmus 2596f6ad915SStephan Aßmus MarkupTextView* fSummaryView; 2606f6ad915SStephan Aßmus 2616f6ad915SStephan Aßmus RatingView* fRatingView; 2626f6ad915SStephan Aßmus BStringView* fAvgRating; 2636f6ad915SStephan Aßmus BStringView* fVoteInfo; 264664372abSStephan Aßmus 265664372abSStephan Aßmus bool fSelected; 266056d423cSStephan Aßmus 267f545fe6aSStephan Aßmus }; 268f545fe6aSStephan Aßmus 269f545fe6aSStephan Aßmus 270f545fe6aSStephan Aßmus // #pragma mark - FeaturedPackagesView 271f545fe6aSStephan Aßmus 272f545fe6aSStephan Aßmus 273f545fe6aSStephan Aßmus FeaturedPackagesView::FeaturedPackagesView() 274f545fe6aSStephan Aßmus : 275f545fe6aSStephan Aßmus BView("featured package view", 0) 276f545fe6aSStephan Aßmus { 277f545fe6aSStephan Aßmus BGroupLayout* layout = new BGroupLayout(B_VERTICAL); 278f545fe6aSStephan Aßmus SetLayout(layout); 279f545fe6aSStephan Aßmus 280f545fe6aSStephan Aßmus ScrollableGroupView* containerView = new ScrollableGroupView(); 281f545fe6aSStephan Aßmus containerView->SetViewColor(255, 255, 255); 282f545fe6aSStephan Aßmus fPackageListLayout = containerView->GroupLayout(); 283f545fe6aSStephan Aßmus 284f545fe6aSStephan Aßmus BScrollView* scrollView = new BScrollView( 2854b930ccaSStephan Aßmus "featured packages scroll view", containerView, 2864b930ccaSStephan Aßmus 0, false, true, B_FANCY_BORDER); 287f545fe6aSStephan Aßmus 2888507d262SStephan Aßmus BScrollBar* scrollBar = scrollView->ScrollBar(B_VERTICAL); 2898507d262SStephan Aßmus if (scrollBar != NULL) 2908507d262SStephan Aßmus scrollBar->SetSteps(10.0f, 20.0f); 2918507d262SStephan Aßmus 292f545fe6aSStephan Aßmus BLayoutBuilder::Group<>(this) 293f545fe6aSStephan Aßmus .Add(scrollView, 1.0f) 294f545fe6aSStephan Aßmus ; 295f545fe6aSStephan Aßmus } 296f545fe6aSStephan Aßmus 297f545fe6aSStephan Aßmus 298f545fe6aSStephan Aßmus FeaturedPackagesView::~FeaturedPackagesView() 299f545fe6aSStephan Aßmus { 300f545fe6aSStephan Aßmus } 301f545fe6aSStephan Aßmus 302f545fe6aSStephan Aßmus 303f545fe6aSStephan Aßmus void 304f545fe6aSStephan Aßmus FeaturedPackagesView::AddPackage(const PackageInfoRef& package) 305f545fe6aSStephan Aßmus { 3064b930ccaSStephan Aßmus // Find insertion index (alphabetical) 3074b930ccaSStephan Aßmus int32 index = 0; 3084b930ccaSStephan Aßmus for (int32 i = 0; BLayoutItem* item = fPackageListLayout->ItemAt(i); i++) { 3094b930ccaSStephan Aßmus PackageView* view = dynamic_cast<PackageView*>(item->View()); 3104b930ccaSStephan Aßmus if (view == NULL) 3114b930ccaSStephan Aßmus break; 3124b930ccaSStephan Aßmus 3134b930ccaSStephan Aßmus BString title = view->PackageTitle(); 31464458d22SStephan Aßmus if (title == package->Title()) { 31564458d22SStephan Aßmus // Don't add packages more than once 31664458d22SStephan Aßmus return; 31764458d22SStephan Aßmus } 3184b930ccaSStephan Aßmus 31964458d22SStephan Aßmus if (title.Compare(package->Title()) < 0) 3204b930ccaSStephan Aßmus index++; 3214b930ccaSStephan Aßmus } 3224b930ccaSStephan Aßmus 32364458d22SStephan Aßmus PackageView* view = new PackageView(); 32464458d22SStephan Aßmus view->SetPackage(package); 32564458d22SStephan Aßmus 3264b930ccaSStephan Aßmus fPackageListLayout->AddView(index, view); 327f545fe6aSStephan Aßmus } 328f545fe6aSStephan Aßmus 329f545fe6aSStephan Aßmus 330f545fe6aSStephan Aßmus void 331*18b941b4SStephan Aßmus FeaturedPackagesView::RemovePackage(const PackageInfoRef& package) 332*18b941b4SStephan Aßmus { 333*18b941b4SStephan Aßmus // Find the package 334*18b941b4SStephan Aßmus for (int32 i = 0; BLayoutItem* item = fPackageListLayout->ItemAt(i); i++) { 335*18b941b4SStephan Aßmus PackageView* view = dynamic_cast<PackageView*>(item->View()); 336*18b941b4SStephan Aßmus if (view == NULL) 337*18b941b4SStephan Aßmus break; 338*18b941b4SStephan Aßmus 339*18b941b4SStephan Aßmus BString title = view->PackageTitle(); 340*18b941b4SStephan Aßmus if (title == package->Title()) { 341*18b941b4SStephan Aßmus view->RemoveSelf(); 342*18b941b4SStephan Aßmus delete view; 343*18b941b4SStephan Aßmus break; 344*18b941b4SStephan Aßmus } 345*18b941b4SStephan Aßmus } 346*18b941b4SStephan Aßmus } 347*18b941b4SStephan Aßmus 348*18b941b4SStephan Aßmus 349*18b941b4SStephan Aßmus void 350f545fe6aSStephan Aßmus FeaturedPackagesView::Clear() 351f545fe6aSStephan Aßmus { 352f545fe6aSStephan Aßmus for (int32 i = fPackageListLayout->CountItems() - 1; 353f545fe6aSStephan Aßmus BLayoutItem* item = fPackageListLayout->ItemAt(i); i--) { 354f545fe6aSStephan Aßmus BView* view = dynamic_cast<PackageView*>(item->View()); 355f545fe6aSStephan Aßmus if (view != NULL) { 356f545fe6aSStephan Aßmus view->RemoveSelf(); 357f545fe6aSStephan Aßmus delete view; 358f545fe6aSStephan Aßmus } 359f545fe6aSStephan Aßmus } 360f545fe6aSStephan Aßmus } 361f545fe6aSStephan Aßmus 362664372abSStephan Aßmus 363664372abSStephan Aßmus void 364664372abSStephan Aßmus FeaturedPackagesView::SelectPackage(const PackageInfoRef& package) 365664372abSStephan Aßmus { 366ede65a8fSStephan Aßmus BString selectedTitle; 367ede65a8fSStephan Aßmus if (package.Get() != NULL) 368ede65a8fSStephan Aßmus selectedTitle = package->Title(); 369ede65a8fSStephan Aßmus 370664372abSStephan Aßmus for (int32 i = 0; BLayoutItem* item = fPackageListLayout->ItemAt(i); i++) { 371664372abSStephan Aßmus PackageView* view = dynamic_cast<PackageView*>(item->View()); 372664372abSStephan Aßmus if (view == NULL) 373664372abSStephan Aßmus break; 374664372abSStephan Aßmus 375664372abSStephan Aßmus BString title = view->PackageTitle(); 376ede65a8fSStephan Aßmus view->SetSelected(title == selectedTitle); 377664372abSStephan Aßmus } 378664372abSStephan Aßmus } 379664372abSStephan Aßmus 380056d423cSStephan Aßmus 381056d423cSStephan Aßmus void 382056d423cSStephan Aßmus FeaturedPackagesView::CleanupIcons() 383056d423cSStephan Aßmus { 384056d423cSStephan Aßmus sInstalledIcon.Unset(); 385056d423cSStephan Aßmus } 386