Automatically shorten titles if they get too long
This commit is contained in:
parent
be20e34b0e
commit
2776741c23
|
|
@ -3,6 +3,7 @@ import app from "ags/gtk4/app";
|
||||||
import { createBinding, createState, For, With, Accessor } from "ags";
|
import { createBinding, createState, For, With, Accessor } from "ags";
|
||||||
import { createPoll } from "ags/time";
|
import { createPoll } from "ags/time";
|
||||||
import { subprocess, execAsync } from "ags/process";
|
import { subprocess, execAsync } from "ags/process";
|
||||||
|
import Pango from "gi://Pango";
|
||||||
import Tray from "gi://AstalTray";
|
import Tray from "gi://AstalTray";
|
||||||
import { getIconName } from "./utils";
|
import { getIconName } from "./utils";
|
||||||
import Wp from "gi://AstalWp";
|
import Wp from "gi://AstalWp";
|
||||||
|
|
@ -295,8 +296,24 @@ function Workspaces({ connector }: { connector: string }): JSX.Element {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function shorten(title: string) {
|
const MAX_TOTAL_CHARS = 120;
|
||||||
return title.length > 40 ? title.slice(0, 20) + "..." : title;
|
const MIN_TITLE_CHARS = 10;
|
||||||
|
const OVERHEAD_PER_WINDOW = 5; // icon + padding + margin in character-width equivalents
|
||||||
|
|
||||||
|
function computeTitleBudgets(wins: any[]): any[] {
|
||||||
|
const totalLength = wins.reduce((sum, w) => sum + (w.title || "").length, 0);
|
||||||
|
const count = wins.length;
|
||||||
|
const totalWithOverhead = totalLength + count * OVERHEAD_PER_WINDOW;
|
||||||
|
|
||||||
|
let maxChars: number;
|
||||||
|
if (count === 0 || totalWithOverhead <= MAX_TOTAL_CHARS) {
|
||||||
|
maxChars = -1;
|
||||||
|
} else {
|
||||||
|
const charsAvailable = MAX_TOTAL_CHARS - count * OVERHEAD_PER_WINDOW;
|
||||||
|
maxChars = Math.max(MIN_TITLE_CHARS, Math.floor(charsAvailable / count));
|
||||||
|
}
|
||||||
|
|
||||||
|
return wins.map(w => ({ ...w, maxChars }));
|
||||||
}
|
}
|
||||||
|
|
||||||
function Clients({ connector }: { connector: string }): JSX.Element {
|
function Clients({ connector }: { connector: string }): JSX.Element {
|
||||||
|
|
@ -311,18 +328,24 @@ function Clients({ connector }: { connector: string }): JSX.Element {
|
||||||
<box>
|
<box>
|
||||||
{/* Generate a derived binding for windows, depending on the active workspace */}
|
{/* Generate a derived binding for windows, depending on the active workspace */}
|
||||||
<For each={windows((wins: any[]) =>
|
<For each={windows((wins: any[]) =>
|
||||||
wins.filter((w: any) => !w.title?.includes("rofi"))
|
computeTitleBudgets(
|
||||||
.filter((w: any) => w.workspace_id === active_ws_for_monitor)
|
wins.filter((w: any) => !w.title?.includes("rofi"))
|
||||||
.sort((a: any, b: any) => {
|
.filter((w: any) => w.workspace_id === active_ws_for_monitor)
|
||||||
const posA = a.layout?.pos_in_scrolling_layout?.[0] ?? 0;
|
.sort((a: any, b: any) => {
|
||||||
const posB = b.layout?.pos_in_scrolling_layout?.[0] ?? 0;
|
const posA = a.layout?.pos_in_scrolling_layout?.[0] ?? 0;
|
||||||
return posA - posB;
|
const posB = b.layout?.pos_in_scrolling_layout?.[0] ?? 0;
|
||||||
})
|
return posA - posB;
|
||||||
|
})
|
||||||
|
)
|
||||||
)}>
|
)}>
|
||||||
{(win: any) => (
|
{(win: any) => (
|
||||||
<box class={win.is_focused ? "focused" : "unfocused"}>
|
<box class={win.is_focused ? "focused" : "unfocused"}>
|
||||||
<image iconName={getIconName(win.app_id, win.title)} class="app-icon" />
|
<image iconName={getIconName(win.app_id, win.title)} class="app-icon" />
|
||||||
<label label={shorten(win.title || "")} />
|
<label
|
||||||
|
label={win.title || ""}
|
||||||
|
maxWidthChars={win.maxChars}
|
||||||
|
ellipsize={Pango.EllipsizeMode.END}
|
||||||
|
/>
|
||||||
</box>
|
</box>
|
||||||
)}
|
)}
|
||||||
</For>
|
</For>
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue