Skip to content

Commit 1af479c

Browse files
feat: ease automatic ink colour transitions
1 parent 111a359 commit 1af479c

3 files changed

Lines changed: 47 additions & 4 deletions

File tree

‎src/glass_auto_ink.h‎

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,4 +43,23 @@ struct Decision {
4343
if(now-candidateAt>=90){white=next;pending=false;}
4444
}
4545
};
46+
struct Fade {
47+
static constexpr double duration=180;
48+
COLORREF from=Dark,target=Dark;
49+
double started=0;
50+
bool initialized=false;
51+
void Reset(COLORREF colour){from=target=colour;initialized=true;started=0;}
52+
bool Running(double now) const {return from!=target && now-started<duration;}
53+
COLORREF Sample(double now) const {
54+
double t=std::clamp((now-started)/duration,0.,1.);
55+
t=t*t*(3-2*t); // smooth departure and arrival, no long grey plateau
56+
auto channel=[t](int a,int b){return int(std::lround(a+(b-a)*t));};
57+
return RGB(channel(GetRValue(from),GetRValue(target)),channel(GetGValue(from),GetGValue(target)),channel(GetBValue(from),GetBValue(target)));
58+
}
59+
void Aim(COLORREF colour,COLORREF current,double now) {
60+
if(!initialized)Reset(current);
61+
if(colour==target)return;
62+
from=Sample(now);target=colour;started=now;
63+
}
64+
};
4665
}

‎src/main.cpp‎

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -592,18 +592,34 @@ void RequestRender() {
592592
#ifdef FLOATNOTE_GLASS_LAB
593593
void SyncAdaptiveInk() {
594594
static bool timer=false;
595+
static bool fadeTimer=false;
596+
static GlassAutoInk::Fade fade;
597+
static double lastInkPaint=0;
595598
const bool motion=ExperienceAbsorbing();
596599
const bool active=g_window && g_settings.autoTextColor && !g_highContrast && g_nativeGlass && g_glassActive &&
597600
g_backdrop.mode==2 && EffectiveOpacityPercent()<100 && g_isVisible && !IsIconic(g_window) && !ExperienceCompact();
598601
if(active && !motion && !timer){SetTimer(g_window,82,100,nullptr);timer=true;}
599602
else if((!active || motion) && timer){KillTimer(g_window,82);timer=false;}
600-
if(motion)return; // Freeze the chosen ink through the cached-surface animation.
603+
if(motion) {
604+
if(fadeTimer){KillTimer(g_window,83);fadeTimer=false;}
605+
fade.Reset(kNoteText);return; // Freeze ink through the cached-surface animation.
606+
}
601607
const int alpha=std::max(g_settings.passThrough?0:1,MulDiv(EffectiveOpacityPercent(),255,100));
602608
const int choice=g_backdrop.UpdateAutoInk(active,kBackground,alpha,kText==GlassAutoInk::Light);
603609
const COLORREF next=g_highContrast?kText:!g_settings.autoTextColor?g_settings.textColor:
604610
choice<0?kText:choice?GlassAutoInk::Light:GlassAutoInk::Dark;
605-
if(next!=kNoteText) {
606-
kNoteText=next;
611+
const double now=GlassClockMs();
612+
if(active && choice>=0)fade.Aim(next,kNoteText,now);
613+
else fade.Reset(next); // Explicit colours and accessibility changes apply immediately.
614+
const bool animating=active && fade.Running(now);
615+
if(animating && !fadeTimer){SetTimer(g_window,83,16,nullptr);fadeTimer=true;}
616+
else if(!animating && fadeTimer){KillTimer(g_window,83);fadeTimer=false;}
617+
// Capture and render-completion events also enter here. Cap fade updates
618+
// so they cannot turn a short animation into a self-posting repaint loop.
619+
const COLORREF presented=animating && now-lastInkPaint<16?kNoteText:fade.Sample(now);
620+
if(presented!=kNoteText) {
621+
lastInkPaint=now;
622+
kNoteText=presented;
607623
if(g_edit)InvalidateRect(g_edit,nullptr,FALSE);
608624
RequestRender();
609625
}
@@ -2434,6 +2450,7 @@ LRESULT CALLBACK WindowProcedure(HWND window, UINT message, WPARAM wParam, LPARA
24342450
if (message == WM_TIMER && wParam == 71) { g_backdrop.Tick(); SyncAdaptiveInk(); return 0; }
24352451
if (message == kGlassFrameReady) { g_backdrop.FrameReady(); SyncAdaptiveInk(); ApplyWindowStacking(); return 0; }
24362452
if (message == WM_TIMER && wParam == 82) { SyncAdaptiveInk(); return 0; }
2453+
if (message == WM_TIMER && wParam == 83) { SyncAdaptiveInk(); return 0; }
24372454
if (message == WM_WINDOWPOSCHANGED) {g_backdrop.RequestDraw();SyncExperienceUI();}
24382455
if (message == WM_ACTIVATE && LOWORD(wParam)!=WA_INACTIVE)SyncExperienceUI();
24392456
if (message == WM_TIMER && wParam==73){ApplyWindowStacking();SyncExperienceUI();return 0;}

‎tests/glass_auto_ink_native.cpp‎

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,12 @@ struct GlassAutoInkTest {
1313
}
1414
static void Check(bool ok,const char* error){if(!ok)throw std::runtime_error(error);}
1515
static void Run() {
16+
GlassAutoInk::Fade fade;fade.Reset(GlassAutoInk::Dark);fade.Aim(GlassAutoInk::Light,GlassAutoInk::Dark,1000);
17+
Check(fade.Sample(1000)==GlassAutoInk::Dark,"fade jumped at start");
18+
const COLORREF middle=fade.Sample(1090);
19+
Check(GetRValue(middle)>GetRValue(GlassAutoInk::Dark) && GetRValue(middle)<GetRValue(GlassAutoInk::Light),"fade lacks intermediate colour");
20+
fade.Aim(GlassAutoInk::Dark,middle,1090);Check(fade.Sample(1090)==middle,"fade reversal jumped");
21+
Check(fade.Sample(1270)==GlassAutoInk::Dark && !fade.Running(1270),"fade failed to settle");
1622
g_instance=GetModuleHandleW(nullptr);
1723
g_window=CreateWindowExW(WS_EX_TOOLWINDOW,L"STATIC",L"Hidden ink test",WS_POPUP,0,0,320,160,nullptr,nullptr,g_instance,nullptr);
1824
g_edit=CreateWindowExW(0,L"EDIT",L"Editable text",WS_CHILD|ES_MULTILINE,0,0,200,100,g_window,nullptr,g_instance,nullptr);
@@ -22,7 +28,8 @@ struct GlassAutoInkTest {
2228
kBackground=RGB(255,255,255);kText=kNoteText=GlassAutoInk::Dark;
2329
SendMessageW(g_edit,EM_SETSEL,0,1);SendMessageW(g_edit,EM_REPLACESEL,TRUE,reinterpret_cast<LPARAM>(L"X"));
2430
DWORD beforeStart=0,beforeEnd=0;SendMessageW(g_edit,EM_GETSEL,reinterpret_cast<WPARAM>(&beforeStart),reinterpret_cast<LPARAM>(&beforeEnd));
25-
Seed();SyncAdaptiveInk();Check(kNoteText==GlassAutoInk::Light,"Auto did not apply sampled white ink");
31+
Seed();SyncAdaptiveInk();Check(kNoteText==GlassAutoInk::Dark,"Auto ink did not start smoothly");
32+
Sleep(200);SyncAdaptiveInk();Check(kNoteText==GlassAutoInk::Light,"Auto did not settle on sampled white ink");
2633
Check(kText==GlassAutoInk::Dark,"Auto recoloured settings UI");
2734
DWORD afterStart=0,afterEnd=0;SendMessageW(g_edit,EM_GETSEL,reinterpret_cast<WPARAM>(&afterStart),reinterpret_cast<LPARAM>(&afterEnd));
2835
Check(afterStart==beforeStart&&afterEnd==beforeEnd&&SendMessageW(g_edit,EM_CANUNDO,0,0),"ink update disturbed native selection/undo");

0 commit comments

Comments
 (0)