Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
56 changes: 56 additions & 0 deletions mango_layouts/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
# Mango Layouts

A clean, minimalist layout switcher plugin for MangoWC. It provides a bar widget and a fast popup panel to switch workspace layouts on the fly, directly from your desktop.

## Plugin

| Field | Value |
| --- | --- |
| ID | `ezequiel/mango_layouts` |
| Entries | Bar widget: `btn`; panel: `panel` |

## Requirements

Install `jq` and `mmsg` (MangoWC CLI) on `PATH`.
Requires MangoWC as the compositor.

## Usage

Add the widget to your Noctalia bar in Settings. Click the widget to open the layout switcher panel and change the current workspace layout.

Alternatively, toggle the panel directly via command line or keybinding:

```sh
noctalia msg panel-toggle ezequiel/mango_layouts:panel
```

## Settings

| Setting | Type | Default | Description |
| --- | --- | --- | --- |
| `list_mode` | `bool` | `false` | Display layouts in a vertical list instead of a grid. |
| `show_tile` | `bool` | `true` | Show Tile layout. |
| `show_scroller` | `bool` | `true` | Show Scroller layout. |
| `show_monocle` | `bool` | `true` | Show Monocle layout. |
| `show_grid` | `bool` | `true` | Show Grid layout. |
| `show_fair` | `bool` | `true` | Show Fair layout. |
| `show_deck` | `bool` | `true` | Show Deck layout. |
| `show_dwindle` | `bool` | `true` | Show Dwindle layout. |
| `show_center_tile` | `bool` | `true` | Show Center Tile layout. |
| `show_vertical_tile` | `bool` | `true` | Show Vertical Tile layout. |
| `show_right_tile` | `bool` | `true` | Show Right Tile layout. |
| `show_vertical_scroller` | `bool` | `true` | Show Vertical Scroller layout. |
| `show_vertical_grid` | `bool` | `true` | Show Vertical Grid layout. |
| `show_vertical_deck` | `bool` | `true` | Show Vertical Deck layout. |
| `show_vertical_fair` | `bool` | `true` | Show Vertical Fair layout. |

Widget Specific Settings:
| Setting | Type | Default | Description |
| --- | --- | --- | --- |
| `show_glyph` | `bool` | `true` | Show the widget icon. |
| `show_text` | `bool` | `false` | Show the active layout name as text. |
| `custom_color` | `string` | `""` | Custom icon/text color (e.g. primary, on_surface). |

## Notes

The plugin uses `mmsg` to communicate with MangoWC for reading the active monitor state and applying the selected layout. Make sure you don't use this plugin on compositors other than MangoWC.
174 changes: 174 additions & 0 deletions mango_layouts/panel.luau
Original file line number Diff line number Diff line change
@@ -0,0 +1,174 @@
local layouts = {
{ sym = "T", name = "tile", label = "Tile", glyph = "layout-sidebar" },
{ sym = "S", name = "scroller", label = "Scroller", glyph = "carousel-horizontal" },
{ sym = "M", name = "monocle", label = "Monocle", glyph = "square" },
{ sym = "G", name = "grid", label = "Grid", glyph = "layout-grid" },
{ sym = "F", name = "fair", label = "Fair", glyph = "layout-board-split" },
{ sym = "D", name = "deck", label = "Deck", glyph = "layers-difference" },
{ sym = "DW", name = "dwindle", label = "Dwindle", glyph = "layout-2" },
{ sym = "CT", name = "center_tile", label = "Center Tile", glyph = "layout-distribute-vertical" },
{ sym = "VT", name = "vertical_tile", label = "Vertical Tile", glyph = "layout-rows" },
{ sym = "RT", name = "right_tile", label = "Right Tile", glyph = "layout-sidebar-right" },
{ sym = "VS", name = "vertical_scroller",label = "Vertical Scroller", glyph = "carousel-vertical" },
{ sym = "VG", name = "vertical_grid", label = "Vertical Grid", glyph = "grid-dots" },
{ sym = "VD", name = "vertical_deck", label = "Vertical Deck", glyph = "chart-funnel" },
{ sym = "VF", name = "vertical_fair", label = "Vertical Fair", glyph = "layout-board" },
}

local COLUMNS = 4
local COLUMN_GAP = 2
local selectedLayout = ""
local pickSlots = {}

local render

local function onPickAt(index)
local slot = pickSlots[index]
if slot == nil then return end
selectedLayout = slot.sym
noctalia.runAsync("mmsg dispatch setlayout," .. slot.entry.name)
panel.close()
end

local function makeGrid(children)
local rows = {}
local row = {}
for i, child in ipairs(children) do
table.insert(row, child)
if #row >= COLUMNS or i == #children then
while #row < COLUMNS do
table.insert(row, ui.spacer({ flexGrow = 1 }))
end
table.insert(rows, ui.row({ gap = COLUMN_GAP, align = "stretch" }, row))
row = {}
end
end
return ui.column({ gap = COLUMN_GAP }, rows)
end

local function getShowConfig(name)
if name == "tile" then return noctalia.getConfig("show_tile") end
if name == "scroller" then return noctalia.getConfig("show_scroller") end
if name == "monocle" then return noctalia.getConfig("show_monocle") end
if name == "grid" then return noctalia.getConfig("show_grid") end
if name == "fair" then return noctalia.getConfig("show_fair") end
if name == "deck" then return noctalia.getConfig("show_deck") end
if name == "dwindle" then return noctalia.getConfig("show_dwindle") end
if name == "center_tile" then return noctalia.getConfig("show_center_tile") end
if name == "vertical_tile" then return noctalia.getConfig("show_vertical_tile") end
if name == "right_tile" then return noctalia.getConfig("show_right_tile") end
if name == "vertical_scroller" then return noctalia.getConfig("show_vertical_scroller") end
if name == "vertical_grid" then return noctalia.getConfig("show_vertical_grid") end
if name == "vertical_deck" then return noctalia.getConfig("show_vertical_deck") end
if name == "vertical_fair" then return noctalia.getConfig("show_vertical_fair") end
return true
end

local function renderButtons(is_list_mode)
local buttons = {}
local i = 0
for _, entry in ipairs(layouts) do
local raw_val = getShowConfig(entry.name)
local enabled = (raw_val == true) or (raw_val == "true") or (raw_val == nil)

if enabled then
local slotIndex = i
local isSelected = selectedLayout == entry.sym
pickSlots[slotIndex] = { sym = entry.sym, entry = entry }

if is_list_mode then
table.insert(buttons, ui.button({
key = entry.sym,
glyph = entry.glyph,
text = entry.label,
variant = if isSelected then "primary" else "ghost",
onClick = `onPick{slotIndex}`,
-- If noctalia supports button alignment, this will align it to the left:
-- (If not, it will just remain centered like an elegant menu)
}))
else
-- Grid Mode
table.insert(buttons, ui.column({
key = entry.sym,
gap = 2,
align = "center",
flexGrow = 1,
}, {
ui.button({
glyph = entry.glyph,
glyphSize = 18,
variant = if isSelected then "primary" else "ghost",
onClick = `onPick{slotIndex}`,
}),
ui.label({
text = entry.label,
fontSize = 9,
fontWeight = "bold",
color = if isSelected then "primary" else "on_surface_variant",
textAlign = "center",
maxLines = 1,
}),
}))
end
i += 1
end
end
return buttons
end

render = function()
pickSlots = {}

local list_mode_raw = noctalia.getConfig("list_mode")
local is_list_mode = (list_mode_raw == true) or (list_mode_raw == "true")

local content
if is_list_mode then
content = ui.column({ padding = 8, gap = 4 }, renderButtons(true))
else
content = ui.column({ padding = 12, gap = COLUMN_GAP }, {
makeGrid(renderButtons(false))
})
end

panel.render(ui.column({ flexGrow = 1 }, {
ui.scroll({ flexGrow = 1 }, {
content
})
}))
end

function onOpen(context)
selectedLayout = ""
render()
noctalia.runAsync(
"mmsg get all-monitors | jq -r '.monitors[] | select(.active == true and .last_open_surface != null) | .layout_symbol'",
function(result)
if result == nil or result.exitCode ~= 0 then return end
local sym = result.stdout:gsub("%s+", "")

-- Check if sym exists in our ordered list
local exists = false
for _, l in ipairs(layouts) do
if l.sym == sym then exists = true end
end
selectedLayout = if exists then sym else ""
render()
end
)
end

function onPick0() onPickAt(0) end
function onPick1() onPickAt(1) end
function onPick2() onPickAt(2) end
function onPick3() onPickAt(3) end
function onPick4() onPickAt(4) end
function onPick5() onPickAt(5) end
function onPick6() onPickAt(6) end
function onPick7() onPickAt(7) end
function onPick8() onPickAt(8) end
function onPick9() onPickAt(9) end
function onPick10() onPickAt(10) end
function onPick11() onPickAt(11) end
function onPick12() onPickAt(12) end
function onPick13() onPickAt(13) end
134 changes: 134 additions & 0 deletions mango_layouts/plugin.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
id = "ezequiel/mango_layouts"
name = "Mango Layouts"
version = "1.0.0"
plugin_api = 14
author = "ezequiel"
license = "MIT"
icon = "layout-filled"
description = "Layout switcher for MangoWC"
tags = ["bar", "panel", "mangowc", "utility"]
dependencies = ["jq", "mmsg"]

[[widget]]
id = "btn"
entry = "widget.luau"
actions = {}

# -- WIDGET SETTINGS --
[[widget.setting]]
key = "show_glyph"
type = "bool"
label_key = "show_icon_label"
default = true

[[widget.setting]]
key = "show_text"
type = "bool"
label_key = "show_text_label"
default = false

[[widget.setting]]
key = "custom_color"
type = "string"
label_key = "custom_color_label"
description_key = "custom_color_desc"
default = ""

[[panel]]
id = "panel"
entry = "panel.luau"
width = 240
height = 250
placement = "floating"
position = "bottom_right"

# -- GLOBAL SETTINGS --
[[setting]]
key = "list_mode"
type = "bool"
label_key = "list_mode_label"
default = false

[[setting]]
key = "show_tile"
type = "bool"
label_key = "layout_tile_label"
default = true

[[setting]]
key = "show_scroller"
type = "bool"
label_key = "layout_scroller_label"
default = true

[[setting]]
key = "show_monocle"
type = "bool"
label_key = "layout_monocle_label"
default = true

[[setting]]
key = "show_grid"
type = "bool"
label_key = "layout_grid_label"
default = true

[[setting]]
key = "show_fair"
type = "bool"
label_key = "layout_fair_label"
default = true

[[setting]]
key = "show_deck"
type = "bool"
label_key = "layout_deck_label"
default = true

[[setting]]
key = "show_dwindle"
type = "bool"
label_key = "layout_dwindle_label"
default = true

[[setting]]
key = "show_center_tile"
type = "bool"
label_key = "layout_center_tile_label"
default = true

[[setting]]
key = "show_vertical_tile"
type = "bool"
label_key = "layout_vertical_tile_label"
default = true

[[setting]]
key = "show_right_tile"
type = "bool"
label_key = "layout_right_tile_label"
default = true

[[setting]]
key = "show_vertical_scroller"
type = "bool"
label_key = "layout_vertical_scroller_label"
default = true

[[setting]]
key = "show_vertical_grid"
type = "bool"
label_key = "layout_vertical_grid_label"
default = true

[[setting]]
key = "show_vertical_deck"
type = "bool"
label_key = "layout_vertical_deck_label"
default = true

[[setting]]
key = "show_vertical_fair"
type = "bool"
label_key = "layout_vertical_fair_label"
default = true
Binary file added mango_layouts/thumbnail.webp
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading