mirror of
https://github.com/end-4/dots-hyprland.git
synced 2026-06-05 23:09:26 -05:00
sideleft: new tool: conversions
This commit is contained in:
@@ -1,4 +1,10 @@
|
||||
|
||||
export function clamp(x, min, max) {
|
||||
return Math.min(Math.max(x, min), max);
|
||||
}
|
||||
|
||||
export function truncateToPrecision(value, precision) {
|
||||
const factor = Math.pow(10, precision);
|
||||
const result = Math.round(value * factor) / factor;
|
||||
return result;
|
||||
}
|
||||
@@ -2,6 +2,7 @@ import Widget from 'resource:///com/github/Aylur/ags/widget.js';
|
||||
const { Box, Label, Scrollable } = Widget;
|
||||
import QuickScripts from './tools/quickscripts.js';
|
||||
import ColorPicker from './tools/colorpicker.js';
|
||||
import Conversions from './tools/conversions.js';
|
||||
import Name from './tools/name.js';
|
||||
|
||||
export default Scrollable({
|
||||
@@ -12,6 +13,7 @@ export default Scrollable({
|
||||
className: 'spacing-v-10',
|
||||
children: [
|
||||
QuickScripts(),
|
||||
Conversions(),
|
||||
ColorPicker(),
|
||||
Box({ vexpand: true }),
|
||||
Name(),
|
||||
|
||||
@@ -0,0 +1,169 @@
|
||||
const { Gtk } = imports.gi;
|
||||
import App from 'resource:///com/github/Aylur/ags/app.js';
|
||||
import Widget from 'resource:///com/github/Aylur/ags/widget.js';
|
||||
import * as Utils from 'resource:///com/github/Aylur/ags/utils.js';
|
||||
const { execAsync, exec } = Utils;
|
||||
const { Box, Button, Entry, EventBox, Icon, Label, Scrollable, Overlay } = Widget;
|
||||
import SidebarModule from './module.js';
|
||||
import { MaterialIcon } from '../../.commonwidgets/materialicon.js';
|
||||
import { setupCursorHover } from '../../.widgetutils/cursorhover.js';
|
||||
import { truncateToPrecision } from '../../.miscutils/mathfuncs.js';
|
||||
|
||||
const VALUE_DEFAULT_PRECISION = 3;
|
||||
const conversions = [
|
||||
{
|
||||
unit1: 'px',
|
||||
unit2: 'rem',
|
||||
unit1Default: 5,
|
||||
formula1to2: '{{x}} / (parseFloat(Utils.exec(\'gsettings get org.gnome.desktop.interface font-name\').split(" ")[1].split("\'"))*4/3)',
|
||||
formula2to1: '{{x}} * 3 / 4',
|
||||
forcePrecision: true,
|
||||
},
|
||||
{
|
||||
unit1: 'degrees',
|
||||
unit2: 'radians',
|
||||
unit1Default: 90,
|
||||
formula1to2: '{{x}} * Math.PI / 180',
|
||||
formula2to1: '{{x}} * 180 / Math.PI',
|
||||
},
|
||||
{
|
||||
unit1: '°F',
|
||||
unit2: '°C',
|
||||
unit1Default: 68,
|
||||
formula1to2: '({{x}} - 32) * 5 / 9',
|
||||
formula2to1: '{{x}} * 9 / 5 + 32',
|
||||
},
|
||||
{
|
||||
unit1: 'Ft',
|
||||
unit2: 'Cm',
|
||||
formula1to2: '{{x}} * 30.48',
|
||||
formula2to1: '{{x}} / 30.48',
|
||||
},
|
||||
// {
|
||||
// unit1: 'Mile',
|
||||
// unit2: 'Km',
|
||||
// formula1to2: '{{x}} * 1.60934',
|
||||
// formula2to1: '{{x}} / 1.60934',
|
||||
// },
|
||||
// {
|
||||
// unit1: 'Inch',
|
||||
// unit2: 'Cm',
|
||||
// formula1to2: '{{x}} * 2.54',
|
||||
// formula2to1: '{{x}} / 2.54',
|
||||
// },
|
||||
{
|
||||
unit1: 'lbs',
|
||||
unit2: 'Kg',
|
||||
formula1to2: '{{x}} * 0.453592',
|
||||
formula2to1: '{{x}} / 0.453592',
|
||||
}
|
||||
]
|
||||
|
||||
export default () => {
|
||||
const ValueBox = ({ unit, initValue = 0, updateCallback }) => {
|
||||
const unitName = Label({
|
||||
xalign: 0,
|
||||
className: 'txt txt-smallie',
|
||||
label: `${unit}`,
|
||||
});
|
||||
const entry = Entry({
|
||||
hexpand: 'true',
|
||||
widthChars: 10,
|
||||
className: 'txt-small techfont',
|
||||
text: `${initValue}`,
|
||||
onChange: updateCallback,
|
||||
});
|
||||
const copyButton = Button({
|
||||
className: 'sidebar-module-csscalc-valuebox-copybtn',
|
||||
child: MaterialIcon('content_copy', 'norm'),
|
||||
onClicked: (self) => {
|
||||
Utils.execAsync(['wl-copy', entry.text]);
|
||||
self.child.label = 'done';
|
||||
Utils.timeout(1000, () => self.child.label = 'content_copy');
|
||||
},
|
||||
setup: setupCursorHover,
|
||||
});
|
||||
const wholeThing = Box({
|
||||
className: 'sidebar-module-csscalc-valuebox',
|
||||
vertical: true,
|
||||
hexpand: true,
|
||||
children: [
|
||||
unitName,
|
||||
Box({
|
||||
children: [
|
||||
entry,
|
||||
copyButton,
|
||||
]
|
||||
})
|
||||
],
|
||||
attribute: {
|
||||
updateValue: (value) => entry.text = `${value}`,
|
||||
getValue: () => entry.text,
|
||||
}
|
||||
});
|
||||
return wholeThing;
|
||||
}
|
||||
// Formula format is js expression, with `{{x}}` being the input value
|
||||
const BidirectionalConversion = ({
|
||||
unit1, unit2, unit1Default = 1,
|
||||
formula1to2, formula2to1,
|
||||
forcePrecision = false, precision = VALUE_DEFAULT_PRECISION,
|
||||
}) => {
|
||||
let updateLock = false;
|
||||
const convert = (value, formula) => {
|
||||
let thisValue;
|
||||
try {
|
||||
thisValue = eval(value)
|
||||
} catch (error) {
|
||||
thisValue = parseFloat(value);
|
||||
}
|
||||
// print(formula.replace('{{x}}', thisValue))
|
||||
// print(eval(formula.replace('{{x}}', thisValue)))
|
||||
const evalResult = eval(formula.replace('{{x}}', thisValue));
|
||||
const result = forcePrecision ?
|
||||
evalResult.toFixed(precision) : truncateToPrecision(evalResult, precision);
|
||||
// print(result)
|
||||
return result;
|
||||
}
|
||||
const unit1Box = ValueBox({
|
||||
unit: unit1,
|
||||
initValue: unit1Default,
|
||||
updateCallback: (self) => {
|
||||
if (updateLock) return;
|
||||
updateLock = true;
|
||||
const newValue = convert(self.text, formula1to2);
|
||||
unit2Box.attribute.updateValue(newValue || 0);
|
||||
updateLock = false;
|
||||
},
|
||||
});
|
||||
const unit2Box = ValueBox({
|
||||
unit: unit2,
|
||||
initValue: truncateToPrecision(eval(formula1to2.replace('\{{x}}', unit1Default)), precision),
|
||||
updateCallback: (self) => {
|
||||
if (updateLock) return;
|
||||
updateLock = true;
|
||||
const newValue = convert(self.text, formula2to1);
|
||||
unit1Box.attribute.updateValue(newValue || 0);
|
||||
updateLock = false;
|
||||
},
|
||||
});
|
||||
return Box({
|
||||
className: 'txt spacing-h-10',
|
||||
children: [
|
||||
unit1Box,
|
||||
MaterialIcon('swap_horiz', 'large'),
|
||||
unit2Box,
|
||||
]
|
||||
})
|
||||
}
|
||||
|
||||
return SidebarModule({
|
||||
icon: MaterialIcon('autorenew', 'norm'),
|
||||
name: getString('Conversions'),
|
||||
child: Box({
|
||||
vertical: true,
|
||||
className: 'spacing-v-5',
|
||||
children: conversions.map(BidirectionalConversion),
|
||||
})
|
||||
});
|
||||
}
|
||||
@@ -14,6 +14,11 @@ $rounding_large: 1.705rem;
|
||||
border-radius: $rounding_unsharpen;
|
||||
}
|
||||
|
||||
@mixin verysmall-rounding {
|
||||
border-radius: $rounding_verysmall;
|
||||
-gtk-outline-radius: $rounding_verysmall;
|
||||
}
|
||||
|
||||
@mixin small-rounding {
|
||||
border-radius: $rounding_small;
|
||||
-gtk-outline-radius: $rounding_small;
|
||||
|
||||
@@ -510,6 +510,31 @@ $colorpicker_rounding: 0.341rem;
|
||||
padding: 0.341rem;
|
||||
}
|
||||
|
||||
.sidebar-module-csscalc-valuebox {
|
||||
@include small-rounding;
|
||||
padding: 0.341rem;
|
||||
background-color: $layer2;
|
||||
color: $onLayer2;
|
||||
}
|
||||
|
||||
.sidebar-module-csscalc-valuebox-copybtn {
|
||||
@include verysmall-rounding;
|
||||
@include element_decel;
|
||||
min-width: 1.705rem;
|
||||
min-height: 1.705rem;
|
||||
background-color: $layer2;
|
||||
color: $onLayer2;
|
||||
|
||||
&:hover,
|
||||
&:focus {
|
||||
background-color: $layer2Hover;
|
||||
}
|
||||
|
||||
&:active {
|
||||
background-color: $layer2Active;
|
||||
}
|
||||
}
|
||||
|
||||
.sidebar-icontabswitcher {
|
||||
@include full-rounding;
|
||||
@include group-padding;
|
||||
|
||||
Reference in New Issue
Block a user