From 74e4e1053aef7fac82cc793fdaaa45655b7b864f Mon Sep 17 00:00:00 2001 From: Alessandro Portale Date: Fri, 31 May 2024 21:31:09 +0200 Subject: [PATCH] ExtensionManager: Update ExtensionManager list items design This updates the list delegate for ExtensionManager items to match the latest Figma design. Change-Id: I769026caa1e08feea4f71d901d1bda01d74ab0a2 Reviewed-by: hjk --- .../extensionmanager/extensionmanager.qrc | 2 + .../extensionmanager/extensionsbrowser.cpp | 237 ++++++++++++------ .../extensionmanager/images/download.png | Bin 0 -> 137 bytes .../extensionmanager/images/download@2x.png | Bin 0 -> 207 bytes .../images/extensionsmall.png | Bin 164 -> 314 bytes .../images/extensionsmall@2x.png | Bin 196 -> 504 bytes .../extensionmanager/images/packsmall.png | Bin 271 -> 260 bytes .../extensionmanager/images/packsmall@2x.png | Bin 454 -> 418 bytes src/tools/icons/qtcreatoricons.svg | 32 ++- 9 files changed, 179 insertions(+), 92 deletions(-) create mode 100644 src/plugins/extensionmanager/images/download.png create mode 100644 src/plugins/extensionmanager/images/download@2x.png diff --git a/src/plugins/extensionmanager/extensionmanager.qrc b/src/plugins/extensionmanager/extensionmanager.qrc index cff16c156ff..b6a3554cb1f 100644 --- a/src/plugins/extensionmanager/extensionmanager.qrc +++ b/src/plugins/extensionmanager/extensionmanager.qrc @@ -1,5 +1,7 @@ + images/download.png + images/download@2x.png images/extensionsmall.png images/extensionsmall@2x.png images/mode_extensionmanager_mask.png diff --git a/src/plugins/extensionmanager/extensionsbrowser.cpp b/src/plugins/extensionmanager/extensionsbrowser.cpp index b5d42ec4f95..ccf814cd7c8 100644 --- a/src/plugins/extensionmanager/extensionsbrowser.cpp +++ b/src/plugins/extensionmanager/extensionsbrowser.cpp @@ -40,27 +40,37 @@ #include #include -using namespace ExtensionSystem; using namespace Core; +using namespace ExtensionSystem; using namespace Utils; +using namespace StyleHelper; +using namespace SpacingTokens; +using namespace WelcomePageHelpers; namespace ExtensionManager::Internal { Q_LOGGING_CATEGORY(browserLog, "qtc.extensionmanager.browser", QtWarningMsg) -constexpr QSize itemSize = {330, 86}; -constexpr int gapSize = StyleHelper::SpacingTokens::ExVPaddingGapXl; -constexpr QSize cellSize = {itemSize.width() + gapSize, itemSize.height() + gapSize}; - -static QColor colorForExtensionName(const QString &name) -{ - const size_t hash = qHash(name); - return QColor::fromHsv(hash % 360, 180, 110); -} +constexpr int gapSize = ExVPaddingGapXl; +constexpr int itemWidth = 330; +constexpr int cellWidth = itemWidth + HPaddingL; class ExtensionItemDelegate : public QItemDelegate { public: + constexpr static QSize dividerS{1, 16}; + constexpr static QSize iconBgS{50, 50}; + constexpr static TextFormat itemNameTF + {Theme::Token_Text_Default, UiElement::UiElementH6}; + constexpr static TextFormat countTF + {Theme::Token_Text_Default, UiElement::UiElementLabelSmall, + Qt::AlignCenter | Qt::TextDontClip}; + constexpr static TextFormat vendorTF + {Theme::Token_Text_Muted, UiElement::UiElementLabelSmall, + Qt::AlignVCenter | Qt::TextDontClip}; + constexpr static TextFormat tagsTF + {Theme::Token_Text_Default, UiElement::UiElementCaption}; + explicit ExtensionItemDelegate(QObject *parent = nullptr) : QItemDelegate(parent) { @@ -69,12 +79,54 @@ public: void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const override { + // +---------------+-------+---------------+----------------------------------------------------------------------+---------------+-----------+ + // | | | | (ExPaddingGapL) | | | + // | | | +-------------------------------------------------------------+--------+ | | + // | | | | || | | + // | | | +-------------------------------------------------------------+--------+ | | + // | | | | (VGapXxs) | | | + // | | | +--------+--------+--------------+--------+--------+---------+---------+ | | + // |(ExPaddingGapL)| |(ExPaddingGapL)||(HGapXs)|(h16)|(HGapXs)||(HGapXxs)||(ExPaddingGapL)|(HPaddingL)| + // | |(50x50)| +--------+--------+--------------+--------+--------+---------+---------+ | | + // | | | | (VGapXxs) | | | + // | | | +----------------------------------------------------------------------+ | | + // | | | | | | | + // | | | +----------------------------------------------------------------------+ | | + // | | | | (ExPaddingGapL) | | | + // +---------------+-------+---------------+----------------------------------------------------------------------+---------------+-----------+ + // | (ExVPaddingGapXl) | + // +------------------------------------------------------------------------------------------------------------------------------------------+ + + const QRect bgRGlobal = option.rect.adjusted(0, 0, -HPaddingL, -gapSize); + const QRect bgR = bgRGlobal.translated(-option.rect.topLeft()); + + const int middleColumnW = bgR.width() - ExPaddingGapL - iconBgS.width() - ExPaddingGapL + - ExPaddingGapL; + + int x = bgR.x(); + int y = bgR.y(); + x += ExPaddingGapL; + const QRect iconBgR(x, y + (bgR.height() - iconBgS.height()) / 2, + iconBgS.width(), iconBgS.height()); + x += iconBgS.width() + ExPaddingGapL; + y += ExPaddingGapL; + const QRect itemNameR(x, y, middleColumnW, itemNameTF.lineHeight()); + const QString itemName = index.data().toString(); + + y += itemNameR.height() + VGapXxs; + const QRect vendorRowR(x, y, middleColumnW, vendorRowHeight()); + QRect vendorR = vendorRowR; + + y += vendorRowR.height() + VGapXxs; + const QRect tagsR(x, y, middleColumnW, tagsTF.lineHeight()); + + QTC_CHECK(option.rect.height() - 1 == tagsR.bottom() + ExPaddingGapL + gapSize); + painter->save(); painter->setRenderHint(QPainter::Antialiasing); + painter->translate(bgRGlobal.topLeft()); - const QString itemName = index.data().toString(); const bool isPack = index.data(RoleItemType) == ItemTypePack; - const QRectF itemRect(option.rect.topLeft(), itemSize); { const bool selected = option.state & QStyle::State_Selected; const bool hovered = option.state & QStyle::State_MouseOver; @@ -85,94 +137,114 @@ public: creatorColor(selected ? Theme::Token_Stroke_Strong : hovered ? WelcomePageHelpers::cardHoverStroke : WelcomePageHelpers::cardDefaultStroke); - WelcomePageHelpers::drawCardBackground(painter, itemRect, fillColor, strokeColor); + WelcomePageHelpers::drawCardBackground(painter, bgR, fillColor, strokeColor); } { - constexpr QRectF bigCircle(16, 16, 48, 48); - constexpr double gradientMargin = 0.14645; - const QRectF bigCircleLocal = bigCircle.translated(itemRect.topLeft()); - QPainterPath bigCirclePath; - bigCirclePath.addEllipse(bigCircleLocal); - QLinearGradient gradient(bigCircleLocal.topLeft(), bigCircleLocal.bottomRight()); - const QColor startColor = isPack ? qRgb(0x1e, 0x99, 0x6e) - : colorForExtensionName(itemName); - const QColor endColor = isPack ? qRgb(0x07, 0x6b, 0x6d) : startColor.lighter(150); - gradient.setColorAt(gradientMargin, startColor); - gradient.setColorAt(1 - gradientMargin, endColor); - painter->fillPath(bigCirclePath, gradient); + QLinearGradient gradient(iconBgR.topRight(), iconBgR.bottomLeft()); + const QColor startColor = creatorColor(Utils::Theme::Token_Gradient01_Start); + const QColor endColor = creatorColor(Utils::Theme::Token_Gradient01_End); + gradient.setColorAt(0, startColor); + gradient.setColorAt(1, endColor); + constexpr int iconRectRounding = 4; + drawCardBackground(painter, iconBgR, gradient, Qt::NoPen, iconRectRounding); - static const QIcon packIcon = - Icon({{":/extensionmanager/images/packsmall.png", - Theme::Token_Text_Default}}, Icon::Tint).icon(); - static const QIcon extensionIcon = - Icon({{":/extensionmanager/images/extensionsmall.png", - Theme::Token_Text_Default}}, Icon::Tint).icon(); - QRectF iconRect(0, 0, 32, 32); - iconRect.moveCenter(bigCircleLocal.center()); - (isPack ? packIcon : extensionIcon).paint(painter, iconRect.toRect()); + // Icon + constexpr Theme::Color color = Theme::Token_Basic_White; + static const QIcon pack = Icon({{":/extensionmanager/images/packsmall.png", color}}, + Icon::Tint).icon(); + static const QIcon extension = Icon({{":/extensionmanager/images/extensionsmall.png", + color}}, Icon::Tint).icon(); + (isPack ? pack : extension).paint(painter, iconBgR); } if (isPack) { - constexpr QRectF smallCircle(47, 50, 18, 18); - constexpr qreal strokeWidth = 1; - constexpr qreal shrink = strokeWidth / 2; - constexpr QRectF smallCircleAdjusted = smallCircle.adjusted(shrink, shrink, - -shrink, -shrink); - const QRectF smallCircleLocal = smallCircleAdjusted.translated(itemRect.topLeft()); + constexpr int circleSize = 18; + constexpr int circleOverlap = 3; // Protrusion from lower right corner of iconRect + const QRect smallCircle(iconBgR.right() + 1 + circleOverlap - circleSize, + iconBgR.bottom() + 1 + circleOverlap - circleSize, + circleSize, circleSize); const QColor fillColor = creatorColor(Theme::Token_Foreground_Muted); const QColor strokeColor = creatorColor(Theme::Token_Stroke_Subtle); - painter->setBrush(fillColor); - painter->setPen(strokeColor); - painter->drawEllipse(smallCircleLocal); + drawCardBackground(painter, smallCircle, fillColor, strokeColor, circleSize / 2); - painter->setFont(StyleHelper::uiFont(StyleHelper::UiElementCaptionStrong)); - const QColor textColor = creatorColor(Theme::Token_Text_Default); - painter->setPen(textColor); + painter->setFont(countTF.font()); + painter->setPen(countTF.color()); const PluginsData plugins = index.data(RolePlugins).value(); - painter->drawText( - smallCircleLocal, - QString::number(plugins.count()), - QTextOption(Qt::AlignCenter)); + painter->drawText(smallCircle, countTF.drawTextFlags, QString::number(plugins.count())); } { - constexpr int textX = 80; - constexpr int rightMargin = StyleHelper::SpacingTokens::ExVPaddingGapXl; - constexpr int maxTextWidth = itemSize.width() - textX - rightMargin; - constexpr Qt::TextElideMode elideMode = Qt::ElideRight; - - constexpr int titleY = 30; - const QPointF titleOrigin(itemRect.topLeft() + QPointF(textX, titleY)); - painter->setPen(creatorColor(Theme::Token_Text_Default)); - painter->setFont(StyleHelper::uiFont(StyleHelper::UiElementH6)); + painter->setPen(itemNameTF.color()); + painter->setFont(itemNameTF.font()); const QString titleElided - = painter->fontMetrics().elidedText(itemName, elideMode, maxTextWidth); - painter->drawText(titleOrigin, titleElided); + = painter->fontMetrics().elidedText(itemName, Qt::ElideRight, itemNameR.width()); + painter->drawText(itemNameR, itemNameTF.drawTextFlags, titleElided); + } + { + const QString vendor = index.data(RoleVendor).toString(); + const QFontMetrics fm(vendorTF.font()); + painter->setPen(vendorTF.color()); + painter->setFont(vendorTF.font()); - constexpr int copyrightY = 52; - const QPointF copyrightOrigin(itemRect.topLeft() + QPointF(textX, copyrightY)); - painter->setPen(creatorColor(Theme::Token_Text_Muted)); - painter->setFont(StyleHelper::uiFont(StyleHelper::UiElementCaptionStrong)); - const QString copyright = index.data(RoleCopyright).toString(); - const QString copyrightElided - = painter->fontMetrics().elidedText(copyright, elideMode, maxTextWidth); - painter->drawText(copyrightOrigin, copyrightElided); + if (const int dlCount = index.data(RoleDownloadCount).toInt(); dlCount > 0) { + constexpr QSize dlIconS(16, 16); + const QString dlCountString = QString::number(dlCount); + const int dlCountW = fm.horizontalAdvance(dlCountString); + const int dlItemsW = HGapXs + dividerS.width() + HGapXs + dlIconS.width() + + HGapXxs + dlCountW; + const int vendorW = fm.horizontalAdvance(vendor); + vendorR.setWidth(qMin(middleColumnW - dlItemsW, vendorW)); - constexpr int tagsY = 70; - const QPointF tagsOrigin(itemRect.topLeft() + QPointF(textX, tagsY)); - const QString tags = index.data(RoleTags).toStringList().join(", "); - painter->setPen(creatorColor(Theme::Token_Text_Default)); - painter->setFont(StyleHelper::uiFont(StyleHelper::UiElementCaption)); - const QString tagsElided = painter->fontMetrics().elidedText( - tags, elideMode, maxTextWidth); - painter->drawText(tagsOrigin, tagsElided); + QRect dividerR = vendorRowR; + dividerR.setLeft(vendorR.right() + HGapXs); + dividerR.setWidth(dividerS.width()); + painter->fillRect(dividerR, vendorTF.color()); + + QRect dlIconR = vendorRowR; + dlIconR.setLeft(dividerR.right() + HGapXs); + dlIconR.setWidth(dlIconS.width()); + static const QIcon dlIcon = Icon({{":/extensionmanager/images/download.png", + vendorTF.themeColor}}, Icon::Tint).icon(); + dlIcon.paint(painter, dlIconR); + + QRect dlCountR = vendorRowR; + dlCountR.setLeft(dlIconR.right() + HGapXxs); + painter->drawText(dlCountR, vendorTF.drawTextFlags, dlCountString); + } + + const QString vendorElided = fm.elidedText(vendor, Qt::ElideRight, vendorR.width()); + painter->drawText(vendorR, vendorTF.drawTextFlags, vendorElided); + } + { + const QStringList tagList = index.data(RoleTags).toStringList(); + const QString tags = tagList.join(", "); + painter->setPen(tagsTF.color()); + painter->setFont(tagsTF.font()); + const QString tagsElided + = painter->fontMetrics().elidedText(tags, Qt::ElideRight, tagsR.width()); + painter->drawText(tagsR, tagsTF.drawTextFlags, tagsElided); } painter->restore(); } + static int vendorRowHeight() + { + return qMax(vendorTF.lineHeight(), dividerS.height()); + } + QSize sizeHint([[maybe_unused]] const QStyleOptionViewItem &option, [[maybe_unused]] const QModelIndex &index) const override { - return cellSize; + const int middleColumnH = + itemNameTF.lineHeight() + + VGapXxs + + vendorRowHeight() + + VGapXxs + + tagsTF.lineHeight(); + const int height = + ExPaddingGapL + + qMax(iconBgS.height(), middleColumnH) + + ExPaddingGapL; + return {cellWidth, height + gapSize}; } }; @@ -196,11 +268,10 @@ ExtensionsBrowser::ExtensionsBrowser(QWidget *parent) setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Preferred); auto manageLabel = new QLabel(Tr::tr("Manage Extensions")); - manageLabel->setFont(StyleHelper::uiFont(StyleHelper::UiElementH1)); + manageLabel->setFont(uiFont(UiElementH1)); d->searchBox = new SearchBox; - d->searchBox->setFixedWidth(itemSize.width()); - + d->searchBox->setFixedWidth(itemWidth); d->updateButton = new Button(Tr::tr("Install..."), Button::MediumPrimary); d->model = new ExtensionsModel(this); @@ -267,14 +338,14 @@ ExtensionsBrowser::~ExtensionsBrowser() void ExtensionsBrowser::adjustToWidth(const int width) { const int widthForItems = width - extraListViewWidth(); - d->columnsCount = qMax(1, qFloor(widthForItems / cellSize.width())); + d->columnsCount = qMax(1, qFloor(widthForItems / cellWidth)); d->updateButton->setVisible(d->columnsCount > 1); updateGeometry(); } QSize ExtensionsBrowser::sizeHint() const { - const int columsWidth = d->columnsCount * cellSize.width(); + const int columsWidth = d->columnsCount * cellWidth; return { columsWidth + extraListViewWidth(), 0}; } diff --git a/src/plugins/extensionmanager/images/download.png b/src/plugins/extensionmanager/images/download.png new file mode 100644 index 0000000000000000000000000000000000000000..d328e062fcc28df0bee443154bf9e6a851a73ee4 GIT binary patch literal 137 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4h9AW2CEqh_A)Rq1bDhQhDc0J{?X4Sv0zIt z?<@vp=2oWLX3Z?y@>{q+82hCr%s6}GAHSNx+=&w#8z(N5PdpYf;Q&jD^Kv62Kc}s! ouR=_+C;mw~+`y8vfpY;P!&Ih&xe>3LUV!ZIboFyt=akR{0Flov_y7O^ literal 0 HcmV?d00001 diff --git a/src/plugins/extensionmanager/images/download@2x.png b/src/plugins/extensionmanager/images/download@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..404df01da06f06b3ccb6cd54ba7799bc6e1c106e GIT binary patch literal 207 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4h9AWhA=@@4F(2=X`U{QAr`0KUfRfa$biT7 zVsz5f&WT4Oe`LD3w6a88U~O%zPv&sGqUReF5Pq*_$q!4lb1m|Y0lc9P4u&%xkPmST zc+39bR<6GA14o_4=Tc_xc^r5iT%5$bmx1X5)7e6+C$SQj-xTZSh^%(r_e>!s{FbxO zyO6jkoI8qhC#w~$jo*4#Y+kJx%TfVe!%1}u1^&yzopr00+EFy8r+H literal 0 HcmV?d00001 diff --git a/src/plugins/extensionmanager/images/extensionsmall.png b/src/plugins/extensionmanager/images/extensionsmall.png index 6cdb8df12c9e14b43bdccf8cc21716e2a99a5e86..b3d270c51468701034c0ecc766275427fdfb4825 100644 GIT binary patch delta 299 zcmZ3&xQl6mL_G%s0|P^tpsEG~10$oSi(`nz>Es{&3X_>U}MYM!NfD&@lJN{5{9#>0^k3+1~t?_G1^frZ`-V$km9m~ z=heOYuWe@>dB|mCv_MZ=Bqc#WXV1s~o_kF+PHZ@G)SRs?zkWOW1_Of!0SrZbqRc!A z5sZNc8dfsA@+g>5m=JuRVME4kGbS#Dhg~ZlNY@El9GG{!fSG;U3%5_LN8NHb*_Jh! zKeqX%!X9$q$bkfdzryESR8D`|Z}rw=n+f3*Mr delta 148 zcmdnRw1jbjL_G^L0|P^2NcwRG1_rGFpAc6D1_owkW-&1_Sy@>lBO_yDV;dWr;^N|| zQ>SjhNeZENw7h?sNJYsTY;PnJTAxm*HLyx5Bqpp14Q6KTOUxNWZzk zl-Ha&|3i0@A;bRI74Ht2Jg`>0uhf2~+=tn$TZk+F$qvE0J&E-VCN6Hf{&DUr`MyMM z8Q)=sj*2(sPMQC!bs`kS`It4z7+Dh=rsSOLW}U#|`jSD#JdSF0aknc5if0>q7x73m zs4y>)>@Z+377%1J5J+aIGMSXa5apzFm*L8io{$Tk!6^sQG*_M#k!%RO!Bfqg7bw-S zp~pMSBx(Jv0yULPCGGGSwvIfdO;yM98a|#`f5gmSgT#UPwKH4P_}UmFj&0sQ;mQdo z(+1@d^Oa|9IvCd^L{)!c|0Ff*|9^HvgAMNTY8zK_ua9WRotVEleZSh`jl63kmT2a@ k^UjrfYuqd4Ai=<}^SCvC6X)b81_lNOPgg&ebxsLQ0I7w=-T(jq delta 169 zcmeyte1vg=ay>)0r;B4q#Np&0{)!0_rU_RX0-4=-B}@}sBtB$rYB$klW+{kVqja;u zH;G3h!LE}nCn4s2DU~%2;Bd`1k$+r27?RH2Uqi{F6|4q5S8glNoQdCcEb6FNX?8zXAc~B zvpsjVyfJh0w<-J?Tt~*zm+?M|EJL=z-X_0{vY~6Harn zN=mSBFMM}&(S!g0^LcpgKX7dEWmGE`(EQQ1@`3auCccvM&P^@M(Iv|4uheol*;J!8 os9J96P*uGsH2Dp?Rz4HMqfYHcM%T@D3=9kmp00i_>zopr09qzs!~g&Q delta 243 zcmZo+>SvmuQh&|U#WBR27?Q+2di|~eytFhvmudzX|}M1$Q{n)6oJ`hzCDeG zZ}`Mm^H1ND+;PhO&;S2Ro2NILzEz#oG+&rSVuq8vgN6U)8Il#R_A6>fXdgfDpprB3 zovJ?@+s>^XTow`%A^~&CoEjS&nLQbqnY%6@IG38>5ZLgFVdQ&MBb@0QE6w A@Bjb+ diff --git a/src/plugins/extensionmanager/images/packsmall@2x.png b/src/plugins/extensionmanager/images/packsmall@2x.png index a58632c756c7b602a11861a1ba697b40352faa82..281ccd8207f07bd85d797bb29b6fec8afff041b3 100644 GIT binary patch delta 392 zcmX@cyoh;%N`0oMi(^Q{;p89wiU|^?2|uI@R!2B3`XRQH?a$q}hfgptU0Yo@G4a4= zK1()>2^#edvl#2k*)|z0V3>AbZhfcOgVO0-KJ%Y0a-C+d&FgyhA|8v$$5^i(oLwfT zQm{8hKTRrz`V7TA15%^tq*n5 zmUOO(DHJV<&y^?oYZ72H5)Li9V=XUL)MA?j3NpXiOtvqovb|>{s zx^+f5;_0Pj3q3a^E%Z;G&2{$gMZ3!!MhpzLwrh(Mbd}i|7#J8lUHx3vIVCVQ0RVLw Br;Y#s delta 428 zcmZ3)e2jU5N`0@Vi(^Q{;p89wiU|^?2|uJi?2YzX_1pR;+n?yAM;KU)jQ>waKM<$P zrg7n(R~zH>y%G}|uBQs|R?IrYbL~V}zyY>2gXK1=2OIQd_Xu>?zWek4zri%YGtadC zdn{qxpYG+bC0eG9V@^@S2Un{)q2vR3u^mNULuVvqt^Oxy^k7Q8ZP;ytnAXD#Hve2( zPUp^H+jCIzxG6V+DKI9(a|Wc*(Gz@kX$$*DIA2hG}~mW?6AcHB5VD5Tq{1 z_CTM%!-yfi(`5*J=pabCl?!z=X>FT*u%1;Z~@jUvn)0@9`l7E&MPZeYCs zQL4fIrqU$yc}cSI#~RZOG8bu!y@`}@KlbP0l+XkKd>g+I diff --git a/src/tools/icons/qtcreatoricons.svg b/src/tools/icons/qtcreatoricons.svg index 7d78434c75a..9c62d2a0ef3 100644 --- a/src/tools/icons/qtcreatoricons.svg +++ b/src/tools/icons/qtcreatoricons.svg @@ -3772,7 +3772,7 @@ height="100%" /> @@ -3787,15 +3787,29 @@ width="100%" height="100%" /> + id="path6795-3" + style="display:inline;fill:none;stroke:#000000;stroke-width:2;stroke-linejoin:round;stroke-linecap:round" + d="m 48,422.5 v 4 m 0,4 v 4 M 59,418 c 0,0 -1.6471,0.674 -3.6667,1.5 M 51.6667,421 C 49.6472,421.826 48,422.5 48,422.5 c 0,0 -1.6471,-0.674 -3.6667,-1.5 m -3.6666,-1.5 C 38.6472,418.674 37,418 37,418 m 7.3333,15.5 C 46.3528,434.326 48,435 48,435 m 11,-17.5 c 0,0 -1.6471,-0.674 -3.6667,-1.5 m -3.6666,-1.5 C 49.6472,413.674 48,413 48,413 c 0,0 -1.6471,0.674 -3.6667,1.5 M 40.6667,416 C 38.6472,416.826 37,417.5 37,417.5 v 4.333 m 0,4.334 v 4.333 c 0,0 1.6471,0.674 3.6667,1.5" /> + style="fill:#000000;stroke:#000000;stroke-width:2;stroke-linejoin:round" + d="M 59,421.75 V 430.5 l -8,3.25 V 425 Z" + id="path32048" + sodipodi:nodetypes="ccccc" /> + + + +