window_title_mac.mm 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179
  1. /*
  2. This file is part of Telegram Desktop,
  3. the official desktop application for the Telegram messaging service.
  4. For license and copyright information please follow this link:
  5. https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
  6. */
  7. #include "platform/platform_window_title.h"
  8. #include "ui/image/image_prepare.h"
  9. #include "ui/painter.h"
  10. #include "core/application.h"
  11. #include "styles/style_window.h"
  12. #include "styles/style_media_view.h"
  13. #include "window/window_controller.h"
  14. #include <Cocoa/Cocoa.h>
  15. namespace Platform {
  16. // All the window decorations preview is done without taking cScale() into
  17. // account, with 100% scale and without "px" dimensions, because thats
  18. // how it will look in real launched macOS app.
  19. int PreviewTitleHeight() {
  20. if (const auto window = Core::App().activePrimaryWindow()) {
  21. if (const auto height = window->widget()->getCustomTitleHeight()) {
  22. return height;
  23. }
  24. }
  25. return 22;
  26. }
  27. QImage PreviewWindowSystemButton(QColor inner, QColor border) {
  28. auto buttonSize = 12;
  29. auto fullSize = buttonSize * style::DevicePixelRatio();
  30. auto result = QImage(fullSize, fullSize, QImage::Format_ARGB32_Premultiplied);
  31. result.fill(Qt::transparent);
  32. {
  33. Painter p(&result);
  34. PainterHighQualityEnabler hq(p);
  35. p.setPen(border);
  36. p.setBrush(inner);
  37. p.drawEllipse(QRectF(0.5, 0.5, fullSize - 1., fullSize - 1.));
  38. }
  39. result.setDevicePixelRatio(style::DevicePixelRatio());
  40. return result;
  41. }
  42. void PreviewWindowTitle(Painter &p, const style::palette &palette, QRect body, int titleHeight, int outerWidth) {
  43. auto titleRect = QRect(body.x(), body.y() - titleHeight, body.width(), titleHeight);
  44. p.fillRect(titleRect, QColor(0, 0, 0));
  45. p.fillRect(titleRect, st::titleBgActive[palette]);
  46. p.fillRect(titleRect.x(), titleRect.y() + titleRect.height() - st::lineWidth, titleRect.width(), st::lineWidth, st::titleShadow[palette]);
  47. QFont font;
  48. const auto families = QStringList{
  49. u".AppleSystemUIFont"_q,
  50. u".SF NS Text"_q,
  51. u"Helvetica Neue"_q,
  52. };
  53. for (auto family : families) {
  54. font.setFamily(family);
  55. if (QFontInfo(font).family() == font.family()) {
  56. break;
  57. }
  58. }
  59. if (QFontInfo(font).family() != font.family()) {
  60. font = st::semiboldFont;
  61. font.setPixelSize(13);
  62. } else if (font.family() == u".AppleSystemUIFont"_q) {
  63. font.setBold(true);
  64. font.setPixelSize(13);
  65. } else {
  66. font.setPixelSize((titleHeight * 15) / 24);
  67. }
  68. p.setPen(st::titleFgActive[palette]);
  69. p.setFont(font);
  70. p.drawText(titleRect, u"Telegram"_q, style::al_center);
  71. auto isGraphite = ([NSColor currentControlTint] == NSGraphiteControlTint);
  72. auto buttonSkip = 8;
  73. auto graphiteInner = QColor(141, 141, 146);
  74. auto graphiteBorder = QColor(104, 104, 109);
  75. auto closeInner = isGraphite ? graphiteInner : QColor(252, 96, 92);
  76. auto closeBorder = isGraphite ? graphiteBorder : QColor(222, 64, 59);
  77. auto minimizeInner = isGraphite ? graphiteInner : QColor(254, 192, 65);
  78. auto minimizeBorder = isGraphite ? graphiteBorder : QColor(221, 152, 25);
  79. auto maximizeInner = isGraphite ? graphiteInner : QColor(52, 200, 74);
  80. auto maximizeBorder = isGraphite ? graphiteBorder : QColor(21, 164, 41);
  81. auto close = PreviewWindowSystemButton(closeInner, closeBorder);
  82. auto left = buttonSkip;
  83. p.drawImage(
  84. titleRect.x() + left,
  85. titleRect.y()
  86. + (titleRect.height()
  87. - (close.height() / style::DevicePixelRatio())) / 2,
  88. close);
  89. left += (close.width() / style::DevicePixelRatio()) + buttonSkip;
  90. auto minimize = PreviewWindowSystemButton(minimizeInner, minimizeBorder);
  91. p.drawImage(
  92. titleRect.x() + left,
  93. titleRect.y()
  94. + (titleRect.height()
  95. - (minimize.height() / style::DevicePixelRatio())) / 2,
  96. minimize);
  97. left += (minimize.width() / style::DevicePixelRatio()) + buttonSkip;
  98. auto maximize = PreviewWindowSystemButton(maximizeInner, maximizeBorder);
  99. p.drawImage(
  100. titleRect.x() + left,
  101. titleRect.y()
  102. + (titleRect.height()
  103. - (maximize.height() / style::DevicePixelRatio())) / 2,
  104. maximize);
  105. }
  106. void PreviewWindowFramePaint(QImage &preview, const style::palette &palette, QRect body, int outerWidth) {
  107. auto retina = style::DevicePixelRatio();
  108. auto titleHeight = PreviewTitleHeight();
  109. {
  110. Painter p(&preview);
  111. PreviewWindowTitle(p, palette, body, titleHeight, outerWidth);
  112. }
  113. auto inner = QRect(body.x(), body.y() - titleHeight, body.width(), body.height() + titleHeight);
  114. auto retinaRadius = st::macWindowRoundRadius * retina;
  115. auto roundMask = QImage(2 * retinaRadius, 2 * retinaRadius, QImage::Format_ARGB32_Premultiplied);
  116. roundMask.setDevicePixelRatio(style::DevicePixelRatio());
  117. roundMask.fill(Qt::transparent);
  118. {
  119. Painter p(&roundMask);
  120. PainterHighQualityEnabler hq(p);
  121. p.setPen(Qt::NoPen);
  122. p.setBrush(QColor(255, 255, 255));
  123. p.drawRoundedRect(0, 0, 2 * st::macWindowRoundRadius, 2 * st::macWindowRoundRadius, st::macWindowRoundRadius, st::macWindowRoundRadius);
  124. }
  125. QImage corners[4];
  126. corners[0] = roundMask.copy(0, 0, retinaRadius, retinaRadius);
  127. corners[1] = roundMask.copy(retinaRadius, 0, retinaRadius, retinaRadius);
  128. corners[2] = roundMask.copy(0, retinaRadius, retinaRadius, retinaRadius);
  129. corners[3] = roundMask.copy(retinaRadius, retinaRadius, retinaRadius, retinaRadius);
  130. auto rounded = Images::Round(
  131. preview.copy(
  132. inner.x() * retina,
  133. inner.y() * retina,
  134. inner.width() * retina,
  135. inner.height() * retina),
  136. corners);
  137. rounded.setDevicePixelRatio(style::DevicePixelRatio());
  138. preview.fill(st::themePreviewBg->c);
  139. auto topLeft = st::macWindowShadowTopLeft.instance(QColor(0, 0, 0), 100);
  140. auto topRight = topLeft.mirrored(true, false);
  141. auto bottomLeft = topLeft.mirrored(false, true);
  142. auto bottomRight = bottomLeft.mirrored(true, false);
  143. auto extend = QMargins(37, 28, 37, 28);
  144. auto left = topLeft.copy(0, topLeft.height() - retina, extend.left() * retina, retina);
  145. auto top = topLeft.copy(topLeft.width() - retina, 0, retina, extend.top() * retina);
  146. auto right = topRight.copy(topRight.width() - (extend.right() * retina), topRight.height() - retina, extend.right() * retina, retina);
  147. auto bottom = bottomRight.copy(0, bottomRight.height() - (extend.bottom() * retina), retina, extend.bottom() * retina);
  148. {
  149. Painter p(&preview);
  150. p.drawImage(inner.x() - extend.left(), inner.y() - extend.top(), topLeft);
  151. p.drawImage(inner.x() + inner.width() + extend.right() - (topRight.width() / retina), inner.y() - extend.top(), topRight);
  152. p.drawImage(inner.x() - extend.left(), inner.y() + inner.height() + extend.bottom() - (bottomLeft.height() / retina), bottomLeft);
  153. p.drawImage(inner.x() + inner.width() + extend.right() - (bottomRight.width() / retina), inner.y() + inner.height() + extend.bottom() - (bottomRight.height() / retina), bottomRight);
  154. p.drawImage(QRect(inner.x() - extend.left(), inner.y() - extend.top() + (topLeft.height() / retina), extend.left(), extend.top() + inner.height() + extend.bottom() - (topLeft.height() / retina) - (bottomLeft.height() / retina)), left);
  155. p.drawImage(QRect(inner.x() - extend.left() + (topLeft.width() / retina), inner.y() - extend.top(), extend.left() + inner.width() + extend.right() - (topLeft.width() / retina) - (topRight.width() / retina), extend.top()), top);
  156. p.drawImage(QRect(inner.x() + inner.width(), inner.y() - extend.top() + (topRight.height() / retina), extend.right(), extend.top() + inner.height() + extend.bottom() - (topRight.height() / retina) - (bottomRight.height() / retina)), right);
  157. p.drawImage(QRect(inner.x() - extend.left() + (bottomLeft.width() / retina), inner.y() + inner.height(), extend.left() + inner.width() + extend.right() - (bottomLeft.width() / retina) - (bottomRight.width() / retina), extend.bottom()), bottom);
  158. p.drawImage(inner.x(), inner.y(), rounded);
  159. }
  160. }
  161. } // namespace Platform