screen-toolkit: add compact/full panel modes, mode-aware toggle, and … (#237)
* screen-toolkit: add compact/full panel modes, mode-aware toggle, and full documentation * screen-toolkit: restrict compact tile hover/click to icon and label * screen-toolkit: full-mode hover border on tile, mirror compact colors * screen-toolkit: add plugin thumbnail screenshot --------- Co-authored-by: Ahmed5Emad <ahmed5emad@users.noreply.github.com>
This commit is contained in:
@@ -16,7 +16,7 @@ not the original implementation.
|
|||||||
| Field | Value |
|
| Field | Value |
|
||||||
| --- | --- |
|
| --- | --- |
|
||||||
| ID | `alexander/screen-toolkit` |
|
| ID | `alexander/screen-toolkit` |
|
||||||
| Entries | Bar widget: `widget`; control-center shortcut: `toggle`; panels: `panel` (tools), `result` (result view); service: `service` |
|
| Entries | Bar widget: `widget`; control-center shortcut: `toggle`; panels: `panel` (compact tools), `panel-full` (full tools), `result` (result view); service: `service` |
|
||||||
|
|
||||||
## Requirements
|
## Requirements
|
||||||
|
|
||||||
@@ -60,12 +60,45 @@ Settings → Control Center shortcuts. Left-click either one opens the main pane
|
|||||||
(or stops a recording); right-clicking the bar widget quick-picks a color. While
|
(or stops a recording); right-clicking the bar widget quick-picks a color. While
|
||||||
a recording is active, the widget and shortcut show a pulsing red dot.
|
a recording is active, the widget and shortcut show a pulsing red dot.
|
||||||
|
|
||||||
Open the main tools panel:
|
The main panel has two layouts, selected by the `panel-mode` setting (default:
|
||||||
|
**Full**):
|
||||||
|
|
||||||
|
- **Full** — the spacious original grid with section titles (`panel-full`,
|
||||||
|
660×340).
|
||||||
|
- **Compact** — a dense grid grouped into tinted sections (`panel`,
|
||||||
|
380×260).
|
||||||
|
|
||||||
|
The widget and shortcut open whichever entry matches the setting; the panel
|
||||||
|
footnote under Settings → Plugins shows both panels' placement/position
|
||||||
|
options.
|
||||||
|
|
||||||
|
Toggle the tools panel (opens the entry matching the `panel-mode` setting):
|
||||||
|
|
||||||
|
```sh
|
||||||
|
noctalia msg plugin alexander/screen-toolkit:service all toggle
|
||||||
|
```
|
||||||
|
|
||||||
|
For example, bind it to `SUPER+P` in Hyprland:
|
||||||
|
|
||||||
|
```ini
|
||||||
|
bind = SUPER, P, exec, noctalia msg plugin alexander/screen-toolkit:service all toggle
|
||||||
|
```
|
||||||
|
|
||||||
|
Because `toggle` reads the `panel-mode` setting, this single bind works in both
|
||||||
|
full and compact mode — no need to change the keybind when you switch layouts.
|
||||||
|
|
||||||
|
Open the compact tools panel:
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
noctalia msg panel-toggle alexander/screen-toolkit:panel
|
noctalia msg panel-toggle alexander/screen-toolkit:panel
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Open the full tools panel (the original spacious grid):
|
||||||
|
|
||||||
|
```sh
|
||||||
|
noctalia msg panel-toggle alexander/screen-toolkit:panel-full
|
||||||
|
```
|
||||||
|
|
||||||
Open the result panel (shows the last capture/recording output):
|
Open the result panel (shows the last capture/recording output):
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
@@ -131,6 +164,7 @@ All settings live in Settings → Plugins (gear on the plugin's row).
|
|||||||
| `record-skip-confirmation` | `bool` | `false` | Save automatically when a recording ends, skipping the save dialog. |
|
| `record-skip-confirmation` | `bool` | `false` | Save automatically when a recording ends, skipping the save dialog. |
|
||||||
| `record-copy-to-clipboard` | `bool` | `false` | Finalize to MP4 and copy the file URI when recording ends. |
|
| `record-copy-to-clipboard` | `bool` | `false` | Finalize to MP4 and copy the file URI when recording ends. |
|
||||||
| `gif-max-seconds` | `int` | `30` | Cap for GIF recordings (1–600 s). |
|
| `gif-max-seconds` | `int` | `30` | Cap for GIF recordings (1–600 s). |
|
||||||
|
| `panel-mode` | `select` | `full` | Main panel layout: `full` (spacious original grid, 660×340) or `compact` (dense grid, 380×260). |
|
||||||
|
|
||||||
## IPC
|
## IPC
|
||||||
|
|
||||||
@@ -153,17 +187,70 @@ noctalia msg plugin alexander/screen-toolkit:service all recordFullscreen
|
|||||||
noctalia msg plugin alexander/screen-toolkit:service all recordFullscreenMp4
|
noctalia msg plugin alexander/screen-toolkit:service all recordFullscreenMp4
|
||||||
noctalia msg plugin alexander/screen-toolkit:service all recordStop
|
noctalia msg plugin alexander/screen-toolkit:service all recordStop
|
||||||
noctalia msg plugin alexander/screen-toolkit:service all recordSave
|
noctalia msg plugin alexander/screen-toolkit:service all recordSave
|
||||||
|
noctalia msg plugin alexander/screen-toolkit:service all recordCopy
|
||||||
noctalia msg plugin alexander/screen-toolkit:service all recordDiscard
|
noctalia msg plugin alexander/screen-toolkit:service all recordDiscard
|
||||||
|
noctalia msg plugin alexander/screen-toolkit:service all ocrSearch
|
||||||
|
noctalia msg plugin alexander/screen-toolkit:service all clearResult
|
||||||
|
noctalia msg plugin alexander/screen-toolkit:service all clearHistory
|
||||||
```
|
```
|
||||||
|
|
||||||
`ocrTranslate` takes a language code payload:
|
`toggle` opens the tools panel **matching the `panel-mode` setting** — one IPC
|
||||||
|
that works for both layouts. The bar widget and control-center shortcut use the
|
||||||
|
same mode-aware toggle.
|
||||||
|
|
||||||
|
Commands that take a payload:
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
|
# Translate the current OCR text into a language (language code payload)
|
||||||
noctalia msg plugin alexander/screen-toolkit:service all ocrTranslate en
|
noctalia msg plugin alexander/screen-toolkit:service all ocrTranslate en
|
||||||
|
# Search the current OCR text (or a payload.text) with the configured engine
|
||||||
|
noctalia msg plugin alexander/screen-toolkit:service all ocrSearch
|
||||||
|
# Share a file on disk (absolute path payload)
|
||||||
|
noctalia msg plugin alexander/screen-toolkit:service all share /path/to/image.png
|
||||||
|
# Save the finished recording (payload format: "gif" or "mp4")
|
||||||
|
noctalia msg plugin alexander/screen-toolkit:service all recordSave mp4
|
||||||
|
# Show or hide the cursor in captures (payload: "true" or "false")
|
||||||
|
noctalia msg plugin alexander/screen-toolkit:service all setCursorHidden true
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Summary of every service command:
|
||||||
|
|
||||||
|
| Command | Payload | Action |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| `toggle` | — | Open/close the tools panel that matches `panel-mode` |
|
||||||
|
| `colorPicker` | — | Pick a color from the screen (region crosshair) |
|
||||||
|
| `ocr` | — | Extract text from a region |
|
||||||
|
| `qr` | — | Decode a QR / barcode from a region |
|
||||||
|
| `palette` | — | Extract hex colors from a region |
|
||||||
|
| `lens` | — | Google Lens search on a region |
|
||||||
|
| `measure` | — | Report a region's pixel size |
|
||||||
|
| `annotate` | — | Open a region in the annotation editor |
|
||||||
|
| `annotateFullscreen` | — | Annotate the full screen |
|
||||||
|
| `annotateWindow` | — | Annotate the focused window (Hyprland only) |
|
||||||
|
| `record` | — | Record a region as GIF |
|
||||||
|
| `recordMp4` | — | Record a region as MP4 |
|
||||||
|
| `recordFullscreen` | — | Record the full screen as GIF |
|
||||||
|
| `recordFullscreenMp4` | — | Record the full screen as MP4 |
|
||||||
|
| `recordStop` | — | Stop the active recording |
|
||||||
|
| `recordSave` | `"gif"` / `"mp4"` | Save the finished recording |
|
||||||
|
| `recordCopy` | — | Finalize to MP4 and copy the file URI |
|
||||||
|
| `recordDiscard` | — | Discard the finished recording |
|
||||||
|
| `ocrSearch` | optional `{text}` | Search OCR text with the configured engine |
|
||||||
|
| `ocrTranslate` | language code | Translate OCR text |
|
||||||
|
| `share` | file path | Upload a file and copy the link |
|
||||||
|
| `clearResult` | — | Clear the current result panel state |
|
||||||
|
| `clearHistory` | — | Clear the color history |
|
||||||
|
| `setCursorHidden` | `"true"` / `"false"` | Include/exclude the cursor in captures |
|
||||||
|
|
||||||
## Notes
|
## Notes
|
||||||
|
|
||||||
|
- **Two panel entries, one layout setting.** Panel size is host-owned: the host
|
||||||
|
sizes each `[[panel]]` entry from its `width`/`height`, and there is no runtime
|
||||||
|
resize. So the two layouts are two entries sharing `panel.luau`: `panel-full`
|
||||||
|
(660×340, the original spacious grid) and `panel` (380×260, the compact grid).
|
||||||
|
The `panel-mode` setting picks which one renders, and `toggle`/widget/shortcut
|
||||||
|
all open the matching entry. Changing the setting only affects which panel
|
||||||
|
opens next time; an already-open panel keeps its current size until closed.
|
||||||
- This is a port of the legacy v4
|
- This is a port of the legacy v4
|
||||||
[screen-toolkit](https://github.com/noctalia-dev/legacy-v4-plugins/tree/main/screen-toolkit)
|
[screen-toolkit](https://github.com/noctalia-dev/legacy-v4-plugins/tree/main/screen-toolkit)
|
||||||
plugin. Tools that relied on freeform v4 QML overlays are adapted: region
|
plugin. Tools that relied on freeform v4 QML overlays are adapted: region
|
||||||
|
|||||||
+171
-44
@@ -1,13 +1,22 @@
|
|||||||
--!nonstrict
|
--!nonstrict
|
||||||
-- Screen Toolkit — main [[panel]].
|
-- Screen Toolkit — main [[panel]].
|
||||||
--
|
--
|
||||||
-- Thin client for the toolkit: a header plus the tool grid grouped into
|
-- Thin client for the toolkit. Two layouts are provided, selected by the
|
||||||
-- Capture / Annotate / Record sections. It only dispatches actions to the
|
-- "panel-mode" plugin setting:
|
||||||
-- [[service]] through the "command" state channel. Capture tools close the
|
-- * compact — a dense grid grouped into tinted sections (default)
|
||||||
-- panel first so the capture never includes it.
|
-- * full — the original spacious layout with section titles
|
||||||
|
-- The panel entry to open (and thus its host-owned size) is chosen by the
|
||||||
|
-- bar [[widget]] / control-center [[shortcut]] from the same setting.
|
||||||
|
-- It only dispatches actions to the [[service]] through the "command"
|
||||||
|
-- state channel. Capture tools close the panel first so the capture never
|
||||||
|
-- includes it.
|
||||||
|
|
||||||
local panelOpen = false
|
local panelOpen = false
|
||||||
local recording = noctalia.state.get("recording") == true
|
local recording = noctalia.state.get("recording") == true
|
||||||
|
local hoveredTool = nil
|
||||||
|
local hoveredClose = false
|
||||||
|
local hoveredStop = false
|
||||||
|
local render
|
||||||
|
|
||||||
-- ── Helpers ────────────────────────────────────────────────────────────────
|
-- ── Helpers ────────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
@@ -20,6 +29,10 @@ local function send(action, payload)
|
|||||||
noctalia.state.set("command", { action = action, payload = payload })
|
noctalia.state.set("command", { action = action, payload = payload })
|
||||||
end
|
end
|
||||||
|
|
||||||
|
local function getMode()
|
||||||
|
return noctalia.getConfig("panel-mode") == "full" and "full" or "compact"
|
||||||
|
end
|
||||||
|
|
||||||
-- Capture tools must not see the panel in the frame, so close it first.
|
-- Capture tools must not see the panel in the frame, so close it first.
|
||||||
local CAPTURE_ACTIONS = {
|
local CAPTURE_ACTIONS = {
|
||||||
colorPicker = true,
|
colorPicker = true,
|
||||||
@@ -44,28 +57,7 @@ local function runTool(action)
|
|||||||
send(action)
|
send(action)
|
||||||
end
|
end
|
||||||
|
|
||||||
-- ── Header ─────────────────────────────────────────────────────────────────
|
-- ── Tool data ──────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
local function header()
|
|
||||||
local actions = {
|
|
||||||
ui.button({ glyph = "close", onClick = function() panel.close() end }),
|
|
||||||
}
|
|
||||||
if recording then
|
|
||||||
table.insert(actions, 1, ui.button({
|
|
||||||
glyph = "square",
|
|
||||||
variant = "destructive",
|
|
||||||
controlSize = "sm",
|
|
||||||
tooltip = tr("panel.stop"),
|
|
||||||
onClick = function() send("recordStop") end,
|
|
||||||
}))
|
|
||||||
end
|
|
||||||
return ui.row({ align = "center", gap = 8 }, {
|
|
||||||
ui.label({ text = tr("panel.title"), flexGrow = 1, fontSize = 16, fontWeight = "bold", color = "on_surface" }),
|
|
||||||
ui.row({ gap = 4 }, actions),
|
|
||||||
})
|
|
||||||
end
|
|
||||||
|
|
||||||
-- ── Tool grid ──────────────────────────────────────────────────────────────
|
|
||||||
|
|
||||||
local TOOLS = {
|
local TOOLS = {
|
||||||
{ action = "colorPicker", label_key = "tools.colorpicker", glyph = "palette" },
|
{ action = "colorPicker", label_key = "tools.colorpicker", glyph = "palette" },
|
||||||
@@ -89,30 +81,155 @@ local RECORD_TOOLS = {
|
|||||||
{ action = "recordFullscreenMp4", label_key = "tools.record_fullscreen_mp4", glyph = "video" },
|
{ action = "recordFullscreenMp4", label_key = "tools.record_fullscreen_mp4", glyph = "video" },
|
||||||
}
|
}
|
||||||
|
|
||||||
local function toolTile(t)
|
-- ── Compact mode ───────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
local function compactHeader()
|
||||||
|
local actions = {
|
||||||
|
ui.column({
|
||||||
|
key = "close-button",
|
||||||
|
width = 24,
|
||||||
|
height = 24,
|
||||||
|
radius = 9,
|
||||||
|
fill = hoveredClose and "primary/0.12" or nil,
|
||||||
|
border = hoveredClose and "primary" or "outline",
|
||||||
|
borderWidth = 1,
|
||||||
|
align = "center",
|
||||||
|
justify = "center",
|
||||||
|
onClick = function() panel.close() end,
|
||||||
|
onHover = function(state)
|
||||||
|
hoveredClose = state == "true"
|
||||||
|
render()
|
||||||
|
end,
|
||||||
|
}, {
|
||||||
|
ui.glyph({ name = "close", size = 14, color = hoveredClose and "on_surface" or "on_surface_variant" }),
|
||||||
|
}),
|
||||||
|
}
|
||||||
|
if recording then
|
||||||
|
table.insert(actions, 1, ui.column({
|
||||||
|
key = "stop-button",
|
||||||
|
width = 24,
|
||||||
|
height = 24,
|
||||||
|
radius = 9,
|
||||||
|
fill = "error",
|
||||||
|
border = hoveredStop and "on_surface" or nil,
|
||||||
|
borderWidth = hoveredStop and 2 or 0,
|
||||||
|
align = "center",
|
||||||
|
justify = "center",
|
||||||
|
tooltip = tr("panel.stop"),
|
||||||
|
onClick = function() send("recordStop") end,
|
||||||
|
onHover = function(state)
|
||||||
|
hoveredStop = state == "true"
|
||||||
|
render()
|
||||||
|
end,
|
||||||
|
}, {
|
||||||
|
ui.glyph({ name = "square", size = 12, color = "on_surface" }),
|
||||||
|
}))
|
||||||
|
end
|
||||||
|
return ui.row({ align = "center", gap = 6 }, {
|
||||||
|
ui.glyph({ name = "crosshair", size = 16, color = "primary" }),
|
||||||
|
ui.label({ text = tr("panel.title"), flexGrow = 1, fontSize = 16, fontWeight = "bold", color = "on_surface" }),
|
||||||
|
ui.row({ gap = 4 }, actions),
|
||||||
|
})
|
||||||
|
end
|
||||||
|
|
||||||
|
local function compactTile(t)
|
||||||
|
local color = hoveredTool == t.action and "primary" or "on_surface"
|
||||||
|
return ui.column({
|
||||||
|
key = "tile-" .. t.action,
|
||||||
|
flexGrow = 1,
|
||||||
|
gap = 2,
|
||||||
|
align = "center",
|
||||||
|
}, {
|
||||||
|
ui.column({
|
||||||
|
gap = 2,
|
||||||
|
align = "center",
|
||||||
|
onClick = function() runTool(t.action) end,
|
||||||
|
onHover = function(state)
|
||||||
|
hoveredTool = (state == "true") and t.action or nil
|
||||||
|
render()
|
||||||
|
end,
|
||||||
|
}, {
|
||||||
|
ui.column({ width = 30, height = 30, radius = 9, fill = "on_primary", border = color == "primary" and "primary" or "on_primary", borderWidth = 1, align = "center", justify = "center" }, {
|
||||||
|
ui.glyph({ name = t.glyph, size = 16, color = color }),
|
||||||
|
}),
|
||||||
|
ui.label({ text = tr(t.label_key), maxWidth = 100, maxLines = 1, textAlign = "center", fontSize = 11, color = color }),
|
||||||
|
}),
|
||||||
|
})
|
||||||
|
end
|
||||||
|
|
||||||
|
local function compactToolsRow(tools)
|
||||||
|
local row = {}
|
||||||
|
for _, t in ipairs(tools) do
|
||||||
|
row[#row + 1] = compactTile(t)
|
||||||
|
end
|
||||||
|
return ui.row({ flexGrow = 1, gap = 2 }, row)
|
||||||
|
end
|
||||||
|
|
||||||
|
local function compactSection(tools)
|
||||||
|
return ui.column({ gap = 4, paddingV = 8, paddingH = 6, radius = 12, fill = "surface_variant" }, {
|
||||||
|
compactToolsRow(tools),
|
||||||
|
})
|
||||||
|
end
|
||||||
|
|
||||||
|
local function compactGrid()
|
||||||
|
return ui.column({ gap = 6 }, {
|
||||||
|
compactSection(TOOLS),
|
||||||
|
compactSection(ANNOTATE_TOOLS),
|
||||||
|
compactSection(RECORD_TOOLS),
|
||||||
|
})
|
||||||
|
end
|
||||||
|
|
||||||
|
-- ── Full mode ──────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
local function fullHeader()
|
||||||
|
local actions = {
|
||||||
|
ui.button({ glyph = "close", onClick = function() panel.close() end }),
|
||||||
|
}
|
||||||
|
if recording then
|
||||||
|
table.insert(actions, 1, ui.button({
|
||||||
|
glyph = "square",
|
||||||
|
variant = "destructive",
|
||||||
|
controlSize = "sm",
|
||||||
|
tooltip = tr("panel.stop"),
|
||||||
|
onClick = function() send("recordStop") end,
|
||||||
|
}))
|
||||||
|
end
|
||||||
|
return ui.row({ align = "center", gap = 10 }, {
|
||||||
|
ui.glyph({ name = "crosshair", size = 24, color = "primary" }),
|
||||||
|
ui.label({ text = tr("panel.title"), flexGrow = 1, fontSize = 22, fontWeight = "bold", color = "on_surface" }),
|
||||||
|
ui.row({ gap = 4 }, actions),
|
||||||
|
})
|
||||||
|
end
|
||||||
|
|
||||||
|
local function fullTile(t)
|
||||||
|
local color = hoveredTool == t.action and "primary" or "on_surface"
|
||||||
return ui.column({
|
return ui.column({
|
||||||
key = "tile-" .. t.action,
|
key = "tile-" .. t.action,
|
||||||
flexGrow = 1,
|
flexGrow = 1,
|
||||||
gap = 6,
|
gap = 6,
|
||||||
align = "center",
|
align = "center",
|
||||||
paddingV = 6,
|
paddingV = 6,
|
||||||
radius = 10,
|
radius = 12,
|
||||||
fill = "surface_variant/0.28",
|
fill = "surface_variant",
|
||||||
borderWidth = 1,
|
borderWidth = 1,
|
||||||
border = "outline",
|
border = color == "primary" and "primary" or "outline",
|
||||||
onClick = function() runTool(t.action) end,
|
onClick = function() runTool(t.action) end,
|
||||||
|
onHover = function(state)
|
||||||
|
hoveredTool = (state == "true") and t.action or nil
|
||||||
|
render()
|
||||||
|
end,
|
||||||
}, {
|
}, {
|
||||||
ui.column({ width = 30, height = 30, radius = 9, fill = "primary/0.12", align = "center", justify = "center" }, {
|
ui.column({ width = 30, height = 30, radius = 9, fill = "on_primary", border = color == "primary" and "primary" or "on_primary", borderWidth = 1, align = "center", justify = "center" }, {
|
||||||
ui.glyph({ name = t.glyph, size = 16, color = "primary" }),
|
ui.glyph({ name = t.glyph, size = 16, color = color }),
|
||||||
}),
|
}),
|
||||||
ui.label({ text = tr(t.label_key), maxWidth = 100, maxLines = 1, textAlign = "center", fontSize = 11, color = "on_surface_variant" }),
|
ui.label({ text = tr(t.label_key), maxWidth = 100, maxLines = 1, textAlign = "center", fontSize = 11, color = color }),
|
||||||
})
|
})
|
||||||
end
|
end
|
||||||
|
|
||||||
local function toolsRow(tools)
|
local function fullToolsRow(tools)
|
||||||
local row = {}
|
local row = {}
|
||||||
for _, t in ipairs(tools) do
|
for _, t in ipairs(tools) do
|
||||||
row[#row + 1] = toolTile(t)
|
row[#row + 1] = fullTile(t)
|
||||||
end
|
end
|
||||||
return ui.row({ flexGrow = 1, gap = 6 }, row)
|
return ui.row({ flexGrow = 1, gap = 6 }, row)
|
||||||
end
|
end
|
||||||
@@ -121,30 +238,40 @@ local function sectionLabel(text)
|
|||||||
return ui.label({ text = text, fontSize = 11, fontWeight = "bold", color = "on_surface_variant" })
|
return ui.label({ text = text, fontSize = 11, fontWeight = "bold", color = "on_surface_variant" })
|
||||||
end
|
end
|
||||||
|
|
||||||
local function toolGrid()
|
local function fullGrid()
|
||||||
return ui.column({ flexGrow = 1, gap = 4, justify = "space_between" }, {
|
return ui.column({ flexGrow = 1, gap = 4, justify = "space_between" }, {
|
||||||
sectionLabel(tr("panel.section_capture")),
|
sectionLabel(tr("panel.section_capture")),
|
||||||
toolsRow(TOOLS),
|
fullToolsRow(TOOLS),
|
||||||
sectionLabel(tr("panel.section_annotate")),
|
sectionLabel(tr("panel.section_annotate")),
|
||||||
toolsRow(ANNOTATE_TOOLS),
|
fullToolsRow(ANNOTATE_TOOLS),
|
||||||
sectionLabel(tr("panel.section_record")),
|
sectionLabel(tr("panel.section_record")),
|
||||||
toolsRow(RECORD_TOOLS),
|
fullToolsRow(RECORD_TOOLS),
|
||||||
})
|
})
|
||||||
end
|
end
|
||||||
|
|
||||||
-- ── Main render ────────────────────────────────────────────────────────────
|
-- ── Main render ────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
local function render()
|
render = function()
|
||||||
panel.render(ui.column({ flexGrow = 1, gap = 10 }, {
|
local body
|
||||||
header(),
|
if getMode() == "full" then
|
||||||
toolGrid(),
|
body = ui.column({ flexGrow = 1, gap = 10 }, {
|
||||||
}))
|
fullHeader(),
|
||||||
|
fullGrid(),
|
||||||
|
})
|
||||||
|
else
|
||||||
|
body = ui.column({ flexGrow = 1, gap = 6 }, {
|
||||||
|
compactHeader(),
|
||||||
|
compactGrid(),
|
||||||
|
})
|
||||||
|
end
|
||||||
|
panel.render(body)
|
||||||
end
|
end
|
||||||
|
|
||||||
-- ── Lifecycle ──────────────────────────────────────────────────────────────
|
-- ── Lifecycle ──────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
function onOpen(_context)
|
function onOpen(_context)
|
||||||
panelOpen = true
|
panelOpen = true
|
||||||
|
hoveredTool = nil
|
||||||
render()
|
render()
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
+44
-20
@@ -8,7 +8,7 @@
|
|||||||
|
|
||||||
id = "alexander/screen-toolkit"
|
id = "alexander/screen-toolkit"
|
||||||
name = "Screen Toolkit"
|
name = "Screen Toolkit"
|
||||||
version = "1.0.0"
|
version = "1.1.0"
|
||||||
plugin_api = 9
|
plugin_api = 9
|
||||||
author = "alexander"
|
author = "alexander"
|
||||||
license = "MIT"
|
license = "MIT"
|
||||||
@@ -40,6 +40,38 @@ dependencies = [
|
|||||||
"wf-recorder",
|
"wf-recorder",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
# ── Panel entries (host-injected placement/size settings appear here, first in the settings editor) ──
|
||||||
|
|
||||||
|
# Main toolkit panel: tool grid + per-tool result views + recording controls.
|
||||||
|
# Open with: noctalia msg panel-toggle alexander/screen-toolkit:panel
|
||||||
|
# Compact layout (default). Full mode uses the "panel-full" entry below; the
|
||||||
|
# bar widget / shortcut open whichever entry matches the "panel-mode" setting.
|
||||||
|
[[panel]]
|
||||||
|
id = "panel"
|
||||||
|
entry = "panel.luau"
|
||||||
|
width = 380
|
||||||
|
height = 260
|
||||||
|
placement = "floating"
|
||||||
|
position = "center"
|
||||||
|
|
||||||
|
# Full-mode layout: the original spacious grid (660x340).
|
||||||
|
[[panel]]
|
||||||
|
id = "panel-full"
|
||||||
|
entry = "panel.luau"
|
||||||
|
width = 660
|
||||||
|
height = 340
|
||||||
|
placement = "floating"
|
||||||
|
position = "center"
|
||||||
|
|
||||||
|
# Result panel: opened by the service when a capture tool finishes.
|
||||||
|
[[panel]]
|
||||||
|
id = "result"
|
||||||
|
entry = "result.luau"
|
||||||
|
width = 560
|
||||||
|
height = 520
|
||||||
|
placement = "floating"
|
||||||
|
position = "center"
|
||||||
|
|
||||||
# ── Plugin-level settings (shared by every entry, edited in Settings → Plugins) ──
|
# ── Plugin-level settings (shared by every entry, edited in Settings → Plugins) ──
|
||||||
|
|
||||||
[[setting]]
|
[[setting]]
|
||||||
@@ -170,6 +202,17 @@ default = 30
|
|||||||
min = 1
|
min = 1
|
||||||
max = 600
|
max = 600
|
||||||
|
|
||||||
|
[[setting]]
|
||||||
|
key = "panel-mode"
|
||||||
|
type = "select"
|
||||||
|
label_key = "settings.panel_mode.label"
|
||||||
|
description_key = "settings.panel_mode.description"
|
||||||
|
default = "full"
|
||||||
|
options = [
|
||||||
|
{ value = "compact", label_key = "settings.panel_mode.options.compact" },
|
||||||
|
{ value = "full", label_key = "settings.panel_mode.options.full" },
|
||||||
|
]
|
||||||
|
|
||||||
# ── Entries ─────────────────────────────────────────────────────────────────
|
# ── Entries ─────────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
# Bar widget: crosshair glyph; shows a pulsing red dot while recording.
|
# Bar widget: crosshair glyph; shows a pulsing red dot while recording.
|
||||||
@@ -183,25 +226,6 @@ entry = "widget.luau"
|
|||||||
id = "toggle"
|
id = "toggle"
|
||||||
entry = "shortcut.luau"
|
entry = "shortcut.luau"
|
||||||
|
|
||||||
# Main toolkit panel: tool grid + per-tool result views + recording controls.
|
|
||||||
# Open with: noctalia msg panel-toggle alexander/screen-toolkit:panel
|
|
||||||
[[panel]]
|
|
||||||
id = "panel"
|
|
||||||
entry = "panel.luau"
|
|
||||||
width = 660
|
|
||||||
height = 340
|
|
||||||
placement = "floating"
|
|
||||||
position = "center"
|
|
||||||
|
|
||||||
# Result panel: opened by the service when a capture tool finishes.
|
|
||||||
[[panel]]
|
|
||||||
id = "result"
|
|
||||||
entry = "result.luau"
|
|
||||||
width = 560
|
|
||||||
height = 520
|
|
||||||
placement = "floating"
|
|
||||||
position = "center"
|
|
||||||
|
|
||||||
# Headless engine: owns captures, tool pipelines, recording, and persistence.
|
# Headless engine: owns captures, tool pipelines, recording, and persistence.
|
||||||
[[service]]
|
[[service]]
|
||||||
id = "service"
|
id = "service"
|
||||||
|
|||||||
@@ -16,6 +16,7 @@
|
|||||||
-- lands in /tmp as MP4; GIF is produced on save via record.sh convert-gif.
|
-- lands in /tmp as MP4; GIF is produced on save via record.sh convert-gif.
|
||||||
|
|
||||||
local PANEL_ID = "alexander/screen-toolkit:panel"
|
local PANEL_ID = "alexander/screen-toolkit:panel"
|
||||||
|
local FULL_PANEL_ID = "alexander/screen-toolkit:panel-full"
|
||||||
local RESULT_PANEL_ID = "alexander/screen-toolkit:result"
|
local RESULT_PANEL_ID = "alexander/screen-toolkit:result"
|
||||||
|
|
||||||
local SCRIPT_CAPTURE = noctalia.pluginDir() .. "/scripts/capture.sh"
|
local SCRIPT_CAPTURE = noctalia.pluginDir() .. "/scripts/capture.sh"
|
||||||
@@ -919,7 +920,10 @@ local HANDLERS = {
|
|||||||
clearResult = clearResult,
|
clearResult = clearResult,
|
||||||
clearHistory = clearHistory,
|
clearHistory = clearHistory,
|
||||||
setCursorHidden = setCursorHidden,
|
setCursorHidden = setCursorHidden,
|
||||||
toggle = function() noctalia.togglePanel(PANEL_ID) end,
|
toggle = function()
|
||||||
|
local id = cfg("panel-mode") == "full" and FULL_PANEL_ID or PANEL_ID
|
||||||
|
noctalia.togglePanel(id)
|
||||||
|
end,
|
||||||
}
|
}
|
||||||
|
|
||||||
-- Tools that begin a brand-new capture. Starting one discards any recording
|
-- Tools that begin a brand-new capture. Starting one discards any recording
|
||||||
|
|||||||
@@ -21,7 +21,8 @@ end)
|
|||||||
function onClick()
|
function onClick()
|
||||||
-- The shortcut tile never stops a recording; it just opens the panel so
|
-- The shortcut tile never stops a recording; it just opens the panel so
|
||||||
-- the stop button (in the panel header, next to the close X) is reachable.
|
-- the stop button (in the panel header, next to the close X) is reachable.
|
||||||
noctalia.togglePanel("alexander/screen-toolkit:panel")
|
local panelId = noctalia.getConfig("panel-mode") == "full" and "alexander/screen-toolkit:panel-full" or "alexander/screen-toolkit:panel"
|
||||||
|
noctalia.togglePanel(panelId)
|
||||||
end
|
end
|
||||||
|
|
||||||
apply()
|
apply()
|
||||||
|
|||||||
Binary file not shown.
|
Before Width: | Height: | Size: 57 KiB After Width: | Height: | Size: 66 KiB |
@@ -199,6 +199,14 @@
|
|||||||
"gif_max_seconds": {
|
"gif_max_seconds": {
|
||||||
"label": "Max GIF Duration",
|
"label": "Max GIF Duration",
|
||||||
"description": "Maximum duration in seconds for GIF recordings."
|
"description": "Maximum duration in seconds for GIF recordings."
|
||||||
|
},
|
||||||
|
"panel_mode": {
|
||||||
|
"label": "Panel Mode",
|
||||||
|
"description": "Layout of the main panel. Compact is the dense grid; Full is the original spacious grid.",
|
||||||
|
"options": {
|
||||||
|
"compact": "Compact",
|
||||||
|
"full": "Full"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -55,7 +55,8 @@ end)
|
|||||||
function onClick()
|
function onClick()
|
||||||
-- The bar icon never stops a recording; it just opens the panel so the
|
-- The bar icon never stops a recording; it just opens the panel so the
|
||||||
-- stop button (in the panel header, next to the close X) is reachable.
|
-- stop button (in the panel header, next to the close X) is reachable.
|
||||||
noctalia.togglePanel("alexander/screen-toolkit:panel")
|
local panelId = noctalia.getConfig("panel-mode") == "full" and "alexander/screen-toolkit:panel-full" or "alexander/screen-toolkit:panel"
|
||||||
|
noctalia.togglePanel(panelId)
|
||||||
end
|
end
|
||||||
|
|
||||||
function onRightClick()
|
function onRightClick()
|
||||||
|
|||||||
Reference in New Issue
Block a user