1414#include < functional>
1515#include < string>
1616#include < utility>
17+ #include " ../src/glass_control_appearance.h"
1718
1819namespace GlassControlIsland {
1920
@@ -23,8 +24,7 @@ namespace Detail {
2324// elasticity without changing its anchored edge or its hit-test footprint.
2425struct Spring {
2526 float value = 0 , velocity = 0 ;
26- bool Step (float target, float seconds) {
27- constexpr float frequency = 22 .0f , damping = 0 .74f ;
27+ bool Step (float target, float seconds, float frequency=22 .0f , float damping=0 .74f ) {
2828 const float dt = std::clamp (seconds, 0 .0f , 1 .0f );
2929 const float decayRate = frequency * damping;
3030 const float dampedFrequency = frequency * std::sqrt (1 .0f - damping * damping);
@@ -99,7 +99,7 @@ class Controller {
9999 static_cast <LONG >(std::lround (centerY + radius))};
100100 }
101101 };
102- Controller () = default ;
102+ Controller () {appearanceFade_. Reset ( RGB ( 0 , 0 , 0 ));}
103103 Controller (const Controller&) = delete ;
104104 Controller& operator =(const Controller&) = delete ;
105105 ~Controller () { Destroy (); }
@@ -186,7 +186,8 @@ class Controller {
186186
187187 void Update (const RECT & noteRect, UINT dpi, bool visible, bool topmost,
188188 bool passThrough, bool menuOpen, HWND noteWindow = nullptr , int cornerRadiusPx = 0 ,
189- 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 ) {
190191 if (!window_)
191192 return ;
192193 const UINT newDpi = dpi ? dpi : 96 ;
@@ -206,7 +207,11 @@ class Controller {
206207 menuOpen_ = effectiveMenuOpen;
207208 // Retain the API for the host, but note/body hover and note capture are
208209 // deliberately no longer expansion sources, including click-through.
209- (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 ;
210215 noteRect_ = noteRect;
211216 cornerRadiusPx_ = std::max (0 , cornerRadiusPx);
212217 const bool previousBelow = below_;
@@ -239,6 +244,7 @@ class Controller {
239244 (flags & ~(SWP_SHOWWINDOW | SWP_HIDEWINDOW )));
240245 }
241246 if (!visible) {
247+ appearanceRequest_.enabled =false ;appearanceSampler_.Submit (appearanceRequest_);
242248 KillTimer (window_, kHoverTimer );
243249 KillTimer (window_, kMotionTimer );
244250 motionRunning_ = false ;
@@ -273,9 +279,12 @@ class Controller {
273279 PollHover ();
274280 if (geometryChanged || appearanceChanged || visibilityChanged || previousBelow != below_)
275281 Render ();
282+ PollAppearance ();
276283 }
277284
278285 void Destroy () {
286+ appearanceSampler_.Stop ();
287+ for (auto & raster:rasters_)raster.Clear ();
279288 closePointerDown_ = false ;
280289 if (closeWindow_) {
281290 if (GetCapture () == closeWindow_) ReleaseCapture ();
@@ -378,6 +387,13 @@ class Controller {
378387 Detail::Spring foldedHover_;
379388 Detail::DotImpulse dotImpulse_;
380389 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 ;
381397 float foldProgress_ = 1 .0f ;
382398 bool noteTransition_ = false , transitionToFold_ = false ;
383399 float insideCenterY_ = 0 , outsideCenterY_ = 0 , foldedCenterY_ = 0 ;
@@ -666,6 +682,7 @@ class Controller {
666682 void Animate () {
667683 if (!window_ || !visible_) return ;
668684 if (reduceMotion_) {
685+ lightAppearance_=GetRValue (appearanceFade_.target )/255 .f ;
669686 dotImpulse_.Clear ();
670687 expansion_.value = expanded_ && ExpansionAllowed () ? 1 .0f : 0 .0f ;
671688 expansion_.velocity = 0 ;
@@ -690,7 +707,11 @@ class Controller {
690707 const ULONGLONG now = GetTickCount64 ();
691708 const float seconds = static_cast <float >(now - lastMotionTick_) / 1000 .0f ;
692709 lastMotionTick_ = now;
693- bool active = expansion_.Step (expanded_ && ExpansionAllowed () ? 1 .0f : 0 .0f , seconds);
710+ // A faster, more pronounced rise and a short elastic settle. Retain
711+ // velocity when the pointer reverses instead of restarting an easing.
712+ 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));
694715 active |= foldedHover_.Step (folded_ && !noteTransition_ && !inputSuppressed_ && hover_ ? 1 .0f : 0 .0f , seconds);
695716 active |= Detail::Fade (settingsTint_, hover_ && !closeHover_ && !inputSuppressed_ && !noteTransition_ ? 1 .0f : 0 .0f , seconds);
696717 active |= Detail::Fade (closeTint_, closeHover_ && ExpansionAllowed () ? 1 .0f : 0 .0f , seconds);
@@ -703,6 +724,28 @@ class Controller {
703724 KillTimer (window_, kMotionTimer );
704725 motionRunning_ = false ;
705726 }
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+ }
706749 }
707750
708751 static void RoundPath (Gdiplus::GraphicsPath& path, float x, float y,
@@ -777,22 +820,9 @@ class Controller {
777820 const int height = static_cast <int >(bounds_.bottom - bounds_.top );
778821 if (width <= 0 || height <= 0 )
779822 return ;
780- BITMAPINFO info{};
781- info.bmiHeader .biSize = sizeof (BITMAPINFOHEADER );
782- info.bmiHeader .biWidth = width;
783- info.bmiHeader .biHeight = -height;
784- info.bmiHeader .biPlanes = 1 ;
785- info.bmiHeader .biBitCount = 32 ;
786- info.bmiHeader .biCompression = BI_RGB ;
787- void * pixels = nullptr ;
788- HDC dc = CreateCompatibleDC (nullptr );
789- HBITMAP dib = CreateDIBSection (dc, &info, DIB_RGB_COLORS , &pixels, nullptr , 0 );
790- if (!dc || !dib || !pixels) {
791- if (dib) DeleteObject (dib);
792- if (dc) DeleteDC (dc);
793- return ;
794- }
795- 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 ;
796826 {
797827 // GDI+ writes premultiplied BGRA directly, including edge coverage.
798828 // Do not re-premultiply these pixels after drawing.
@@ -838,15 +868,12 @@ class Controller {
838868 graphics.TranslateTransform (38 .0f , centerY);
839869 graphics.ScaleTransform (surface.width / 72 .0f , 1 .0f );
840870 graphics.TranslateTransform (-38 .0f , -centerY);
841- const float materialWeight = std::max (glyphAlpha, folded_ ? foldProgress_ : 0 .0f );
842- Gdiplus::Color background = Mix (Gdiplus::Color (248 , 64 , 66 , 70 ),
843- Gdiplus::Color (248 , 48 , 50 , 54 ), materialWeight);
844- 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;
845873 Gdiplus::Color closeBackground = Mix (background, Gdiplus::Color (255 , 220 , 52 , 65 ), closeTint_);
846874 closeBackground = Mix (settingsBackground, closeBackground, separation);
847- Gdiplus::Color foreground (255 , 245 , 247 , 251 );
848- Gdiplus::Color closeForeground = Mix (Gdiplus::Color (255 , 255 , 112 , 113 ),
849- 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;
850877 if (highContrast_) {
851878 const COLORREF bg = GetSysColor (COLOR_BTNFACE ), fg = GetSysColor (COLOR_BTNTEXT );
852879 settingsBackground = Gdiplus::Color (255 , GetRValue (bg), GetGValue (bg), GetBValue (bg));
@@ -870,9 +897,7 @@ class Controller {
870897 Gdiplus::SolidBrush closeFill (closeBackground);
871898 graphics.FillPath (&closeFill, &path);
872899 graphics.Restore (surfaceClip);
873- Gdiplus::Pen rim (Gdiplus::Color (highContrast_ ? 255 : 52 , foreground.GetR (), foreground.GetG (),
874- foreground.GetB ()), 0 .65f );
875- graphics.DrawPath (&rim, &path);
900+ if (highContrast_) {Gdiplus::Pen rim (foreground,0 .65f );graphics.DrawPath (&rim,&path);}
876901 if (glyphAlpha > 0 ) {
877902 Gdiplus::Color crossColor (static_cast <BYTE >(255 * glyphAlpha), closeForeground.GetR (),
878903 closeForeground.GetG (), closeForeground.GetB ());
@@ -887,6 +912,10 @@ class Controller {
887912 line.SetStartCap (Gdiplus::LineCapRound);
888913 line.SetEndCap (Gdiplus::LineCapRound);
889914 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);
890919 // Original vector artwork: three adjustment tracks with alternating
891920 // handles, not a vendor font glyph or an embedded platform asset.
892921 const float rows[] = {centerY - 5 .0f , centerY, centerY + 5 .0f };
@@ -897,9 +926,9 @@ class Controller {
897926 graphics.FillEllipse (&cutout, handles[row] - 3 , rows[row] - 3 , 6 .0f , 6 .0f );
898927 graphics.FillEllipse (&knob, handles[row] - 1 .9f , rows[row] - 1 .9f , 3 .8f , 3 .8f );
899928 }
929+ graphics.Restore (glyphTransform);
900930 if (passThrough_) {
901- Gdiplus::SolidBrush status (highContrast_ ? glyph :
902- Gdiplus::Color (static_cast <BYTE >(255 * glyphAlpha), 111 , 190 , 255 ));
931+ Gdiplus::SolidBrush status (glyph);
903932 graphics.FillEllipse (&status, 36 .0f , centerY + 5 .0f , 2 .5f , 2 .5f );
904933 }
905934 }
@@ -919,9 +948,6 @@ class Controller {
919948 SIZE size{width, height};
920949 BLENDFUNCTION blend{AC_SRC_OVER , 0 , 255 , AC_SRC_ALPHA };
921950 UpdateLayeredWindow (target, nullptr , &destination, &size, dc, &source, 0 , &blend, ULW_ALPHA );
922- SelectObject (dc, old);
923- DeleteObject (dib);
924- DeleteDC (dc);
925951 }
926952
927953 void FinishPointer (bool click) {
@@ -1123,6 +1149,7 @@ class Controller {
11231149 }
11241150 if (wp == kHoverTimer ) {
11251151 PollHover ();
1152+ PollAppearance ();
11261153 return 0 ;
11271154 }
11281155 break ;
0 commit comments