Allow bools, ints and floats for widget configs and major refactoring (#248)

This commit is contained in:
magnouvean 2024-07-12 18:47:31 +02:00 committed by GitHub
parent 8c84e04023
commit 0557cecf3f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
11 changed files with 510 additions and 352 deletions

View File

@ -1,40 +1,60 @@
{ lib, widgets, ... }:
{ lib, ... }:
let
inherit (lib) mkOption types;
inherit (widgets.lib) mkBoolOption mkEnumOption;
convertHorizontalAlignment = horizontalAlignment: let
mappings = {
"left" = "1";
"right" = "2";
"center" = "4";
"justify" = "8";
};
in
mappings.${horizontalAlignment} or (throw "Invalid enum value: ${horizontalAlignment}");
mkBoolOption = description: lib.mkOption {
type = with lib.types; nullOr bool;
default = null;
inherit description;
};
convertVerticalAlignment = verticalAlignment: let
mappings = {
"top" = "1";
"center" = "128";
"bottom" = "64";
"baseline" = "256";
};
in
mappings.${verticalAlignment} or (throw "Invalid enum value: ${verticalAlignment}");
convertHorizontalAlignment = horizontalAlignment:
let
mappings = {
left = 1;
right = 2;
center = 4;
justify = 8;
};
in
mappings.${horizontalAlignment} or (throw "Invalid enum value: ${horizontalAlignment}");
convertVerticalAlignment = verticalAlignment:
let
mappings = {
top = 1;
center = 128;
bottom = 64;
baseline = 256;
};
in
mappings.${verticalAlignment} or (throw "Invalid enum value: ${verticalAlignment}");
getIndexFromEnum = enum: value:
if value == null
then null
else
lib.lists.findFirstIndex
(x: x == value)
(throw "getIndexFromEnum (application-title-bar widget): Value ${value} isn't present in the enum. This is a bug")
enum;
fontType = types.submodule {
options = {
bold = mkBoolOption "Enable bold text.";
fit = mkEnumOption [ "fixedSize" "horizontalFit" "verticalFit" "fit" ] // {
example = "fixedSize";
description = "The mode of the size of the font.";
};
fit =
let enumVals = [ "fixedSize" "horizontalFit" "verticalFit" "fit" ];
in mkOption {
type = with types; nullOr (enum enumVals);
default = null;
example = "fixedSize";
description = "The mode of the size of the font.";
apply = getIndexFromEnum enumVals;
};
size = mkOption {
type = types.ints.positive;
default = 10;
description = "The size of the font.";
apply = builtins.toString;
};
};
};
@ -45,25 +65,21 @@ let
type = types.ints.unsigned;
default = 10;
description = "The left margin.";
apply = builtins.toString;
};
right = mkOption {
type = types.ints.unsigned;
default = 10;
description = "The right margin.";
apply = builtins.toString;
};
top = mkOption {
type = types.ints.unsigned;
default = 0;
description = "The top margin.";
apply = builtins.toString;
};
bottom = mkOption {
type = types.ints.unsigned;
default = 0;
description = "The bottom margin.";
apply = builtins.toString;
};
};
};
@ -78,13 +94,11 @@ in
type = types.nullOr types.ints.unsigned;
default = null;
description = "The margins around the widget.";
apply = builtins.toString;
};
spacingBetweenElements = mkOption {
type = types.nullOr types.ints.unsigned;
default = null;
description = "The spacing between elements.";
apply = builtins.toString;
};
horizontalAlignment = mkOption {
type = types.enum [ "left" "right" "center" "justify" ];
@ -98,10 +112,15 @@ in
description = "The vertical alignment of the widget.";
apply = convertVerticalAlignment;
};
showDisabledElements = mkEnumOption [ "deactivated" "hideKeepSpace" "hide" ] // {
example = "deactivated";
description = "How to show the elements when the widget is disabled.";
};
showDisabledElements =
let enumVals = [ "deactivated" "hideKeepSpace" "hide" ];
in mkOption {
type = with types; nullOr (enum enumVals);
default = null;
example = "deactivated";
description = "How to show the elements when the widget is disabled.";
apply = getIndexFromEnum enumVals;
};
fillFreeSpace = mkBoolOption "Whether the widget should fill the free space on the panel.";
elements = mkOption {
type = types.nullOr (types.listOf (types.enum [
@ -123,17 +142,22 @@ in
};
};
windowControlButtons = {
iconSource = mkEnumOption [ "plasma" "breeze" "aurorae" "oxygen" ] // {
example = "plasma";
description = ''
The icon source for the control buttons.
iconSource =
let enumVals = [ "plasma" "breeze" "aurorae" "oxygen" ];
in mkOption {
type = with types; nullOr (enum enumVals);
default = null;
example = "plasma";
description = ''
The icon source for the control buttons.
- Plasma: Global icon theme
- Breeze: Implicit Breeze icons
- Aurorae: Window decorations theme
- Oxygen: Implicit Oxygen icons
'';
};
- Plasma: Global icon theme
- Breeze: Implicit Breeze icons
- Aurorae: Window decorations theme
- Oxygen: Implicit Oxygen icons
'';
apply = getIndexFromEnum enumVals;
};
auroraeTheme = mkOption {
type = types.nullOr types.str;
default = null;
@ -143,19 +167,16 @@ in
type = types.nullOr types.ints.unsigned;
default = null;
description = "The margin around the buttons.";
apply = builtins.toString;
};
buttonsAspectRatio = mkOption {
type = types.nullOr types.ints.unsigned;
default = null;
description = "The ratio of button width in percent to 100% of its height. If you need wider buttons, the value should be >100, otherwise less.";
apply = builtins.toString;
};
buttonsAnimationSpeed = mkOption {
type = types.nullOr types.ints.unsigned;
default = null;
description = "The speed of the buttons animation in milliseconds.";
apply = builtins.toString;
};
};
windowTitle = {
@ -163,13 +184,11 @@ in
type = types.nullOr types.ints.unsigned;
default = null;
description = "The minimum width of the window title.";
apply = builtins.toString;
};
maximumWidth = mkOption {
type = types.nullOr types.ints.unsigned;
default = null;
description = "The maximum width of the window title.";
apply = builtins.toString;
};
font = mkOption {
type = types.nullOr fontType;
@ -192,17 +211,22 @@ in
default = null;
description = "The text to show when the window title is undefined.";
};
source = mkEnumOption [ "appName" "decoration" "genericAppName" "alwaysUndefined" ] // {
example = "appName";
description = ''
The source of the window title.
source =
let enumVals = [ "appName" "decoration" "genericAppName" "alwaysUndefined" ];
in mkOption {
type = with types; nullOr (enum enumVals);
default = null;
example = "appName";
description = ''
The source of the window title.
- appName: The name of the application
- decoration: The title of the window decoration
- genericAppName: The generic name of the application
- alwaysUndefined: Always show the undefined title
'';
};
- appName: The name of the application
- decoration: The title of the window decoration
- genericAppName: The generic name of the application
- alwaysUndefined: Always show the undefined title
'';
apply = getIndexFromEnum enumVals;
};
margins = mkOption {
type = types.nullOr marginType;
default = null;
@ -241,29 +265,41 @@ in
The elements to show in the widget for maximized windows.
'';
};
source = mkEnumOption [ "appName" "decoration" "genericAppName" "alwaysUndefined" ] // {
example = "appName";
description = ''
The source of the window title for maximized windows.
source =
let
enumVals = [ "appName" "decoration" "genericAppName" "alwaysUndefined" ];
in
mkOption {
type = with types; nullOr (enum enumVals);
default = null;
example = "appName";
description = ''
The source of the window title for maximized windows.
- appName: The name of the application
- decoration: The title of the window decoration
- genericAppName: The generic name of the application
- alwaysUndefined: Always show the undefined title
'';
};
- appName: The name of the application
- decoration: The title of the window decoration
- genericAppName: The generic name of the application
- alwaysUndefined: Always show the undefined title
'';
apply = getIndexFromEnum enumVals;
};
};
behavior = {
activeTaskSource = mkEnumOption [ "activeTask" "lastActiveTask" "lastActiveMaximized" ] // {
example = "activeTask";
description = ''
The source of the active task.
activeTaskSource =
let enumVals = [ "activeTask" "lastActiveTask" "lastActiveMaximized" ];
in mkOption {
type = with types; nullOr (enum enumVals);
default = null;
example = "activeTask";
description = ''
The source of the active task.
- activeTask: The active task
- lastActiveTask: The last active task
- lastActiveMaximized: The last active maximized task
'';
};
- activeTask: The active task
- lastActiveTask: The last active task
- lastActiveMaximized: The last active maximized task
'';
apply = getIndexFromEnum enumVals;
};
filterByActivity = mkBoolOption "Whether to filter the tasks by activity.";
filterByScreen = mkBoolOption "Whether to filter the tasks by screen.";
filterByVirtualDesktop = mkBoolOption "Whether to filter the tasks by virtual desktop.";
@ -277,7 +313,6 @@ in
type = types.nullOr types.ints.unsigned;
default = null;
description = "The threshold for dragging the widget.";
apply = builtins.toString;
};
leftDragAction = mkOption {
type = types.nullOr types.str;
@ -329,13 +364,11 @@ in
type = types.nullOr types.ints.unsigned;
default = null;
description = "The distance of the first event.";
apply = builtins.toString;
};
nextEventDistance = mkOption {
type = types.nullOr types.ints.unsigned;
default = null;
description = "The distance of the next event.";
apply = builtins.toString;
};
wheelUp = mkOption {
type = types.nullOr types.str;
@ -359,88 +392,88 @@ in
};
};
};
convert =
{ layout
, windowControlButtons
, windowTitle
, overrideForMaximized
, behavior
, mouseAreaDrag
, mouseAreaClick
, mouseAreaWheel
}: {
name = "com.github.antroids.application-title-bar";
config = {
Appearance = lib.filterAttrs (_: v: v != null) (
{
# Widget layout
widgetMargins = layout.widgetMargins;
widgetSpacing = layout.spacingBetweenElements;
widgetHorizontalAlignment = layout.horizontalAlignment;
widgetVerticalAlignment = layout.verticalAlignment;
widgetElementsDisabledMode = layout.showDisabledElements;
widgetFillWidth = layout.fillFreeSpace;
widgetElements = layout.elements;
convert =
{ layout
, windowControlButtons
, windowTitle
, overrideForMaximized
, behavior
, mouseAreaDrag
, mouseAreaClick
, mouseAreaWheel
}: {
name = "com.github.antroids.application-title-bar";
config = {
Appearance = lib.filterAttrs (_: v: v != null) (
{
# Widget layout
widgetMargins = layout.widgetMargins;
widgetSpacing = layout.spacingBetweenElements;
widgetHorizontalAlignment = layout.horizontalAlignment;
widgetVerticalAlignment = layout.verticalAlignment;
widgetElementsDisabledMode = layout.showDisabledElements;
widgetFillWidth = layout.fillFreeSpace;
widgetElements = layout.elements;
# Window control buttons
widgetButtonsIconsTheme = windowControlButtons.iconSource;
widgetButtonsAuroraeTheme = windowControlButtons.auroraeTheme;
widgetButtonsMargins = windowControlButtons.buttonsMargin;
widgetButtonsAspectRatio = windowControlButtons.buttonsAspectRatio;
widgetButtonsAnimation = windowControlButtons.buttonsAnimationSpeed;
# Window control buttons
widgetButtonsIconsTheme = windowControlButtons.iconSource;
widgetButtonsAuroraeTheme = windowControlButtons.auroraeTheme;
widgetButtonsMargins = windowControlButtons.buttonsMargin;
widgetButtonsAspectRatio = windowControlButtons.buttonsAspectRatio;
widgetButtonsAnimation = windowControlButtons.buttonsAnimationSpeed;
# Window title
windowTitleMinimumWidth = windowTitle.minimumWidth;
windowTitleMaximumWidth = windowTitle.maximumWidth;
windowTitleHideEmpty = windowTitle.hideEmptyTitle;
windowTitleUndefined = windowTitle.undefinedWindowTitle;
windowTitleSource = windowTitle.source;
# Window title
windowTitleMinimumWidth = windowTitle.minimumWidth;
windowTitleMaximumWidth = windowTitle.maximumWidth;
windowTitleHideEmpty = windowTitle.hideEmptyTitle;
windowTitleUndefined = windowTitle.undefinedWindowTitle;
windowTitleSource = windowTitle.source;
# Override for maximized windows
overrideElementsMaximized = overrideForMaximized.enable;
widgetElementsMaximized = overrideForMaximized.elements;
windowTitleSourceMaximized = overrideForMaximized.source;
}
// windowTitle.font
// windowTitle.margins
);
Behavior = lib.filterAttrs (_: v: v != null) (
{
# Behavior
widgetActiveTaskSource = behavior.activeTaskSource;
widgetActiveTaskFilterByActivity = behavior.filterByActivity;
widgetActiveTaskFilterByScreen = behavior.filterByScreen;
widgetActiveTaskFilterByVirtualDesktop = behavior.filterByVirtualDesktop;
widgetActiveTaskFilterNotMaximized = behavior.disableForNotMaximized;
disableButtonsForNotHoveredWidget = behavior.disableButtonsForNotHovered;
# Override for maximized windows
overrideElementsMaximized = overrideForMaximized.enable;
widgetElementsMaximized = overrideForMaximized.elements;
windowTitleSourceMaximized = overrideForMaximized.source;
}
// windowTitle.font
// windowTitle.margins
);
Behavior = lib.filterAttrs (_: v: v != null) (
{
# Behavior
widgetActiveTaskSource = behavior.activeTaskSource;
widgetActiveTaskFilterByActivity = behavior.filterByActivity;
widgetActiveTaskFilterByScreen = behavior.filterByScreen;
widgetActiveTaskFilterByVirtualDesktop = behavior.filterByVirtualDesktop;
widgetActiveTaskFilterNotMaximized = behavior.disableForNotMaximized;
disableButtonsForNotHoveredWidget = behavior.disableButtonsForNotHovered;
# Mouse area drag
windowTitleDragEnabled = mouseAreaDrag.enable;
windowTitleDragOnlyMaximized = mouseAreaDrag.onlyMaximized;
windowTitleDragThreshold = mouseAreaDrag.threshold;
widgetMouseAreaLeftDragAction = mouseAreaDrag.leftDragAction;
widgetMouseAreaMiddleDragAction = mouseAreaDrag.middleDragAction;
# Mouse area drag
windowTitleDragEnabled = mouseAreaDrag.enable;
windowTitleDragOnlyMaximized = mouseAreaDrag.onlyMaximized;
windowTitleDragThreshold = mouseAreaDrag.threshold;
widgetMouseAreaLeftDragAction = mouseAreaDrag.leftDragAction;
widgetMouseAreaMiddleDragAction = mouseAreaDrag.middleDragAction;
# Mouse area click
widgetMouseAreaClickEnabled = mouseAreaClick.enable;
widgetMouseAreaLeftClickAction = mouseAreaClick.leftButtonClick;
widgetMouseAreaLeftDoubleClickAction = mouseAreaClick.leftButtonDoubleClick;
widgetMouseAreaLeftLongPressAction = mouseAreaClick.leftButtonLongClick;
widgetMouseAreaMiddleClickAction = mouseAreaClick.middleButtonClick;
widgetMouseAreaMiddleDoubleClickAction = mouseAreaClick.middleButtonDoubleClick;
widgetMouseAreaMiddleLongPressAction = mouseAreaClick.middleButtonLongClick;
# Mouse area click
widgetMouseAreaClickEnabled = mouseAreaClick.enable;
widgetMouseAreaLeftClickAction = mouseAreaClick.leftButtonClick;
widgetMouseAreaLeftDoubleClickAction = mouseAreaClick.leftButtonDoubleClick;
widgetMouseAreaLeftLongPressAction = mouseAreaClick.leftButtonLongClick;
widgetMouseAreaMiddleClickAction = mouseAreaClick.middleButtonClick;
widgetMouseAreaMiddleDoubleClickAction = mouseAreaClick.middleButtonDoubleClick;
widgetMouseAreaMiddleLongPressAction = mouseAreaClick.middleButtonLongClick;
# Mouse area wheel
widgetMouseAreaWheelEnabled = mouseAreaWheel.enable;
widgetMouseAreaWheelFirstEventDistance = mouseAreaWheel.firstEventDistance;
widgetMouseAreaWheelNextEventDistance = mouseAreaWheel.nextEventDistance;
widgetMouseAreaWheelUpAction = mouseAreaWheel.wheelUp;
widgetMouseAreaWheelDownAction = mouseAreaWheel.wheelDown;
widgetMouseAreaWheelLeftAction = mouseAreaWheel.wheelLeft;
widgetMouseAreaWheelRightAction = mouseAreaWheel.wheelRight;
}
);
# Mouse area wheel
widgetMouseAreaWheelEnabled = mouseAreaWheel.enable;
widgetMouseAreaWheelFirstEventDistance = mouseAreaWheel.firstEventDistance;
widgetMouseAreaWheelNextEventDistance = mouseAreaWheel.nextEventDistance;
widgetMouseAreaWheelUpAction = mouseAreaWheel.wheelUp;
widgetMouseAreaWheelDownAction = mouseAreaWheel.wheelDown;
widgetMouseAreaWheelLeftAction = mouseAreaWheel.wheelLeft;
widgetMouseAreaWheelRightAction = mouseAreaWheel.wheelRight;
}
);
};
};
};
};
}
}

View File

@ -1,9 +1,14 @@
{ lib, widgets, ... }: {
{ lib, ... }: {
battery = {
description = "The battery indicator widget.";
# See https://invent.kde.org/plasma/plasma-workspace/-/blob/master/applets/batterymonitor/package/contents/config/main.xml for the accepted raw options
opts.showPercentage = widgets.lib.mkBoolOption "Enable to show the battery percentage as a small label over the battery icon.";
opts.showPercentage = lib.mkOption {
type = with lib.types; nullOr bool;
default = null;
example = true;
description = "Enable to show the battery percentage as a small label over the battery icon.";
};
convert = { showPercentage }: {
name = "org.kde.plasma.battery";

View File

@ -34,7 +34,7 @@ let
description = "The name of the widget to add.";
};
config = lib.mkOption {
type = with lib.types; nullOr (attrsOf (attrsOf (either str (listOf str))));
type = (import ./lib.nix (args // { widgets = self; })).configValueType;
default = null;
example = {
General.icon = "nix-snowflake-white";

View File

@ -1,7 +1,21 @@
{ lib, widgets, ... }:
{ lib, ... }:
let
inherit (lib) mkOption types;
inherit (widgets.lib) mkBoolOption mkEnumOption boolToString';
mkBoolOption = description: mkOption {
type = with types; nullOr bool;
default = null;
inherit description;
};
getIndexFromEnum = enum: value:
if value == null
then null
else
lib.lists.findFirstIndex
(x: x == value)
(throw "getIndexFromEnum (digital-clock widget): Value ${value} isn't present in the enum. This is a bug")
enum;
fontType = types.submodule {
options = {
@ -16,7 +30,6 @@ let
type = types.ints.between 1 1000;
default = 50;
description = "The weight of the font.";
apply = builtins.toString;
};
style = mkOption {
type = types.nullOr types.str;
@ -27,7 +40,6 @@ let
type = types.ints.positive;
default = 10;
description = "The size of the font.";
apply = builtins.toString;
};
};
};
@ -44,12 +56,12 @@ in
format =
let
enum = [ "shortDate" "longDate" "isoDate" ];
enumVals = [ "shortDate" "longDate" "isoDate" ];
in
mkOption {
type = types.nullOr (types.either (types.enum enum) (types.submodule {
type = with types; nullOr (either (enum enumVals) (submodule {
options.custom = mkOption {
type = types.str;
type = str;
example = "ddd d";
description = "The custom date format to use.";
};
@ -75,38 +87,53 @@ in
};
position = mkEnumOption [ "adaptive" "besideTime" "belowTime" ] // {
example = "belowTime";
description = ''
The position where the date is displayed.
position =
let enumVals = [ "adaptive" "besideTime" "belowTime" ];
in mkOption {
type = with types; nullOr (enum enumVals);
default = null;
example = "belowTime";
description = ''
The position where the date is displayed.
Could be adaptive, always beside the displayed time, or below the displayed time.
'';
};
Could be adaptive, always beside the displayed time, or below the displayed time.
'';
apply = getIndexFromEnum enumVals;
};
};
time = {
showSeconds = mkEnumOption [ "never" "onlyInTooltip" "always" ] // {
example = "always";
description = ''
When and where the seconds should be shown on the clock.
showSeconds =
let enumVals = [ "never" "onlyInTooltip" "always" ];
in mkOption {
type = with types; nullOr (enum enumVals);
default = null;
example = "always";
description = ''
When and where the seconds should be shown on the clock.
Could be never, only in the tooltip on hover, or always.
'';
};
format = mkEnumOption [ "12h" "default" "24h" ] // {
example = "24h";
description = ''
The time format used for this clock.
Could be never, only in the tooltip on hover, or always.
'';
apply = getIndexFromEnum enumVals;
};
format =
let enumVals = [ "12h" "default" "24h" ];
in mkOption {
type = with types; nullOr (enum enumVals);
default = null;
example = "24h";
description = ''
The time format used for this clock.
Could be 12-hour, the default for your locale, or 24-hour.
'';
};
Could be 12-hour, the default for your locale, or 24-hour.
'';
apply = getIndexFromEnum enumVals;
};
};
timeZone = {
selected = mkOption {
type = types.nullOr (types.listOf types.str);
type = with types; nullOr (listOf str);
default = null;
example = [ "Europe/Berlin" "Asia/Shanghai" ];
description = ''
@ -116,7 +143,7 @@ in
'';
};
lastSelected = mkOption {
type = types.nullOr types.str;
type = with types; nullOr str;
default = null;
description = ''
The timezone to show upon widget restore.
@ -125,29 +152,39 @@ in
'';
};
changeOnScroll = mkBoolOption "Allow changing the displayed timezone by scrolling on the widget with the mouse wheel.";
format = mkEnumOption [ "code" "city" "offset" ] // {
example = "code";
description = ''
The format of the timezone displayed, whether as a
code, full name of the city that the timezone belongs to,
or as an UTC offset.
format =
let enumVals = [ "code" "city" "offset" ];
in mkOption {
type = with types; nullOr (enum enumVals);
default = null;
example = "code";
description = ''
The format of the timezone displayed, whether as a
code, full name of the city that the timezone belongs to,
or as an UTC offset.
For example, for the timezone Asia/Shanghai, the three formats
listed above would display "CST", "Shanghai" and "+8" respectively.
'';
};
For example, for the timezone Asia/Shanghai, the three formats
listed above would display "CST", "Shanghai" and "+8" respectively.
'';
apply = getIndexFromEnum enumVals;
};
alwaysShow = mkBoolOption "Always show the selected timezone, when it's the same with the system timezone";
};
calendar = {
firstDayOfWeek = mkEnumOption [ "sunday" "monday" "tuesday" "wednesday" "thursday" "friday" "saturday" ] // {
example = "monday";
description = ''
The first day of the week that the calendar uses.
firstDayOfWeek =
let enumVals = [ "sunday" "monday" "tuesday" "wednesday" "thursday" "friday" "saturday" ];
in mkOption {
type = with types; nullOr (enum enumVals);
default = null;
example = "monday";
description = ''
The first day of the week that the calendar uses.
If null, then the default for the user locale is used.
'';
};
If null, then the default for the user locale is used.
'';
apply = getIndexFromEnum enumVals;
};
plugins = mkOption {
type = types.nullOr (types.listOf types.str);
default = null;
@ -171,7 +208,7 @@ in
'';
apply = font:
{
autoFontAndSize = boolToString' (font == null);
autoFontAndSize = (font == null);
}
// lib.optionalAttrs (font != null) {
fontFamily = font.family;

View File

@ -1,19 +1,38 @@
{ lib, widgets, ... }:
{ lib, ... }:
let
inherit (lib) mkOption types;
inherit (widgets.lib) mkBoolOption mkEnumOption;
convertSpacing = spacing: let
mappings = {
"small" = "0";
"medium" = "1";
"large" = "3";
};
in mappings.${spacing} or (throw "Invalid spacing: ${spacing}");
mkBoolOption = description: mkOption {
type = with types; nullOr bool;
default = null;
inherit description;
};
positionToReverse = position: let
mappings = { "left" = "true"; "right" = "false"; };
in mappings.${position} or (throw "Invalid position: ${position}");
convertSpacing = spacing:
let
mappings = {
small = 0;
medium = 1;
large = 3;
};
in
mappings.${spacing} or (throw "Invalid spacing: ${spacing}");
getIndexFromEnum = enum: value:
if value == null
then null
else
lib.lists.findFirstIndex
(x: x == value)
(throw "getIndexFromEnum (icon-tasks widget): Value ${value} isn't present in the enum. This is a bug")
enum;
positionToReverse = position:
let
mappings = { left = true; right = false; };
in
mappings.${position} or (throw "Invalid position: ${position}");
in
{
iconTasks = {
@ -37,14 +56,13 @@ in
default = "never";
example = "lowSpace";
description = "When to use multi-row view.";
apply = multirowView: if multirowView == "never" then "false" else (if multirowView == "always" then "true" else null);
apply = multirowView: if multirowView == "never" then false else (if multirowView == "always" then true else null);
};
maximum = mkOption {
type = types.nullOr types.ints.positive;
default = null;
example = 5;
description = "The maximum number of rows (in a horizontal-orientation containment, i.e. panel) or columns (in a vertical-orientation containment) to layout task buttons in.";
apply = builtins.toString;
};
};
iconSpacing = mkOption {
@ -57,24 +75,44 @@ in
};
behavior = {
grouping = {
method = mkEnumOption [ "none" "byProgramName" ] // {
example = "none";
description = "How tasks are grouped";
};
clickAction = mkEnumOption [ "cycle" "showTooltips" "showPresentWindowsEffect" "showTextualList" ] // {
example = "cycle";
description = "What happens when clicking on a grouped task";
method =
let enumVals = [ "none" "byProgramName" ];
in mkOption {
type = with types; nullOr (enum enumVals);
default = null;
example = "none";
description = "How tasks are grouped";
apply = getIndexFromEnum enumVals;
};
clickAction =
let enumVals = [ "cycle" "showTooltips" "showPresentWindowsEffect" "showTextualList" ];
in mkOption {
type = with types; nullOr (enum enumVals);
default = null;
example = "cycle";
description = "What happens when clicking on a grouped task";
apply = getIndexFromEnum enumVals;
};
};
sortingMethod =
let enumVals = [ "none" "manually" "alphabetically" "byDesktop" "byActivity" ];
in mkOption {
type = with types; nullOr (enum enumVals);
default = null;
example = "manually";
description = "How to sort tasks";
apply = getIndexFromEnum enumVals;
};
};
sortingMethod = mkEnumOption [ "none" "manually" "alphabetically" "byDesktop" "byActivity" ] // {
example = "manually";
description = "How to sort tasks";
};
minimizeActiveTaskOnClick = mkBoolOption "Whether to minimize the currently-active task when clicked. If false, clicking on the currently-active task will do nothing.";
middleClickAction = mkEnumOption [ "none" "close" "newInstance" "toggleMinimized" "toggleGrouping" "bringToCurrentDesktop" ] // {
example = "bringToCurrentDesktop";
description = "What to do on middle-mouse click on a task button.";
};
middleClickAction =
let enumVals = [ "none" "close" "newInstance" "toggleMinimized" "toggleGrouping" "bringToCurrentDesktop" ];
in mkOption {
type = with types; nullOr (enum enumVals);
default = null;
example = "bringToCurrentDesktop";
description = "What to do on middle-mouse click on a task button.";
apply = getIndexFromEnum enumVals;
};
wheel = {
switchBetweenTasks = mkBoolOption "Whether using the mouse wheel with the mouse pointer above the widget should switch between tasks.";
ignoreMinimizedTasks = mkBoolOption "Whether to skip minimized tasks when switching between them using the mouse wheel.";
@ -98,9 +136,10 @@ in
convert =
{ appearance
, behavior
, launchers }: {
name = "org.kde.plasma.icontasks";
config.General = lib.filterAttrs (_: v: v != null) (
, launchers
}: {
name = "org.kde.plasma.icontasks";
config.General = lib.filterAttrs (_: v: v != null) (
{
launchers = launchers;
@ -134,6 +173,6 @@ in
reverseMode = behavior.newTasksAppearOn;
}
);
};
};
};
}
}

View File

@ -1,16 +1,32 @@
{ lib, widgets, ...}:
{ lib, ... }:
let
inherit (lib) mkOption types;
inherit (widgets.lib) mkBoolOption mkEnumOption;
convertSidebarPosition = sidebarPosition: let
mappings = { "left" = "false"; "right" = "true"; };
in mappings.${sidebarPosition} or (throw "Invalid sidebar position: ${sidebarPosition}");
mkBoolOption = description: mkOption {
type = with types; nullOr bool;
default = null;
inherit description;
};
getIndexFromEnum = enum: value:
if value == null
then null
else
lib.lists.findFirstIndex
(x: x == value)
(throw "getIndexFromEnum (kickoff widget): Value ${value} isn't present in the enum. This is a bug")
enum;
convertSidebarPosition = sidebarPosition:
let
mappings = { left = false; right = true; };
in
mappings.${sidebarPosition} or (throw "Invalid sidebar position: ${sidebarPosition}");
in
{
kickoff = {
description = "Kickoff is the default application launcher of the Plasma desktop.";
opts = {
icon = mkOption {
type = types.nullOr types.str;
@ -33,18 +49,33 @@ in
description = "The position of the sidebar.";
apply = convertSidebarPosition;
};
favoritesDisplayMode = mkEnumOption [ "grid" "list" ] // {
example = "list";
description = "How to display favorites.";
};
applicationsDisplayMode = mkEnumOption [ "grid" "list" ] // {
example = "grid";
description = "How to display applications.";
};
showButtonsFor = mkEnumOption [ "power" "session" "custom" "powerAndSession" ] // {
example = "powerAndSession";
description = "Which actions should be displayed in the footer.";
};
favoritesDisplayMode =
let enumVals = [ "grid" "list" ];
in mkOption {
type = with types; nullOr (enum enumVals);
default = null;
example = "list";
description = "How to display favorites.";
apply = getIndexFromEnum enumVals;
};
applicationsDisplayMode =
let enumVals = [ "grid" "list" ];
in mkOption {
type = with types; nullOr (enum enumVals);
default = null;
example = "grid";
description = "How to display applications.";
apply = getIndexFromEnum enumVals;
};
showButtonsFor =
let enumVals = [ "power" "session" "custom" "powerAndSession" ];
in mkOption {
type = with types; nullOr (enum enumVals);
default = null;
example = "powerAndSession";
description = "Which actions should be displayed in the footer.";
apply = getIndexFromEnum enumVals;
};
showActionButtonCaptions = mkBoolOption "Whether to display captions ('shut down', 'log out', etc.) for the footer action buttons";
pin = mkBoolOption "Whether the popup should remain open when another window is activated.";
};
@ -72,11 +103,11 @@ in
applicationsDisplay = applicationsDisplayMode;
primaryActions = showButtonsFor;
showActionButtonCaptions = showActionButtonCaptions;
# Other useful options
pin = pin;
}
);
};
};
}
}

View File

@ -1,39 +1,35 @@
{ lib, widgets, ... }:
{ lib, ... }:
let
inherit (lib)
optionalString
concatMapStringsSep
concatStringsSep
mapAttrsToList
splitString
mkOption
types
;
splitString;
configValueTypes = with lib.types; oneOf [ bool float int str ];
configValueType = with lib.types; nullOr (attrsOf (attrsOf (either configValueTypes (listOf configValueTypes))));
# any value or null -> string -> string
# If value is null, returns the empty string, otherwise returns the provided string
stringIfNotNull = v: optionalString (v != null);
# string -> string
# Wrap a string in double quotes.
wrapInQuotes = s: ''"${s}"'';
# Converts each datatype into an expression which can be parsed in JavaScript
valToJS = v: if (builtins.isString v) then ''"${v}"'' else if (builtins.isBool v) then (lib.boolToString v) else (builtins.toString v);
# list of strings -> string
# Converts a list of strings to a single string, that can be parsed as a string list in JavaScript
toJSStringList = values: ''[${concatMapStringsSep ", " wrapInQuotes values}]'';
# Converts a list of to a single string, that can be parsed as a string list in JavaScript
toJSList = values: ''[${concatMapStringsSep ", " valToJS values}]'';
setWidgetSettings = var: settings:
let
perConfig = group: key: value: ''${var}.writeConfig("${key}", ${
if builtins.isString value
then wrapInQuotes value
else if builtins.isList value
then toJSStringList value
else throw "widget config ${group}.${key} can only be string or string list, found ${builtins.typeOf value}"
});'';
if builtins.isList value
then toJSList value
else valToJS value
});'';
perGroup = group: configs: ''
${var}.currentConfigGroup = ${toJSStringList (splitString "/" group)};
${var}.currentConfigGroup = ${toJSList (splitString "/" group)};
${concatStringsSep "\n" (mapAttrsToList (perConfig group) configs)}
'';
in
@ -58,43 +54,11 @@ let
const ${var} = {};
${lib.concatMapStringsSep "\n" addStmt ws}
'';
boolToString' = b: if b == null then null else lib.boolToString b;
getEnum = es: e:
if e == null
then null
else
toString (
lib.lists.findFirstIndex
(x: x == e)
(throw "getEnum: nonexistent key ${e}! This is a bug!")
es
);
mkBoolOption = description: mkOption {
inherit description;
type = types.nullOr types.bool;
default = null;
example = true;
apply = widgets.lib.boolToString';
};
mkEnumOption = enum: mkOption {
type = types.nullOr (types.enum enum);
default = null;
apply = widgets.lib.getEnum enum;
};
in
{
inherit
stringIfNotNull
setWidgetSettings
addWidgetStmts
boolToString'
getEnum
mkBoolOption
mkEnumOption
;
configValueType;
}

View File

@ -1,7 +1,21 @@
{lib, widgets, ...}:
{ lib, ... }:
let
inherit (lib) mkOption types;
inherit (widgets.lib) mkBoolOption mkEnumOption;
mkBoolOption = description: lib.mkOption {
type = with lib.types; nullOr bool;
default = null;
inherit description;
};
getIndexFromEnum = enum: value:
if value == null
then null
else
lib.lists.findFirstIndex
(x: x == value)
(throw "getIndexFromEnum (plasmusic-toolbar widget): Value ${value} isn't present in the enum. This is a bug")
enum;
in
{
plasmusicToolbar = {
@ -22,40 +36,49 @@ in
default = null;
example = 8;
description = "Radius of the album cover icon.";
apply = builtins.toString;
};
};
};
preferredSource = mkEnumOption [ "any" "spotify" "vlc" ] // {
example = "any";
description = "Preferred source for song information.";
};
preferredSource =
let enumVals = [ "any" "spotify" "vlc" ];
in mkOption {
type = with types; nullOr (enum enumVals);
default = null;
example = "any";
description = "Preferred source for song information.";
apply = getIndexFromEnum enumVals;
};
songText = {
maximumWidth = mkOption {
type = types.nullOr types.ints.unsigned;
default = null;
example = 200;
description = "Maximum width of the song text.";
apply = builtins.toString;
};
scrolling = {
behavior = mkEnumOption [ "alwaysScroll" "scrollOnHover" "alwaysScrollExceptOnHover" ] // {
example = "alwaysScroll";
description = "Scrolling behavior of the song text.";
};
behavior =
let
enumVals = [ "alwaysScroll" "scrollOnHover" "alwaysScrollExceptOnHover" ];
in
mkOption {
type = with types; nullOr (enum enumVals);
default = null;
example = "alwaysScroll";
description = "Scrolling behavior of the song text.";
apply = getIndexFromEnum enumVals;
};
speed = mkOption {
type = types.nullOr (types.ints.between 1 10);
default = null;
example = 3;
description = "Speed of the scrolling text.";
apply = builtins.toString;
};
};
displayInSeparateLines = mkBoolOption "Whether to display song information (title and artist) in separate lines or not.";
};
showPlaybackControls = mkBoolOption "Whether to show playback controls or not.";
};
convert =
convert =
{ panelIcon
, preferredSource
, songText
@ -80,4 +103,4 @@ in
);
};
};
}
}

View File

@ -1,7 +1,6 @@
{ lib, widgets, ... }:
{ lib, ... }:
let
inherit (lib) mkOption types;
inherit (widgets.lib) mkBoolOption;
# KDE expects a key/value pair like this:
# ```ini
@ -60,7 +59,11 @@ in
default = null;
description = "The title of this system monitor.";
};
showTitle = mkBoolOption "Show or hide the title.";
showTitle = mkOption {
type = with types; nullOr bool;
default = null;
description = "Show or hide the title.";
};
displayStyle = mkOption {
type = with types; nullOr str;
default = null;
@ -116,6 +119,18 @@ in
The list of text-only sensors, displayed in the pop-up upon clicking the widget.
'';
};
range = {
from = mkOption {
type = with lib.types; nullOr (ints.between 0 100);
default = null;
description = "The lower range the sensors can take.";
};
to = mkOption {
type = with lib.types; nullOr (ints.between 0 100);
default = null;
description = "The upper range the sensors can take.";
};
};
};
convert =
@ -125,21 +140,28 @@ in
, totalSensors
, sensors
, textOnlySensors
, range
}: {
name = "org.kde.plasma.systemmonitor";
config = lib.filterAttrsRecursive (_: v: v != null) (lib.recursiveUpdate
{
Appearance = {
inherit title;
inherit showTitle;
chartFace = displayStyle;
};
Sensors = {
lowPrioritySensorIds = textOnlySensors;
totalSensors = totalSensors;
};
}
sensors);
config = lib.filterAttrsRecursive (_: v: v != null)
(lib.recursiveUpdate
({
Appearance = {
inherit title;
inherit showTitle;
chartFace = displayStyle;
};
Sensors = {
lowPrioritySensorIds = textOnlySensors;
totalSensors = totalSensors;
};
"org.kde.ksysguard.piechart/General" = {
rangeAuto = (range.from == null && range.to == null);
rangeFrom = range.from;
rangeTo = range.to;
};
})
sensors);
};
};
}

View File

@ -1,7 +1,12 @@
{ lib, widgets, ... }:
let
inherit (lib) mkOption types;
inherit (widgets.lib) mkBoolOption;
mkBoolOption = description: mkOption {
type = with types; nullOr bool;
default = null;
inherit description;
};
in
{
systemTray = {
@ -29,9 +34,9 @@ in
(if (spacing == null) then null
else
(if builtins.isInt spacing then
toString spacing
spacing
else
builtins.elemAt [ "1" "2" "6" ] (
builtins.elemAt [ 1 2 6 ] (
lib.lists.findFirstIndex
(x: x == spacing)
(throw "systemTray: nonexistent spacing ${spacing}! This is a bug!")

View File

@ -1,10 +1,9 @@
{ lib
, pkgs
, config
, ...
}:
with lib.types; let
inherit (builtins) length listToAttrs foldl' toString attrNames getAttr hasAttr concatStringsSep add isAttrs;
inherit (builtins) length listToAttrs foldl' toString attrNames getAttr concatStringsSep add isAttrs;
inherit (lib) mkOption mkIf;
inherit (lib.trivial) mergeAttrs;
inherit (lib.lists) imap0;