diff --git a/drape_frontend/drape_engine.cpp b/drape_frontend/drape_engine.cpp index 43dd97b0f6..eee38244ed 100644 --- a/drape_frontend/drape_engine.cpp +++ b/drape_frontend/drape_engine.cpp @@ -935,7 +935,7 @@ drape_ptr DrapeEngine::GenerateMarkRenderInfo(UserPointMar renderInfo->m_pixelOffset = mark->GetPixelOffset(); renderInfo->m_titleDecl = mark->GetTitleDecl(); renderInfo->m_symbolNames = mark->GetSymbolNames(); - renderInfo->m_badgeNames = mark->GetBadgeNames(); + renderInfo->m_badgeInfo = mark->GetBadgeInfo(); renderInfo->m_coloredSymbols = mark->GetColoredSymbols(); renderInfo->m_symbolSizes = mark->GetSymbolSizes(); renderInfo->m_symbolOffsets = mark->GetSymbolOffsets(); diff --git a/drape_frontend/poi_symbol_shape.cpp b/drape_frontend/poi_symbol_shape.cpp index 091794105e..33d74326f0 100644 --- a/drape_frontend/poi_symbol_shape.cpp +++ b/drape_frontend/poi_symbol_shape.cpp @@ -1,4 +1,5 @@ #include "drape_frontend/poi_symbol_shape.hpp" + #include "drape_frontend/color_constants.hpp" #include "shaders/programs.hpp" @@ -9,6 +10,7 @@ #include "drape/utils/vertex_decl.hpp" #include +#include namespace { @@ -53,21 +55,44 @@ void Batch(ref_ptr context, ref_ptr batche dp::TextureManager::SymbolRegion const & symbolRegion, dp::TextureManager::ColorRegion const & colorRegion) { - m2::PointF const pixelSize = symbolRegion.GetPixelSize(); - m2::PointF const halfSize(pixelSize.x * 0.5f, pixelSize.y * 0.5f); + m2::PointF const symbolRegionSize = symbolRegion.GetPixelSize(); + m2::PointF pixelSize = symbolRegionSize; + if (pixelSize.x < params.m_pixelWidth) + pixelSize.x = params.m_pixelWidth; + m2::PointF const halfSize = pixelSize * 0.5f; m2::RectF const & texRect = symbolRegion.GetTexRect(); - SV vertexes[] = + std::vector vertexes; + vertexes.reserve(params.m_pixelWidth ? 8 : 4); + vertexes.emplace_back(position, + ShiftNormal(glsl::vec2(-halfSize.x, halfSize.y), params, pixelSize), + glsl::vec2(texRect.minX(), texRect.maxY())); + vertexes.emplace_back(position, + ShiftNormal(glsl::vec2(-halfSize.x, -halfSize.y), params, pixelSize), + glsl::vec2(texRect.minX(), texRect.minY())); + if (symbolRegionSize.x < params.m_pixelWidth) { - SV{ position, ShiftNormal(glsl::vec2(-halfSize.x, halfSize.y), params, pixelSize), - glsl::vec2(texRect.minX(), texRect.maxY()) }, - SV{ position, ShiftNormal(glsl::vec2(-halfSize.x, -halfSize.y), params, pixelSize), - glsl::vec2(texRect.minX(), texRect.minY()) }, - SV{ position, ShiftNormal(glsl::vec2(halfSize.x, halfSize.y), params, pixelSize), - glsl::vec2(texRect.maxX(), texRect.maxY()) }, - SV{ position, ShiftNormal(glsl::vec2(halfSize.x, -halfSize.y), params, pixelSize), - glsl::vec2(texRect.maxX(), texRect.minY()) }, - }; + float const stretchHalfWidth = (params.m_pixelWidth - symbolRegionSize.x) * 0.5f; + float const midTexU = (texRect.minX() + texRect.maxX()) * 0.5f; + vertexes.emplace_back(position, + ShiftNormal(glsl::vec2(-stretchHalfWidth, halfSize.y), params, pixelSize), + glsl::vec2(midTexU, texRect.maxY())); + vertexes.emplace_back(position, + ShiftNormal(glsl::vec2(-stretchHalfWidth, -halfSize.y), params, pixelSize), + glsl::vec2(midTexU, texRect.minY())); + vertexes.emplace_back(position, + ShiftNormal(glsl::vec2(stretchHalfWidth, halfSize.y), params, pixelSize), + glsl::vec2(midTexU, texRect.maxY())); + vertexes.emplace_back(position, + ShiftNormal(glsl::vec2(stretchHalfWidth, -halfSize.y), params, pixelSize), + glsl::vec2(midTexU, texRect.minY())); + } + vertexes.emplace_back(position, + ShiftNormal(glsl::vec2(halfSize.x, halfSize.y), params, pixelSize), + glsl::vec2(texRect.maxX(), texRect.maxY())); + vertexes.emplace_back(position, + ShiftNormal(glsl::vec2(halfSize.x, -halfSize.y), params, pixelSize), + glsl::vec2(texRect.maxX(), texRect.minY())); auto state = df::CreateRenderState(gpu::Program::Texturing, params.m_depthLayer); state.SetProgram3d(gpu::Program::TexturingBillboard); @@ -76,8 +101,8 @@ void Batch(ref_ptr context, ref_ptr batche state.SetTextureFilter(dp::TextureFilter::Nearest); state.SetTextureIndex(symbolRegion.GetTextureIndex()); - dp::AttributeProvider provider(1 /* streamCount */, ARRAY_SIZE(vertexes)); - provider.InitStream(0 /* streamIndex */, SV::GetBindingInfo(), make_ref(vertexes)); + dp::AttributeProvider provider(1 /* streamCount */, vertexes.size()); + provider.InitStream(0 /* streamIndex */, SV::GetBindingInfo(), make_ref(vertexes.data())); batcher->InsertTriangleStrip(context, state, make_ref(&provider), move(handle)); } @@ -88,22 +113,45 @@ void Batch(ref_ptr context, ref_ptr batche dp::TextureManager::SymbolRegion const & symbolRegion, dp::TextureManager::ColorRegion const & colorRegion) { - m2::PointF const pixelSize = symbolRegion.GetPixelSize(); - m2::PointF const halfSize(pixelSize.x * 0.5f, pixelSize.y * 0.5f); + m2::PointF const symbolRegionSize = symbolRegion.GetPixelSize(); + m2::PointF pixelSize = symbolRegionSize; + if (pixelSize.x < params.m_pixelWidth) + pixelSize.x = params.m_pixelWidth; + m2::PointF const halfSize = pixelSize * 0.5f; m2::RectF const & texRect = symbolRegion.GetTexRect(); glsl::vec2 const maskColorCoords = glsl::ToVec2(colorRegion.GetTexRect().Center()); - MV vertexes[] = + std::vector vertexes; + vertexes.reserve(params.m_pixelWidth ? 8 : 4); + vertexes.emplace_back(position, + ShiftNormal(glsl::vec2(-halfSize.x, halfSize.y), params, pixelSize), + glsl::vec2(texRect.minX(), texRect.maxY()), maskColorCoords); + vertexes.emplace_back(position, + ShiftNormal(glsl::vec2(-halfSize.x, -halfSize.y), params, pixelSize), + glsl::vec2(texRect.minX(), texRect.minY()), maskColorCoords); + if (symbolRegionSize.x < params.m_pixelWidth) { - MV{ position, ShiftNormal(glsl::vec2(-halfSize.x, halfSize.y), params, pixelSize), - glsl::vec2(texRect.minX(), texRect.maxY()), maskColorCoords }, - MV{ position, ShiftNormal(glsl::vec2(-halfSize.x, -halfSize.y), params, pixelSize), - glsl::vec2(texRect.minX(), texRect.minY()), maskColorCoords }, - MV{ position, ShiftNormal(glsl::vec2(halfSize.x, halfSize.y), params, pixelSize), - glsl::vec2(texRect.maxX(), texRect.maxY()), maskColorCoords }, - MV{ position, ShiftNormal(glsl::vec2(halfSize.x, -halfSize.y), params, pixelSize), - glsl::vec2(texRect.maxX(), texRect.minY()), maskColorCoords }, - }; + float const stretchHalfWidth = (params.m_pixelWidth - symbolRegionSize.x) * 0.5f; + float const midTexU = (texRect.minX() + texRect.maxX()) * 0.5f; + vertexes.emplace_back(position, + ShiftNormal(glsl::vec2(-stretchHalfWidth, halfSize.y), params, pixelSize), + glsl::vec2(midTexU, texRect.maxY()), maskColorCoords); + vertexes.emplace_back(position, + ShiftNormal(glsl::vec2(-stretchHalfWidth, -halfSize.y), params, pixelSize), + glsl::vec2(midTexU, texRect.minY()), maskColorCoords); + vertexes.emplace_back(position, + ShiftNormal(glsl::vec2(stretchHalfWidth, halfSize.y), params, pixelSize), + glsl::vec2(midTexU, texRect.maxY()), maskColorCoords); + vertexes.emplace_back(position, + ShiftNormal(glsl::vec2(stretchHalfWidth, -halfSize.y), params, pixelSize), + glsl::vec2(midTexU, texRect.minY()), maskColorCoords); + } + vertexes.emplace_back(position, + ShiftNormal(glsl::vec2(halfSize.x, halfSize.y), params, pixelSize), + glsl::vec2(texRect.maxX(), texRect.maxY()), maskColorCoords); + vertexes.emplace_back(position, + ShiftNormal(glsl::vec2(halfSize.x, -halfSize.y), params, pixelSize), + glsl::vec2(texRect.maxX(), texRect.minY()), maskColorCoords); auto state = df::CreateRenderState(gpu::Program::MaskedTexturing, params.m_depthLayer); state.SetProgram3d(gpu::Program::MaskedTexturingBillboard); @@ -113,8 +161,8 @@ void Batch(ref_ptr context, ref_ptr batche state.SetTextureFilter(dp::TextureFilter::Nearest); state.SetTextureIndex(symbolRegion.GetTextureIndex()); - dp::AttributeProvider provider(1 /* streamCount */, ARRAY_SIZE(vertexes)); - provider.InitStream(0 /* streamIndex */, MV::GetBindingInfo(), make_ref(vertexes)); + dp::AttributeProvider provider(1 /* streamCount */, vertexes.size()); + provider.InitStream(0 /* streamIndex */, MV::GetBindingInfo(), make_ref(vertexes.data())); batcher->InsertTriangleStrip(context, state, make_ref(&provider), move(handle)); } } // namespace diff --git a/drape_frontend/shape_view_params.hpp b/drape_frontend/shape_view_params.hpp index b548d3defe..df75814ca6 100644 --- a/drape_frontend/shape_view_params.hpp +++ b/drape_frontend/shape_view_params.hpp @@ -7,6 +7,7 @@ #include "drape/stipple_pen_resource.hpp" #include "indexer/feature_decl.hpp" + #include "geometry/point2d.hpp" #include @@ -58,6 +59,11 @@ struct PoiSymbolViewParams : CommonOverlayViewParams bool m_obsoleteInEditor = false; dp::Anchor m_anchor = dp::Center; m2::PointF m_offset = m2::PointF(0.0f, 0.0f); + + // If greater then actual width of the symbol then symbol splitted at horz center and + // extended horizontally using texture coordinates taken at split line. + // If less or equal, then ignored. + float m_pixelWidth = 0.0f; }; struct AreaViewParams : CommonViewParams diff --git a/drape_frontend/user_mark_shapes.cpp b/drape_frontend/user_mark_shapes.cpp index 47bca8c8d9..5bb3a5b2fd 100644 --- a/drape_frontend/user_mark_shapes.cpp +++ b/drape_frontend/user_mark_shapes.cpp @@ -66,6 +66,19 @@ void AlignVertical(float halfHeight, dp::Anchor anchor, glsl::vec2 & up, glsl::v dp::Bottom, up, down); } +TextLayout MakePrimaryTextLayout(dp::TitleDecl const & titleDecl, + ref_ptr textures) +{ + dp::FontDecl const & fontDecl = titleDecl.m_primaryTextFont; + auto const vs = static_cast(df::VisualParams::Instance().GetVisualScale()); + bool const isSdf = fontDecl.m_outlineColor != dp::Color::Transparent() || + df::VisualParams::Instance().IsSdfPrefered(); + TextLayout textLayout; + textLayout.Init(strings::MakeUniString(titleDecl.m_primaryText), fontDecl.m_size * vs, isSdf, + textures); + return textLayout; +} + struct UserPointVertex : public gpu::BaseVertex { using TTexCoord = glsl::vec4; @@ -135,13 +148,7 @@ void GenerateColoredSymbolShapes(ref_ptr context, ref_ptrat(0); - dp::FontDecl const & fontDecl = titleDecl.m_primaryTextFont; - auto isSdf = df::VisualParams::Instance().IsSdfPrefered(); - isSdf = fontDecl.m_outlineColor != dp::Color::Transparent() ? true : isSdf; - auto const vs = static_cast(df::VisualParams::Instance().GetVisualScale()); - - TextLayout textLayout; - textLayout.Init(strings::MakeUniString(titleDecl.m_primaryText), fontDecl.m_size * vs, isSdf, textures); + auto textLayout = MakePrimaryTextLayout(titleDecl, textures); sizeInc.x = textLayout.GetPixelLength(); sizeInc.y = textLayout.GetPixelHeight(); @@ -222,6 +229,29 @@ void GeneratePoiSymbolShape(ref_ptr context, ref_ptrm_badgeTitleIndex) + { + size_t const badgeTitleIndex = *renderInfo.m_badgeInfo->m_badgeTitleIndex; + CHECK_LESS(badgeTitleIndex, renderInfo.m_titleDecl->size(), ()); + + dp::TitleDecl const & titleDecl = (*renderInfo.m_titleDecl)[badgeTitleIndex]; + TextLayout textLayout = MakePrimaryTextLayout(titleDecl, textures); + float const textWidth = textLayout.GetPixelLength(); + + dp::TextureManager::SymbolRegion region; + textures->GetSymbolRegion(symbolName, region); + float const pixelHalfWidth = 0.5f * region.GetPixelSize().x; + + float constexpr kBadgeSpecialMarginsAdjustmentMultplier = 4.0f; + float const badgeSpecialMarginsAdjustment = + kBadgeSpecialMarginsAdjustmentMultplier * titleDecl.m_primaryOffset.x; + + params.m_pixelWidth = 3.0f * pixelHalfWidth + textWidth + badgeSpecialMarginsAdjustment; + params.m_offset.x += 0.5f * (pixelHalfWidth + textWidth + badgeSpecialMarginsAdjustment); + } + params.m_tileCenter = tileCenter; params.m_depthTestEnabled = renderInfo.m_depthTestEnabled; params.m_depth = renderInfo.m_depth; @@ -231,7 +261,6 @@ void GeneratePoiSymbolShape(ref_ptr context, ref_ptrm_needOverlay; params.m_startOverlayRank = hasColoredOverlay ? dp::OverlayRank1 : dp::OverlayRank0; @@ -482,11 +511,12 @@ void CacheUserMarks(ref_ptr context, TileKey const & tileKe if (renderInfo.m_titleDecl != nullptr) GenerateTextShapes(context, textures, renderInfo, tileKey, tileCenter, symbolOffset, symbolSize, batcher); - if (renderInfo.m_badgeNames != nullptr) + if (renderInfo.m_badgeInfo != nullptr) { ASSERT(!renderInfo.m_symbolIsPOI || renderInfo.m_symbolNames == nullptr, ("Multiple POI shapes in an usermark are not supported yet")); - auto const badgeName = GetSymbolNameForZoomLevel(make_ref(renderInfo.m_badgeNames), tileKey); + auto const badgeName = + GetSymbolNameForZoomLevel(make_ref(&renderInfo.m_badgeInfo->m_zoomInfo), tileKey); if (!badgeName.empty()) { // TODO: Badges use symbol offset. Refactor and create own "offset"-method for badges. diff --git a/drape_frontend/user_mark_shapes.hpp b/drape_frontend/user_mark_shapes.hpp index c19a9f571b..9f76244190 100644 --- a/drape_frontend/user_mark_shapes.hpp +++ b/drape_frontend/user_mark_shapes.hpp @@ -26,7 +26,7 @@ struct UserMarkRenderParams drape_ptr m_titleDecl; drape_ptr m_symbolSizes; drape_ptr m_symbolOffsets; - drape_ptr m_badgeNames; + drape_ptr m_badgeInfo; df::ColorConstant m_color; bool m_symbolIsPOI = false; bool m_hasTitlePriority = false; diff --git a/drape_frontend/user_marks_provider.hpp b/drape_frontend/user_marks_provider.hpp index 48e0c7e7fd..b0a0170217 100644 --- a/drape_frontend/user_marks_provider.hpp +++ b/drape_frontend/user_marks_provider.hpp @@ -38,6 +38,10 @@ struct IDCollections class UserPointMark { public: + using SymbolNameZoomInfo = std::map; + using TitlesInfo = std::vector; + using SymbolSizes = std::vector; + using SymbolOffsets = std::vector; struct ColoredSymbolZoomInfo { std::map m_zoomInfo; @@ -45,10 +49,11 @@ public: bool m_needOverlay = true; bool m_addTextSize = false; }; - using SymbolNameZoomInfo = std::map; - using TitlesInfo = std::vector; - using SymbolSizes = std::vector; - using SymbolOffsets = std::vector; + struct BageInfo + { + SymbolNameZoomInfo m_zoomInfo; + std::optional m_badgeTitleIndex; + }; static float constexpr kInvalidDepth = dp::kMinDepth - 1.0; @@ -70,7 +75,7 @@ public: virtual bool IsVisible() const = 0; virtual drape_ptr GetTitleDecl() const = 0; virtual drape_ptr GetSymbolNames() const = 0; - virtual drape_ptr GetBadgeNames() const = 0; + virtual drape_ptr GetBadgeInfo() const = 0; virtual drape_ptr GetColoredSymbols() const = 0; virtual drape_ptr GetSymbolSizes() const = 0; virtual drape_ptr GetSymbolOffsets() const = 0; diff --git a/map/search_mark.cpp b/map/search_mark.cpp index 33a3ab93a3..740a975dd2 100644 --- a/map/search_mark.cpp +++ b/map/search_mark.cpp @@ -1,20 +1,23 @@ #include "map/search_mark.hpp" + #include "map/bookmark_manager.hpp" #include "map/place_page_info.hpp" #include "drape_frontend/drape_engine.hpp" #include "drape_frontend/visual_params.hpp" +#include "indexer/scales.hpp" + #include "platform/platform.hpp" #include "base/stl_helpers.hpp" +#include "defines.hpp" + #include #include #include -#include "defines.hpp" - namespace { enum class SearchMarkType @@ -101,53 +104,26 @@ std::array(SearchMarkType::Count)> const kSymbo "non-found-search-result", // NotFound. }; -std::string const kSaleBadgeName = "search-badge-booking-sale"; +std::string const kPriceChips = "price-chips"; +std::string const kPriceChipsSelected = "price-chips-selected"; +std::string const kPriceChipsDiscount = "price-chips-discount"; +std::string const kPriceChipsSelectedDiscount = "price-chips-selected-discount"; + std::string const kUGCRatingBadgeName = "search-badge-rating"; std::string const kRatedDefaultSearchIcon = "rated-default-search-result"; std::string const kLocalAdsRatedDefaultSearchIcon = "local_ads-rated-default-search-result"; float const kRatingThreshold = 6.0f; -float const kMetricThreshold = 0.38f; int constexpr kUGCBadgeMinZoomLevel = 10; -inline bool HasRating(float rating) +// Offset for price text relative to symbol and adjustment of price chip size +// for better margins of price text into the chip +float constexpr kPriceSpecialOffset = -4.0f; + +std::string GetBookingSmallIcon(bool hasLocalAds) { - return rating > kInvalidRatingValue; -} - -float CalculateAggregateMetric(float rating, int pricing) -{ - float const p1 = base::Clamp(rating, 0.0f, 10.0f) / 10.0f; - float const p2 = (3 - base::Clamp(pricing, 0, 3)) / 3.0f; - float const s = p1 + p2; - if (fabs(s) < 1e-5) - return 0.0f; - return 2.0f * p1 * p2 / s; -} - -std::string GetBookingBadgeName(int pricing) -{ - if (pricing == 0) - return {}; - - return std::string("search-badge-booking-ext-") + strings::to_string(pricing); -} - -bool NeedShowBookingBadge(float rating, int pricing) -{ - if (pricing == 0) - return false; - auto const metric = CalculateAggregateMetric(rating, pricing); - return metric >= kMetricThreshold; -} - -std::string GetBookingSmallIcon(SearchMarkType type, bool hasLocalAds) -{ - if (type != SearchMarkType::Booking) - return {}; - - return hasLocalAds ? "search-adv" : "coloredmark-default-s"; + return hasLocalAds ? "local_ads-coloredmark-default-s" : "coloredmark-default-s"; } std::string GetSymbol(SearchMarkType searchMarkType, bool hasLocalAds, bool isRated) @@ -160,12 +136,12 @@ std::string GetSymbol(SearchMarkType searchMarkType, bool hasLocalAds, bool isRa if (!hasLocalAds) return kSymbols[index]; - if (searchMarkType == SearchMarkType::Booking) - return "searchbookingadv-default-l"; - return "local_ads-" + kSymbols[index]; } +constexpr int GetGoodRatingZoomLevel() { return 1; } +constexpr int GetBadRatingZoomLevel() { return scales::GetUpperScale(); } + bool HasLocalAdsVariant(SearchMarkType searchMarkType) { if (searchMarkType == SearchMarkType::NotFound) @@ -274,15 +250,20 @@ SearchMarkType GetSearchMarkType(uint32_t type) SearchMarkPoint::SearchMarkPoint(m2::PointD const & ptOrg) : UserMark(ptOrg, UserMark::Type::SEARCH) { + double const fs = df::VisualParams::Instance().GetFontScale(); + m_titleDecl.m_anchor = dp::Center; m_titleDecl.m_primaryTextFont.m_color = df::GetColorConstant("RatingText"); - m_titleDecl.m_primaryTextFont.m_size = - static_cast(12.0 / df::VisualParams::Instance().GetFontScale()); + m_titleDecl.m_primaryTextFont.m_size = static_cast(10.0 / fs); m_ugcTitleDecl.m_anchor = dp::LeftTop; m_ugcTitleDecl.m_primaryTextFont.m_color = df::GetColorConstant("UGCRatingText"); - m_ugcTitleDecl.m_primaryTextFont.m_size = - static_cast(14.0 / df::VisualParams::Instance().GetFontScale()); + m_ugcTitleDecl.m_primaryTextFont.m_size = static_cast(10.0 / fs); + + m_badgeTitleDecl.m_anchor = dp::Left; + m_badgeTitleDecl.m_primaryTextFont.m_color = df::GetColorConstant("HotelPriceText"); + m_badgeTitleDecl.m_primaryTextFont.m_size = static_cast(10.0 / fs); + m_badgeTitleDecl.m_primaryOffset.x = kPriceSpecialOffset; } std::string SearchMarkPoint::GetSymbolName() const @@ -291,15 +272,15 @@ std::string SearchMarkPoint::GetSymbolName() const if (m_type >= static_cast(SearchMarkType::Count)) { ASSERT(false, ("Unknown search mark symbol.")); - name = GetSymbol(SearchMarkType::Default, false /* hasLocalAds */, HasRating(m_rating)); + name = GetSymbol(SearchMarkType::Default, false /* hasLocalAds */, HasRating()); } else if (m_isPreparing) { - name = GetPreparingSymbol(SMT(m_type), m_hasLocalAds, HasRating(m_rating)); + name = GetPreparingSymbol(SMT(m_type), m_hasLocalAds, HasRating()); } else { - name = GetSymbol(SMT(m_type), m_hasLocalAds, HasRating(m_rating)); + name = GetSymbol(SMT(m_type), m_hasLocalAds, HasRating()); } return name; } @@ -310,39 +291,48 @@ drape_ptr SearchMarkPoint::GetSymbolNames auto symbol = make_unique_dp(); if (IsBookingSpecialMark()) { - symbol->insert(std::make_pair( - 1 /* zoomLevel */, - m_rating < kRatingThreshold ? GetBookingSmallIcon(SMT(m_type), m_hasLocalAds) : name)); - symbol->insert(std::make_pair(17 /* zoomLevel */, name)); + if (HasGoodRating()) + { + symbol->emplace(GetGoodRatingZoomLevel(), name); + } + else + { + symbol->emplace(GetGoodRatingZoomLevel(), GetBookingSmallIcon(m_hasLocalAds)); + symbol->emplace(GetBadRatingZoomLevel(), name); + } } else { - symbol->insert(std::make_pair(1 /* zoomLevel */, name)); + symbol->emplace(1 /* zoomLevel */, name); } return symbol; } -drape_ptr SearchMarkPoint::GetBadgeNames() const +drape_ptr SearchMarkPoint::GetBadgeInfo() const { + if (!HasRating()) + return nullptr; + auto const badgeName = GetBadgeName(); if (badgeName.empty()) return nullptr; - - if (IsBookingSpecialMark()) + + if (IsBookingSpecialMark() && (HasPrice() || HasPricing())) { - auto symbol = make_unique_dp(); - if (NeedShowBookingBadge(m_rating, m_pricing) && m_rating >= kRatingThreshold) - symbol->insert(std::make_pair(10 /* zoomLevel */, badgeName)); + auto badgeInfo = make_unique_dp(); + badgeInfo->m_badgeTitleIndex = 1; + if (HasGoodRating()) + badgeInfo->m_zoomInfo.emplace(GetGoodRatingZoomLevel(), badgeName); else - symbol->insert(std::make_pair(17 /* zoomLevel */, badgeName)); - return symbol; + badgeInfo->m_zoomInfo.emplace(GetBadRatingZoomLevel(), badgeName); + return badgeInfo; } if (IsUGCMark()) { - auto symbol = make_unique_dp(); - symbol->insert(std::make_pair(kUGCBadgeMinZoomLevel /* zoomLevel */, badgeName)); - return symbol; + auto badgeInfo = make_unique_dp(); + badgeInfo->m_zoomInfo.emplace(kUGCBadgeMinZoomLevel, badgeName); + return badgeInfo; } return nullptr; @@ -386,7 +376,7 @@ df::ColorConstant SearchMarkPoint::GetColorConstant() const if (SMT(m_type) == SearchMarkType::Booking && m_hasLocalAds) return "RatingLocalAds"; - if (!HasRating(m_rating)) + if (!HasRating()) return "RatingNone"; if (m_rating < 2.0f) return "RatingHorrible"; @@ -401,13 +391,14 @@ df::ColorConstant SearchMarkPoint::GetColorConstant() const drape_ptr SearchMarkPoint::GetTitleDecl() const { - auto const isUGC = IsUGCMark(); - if ((!IsBookingSpecialMark() && !isUGC) || !HasRating(m_rating)) + if (!HasRating()) return nullptr; - auto titles = make_unique_dp(); - if (isUGC) + drape_ptr titles; + + if (IsUGCMark()) { + titles = make_unique_dp(); auto titleDecl = m_ugcTitleDecl; auto const sz = SearchMarks::GetSize(GetSymbolName()); if (!sz) @@ -421,25 +412,40 @@ drape_ptr SearchMarkPoint::GetTitleDecl() const } else { + titles = make_unique_dp(); titles->push_back(m_titleDecl); - if (!m_price.empty()) + if (IsBookingSpecialMark()) { - auto priceDecl = m_titleDecl; - priceDecl.m_primaryText = m_price; - priceDecl.m_anchor = dp::Anchor::Left; - titles->push_back(priceDecl); + if (HasPrice()) + { + dp::TitleDecl badgeTitleDecl = m_badgeTitleDecl; + badgeTitleDecl.m_primaryText = m_price; + titles->push_back(badgeTitleDecl); + } + else if (HasPricing()) + { + dp::TitleDecl badgeTitleDecl = m_badgeTitleDecl; + badgeTitleDecl.m_primaryText.assign(static_cast(m_pricing), '$'); + titles->push_back(badgeTitleDecl); + } } } + return titles; } int SearchMarkPoint::GetMinTitleZoom() const { - if (IsBookingSpecialMark() && m_rating < kRatingThreshold) - return 17; + if (IsBookingSpecialMark() && (HasPrice() || HasPricing())) + { + if (HasGoodRating()) + return GetGoodRatingZoomLevel(); + else + return GetBadRatingZoomLevel(); + } if (IsUGCMark()) return kUGCBadgeMinZoomLevel; - return 1; + return GetGoodRatingZoomLevel(); } df::DepthLayer SearchMarkPoint::GetDepthLayer() const @@ -494,9 +500,7 @@ void SearchMarkPoint::SetPricing(int pricing) void SearchMarkPoint::SetPrice(std::string && price) { - // Dummy. - // TODO: uncomment when drape will be ready. - // SetAttributeValue(m_price, std::move(price)); + SetAttributeValue(m_price, std::move(price)); } void SearchMarkPoint::SetSale(bool hasSale) @@ -524,19 +528,41 @@ bool SearchMarkPoint::IsBookingSpecialMark() const return (SMT(m_type) == SearchMarkType::Booking) && !m_isPreparing; } -bool SearchMarkPoint::IsUGCMark() const +bool SearchMarkPoint::HasGoodRating() const { return m_rating >= kRatingThreshold; } + +bool SearchMarkPoint::HasPrice() const { return !m_price.empty(); } + +bool SearchMarkPoint::HasPricing() const { return m_pricing > 0; } + +bool SearchMarkPoint::HasRating() const { return m_rating > kInvalidRatingValue; } + +bool SearchMarkPoint::IsUGCMark() const { return SMT(m_type) != SearchMarkType::Booking; } + +bool SearchMarkPoint::IsSelected() const { - return (SMT(m_type) != SearchMarkType::Booking) && HasRating(m_rating); + return false; // TODO(tomilov): add sane condition } +bool SearchMarkPoint::HasSale() const { return m_hasSale; } + std::string SearchMarkPoint::GetBadgeName() const { + if (!HasRating()) + return {}; + std::string badgeName; if (IsBookingSpecialMark()) - badgeName = m_hasSale ? kSaleBadgeName : GetBookingBadgeName(m_pricing); + { + if (IsSelected()) + badgeName = HasSale() ? kPriceChipsSelectedDiscount : kPriceChipsSelected; + else + badgeName = HasSale() ? kPriceChipsDiscount : kPriceChips; + } else if (IsUGCMark()) + { badgeName = kUGCRatingBadgeName; - + } + if (badgeName.empty() || !SearchMarks::GetSize(badgeName)) return {}; @@ -570,9 +596,11 @@ void SearchMarks::SetDrapeEngine(ref_ptr engine) } } - for (int pricing = 1; pricing <= 3; pricing++) - symbols.emplace_back(GetBookingBadgeName(pricing)); - symbols.emplace_back(kSaleBadgeName); + symbols.emplace_back(kPriceChips); + symbols.emplace_back(kPriceChipsSelected); + symbols.emplace_back(kPriceChipsDiscount); + symbols.emplace_back(kPriceChipsSelectedDiscount); + symbols.emplace_back(kUGCRatingBadgeName); base::SortUnique(symbols); diff --git a/map/search_mark.hpp b/map/search_mark.hpp index 98b87054d4..a2f194ddd3 100644 --- a/map/search_mark.hpp +++ b/map/search_mark.hpp @@ -30,7 +30,7 @@ public: drape_ptr GetTitleDecl() const override; int GetMinTitleZoom() const override; df::DepthLayer GetDepthLayer() const override; - drape_ptr GetBadgeNames() const override; + drape_ptr GetBadgeInfo() const override; drape_ptr GetSymbolOffsets() const override; bool GetDepthTestEnabled() const override { return false; } bool IsMarkAboveText() const override; @@ -66,7 +66,13 @@ protected: } bool IsBookingSpecialMark() const; + bool HasGoodRating() const; + bool HasPrice() const; + bool HasPricing() const; + bool HasRating() const; bool IsUGCMark() const; + bool IsSelected() const; + bool HasSale() const; std::string GetSymbolName() const; std::string GetBadgeName() const; @@ -81,6 +87,7 @@ protected: std::string m_price; bool m_hasSale = false; dp::TitleDecl m_titleDecl; + dp::TitleDecl m_badgeTitleDecl; dp::TitleDecl m_ugcTitleDecl; bool m_isVisited = false; bool m_isAvailable = true; diff --git a/map/user_mark.hpp b/map/user_mark.hpp index 841d00543e..0f25835fbb 100644 --- a/map/user_mark.hpp +++ b/map/user_mark.hpp @@ -78,7 +78,7 @@ public: df::DepthLayer GetDepthLayer() const override { return df::DepthLayer::UserMarkLayer; } drape_ptr GetTitleDecl() const override { return nullptr; } drape_ptr GetColoredSymbols() const override { return nullptr; } - drape_ptr GetBadgeNames() const override { return nullptr; } + drape_ptr GetBadgeInfo() const override { return nullptr; } drape_ptr GetSymbolSizes() const override { return nullptr; } drape_ptr GetSymbolOffsets() const override { return nullptr; } uint16_t GetPriority() const override { return static_cast(Priority::Default); }