diff --git a/modules/bar/window_title/index.ts b/modules/bar/window_title/index.ts index 0b0818e..70458a0 100644 --- a/modules/bar/window_title/index.ts +++ b/modules/bar/window_title/index.ts @@ -1,6 +1,7 @@ const hyprland = await Service.import("hyprland"); import options from 'options'; import { ActiveClient } from 'types/service/hyprland' +import Label from "types/widgets/label"; const filterTitle = (windowtitle: ActiveClient) => { const windowTitleMap = [ @@ -127,15 +128,36 @@ const filterTitle = (windowtitle: ActiveClient) => { } return { - icon: foundMatch ? foundMatch[1] : windowTitleMap[windowTitleMap.length - 1][1], - label: foundMatch ? foundMatch[2] : windowTitleMap[windowTitleMap.length - 1][2] + icon: foundMatch[1], + label: foundMatch[2] }; }; +const getTitle = (client: ActiveClient, useCustomTitle: boolean, useClassName: boolean) => { + if (useCustomTitle) return filterTitle(client).label; + if (useClassName) return client.class; + + let title = client.title; + // If the title is empty or only filled with spaces, fallback to the class name + if (title.length === 0 || title.match(/^ *$/)) { + return client.class; + } + return title; +}; + +const truncateTitle = (title: string, max_size: number) => { + if (max_size > 0 && title.length > max_size) { + return title.substring(0, max_size).trim() + "..."; + } + return title; +}; + const ClientTitle = () => { + const { custom_title, class_name, label, icon, truncation, truncation_size } = options.bar.windowtitle; + return { component: Widget.Box({ - className: Utils.merge([options.theme.bar.buttons.style.bind("value"), options.bar.windowtitle.label.bind("value")], (style, showLabel) => { + className: Utils.merge([options.theme.bar.buttons.style.bind("value"), label.bind("value")], (style, showLabel) => { const styleMap = { default: "style1", split: "style2", @@ -144,17 +166,26 @@ const ClientTitle = () => { }; return `windowtitle ${styleMap[style]} ${!showLabel ? "no-label" : ""}`; }), - children: options.bar.windowtitle.label.bind("value").as((showLabel) => { - const titleIcon = Widget.Label({ - class_name: "bar-button-icon windowtitle txt-icon bar", - label: hyprland.active.bind("client").as((v) => filterTitle(v).icon), - }); - const titleLabel = Widget.Label({ - class_name: "bar-button-label windowtitle", - label: hyprland.active.bind("client").as((v) => filterTitle(v).label), - }); - return showLabel ? [titleIcon, titleLabel] : [titleIcon]; - }), + children: + Utils.merge( + [hyprland.active.bind("client"), custom_title.bind("value"), class_name.bind("value"), label.bind("value"), + icon.bind("value"), truncation.bind("value"), truncation_size.bind("value")], + (client, useCustomTitle, useClassName, showLabel, showIcon, truncate, truncationSize) => { + const children: Label[] = []; + if (showIcon) { + children.push(Widget.Label({ + class_name: "bar-button-icon windowtitle txt-icon bar", + label: filterTitle(client).icon, + })); + } + if (showLabel) { + children.push(Widget.Label({ + class_name: `bar-button-label windowtitle ${showIcon ? "" : "no-icon"}`, + label: truncateTitle(getTitle(client, useCustomTitle, useClassName), truncate ? truncationSize : -1), + })); + } + return children; + }), }), isVisible: true, boxClass: "windowtitle", diff --git a/options.ts b/options.ts index 529c987..c5d6f7e 100644 --- a/options.ts +++ b/options.ts @@ -814,8 +814,13 @@ const options = mkOptions(OPTIONS, { icon: opt("󰣇"), }, windowtitle: { + custom_title: opt(true), title_map: opt([]), + class_name: opt(true), label: opt(true), + icon: opt(true), + truncation: opt(true), + truncation_size: opt(50), }, workspaces: { show_icons: opt(false), diff --git a/scss/style/bar/window_title.scss b/scss/style/bar/window_title.scss index 53e4836..92bee80 100644 --- a/scss/style/bar/window_title.scss +++ b/scss/style/bar/window_title.scss @@ -5,6 +5,10 @@ .bar-button-label.windowtitle { color: if($bar-buttons-monochrome, $bar-buttons-text, $bar-buttons-windowtitle-text); margin-left: $bar-buttons-windowtitle-spacing; + + &.no-icon { + margin-left: 0; + } } .style2 { diff --git a/widget/settings/pages/config/bar/index.ts b/widget/settings/pages/config/bar/index.ts index 85cc2d2..d63fdd7 100644 --- a/widget/settings/pages/config/bar/index.ts +++ b/widget/settings/pages/config/bar/index.ts @@ -220,22 +220,50 @@ export const BarSettings = (): Scrollable => { */ Header("Window Titles"), Option({ - opt: options.bar.windowtitle.label, - title: "Show Window Title Label", - type: "boolean", - }), - Option({ - opt: options.theme.bar.buttons.windowtitle.spacing, - title: "Inner Spacing", - subtitle: "Spacing between the icon and the label inside the buttons.", - type: "string", + opt: options.bar.windowtitle.custom_title, + title: 'Use Custom Title', + type: 'boolean' }), Option({ opt: options.bar.windowtitle.title_map, - title: "Window Title Mappings", - subtitle: "Wiki Link: https://hyprpanel.com/configuration/panel.html#window-title-mappings", - type: "object", - subtitleLink: "https://hyprpanel.com/configuration/panel.html#window-title-mappings", + title: 'Window Title Mappings', + subtitle: 'Only applicable if Show Custom Title is enabled\nWiki Link: https://hyprpanel.com/configuration/panel.html#window-title-mappings', + type: 'object', + subtitleLink: 'https://hyprpanel.com/configuration/panel.html#window-title-mappings' + }), + Option({ + opt: options.bar.windowtitle.class_name, + title: 'Use Class Name', + subtitle: 'Only applicable if Show Custom Title is disabled\nDisplays the window\'s class name instead of its title.', + type: 'boolean' + }), + Option({ + opt: options.bar.windowtitle.label, + title: 'Show Window Title Label', + type: 'boolean' + }), + Option({ + opt: options.bar.windowtitle.icon, + title: 'Show Icon', + type: 'boolean' + }), + Option({ + opt: options.bar.windowtitle.truncation, + title: 'Truncate Window Title', + subtitle: 'Will truncate the window title to the specified size below.', + type: 'boolean' + }), + Option({ + opt: options.bar.windowtitle.truncation_size, + title: 'Truncation Size', + type: 'number', + min: 10 + }), + Option({ + opt: options.theme.bar.buttons.windowtitle.spacing, + title: 'Inner Spacing', + subtitle: 'Spacing between the icon and the label inside the buttons.', + type: 'string' }), /*