1414#include < functional>
1515#include < string>
1616#include < utility>
17+ #include " ../src/glass_control_appearance.h"
1718
1819namespace GlassControlIsland {
1920
@@ -98,7 +99,7 @@ class Controller {
9899 static_cast <LONG >(std::lround (centerY + radius))};
99100 }
100101 };
101- Controller () = default ;
102+ Controller () {appearanceFade_. Reset ( RGB ( 0 , 0 , 0 ));}
102103 Controller (const Controller&) = delete ;
103104 Controller& operator =(const Controller&) = delete ;
104105 ~Controller () { Destroy (); }
@@ -185,7 +186,8 @@ class Controller {
185186
186187 void Update (const RECT & noteRect, UINT dpi, bool visible, bool topmost,
187188 bool passThrough, bool menuOpen, HWND noteWindow = nullptr , int cornerRadiusPx = 0 ,
188- bool folded = false , float foldProgress = 1 .0f , bool noteTransition = false ) {
189+ bool folded = false , float foldProgress = 1 .0f , bool noteTransition = false ,
190+ COLORREF backingColour=0 ,int backingAlpha=0 ) {
189191 if (!window_)
190192 return ;
191193 const UINT newDpi = dpi ? dpi : 96 ;
@@ -205,7 +207,11 @@ class Controller {
205207 menuOpen_ = effectiveMenuOpen;
206208 // Retain the API for the host, but note/body hover and note capture are
207209 // deliberately no longer expansion sources, including click-through.
208- (void )noteWindow;
210+ DWORD affinity=WDA_NONE ;
211+ if (noteWindow)GetWindowDisplayAffinity (noteWindow,&affinity);
212+ appearanceRequest_.note =noteRect;appearanceRequest_.tint =backingColour;
213+ appearanceRequest_.radius =cornerRadiusPx;
214+ appearanceRequest_.alpha =!folded && affinity==WDA_EXCLUDEFROMCAPTURE ?std::clamp (backingAlpha,0 ,255 ):0 ;
209215 noteRect_ = noteRect;
210216 cornerRadiusPx_ = std::max (0 , cornerRadiusPx);
211217 const bool previousBelow = below_;
@@ -238,6 +244,7 @@ class Controller {
238244 (flags & ~(SWP_SHOWWINDOW | SWP_HIDEWINDOW )));
239245 }
240246 if (!visible) {
247+ appearanceRequest_.enabled =false ;appearanceSampler_.Submit (appearanceRequest_);
241248 KillTimer (window_, kHoverTimer );
242249 KillTimer (window_, kMotionTimer );
243250 motionRunning_ = false ;
@@ -272,9 +279,12 @@ class Controller {
272279 PollHover ();
273280 if (geometryChanged || appearanceChanged || visibilityChanged || previousBelow != below_)
274281 Render ();
282+ PollAppearance ();
275283 }
276284
277285 void Destroy () {
286+ appearanceSampler_.Stop ();
287+ for (auto & raster:rasters_)raster.Clear ();
278288 closePointerDown_ = false ;
279289 if (closeWindow_) {
280290 if (GetCapture () == closeWindow_) ReleaseCapture ();
@@ -377,6 +387,13 @@ class Controller {
377387 Detail::Spring foldedHover_;
378388 Detail::DotImpulse dotImpulse_;
379389 float settingsTint_ = 0 , closeTint_ = 0 ;
390+ std::array<GlassControlAppearance::Raster,2 > rasters_;
391+ GlassControlAppearance::Sampler appearanceSampler_;
392+ GlassControlAppearance::Request appearanceRequest_;
393+ GlassAutoInk::Decision appearanceDecision_;
394+ GlassAutoInk::Fade appearanceFade_;
395+ unsigned appearanceSeen_=0 ;
396+ float lightAppearance_=0 ;
380397 float foldProgress_ = 1 .0f ;
381398 bool noteTransition_ = false , transitionToFold_ = false ;
382399 float insideCenterY_ = 0 , outsideCenterY_ = 0 , foldedCenterY_ = 0 ;
@@ -665,6 +682,7 @@ class Controller {
665682 void Animate () {
666683 if (!window_ || !visible_) return ;
667684 if (reduceMotion_) {
685+ lightAppearance_=GetRValue (appearanceFade_.target )/255 .f ;
668686 dotImpulse_.Clear ();
669687 expansion_.value = expanded_ && ExpansionAllowed () ? 1 .0f : 0 .0f ;
670688 expansion_.velocity = 0 ;
@@ -692,6 +710,8 @@ class Controller {
692710 // A faster, more pronounced rise and a short elastic settle. Retain
693711 // velocity when the pointer reverses instead of restarting an easing.
694712 bool active = expansion_.Step (expanded_ && ExpansionAllowed () ? 1 .0f : 0 .0f , seconds, 32 .0f , 0 .72f );
713+ lightAppearance_=GetRValue (appearanceFade_.Sample (double (now)))/255 .f ;
714+ active |= appearanceFade_.Running (double (now));
695715 active |= foldedHover_.Step (folded_ && !noteTransition_ && !inputSuppressed_ && hover_ ? 1 .0f : 0 .0f , seconds);
696716 active |= Detail::Fade (settingsTint_, hover_ && !closeHover_ && !inputSuppressed_ && !noteTransition_ ? 1 .0f : 0 .0f , seconds);
697717 active |= Detail::Fade (closeTint_, closeHover_ && ExpansionAllowed () ? 1 .0f : 0 .0f , seconds);
@@ -704,6 +724,28 @@ class Controller {
704724 KillTimer (window_, kMotionTimer );
705725 motionRunning_ = false ;
706726 }
727+ PollAppearance ();
728+ }
729+
730+ void PollAppearance () {
731+ auto request=appearanceRequest_;
732+ const auto rectangles=VisibleSurfaceRects ();request.surface =rectangles[0 ];
733+ if (rectangles[1 ].right >rectangles[1 ].left )UnionRect (&request.surface ,&request.surface ,&rectangles[1 ]);
734+ request.padding =std::max (6 ,Scale (6 ));request.guard =std::max (2 ,Scale (3 ));
735+ request.enabled =visible_ && !highContrast_ && !noteTransition_ && !inputSuppressed_;
736+ appearanceSampler_.Submit (request);
737+ double share=0 ;
738+ if (appearanceSampler_.Read (appearanceSeen_,share))appearanceDecision_.Update (share,double (GetTickCount64 ()));
739+ // Keep the chosen X colour throughout red hover, including its retreat.
740+ if (closeHover_ || closePointerDown_ || closeTint_>.001f ) {
741+ const int c=int (std::lround (lightAppearance_*255 ));appearanceFade_.Reset (RGB (c,c,c));return ;
742+ }
743+ if (!request.enabled || !appearanceDecision_.valid )return ;
744+ const COLORREF target=appearanceDecision_.white ?RGB (255 ,255 ,255 ):RGB (0 ,0 ,0 );
745+ if (!appearanceFade_.initialized || appearanceFade_.target !=target) {
746+ const int c=int (std::lround (lightAppearance_*255 ));
747+ appearanceFade_.Aim (target,RGB (c,c,c),double (GetTickCount64 ()));Animate ();
748+ }
707749 }
708750
709751 static void RoundPath (Gdiplus::GraphicsPath& path, float x, float y,
@@ -778,22 +820,9 @@ class Controller {
778820 const int height = static_cast <int >(bounds_.bottom - bounds_.top );
779821 if (width <= 0 || height <= 0 )
780822 return ;
781- BITMAPINFO info{};
782- info.bmiHeader .biSize = sizeof (BITMAPINFOHEADER );
783- info.bmiHeader .biWidth = width;
784- info.bmiHeader .biHeight = -height;
785- info.bmiHeader .biPlanes = 1 ;
786- info.bmiHeader .biBitCount = 32 ;
787- info.bmiHeader .biCompression = BI_RGB ;
788- void * pixels = nullptr ;
789- HDC dc = CreateCompatibleDC (nullptr );
790- HBITMAP dib = CreateDIBSection (dc, &info, DIB_RGB_COLORS , &pixels, nullptr , 0 );
791- if (!dc || !dib || !pixels) {
792- if (dib) DeleteObject (dib);
793- if (dc) DeleteDC (dc);
794- return ;
795- }
796- const HGDIOBJ old = SelectObject (dc, dib);
823+ auto & raster=rasters_[close?1 :0 ];
824+ if (!raster.Ensure (width,height))return ;
825+ void * pixels=raster.pixels ;HDC dc=raster.dc ;
797826 {
798827 // GDI+ writes premultiplied BGRA directly, including edge coverage.
799828 // Do not re-premultiply these pixels after drawing.
@@ -839,15 +868,12 @@ class Controller {
839868 graphics.TranslateTransform (38 .0f , centerY);
840869 graphics.ScaleTransform (surface.width / 72 .0f , 1 .0f );
841870 graphics.TranslateTransform (-38 .0f , -centerY);
842- const float materialWeight = std::max (glyphAlpha, folded_ ? foldProgress_ : 0 .0f );
843- Gdiplus::Color background = Mix (Gdiplus::Color (248 , 64 , 66 , 70 ),
844- Gdiplus::Color (248 , 48 , 50 , 54 ), materialWeight);
845- Gdiplus::Color settingsBackground = Mix (background, Gdiplus::Color (252 , 72 , 75 , 80 ), settingsTint_);
871+ Gdiplus::Color background = Mix (Gdiplus::Color (255 ,0 ,0 ,0 ),Gdiplus::Color (255 ,255 ,255 ,255 ),lightAppearance_);
872+ Gdiplus::Color settingsBackground = background;
846873 Gdiplus::Color closeBackground = Mix (background, Gdiplus::Color (255 , 220 , 52 , 65 ), closeTint_);
847874 closeBackground = Mix (settingsBackground, closeBackground, separation);
848- Gdiplus::Color foreground (255 , 245 , 247 , 251 );
849- Gdiplus::Color closeForeground = Mix (Gdiplus::Color (255 , 255 , 112 , 113 ),
850- Gdiplus::Color (255 , 255 , 255 , 255 ), closeTint_);
875+ Gdiplus::Color foreground (255 ,255 -background.GetR (),255 -background.GetG (),255 -background.GetB ());
876+ Gdiplus::Color closeForeground = foreground;
851877 if (highContrast_) {
852878 const COLORREF bg = GetSysColor (COLOR_BTNFACE ), fg = GetSysColor (COLOR_BTNTEXT );
853879 settingsBackground = Gdiplus::Color (255 , GetRValue (bg), GetGValue (bg), GetBValue (bg));
@@ -871,9 +897,7 @@ class Controller {
871897 Gdiplus::SolidBrush closeFill (closeBackground);
872898 graphics.FillPath (&closeFill, &path);
873899 graphics.Restore (surfaceClip);
874- Gdiplus::Pen rim (Gdiplus::Color (highContrast_ ? 255 : 52 , foreground.GetR (), foreground.GetG (),
875- foreground.GetB ()), 0 .65f );
876- graphics.DrawPath (&rim, &path);
900+ if (highContrast_) {Gdiplus::Pen rim (foreground,0 .65f );graphics.DrawPath (&rim,&path);}
877901 if (glyphAlpha > 0 ) {
878902 Gdiplus::Color crossColor (static_cast <BYTE >(255 * glyphAlpha), closeForeground.GetR (),
879903 closeForeground.GetG (), closeForeground.GetB ());
@@ -888,6 +912,10 @@ class Controller {
888912 line.SetStartCap (Gdiplus::LineCapRound);
889913 line.SetEndCap (Gdiplus::LineCapRound);
890914 Gdiplus::SolidBrush knob (glyph);
915+ const auto glyphTransform=graphics.Save ();
916+ graphics.TranslateTransform (24 ,centerY);
917+ graphics.ScaleTransform (1 +.06f *settingsTint_,1 +.06f *settingsTint_);
918+ graphics.TranslateTransform (-24 ,-centerY);
891919 // Original vector artwork: three adjustment tracks with alternating
892920 // handles, not a vendor font glyph or an embedded platform asset.
893921 const float rows[] = {centerY - 5 .0f , centerY, centerY + 5 .0f };
@@ -898,9 +926,9 @@ class Controller {
898926 graphics.FillEllipse (&cutout, handles[row] - 3 , rows[row] - 3 , 6 .0f , 6 .0f );
899927 graphics.FillEllipse (&knob, handles[row] - 1 .9f , rows[row] - 1 .9f , 3 .8f , 3 .8f );
900928 }
929+ graphics.Restore (glyphTransform);
901930 if (passThrough_) {
902- Gdiplus::SolidBrush status (highContrast_ ? glyph :
903- Gdiplus::Color (static_cast <BYTE >(255 * glyphAlpha), 111 , 190 , 255 ));
931+ Gdiplus::SolidBrush status (glyph);
904932 graphics.FillEllipse (&status, 36 .0f , centerY + 5 .0f , 2 .5f , 2 .5f );
905933 }
906934 }
@@ -920,9 +948,6 @@ class Controller {
920948 SIZE size{width, height};
921949 BLENDFUNCTION blend{AC_SRC_OVER , 0 , 255 , AC_SRC_ALPHA };
922950 UpdateLayeredWindow (target, nullptr , &destination, &size, dc, &source, 0 , &blend, ULW_ALPHA );
923- SelectObject (dc, old);
924- DeleteObject (dib);
925- DeleteDC (dc);
926951 }
927952
928953 void FinishPointer (bool click) {
@@ -1124,6 +1149,7 @@ class Controller {
11241149 }
11251150 if (wp == kHoverTimer ) {
11261151 PollHover ();
1152+ PollAppearance ();
11271153 return 0 ;
11281154 }
11291155 break ;
0 commit comments