Skip to content

Commit 68ce0bc

Browse files
feat(injector): winui3-like buttons
1 parent c2cec22 commit 68ce0bc

File tree

3 files changed

+103
-23
lines changed

3 files changed

+103
-23
lines changed

src/inject/inject.cc

Lines changed: 83 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -139,7 +139,7 @@ int InjectToPID(int targetPID, std::wstring_view dllPath) {
139139
ShowCrashDialog();
140140
}
141141
} else {
142-
crash_count = 0; // Reset crash count on successful injection
142+
crash_count = 0;
143143
}
144144
CloseHandle(hProcess);
145145
}).detach();
@@ -237,24 +237,101 @@ struct button_widget : public ui::padding_widget {
237237
auto text = emplace_child<ui::text_widget>();
238238
text->text = button_text;
239239
text->font_size = 14;
240-
text->color.reset_to({1, 1, 1, 1});
240+
text->color.reset_to({1, 1, 1, 0.95});
241241

242242
padding_bottom->reset_to(10);
243243
padding_top->reset_to(10);
244244
padding_left->reset_to(22);
245245
padding_right->reset_to(20);
246-
}
247246

248-
ui::animated_color bg_color = {this, 40 / 255.f, 40 / 255.f, 40 / 255.f, 0.6};
247+
border_top.reset_to({1, 1, 1, 0.12});
248+
border_right.reset_to({1, 1, 1, 0.04});
249+
border_bottom.reset_to({1, 1, 1, 0.02});
250+
border_left.reset_to({1, 1, 1, 0.04});
251+
}
249252

250-
virtual void on_click() = 0;
253+
ui::animated_color border_top = {this, 0, 0, 0, 0},
254+
border_right = {this, 0, 0, 0, 0},
255+
border_bottom = {this, 0, 0, 0, 0},
256+
border_left = {this, 0, 0, 0, 0};
251257

252258
void render(ui::nanovg_context ctx) override {
253-
ctx.fillColor(bg_color.nvg());
259+
260+
ctx.fillColor(bg_color);
254261
ctx.fillRoundedRect(*x, *y, *width, *height, 6);
262+
263+
float bw = 1.0f;
264+
265+
float radius = 6.0f;
266+
// 4 edges
267+
ctx.beginPath();
268+
ctx.strokeWidth(bw);
269+
ctx.strokeColor(border_top);
270+
ctx.moveTo(*x + radius, *y + bw / 2);
271+
ctx.lineTo(*x + *width - radius, *y + bw / 2);
272+
ctx.stroke();
273+
274+
ctx.beginPath();
275+
ctx.strokeWidth(bw);
276+
ctx.strokeColor(border_right);
277+
ctx.moveTo(*x + *width - bw / 2, *y + radius);
278+
ctx.lineTo(*x + *width - bw / 2, *y + *height - radius);
279+
ctx.stroke();
280+
281+
ctx.beginPath();
282+
ctx.strokeWidth(bw);
283+
ctx.strokeColor(border_bottom);
284+
ctx.moveTo(*x + *width - radius, *y + *height - bw / 2);
285+
ctx.lineTo(*x + radius, *y + *height - bw / 2);
286+
ctx.stroke();
287+
288+
ctx.beginPath();
289+
ctx.strokeWidth(bw);
290+
ctx.strokeColor(border_left);
291+
ctx.moveTo(*x + bw / 2, *y + *height - radius);
292+
ctx.lineTo(*x + bw / 2, *y + radius);
293+
ctx.stroke();
294+
295+
// 4 corners
296+
float cr = radius - bw / 2;
297+
ctx.beginPath();
298+
ctx.strokeWidth(bw);
299+
ctx.strokeColor(border_right.blend(border_top));
300+
ctx.moveTo(*x + *width - radius, *y + bw / 2);
301+
ctx.arcTo(*x + *width - bw / 2, *y + bw / 2, *x + *width - bw / 2,
302+
*y + radius, cr);
303+
ctx.stroke();
304+
305+
ctx.beginPath();
306+
ctx.strokeWidth(bw);
307+
ctx.strokeColor(border_bottom.blend(border_right));
308+
ctx.moveTo(*x + *width - bw / 2, *y + *height - radius);
309+
ctx.arcTo(*x + *width - bw / 2, *y + *height - bw / 2, *x + *width - radius,
310+
*y + *height - bw / 2, cr);
311+
ctx.stroke();
312+
313+
ctx.beginPath();
314+
ctx.strokeWidth(bw);
315+
ctx.strokeColor(border_left.blend(border_bottom));
316+
ctx.moveTo(*x + radius, *y + *height - bw / 2);
317+
ctx.arcTo(*x + bw / 2, *y + *height - bw / 2, *x + bw / 2,
318+
*y + *height - radius, cr);
319+
ctx.stroke();
320+
321+
ctx.beginPath();
322+
ctx.strokeWidth(bw);
323+
ctx.strokeColor(border_top.blend(border_left));
324+
ctx.moveTo(*x + bw / 2, *y + radius);
325+
ctx.arcTo(*x + bw / 2, *y + bw / 2, *x + radius, *y + bw / 2, cr);
326+
ctx.stroke();
327+
255328
padding_widget::render(ctx);
256329
}
257330

331+
ui::animated_color bg_color = {this, 40 / 255.f, 40 / 255.f, 40 / 255.f, 0.6};
332+
333+
virtual void on_click() = 0;
334+
258335
virtual void update_colors(bool is_active, bool is_hovered) {
259336
if (is_active) {
260337
bg_color.animate_to({0.3, 0.3, 0.3, 0.7});
@@ -540,7 +617,6 @@ struct injector_ui_main : public ui::widget_flex {
540617
auto gradient_height = 130;
541618
ctx.fillRect(0, gradient_height, 999, 999);
542619

543-
// 20->0 linear gradient
544620
NVGpaint bg = nvgLinearGradient(ctx.ctx, 0, gradient_height, 0, 0,
545621
nvgRGB(32, 32, 32), nvgRGBAf(0, 0, 0, 0));
546622
ctx.beginPath();
@@ -608,16 +684,13 @@ void ShowCrashDialog() {
608684

609685
nvgCreateFont(rt.nvg, "main", "C:\\WINDOWS\\FONTS\\msyh.ttc");
610686

611-
// Create error UI
612687
auto error_ui = rt.root->emplace_child<ui::widget_flex>();
613688
error_ui->gap = 15;
614689
error_ui->x->reset_to(20);
615690
error_ui->y->reset_to(0);
616691

617-
// Icon
618692
error_ui->emplace_child<breeze_icon>();
619693

620-
// Error message
621694
auto msg_box = error_ui->emplace_child<ui::widget_flex>();
622695
msg_box->gap = 10;
623696

src/ui/animator.h

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66
#include <optional>
77
#include <print>
88

9-
109
namespace ui {
1110
struct widget;
1211
enum class easing_type {
@@ -66,12 +65,22 @@ struct animated_color {
6665
sp_anim_float b = nullptr;
6766
sp_anim_float a = nullptr;
6867

68+
operator NVGcolor() {
69+
return nvgRGBAf(r->var(), g->var(), b->var(), a->var());
70+
}
6971
animated_color() = delete;
7072
animated_color(animated_color &&) = default;
7173

7274
animated_color(ui::widget *thiz, float r = 0, float g = 0, float b = 0,
7375
float a = 0);
7476

77+
NVGcolor blend(const animated_color &other, float factor = 0.5f) const {
78+
return nvgRGBAf(r->var() * (1 - factor) + other.r->var() * factor,
79+
g->var() * (1 - factor) + other.g->var() * factor,
80+
b->var() * (1 - factor) + other.b->var() * factor,
81+
a->var() * (1 - factor) + other.a->var() * factor);
82+
}
83+
7584
std::array<float, 4> operator*() const;
7685

7786
inline void animate_to(float r, float g, float b, float a) {

src/ui/nanovg_wrapper.h

Lines changed: 10 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -12,14 +12,12 @@ struct render_target;
1212
struct nanovg_context {
1313
NVGcontext *ctx;
1414
render_target *rt;
15+
// clang-format off
1516
/*
1617
Codegen:
1718
18-
console.log([...nanovgSource.matchAll(/nvg(\S+)\(NVGcontext\*
19-
ctx,?(.*)\);/g)].map(v=>{ if(v[1] === 'nvgTranslate') return; return `inline
20-
auto ${v[1][0].toLowerCase() + v[1].slice(1)}(${v[2]}) { return nvg${v[1]}(${
21-
['ctx',...v[2].split(',').filter(Boolean)].map(v=>v.trim().split('
22-
').pop()) .map(v=>{ if (v === 'x' || v === 'y') return `${v} + offset_${v}`
19+
console.log([...nanovgSource.matchAll(/nvg(\S+)\(NVGcontext\* ctx,?(.*)\);/g)].map(v=>{ if(v[1][0] === 'nvgTranslate') return; return `inline auto ${v[1][0].toLowerCase() + v[1].slice(1)}(${v[2]}) { return nvg${v[1]}(${
20+
['ctx',...v[2].split(',').filter(Boolean)].map(v=>v.trim().split(' ').pop()) .map(v=>{ if ('x,y,c1x,c1y,y1,y2,x1,x2,cx,cy'.split(',').includes(v)) return `${v} + offset_${v.includes('x') ? 'x' : 'y'}`
2321
return v
2422
})
2523
.join(',')
@@ -29,7 +27,7 @@ auto ${v[1][0].toLowerCase() + v[1].slice(1)}(${v[2]}) { return nvg${v[1]}(${
2927

3028
float offset_x = 0, offset_y = 0;
3129

32-
// clang-format off
30+
3331
inline auto beginFrame( float windowWidth, float windowHeight, float devicePixelRatio) { return nvgBeginFrame(ctx,windowWidth,windowHeight,devicePixelRatio); }
3432
inline auto cancelFrame() { return nvgCancelFrame(ctx); }
3533
inline auto endFrame() { return nvgEndFrame(ctx); }
@@ -69,17 +67,17 @@ inline auto resetScissor() { return nvgResetScissor(ctx); }
6967
inline auto beginPath() { return nvgBeginPath(ctx); }
7068
inline auto moveTo( float x, float y) { return nvgMoveTo(ctx,x + offset_x,y + offset_y); }
7169
inline auto lineTo( float x, float y) { return nvgLineTo(ctx,x + offset_x,y + offset_y); }
72-
inline auto bezierTo( float c1x, float c1y, float c2x, float c2y, float x, float y) { return nvgBezierTo(ctx,c1x,c1y,c2x,c2y,x + offset_x,y + offset_y); }
73-
inline auto quadTo( float cx, float cy, float x, float y) { return nvgQuadTo(ctx,cx,cy,x + offset_x,y + offset_y); }
74-
inline auto arcTo( float x1, float y1, float x2, float y2, float radius) { return nvgArcTo(ctx,x1,y1,x2,y2,radius); }
70+
inline auto bezierTo( float c1x, float c1y, float c2x, float c2y, float x, float y) { return nvgBezierTo(ctx,c1x + offset_x,c1y + offset_y,c2x,c2y,x + offset_x,y + offset_y); }
71+
inline auto quadTo( float cx, float cy, float x, float y) { return nvgQuadTo(ctx,cx + offset_x,cy + offset_y,x + offset_x,y + offset_y); }
72+
inline auto arcTo( float x1, float y1, float x2, float y2, float radius) { return nvgArcTo(ctx,x1 + offset_x,y1 + offset_y,x2 + offset_x,y2 + offset_y,radius); }
7573
inline auto closePath() { return nvgClosePath(ctx); }
7674
inline auto pathWinding( int dir) { return nvgPathWinding(ctx,dir); }
77-
inline auto arc( float cx, float cy, float r, float a0, float a1, int dir) { return nvgArc(ctx,cx,cy,r,a0,a1,dir); }
75+
inline auto arc( float cx, float cy, float r, float a0, float a1, int dir) { return nvgArc(ctx,cx + offset_x,cy + offset_y,r,a0,a1,dir); }
7876
inline auto rect( float x, float y, float w, float h) { return nvgRect(ctx,x + offset_x,y + offset_y,w,h); }
7977
inline auto roundedRect( float x, float y, float w, float h, float r) { return nvgRoundedRect(ctx,x + offset_x,y + offset_y,w,h,r); }
8078
inline auto roundedRectVarying( float x, float y, float w, float h, float radTopLeft, float radTopRight, float radBottomRight, float radBottomLeft) { return nvgRoundedRectVarying(ctx,x + offset_x,y + offset_y,w,h,radTopLeft,radTopRight,radBottomRight,radBottomLeft); }
81-
inline auto ellipse( float cx, float cy, float rx, float ry) { return nvgEllipse(ctx,cx,cy,rx,ry); }
82-
inline auto circle( float cx, float cy, float r) { return nvgCircle(ctx,cx,cy,r); }
79+
inline auto ellipse( float cx, float cy, float rx, float ry) { return nvgEllipse(ctx,cx + offset_x,cy + offset_y,rx,ry); }
80+
inline auto circle( float cx, float cy, float r) { return nvgCircle(ctx,cx + offset_x,cy + offset_y,r); }
8381
inline auto fill() { return nvgFill(ctx); }
8482
inline auto stroke() { return nvgStroke(ctx); }
8583
inline auto createFont( const char* name, const char* filename) { return nvgCreateFont(ctx,name,filename); }

0 commit comments

Comments
 (0)