feat(ags osk): add cairo arc for fun
All checks were successful
Discord / discord commits (push) Has been skipped

This commit is contained in:
matt1432 2024-11-26 19:25:02 -05:00
parent 7775cb71b6
commit 88d0a52a4e
4 changed files with 219 additions and 95 deletions

View file

@ -132,6 +132,7 @@ export default tseslint.config({
'no-loop-func': [ 'no-loop-func': [
'error', 'error',
], ],
/*
'no-magic-numbers': [ 'no-magic-numbers': [
'error', 'error',
{ {
@ -159,6 +160,7 @@ export default tseslint.config({
ignoreClassFieldInitialValues: true, ignoreClassFieldInitialValues: true,
}, },
], ],
*/
'no-multi-assign': [ 'no-multi-assign': [
'error', 'error',
], ],

View file

@ -18,7 +18,6 @@
.osk { .osk {
padding-top: 4px; padding-top: 4px;
border-radius: 10px 10px 0;
&.hidden { &.hidden {
opacity: 0; opacity: 0;
@ -83,6 +82,8 @@
} }
&.right-side { &.right-side {
border-radius: 0 10px 0 0;
.key .mod { .key .mod {
&.Ctrl { &.Ctrl {
min-width: 2.4rem; min-width: 2.4rem;
@ -91,6 +92,8 @@
} }
&.left-side { &.left-side {
border-radius: 10px 0 0 0;
.key .mod { .key .mod {
&.Alt { &.Alt {
min-width: 3rem; min-width: 3rem;

View file

@ -0,0 +1,74 @@
import { Gtk } from 'astal/gtk3';
import Cairo from 'cairo';
/* Types */
interface Point {
x: number
y: number
}
type Bezier = [number, number, number, number];
export default ({
css = 'background-color: black;',
allocation = { width: 0, height: 0 },
}) => (
<box>
<drawingarea
css={css}
setup={(widget) => {
widget.set_size_request(allocation.width, allocation.height);
const styleContext = widget.get_style_context();
const bgColor = styleContext.get_background_color(Gtk.StateFlags.NORMAL);
widget.connect('draw', (_, cairoContext: Cairo.Context) => {
const drawBezier = (dest: Point, curve: Bezier) => {
curve[0] *= (dest.x - cairoContext.getCurrentPoint()[0]);
curve[0] += cairoContext.getCurrentPoint()[0];
curve[1] *= (dest.y - cairoContext.getCurrentPoint()[1]);
curve[1] += cairoContext.getCurrentPoint()[1];
curve[2] *= (dest.x - cairoContext.getCurrentPoint()[0]);
curve[2] += cairoContext.getCurrentPoint()[0];
curve[3] *= (dest.y - cairoContext.getCurrentPoint()[1]);
curve[3] += cairoContext.getCurrentPoint()[1];
cairoContext.curveTo(...curve, dest.x, dest.y);
};
// bottom left to top left
cairoContext.moveTo(0, allocation.height);
cairoContext.lineTo(0, 0);
// top left to middle left
drawBezier(
{ x: allocation.width / 3, y: allocation.height * 0.8 },
[0.76, 0, 0.24, 1],
);
// middle left to middle right
cairoContext.lineTo((allocation.width / 3) * 2, allocation.height * 0.8);
// middle right to top right
drawBezier(
{ x: allocation.width, y: 0 },
[0.76, 0, 0.24, 1],
);
// top right to bottom right
cairoContext.lineTo(allocation.width, allocation.height);
// bottom right to bottom left
cairoContext.closePath();
// Add color
cairoContext.setSourceRGBA(bgColor.red, bgColor.green, bgColor.blue, bgColor.alpha);
cairoContext.fill();
});
}}
/>
</box>
);

View file

@ -1,8 +1,10 @@
import { bind, idle, Variable } from 'astal';
import { Astal, astalify, Gtk, type ConstructProps, Widget } from 'astal/gtk3'; import { Astal, astalify, Gtk, type ConstructProps, Widget } from 'astal/gtk3';
import { register } from 'astal/gobject'; import { register } from 'astal/gobject';
import Separator from '../misc/separator'; import Separator from '../misc/separator';
import Arc from './arcs';
import Key from './keys'; import Key from './keys';
import { defaultOskLayout, oskLayouts } from './keyboard-layouts'; import { defaultOskLayout, oskLayouts } from './keyboard-layouts';
@ -22,110 +24,153 @@ class ToggleButton extends astalify(Gtk.ToggleButton) {
} }
} }
const L_KEY_PER_ROW = [8, 7, 6, 6, 6, 4]; // eslint-disable-line const L_KEY_PER_ROW = [8, 7, 6, 6, 6, 4];
const COLOR = 'rgba(0, 0, 0, 0.3)';
const SPACING = 4; const SPACING = 4;
const COLOR = 'rgba(0, 0, 0, 0.3)';
export default () => ( export default () => {
<box vertical> const ThirdWidth = Variable(0);
<centerbox
css={`background: ${COLOR};`} return (
className="osk hidden" <box
hexpand vertical
onRealize={(self) => idle(() => {
ThirdWidth.set(self.get_allocated_width() / 3);
})}
> >
<box <centerbox
className="left-side side" className="osk hidden"
halign={Gtk.Align.START} hexpand
vertical
>
{...keyboardJson.keys.map((row, rowIndex) => {
const keys = [] as Widget.Box[];
row.forEach((key, keyIndex) => {
if (keyIndex < L_KEY_PER_ROW[rowIndex]) {
keys.push(Key(key));
}
});
return (
<box vertical>
<box className="row">
<Separator size={SPACING} />
{...keys}
</box>
<Separator size={SPACING} vertical />
</box>
);
})}
</box>
<box
halign={Gtk.Align.CENTER}
valign={Gtk.Align.END}
> >
{/* LEFT */}
<box <box
halign={Gtk.Align.CENTER} widthRequest={bind(ThirdWidth)}
className="settings" css={`background: ${COLOR};`}
className="left-side side"
halign={Gtk.Align.START}
vertical
> >
<ToggleButton {...keyboardJson.keys.map((row, rowIndex) => {
className="button" const keys = [] as Widget.Box[];
cursor="pointer"
active
valign={Gtk.Align.CENTER}
onToggled={(self) => { row.forEach((key, keyIndex) => {
self.toggleClassName( if (keyIndex < L_KEY_PER_ROW[rowIndex]) {
'toggled', keys.push(Key(key));
self.get_active(),
);
if (self.get_toplevel() === self) {
return;
} }
});
(self.get_toplevel() as Widget.Window | undefined) return (
?.set_exclusivity( <box vertical>
self.get_active() ? <box className="row">
Astal.Exclusivity.EXCLUSIVE : <Separator size={SPACING} />
Astal.Exclusivity.NORMAL,
);
}}
>
Exclusive
</ToggleButton>
</box>
</box>
<box {...keys}
className="right-side side" </box>
halign={Gtk.Align.END}
vertical
>
{...keyboardJson.keys.map((row, rowIndex) => {
const keys = [] as Widget.Box[];
row.forEach((key, keyIndex) => { <Separator size={SPACING} vertical />
if (keyIndex >= L_KEY_PER_ROW[rowIndex]) {
keys.push(Key(key));
}
});
return (
<box vertical>
<box
className="row"
halign={Gtk.Align.END}
>
{...keys}
</box> </box>
);
})}
</box>
<Separator size={SPACING} vertical /> {/* MIDDLE */}
</box> <box
); widthRequest={bind(ThirdWidth)}
})} halign={Gtk.Align.CENTER}
</box> valign={Gtk.Align.FILL}
</centerbox> vertical
</box> >
) as Widget.Box; <box
valign={Gtk.Align.START}
>
{bind(ThirdWidth).as((width) => (
<Arc
allocation={{ width, height: 160 }}
css={`background: ${COLOR};`}
/>
))}
</box>
<box
halign={Gtk.Align.FILL}
hexpand
vexpand
css={`background: ${COLOR};`}
className="settings"
>
<centerbox
halign={Gtk.Align.FILL}
hexpand
vexpand
>
<box />
<ToggleButton
className="button"
cursor="pointer"
active
valign={Gtk.Align.CENTER}
halign={Gtk.Align.CENTER}
onToggled={(self) => {
self.toggleClassName(
'toggled',
self.get_active(),
);
if (self.get_toplevel() === self) {
return;
}
(self.get_toplevel() as Widget.Window | undefined)
?.set_exclusivity(
self.get_active() ?
Astal.Exclusivity.EXCLUSIVE :
Astal.Exclusivity.NORMAL,
);
}}
>
Exclusive
</ToggleButton>
<box />
</centerbox>
</box>
</box>
{/* RIGHT */}
<box
widthRequest={bind(ThirdWidth)}
css={`background: ${COLOR};`}
className="right-side side"
halign={Gtk.Align.END}
vertical
>
{...keyboardJson.keys.map((row, rowIndex) => {
const keys = [] as Widget.Box[];
row.forEach((key, keyIndex) => {
if (keyIndex >= L_KEY_PER_ROW[rowIndex]) {
keys.push(Key(key));
}
});
return (
<box vertical>
<box
className="row"
halign={Gtk.Align.END}
>
{...keys}
</box>
<Separator size={SPACING} vertical />
</box>
);
})}
</box>
</centerbox>
</box>
) as Widget.Box;
};