From df9bd91d9a2428b5092b2653f56225724a380dfe Mon Sep 17 00:00:00 2001 From: John Preston Date: Tue, 28 Feb 2023 16:26:48 +0400 Subject: [PATCH] Implement semi-native macOS title buttons for the viewer. --- .../mediaview/title_button_close_mac.png | Bin 0 -> 260 bytes .../mediaview/title_button_close_mac@2x.png | Bin 0 -> 368 bytes .../mediaview/title_button_close_mac@3x.png | Bin 0 -> 490 bytes .../icons/mediaview/title_button_mac.png | Bin 0 -> 292 bytes .../icons/mediaview/title_button_mac@2x.png | Bin 0 -> 485 bytes .../icons/mediaview/title_button_mac@3x.png | Bin 0 -> 703 bytes .../mediaview/title_button_maximize_mac.png | Bin 0 -> 244 bytes .../title_button_maximize_mac@2x.png | Bin 0 -> 324 bytes .../title_button_maximize_mac@3x.png | Bin 0 -> 448 bytes .../mediaview/title_button_minimize_mac.png | Bin 0 -> 210 bytes .../title_button_minimize_mac@2x.png | Bin 0 -> 265 bytes .../title_button_minimize_mac@3x.png | Bin 0 -> 319 bytes .../mediaview/title_button_shadow_mac.png | Bin 0 -> 371 bytes .../mediaview/title_button_shadow_mac@2x.png | Bin 0 -> 636 bytes .../mediaview/title_button_shadow_mac@3x.png | Bin 0 -> 915 bytes .../mediaview/title_button_shrink_mac.png | Bin 0 -> 259 bytes .../mediaview/title_button_shrink_mac@2x.png | Bin 0 -> 319 bytes .../mediaview/title_button_shrink_mac@3x.png | Bin 0 -> 434 bytes .../SourceFiles/media/view/media_view.style | 13 + .../media/view/media_view_overlay_widget.cpp | 1 + .../platform/mac/overlay_widget_mac.h | 20 +- .../platform/mac/overlay_widget_mac.mm | 328 +++++++++--------- Telegram/build/prepare/prepare.py | 2 +- Telegram/lib_ui | 2 +- 24 files changed, 208 insertions(+), 158 deletions(-) create mode 100644 Telegram/Resources/icons/mediaview/title_button_close_mac.png create mode 100644 Telegram/Resources/icons/mediaview/title_button_close_mac@2x.png create mode 100644 Telegram/Resources/icons/mediaview/title_button_close_mac@3x.png create mode 100644 Telegram/Resources/icons/mediaview/title_button_mac.png create mode 100644 Telegram/Resources/icons/mediaview/title_button_mac@2x.png create mode 100644 Telegram/Resources/icons/mediaview/title_button_mac@3x.png create mode 100644 Telegram/Resources/icons/mediaview/title_button_maximize_mac.png create mode 100644 Telegram/Resources/icons/mediaview/title_button_maximize_mac@2x.png create mode 100644 Telegram/Resources/icons/mediaview/title_button_maximize_mac@3x.png create mode 100644 Telegram/Resources/icons/mediaview/title_button_minimize_mac.png create mode 100644 Telegram/Resources/icons/mediaview/title_button_minimize_mac@2x.png create mode 100644 Telegram/Resources/icons/mediaview/title_button_minimize_mac@3x.png create mode 100644 Telegram/Resources/icons/mediaview/title_button_shadow_mac.png create mode 100644 Telegram/Resources/icons/mediaview/title_button_shadow_mac@2x.png create mode 100644 Telegram/Resources/icons/mediaview/title_button_shadow_mac@3x.png create mode 100644 Telegram/Resources/icons/mediaview/title_button_shrink_mac.png create mode 100644 Telegram/Resources/icons/mediaview/title_button_shrink_mac@2x.png create mode 100644 Telegram/Resources/icons/mediaview/title_button_shrink_mac@3x.png diff --git a/Telegram/Resources/icons/mediaview/title_button_close_mac.png b/Telegram/Resources/icons/mediaview/title_button_close_mac.png new file mode 100644 index 0000000000000000000000000000000000000000..8df83a2d768f08acb4ae2b72ba4a1be5d6d8bf21 GIT binary patch literal 260 zcmeAS@N?(olHy`uVBq!ia0vp^5+KaM1SIoCSFHz9jKx9jP7LeL$-D$|Tv8)E(|mmy zw18|52FCVG1{RPKAeI7R1_tH@j10^`nh_+nfC(-uv49!D1}S`GTDlfU<$1a|hFA!` z4RGW-V8EfB{2+brSLv@w_b=;<{9a_5vthBeb#8*6Q&NworU37sC5*<}OJfpUmwbQ6 za$k1c)@j9RN*OaGI-7E&|i942U2f4u0)z4*}Q$iB}njuC| literal 0 HcmV?d00001 diff --git a/Telegram/Resources/icons/mediaview/title_button_close_mac@2x.png b/Telegram/Resources/icons/mediaview/title_button_close_mac@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..e35cd25b908c65d2202ea51220e4b7d94447da3b GIT binary patch literal 368 zcmeAS@N?(olHy`uVBq!ia0vp^1|ZDA1SD@HumX>(vcwGGXoY17rYzB0_HPZ@`7EgGPMlpk2gi)*=}gy;Ix(9#AP^s0(Yd|f zgS>hI+ueodR!j}L^!MFY%ja(+qq6nYLM}|HGuY|;f;DUHCWCp0mSkSw^sm}eeOHHH zO{Dn+U!s_S&n&f;1h)Sxb{ZYLtax_5-O_;5__pSGJ_mMgSMxCLHS~LwfBxvz#=}xlK3NA;!r9q!*q^dUEnq~T9|sP|I&6J3 TC&;&+u6{1-oD!M<2P1c# literal 0 HcmV?d00001 diff --git a/Telegram/Resources/icons/mediaview/title_button_close_mac@3x.png b/Telegram/Resources/icons/mediaview/title_button_close_mac@3x.png new file mode 100644 index 0000000000000000000000000000000000000000..ede3dd8075aade988606074c13734626a3047a74 GIT binary patch literal 490 zcmeAS@N?(olHy`uVBq!ia0vp^9w5xY1SD_us|Wxo#^NA%Cx&(BWL^R}E~ycoX}-P; zT0k}j17mw80}DtA5K93u0|WB{Mh0de%?J`(zyz1|Sip>6gA`6MbbAj}7UJpR7?Q#I zcKSiyW&sqOKCpMOIzdH)lffnmx}isP(fmGfNy`U^8f7 zs~L?u+g3s)O2Y|%(SJ`rv=u`TK3iW*FO8y;DF%yYeI7* z87sUar=`Ykl+(H0=w1Z#13_(sZmgQfA24T<(4Um)OittDcH}XE^je z>-DO;D=H`6xH@N(>$VkZC*-S~E88E}y3BUly4NP6X=?R#YU_XeX5Cws8-GiDR$1pG zi>t9W{Z?L4>OIWASSh?d=j5+vftu?Ilg;M#E9DB#{yRHwmfFnguen~jNH^U)n|AYE zA;&e@6!y&_voA2;w&=Uw=@%9$?yDQ(dx1^3Av`?zw`=hFip(R1I6MyylK*KBSf5@N UT-aIbk^~B8Pgg&ebxsLQ03w5{2LJ#7 literal 0 HcmV?d00001 diff --git a/Telegram/Resources/icons/mediaview/title_button_mac.png b/Telegram/Resources/icons/mediaview/title_button_mac.png new file mode 100644 index 0000000000000000000000000000000000000000..258c403483913066d8b7067d87babff6a96db137 GIT binary patch literal 292 zcmeAS@N?(olHy`uVBq!ia0vp^5+KaM1SIoCSFHz9jKx9jP7LeL$-D$|Tv8)E(|mmy zw18|52FCVG1{RPKAeI7R1_tH@j10^`nh_+nfC(-uv49!D1}S`GTDlfU^?ABDhFA!` zoqUnEL4n8RsIJ6>jS{W(VhKX*7sNldZ#kId;luN{>Gf9&zSwDz_Fe}p#hp%A=BIB= z;QsNZ>)!7vm-M(MObhK!4xOsyefm|mHitGZ!@-m;i&>T%8xw?-VhnFH2rRjvwXnQH zDa7k#_DU94jbk^&cd5oaK0Hr;uc3U3Y1?|n{T}vzopr0FNJ45&!@I literal 0 HcmV?d00001 diff --git a/Telegram/Resources/icons/mediaview/title_button_mac@2x.png b/Telegram/Resources/icons/mediaview/title_button_mac@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..411f40563d82d0edd407288e484759870983db77 GIT binary patch literal 485 zcmeAS@N?(olHy`uVBq!ia0vp^1|ZDA1SD@HxQw2wL6Bkh%jduA(3_qGCO+0g$L-N?O3BtPl9B*#kOx$xrdg&7( z_9Kji4l)Alb+;R*Z~vp>*|q4zCLQ0)7JUaVf3Lm0&G+(^(z~T|%{Lb-TnZ00^}T$& zD3Oa{?WLJ_O%=|6PL$B`3On4u_~z96HvQ8@^PY#^y35`m_-I^!P2 z!m=|c`m{hrt?fdO?K6J}wtV(3>^UO7@3XJrCIP-lkA1xMN(y|Nt_QuEF&r?~*lBoYpIMFTEX_G+T;}asM?ATP6+1<8%IzjhGA5fX!+0Q#Yg}emL zefZqu0i>i;rVHl< yJhtZLT*mMr`_#Wj`4hf*)*Xce#F0h=nIBBO7Rh#rn8bg=d#Wzp$Pz!6R}JH literal 0 HcmV?d00001 diff --git a/Telegram/Resources/icons/mediaview/title_button_mac@3x.png b/Telegram/Resources/icons/mediaview/title_button_mac@3x.png new file mode 100644 index 0000000000000000000000000000000000000000..e9add22c2e432aa58f94a4cc35fb85374dd162d4 GIT binary patch literal 703 zcmeAS@N?(olHy`uVBq!ia0vp^9w5xY1SD_us|Wxo#^NA%Cx&(BWL^R}E~ycoX}-P; zT0k}j17mw80}DtA5K93u0|WB{Mh0de%?J`(zyz1|Sip>6gA`6MbbHUhz@+Kv;uw;_ z`Zm(A?~sAO6TK-4j@3dnEwi|0{n6=fWE0?h#BIZ{WU-InE|GHOj5W$?-zFqHnJuDG zR904|c5tKl+&(@_1@HTM4!FiWzKIhVHiWr>ws|NeFCMz!(% zk3a5+TR;7D>b&PUzXW!e_-?29`lG36o}xAvHZ?%c??Cf0B#_XgJ{CYR7ZUz6v5RSXsU{BzIkw_&lFMLZ%3kBlZA z+K~4AM@^uKpk|JV)X!-rj$U?IVvw_bhf^(3Z0ALtu0_{h{|xgy60bMCZofanN$a-C z9tC9up!zp8cEX`T0<$_q+Rm{CsxmI@^hkVhOaLOZ?PgAg7AME7NS3a4m)%R8>mTj*MeMngQ~Hu^JLQCT8NP`A^E0H{ wYVL+zu{vUmVLoY{R@2d<5gex<-pl@A-O5<#bVlXt4N&6oboFyt=akR{0PdI*tpET3 literal 0 HcmV?d00001 diff --git a/Telegram/Resources/icons/mediaview/title_button_maximize_mac.png b/Telegram/Resources/icons/mediaview/title_button_maximize_mac.png new file mode 100644 index 0000000000000000000000000000000000000000..76b05acab737adcf904d483c6a1ab15093b555d6 GIT binary patch literal 244 zcmeAS@N?(olHy`uVBq!ia0vp^5+KaM1SIoCSFHz9jKx9jP7LeL$-D$|Tv8)E(|mmy zw18|52FCVG1{RPKAeI7R1_tH@j10^`nh_+nfC(-uv49!D1}S`GTDlfU#d*3ohFA!` zy>O6|!H~n{VuI?o`x74=wA%BAPtt=?I3nVLb6%xk{o0wDA0{*1{rl$RnblKQhD_bf zY-Bu)kj%NyYx1TXrC6gA`6MbbAj}rse747?Q#I zcDf;7vjLCmYCn!NF|~K~nh^r(4oQpS*S4&hVzFfrZ&M_D~AJ<6lCH$V3JO8;fg&(0HUxEZqR*NO9SWxE>E zH_Q#$rD~i1tw%J+eyaM0?JH^;Rtm3>KeF#oS9fLX)vpS_-MqyY+*`}HZ>IR-PaBhF zdvHmG^c~F6TA$#lH9eu~{uS?#UA9TmKOX=1_&?cEGc;7xRgk4Q`0s2sK|e!$zN*iD Zz*cQ=m8y4AI(2s<(`vIsc9h;v*u9#)o8 TZ&uyD3UY?0tDnm{r-UW|y(L7? literal 0 HcmV?d00001 diff --git a/Telegram/Resources/icons/mediaview/title_button_minimize_mac@3x.png b/Telegram/Resources/icons/mediaview/title_button_minimize_mac@3x.png new file mode 100644 index 0000000000000000000000000000000000000000..56ad3aceb35b9937d44f00b4c036663b223e12fb GIT binary patch literal 319 zcmeAS@N?(olHy`uVBq!ia0vp^9w5xY1SD_us|Wxo#^NA%Cx&(BWL^R}E~ycoX}-P; zT0k}j17mw80}DtA5K93u0|WB{Mh0de%?J`(zyz1|Sip>6gA`6MbbAk^R(iTPhGek5 zy<*69L_vV{LW;k_wRvYRHCGyOXRqJz`p`8-XO75xTZ}~Nzb3ba!V_$`MS(;waH+k&+wy!(> t`0cX&O#M||cKrR5uo?-qt?@Zm4TI~i?-)QoaBH literal 0 HcmV?d00001 diff --git a/Telegram/Resources/icons/mediaview/title_button_shadow_mac.png b/Telegram/Resources/icons/mediaview/title_button_shadow_mac.png new file mode 100644 index 0000000000000000000000000000000000000000..10b33a61a7557cc95483c99337ba1f7d151ab8f6 GIT binary patch literal 371 zcmeAS@N?(olHy`uVBq!ia0vp^5+KaM1SIoCSFHz9jKx9jP7LeL$-D$|Tv8)E(|mmy zw18|52FCVG1{RPKAeI7R1_tH@j10^`nh_+nfC(-uv49!D1}S`GTDlfU-Su>F46zV= zJ9#5li-Ca4UhWyE6e1#`p8o&uvB5{ZskNzqf8E5Jdk-C2y`@M!UwwAU_Eq!V=bL}{ zwKbSy;rrj)a+7-uZf`sLImXMf@38O3-XO2T23JaTEr0Lxzr01K`$fw^uN_b3tURHo zSQfi|oi^*KSJ6oUS%QI147+=!3iZFaB(X54Es`qS?X+Xz(JL>0yXAd~+%iLI?o03g zSt;`mZ{0jY>SAf$vJSCe<*MoHCYx|F9&ia!R%^H?>fyv-t>O2(sIF>zrqu1yD@J{b pt(E?*31rfn-WIm1?vQo<17^QRQA%aHnE@aVd%F6$taD0e0sy95g2Mm+ literal 0 HcmV?d00001 diff --git a/Telegram/Resources/icons/mediaview/title_button_shadow_mac@2x.png b/Telegram/Resources/icons/mediaview/title_button_shadow_mac@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..5b62a0987c66fb2773614c41dfb713b90249ab5c GIT binary patch literal 636 zcmeAS@N?(olHy`uVBq!ia0vp^1|ZDA1SD@HY#Yx16h2?jHL+!hC}zy7*x_X``j{@;J=?B@3$fBdy7ciA1546C_%V%>H7 z^Ox+ooA>+gzXA&h!>#K~6cnbNep+C$=ISq#IKAn2^Vsh!*G_wRL}vcCj}?33*1tUz zlJ?Q$`De=rn^Rrd->!4BoXy&rwf(l?!WnZlH{a~(eVS6l7$}-`xj`*J%=O^6bbH(R z=OxNB%h%4Rz5H^=1@F738eVpU^lYs+6-Ym|zdO5_MOn#1lJVfuMvI3*MSns$vb;xjoTg(5r?)f z(_@%A`X1E_dpj~d+0*dn0!V}AugR54Kn;t&e_rzOxQ8R7i~6i9aW_*uPF@RRnAqTV z#qaU=swE}@wLH4>?Xz`+1pT|$HhMV3zj?VfN#n-Mz7D~FT`{@hMQi%~rrcXU=cPQz z`(@hY{sJY8f~S5r3!jdid+Wp|i44ExlZzSS792RDw&3Gr@sydfcjcK$r{^A8qt^eR u-A?56QsW<&mVdb~QaML^0vLYi7Oh}bjo#(MS=jCaig{00KbLh*2~7b0y#(|C literal 0 HcmV?d00001 diff --git a/Telegram/Resources/icons/mediaview/title_button_shadow_mac@3x.png b/Telegram/Resources/icons/mediaview/title_button_shadow_mac@3x.png new file mode 100644 index 0000000000000000000000000000000000000000..a358b377e7ace8c43f90736a851aa343196ba3e4 GIT binary patch literal 915 zcmeAS@N?(olHy`uVBq!ia0vp^9w5xY1SD_us|Wxo#^NA%Cx&(BWL^R}E~ycoX}-P; zT0k}j17mw80}DtA5K93u0|WB{Mh0de%?J`(zyz1|Sip>6gA`6MbbHUh!1UMC#W5s< z_3bRrZY4(nx7(>lM8j=f_`3Z6|6Y)Vze=Fc`Hs|9c`=bzvt+jvtINhM%Qy9$(Z4sn zJ9UY?{5K=^GmOOtWDJm~2kzDrs^ZI9ofd|ze){=mjNbRx|D0Zb{%1A+{PD+yd*kH! z+Rar30n+JKMm)A<-=56<9;@6kXHh+`#Nnr(YgJDPDL!%WU6f!b@!IQq&O#5p ztfo0hhTR7%_(GPi$Xg*G+WfI(^*R5$0g778kEJ8GPr2$5=H`TY zxA64D_c9iXma0yj*7$d7rNl??rKt%v@?AN65;{}OHZ(l@KXF}(^0Uv(CxzX$audoA zGlxxF!mKfMTCYT?U#8Q-M@ugm8FbBFC^Yq(GSG;?^;7*gH4kk6*x}`U)W{%Y>ABk3 zE50mq3gK~^8#`-S{T?9e*pvn5-pyZK&40r4x#HaJgBgckHm*~7#wYBq)DrXO+FvK; zV?ocp9Ed%vE~I$3Z0Q>9py>4>T9@Vv1v!PNP43Jq(>N%wxbNgk#;;MCyZS!zT*)xm z6{FYpkw5X*mKCcWYblZD&`A=2f?7p(M8 ztb6gW>dZ0L(r^FYz8CPcS-0};ruBcG@$1Y!d#t#Gnt}}CH8bDmy|NiW^qZmoEly17n=IAt2uS8 zsGz9B-v85rC(d+iEGo}3Vm>%E=!WFJluJ!}Hso^}@^sIE?LH6W08dvxmvv4FO#rv3Mq2;? literal 0 HcmV?d00001 diff --git a/Telegram/Resources/icons/mediaview/title_button_shrink_mac@2x.png b/Telegram/Resources/icons/mediaview/title_button_shrink_mac@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..249011ff383313d8d3f544a81af249b3b9c223cb GIT binary patch literal 319 zcmeAS@N?(olHy`uVBq!ia0vp^1|ZDA1SD@HSNfgV8#*I@~ZK@9_Nwi@?UpJh%8`W)o@_s3V6WJJtatJ zWpsA&IUR*eyZsZHO0r!(HHY=eZ^=BfU`1h5*4kNieCMSuRW6p5Gu>Ox|H9z4gtF7p z?Q>@aF1G%)zdgU=dmu~Z+x^y0f4-GIv1Vc^>rYc{jn-#usTVnx$iBN1ER=J&>|PF^ jo+ik;1}2dO2M#mEcZ6gA`6MbbAj}CgbVi7?Q#I z_PQZolY@wBV6y9iWeb!3&u(hlz$9c~d@cyb!ItZm%?ngUz>pPQCtu3FV)pEYaQ52nYlTaRuJ z`TQhw^C#2tH|}rNy?&&9y)<^3>b_@vyFb3Yv}R5G0_%CdzxX)LD4e>fIPqTSPJ`d8 z4sQ@z^)0bAL^bhgNbcdTRlnM%hAlPl^_ev_cK#u*6S`*`f5}g{{j`=vz=44ggD?=R YVD8bl%Ec+r0SapdPgg&ebxsLQ0QTUSFaQ7m literal 0 HcmV?d00001 diff --git a/Telegram/SourceFiles/media/view/media_view.style b/Telegram/SourceFiles/media/view/media_view.style index 5130bc448..651d0c8da 100644 --- a/Telegram/SourceFiles/media/view/media_view.style +++ b/Telegram/SourceFiles/media/view/media_view.style @@ -321,6 +321,19 @@ mediaviewTitle: WindowTitle(defaultWindowTitle) { closeIconActive: mediaviewTitleClose; closeIconActiveOver: mediaviewTitleClose; } + +mediaviewTitleButtonMac: icon{ + { "mediaview/title_button_shadow_mac", windowShadowFg }, + { "mediaview/title_button_mac", mediaviewControlFg }, +}; +mediaviewTitleMinimizeMac: icon {{ "mediaview/title_button_minimize_mac", mediaviewBg }}; +mediaviewTitleMaximizeMac: icon {{ "mediaview/title_button_maximize_mac", mediaviewBg }}; +mediaviewTitleRestoreMac: icon {{ "mediaview/title_button_shrink_mac", mediaviewBg }}; +mediaviewTitleCloseMac: icon {{ "mediaview/title_button_close_mac", mediaviewBg }}; +mediaviewTitleCloseMacPadding: margins(8px, 4px, 0px, 4px); +mediaviewTitleMinimizeMacPadding: margins(0px, 4px, 0px, 4px); +mediaviewTitleMaximizeMacPadding: margins(0px, 4px, 8px, 4px); + mediaviewShadowTop: icon{{ "mediaview/shadow_top", windowShadowFg }}; mediaviewShadowBottom: icon{{ "mediaview/shadow_bottom", windowShadowFg }}; diff --git a/Telegram/SourceFiles/media/view/media_view_overlay_widget.cpp b/Telegram/SourceFiles/media/view/media_view_overlay_widget.cpp index b5d3498d4..b36d7a005 100644 --- a/Telegram/SourceFiles/media/view/media_view_overlay_widget.cpp +++ b/Telegram/SourceFiles/media/view/media_view_overlay_widget.cpp @@ -3080,6 +3080,7 @@ void OverlayWidget::displayFinished() { //Ui::Platform::UpdateOverlayed(_window); showAndActivate(); } else if (isMinimized()) { + _helper->beforeShow(_fullscreen); showAndActivate(); } else { activate(); diff --git a/Telegram/SourceFiles/platform/mac/overlay_widget_mac.h b/Telegram/SourceFiles/platform/mac/overlay_widget_mac.h index ef9c6690a..2fa33447b 100644 --- a/Telegram/SourceFiles/platform/mac/overlay_widget_mac.h +++ b/Telegram/SourceFiles/platform/mac/overlay_widget_mac.h @@ -9,6 +9,17 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "platform/platform_overlay_widget.h" +template +class object_ptr; + +namespace Ui { +class AbstractButton; +} // namespace Ui + +namespace Ui::Platform { +enum class TitleControl; +} // namespace Ui::Platform + namespace Platform { class MacOverlayWidgetHelper final : public OverlayWidgetHelper { @@ -22,15 +33,22 @@ public: void afterShow(bool fullscreen) override; void notifyFileDialogShown(bool shown) override; void minimize(not_null window) override; + void clearState() override; + void setControlsOpacity(float64 opacity) override; private: + using Control = Ui::Platform::TitleControl; struct Data; - void activate(int button); // NSWindowButton + void activate(Control control); void resolveNative(); void updateStyles(bool fullscreen); void refreshButtons(bool fullscreen); + object_ptr create( + not_null parent, + Control control); + std::unique_ptr _data; }; diff --git a/Telegram/SourceFiles/platform/mac/overlay_widget_mac.mm b/Telegram/SourceFiles/platform/mac/overlay_widget_mac.mm index 877b8ea8a..3429763d6 100644 --- a/Telegram/SourceFiles/platform/mac/overlay_widget_mac.mm +++ b/Telegram/SourceFiles/platform/mac/overlay_widget_mac.mm @@ -7,85 +7,34 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL */ #include "platform/mac/overlay_widget_mac.h" +#include "base/object_ptr.h" +#include "ui/platform/ui_platform_window_title.h" +#include "ui/widgets/buttons.h" #include "ui/widgets/rp_window.h" +#include "styles/style_media_view.h" #include #include -@interface ButtonHandler : NSObject { -} - -- (instancetype) initWithCallback:(Fn)callback; -- (void) close:(id) sender; -- (void) miniaturize:(id) sender; -- (void) zoom:(id) sender; - -@end // @interface ButtonHandler - -@implementation ButtonHandler { - Fn _callback; -} - -- (instancetype) initWithCallback:(Fn)callback { - _callback = std::move(callback); - return [super init]; -} - -- (void) close:(id) sender { - _callback(NSWindowCloseButton); -} - -- (void) miniaturize:(id) sender { - _callback(NSWindowMiniaturizeButton); -} - -- (void) zoom:(id) sender { - _callback(NSWindowZoomButton); -} - -@end // @implementation ButtonHandler - namespace Platform { namespace { -[[nodiscard]] base::flat_map ButtonGeometries() { - auto result = base::flat_map(); - auto normal = QWidget(); - normal.hide(); - normal.createWinId(); - const auto view = reinterpret_cast(normal.winId()); - const auto window = [view window]; - const auto process = [&](NSWindowButton type) { - if (const auto button = [window standardWindowButton:type]) { - result.emplace(int(type), [button frame]); - } - }; - process(NSWindowCloseButton); - process(NSWindowMiniaturizeButton); - process(NSWindowZoomButton); - - const auto full = [window frame]; - const auto inner = [window contentRectForFrameRect:full].size.height; - const auto height = std::max(full.size.height - inner, 0.); - - result[int(NSWindowToolbarButton)] = { CGPoint(), CGSize{ full.size.width, height }}; - return result; -} +using namespace Media::View; } // namespace struct MacOverlayWidgetHelper::Data { const not_null window; const Fn maximize; - const base::flat_map buttons; - ButtonHandler *handler = nil; + object_ptr buttonClose = { nullptr }; + object_ptr buttonMinimize = { nullptr }; + object_ptr buttonMaximize = { nullptr }; + rpl::event_stream<> activations; + rpl::variable masterOpacity = 1.; + rpl::variable maximized = false; + rpl::event_stream<> clearStateRequests; + bool anyOver = false; NSWindow * __weak native = nil; - NSButton * __weak closeNative = nil; - NSButton * __weak miniaturizeNative = nil; - NSButton * __weak zoomNative = nil; - NSButton * __weak close = nil; - NSButton * __weak miniaturize = nil; - NSButton * __weak zoom = nil; }; MacOverlayWidgetHelper::MacOverlayWidgetHelper( @@ -94,24 +43,20 @@ MacOverlayWidgetHelper::MacOverlayWidgetHelper( : _data(std::make_unique(Data{ .window = window, .maximize = std::move(maximize), - .buttons = ButtonGeometries(), - .handler = [[ButtonHandler alloc] initWithCallback:[=](NSWindowButton button) { - activate(int(button)); - }] })) { + _data->buttonClose = create(window, Control::Close); + _data->buttonMinimize = create(window, Control::Minimize); + _data->buttonMaximize = create(window, Control::Maximize); } -MacOverlayWidgetHelper::~MacOverlayWidgetHelper() { - [_data->handler release]; - _data->handler = nil; -} +MacOverlayWidgetHelper::~MacOverlayWidgetHelper() = default; -void MacOverlayWidgetHelper::activate(int button) { +void MacOverlayWidgetHelper::activate(Control control) { const auto fullscreen = (_data->window->windowHandle()->flags() & Qt::FramelessWindowHint); - switch (NSWindowButton(button)) { - case NSWindowCloseButton: _data->window->close(); return; - case NSWindowMiniaturizeButton: [_data->native miniaturize:_data->handler]; return; - case NSWindowZoomButton: _data->maximize(!fullscreen); return; + switch (control) { + case Control::Close: _data->window->close(); return; + case Control::Minimize: [_data->native miniaturize:_data->native]; return; + case Control::Maximize: _data->maximize(!fullscreen); return; } } @@ -119,6 +64,7 @@ void MacOverlayWidgetHelper::beforeShow(bool fullscreen) { _data->window->setAttribute(Qt::WA_MacAlwaysShowToolWindow, !fullscreen); _data->window->windowHandle()->setFlag(Qt::FramelessWindowHint, fullscreen); updateStyles(fullscreen); + clearState(); } void MacOverlayWidgetHelper::afterShow(bool fullscreen) { @@ -133,6 +79,8 @@ void MacOverlayWidgetHelper::resolveNative() { } void MacOverlayWidgetHelper::updateStyles(bool fullscreen) { + _data->maximized = fullscreen; + resolveNative(); if (!_data->native) { return; @@ -153,85 +101,23 @@ void MacOverlayWidgetHelper::refreshButtons(bool fullscreen) { Expects(_data->native != nullptr); const auto window = _data->native; - auto next = CGPoint(); - const auto added = [&](NSRect frame) { - const auto left = frame.origin.x + frame.size.width * 1.5; - const auto top = frame.origin.y; - if (next.x < left) { - next.x = left; + const auto process = [&](NSWindowButton type) { + if (const auto button = [window standardWindowButton:type]) { + [button setHidden:YES]; } - next.y = top; }; - for (const auto &[type, frame] : _data->buttons) { - added(frame); - } - const auto skip = fullscreen - ? _data->buttons.find(int(NSWindowToolbarButton))->second.size.height - : 0.; - const auto process = [&](auto native, auto custom, NSWindowButton type, auto action) { - auto retained = (NSButton*)nil; - while (const auto button = [window standardWindowButton:type]) { - if ([button superview] != [window contentView]) { - *native = button; - [button setHidden:YES]; - break; - } else if (button == *custom) { - retained = [button retain]; - } - [button removeFromSuperview]; - } - const auto i = _data->buttons.find(int(type)); - const auto frame = [&](NSButton *button) { - if (i != end(_data->buttons)) { - auto origin = i->second.origin; - origin.y += skip; - return NSRect{ origin, i->second.size }; - } - const auto size = [button frame].size; - auto result = NSRect{ next, size }; - added(result); - result.origin.y += skip; - return result; - }; - if (!retained) { - if (*custom) { - retained = *custom; - [retained retain]; - [retained removeFromSuperview]; - } else { - const auto style = NSWindowStyleMaskTitled - | NSWindowStyleMaskClosable - | NSWindowStyleMaskMiniaturizable - | NSWindowStyleMaskResizable; - *custom - = retained - = [NSWindow standardWindowButton:type forStyleMask:style]; - [retained setTarget:_data->handler]; - [retained setAction:action]; - [retained retain]; - } - } - [[window contentView] addSubview:retained]; - [retained setFrame:frame(retained)]; - [retained setEnabled:YES]; - [retained setHidden:NO]; - [retained release]; - }; - process( - &_data->closeNative, - &_data->close, - NSWindowCloseButton, - @selector(close:)); - process( - &_data->miniaturizeNative, - &_data->miniaturize, - NSWindowMiniaturizeButton, - @selector(miniaturize:)); - process( - &_data->zoomNative, - &_data->zoom, - NSWindowZoomButton, - @selector(zoom:)); + process(NSWindowCloseButton); + process(NSWindowMiniaturizeButton); + process(NSWindowZoomButton); + _data->buttonClose->moveToLeft(0, 0); + _data->buttonClose->raise(); + _data->buttonClose->show(); + _data->buttonMinimize->moveToLeft(_data->buttonClose->width(), 0); + _data->buttonMinimize->raise(); + _data->buttonMinimize->show(); + _data->buttonMaximize->moveToLeft(_data->buttonClose->width() + _data->buttonMinimize->width(), 0); + _data->buttonMaximize->raise(); + _data->buttonMaximize->show(); } void MacOverlayWidgetHelper::notifyFileDialogShown(bool shown) { @@ -250,10 +136,142 @@ void MacOverlayWidgetHelper::notifyFileDialogShown(bool shown) { void MacOverlayWidgetHelper::minimize(not_null window) { resolveNative(); if (_data->native) { - [_data->native miniaturize:_data->handler]; + [_data->native miniaturize:_data->native]; } } +void MacOverlayWidgetHelper::clearState() { + _data->clearStateRequests.fire({}); +} + +void MacOverlayWidgetHelper::setControlsOpacity(float64 opacity) { + _data->masterOpacity = opacity; +} + +object_ptr MacOverlayWidgetHelper::create( + not_null parent, + Control control) { + auto result = object_ptr(parent); + const auto raw = result.data(); + + raw->setClickedCallback([=] { activate(control); }); + + struct State { + Ui::Animations::Simple animation; + float64 progress = -1.; + QImage frame; + bool maximized = false; + bool anyOver = false; + bool over = false; + }; + const auto state = raw->lifetime().make_state(); + + rpl::merge( + _data->masterOpacity.changes() | rpl::to_empty, + _data->maximized.changes() | rpl::to_empty + ) | rpl::start_with_next([=] { + raw->update(); + }, raw->lifetime()); + + _data->clearStateRequests.events( + ) | rpl::start_with_next([=] { + raw->clearState(); + raw->update(); + state->over = raw->isOver(); + _data->anyOver = false; + state->animation.stop(); + }, raw->lifetime()); + + struct Info { + const style::icon *icon = nullptr; + style::margins padding; + }; + const auto info = [&]() -> Info { + switch (control) { + case Control::Minimize: + return { &st::mediaviewTitleMinimizeMac, st::mediaviewTitleMinimizeMacPadding }; + case Control::Maximize: + return { &st::mediaviewTitleMaximizeMac, st::mediaviewTitleMaximizeMacPadding }; + case Control::Close: + return { &st::mediaviewTitleCloseMac, st::mediaviewTitleCloseMacPadding }; + } + Unexpected("Value in DefaultOverlayWidgetHelper::Buttons::create."); + }(); + const auto icon = info.icon; + + raw->resize(QRect(QPoint(), icon->size()).marginsAdded(info.padding).size()); + state->frame = QImage( + icon->size() * style::DevicePixelRatio(), + QImage::Format_ARGB32_Premultiplied); + state->frame.setDevicePixelRatio(style::DevicePixelRatio()); + + const auto updateOver = [=] { + const auto over = raw->isOver(); + if (state->over == over) { + return; + } + state->over = over; + const auto anyOver = over + || _data->buttonClose->isOver() + || _data->buttonMinimize->isOver() + || _data->buttonMaximize->isOver(); + if (_data->anyOver != anyOver) { + _data->anyOver = anyOver; + _data->buttonClose->update(); + _data->buttonMinimize->update(); + _data->buttonMaximize->update(); + } + state->animation.start( + [=] { raw->update(); }, + state->over ? 0. : 1., + state->over ? 1. : 0., + st::mediaviewFadeDuration); + }; + + const auto prepareFrame = [=] { + const auto progress = state->animation.value(state->over ? 1. : 0.); + const auto maximized = _data->maximized.current(); + const auto anyOver = _data->anyOver; + if (state->progress == progress + && state->maximized == maximized + && state->anyOver == anyOver) { + return; + } + state->progress = progress; + state->maximized = maximized; + state->anyOver = anyOver; + auto current = icon; + if (control == Control::Maximize) { + current = maximized ? &st::mediaviewTitleRestoreMac : icon; + } + state->frame.fill(Qt::transparent); + + auto q = QPainter(&state->frame); + const auto normal = maximized + ? kMaximizedIconOpacity + : kNormalIconOpacity; + q.setOpacity(progress + (1 - progress) * normal); + st::mediaviewTitleButtonMac.paint(q, 0, 0, raw->width()); + if (anyOver) { + q.setOpacity(1.); + current->paint(q, 0, 0, raw->width()); + } + q.end(); + }; + + raw->paintRequest( + ) | rpl::start_with_next([=, padding = info.padding] { + updateOver(); + prepareFrame(); + + auto p = QPainter(raw); + p.setOpacity(_data->masterOpacity.current()); + p.drawImage(padding.left(), padding.top(), state->frame); + }, raw->lifetime()); + + return result; +} + std::unique_ptr CreateOverlayWidgetHelper( not_null window, Fn maximize) { diff --git a/Telegram/build/prepare/prepare.py b/Telegram/build/prepare/prepare.py index 7c293d3f3..de2fd25df 100644 --- a/Telegram/build/prepare/prepare.py +++ b/Telegram/build/prepare/prepare.py @@ -404,7 +404,7 @@ if customRunCommand: stage('patches', """ git clone https://github.com/desktop-app/patches.git cd patches - git checkout e8574ccccc + git checkout 53214c8a8a """) stage('msys64', """ diff --git a/Telegram/lib_ui b/Telegram/lib_ui index 85b73e98e..0b87868b1 160000 --- a/Telegram/lib_ui +++ b/Telegram/lib_ui @@ -1 +1 @@ -Subproject commit 85b73e98eccec7e77d7910f92bf747c7db3f1c4c +Subproject commit 0b87868b1d708020155571d4e0c90095e58d6572