diff --git a/modules/widgets/application-title-bar.nix b/modules/widgets/application-title-bar.nix index d1113c2..8002e44 100644 --- a/modules/widgets/application-title-bar.nix +++ b/modules/widgets/application-title-bar.nix @@ -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; + } + ); + }; }; - }; }; -} \ No newline at end of file +} diff --git a/modules/widgets/battery.nix b/modules/widgets/battery.nix index 9e19ed2..1506286 100644 --- a/modules/widgets/battery.nix +++ b/modules/widgets/battery.nix @@ -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"; diff --git a/modules/widgets/default.nix b/modules/widgets/default.nix index 33239d0..b32b576 100644 --- a/modules/widgets/default.nix +++ b/modules/widgets/default.nix @@ -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"; diff --git a/modules/widgets/digital-clock.nix b/modules/widgets/digital-clock.nix index 28631d6..6f0208f 100644 --- a/modules/widgets/digital-clock.nix +++ b/modules/widgets/digital-clock.nix @@ -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; diff --git a/modules/widgets/icon-tasks.nix b/modules/widgets/icon-tasks.nix index 0e4699d..f94257a 100644 --- a/modules/widgets/icon-tasks.nix +++ b/modules/widgets/icon-tasks.nix @@ -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; } ); - }; + }; }; -} \ No newline at end of file +} diff --git a/modules/widgets/kickoff.nix b/modules/widgets/kickoff.nix index 4be4984..927f58e 100644 --- a/modules/widgets/kickoff.nix +++ b/modules/widgets/kickoff.nix @@ -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; } ); }; }; -} \ No newline at end of file +} diff --git a/modules/widgets/lib.nix b/modules/widgets/lib.nix index 0170d0d..30a2e14 100644 --- a/modules/widgets/lib.nix +++ b/modules/widgets/lib.nix @@ -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; } diff --git a/modules/widgets/plasmusic-toolbar.nix b/modules/widgets/plasmusic-toolbar.nix index 3a27aba..23c83c4 100644 --- a/modules/widgets/plasmusic-toolbar.nix +++ b/modules/widgets/plasmusic-toolbar.nix @@ -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 ); }; }; -} \ No newline at end of file +} diff --git a/modules/widgets/system-monitor.nix b/modules/widgets/system-monitor.nix index 65d107f..b1a0f35 100644 --- a/modules/widgets/system-monitor.nix +++ b/modules/widgets/system-monitor.nix @@ -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); }; }; } diff --git a/modules/widgets/system-tray.nix b/modules/widgets/system-tray.nix index f37b73d..57d8847 100644 --- a/modules/widgets/system-tray.nix +++ b/modules/widgets/system-tray.nix @@ -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!") diff --git a/modules/window-rules.nix b/modules/window-rules.nix index aeef308..47074ba 100644 --- a/modules/window-rules.nix +++ b/modules/window-rules.nix @@ -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;