feat(ags osk): allow adding borders to arc
All checks were successful
Discord / discord commits (push) Has been skipped
All checks were successful
Discord / discord commits (push) Has been skipped
This commit is contained in:
parent
dc2739f402
commit
cc189d6f64
2 changed files with 155 additions and 30 deletions
|
@ -29,6 +29,54 @@ export interface CursorPos {
|
||||||
y: number
|
y: number
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type PointProps = [number, number] | {
|
||||||
|
x: number
|
||||||
|
y: number
|
||||||
|
} | number;
|
||||||
|
|
||||||
|
export class Point {
|
||||||
|
public x = 0;
|
||||||
|
public y = 0;
|
||||||
|
|
||||||
|
get values(): [number, number] {
|
||||||
|
return [this.x, this.y];
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor(props?: PointProps, y?: number) {
|
||||||
|
if (typeof props === 'number') {
|
||||||
|
if (y) {
|
||||||
|
this.x = props;
|
||||||
|
this.y = y;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
throw new Error('Wrong props');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (Array.isArray(props)) {
|
||||||
|
this.x = props[0];
|
||||||
|
this.y = props[1];
|
||||||
|
}
|
||||||
|
else if (props) {
|
||||||
|
this.x = props.x;
|
||||||
|
this.y = props.y;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export type BezierPoints = [number, number, number, number];
|
||||||
|
|
||||||
|
export class Bezier {
|
||||||
|
private _points: BezierPoints;
|
||||||
|
|
||||||
|
get points() {
|
||||||
|
return [...this._points] as BezierPoints;
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor(x1: number, y1: number, x2: number, y2: number) {
|
||||||
|
this._points = [x1, y1, x2, y2];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
export const get_hyprland_monitor = (monitor: Gdk.Monitor): AstalHyprland.Monitor | undefined => {
|
export const get_hyprland_monitor = (monitor: Gdk.Monitor): AstalHyprland.Monitor | undefined => {
|
||||||
const hyprland = AstalHyprland.get_default();
|
const hyprland = AstalHyprland.get_default();
|
||||||
|
|
|
@ -1,12 +1,14 @@
|
||||||
import { Gtk } from 'astal/gtk3';
|
import { Gdk, Gtk } from 'astal/gtk3';
|
||||||
|
|
||||||
import Cairo from 'cairo';
|
import Cairo from 'cairo';
|
||||||
|
|
||||||
|
import { Bezier, BezierPoints, Point } from '../../lib';
|
||||||
|
|
||||||
/* Types */
|
/* Types */
|
||||||
interface Point {
|
type Side = 'top' | 'right' | 'bottom' | 'left';
|
||||||
x: number
|
|
||||||
y: number
|
|
||||||
}
|
const SIDES: Side[] = ['top', 'right', 'bottom', 'left'];
|
||||||
type Bezier = [number, number, number, number];
|
|
||||||
|
|
||||||
export default ({
|
export default ({
|
||||||
css = 'background-color: black;',
|
css = 'background-color: black;',
|
||||||
|
@ -19,47 +21,115 @@ export default ({
|
||||||
setup={(widget) => {
|
setup={(widget) => {
|
||||||
widget.set_size_request(allocation.width, allocation.height);
|
widget.set_size_request(allocation.width, allocation.height);
|
||||||
|
|
||||||
|
widget.connect('draw', (_, cairoContext: Cairo.Context) => {
|
||||||
|
widget.set_size_request(allocation.width, allocation.height);
|
||||||
|
|
||||||
const styleContext = widget.get_style_context();
|
const styleContext = widget.get_style_context();
|
||||||
|
|
||||||
const bgColor = styleContext.get_background_color(Gtk.StateFlags.NORMAL);
|
const bgColor = styleContext.get_background_color(Gtk.StateFlags.NORMAL);
|
||||||
|
|
||||||
widget.connect('draw', (_, cairoContext: Cairo.Context) => {
|
const borderWidth = styleContext.get_border(Gtk.StateFlags.NORMAL);
|
||||||
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]);
|
const borderColor = Object.fromEntries(SIDES.map((side) => [
|
||||||
curve[1] += cairoContext.getCurrentPoint()[1];
|
side,
|
||||||
|
styleContext.get_property(
|
||||||
|
`border-${side}-color`, Gtk.StateFlags.NORMAL,
|
||||||
|
) as Gdk.RGBA,
|
||||||
|
])) as Record<Side, Gdk.RGBA>;
|
||||||
|
|
||||||
curve[2] *= (dest.x - cairoContext.getCurrentPoint()[0]);
|
/*
|
||||||
curve[2] += cairoContext.getCurrentPoint()[0];
|
* Draws a cubic bezier curve from the current point
|
||||||
|
* of the cairo context.
|
||||||
|
*
|
||||||
|
* @param dest the destination point of the curve
|
||||||
|
* @param curve the cubic bezier's control points. this
|
||||||
|
* is the same as a CSS easing function
|
||||||
|
*/
|
||||||
|
const drawBezier = (dest: Point, curve: BezierPoints): void => {
|
||||||
|
const start = new Point(cairoContext.getCurrentPoint());
|
||||||
|
|
||||||
curve[3] *= (dest.y - cairoContext.getCurrentPoint()[1]);
|
// Converts the ratios to absolute coordinates
|
||||||
curve[3] += cairoContext.getCurrentPoint()[1];
|
curve[0] = curve[0] * (dest.x - start.x) + start.x;
|
||||||
|
curve[1] = curve[1] * (dest.y - start.y) + start.y;
|
||||||
|
curve[2] = curve[2] * (dest.x - start.x) + start.x;
|
||||||
|
curve[3] = curve[3] * (dest.y - start.y) + start.y;
|
||||||
|
|
||||||
cairoContext.curveTo(...curve, dest.x, dest.y);
|
cairoContext.curveTo(...curve, dest.x, dest.y);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const colorBorder = (
|
||||||
|
side: Side,
|
||||||
|
start: Point,
|
||||||
|
dest: Point,
|
||||||
|
curve?: BezierPoints,
|
||||||
|
) => {
|
||||||
|
cairoContext.moveTo(...start.values);
|
||||||
|
|
||||||
|
if (curve) {
|
||||||
|
drawBezier(dest, curve);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
cairoContext.lineTo(...dest.values);
|
||||||
|
}
|
||||||
|
|
||||||
|
cairoContext.setLineWidth(borderWidth[side]);
|
||||||
|
cairoContext.setSourceRGBA(
|
||||||
|
borderColor[side].red,
|
||||||
|
borderColor[side].green,
|
||||||
|
borderColor[side].blue,
|
||||||
|
borderColor[side].alpha,
|
||||||
|
);
|
||||||
|
|
||||||
|
cairoContext.stroke();
|
||||||
|
};
|
||||||
|
|
||||||
|
const bottomLeft = new Point({
|
||||||
|
x: 0,
|
||||||
|
y: allocation.height,
|
||||||
|
});
|
||||||
|
|
||||||
|
const topLeft = new Point({
|
||||||
|
x: 0,
|
||||||
|
y: 0,
|
||||||
|
});
|
||||||
|
|
||||||
|
const middleLeft = new Point({
|
||||||
|
x: allocation.width / 3,
|
||||||
|
y: allocation.height * 0.8,
|
||||||
|
});
|
||||||
|
|
||||||
|
const middleRight = new Point({
|
||||||
|
x: (allocation.width / 3) * 2,
|
||||||
|
y: allocation.height * 0.8,
|
||||||
|
});
|
||||||
|
|
||||||
|
const topRight = new Point({
|
||||||
|
x: allocation.width,
|
||||||
|
y: 0,
|
||||||
|
});
|
||||||
|
|
||||||
|
const bottomRight = new Point({
|
||||||
|
x: allocation.width,
|
||||||
|
y: allocation.height,
|
||||||
|
});
|
||||||
|
|
||||||
|
const bezier = new Bezier(0.76, 0, 0.24, 1);
|
||||||
|
|
||||||
// bottom left to top left
|
// bottom left to top left
|
||||||
cairoContext.moveTo(0, allocation.height);
|
cairoContext.moveTo(...bottomLeft.values);
|
||||||
cairoContext.lineTo(0, 0);
|
cairoContext.lineTo(...topLeft.values);
|
||||||
|
|
||||||
// top left to middle left
|
// top left to middle left
|
||||||
drawBezier(
|
drawBezier(middleLeft, bezier.points);
|
||||||
{ x: allocation.width / 3, y: allocation.height * 0.8 },
|
|
||||||
[0.76, 0, 0.24, 1],
|
|
||||||
);
|
|
||||||
|
|
||||||
// middle left to middle right
|
// middle left to middle right
|
||||||
cairoContext.lineTo((allocation.width / 3) * 2, allocation.height * 0.8);
|
cairoContext.lineTo(...middleRight.values);
|
||||||
|
|
||||||
// middle right to top right
|
// middle right to top right
|
||||||
drawBezier(
|
drawBezier(topRight, bezier.points);
|
||||||
{ x: allocation.width, y: 0 },
|
|
||||||
[0.76, 0, 0.24, 1],
|
|
||||||
);
|
|
||||||
|
|
||||||
// top right to bottom right
|
// top right to bottom right
|
||||||
cairoContext.lineTo(allocation.width, allocation.height);
|
cairoContext.lineTo(...bottomRight.values);
|
||||||
|
|
||||||
// bottom right to bottom left
|
// bottom right to bottom left
|
||||||
cairoContext.closePath();
|
cairoContext.closePath();
|
||||||
|
@ -67,6 +137,13 @@ export default ({
|
||||||
// Add color
|
// Add color
|
||||||
cairoContext.setSourceRGBA(bgColor.red, bgColor.green, bgColor.blue, bgColor.alpha);
|
cairoContext.setSourceRGBA(bgColor.red, bgColor.green, bgColor.blue, bgColor.alpha);
|
||||||
cairoContext.fill();
|
cairoContext.fill();
|
||||||
|
|
||||||
|
colorBorder('left', bottomLeft, topLeft);
|
||||||
|
colorBorder('top', topLeft, middleLeft, bezier.points);
|
||||||
|
colorBorder('top', middleLeft, middleRight);
|
||||||
|
colorBorder('top', middleRight, topRight, bezier.points);
|
||||||
|
colorBorder('right', topRight, bottomRight);
|
||||||
|
colorBorder('bottom', bottomLeft, bottomRight);
|
||||||
});
|
});
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
|
Loading…
Reference in a new issue