hyprpanel
This commit is contained in:
1 parent
10080a83ee
commit
5151ac24da
322 files changed
+38276
No files matched your search
@@ -0,0 +1,77 @@
|
||||
import GLib from 'gi://GLib?version=2.0';
|
||||
import { GenericFunction } from 'lib/types/customModules/generic';
|
||||
import { Bind } from 'lib/types/variable';
|
||||
import { Variable as VariableType } from 'types/variable';
|
||||
|
||||
/**
|
||||
* @param {VariableType<T>} targetVariable - The Variable to update with the function's result.
|
||||
* @param {Array<Bind>} trackers - Array of trackers to watch.
|
||||
* @param {Bind} pollingInterval - The polling interval in milliseconds.
|
||||
* @param {GenericFunction<T, P>} someFunc - The function to execute at each interval, which updates the Variable.
|
||||
* @param {...P} params - Parameters to pass to someFunc.
|
||||
*/
|
||||
export const pollVariable = <T, P extends unknown[], F extends GenericFunction<T, P>>(
|
||||
targetVariable: VariableType<T>,
|
||||
trackers: Array<Bind>,
|
||||
pollingInterval: Bind,
|
||||
someFunc: F,
|
||||
...params: P
|
||||
): void => {
|
||||
let intervalInstance: number | null = null;
|
||||
|
||||
const intervalFn = (pollIntrvl: number): void => {
|
||||
if (intervalInstance !== null) {
|
||||
GLib.source_remove(intervalInstance);
|
||||
}
|
||||
|
||||
intervalInstance = Utils.interval(pollIntrvl, () => {
|
||||
targetVariable.value = someFunc(...params);
|
||||
});
|
||||
};
|
||||
|
||||
Utils.merge([pollingInterval, ...trackers], (pollIntrvl: number) => {
|
||||
intervalFn(pollIntrvl);
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {VariableType<T>} targetVariable - The Variable to update with the result of the command.
|
||||
* @param {Array<Bind>} trackers - Array of trackers to watch.
|
||||
* @param {Bind} pollingInterval - The polling interval in milliseconds.
|
||||
* @param {string} someCommand - The bash command to execute.
|
||||
* @param {GenericFunction<T, [unknown, ...P]>} someFunc - The function to execute after processing the command result;
|
||||
* with the first argument being the result of the command execution.
|
||||
* @param {...P} params - Additional parameters to pass to someFunc.
|
||||
*/
|
||||
export const pollVariableBash = <T, P extends unknown[], F extends GenericFunction<T, [string, ...P]>>(
|
||||
targetVariable: VariableType<T>,
|
||||
trackers: Array<Bind>,
|
||||
pollingInterval: Bind,
|
||||
someCommand: string,
|
||||
someFunc: F,
|
||||
...params: P
|
||||
): void => {
|
||||
let intervalInstance: number | null = null;
|
||||
|
||||
const intervalFn = (pollIntrvl: number): void => {
|
||||
if (intervalInstance !== null) {
|
||||
GLib.source_remove(intervalInstance);
|
||||
}
|
||||
|
||||
intervalInstance = Utils.interval(pollIntrvl, () => {
|
||||
Utils.execAsync(`bash -c "${someCommand}"`)
|
||||
.then((res: string) => {
|
||||
try {
|
||||
targetVariable.value = someFunc(res, ...params);
|
||||
} catch (error) {
|
||||
console.warn(`An error occurred when running interval bash function: ${error}`);
|
||||
}
|
||||
})
|
||||
.catch((err) => console.error(`Error running command "${someCommand}": ${err}`));
|
||||
});
|
||||
};
|
||||
|
||||
Utils.merge([pollingInterval, ...trackers], (pollIntrvl: number) => {
|
||||
intervalFn(pollIntrvl);
|
||||
});
|
||||
};
|
||||
@@ -0,0 +1,595 @@
|
||||
import { Option } from 'widget/settings/shared/Option';
|
||||
import { Header } from 'widget/settings/shared/Header';
|
||||
|
||||
import options from 'options';
|
||||
import Scrollable from 'types/widgets/scrollable';
|
||||
import { Attribute, GtkWidget } from 'lib/types/widget';
|
||||
|
||||
export const CustomModuleSettings = (): Scrollable<GtkWidget, Attribute> =>
|
||||
Widget.Scrollable({
|
||||
vscroll: 'automatic',
|
||||
hscroll: 'automatic',
|
||||
class_name: 'menu-theme-page customModules paged-container',
|
||||
child: Widget.Box({
|
||||
class_name: 'menu-theme-page paged-container',
|
||||
vertical: true,
|
||||
children: [
|
||||
/*
|
||||
************************************
|
||||
* GENERAL *
|
||||
************************************
|
||||
*/
|
||||
Header('General'),
|
||||
Option({
|
||||
opt: options.bar.customModules.scrollSpeed,
|
||||
title: 'Scrolling Speed',
|
||||
type: 'number',
|
||||
}),
|
||||
|
||||
/*
|
||||
************************************
|
||||
* RAM *
|
||||
************************************
|
||||
*/
|
||||
Header('RAM'),
|
||||
Option({
|
||||
opt: options.theme.bar.buttons.modules.ram.enableBorder,
|
||||
title: 'Button Border',
|
||||
type: 'boolean',
|
||||
}),
|
||||
Option({
|
||||
opt: options.bar.customModules.ram.icon,
|
||||
title: 'Ram Icon',
|
||||
type: 'string',
|
||||
}),
|
||||
Option({
|
||||
opt: options.bar.customModules.ram.label,
|
||||
title: 'Show Label',
|
||||
type: 'boolean',
|
||||
}),
|
||||
Option({
|
||||
opt: options.theme.bar.buttons.modules.ram.spacing,
|
||||
title: 'Spacing',
|
||||
type: 'string',
|
||||
}),
|
||||
Option({
|
||||
opt: options.bar.customModules.ram.labelType,
|
||||
title: 'Label Type',
|
||||
type: 'enum',
|
||||
enums: ['used/total', 'used', 'free', 'percentage'],
|
||||
}),
|
||||
Option({
|
||||
opt: options.bar.customModules.ram.round,
|
||||
title: 'Round',
|
||||
type: 'boolean',
|
||||
}),
|
||||
Option({
|
||||
opt: options.bar.customModules.ram.pollingInterval,
|
||||
title: 'Polling Interval',
|
||||
type: 'number',
|
||||
min: 100,
|
||||
max: 60 * 24 * 1000,
|
||||
increment: 1000,
|
||||
}),
|
||||
Option({
|
||||
opt: options.bar.customModules.ram.leftClick,
|
||||
title: 'Left Click',
|
||||
type: 'string',
|
||||
}),
|
||||
Option({
|
||||
opt: options.bar.customModules.ram.rightClick,
|
||||
title: 'Right Click',
|
||||
type: 'string',
|
||||
}),
|
||||
Option({
|
||||
opt: options.bar.customModules.ram.middleClick,
|
||||
title: 'Middle Click',
|
||||
type: 'string',
|
||||
}),
|
||||
|
||||
/*
|
||||
************************************
|
||||
* CPU *
|
||||
************************************
|
||||
*/
|
||||
Header('CPU'),
|
||||
Option({
|
||||
opt: options.theme.bar.buttons.modules.cpu.enableBorder,
|
||||
title: 'Button Border',
|
||||
type: 'boolean',
|
||||
}),
|
||||
Option({
|
||||
opt: options.bar.customModules.cpu.icon,
|
||||
title: 'Cpu Icon',
|
||||
type: 'string',
|
||||
}),
|
||||
Option({
|
||||
opt: options.bar.customModules.cpu.label,
|
||||
title: 'Show Label',
|
||||
type: 'boolean',
|
||||
}),
|
||||
Option({
|
||||
opt: options.theme.bar.buttons.modules.cpu.spacing,
|
||||
title: 'Spacing',
|
||||
type: 'string',
|
||||
}),
|
||||
Option({
|
||||
opt: options.bar.customModules.cpu.round,
|
||||
title: 'Round',
|
||||
type: 'boolean',
|
||||
}),
|
||||
Option({
|
||||
opt: options.bar.customModules.cpu.pollingInterval,
|
||||
title: 'Polling Interval',
|
||||
type: 'number',
|
||||
min: 100,
|
||||
max: 60 * 24 * 1000,
|
||||
increment: 1000,
|
||||
}),
|
||||
Option({
|
||||
opt: options.bar.customModules.cpu.leftClick,
|
||||
title: 'Left Click',
|
||||
type: 'string',
|
||||
}),
|
||||
Option({
|
||||
opt: options.bar.customModules.cpu.rightClick,
|
||||
title: 'Right Click',
|
||||
type: 'string',
|
||||
}),
|
||||
Option({
|
||||
opt: options.bar.customModules.cpu.middleClick,
|
||||
title: 'Middle Click',
|
||||
type: 'string',
|
||||
}),
|
||||
Option({
|
||||
opt: options.bar.customModules.cpu.scrollUp,
|
||||
title: 'Scroll Up',
|
||||
type: 'string',
|
||||
}),
|
||||
Option({
|
||||
opt: options.bar.customModules.cpu.scrollDown,
|
||||
title: 'Scroll Down',
|
||||
type: 'string',
|
||||
}),
|
||||
|
||||
/*
|
||||
************************************
|
||||
* STORAGE *
|
||||
************************************
|
||||
*/
|
||||
Header('Storage'),
|
||||
Option({
|
||||
opt: options.theme.bar.buttons.modules.storage.enableBorder,
|
||||
title: 'Button Border',
|
||||
type: 'boolean',
|
||||
}),
|
||||
Option({
|
||||
opt: options.bar.customModules.storage.icon,
|
||||
title: 'Storage Icon',
|
||||
type: 'string',
|
||||
}),
|
||||
Option({
|
||||
opt: options.bar.customModules.storage.label,
|
||||
title: 'Show Label',
|
||||
type: 'boolean',
|
||||
}),
|
||||
Option({
|
||||
opt: options.theme.bar.buttons.modules.storage.spacing,
|
||||
title: 'Spacing',
|
||||
type: 'string',
|
||||
}),
|
||||
Option({
|
||||
opt: options.bar.customModules.storage.labelType,
|
||||
title: 'Label Type',
|
||||
type: 'enum',
|
||||
enums: ['used/total', 'used', 'free', 'percentage'],
|
||||
}),
|
||||
Option({
|
||||
opt: options.bar.customModules.storage.round,
|
||||
title: 'Round',
|
||||
type: 'boolean',
|
||||
}),
|
||||
Option({
|
||||
opt: options.bar.customModules.storage.pollingInterval,
|
||||
title: 'Polling Interval',
|
||||
type: 'number',
|
||||
min: 100,
|
||||
max: 60 * 24 * 1000,
|
||||
increment: 1000,
|
||||
}),
|
||||
Option({
|
||||
opt: options.bar.customModules.storage.leftClick,
|
||||
title: 'Left Click',
|
||||
type: 'string',
|
||||
}),
|
||||
Option({
|
||||
opt: options.bar.customModules.storage.rightClick,
|
||||
title: 'Right Click',
|
||||
type: 'string',
|
||||
}),
|
||||
Option({
|
||||
opt: options.bar.customModules.storage.middleClick,
|
||||
title: 'Middle Click',
|
||||
type: 'string',
|
||||
}),
|
||||
|
||||
/*
|
||||
************************************
|
||||
* NETSTAT *
|
||||
************************************
|
||||
*/
|
||||
Header('Netstat'),
|
||||
Option({
|
||||
opt: options.theme.bar.buttons.modules.netstat.enableBorder,
|
||||
title: 'Button Border',
|
||||
type: 'boolean',
|
||||
}),
|
||||
Option({
|
||||
opt: options.bar.customModules.netstat.networkInterface,
|
||||
title: 'Network Interface',
|
||||
subtitle:
|
||||
"Name of the network interface to poll.\nHINT: Get list of interfaces with 'cat /proc/net/dev'",
|
||||
type: 'string',
|
||||
}),
|
||||
Option({
|
||||
opt: options.bar.customModules.netstat.icon,
|
||||
title: 'Netstat Icon',
|
||||
type: 'string',
|
||||
}),
|
||||
Option({
|
||||
opt: options.bar.customModules.netstat.label,
|
||||
title: 'Show Label',
|
||||
type: 'boolean',
|
||||
}),
|
||||
Option({
|
||||
opt: options.bar.customModules.netstat.rateUnit,
|
||||
title: 'Rate Unit',
|
||||
type: 'enum',
|
||||
enums: ['GiB', 'MiB', 'KiB', 'auto'],
|
||||
}),
|
||||
Option({
|
||||
opt: options.theme.bar.buttons.modules.netstat.spacing,
|
||||
title: 'Spacing',
|
||||
type: 'string',
|
||||
}),
|
||||
Option({
|
||||
opt: options.bar.customModules.netstat.labelType,
|
||||
title: 'Label Type',
|
||||
type: 'enum',
|
||||
enums: ['full', 'in', 'out'],
|
||||
}),
|
||||
Option({
|
||||
opt: options.bar.customModules.netstat.round,
|
||||
title: 'Round',
|
||||
type: 'boolean',
|
||||
}),
|
||||
Option({
|
||||
opt: options.bar.customModules.netstat.pollingInterval,
|
||||
title: 'Polling Interval',
|
||||
type: 'number',
|
||||
min: 100,
|
||||
max: 60 * 24 * 1000,
|
||||
increment: 1000,
|
||||
}),
|
||||
Option({
|
||||
opt: options.bar.customModules.netstat.leftClick,
|
||||
title: 'Left Click',
|
||||
type: 'string',
|
||||
}),
|
||||
Option({
|
||||
opt: options.bar.customModules.netstat.rightClick,
|
||||
title: 'Right Click',
|
||||
type: 'string',
|
||||
}),
|
||||
Option({
|
||||
opt: options.bar.customModules.netstat.middleClick,
|
||||
title: 'Middle Click',
|
||||
type: 'string',
|
||||
}),
|
||||
|
||||
/*
|
||||
************************************
|
||||
* KEYBOARD LAYOUT *
|
||||
************************************
|
||||
*/
|
||||
Header('Keyboard Layout'),
|
||||
Option({
|
||||
opt: options.theme.bar.buttons.modules.kbLayout.enableBorder,
|
||||
title: 'Button Border',
|
||||
type: 'boolean',
|
||||
}),
|
||||
Option({
|
||||
opt: options.bar.customModules.kbLayout.icon,
|
||||
title: 'Keyboard Layout Icon',
|
||||
type: 'string',
|
||||
}),
|
||||
Option({
|
||||
opt: options.bar.customModules.kbLayout.label,
|
||||
title: 'Show Label',
|
||||
type: 'boolean',
|
||||
}),
|
||||
Option({
|
||||
opt: options.bar.customModules.kbLayout.labelType,
|
||||
title: 'Label Type',
|
||||
type: 'enum',
|
||||
enums: ['layout', 'code'],
|
||||
}),
|
||||
Option({
|
||||
opt: options.theme.bar.buttons.modules.kbLayout.spacing,
|
||||
title: 'Spacing',
|
||||
type: 'string',
|
||||
}),
|
||||
Option({
|
||||
opt: options.bar.customModules.kbLayout.leftClick,
|
||||
title: 'Left Click',
|
||||
type: 'string',
|
||||
}),
|
||||
Option({
|
||||
opt: options.bar.customModules.kbLayout.rightClick,
|
||||
title: 'Right Click',
|
||||
type: 'string',
|
||||
}),
|
||||
Option({
|
||||
opt: options.bar.customModules.kbLayout.middleClick,
|
||||
title: 'Middle Click',
|
||||
type: 'string',
|
||||
}),
|
||||
Option({
|
||||
opt: options.bar.customModules.kbLayout.scrollUp,
|
||||
title: 'Scroll Up',
|
||||
type: 'string',
|
||||
}),
|
||||
Option({
|
||||
opt: options.bar.customModules.kbLayout.scrollDown,
|
||||
title: 'Scroll Down',
|
||||
type: 'string',
|
||||
}),
|
||||
|
||||
/*
|
||||
************************************
|
||||
* UPDATES *
|
||||
************************************
|
||||
*/
|
||||
Header('Updates'),
|
||||
Option({
|
||||
opt: options.theme.bar.buttons.modules.updates.enableBorder,
|
||||
title: 'Button Border',
|
||||
type: 'boolean',
|
||||
}),
|
||||
Option({
|
||||
opt: options.bar.customModules.updates.updateCommand,
|
||||
title: 'Check Updates Command',
|
||||
type: 'string',
|
||||
}),
|
||||
Option({
|
||||
opt: options.bar.customModules.updates.icon,
|
||||
title: 'Updates Icon',
|
||||
type: 'string',
|
||||
}),
|
||||
Option({
|
||||
opt: options.bar.customModules.updates.label,
|
||||
title: 'Show Label',
|
||||
type: 'boolean',
|
||||
}),
|
||||
Option({
|
||||
opt: options.bar.customModules.updates.padZero,
|
||||
title: 'Pad with 0',
|
||||
type: 'boolean',
|
||||
}),
|
||||
Option({
|
||||
opt: options.theme.bar.buttons.modules.updates.spacing,
|
||||
title: 'Spacing',
|
||||
type: 'string',
|
||||
}),
|
||||
Option({
|
||||
opt: options.bar.customModules.updates.pollingInterval,
|
||||
title: 'Polling Interval',
|
||||
type: 'number',
|
||||
subtitle: "WARNING: Be careful of your package manager's rate limit.",
|
||||
min: 100,
|
||||
max: 60 * 24 * 1000,
|
||||
increment: 1000,
|
||||
}),
|
||||
Option({
|
||||
opt: options.bar.customModules.updates.leftClick,
|
||||
title: 'Left Click',
|
||||
type: 'string',
|
||||
}),
|
||||
Option({
|
||||
opt: options.bar.customModules.updates.rightClick,
|
||||
title: 'Right Click',
|
||||
type: 'string',
|
||||
}),
|
||||
Option({
|
||||
opt: options.bar.customModules.updates.middleClick,
|
||||
title: 'Middle Click',
|
||||
type: 'string',
|
||||
}),
|
||||
Option({
|
||||
opt: options.bar.customModules.updates.scrollUp,
|
||||
title: 'Scroll Up',
|
||||
type: 'string',
|
||||
}),
|
||||
Option({
|
||||
opt: options.bar.customModules.updates.scrollDown,
|
||||
title: 'Scroll Down',
|
||||
type: 'string',
|
||||
}),
|
||||
|
||||
/*
|
||||
************************************
|
||||
* SUBMAP *
|
||||
************************************
|
||||
*/
|
||||
Header('Submap'),
|
||||
Option({
|
||||
opt: options.theme.bar.buttons.modules.submap.enableBorder,
|
||||
title: 'Button Border',
|
||||
type: 'boolean',
|
||||
}),
|
||||
Option({
|
||||
opt: options.bar.customModules.submap.showSubmapName,
|
||||
title: 'Show Submap Name',
|
||||
subtitle:
|
||||
'When enabled, the name of the current submap will be displayed' +
|
||||
' instead of the Submap Enabled or Disabled text.',
|
||||
type: 'boolean',
|
||||
}),
|
||||
Option({
|
||||
opt: options.bar.customModules.submap.enabledIcon,
|
||||
title: 'Enabled Icon',
|
||||
type: 'string',
|
||||
}),
|
||||
Option({
|
||||
opt: options.bar.customModules.submap.disabledIcon,
|
||||
title: 'Disabled Icon',
|
||||
type: 'string',
|
||||
}),
|
||||
Option({
|
||||
opt: options.bar.customModules.submap.enabledText,
|
||||
title: 'Enabled Text',
|
||||
type: 'string',
|
||||
}),
|
||||
Option({
|
||||
opt: options.bar.customModules.submap.disabledText,
|
||||
title: 'Disabled Text',
|
||||
type: 'string',
|
||||
}),
|
||||
Option({
|
||||
opt: options.bar.customModules.submap.label,
|
||||
title: 'Show Label',
|
||||
type: 'boolean',
|
||||
}),
|
||||
Option({
|
||||
opt: options.theme.bar.buttons.modules.submap.spacing,
|
||||
title: 'Spacing',
|
||||
type: 'string',
|
||||
}),
|
||||
Option({
|
||||
opt: options.bar.customModules.submap.leftClick,
|
||||
title: 'Left Click',
|
||||
type: 'string',
|
||||
}),
|
||||
Option({
|
||||
opt: options.bar.customModules.submap.rightClick,
|
||||
title: 'Right Click',
|
||||
type: 'string',
|
||||
}),
|
||||
Option({
|
||||
opt: options.bar.customModules.submap.middleClick,
|
||||
title: 'Middle Click',
|
||||
type: 'string',
|
||||
}),
|
||||
Option({
|
||||
opt: options.bar.customModules.submap.scrollUp,
|
||||
title: 'Scroll Up',
|
||||
type: 'string',
|
||||
}),
|
||||
Option({
|
||||
opt: options.bar.customModules.submap.scrollDown,
|
||||
title: 'Scroll Down',
|
||||
type: 'string',
|
||||
}),
|
||||
|
||||
/*
|
||||
************************************
|
||||
* WEATHER *
|
||||
************************************
|
||||
*/
|
||||
Header('Weather'),
|
||||
Option({
|
||||
opt: options.theme.bar.buttons.modules.weather.enableBorder,
|
||||
title: 'Button Border',
|
||||
type: 'boolean',
|
||||
}),
|
||||
Option({
|
||||
opt: options.bar.customModules.weather.label,
|
||||
title: 'Show Label',
|
||||
type: 'boolean',
|
||||
}),
|
||||
Option({
|
||||
opt: options.bar.customModules.weather.unit,
|
||||
title: 'Units',
|
||||
type: 'enum',
|
||||
enums: ['imperial', 'metric'],
|
||||
}),
|
||||
Option({
|
||||
opt: options.theme.bar.buttons.modules.weather.spacing,
|
||||
title: 'Spacing',
|
||||
type: 'string',
|
||||
}),
|
||||
Option({
|
||||
opt: options.bar.customModules.weather.leftClick,
|
||||
title: 'Left Click',
|
||||
type: 'string',
|
||||
}),
|
||||
Option({
|
||||
opt: options.bar.customModules.weather.rightClick,
|
||||
title: 'Right Click',
|
||||
type: 'string',
|
||||
}),
|
||||
Option({
|
||||
opt: options.bar.customModules.weather.middleClick,
|
||||
title: 'Middle Click',
|
||||
type: 'string',
|
||||
}),
|
||||
Option({
|
||||
opt: options.bar.customModules.weather.scrollUp,
|
||||
title: 'Scroll Up',
|
||||
type: 'string',
|
||||
}),
|
||||
Option({
|
||||
opt: options.bar.customModules.weather.scrollDown,
|
||||
title: 'Scroll Down',
|
||||
type: 'string',
|
||||
}),
|
||||
|
||||
/*
|
||||
************************************
|
||||
* POWER *
|
||||
************************************
|
||||
*/
|
||||
Header('Power'),
|
||||
Option({
|
||||
opt: options.theme.bar.buttons.modules.power.enableBorder,
|
||||
title: 'Button Border',
|
||||
type: 'boolean',
|
||||
}),
|
||||
Option({
|
||||
opt: options.theme.bar.buttons.modules.power.spacing,
|
||||
title: 'Spacing',
|
||||
type: 'string',
|
||||
}),
|
||||
Option({
|
||||
opt: options.bar.customModules.power.icon,
|
||||
title: 'Power Button Icon',
|
||||
type: 'string',
|
||||
}),
|
||||
Option({
|
||||
opt: options.bar.customModules.power.leftClick,
|
||||
title: 'Left Click',
|
||||
type: 'string',
|
||||
}),
|
||||
Option({
|
||||
opt: options.bar.customModules.power.rightClick,
|
||||
title: 'Right Click',
|
||||
type: 'string',
|
||||
}),
|
||||
Option({
|
||||
opt: options.bar.customModules.power.middleClick,
|
||||
title: 'Middle Click',
|
||||
type: 'string',
|
||||
}),
|
||||
Option({
|
||||
opt: options.bar.customModules.power.scrollUp,
|
||||
title: 'Scroll Up',
|
||||
type: 'string',
|
||||
}),
|
||||
Option({
|
||||
opt: options.bar.customModules.power.scrollDown,
|
||||
title: 'Scroll Down',
|
||||
type: 'string',
|
||||
}),
|
||||
],
|
||||
}),
|
||||
});
|
||||
@@ -0,0 +1,20 @@
|
||||
// @ts-expect-error: This import is a special directive that tells the compiler to use the GTop library
|
||||
import GTop from 'gi://GTop';
|
||||
|
||||
let previousCpuData = new GTop.glibtop_cpu();
|
||||
GTop.glibtop_get_cpu(previousCpuData);
|
||||
|
||||
export const computeCPU = (): number => {
|
||||
const currentCpuData = new GTop.glibtop_cpu();
|
||||
GTop.glibtop_get_cpu(currentCpuData);
|
||||
|
||||
// Calculate the differences from the previous to current data
|
||||
const totalDiff = currentCpuData.total - previousCpuData.total;
|
||||
const idleDiff = currentCpuData.idle - previousCpuData.idle;
|
||||
|
||||
const cpuUsagePercentage = totalDiff > 0 ? ((totalDiff - idleDiff) / totalDiff) * 100 : 0;
|
||||
|
||||
previousCpuData = currentCpuData;
|
||||
|
||||
return cpuUsagePercentage;
|
||||
};
|
||||
@@ -0,0 +1,69 @@
|
||||
import options from 'options';
|
||||
|
||||
// Module initializer
|
||||
import { module } from '../module';
|
||||
|
||||
import Button from 'types/widgets/button';
|
||||
|
||||
// Utility Methods
|
||||
import { inputHandler } from 'customModules/utils';
|
||||
import { computeCPU } from './computeCPU';
|
||||
import { pollVariable } from 'customModules/PollVar';
|
||||
import { BarBoxChild } from 'lib/types/bar';
|
||||
import { Attribute, Child } from 'lib/types/widget';
|
||||
|
||||
// All the user configurable options for the cpu module that are needed
|
||||
const { label, round, leftClick, rightClick, middleClick, scrollUp, scrollDown, pollingInterval, icon } =
|
||||
options.bar.customModules.cpu;
|
||||
|
||||
export const cpuUsage = Variable(0);
|
||||
|
||||
pollVariable(
|
||||
// Variable to poll and update with the result of the function passed in
|
||||
cpuUsage,
|
||||
// Variables that should trigger the polling function to update when they change
|
||||
[round.bind('value')],
|
||||
// Interval at which to poll
|
||||
pollingInterval.bind('value'),
|
||||
// Function to execute to get the network data
|
||||
computeCPU,
|
||||
);
|
||||
|
||||
export const Cpu = (): BarBoxChild => {
|
||||
const renderLabel = (cpuUsg: number, rnd: boolean): string => {
|
||||
return rnd ? `${Math.round(cpuUsg)}%` : `${cpuUsg.toFixed(2)}%`;
|
||||
};
|
||||
|
||||
const cpuModule = module({
|
||||
textIcon: icon.bind('value'),
|
||||
label: Utils.merge([cpuUsage.bind('value'), round.bind('value')], (cpuUsg, rnd) => {
|
||||
return renderLabel(cpuUsg, rnd);
|
||||
}),
|
||||
tooltipText: 'CPU',
|
||||
boxClass: 'cpu',
|
||||
showLabelBinding: label.bind('value'),
|
||||
props: {
|
||||
setup: (self: Button<Child, Attribute>) => {
|
||||
inputHandler(self, {
|
||||
onPrimaryClick: {
|
||||
cmd: leftClick,
|
||||
},
|
||||
onSecondaryClick: {
|
||||
cmd: rightClick,
|
||||
},
|
||||
onMiddleClick: {
|
||||
cmd: middleClick,
|
||||
},
|
||||
onScrollUp: {
|
||||
cmd: scrollUp,
|
||||
},
|
||||
onScrollDown: {
|
||||
cmd: scrollDown,
|
||||
},
|
||||
});
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
return cpuModule;
|
||||
};
|
||||
@@ -0,0 +1,28 @@
|
||||
import {
|
||||
HyprctlDeviceLayout,
|
||||
HyprctlKeyboard,
|
||||
KbLabelType,
|
||||
LayoutKeys,
|
||||
LayoutValues,
|
||||
} from 'lib/types/customModules/kbLayout';
|
||||
import { layoutMap } from './layouts';
|
||||
|
||||
export const getKeyboardLayout = (obj: string, format: KbLabelType): LayoutKeys | LayoutValues => {
|
||||
const hyprctlDevices: HyprctlDeviceLayout = JSON.parse(obj);
|
||||
const keyboards = hyprctlDevices['keyboards'];
|
||||
|
||||
if (keyboards.length === 0) {
|
||||
return format === 'code' ? 'Unknown' : 'Unknown Layout';
|
||||
}
|
||||
|
||||
let mainKb = keyboards.find((kb: HyprctlKeyboard) => kb.main);
|
||||
|
||||
if (!mainKb) {
|
||||
mainKb = keyboards[keyboards.length - 1];
|
||||
}
|
||||
|
||||
const layout: LayoutKeys = mainKb['active_keymap'] as LayoutKeys;
|
||||
const foundLayout: LayoutValues = layoutMap[layout];
|
||||
|
||||
return format === 'code' ? foundLayout || layout : layout;
|
||||
};
|
||||
@@ -0,0 +1,73 @@
|
||||
const hyprland = await Service.import('hyprland');
|
||||
|
||||
import options from 'options';
|
||||
import { module } from '../module';
|
||||
|
||||
import { inputHandler } from 'customModules/utils';
|
||||
import Gtk from 'types/@girs/gtk-3.0/gtk-3.0';
|
||||
import Button from 'types/widgets/button';
|
||||
import Label from 'types/widgets/label';
|
||||
import { getKeyboardLayout } from './getLayout';
|
||||
import { BarBoxChild } from 'lib/types/bar';
|
||||
import { Attribute, Child } from 'lib/types/widget';
|
||||
|
||||
const { label, labelType, icon, leftClick, rightClick, middleClick, scrollUp, scrollDown } =
|
||||
options.bar.customModules.kbLayout;
|
||||
|
||||
export const KbInput = (): BarBoxChild => {
|
||||
const keyboardModule = module({
|
||||
textIcon: icon.bind('value'),
|
||||
tooltipText: '',
|
||||
labelHook: (self: Label<Gtk.Widget>): void => {
|
||||
self.hook(
|
||||
hyprland,
|
||||
() => {
|
||||
Utils.execAsync('hyprctl devices -j')
|
||||
.then((obj) => {
|
||||
self.label = getKeyboardLayout(obj, labelType.value);
|
||||
})
|
||||
.catch((err) => {
|
||||
console.error(err);
|
||||
});
|
||||
},
|
||||
'keyboard-layout',
|
||||
);
|
||||
|
||||
self.hook(labelType, () => {
|
||||
Utils.execAsync('hyprctl devices -j')
|
||||
.then((obj) => {
|
||||
self.label = getKeyboardLayout(obj, labelType.value);
|
||||
})
|
||||
.catch((err) => {
|
||||
console.error(err);
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
boxClass: 'kblayout',
|
||||
showLabelBinding: label.bind('value'),
|
||||
props: {
|
||||
setup: (self: Button<Child, Attribute>) => {
|
||||
inputHandler(self, {
|
||||
onPrimaryClick: {
|
||||
cmd: leftClick,
|
||||
},
|
||||
onSecondaryClick: {
|
||||
cmd: rightClick,
|
||||
},
|
||||
onMiddleClick: {
|
||||
cmd: middleClick,
|
||||
},
|
||||
onScrollUp: {
|
||||
cmd: scrollUp,
|
||||
},
|
||||
onScrollDown: {
|
||||
cmd: scrollDown,
|
||||
},
|
||||
});
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
return keyboardModule;
|
||||
};
|
||||
@@ -0,0 +1,585 @@
|
||||
export const layoutMap = {
|
||||
'Abkhazian (Russia)': 'RU (Ab)',
|
||||
Akan: 'GH (Akan)',
|
||||
Albanian: 'AL',
|
||||
'Albanian (Plisi)': 'AL (Plisi)',
|
||||
'Albanian (Veqilharxhi)': 'AL (Veqilharxhi)',
|
||||
Amharic: 'ET',
|
||||
Arabic: 'ARA',
|
||||
'Arabic (Algeria)': 'DZ (Ar)',
|
||||
'Arabic (AZERTY, Eastern Arabic numerals)': 'ARA (Azerty Digits)',
|
||||
'Arabic (AZERTY)': 'ARA (Azerty)',
|
||||
'Arabic (Buckwalter)': 'ARA (Buckwalter)',
|
||||
'Arabic (Eastern Arabic numerals)': 'ARA (Digits)',
|
||||
'Arabic (Macintosh)': 'ARA (Mac)',
|
||||
'Arabic (Morocco)': 'MA',
|
||||
'Arabic (OLPC)': 'ARA (Olpc)',
|
||||
'Arabic (Pakistan)': 'PK (Ara)',
|
||||
'Arabic (QWERTY, Eastern Arabic numerals)': 'ARA (Qwerty Digits)',
|
||||
'Arabic (QWERTY)': 'ARA (Qwerty)',
|
||||
'Arabic (Syria)': 'SY',
|
||||
Armenian: 'AM',
|
||||
'Armenian (alt. eastern)': 'AM (Eastern-Alt)',
|
||||
'Armenian (alt. phonetic)': 'AM (Phonetic-Alt)',
|
||||
'Armenian (eastern)': 'AM (Eastern)',
|
||||
'Armenian (phonetic)': 'AM (Phonetic)',
|
||||
'Armenian (western)': 'AM (Western)',
|
||||
'Asturian (Spain, with bottom-dot H and L)': 'ES (Ast)',
|
||||
Avatime: 'GH (Avn)',
|
||||
Azerbaijani: 'AZ',
|
||||
'Azerbaijani (Cyrillic)': 'AZ (Cyrillic)',
|
||||
'Azerbaijani (Iran)': 'IR (Azb)',
|
||||
Bambara: 'ML',
|
||||
Bangla: 'BD',
|
||||
'Bangla (India, Baishakhi InScript)': 'IN (Ben Inscript)',
|
||||
'Bangla (India, Baishakhi)': 'IN (Ben Baishakhi)',
|
||||
'Bangla (India, Bornona)': 'IN (Ben Bornona)',
|
||||
'Bangla (India, Gitanjali)': 'IN (Ben Gitanjali)',
|
||||
'Bangla (India, Probhat)': 'IN (Ben Probhat)',
|
||||
'Bangla (India)': 'IN (Ben)',
|
||||
'Bangla (Probhat)': 'BD (Probhat)',
|
||||
Bashkirian: 'RU (Bak)',
|
||||
Belarusian: 'BY',
|
||||
'Belarusian (intl.)': 'BY (Intl)',
|
||||
'Belarusian (Latin)': 'BY (Latin)',
|
||||
'Belarusian (legacy)': 'BY (Legacy)',
|
||||
'Belarusian (phonetic)': 'BY (Phonetic)',
|
||||
Belgian: 'BE',
|
||||
'Belgian (alt.)': 'BE (Oss)',
|
||||
'Belgian (ISO, alt.)': 'BE (Iso-Alternate)',
|
||||
'Belgian (Latin-9 only, alt.)': 'BE (Oss Latin9)',
|
||||
'Belgian (no dead keys)': 'BE (Nodeadkeys)',
|
||||
'Belgian (Wang 724 AZERTY)': 'BE (Wang)',
|
||||
'Berber (Algeria, Latin)': 'DZ',
|
||||
'Berber (Algeria, Tifinagh)': 'DZ (Ber)',
|
||||
'Berber (Morocco, Tifinagh alt.)': 'MA (Tifinagh-Alt)',
|
||||
'Berber (Morocco, Tifinagh extended phonetic)': 'MA (Tifinagh-Extended-Phonetic)',
|
||||
'Berber (Morocco, Tifinagh extended)': 'MA (Tifinagh-Extended)',
|
||||
'Berber (Morocco, Tifinagh phonetic, alt.)': 'MA (Tifinagh-Alt-Phonetic)',
|
||||
'Berber (Morocco, Tifinagh phonetic)': 'MA (Tifinagh-Phonetic)',
|
||||
'Berber (Morocco, Tifinagh)': 'MA (Tifinagh)',
|
||||
Bosnian: 'BA',
|
||||
'Bosnian (US, with Bosnian digraphs)': 'BA (Unicodeus)',
|
||||
'Bosnian (US)': 'BA (Us)',
|
||||
'Bosnian (with Bosnian digraphs)': 'BA (Unicode)',
|
||||
'Bosnian (with guillemets)': 'BA (Alternatequotes)',
|
||||
Braille: 'BRAI',
|
||||
'Braille (left-handed inverted thumb)': 'BRAI (Left Hand Invert)',
|
||||
'Braille (left-handed)': 'BRAI (Left Hand)',
|
||||
'Braille (right-handed inverted thumb)': 'BRAI (Right Hand Invert)',
|
||||
'Braille (right-handed)': 'BRAI (Right Hand)',
|
||||
'Breton (France)': 'FR (Bre)',
|
||||
Bulgarian: 'BG',
|
||||
'Bulgarian (enhanced)': 'BG (Bekl)',
|
||||
'Bulgarian (new phonetic)': 'BG (Bas Phonetic)',
|
||||
'Bulgarian (traditional phonetic)': 'BG (Phonetic)',
|
||||
Burmese: 'MM',
|
||||
'Burmese Zawgyi': 'MM (Zawgyi)',
|
||||
'Cameroon (AZERTY, intl.)': 'CM (Azerty)',
|
||||
'Cameroon (Dvorak, intl.)': 'CM (Dvorak)',
|
||||
'Cameroon Multilingual (QWERTY, intl.)': 'CM (Qwerty)',
|
||||
'Canadian (CSA)': 'CA (Multix)',
|
||||
'Catalan (Spain, with middle-dot L)': 'ES (Cat)',
|
||||
Cherokee: 'US (Chr)',
|
||||
Chinese: 'CN',
|
||||
Chuvash: 'RU (Cv)',
|
||||
'Chuvash (Latin)': 'RU (Cv Latin)',
|
||||
CloGaelach: 'IE (CloGaelach)',
|
||||
'Crimean Tatar (Turkish Alt-Q)': 'UA (Crh Alt)',
|
||||
'Crimean Tatar (Turkish F)': 'UA (Crh F)',
|
||||
'Crimean Tatar (Turkish Q)': 'UA (Crh)',
|
||||
Croatian: 'HR',
|
||||
'Croatian (US, with Croatian digraphs)': 'HR (Unicodeus)',
|
||||
'Croatian (US)': 'HR (Us)',
|
||||
'Croatian (with Croatian digraphs)': 'HR (Unicode)',
|
||||
'Croatian (with guillemets)': 'HR (Alternatequotes)',
|
||||
Czech: 'CZ',
|
||||
'Czech (QWERTY, extended backslash)': 'CZ (Qwerty Bksl)',
|
||||
'Czech (QWERTY, Macintosh)': 'CZ (Qwerty-Mac)',
|
||||
'Czech (QWERTY)': 'CZ (Qwerty)',
|
||||
'Czech (UCW, only accented letters)': 'CZ (Ucw)',
|
||||
'Czech (US, Dvorak, UCW support)': 'CZ (Dvorak-Ucw)',
|
||||
'Czech (with <\\|> key)': 'CZ (Bksl)',
|
||||
Danish: 'DK',
|
||||
'Danish (Dvorak)': 'DK (Dvorak)',
|
||||
'Danish (Macintosh, no dead keys)': 'DK (Mac Nodeadkeys)',
|
||||
'Danish (Macintosh)': 'DK (Mac)',
|
||||
'Danish (no dead keys)': 'DK (Nodeadkeys)',
|
||||
'Danish (Windows)': 'DK (Winkeys)',
|
||||
Dari: 'AF',
|
||||
'Dari (Afghanistan, OLPC)': 'AF (Fa-Olpc)',
|
||||
Dhivehi: 'MV',
|
||||
Dutch: 'NL',
|
||||
'Dutch (Macintosh)': 'NL (Mac)',
|
||||
'Dutch (standard)': 'NL (Std)',
|
||||
'Dutch (US)': 'NL (Us)',
|
||||
Dzongkha: 'BT',
|
||||
'English (Australian)': 'AU',
|
||||
'English (Cameroon)': 'CM',
|
||||
'English (Canada)': 'CA (Eng)',
|
||||
'English (classic Dvorak)': 'US (Dvorak-Classic)',
|
||||
'English (Colemak-DH ISO)': 'US (Colemak Dh Iso)',
|
||||
'English (Colemak-DH)': 'US (Colemak Dh)',
|
||||
'English (Colemak)': 'US (Colemak)',
|
||||
'English (Dvorak, alt. intl.)': 'US (Dvorak-Alt-Intl)',
|
||||
'English (Dvorak, intl., with dead keys)': 'US (Dvorak-Intl)',
|
||||
'English (Dvorak, left-handed)': 'US (Dvorak-L)',
|
||||
'English (Dvorak, Macintosh)': 'US (Dvorak-Mac)',
|
||||
'English (Dvorak, right-handed)': 'US (Dvorak-R)',
|
||||
'English (Dvorak)': 'US (Dvorak)',
|
||||
'English (Ghana, GILLBT)': 'GH (Gillbt)',
|
||||
'English (Ghana, multilingual)': 'GH (Generic)',
|
||||
'English (Ghana)': 'GH',
|
||||
'English (India, with rupee)': 'IN (Eng)',
|
||||
'English (intl., with AltGr dead keys)': 'US (Altgr-Intl)',
|
||||
'English (Macintosh)': 'US (Mac)',
|
||||
'English (Mali, US, intl.)': 'ML (Us-Intl)',
|
||||
'English (Mali, US, Macintosh)': 'ML (Us-Mac)',
|
||||
'English (Nigeria)': 'NG',
|
||||
'English (Norman)': 'US (Norman)',
|
||||
'English (programmer Dvorak)': 'US (Dvp)',
|
||||
'English (South Africa)': 'ZA',
|
||||
'English (the divide/multiply toggle the layout)': 'US (Olpc2)',
|
||||
'English (UK, Colemak-DH)': 'GB (Colemak Dh)',
|
||||
'English (UK, Colemak)': 'GB (Colemak)',
|
||||
'English (UK, Dvorak, with UK punctuation)': 'GB (Dvorakukp)',
|
||||
'English (UK, Dvorak)': 'GB (Dvorak)',
|
||||
'English (UK, extended, Windows)': 'GB (Extd)',
|
||||
'English (UK, intl., with dead keys)': 'GB (Intl)',
|
||||
'English (UK, Macintosh, intl.)': 'GB (Mac Intl)',
|
||||
'English (UK, Macintosh)': 'GB (Mac)',
|
||||
'English (UK)': 'GB',
|
||||
'English (US, alt. intl.)': 'US (Alt-Intl)',
|
||||
'English (US, euro on 5)': 'US (Euro)',
|
||||
'English (US, intl., with dead keys)': 'US (Intl)',
|
||||
'English (US, Symbolic)': 'US (Symbolic)',
|
||||
'English (US)': 'US',
|
||||
'English (Workman, intl., with dead keys)': 'US (Workman-Intl)',
|
||||
'English (Workman)': 'US (Workman)',
|
||||
Esperanto: 'EPO',
|
||||
'Esperanto (Brazil, Nativo)': 'BR (Nativo-Epo)',
|
||||
'Esperanto (legacy)': 'EPO (Legacy)',
|
||||
'Esperanto (Portugal, Nativo)': 'PT (Nativo-Epo)',
|
||||
Estonian: 'EE',
|
||||
'Estonian (Dvorak)': 'EE (Dvorak)',
|
||||
'Estonian (no dead keys)': 'EE (Nodeadkeys)',
|
||||
'Estonian (US)': 'EE (Us)',
|
||||
Ewe: 'GH (Ewe)',
|
||||
Faroese: 'FO',
|
||||
'Faroese (no dead keys)': 'FO (Nodeadkeys)',
|
||||
Filipino: 'PH',
|
||||
'Filipino (Capewell-Dvorak, Baybayin)': 'PH (Capewell-Dvorak-Bay)',
|
||||
'Filipino (Capewell-Dvorak, Latin)': 'PH (Capewell-Dvorak)',
|
||||
'Filipino (Capewell-QWERF 2006, Baybayin)': 'PH (Capewell-Qwerf2k6-Bay)',
|
||||
'Filipino (Capewell-QWERF 2006, Latin)': 'PH (Capewell-Qwerf2k6)',
|
||||
'Filipino (Colemak, Baybayin)': 'PH (Colemak-Bay)',
|
||||
'Filipino (Colemak, Latin)': 'PH (Colemak)',
|
||||
'Filipino (Dvorak, Baybayin)': 'PH (Dvorak-Bay)',
|
||||
'Filipino (Dvorak, Latin)': 'PH (Dvorak)',
|
||||
'Filipino (QWERTY, Baybayin)': 'PH (Qwerty-Bay)',
|
||||
Finnish: 'FI',
|
||||
'Finnish (classic, no dead keys)': 'FI (Nodeadkeys)',
|
||||
'Finnish (classic)': 'FI (Classic)',
|
||||
'Finnish (Macintosh)': 'FI (Mac)',
|
||||
'Finnish (Windows)': 'FI (Winkeys)',
|
||||
French: 'FR',
|
||||
'French (alt., Latin-9 only)': 'FR (Oss Latin9)',
|
||||
'French (alt., no dead keys)': 'FR (Oss Nodeadkeys)',
|
||||
'French (alt.)': 'FR (Oss)',
|
||||
'French (AZERTY, AFNOR)': 'FR (Afnor)',
|
||||
'French (AZERTY)': 'FR (Azerty)',
|
||||
'French (BEPO, AFNOR)': 'FR (Bepo Afnor)',
|
||||
'French (BEPO, Latin-9 only)': 'FR (Bepo Latin9)',
|
||||
'French (BEPO)': 'FR (Bepo)',
|
||||
'French (Cameroon)': 'CM (French)',
|
||||
'French (Canada, Dvorak)': 'CA (Fr-Dvorak)',
|
||||
'French (Canada, legacy)': 'CA (Fr-Legacy)',
|
||||
'French (Canada)': 'CA',
|
||||
'French (Democratic Republic of the Congo)': 'CD',
|
||||
'French (Dvorak)': 'FR (Dvorak)',
|
||||
'French (legacy, alt., no dead keys)': 'FR (Latin9 Nodeadkeys)',
|
||||
'French (legacy, alt.)': 'FR (Latin9)',
|
||||
'French (Macintosh)': 'FR (Mac)',
|
||||
'French (Mali, alt.)': 'ML (Fr-Oss)',
|
||||
'French (Morocco)': 'MA (French)',
|
||||
'French (no dead keys)': 'FR (Nodeadkeys)',
|
||||
'French (Switzerland, Macintosh)': 'CH (Fr Mac)',
|
||||
'French (Switzerland, no dead keys)': 'CH (Fr Nodeadkeys)',
|
||||
'French (Switzerland)': 'CH (Fr)',
|
||||
'French (Togo)': 'TG',
|
||||
'French (US)': 'FR (Us)',
|
||||
'Friulian (Italy)': 'IT (Fur)',
|
||||
Fula: 'GH (Fula)',
|
||||
Ga: 'GH (Ga)',
|
||||
Georgian: 'GE',
|
||||
'Georgian (ergonomic)': 'GE (Ergonomic)',
|
||||
'Georgian (France, AZERTY Tskapo)': 'FR (Geo)',
|
||||
'Georgian (Italy)': 'IT (Geo)',
|
||||
'Georgian (MESS)': 'GE (Mess)',
|
||||
German: 'DE',
|
||||
'German (Austria, Macintosh)': 'AT (Mac)',
|
||||
'German (Austria, no dead keys)': 'AT (Nodeadkeys)',
|
||||
'German (Austria)': 'AT',
|
||||
'German (dead acute)': 'DE (Deadacute)',
|
||||
'German (dead grave acute)': 'DE (Deadgraveacute)',
|
||||
'German (dead tilde)': 'DE (Deadtilde)',
|
||||
'German (Dvorak)': 'DE (Dvorak)',
|
||||
'German (E1)': 'DE (E1)',
|
||||
'German (E2)': 'DE (E2)',
|
||||
'German (Macintosh, no dead keys)': 'DE (Mac Nodeadkeys)',
|
||||
'German (Macintosh)': 'DE (Mac)',
|
||||
'German (Neo 2)': 'DE (Neo)',
|
||||
'German (no dead keys)': 'DE (Nodeadkeys)',
|
||||
'German (QWERTY)': 'DE (Qwerty)',
|
||||
'German (Switzerland, legacy)': 'CH (Legacy)',
|
||||
'German (Switzerland, Macintosh)': 'CH (De Mac)',
|
||||
'German (Switzerland, no dead keys)': 'CH (De Nodeadkeys)',
|
||||
'German (Switzerland)': 'CH',
|
||||
'German (T3)': 'DE (T3)',
|
||||
'German (US)': 'DE (Us)',
|
||||
Greek: 'GR',
|
||||
'Greek (extended)': 'GR (Extended)',
|
||||
'Greek (no dead keys)': 'GR (Nodeadkeys)',
|
||||
'Greek (polytonic)': 'GR (Polytonic)',
|
||||
'Greek (simple)': 'GR (Simple)',
|
||||
Gujarati: 'IN (Guj)',
|
||||
'Hanyu Pinyin Letters (with AltGr dead keys)': 'CN (Altgr-Pinyin)',
|
||||
'Hausa (Ghana)': 'GH (Hausa)',
|
||||
'Hausa (Nigeria)': 'NG (Hausa)',
|
||||
Hawaiian: 'US (Haw)',
|
||||
Hebrew: 'IL',
|
||||
'Hebrew (Biblical, Tiro)': 'IL (Biblical)',
|
||||
'Hebrew (lyx)': 'IL (Lyx)',
|
||||
'Hebrew (phonetic)': 'IL (Phonetic)',
|
||||
'Hindi (Bolnagri)': 'IN (Bolnagri)',
|
||||
'Hindi (KaGaPa, phonetic)': 'IN (Hin-Kagapa)',
|
||||
'Hindi (Wx)': 'IN (Hin-Wx)',
|
||||
Hungarian: 'HU',
|
||||
'Hungarian (no dead keys)': 'HU (Nodeadkeys)',
|
||||
'Hungarian (QWERTY, 101-key, comma, dead keys)': 'HU (101 Qwerty Comma Dead)',
|
||||
'Hungarian (QWERTY, 101-key, comma, no dead keys)': 'HU (101 Qwerty Comma Nodead)',
|
||||
'Hungarian (QWERTY, 101-key, dot, dead keys)': 'HU (101 Qwerty Dot Dead)',
|
||||
'Hungarian (QWERTY, 101-key, dot, no dead keys)': 'HU (101 Qwerty Dot Nodead)',
|
||||
'Hungarian (QWERTY, 102-key, comma, dead keys)': 'HU (102 Qwerty Comma Dead)',
|
||||
'Hungarian (QWERTY, 102-key, comma, no dead keys)': 'HU (102 Qwerty Comma Nodead)',
|
||||
'Hungarian (QWERTY, 102-key, dot, dead keys)': 'HU (102 Qwerty Dot Dead)',
|
||||
'Hungarian (QWERTY, 102-key, dot, no dead keys)': 'HU (102 Qwerty Dot Nodead)',
|
||||
'Hungarian (QWERTY)': 'HU (Qwerty)',
|
||||
'Hungarian (QWERTZ, 101-key, comma, dead keys)': 'HU (101 Qwertz Comma Dead)',
|
||||
'Hungarian (QWERTZ, 101-key, comma, no dead keys)': 'HU (101 Qwertz Comma Nodead)',
|
||||
'Hungarian (QWERTZ, 101-key, dot, dead keys)': 'HU (101 Qwertz Dot Dead)',
|
||||
'Hungarian (QWERTZ, 101-key, dot, no dead keys)': 'HU (101 Qwertz Dot Nodead)',
|
||||
'Hungarian (QWERTZ, 102-key, comma, dead keys)': 'HU (102 Qwertz Comma Dead)',
|
||||
'Hungarian (QWERTZ, 102-key, comma, no dead keys)': 'HU (102 Qwertz Comma Nodead)',
|
||||
'Hungarian (QWERTZ, 102-key, dot, dead keys)': 'HU (102 Qwertz Dot Dead)',
|
||||
'Hungarian (QWERTZ, 102-key, dot, no dead keys)': 'HU (102 Qwertz Dot Nodead)',
|
||||
'Hungarian (standard)': 'HU (Standard)',
|
||||
Icelandic: 'IS',
|
||||
'Icelandic (Dvorak)': 'IS (Dvorak)',
|
||||
'Icelandic (Macintosh, legacy)': 'IS (Mac Legacy)',
|
||||
'Icelandic (Macintosh)': 'IS (Mac)',
|
||||
Igbo: 'NG (Igbo)',
|
||||
Indian: 'IN',
|
||||
'Indic IPA': 'IN (Iipa)',
|
||||
'Indonesian (Arab Melayu, extended phonetic)': 'ID (Melayu-Phoneticx)',
|
||||
'Indonesian (Arab Melayu, phonetic)': 'ID (Melayu-Phonetic)',
|
||||
'Indonesian (Arab Pegon, phonetic)': 'ID (Pegon-Phonetic)',
|
||||
'Indonesian (Latin)': 'ID',
|
||||
Inuktitut: 'CA (Ike)',
|
||||
Iraqi: 'IQ',
|
||||
Irish: 'IE',
|
||||
'Irish (UnicodeExpert)': 'IE (UnicodeExpert)',
|
||||
Italian: 'IT',
|
||||
'Italian (IBM 142)': 'IT (Ibm)',
|
||||
'Italian (intl., with dead keys)': 'IT (Intl)',
|
||||
'Italian (Macintosh)': 'IT (Mac)',
|
||||
'Italian (no dead keys)': 'IT (Nodeadkeys)',
|
||||
'Italian (US)': 'IT (Us)',
|
||||
'Italian (Windows)': 'IT (Winkeys)',
|
||||
Japanese: 'JP',
|
||||
'Japanese (Dvorak)': 'JP (Dvorak)',
|
||||
'Japanese (Kana 86)': 'JP (Kana86)',
|
||||
'Japanese (Kana)': 'JP (Kana)',
|
||||
'Japanese (Macintosh)': 'JP (Mac)',
|
||||
'Japanese (OADG 109A)': 'JP (OADG109A)',
|
||||
Javanese: 'ID (Javanese)',
|
||||
'Kabyle (AZERTY, with dead keys)': 'DZ (Azerty-Deadkeys)',
|
||||
'Kabyle (QWERTY, UK, with dead keys)': 'DZ (Qwerty-Gb-Deadkeys)',
|
||||
'Kabyle (QWERTY, US, with dead keys)': 'DZ (Qwerty-Us-Deadkeys)',
|
||||
Kalmyk: 'RU (Xal)',
|
||||
Kannada: 'IN (Kan)',
|
||||
'Kannada (KaGaPa, phonetic)': 'IN (Kan-Kagapa)',
|
||||
Kashubian: 'PL (Csb)',
|
||||
Kazakh: 'KZ',
|
||||
'Kazakh (extended)': 'KZ (Ext)',
|
||||
'Kazakh (Latin)': 'KZ (Latin)',
|
||||
'Kazakh (with Russian)': 'KZ (Kazrus)',
|
||||
'Khmer (Cambodia)': 'KH',
|
||||
Kikuyu: 'KE (Kik)',
|
||||
Komi: 'RU (Kom)',
|
||||
Korean: 'KR',
|
||||
'Korean (101/104-key compatible)': 'KR (Kr104)',
|
||||
'Kurdish (Iran, Arabic-Latin)': 'IR (Ku Ara)',
|
||||
'Kurdish (Iran, F)': 'IR (Ku F)',
|
||||
'Kurdish (Iran, Latin Alt-Q)': 'IR (Ku Alt)',
|
||||
'Kurdish (Iran, Latin Q)': 'IR (Ku)',
|
||||
'Kurdish (Iraq, Arabic-Latin)': 'IQ (Ku Ara)',
|
||||
'Kurdish (Iraq, F)': 'IQ (Ku F)',
|
||||
'Kurdish (Iraq, Latin Alt-Q)': 'IQ (Ku Alt)',
|
||||
'Kurdish (Iraq, Latin Q)': 'IQ (Ku)',
|
||||
'Kurdish (Syria, F)': 'SY (Ku F)',
|
||||
'Kurdish (Syria, Latin Alt-Q)': 'SY (Ku Alt)',
|
||||
'Kurdish (Syria, Latin Q)': 'SY (Ku)',
|
||||
'Kurdish (Turkey, F)': 'TR (Ku F)',
|
||||
'Kurdish (Turkey, Latin Alt-Q)': 'TR (Ku Alt)',
|
||||
'Kurdish (Turkey, Latin Q)': 'TR (Ku)',
|
||||
Kyrgyz: 'KG',
|
||||
'Kyrgyz (phonetic)': 'KG (Phonetic)',
|
||||
Lao: 'LA',
|
||||
'Lao (STEA)': 'LA (Stea)',
|
||||
Latvian: 'LV',
|
||||
'Latvian (adapted)': 'LV (Adapted)',
|
||||
'Latvian (apostrophe)': 'LV (Apostrophe)',
|
||||
'Latvian (ergonomic, ŪGJRMV)': 'LV (Ergonomic)',
|
||||
'Latvian (F)': 'LV (Fkey)',
|
||||
'Latvian (modern)': 'LV (Modern)',
|
||||
'Latvian (tilde)': 'LV (Tilde)',
|
||||
Lithuanian: 'LT',
|
||||
'Lithuanian (IBM LST 1205-92)': 'LT (Ibm)',
|
||||
'Lithuanian (LEKP)': 'LT (Lekp)',
|
||||
'Lithuanian (LEKPa)': 'LT (Lekpa)',
|
||||
'Lithuanian (Ratise)': 'LT (Ratise)',
|
||||
'Lithuanian (standard)': 'LT (Std)',
|
||||
'Lithuanian (US)': 'LT (Us)',
|
||||
'Lower Sorbian': 'DE (Dsb)',
|
||||
'Lower Sorbian (QWERTZ)': 'DE (Dsb Qwertz)',
|
||||
Macedonian: 'MK',
|
||||
'Macedonian (no dead keys)': 'MK (Nodeadkeys)',
|
||||
'Malay (Jawi, Arabic Keyboard)': 'MY',
|
||||
'Malay (Jawi, phonetic)': 'MY (Phonetic)',
|
||||
Malayalam: 'IN (Mal)',
|
||||
'Malayalam (enhanced InScript, with rupee)': 'IN (Mal Enhanced)',
|
||||
'Malayalam (Lalitha)': 'IN (Mal Lalitha)',
|
||||
Maltese: 'MT',
|
||||
'Maltese (UK, with AltGr overrides)': 'MT (Alt-Gb)',
|
||||
'Maltese (US, with AltGr overrides)': 'MT (Alt-Us)',
|
||||
'Maltese (US)': 'MT (Us)',
|
||||
'Manipuri (Eeyek)': 'IN (Eeyek)',
|
||||
Maori: 'MAO',
|
||||
'Marathi (enhanced InScript)': 'IN (Marathi)',
|
||||
'Marathi (KaGaPa, phonetic)': 'IN (Mar-Kagapa)',
|
||||
Mari: 'RU (Chm)',
|
||||
Mmuock: 'CM (Mmuock)',
|
||||
Moldavian: 'MD',
|
||||
'Moldavian (Gagauz)': 'MD (Gag)',
|
||||
Mon: 'MM (Mnw)',
|
||||
'Mon (A1)': 'MM (Mnw-A1)',
|
||||
Mongolian: 'MN',
|
||||
'Mongolian (Bichig)': 'CN (Mon Trad)',
|
||||
'Mongolian (Galik)': 'CN (Mon Trad Galik)',
|
||||
'Mongolian (Manchu Galik)': 'CN (Mon Manchu Galik)',
|
||||
'Mongolian (Manchu)': 'CN (Mon Trad Manchu)',
|
||||
'Mongolian (Todo Galik)': 'CN (Mon Todo Galik)',
|
||||
'Mongolian (Todo)': 'CN (Mon Trad Todo)',
|
||||
'Mongolian (Xibe)': 'CN (Mon Trad Xibe)',
|
||||
Montenegrin: 'ME',
|
||||
'Montenegrin (Cyrillic, with guillemets)': 'ME (Cyrillicalternatequotes)',
|
||||
'Montenegrin (Cyrillic, ZE and ZHE swapped)': 'ME (Cyrillicyz)',
|
||||
'Montenegrin (Cyrillic)': 'ME (Cyrillic)',
|
||||
'Montenegrin (Latin, QWERTY)': 'ME (Latinyz)',
|
||||
'Montenegrin (Latin, Unicode, QWERTY)': 'ME (Latinunicodeyz)',
|
||||
'Montenegrin (Latin, Unicode)': 'ME (Latinunicode)',
|
||||
'Montenegrin (Latin, with guillemets)': 'ME (Latinalternatequotes)',
|
||||
"N'Ko (AZERTY)": 'GN',
|
||||
Nepali: 'NP',
|
||||
'Northern Saami (Finland)': 'FI (Smi)',
|
||||
'Northern Saami (Norway, no dead keys)': 'NO (Smi Nodeadkeys)',
|
||||
'Northern Saami (Norway)': 'NO (Smi)',
|
||||
'Northern Saami (Sweden)': 'SE (Smi)',
|
||||
Norwegian: 'NO',
|
||||
'Norwegian (Colemak)': 'NO (Colemak)',
|
||||
'Norwegian (Dvorak)': 'NO (Dvorak)',
|
||||
'Norwegian (Macintosh, no dead keys)': 'NO (Mac Nodeadkeys)',
|
||||
'Norwegian (Macintosh)': 'NO (Mac)',
|
||||
'Norwegian (no dead keys)': 'NO (Nodeadkeys)',
|
||||
'Norwegian (Windows)': 'NO (Winkeys)',
|
||||
Occitan: 'FR (Oci)',
|
||||
Ogham: 'IE (Ogam)',
|
||||
'Ogham (IS434)': 'IE (Ogam Is434)',
|
||||
'Ol Chiki': 'IN (Olck)',
|
||||
'Old Turkic': 'TR (Otk)',
|
||||
'Old Turkic (F)': 'TR (Otkf)',
|
||||
Oriya: 'IN (Ori)',
|
||||
'Oriya (Bolnagri)': 'IN (Ori-Bolnagri)',
|
||||
'Oriya (Wx)': 'IN (Ori-Wx)',
|
||||
'Ossetian (Georgia)': 'GE (Os)',
|
||||
'Ossetian (legacy)': 'RU (Os Legacy)',
|
||||
'Ossetian (Windows)': 'RU (Os Winkeys)',
|
||||
'Ottoman (F)': 'TR (Otf)',
|
||||
'Ottoman (Q)': 'TR (Ot)',
|
||||
'Pannonian Rusyn': 'RS (Rue)',
|
||||
Pashto: 'AF (Ps)',
|
||||
'Pashto (Afghanistan, OLPC)': 'AF (Ps-Olpc)',
|
||||
Persian: 'IR',
|
||||
'Persian (with Persian keypad)': 'IR (Pes Keypad)',
|
||||
Polish: 'PL',
|
||||
'Polish (British keyboard)': 'GB (Pl)',
|
||||
'Polish (Dvorak, with Polish quotes on key 1)': 'PL (Dvorak Altquotes)',
|
||||
'Polish (Dvorak, with Polish quotes on quotemark key)': 'PL (Dvorak Quotes)',
|
||||
'Polish (Dvorak)': 'PL (Dvorak)',
|
||||
'Polish (legacy)': 'PL (Legacy)',
|
||||
'Polish (programmer Dvorak)': 'PL (Dvp)',
|
||||
'Polish (QWERTZ)': 'PL (Qwertz)',
|
||||
Portuguese: 'PT',
|
||||
'Portuguese (Brazil, Dvorak)': 'BR (Dvorak)',
|
||||
'Portuguese (Brazil, IBM/Lenovo ThinkPad)': 'BR (Thinkpad)',
|
||||
'Portuguese (Brazil, Nativo for US keyboards)': 'BR (Nativo-Us)',
|
||||
'Portuguese (Brazil, Nativo)': 'BR (Nativo)',
|
||||
'Portuguese (Brazil, no dead keys)': 'BR (Nodeadkeys)',
|
||||
'Portuguese (Brazil)': 'BR',
|
||||
'Portuguese (Macintosh, no dead keys)': 'PT (Mac Nodeadkeys)',
|
||||
'Portuguese (Macintosh)': 'PT (Mac)',
|
||||
'Portuguese (Nativo for US keyboards)': 'PT (Nativo-Us)',
|
||||
'Portuguese (Nativo)': 'PT (Nativo)',
|
||||
'Portuguese (no dead keys)': 'PT (Nodeadkeys)',
|
||||
'Punjabi (Gurmukhi Jhelum)': 'IN (Jhelum)',
|
||||
'Punjabi (Gurmukhi)': 'IN (Guru)',
|
||||
Romanian: 'RO',
|
||||
'Romanian (Germany, no dead keys)': 'DE (Ro Nodeadkeys)',
|
||||
'Romanian (Germany)': 'DE (Ro)',
|
||||
'Romanian (standard)': 'RO (Std)',
|
||||
'Romanian (Windows)': 'RO (Winkeys)',
|
||||
Russian: 'RU',
|
||||
'Russian (Belarus)': 'BY (Ru)',
|
||||
'Russian (Czech, phonetic)': 'CZ (Rus)',
|
||||
'Russian (DOS)': 'RU (Dos)',
|
||||
'Russian (engineering, EN)': 'RU (Ruchey En)',
|
||||
'Russian (engineering, RU)': 'RU (Ruchey Ru)',
|
||||
'Russian (Georgia)': 'GE (Ru)',
|
||||
'Russian (Germany, phonetic)': 'DE (Ru)',
|
||||
'Russian (Kazakhstan, with Kazakh)': 'KZ (Ruskaz)',
|
||||
'Russian (legacy)': 'RU (Legacy)',
|
||||
'Russian (Macintosh)': 'RU (Mac)',
|
||||
'Russian (phonetic, AZERTY)': 'RU (Phonetic Azerty)',
|
||||
'Russian (phonetic, Dvorak)': 'RU (Phonetic Dvorak)',
|
||||
'Russian (phonetic, French)': 'RU (Phonetic Fr)',
|
||||
'Russian (phonetic, Windows)': 'RU (Phonetic Winkeys)',
|
||||
'Russian (phonetic, YAZHERTY)': 'RU (Phonetic YAZHERTY)',
|
||||
'Russian (phonetic)': 'RU (Phonetic)',
|
||||
'Russian (Poland, phonetic Dvorak)': 'PL (Ru Phonetic Dvorak)',
|
||||
'Russian (Sweden, phonetic, no dead keys)': 'SE (Rus Nodeadkeys)',
|
||||
'Russian (Sweden, phonetic)': 'SE (Rus)',
|
||||
'Russian (typewriter, legacy)': 'RU (Typewriter-Legacy)',
|
||||
'Russian (typewriter)': 'RU (Typewriter)',
|
||||
'Russian (Ukraine, standard RSTU)': 'UA (Rstu Ru)',
|
||||
'Russian (US, phonetic)': 'US (Rus)',
|
||||
'Saisiyat (Taiwan)': 'TW (Saisiyat)',
|
||||
Samogitian: 'LT (Sgs)',
|
||||
'Sanskrit (KaGaPa, phonetic)': 'IN (San-Kagapa)',
|
||||
'Scottish Gaelic': 'GB (Gla)',
|
||||
Serbian: 'RS',
|
||||
'Serbian (Cyrillic, with guillemets)': 'RS (Alternatequotes)',
|
||||
'Serbian (Cyrillic, ZE and ZHE swapped)': 'RS (Yz)',
|
||||
'Serbian (Latin, QWERTY)': 'RS (Latinyz)',
|
||||
'Serbian (Latin, Unicode, QWERTY)': 'RS (Latinunicodeyz)',
|
||||
'Serbian (Latin, Unicode)': 'RS (Latinunicode)',
|
||||
'Serbian (Latin, with guillemets)': 'RS (Latinalternatequotes)',
|
||||
'Serbian (Latin)': 'RS (Latin)',
|
||||
'Serbian (Russia)': 'RU (Srp)',
|
||||
'Serbo-Croatian (US)': 'US (Hbs)',
|
||||
Shan: 'MM (Shn)',
|
||||
'Shan (Zawgyi Tai)': 'MM (Zgt)',
|
||||
Sicilian: 'IT (Scn)',
|
||||
Silesian: 'PL (Szl)',
|
||||
Sindhi: 'PK (Snd)',
|
||||
'Sinhala (phonetic)': 'LK',
|
||||
'Sinhala (US)': 'LK (Us)',
|
||||
Slovak: 'SK',
|
||||
'Slovak (extended backslash)': 'SK (Bksl)',
|
||||
'Slovak (QWERTY, extended backslash)': 'SK (Qwerty Bksl)',
|
||||
'Slovak (QWERTY)': 'SK (Qwerty)',
|
||||
Slovenian: 'SI',
|
||||
'Slovenian (US)': 'SI (Us)',
|
||||
'Slovenian (with guillemets)': 'SI (Alternatequotes)',
|
||||
Spanish: 'ES',
|
||||
'Spanish (dead tilde)': 'ES (Deadtilde)',
|
||||
'Spanish (Dvorak)': 'ES (Dvorak)',
|
||||
'Spanish (Latin American, Colemak)': 'LATAM (Colemak)',
|
||||
'Spanish (Latin American, dead tilde)': 'LATAM (Deadtilde)',
|
||||
'Spanish (Latin American, Dvorak)': 'LATAM (Dvorak)',
|
||||
'Spanish (Latin American, no dead keys)': 'LATAM (Nodeadkeys)',
|
||||
'Spanish (Latin American)': 'LATAM',
|
||||
'Spanish (Macintosh)': 'ES (Mac)',
|
||||
'Spanish (no dead keys)': 'ES (Nodeadkeys)',
|
||||
'Spanish (Windows)': 'ES (Winkeys)',
|
||||
'Swahili (Kenya)': 'KE',
|
||||
'Swahili (Tanzania)': 'TZ',
|
||||
Swedish: 'SE',
|
||||
'Swedish (Dvorak, intl.)': 'SE (Us Dvorak)',
|
||||
'Swedish (Dvorak)': 'SE (Dvorak)',
|
||||
'Swedish (Macintosh)': 'SE (Mac)',
|
||||
'Swedish (no dead keys)': 'SE (Nodeadkeys)',
|
||||
'Swedish (Svdvorak)': 'SE (Svdvorak)',
|
||||
'Swedish (US)': 'SE (Us)',
|
||||
'Swedish Sign Language': 'SE (Swl)',
|
||||
Syriac: 'SY (Syc)',
|
||||
'Syriac (phonetic)': 'SY (Syc Phonetic)',
|
||||
Taiwanese: 'TW',
|
||||
'Taiwanese (indigenous)': 'TW (Indigenous)',
|
||||
Tajik: 'TJ',
|
||||
'Tajik (legacy)': 'TJ (Legacy)',
|
||||
'Tamil (InScript, with Arabic numerals)': 'IN (Tam)',
|
||||
'Tamil (InScript, with Tamil numerals)': 'IN (Tam Tamilnumbers)',
|
||||
"Tamil (Sri Lanka, TamilNet '99, TAB encoding)": 'LK (Tam TAB)',
|
||||
"Tamil (Sri Lanka, TamilNet '99)": 'LK (Tam Unicode)',
|
||||
"Tamil (TamilNet '99 with Tamil numerals)": 'IN (Tamilnet Tamilnumbers)',
|
||||
"Tamil (TamilNet '99, TAB encoding)": 'IN (Tamilnet TAB)',
|
||||
"Tamil (TamilNet '99, TSCII encoding)": 'IN (Tamilnet TSCII)',
|
||||
"Tamil (TamilNet '99)": 'IN (Tamilnet)',
|
||||
Tarifit: 'MA (Rif)',
|
||||
Tatar: 'RU (Tt)',
|
||||
Telugu: 'IN (Tel)',
|
||||
'Telugu (KaGaPa, phonetic)': 'IN (Tel-Kagapa)',
|
||||
'Telugu (Sarala)': 'IN (Tel-Sarala)',
|
||||
Thai: 'TH',
|
||||
'Thai (Pattachote)': 'TH (Pat)',
|
||||
'Thai (TIS-820.2538)': 'TH (Tis)',
|
||||
Tibetan: 'CN (Tib)',
|
||||
'Tibetan (with ASCII numerals)': 'CN (Tib Asciinum)',
|
||||
Tswana: 'BW',
|
||||
Turkish: 'TR',
|
||||
'Turkish (Alt-Q)': 'TR (Alt)',
|
||||
'Turkish (E)': 'TR (E)',
|
||||
'Turkish (F)': 'TR (F)',
|
||||
'Turkish (Germany)': 'DE (Tr)',
|
||||
'Turkish (intl., with dead keys)': 'TR (Intl)',
|
||||
Turkmen: 'TM',
|
||||
'Turkmen (Alt-Q)': 'TM (Alt)',
|
||||
Udmurt: 'RU (Udm)',
|
||||
Ukrainian: 'UA',
|
||||
'Ukrainian (homophonic)': 'UA (Homophonic)',
|
||||
'Ukrainian (legacy)': 'UA (Legacy)',
|
||||
'Ukrainian (macOS)': 'UA (MacOS)',
|
||||
'Ukrainian (phonetic)': 'UA (Phonetic)',
|
||||
'Ukrainian (standard RSTU)': 'UA (Rstu)',
|
||||
'Ukrainian (typewriter)': 'UA (Typewriter)',
|
||||
'Ukrainian (Windows)': 'UA (Winkeys)',
|
||||
'Urdu (alt. phonetic)': 'IN (Urd-Phonetic3)',
|
||||
'Urdu (Pakistan, CRULP)': 'PK (Urd-Crulp)',
|
||||
'Urdu (Pakistan, NLA)': 'PK (Urd-Nla)',
|
||||
'Urdu (Pakistan)': 'PK',
|
||||
'Urdu (phonetic)': 'IN (Urd-Phonetic)',
|
||||
'Urdu (Windows)': 'IN (Urd-Winkeys)',
|
||||
Uyghur: 'CN (Ug)',
|
||||
Uzbek: 'UZ',
|
||||
'Uzbek (Afghanistan, OLPC)': 'AF (Uz-Olpc)',
|
||||
'Uzbek (Afghanistan)': 'AF (Uz)',
|
||||
'Uzbek (Latin)': 'UZ (Latin)',
|
||||
Vietnamese: 'VN',
|
||||
'Vietnamese (France)': 'VN (Fr)',
|
||||
'Vietnamese (US)': 'VN (Us)',
|
||||
Wolof: 'SN',
|
||||
Yakut: 'RU (Sah)',
|
||||
Yoruba: 'NG (Yoruba)',
|
||||
'Unknown Layout': 'Unknown',
|
||||
} as const;
|
||||
@@ -0,0 +1,84 @@
|
||||
import { BarBoxChild, Module } from 'lib/types/bar';
|
||||
import { BarButtonStyles } from 'lib/types/options';
|
||||
import { Bind } from 'lib/types/variable';
|
||||
import { GtkWidget } from 'lib/types/widget';
|
||||
import options from 'options';
|
||||
import Gtk from 'types/@girs/gtk-3.0/gtk-3.0';
|
||||
|
||||
const { style } = options.theme.bar.buttons;
|
||||
|
||||
const undefinedVar = Variable(undefined);
|
||||
|
||||
export const module = ({
|
||||
icon,
|
||||
textIcon,
|
||||
label,
|
||||
tooltipText,
|
||||
boxClass,
|
||||
props = {},
|
||||
showLabelBinding = undefinedVar.bind('value'),
|
||||
showLabel,
|
||||
labelHook,
|
||||
hook,
|
||||
}: Module): BarBoxChild => {
|
||||
const getIconWidget = (): GtkWidget | undefined => {
|
||||
let iconWidget: Gtk.Widget | undefined;
|
||||
|
||||
if (icon !== undefined) {
|
||||
iconWidget = Widget.Icon({
|
||||
class_name: `txt-icon bar-button-icon module-icon ${boxClass}`,
|
||||
icon: icon,
|
||||
}) as unknown as Gtk.Widget;
|
||||
} else if (textIcon !== undefined) {
|
||||
iconWidget = Widget.Label({
|
||||
class_name: `txt-icon bar-button-icon module-icon ${boxClass}`,
|
||||
label: textIcon,
|
||||
}) as unknown as Gtk.Widget;
|
||||
}
|
||||
|
||||
return iconWidget;
|
||||
};
|
||||
|
||||
return {
|
||||
component: Widget.Box({
|
||||
className: Utils.merge(
|
||||
[style.bind('value'), showLabelBinding],
|
||||
(style: BarButtonStyles, shwLabel: boolean) => {
|
||||
const shouldShowLabel = shwLabel || showLabel;
|
||||
const styleMap = {
|
||||
default: 'style1',
|
||||
split: 'style2',
|
||||
wave: 'style3',
|
||||
wave2: 'style3',
|
||||
};
|
||||
return `${boxClass} ${styleMap[style]} ${!shouldShowLabel ? 'no-label' : ''}`;
|
||||
},
|
||||
),
|
||||
tooltip_text: tooltipText,
|
||||
children: Utils.merge([showLabelBinding], (showLabelBinding): Gtk.Widget[] => {
|
||||
const childrenArray: Gtk.Widget[] = [];
|
||||
const iconWidget = getIconWidget();
|
||||
|
||||
if (iconWidget !== undefined) {
|
||||
childrenArray.push(iconWidget);
|
||||
}
|
||||
|
||||
if (showLabelBinding) {
|
||||
childrenArray.push(
|
||||
Widget.Label({
|
||||
class_name: `bar-button-label module-label ${boxClass}`,
|
||||
label: label,
|
||||
setup: labelHook,
|
||||
}) as unknown as Gtk.Widget,
|
||||
);
|
||||
}
|
||||
return childrenArray;
|
||||
}) as Bind,
|
||||
setup: hook,
|
||||
}),
|
||||
tooltip_text: tooltipText,
|
||||
isVisible: true,
|
||||
boxClass,
|
||||
props,
|
||||
};
|
||||
};
|
||||
@@ -0,0 +1,110 @@
|
||||
import GLib from 'gi://GLib';
|
||||
import { Variable as VariableType } from 'types/variable';
|
||||
import { NetworkResourceData } from 'lib/types/customModules/network';
|
||||
import { GET_DEFAULT_NETSTAT_DATA } from 'lib/types/defaults/netstat';
|
||||
import { RateUnit } from 'lib/types/bar';
|
||||
|
||||
let previousNetUsage = { rx: 0, tx: 0, time: 0 };
|
||||
|
||||
const formatRate = (rate: number, type: string, round: boolean): string => {
|
||||
const fixed = round ? 0 : 2;
|
||||
|
||||
switch (true) {
|
||||
case type === 'KiB':
|
||||
return `${(rate / 1e3).toFixed(fixed)} KiB/s`;
|
||||
case type === 'MiB':
|
||||
return `${(rate / 1e6).toFixed(fixed)} MiB/s`;
|
||||
case type === 'GiB':
|
||||
return `${(rate / 1e9).toFixed(fixed)} GiB/s`;
|
||||
case rate >= 1e9:
|
||||
return `${(rate / 1e9).toFixed(fixed)} GiB/s`;
|
||||
case rate >= 1e6:
|
||||
return `${(rate / 1e6).toFixed(fixed)} MiB/s`;
|
||||
case rate >= 1e3:
|
||||
return `${(rate / 1e3).toFixed(fixed)} KiB/s`;
|
||||
default:
|
||||
return `${rate.toFixed(fixed)} bytes/s`;
|
||||
}
|
||||
};
|
||||
|
||||
interface NetworkUsage {
|
||||
name: string;
|
||||
rx: number;
|
||||
tx: number;
|
||||
}
|
||||
|
||||
const parseInterfaceData = (line: string): NetworkUsage | null => {
|
||||
const trimmedLine = line.trim();
|
||||
if (!trimmedLine || trimmedLine.startsWith('Inter-') || trimmedLine.startsWith('face')) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const [iface, rx, , , , , , , , tx] = trimmedLine.split(/\s+/);
|
||||
const rxValue = parseInt(rx, 10);
|
||||
const txValue = parseInt(tx, 10);
|
||||
const cleanedIface = iface.replace(':', '');
|
||||
|
||||
return { name: cleanedIface, rx: rxValue, tx: txValue };
|
||||
};
|
||||
|
||||
const isValidInterface = (iface: NetworkUsage | null, interfaceName: string): boolean => {
|
||||
if (!iface) return false;
|
||||
if (interfaceName) return iface.name === interfaceName;
|
||||
return iface.name !== 'lo' && iface.rx > 0 && iface.tx > 0;
|
||||
};
|
||||
|
||||
const getNetworkUsage = (interfaceName: string = ''): NetworkUsage => {
|
||||
const [success, data] = GLib.file_get_contents('/proc/net/dev');
|
||||
if (!success) {
|
||||
console.error('Failed to read /proc/net/dev');
|
||||
return { name: '', rx: 0, tx: 0 };
|
||||
}
|
||||
|
||||
const lines = new TextDecoder('utf-8').decode(data).split('\n');
|
||||
for (const line of lines) {
|
||||
const iface = parseInterfaceData(line);
|
||||
if (isValidInterface(iface, interfaceName)) {
|
||||
return iface!;
|
||||
}
|
||||
}
|
||||
|
||||
return { name: '', rx: 0, tx: 0 };
|
||||
};
|
||||
|
||||
export const computeNetwork = (
|
||||
round: VariableType<boolean>,
|
||||
interfaceNameVar: VariableType<string>,
|
||||
dataType: VariableType<RateUnit>,
|
||||
): NetworkResourceData => {
|
||||
const rateUnit = dataType.value;
|
||||
const interfaceName = interfaceNameVar ? interfaceNameVar.value : '';
|
||||
|
||||
const DEFAULT_NETSTAT_DATA = GET_DEFAULT_NETSTAT_DATA(rateUnit);
|
||||
try {
|
||||
const { rx, tx, name } = getNetworkUsage(interfaceName);
|
||||
const currentTime = Date.now();
|
||||
|
||||
if (!name) {
|
||||
return DEFAULT_NETSTAT_DATA;
|
||||
}
|
||||
|
||||
if (previousNetUsage.time === 0) {
|
||||
previousNetUsage = { rx, tx, time: currentTime };
|
||||
return DEFAULT_NETSTAT_DATA;
|
||||
}
|
||||
|
||||
const timeDiff = Math.max((currentTime - previousNetUsage.time) / 1000, 1);
|
||||
const rxRate = (rx - previousNetUsage.rx) / timeDiff;
|
||||
const txRate = (tx - previousNetUsage.tx) / timeDiff;
|
||||
|
||||
previousNetUsage = { rx, tx, time: currentTime };
|
||||
|
||||
return {
|
||||
in: formatRate(rxRate, rateUnit, round.value),
|
||||
out: formatRate(txRate, rateUnit, round.value),
|
||||
};
|
||||
} catch (error) {
|
||||
console.error('Error calculating network usage:', error);
|
||||
return DEFAULT_NETSTAT_DATA;
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,105 @@
|
||||
import options from 'options';
|
||||
import { module } from '../module';
|
||||
import { inputHandler } from 'customModules/utils';
|
||||
import { computeNetwork } from './computeNetwork';
|
||||
import { BarBoxChild, NetstatLabelType } from 'lib/types/bar';
|
||||
import Button from 'types/widgets/button';
|
||||
import { NetworkResourceData } from 'lib/types/customModules/network';
|
||||
import { NETWORK_LABEL_TYPES } from 'lib/types/defaults/bar';
|
||||
import { GET_DEFAULT_NETSTAT_DATA } from 'lib/types/defaults/netstat';
|
||||
import { pollVariable } from 'customModules/PollVar';
|
||||
import { Attribute, Child } from 'lib/types/widget';
|
||||
|
||||
const {
|
||||
label,
|
||||
labelType,
|
||||
networkInterface,
|
||||
rateUnit,
|
||||
icon,
|
||||
round,
|
||||
leftClick,
|
||||
rightClick,
|
||||
middleClick,
|
||||
pollingInterval,
|
||||
} = options.bar.customModules.netstat;
|
||||
|
||||
export const networkUsage = Variable<NetworkResourceData>(GET_DEFAULT_NETSTAT_DATA(rateUnit.value));
|
||||
|
||||
pollVariable(
|
||||
// Variable to poll and update with the result of the function passed in
|
||||
networkUsage,
|
||||
// Variables that should trigger the polling function to update when they change
|
||||
[rateUnit.bind('value'), networkInterface.bind('value'), round.bind('value')],
|
||||
// Interval at which to poll
|
||||
pollingInterval.bind('value'),
|
||||
// Function to execute to get the network data
|
||||
computeNetwork,
|
||||
// Optional parameters to pass to the function
|
||||
// round is a boolean that determines whether to round the values
|
||||
round,
|
||||
// Optional parameters to pass to the function
|
||||
// networkInterface is the interface name to filter the data
|
||||
networkInterface,
|
||||
// Optional parameters to pass to the function
|
||||
// rateUnit is the unit to display the data in
|
||||
// e.g. KiB, MiB, GiB, etc.
|
||||
rateUnit,
|
||||
);
|
||||
|
||||
export const Netstat = (): BarBoxChild => {
|
||||
const renderNetworkLabel = (lblType: NetstatLabelType, network: NetworkResourceData): string => {
|
||||
switch (lblType) {
|
||||
case 'in':
|
||||
return `↓ ${network.in}`;
|
||||
case 'out':
|
||||
return `↑ ${network.out}`;
|
||||
default:
|
||||
return `↓ ${network.in} ↑ ${network.out}`;
|
||||
}
|
||||
};
|
||||
|
||||
const netstatModule = module({
|
||||
textIcon: icon.bind('value'),
|
||||
label: Utils.merge(
|
||||
[networkUsage.bind('value'), labelType.bind('value')],
|
||||
(network: NetworkResourceData, lblTyp: NetstatLabelType) => renderNetworkLabel(lblTyp, network),
|
||||
),
|
||||
tooltipText: labelType.bind('value').as((lblTyp) => {
|
||||
return lblTyp === 'full' ? 'Ingress / Egress' : lblTyp === 'in' ? 'Ingress' : 'Egress';
|
||||
}),
|
||||
boxClass: 'netstat',
|
||||
showLabelBinding: label.bind('value'),
|
||||
props: {
|
||||
setup: (self: Button<Child, Attribute>) => {
|
||||
inputHandler(self, {
|
||||
onPrimaryClick: {
|
||||
cmd: leftClick,
|
||||
},
|
||||
onSecondaryClick: {
|
||||
cmd: rightClick,
|
||||
},
|
||||
onMiddleClick: {
|
||||
cmd: middleClick,
|
||||
},
|
||||
onScrollUp: {
|
||||
fn: () => {
|
||||
labelType.value = NETWORK_LABEL_TYPES[
|
||||
(NETWORK_LABEL_TYPES.indexOf(labelType.value) + 1) % NETWORK_LABEL_TYPES.length
|
||||
] as NetstatLabelType;
|
||||
},
|
||||
},
|
||||
onScrollDown: {
|
||||
fn: () => {
|
||||
labelType.value = NETWORK_LABEL_TYPES[
|
||||
(NETWORK_LABEL_TYPES.indexOf(labelType.value) - 1 + NETWORK_LABEL_TYPES.length) %
|
||||
NETWORK_LABEL_TYPES.length
|
||||
] as NetstatLabelType;
|
||||
},
|
||||
},
|
||||
});
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
return netstatModule;
|
||||
};
|
||||
@@ -0,0 +1,40 @@
|
||||
import options from 'options';
|
||||
import { module } from '../module';
|
||||
|
||||
import { inputHandler } from 'customModules/utils';
|
||||
import Button from 'types/widgets/button';
|
||||
import { Attribute, Child } from 'lib/types/widget';
|
||||
import { BarBoxChild } from 'lib/types/bar';
|
||||
|
||||
const { icon, leftClick, rightClick, middleClick, scrollUp, scrollDown } = options.bar.customModules.power;
|
||||
|
||||
export const Power = (): BarBoxChild => {
|
||||
const powerModule = module({
|
||||
tooltipText: 'Power Menu',
|
||||
textIcon: icon.bind('value'),
|
||||
boxClass: 'powermodule',
|
||||
props: {
|
||||
setup: (self: Button<Child, Attribute>) => {
|
||||
inputHandler(self, {
|
||||
onPrimaryClick: {
|
||||
cmd: leftClick,
|
||||
},
|
||||
onSecondaryClick: {
|
||||
cmd: rightClick,
|
||||
},
|
||||
onMiddleClick: {
|
||||
cmd: middleClick,
|
||||
},
|
||||
onScrollUp: {
|
||||
cmd: scrollUp,
|
||||
},
|
||||
onScrollDown: {
|
||||
cmd: scrollDown,
|
||||
},
|
||||
});
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
return powerModule;
|
||||
};
|
||||
@@ -0,0 +1,40 @@
|
||||
const GLib = imports.gi.GLib;
|
||||
|
||||
import { divide } from 'customModules/utils';
|
||||
import { GenericResourceData } from 'lib/types/customModules/generic';
|
||||
import { Variable as VariableType } from 'types/variable';
|
||||
|
||||
export const calculateRamUsage = (round: VariableType<boolean>): GenericResourceData => {
|
||||
try {
|
||||
const [success, meminfoBytes] = GLib.file_get_contents('/proc/meminfo');
|
||||
|
||||
if (!success || !meminfoBytes) {
|
||||
throw new Error('Failed to read /proc/meminfo or file content is null.');
|
||||
}
|
||||
|
||||
const meminfo = new TextDecoder('utf-8').decode(meminfoBytes);
|
||||
|
||||
const totalMatch = meminfo.match(/MemTotal:\s+(\d+)/);
|
||||
const availableMatch = meminfo.match(/MemAvailable:\s+(\d+)/);
|
||||
|
||||
if (!totalMatch || !availableMatch) {
|
||||
throw new Error('Failed to parse /proc/meminfo for memory values.');
|
||||
}
|
||||
|
||||
const totalRamInBytes = parseInt(totalMatch[1], 10) * 1024;
|
||||
const availableRamInBytes = parseInt(availableMatch[1], 10) * 1024;
|
||||
|
||||
let usedRam = totalRamInBytes - availableRamInBytes;
|
||||
usedRam = isNaN(usedRam) || usedRam < 0 ? 0 : usedRam;
|
||||
|
||||
return {
|
||||
percentage: divide([totalRamInBytes, usedRam], round.value),
|
||||
total: totalRamInBytes,
|
||||
used: usedRam,
|
||||
free: availableRamInBytes,
|
||||
};
|
||||
} catch (error) {
|
||||
console.error('Error calculating RAM usage:', error);
|
||||
return { total: 0, used: 0, percentage: 0, free: 0 };
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,79 @@
|
||||
import options from 'options';
|
||||
|
||||
// Module initializer
|
||||
import { module } from '../module';
|
||||
|
||||
// Types
|
||||
import { GenericResourceData } from 'lib/types/customModules/generic';
|
||||
import Button from 'types/widgets/button';
|
||||
|
||||
// Helper Methods
|
||||
import { calculateRamUsage } from './computeRam';
|
||||
|
||||
// Utility Methods
|
||||
import { formatTooltip, inputHandler, renderResourceLabel } from 'customModules/utils';
|
||||
import { BarBoxChild, ResourceLabelType } from 'lib/types/bar';
|
||||
|
||||
// Global Constants
|
||||
import { LABEL_TYPES } from 'lib/types/defaults/bar';
|
||||
import { pollVariable } from 'customModules/PollVar';
|
||||
import { Attribute, Child } from 'lib/types/widget';
|
||||
|
||||
// All the user configurable options for the ram module that are needed
|
||||
const { label, labelType, round, leftClick, rightClick, middleClick, pollingInterval, icon } =
|
||||
options.bar.customModules.ram;
|
||||
|
||||
const defaultRamData: GenericResourceData = { total: 0, used: 0, percentage: 0, free: 0 };
|
||||
const ramUsage = Variable<GenericResourceData>(defaultRamData);
|
||||
|
||||
pollVariable(ramUsage, [round.bind('value')], pollingInterval.bind('value'), calculateRamUsage, round);
|
||||
|
||||
export const Ram = (): BarBoxChild => {
|
||||
const ramModule = module({
|
||||
textIcon: icon.bind('value'),
|
||||
label: Utils.merge(
|
||||
[ramUsage.bind('value'), labelType.bind('value'), round.bind('value')],
|
||||
(rmUsg: GenericResourceData, lblTyp: ResourceLabelType, round: boolean) => {
|
||||
const returnValue = renderResourceLabel(lblTyp, rmUsg, round);
|
||||
|
||||
return returnValue;
|
||||
},
|
||||
),
|
||||
tooltipText: labelType.bind('value').as((lblTyp) => {
|
||||
return formatTooltip('RAM', lblTyp);
|
||||
}),
|
||||
boxClass: 'ram',
|
||||
showLabelBinding: label.bind('value'),
|
||||
props: {
|
||||
setup: (self: Button<Child, Attribute>) => {
|
||||
inputHandler(self, {
|
||||
onPrimaryClick: {
|
||||
cmd: leftClick,
|
||||
},
|
||||
onSecondaryClick: {
|
||||
cmd: rightClick,
|
||||
},
|
||||
onMiddleClick: {
|
||||
cmd: middleClick,
|
||||
},
|
||||
onScrollUp: {
|
||||
fn: () => {
|
||||
labelType.value = LABEL_TYPES[
|
||||
(LABEL_TYPES.indexOf(labelType.value) + 1) % LABEL_TYPES.length
|
||||
] as ResourceLabelType;
|
||||
},
|
||||
},
|
||||
onScrollDown: {
|
||||
fn: () => {
|
||||
labelType.value = LABEL_TYPES[
|
||||
(LABEL_TYPES.indexOf(labelType.value) - 1 + LABEL_TYPES.length) % LABEL_TYPES.length
|
||||
] as ResourceLabelType;
|
||||
},
|
||||
},
|
||||
});
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
return ramModule;
|
||||
};
|
||||
@@ -0,0 +1,28 @@
|
||||
// @ts-expect-error is a special directive that tells the compiler to use the GTop library
|
||||
import GTop from 'gi://GTop';
|
||||
|
||||
import { divide } from 'customModules/utils';
|
||||
import { Variable as VariableType } from 'types/variable';
|
||||
import { GenericResourceData } from 'lib/types/customModules/generic';
|
||||
|
||||
export const computeStorage = (round: VariableType<boolean>): GenericResourceData => {
|
||||
try {
|
||||
const currentFsUsage = new GTop.glibtop_fsusage();
|
||||
|
||||
GTop.glibtop_get_fsusage(currentFsUsage, '/');
|
||||
|
||||
const total = currentFsUsage.blocks * currentFsUsage.block_size;
|
||||
const available = currentFsUsage.bavail * currentFsUsage.block_size;
|
||||
const used = total - available;
|
||||
|
||||
return {
|
||||
total,
|
||||
used,
|
||||
free: available,
|
||||
percentage: divide([total, used], round.value),
|
||||
};
|
||||
} catch (error) {
|
||||
console.error('Error calculating RAM usage:', error);
|
||||
return { total: 0, used: 0, percentage: 0, free: 0 };
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,68 @@
|
||||
import options from 'options';
|
||||
import { module } from '../module';
|
||||
|
||||
import { formatTooltip, inputHandler, renderResourceLabel } from 'customModules/utils';
|
||||
import { computeStorage } from './computeStorage';
|
||||
import { BarBoxChild, ResourceLabelType } from 'lib/types/bar';
|
||||
import { GenericResourceData } from 'lib/types/customModules/generic';
|
||||
import Button from 'types/widgets/button';
|
||||
import { LABEL_TYPES } from 'lib/types/defaults/bar';
|
||||
import { pollVariable } from 'customModules/PollVar';
|
||||
import { Attribute, Child } from 'lib/types/widget';
|
||||
|
||||
const { label, labelType, icon, round, leftClick, rightClick, middleClick, pollingInterval } =
|
||||
options.bar.customModules.storage;
|
||||
|
||||
const defaultStorageData = { total: 0, used: 0, percentage: 0, free: 0 };
|
||||
|
||||
const storageUsage = Variable<GenericResourceData>(defaultStorageData);
|
||||
|
||||
pollVariable(storageUsage, [round.bind('value')], pollingInterval.bind('value'), computeStorage, round);
|
||||
|
||||
export const Storage = (): BarBoxChild => {
|
||||
const storageModule = module({
|
||||
textIcon: icon.bind('value'),
|
||||
label: Utils.merge(
|
||||
[storageUsage.bind('value'), labelType.bind('value'), round.bind('value')],
|
||||
(storage: GenericResourceData, lblTyp: ResourceLabelType, round: boolean) => {
|
||||
return renderResourceLabel(lblTyp, storage, round);
|
||||
},
|
||||
),
|
||||
tooltipText: labelType.bind('value').as((lblTyp) => {
|
||||
return formatTooltip('Storage', lblTyp);
|
||||
}),
|
||||
boxClass: 'storage',
|
||||
showLabelBinding: label.bind('value'),
|
||||
props: {
|
||||
setup: (self: Button<Child, Attribute>) => {
|
||||
inputHandler(self, {
|
||||
onPrimaryClick: {
|
||||
cmd: leftClick,
|
||||
},
|
||||
onSecondaryClick: {
|
||||
cmd: rightClick,
|
||||
},
|
||||
onMiddleClick: {
|
||||
cmd: middleClick,
|
||||
},
|
||||
onScrollUp: {
|
||||
fn: () => {
|
||||
labelType.value = LABEL_TYPES[
|
||||
(LABEL_TYPES.indexOf(labelType.value) + 1) % LABEL_TYPES.length
|
||||
] as ResourceLabelType;
|
||||
},
|
||||
},
|
||||
onScrollDown: {
|
||||
fn: () => {
|
||||
labelType.value = LABEL_TYPES[
|
||||
(LABEL_TYPES.indexOf(labelType.value) - 1 + LABEL_TYPES.length) % LABEL_TYPES.length
|
||||
] as ResourceLabelType;
|
||||
},
|
||||
},
|
||||
});
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
return storageModule;
|
||||
};
|
||||
@@ -0,0 +1,20 @@
|
||||
import { Variable } from 'types/variable';
|
||||
|
||||
const hyprland = await Service.import('hyprland');
|
||||
|
||||
export const isSubmapEnabled = (submap: string, enabled: string, disabled: string): string => {
|
||||
return submap !== 'default' ? enabled : disabled;
|
||||
};
|
||||
|
||||
export const getInitialSubmap = (submapStatus: Variable<string>): void => {
|
||||
let submap = hyprland.message('submap');
|
||||
|
||||
const newLineCarriage = /\n/g;
|
||||
submap = submap.replace(newLineCarriage, '');
|
||||
|
||||
if (submap === 'unknown request') {
|
||||
submap = 'default';
|
||||
}
|
||||
|
||||
submapStatus.value = submap;
|
||||
};
|
||||
@@ -0,0 +1,101 @@
|
||||
const hyprland = await Service.import('hyprland');
|
||||
import options from 'options';
|
||||
import { module } from '../module';
|
||||
|
||||
import { inputHandler } from 'customModules/utils';
|
||||
import Button from 'types/widgets/button';
|
||||
import { Variable as VariableType } from 'types/variable';
|
||||
import { Attribute, Child } from 'lib/types/widget';
|
||||
import { BarBoxChild } from 'lib/types/bar';
|
||||
import { capitalizeFirstLetter } from 'lib/utils';
|
||||
import { getInitialSubmap, isSubmapEnabled } from './helpers';
|
||||
|
||||
const {
|
||||
label,
|
||||
showSubmapName,
|
||||
enabledIcon,
|
||||
disabledIcon,
|
||||
enabledText,
|
||||
disabledText,
|
||||
leftClick,
|
||||
rightClick,
|
||||
middleClick,
|
||||
scrollUp,
|
||||
scrollDown,
|
||||
} = options.bar.customModules.submap;
|
||||
|
||||
const submapStatus: VariableType<string> = Variable('default');
|
||||
|
||||
hyprland.connect('submap', (_, currentSubmap) => {
|
||||
if (currentSubmap.length === 0) {
|
||||
submapStatus.value = 'default';
|
||||
} else {
|
||||
submapStatus.value = currentSubmap;
|
||||
}
|
||||
});
|
||||
|
||||
getInitialSubmap(submapStatus);
|
||||
|
||||
export const Submap = (): BarBoxChild => {
|
||||
const submapModule = module({
|
||||
textIcon: Utils.merge(
|
||||
[submapStatus.bind('value'), enabledIcon.bind('value'), disabledIcon.bind('value')],
|
||||
(status, enabled, disabled) => {
|
||||
return isSubmapEnabled(status, enabled, disabled);
|
||||
},
|
||||
),
|
||||
tooltipText: Utils.merge(
|
||||
[
|
||||
submapStatus.bind('value'),
|
||||
enabledText.bind('value'),
|
||||
disabledText.bind('value'),
|
||||
showSubmapName.bind('value'),
|
||||
],
|
||||
(status, enabled, disabled, showSmName) => {
|
||||
if (showSmName) {
|
||||
return capitalizeFirstLetter(status);
|
||||
}
|
||||
return isSubmapEnabled(status, enabled, disabled);
|
||||
},
|
||||
),
|
||||
boxClass: 'submap',
|
||||
label: Utils.merge(
|
||||
[
|
||||
submapStatus.bind('value'),
|
||||
enabledText.bind('value'),
|
||||
disabledText.bind('value'),
|
||||
showSubmapName.bind('value'),
|
||||
],
|
||||
(status, enabled, disabled, showSmName) => {
|
||||
if (showSmName) {
|
||||
return capitalizeFirstLetter(status);
|
||||
}
|
||||
return isSubmapEnabled(status, enabled, disabled);
|
||||
},
|
||||
),
|
||||
showLabelBinding: label.bind('value'),
|
||||
props: {
|
||||
setup: (self: Button<Child, Attribute>) => {
|
||||
inputHandler(self, {
|
||||
onPrimaryClick: {
|
||||
cmd: leftClick,
|
||||
},
|
||||
onSecondaryClick: {
|
||||
cmd: rightClick,
|
||||
},
|
||||
onMiddleClick: {
|
||||
cmd: middleClick,
|
||||
},
|
||||
onScrollUp: {
|
||||
cmd: scrollUp,
|
||||
},
|
||||
onScrollDown: {
|
||||
cmd: scrollDown,
|
||||
},
|
||||
});
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
return submapModule;
|
||||
};
|
||||
@@ -0,0 +1,171 @@
|
||||
import { Option } from 'widget/settings/shared/Option';
|
||||
import { Header } from 'widget/settings/shared/Header';
|
||||
|
||||
import options from 'options';
|
||||
import Scrollable from 'types/widgets/scrollable';
|
||||
import { Attribute, GtkWidget } from 'lib/types/widget';
|
||||
|
||||
export const CustomModuleTheme = (): Scrollable<GtkWidget, Attribute> => {
|
||||
return Widget.Scrollable({
|
||||
vscroll: 'automatic',
|
||||
hscroll: 'automatic',
|
||||
class_name: 'menu-theme-page customModules paged-container',
|
||||
child: Widget.Box({
|
||||
class_name: 'bar-theme-page paged-container',
|
||||
vertical: true,
|
||||
children: [
|
||||
Header('RAM'),
|
||||
Option({ opt: options.theme.bar.buttons.modules.ram.text, title: 'Text', type: 'color' }),
|
||||
Option({ opt: options.theme.bar.buttons.modules.ram.icon, title: 'Icon', type: 'color' }),
|
||||
Option({
|
||||
opt: options.theme.bar.buttons.modules.ram.background,
|
||||
title: 'Label Background',
|
||||
type: 'color',
|
||||
}),
|
||||
Option({
|
||||
opt: options.theme.bar.buttons.modules.ram.icon_background,
|
||||
title: 'Icon Background',
|
||||
subtitle:
|
||||
"Applies a background color to the icon section of the button.\nRequires 'split' button styling.",
|
||||
type: 'color',
|
||||
}),
|
||||
Option({ opt: options.theme.bar.buttons.modules.ram.border, title: 'Border', type: 'color' }),
|
||||
|
||||
Header('CPU'),
|
||||
Option({ opt: options.theme.bar.buttons.modules.cpu.text, title: 'Text', type: 'color' }),
|
||||
Option({ opt: options.theme.bar.buttons.modules.cpu.icon, title: 'Icon', type: 'color' }),
|
||||
Option({
|
||||
opt: options.theme.bar.buttons.modules.cpu.background,
|
||||
title: 'Label Background',
|
||||
type: 'color',
|
||||
}),
|
||||
Option({
|
||||
opt: options.theme.bar.buttons.modules.cpu.icon_background,
|
||||
title: 'Icon Background',
|
||||
subtitle:
|
||||
"Applies a background color to the icon section of the button.\nRequires 'split' button styling.",
|
||||
type: 'color',
|
||||
}),
|
||||
Option({ opt: options.theme.bar.buttons.modules.cpu.border, title: 'Border', type: 'color' }),
|
||||
|
||||
Header('Storage'),
|
||||
Option({ opt: options.theme.bar.buttons.modules.storage.text, title: 'Text', type: 'color' }),
|
||||
Option({ opt: options.theme.bar.buttons.modules.storage.icon, title: 'Icon', type: 'color' }),
|
||||
Option({
|
||||
opt: options.theme.bar.buttons.modules.storage.background,
|
||||
title: 'Label Background',
|
||||
type: 'color',
|
||||
}),
|
||||
Option({
|
||||
opt: options.theme.bar.buttons.modules.storage.icon_background,
|
||||
title: 'Icon Background',
|
||||
subtitle:
|
||||
"Applies a background color to the icon section of the button.\nRequires 'split' button styling.",
|
||||
type: 'color',
|
||||
}),
|
||||
Option({ opt: options.theme.bar.buttons.modules.storage.border, title: 'Border', type: 'color' }),
|
||||
|
||||
Header('Netstat'),
|
||||
Option({ opt: options.theme.bar.buttons.modules.netstat.text, title: 'Text', type: 'color' }),
|
||||
Option({ opt: options.theme.bar.buttons.modules.netstat.icon, title: 'Icon', type: 'color' }),
|
||||
Option({
|
||||
opt: options.theme.bar.buttons.modules.netstat.background,
|
||||
title: 'Label Background',
|
||||
type: 'color',
|
||||
}),
|
||||
Option({
|
||||
opt: options.theme.bar.buttons.modules.netstat.icon_background,
|
||||
title: 'Icon Background',
|
||||
subtitle:
|
||||
"Applies a background color to the icon section of the button.\nRequires 'split' button styling.",
|
||||
type: 'color',
|
||||
}),
|
||||
Option({ opt: options.theme.bar.buttons.modules.netstat.border, title: 'Border', type: 'color' }),
|
||||
|
||||
Header('Keyboard Layout'),
|
||||
Option({ opt: options.theme.bar.buttons.modules.kbLayout.text, title: 'Text', type: 'color' }),
|
||||
Option({ opt: options.theme.bar.buttons.modules.kbLayout.icon, title: 'Icon', type: 'color' }),
|
||||
Option({
|
||||
opt: options.theme.bar.buttons.modules.kbLayout.background,
|
||||
title: 'Label Background',
|
||||
type: 'color',
|
||||
}),
|
||||
Option({
|
||||
opt: options.theme.bar.buttons.modules.kbLayout.icon_background,
|
||||
title: 'Icon Background',
|
||||
subtitle:
|
||||
"Applies a background color to the icon section of the button.\nRequires 'split' button styling.",
|
||||
type: 'color',
|
||||
}),
|
||||
Option({ opt: options.theme.bar.buttons.modules.kbLayout.border, title: 'Border', type: 'color' }),
|
||||
|
||||
Header('Updates'),
|
||||
Option({ opt: options.theme.bar.buttons.modules.updates.text, title: 'Text', type: 'color' }),
|
||||
Option({ opt: options.theme.bar.buttons.modules.updates.icon, title: 'Icon', type: 'color' }),
|
||||
Option({
|
||||
opt: options.theme.bar.buttons.modules.updates.background,
|
||||
title: 'Label Background',
|
||||
type: 'color',
|
||||
}),
|
||||
Option({
|
||||
opt: options.theme.bar.buttons.modules.updates.icon_background,
|
||||
title: 'Icon Background',
|
||||
subtitle:
|
||||
"Applies a background color to the icon section of the button.\nRequires 'split' button styling.",
|
||||
type: 'color',
|
||||
}),
|
||||
Option({ opt: options.theme.bar.buttons.modules.updates.border, title: 'Border', type: 'color' }),
|
||||
|
||||
Header('Submap'),
|
||||
Option({ opt: options.theme.bar.buttons.modules.submap.text, title: 'Text', type: 'color' }),
|
||||
Option({ opt: options.theme.bar.buttons.modules.submap.icon, title: 'Icon', type: 'color' }),
|
||||
Option({
|
||||
opt: options.theme.bar.buttons.modules.submap.background,
|
||||
title: 'Label Background',
|
||||
type: 'color',
|
||||
}),
|
||||
Option({
|
||||
opt: options.theme.bar.buttons.modules.submap.icon_background,
|
||||
title: 'Icon Background',
|
||||
subtitle:
|
||||
"Applies a background color to the icon section of the button.\nRequires 'split' button styling.",
|
||||
type: 'color',
|
||||
}),
|
||||
Option({ opt: options.theme.bar.buttons.modules.submap.border, title: 'Border', type: 'color' }),
|
||||
|
||||
Header('Weather'),
|
||||
Option({ opt: options.theme.bar.buttons.modules.weather.icon, title: 'Icon', type: 'color' }),
|
||||
Option({ opt: options.theme.bar.buttons.modules.weather.text, title: 'Text', type: 'color' }),
|
||||
Option({
|
||||
opt: options.theme.bar.buttons.modules.weather.background,
|
||||
title: 'Label Background',
|
||||
type: 'color',
|
||||
}),
|
||||
Option({
|
||||
opt: options.theme.bar.buttons.modules.weather.icon_background,
|
||||
title: 'Icon Background',
|
||||
subtitle:
|
||||
"Applies a background color to the icon section of the button.\nRequires 'split' button styling.",
|
||||
type: 'color',
|
||||
}),
|
||||
Option({ opt: options.theme.bar.buttons.modules.weather.border, title: 'Border', type: 'color' }),
|
||||
|
||||
Header('Power'),
|
||||
Option({ opt: options.theme.bar.buttons.modules.power.icon, title: 'Icon', type: 'color' }),
|
||||
Option({
|
||||
opt: options.theme.bar.buttons.modules.power.background,
|
||||
title: 'Label Background',
|
||||
type: 'color',
|
||||
}),
|
||||
Option({
|
||||
opt: options.theme.bar.buttons.modules.power.icon_background,
|
||||
title: 'Icon Background',
|
||||
subtitle:
|
||||
"Applies a background color to the icon section of the button.\nRequires 'split' button styling.",
|
||||
type: 'color',
|
||||
}),
|
||||
Option({ opt: options.theme.bar.buttons.modules.power.border, title: 'Border', type: 'color' }),
|
||||
],
|
||||
}),
|
||||
});
|
||||
};
|
||||
@@ -0,0 +1,70 @@
|
||||
import options from 'options';
|
||||
import { module } from '../module';
|
||||
|
||||
import { inputHandler } from 'customModules/utils';
|
||||
import Button from 'types/widgets/button';
|
||||
import { Variable as VariableType } from 'types/variable';
|
||||
import { pollVariableBash } from 'customModules/PollVar';
|
||||
import { Attribute, Child } from 'lib/types/widget';
|
||||
import { BarBoxChild } from 'lib/types/bar';
|
||||
|
||||
const {
|
||||
updateCommand,
|
||||
label,
|
||||
padZero,
|
||||
pollingInterval,
|
||||
icon,
|
||||
leftClick,
|
||||
rightClick,
|
||||
middleClick,
|
||||
scrollUp,
|
||||
scrollDown,
|
||||
} = options.bar.customModules.updates;
|
||||
|
||||
const pendingUpdates: VariableType<string> = Variable(' 0');
|
||||
|
||||
const processUpdateCount = (updateCount: string): string => {
|
||||
if (!padZero.value) return updateCount;
|
||||
return `${updateCount.padStart(2, '0')}`;
|
||||
};
|
||||
|
||||
pollVariableBash(
|
||||
pendingUpdates,
|
||||
[padZero.bind('value')],
|
||||
pollingInterval.bind('value'),
|
||||
updateCommand.value,
|
||||
processUpdateCount,
|
||||
);
|
||||
|
||||
export const Updates = (): BarBoxChild => {
|
||||
const updatesModule = module({
|
||||
textIcon: icon.bind('value'),
|
||||
tooltipText: pendingUpdates.bind('value').as((v) => `${v} updates available`),
|
||||
boxClass: 'updates',
|
||||
label: pendingUpdates.bind('value'),
|
||||
showLabelBinding: label.bind('value'),
|
||||
props: {
|
||||
setup: (self: Button<Child, Attribute>) => {
|
||||
inputHandler(self, {
|
||||
onPrimaryClick: {
|
||||
cmd: leftClick,
|
||||
},
|
||||
onSecondaryClick: {
|
||||
cmd: rightClick,
|
||||
},
|
||||
onMiddleClick: {
|
||||
cmd: middleClick,
|
||||
},
|
||||
onScrollUp: {
|
||||
cmd: scrollUp,
|
||||
},
|
||||
onScrollDown: {
|
||||
cmd: scrollDown,
|
||||
},
|
||||
});
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
return updatesModule;
|
||||
};
|
||||
@@ -0,0 +1,197 @@
|
||||
import { ResourceLabelType } from 'lib/types/bar';
|
||||
import { GenericResourceData, Postfix } from 'lib/types/customModules/generic';
|
||||
import { InputHandlerEvents, RunAsyncCommand } from 'lib/types/customModules/utils';
|
||||
import { ThrottleFn, ThrottleFnCallback } from 'lib/types/utils';
|
||||
import { Attribute, Child, EventArgs } from 'lib/types/widget';
|
||||
import { Binding } from 'lib/utils';
|
||||
import { openMenu } from 'modules/bar/utils';
|
||||
import options from 'options';
|
||||
import Gdk from 'types/@girs/gdk-3.0/gdk-3.0';
|
||||
import { Variable as VariableType } from 'types/variable';
|
||||
import Button from 'types/widgets/button';
|
||||
|
||||
const { scrollSpeed } = options.bar.customModules;
|
||||
|
||||
export const runAsyncCommand: RunAsyncCommand = (cmd, events, fn): void => {
|
||||
if (cmd.startsWith('menu:')) {
|
||||
const menuName = cmd.split(':')[1].trim().toLowerCase();
|
||||
openMenu(events.clicked, events.event, `${menuName}menu`);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
Utils.execAsync(`bash -c "${cmd}"`)
|
||||
.then((output) => {
|
||||
if (fn !== undefined) {
|
||||
fn(output);
|
||||
}
|
||||
})
|
||||
.catch((err) => console.error(`Error running command "${cmd}": ${err})`));
|
||||
};
|
||||
|
||||
export function throttle<T extends ThrottleFn>(func: T, limit: number): T {
|
||||
let inThrottle: boolean;
|
||||
return function (this: ThisParameterType<T>, ...args: Parameters<T>) {
|
||||
if (!inThrottle) {
|
||||
func.apply(this, args);
|
||||
inThrottle = true;
|
||||
setTimeout(() => {
|
||||
inThrottle = false;
|
||||
}, limit);
|
||||
}
|
||||
} as T;
|
||||
}
|
||||
|
||||
export const throttledScrollHandler = (interval: number): ThrottleFn =>
|
||||
throttle((cmd: string, events: EventArgs, fn: ThrottleFnCallback) => {
|
||||
runAsyncCommand(cmd, events, fn);
|
||||
}, 200 / interval);
|
||||
|
||||
const dummyVar = Variable('');
|
||||
|
||||
export const inputHandler = (
|
||||
self: Button<Child, Attribute>,
|
||||
{ onPrimaryClick, onSecondaryClick, onMiddleClick, onScrollUp, onScrollDown }: InputHandlerEvents,
|
||||
): void => {
|
||||
const sanitizeInput = (input: VariableType<string>): string => {
|
||||
if (input === undefined) {
|
||||
return '';
|
||||
}
|
||||
return input.value;
|
||||
};
|
||||
|
||||
const updateHandlers = (): void => {
|
||||
const interval = scrollSpeed.value;
|
||||
const throttledHandler = throttledScrollHandler(interval);
|
||||
|
||||
self.on_primary_click = (clicked: Button<Child, Attribute>, event: Gdk.Event): void =>
|
||||
runAsyncCommand(sanitizeInput(onPrimaryClick?.cmd || dummyVar), { clicked, event }, onPrimaryClick.fn);
|
||||
|
||||
self.on_secondary_click = (clicked: Button<Child, Attribute>, event: Gdk.Event): void =>
|
||||
runAsyncCommand(sanitizeInput(onSecondaryClick?.cmd || dummyVar), { clicked, event }, onSecondaryClick.fn);
|
||||
|
||||
self.on_middle_click = (clicked: Button<Child, Attribute>, event: Gdk.Event): void =>
|
||||
runAsyncCommand(sanitizeInput(onMiddleClick?.cmd || dummyVar), { clicked, event }, onMiddleClick.fn);
|
||||
|
||||
self.on_scroll_up = (clicked: Button<Child, Attribute>, event: Gdk.Event): void =>
|
||||
throttledHandler(sanitizeInput(onScrollUp?.cmd || dummyVar), { clicked, event }, onScrollUp.fn);
|
||||
|
||||
self.on_scroll_down = (clicked: Button<Child, Attribute>, event: Gdk.Event): void =>
|
||||
throttledHandler(sanitizeInput(onScrollDown?.cmd || dummyVar), { clicked, event }, onScrollDown.fn);
|
||||
};
|
||||
|
||||
// Initial setup of event handlers
|
||||
updateHandlers();
|
||||
|
||||
const sanitizeVariable = (someVar: VariableType<string> | undefined): Binding<string> => {
|
||||
if (someVar === undefined || typeof someVar.bind !== 'function') {
|
||||
return dummyVar.bind('value');
|
||||
}
|
||||
return someVar.bind('value');
|
||||
};
|
||||
|
||||
// Re-run the update whenever scrollSpeed changes
|
||||
Utils.merge(
|
||||
[
|
||||
scrollSpeed.bind('value'),
|
||||
sanitizeVariable(onPrimaryClick),
|
||||
sanitizeVariable(onSecondaryClick),
|
||||
sanitizeVariable(onMiddleClick),
|
||||
sanitizeVariable(onScrollUp),
|
||||
sanitizeVariable(onScrollDown),
|
||||
],
|
||||
updateHandlers,
|
||||
);
|
||||
};
|
||||
|
||||
export const divide = ([total, used]: number[], round: boolean): number => {
|
||||
const percentageTotal = (used / total) * 100;
|
||||
if (round) {
|
||||
return total > 0 ? Math.round(percentageTotal) : 0;
|
||||
}
|
||||
return total > 0 ? parseFloat(percentageTotal.toFixed(2)) : 0;
|
||||
};
|
||||
|
||||
export const formatSizeInKiB = (sizeInBytes: number, round: boolean): number => {
|
||||
const sizeInGiB = sizeInBytes / 1024 ** 1;
|
||||
return round ? Math.round(sizeInGiB) : parseFloat(sizeInGiB.toFixed(2));
|
||||
};
|
||||
export const formatSizeInMiB = (sizeInBytes: number, round: boolean): number => {
|
||||
const sizeInGiB = sizeInBytes / 1024 ** 2;
|
||||
return round ? Math.round(sizeInGiB) : parseFloat(sizeInGiB.toFixed(2));
|
||||
};
|
||||
export const formatSizeInGiB = (sizeInBytes: number, round: boolean): number => {
|
||||
const sizeInGiB = sizeInBytes / 1024 ** 3;
|
||||
return round ? Math.round(sizeInGiB) : parseFloat(sizeInGiB.toFixed(2));
|
||||
};
|
||||
export const formatSizeInTiB = (sizeInBytes: number, round: boolean): number => {
|
||||
const sizeInGiB = sizeInBytes / 1024 ** 4;
|
||||
return round ? Math.round(sizeInGiB) : parseFloat(sizeInGiB.toFixed(2));
|
||||
};
|
||||
|
||||
export const autoFormatSize = (sizeInBytes: number, round: boolean): number => {
|
||||
// auto convert to GiB, MiB, KiB, TiB, or bytes
|
||||
if (sizeInBytes >= 1024 ** 4) return formatSizeInTiB(sizeInBytes, round);
|
||||
if (sizeInBytes >= 1024 ** 3) return formatSizeInGiB(sizeInBytes, round);
|
||||
if (sizeInBytes >= 1024 ** 2) return formatSizeInMiB(sizeInBytes, round);
|
||||
if (sizeInBytes >= 1024 ** 1) return formatSizeInKiB(sizeInBytes, round);
|
||||
|
||||
return sizeInBytes;
|
||||
};
|
||||
|
||||
export const getPostfix = (sizeInBytes: number): Postfix => {
|
||||
if (sizeInBytes >= 1024 ** 4) return 'TiB';
|
||||
if (sizeInBytes >= 1024 ** 3) return 'GiB';
|
||||
if (sizeInBytes >= 1024 ** 2) return 'MiB';
|
||||
if (sizeInBytes >= 1024 ** 1) return 'KiB';
|
||||
|
||||
return 'B';
|
||||
};
|
||||
|
||||
export const renderResourceLabel = (lblType: ResourceLabelType, rmUsg: GenericResourceData, round: boolean): string => {
|
||||
const { used, total, percentage, free } = rmUsg;
|
||||
|
||||
const formatFunctions = {
|
||||
TiB: formatSizeInTiB,
|
||||
GiB: formatSizeInGiB,
|
||||
MiB: formatSizeInMiB,
|
||||
KiB: formatSizeInKiB,
|
||||
B: (size: number): number => size,
|
||||
};
|
||||
|
||||
// Get them datas in proper GiB, MiB, KiB, TiB, or bytes
|
||||
const totalSizeFormatted = autoFormatSize(total, round);
|
||||
// get the postfix: one of [TiB, GiB, MiB, KiB, B]
|
||||
const postfix = getPostfix(total);
|
||||
|
||||
// Determine which format function to use
|
||||
const formatUsed = formatFunctions[postfix] || formatFunctions['B'];
|
||||
const usedSizeFormatted = formatUsed(used, round);
|
||||
|
||||
if (lblType === 'used/total') {
|
||||
return `${usedSizeFormatted}/${totalSizeFormatted} ${postfix}`;
|
||||
}
|
||||
if (lblType === 'used') {
|
||||
return `${autoFormatSize(used, round)} ${getPostfix(used)}`;
|
||||
}
|
||||
if (lblType === 'free') {
|
||||
return `${autoFormatSize(free, round)} ${getPostfix(free)}`;
|
||||
}
|
||||
|
||||
return `${percentage}%`;
|
||||
};
|
||||
|
||||
export const formatTooltip = (dataType: string, lblTyp: ResourceLabelType): string => {
|
||||
switch (lblTyp) {
|
||||
case 'used':
|
||||
return `Used ${dataType}`;
|
||||
case 'free':
|
||||
return `Free ${dataType}`;
|
||||
case 'used/total':
|
||||
return `Used/Total ${dataType}`;
|
||||
case 'percentage':
|
||||
return `Percentage ${dataType} Usage`;
|
||||
default:
|
||||
return '';
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,52 @@
|
||||
import options from 'options';
|
||||
import { module } from '../module';
|
||||
|
||||
import { inputHandler } from 'customModules/utils';
|
||||
import Button from 'types/widgets/button';
|
||||
import { getWeatherStatusTextIcon, globalWeatherVar } from 'globals/weather';
|
||||
import { Attribute, Child } from 'lib/types/widget';
|
||||
import { BarBoxChild } from 'lib/types/bar';
|
||||
|
||||
const { label, unit, leftClick, rightClick, middleClick, scrollUp, scrollDown } = options.bar.customModules.weather;
|
||||
|
||||
export const Weather = (): BarBoxChild => {
|
||||
const weatherModule = module({
|
||||
textIcon: Utils.merge([globalWeatherVar.bind('value')], (wthr) => {
|
||||
const weatherStatusIcon = getWeatherStatusTextIcon(wthr);
|
||||
return weatherStatusIcon;
|
||||
}),
|
||||
tooltipText: globalWeatherVar.bind('value').as((v) => `Weather Status: ${v.current.condition.text}`),
|
||||
boxClass: 'weather-custom',
|
||||
label: Utils.merge([globalWeatherVar.bind('value'), unit.bind('value')], (wthr, unt) => {
|
||||
if (unt === 'imperial') {
|
||||
return `${Math.ceil(wthr.current.temp_f)}° F`;
|
||||
} else {
|
||||
return `${Math.ceil(wthr.current.temp_c)}° C`;
|
||||
}
|
||||
}),
|
||||
showLabelBinding: label.bind('value'),
|
||||
props: {
|
||||
setup: (self: Button<Child, Attribute>) => {
|
||||
inputHandler(self, {
|
||||
onPrimaryClick: {
|
||||
cmd: leftClick,
|
||||
},
|
||||
onSecondaryClick: {
|
||||
cmd: rightClick,
|
||||
},
|
||||
onMiddleClick: {
|
||||
cmd: middleClick,
|
||||
},
|
||||
onScrollUp: {
|
||||
cmd: scrollUp,
|
||||
},
|
||||
onScrollDown: {
|
||||
cmd: scrollDown,
|
||||
},
|
||||
});
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
return weatherModule;
|
||||
};
|
||||
Reference in new issue
Block a user