---@module "mez_types" ---@class Euclid ---@field default_config EuclidConfig ---@field config EuclidConfig ---@field state EuclidState local M = {} local utils = {} ---@param view_id integer ---@return integer? view_idx ---@return integer? tag_idx utils.find_view = function (view_id) for tag_idx = 1, M.config.tag_count do for view_idx, v in ipairs(M.state.tags[tag_idx].views) do if v == view_id then return view_idx, tag_idx end end end return nil, nil end ---@class EuclidConfig ---@field mod_key string ---@field tag_count number ---@field focus_on_spawn boolean ---@field refocus_on_kill boolean local default_config = { mod_key = "alt", tag_count = 5, focus_on_spawn = true, refocus_on_kill = true, } ---@class EuclidTag ---@field views number[] ---@field last_focused number | nil ---@class EuclidState ---@field tag_id number ---@field tags EuclidTag[] ---Add the id of a new view ---@param view_id number M.add_view = function(view_id) local tag = M.state.tags[M.state.tag_id] tag.views[#tag.views + 1] = view_id local res = mez.output.get_available_area(0) if res == nil then return end mez.view.set_geometry(view_id, { x = (0.25 / 2) * res.width, y = (0.25 / 2) * res.height, width = res.width * 0.75, height = res.height * 0.75 }) if M.config.focus_on_spawn then mez.view.set_focused(view_id) end end ---Move the focus in a tag to the next view M.focus_next = function() local view_id = mez.view.get_focused_id() if view_id == nil then return end local view_idx, tag_idx = utils.find_view(view_id) if view_idx == nil or tag_idx == nil then return end local tag = M.state.tags[tag_idx] if view_idx == #tag.views then mez.view.set_focused(tag.views[1]) else mez.view.set_focused(tag.views[view_idx + 1]) end end ---Move the focus in a tag to the previous view M.focus_prev = function() local view_id = mez.view.get_focused_id() if view_id == nil then return end local view_idx, tag_idx = utils.find_view(view_id) if view_idx == nil or tag_idx == nil then return end local tag = M.state.tags[tag_idx] if view_idx == 1 then mez.view.set_focused(tag.views[#tag.views]) else mez.view.set_focused(tag.views[view_idx - 1]) end end ---Remove a view_id from the layout ---@param view_id integer M.remove_view = function(view_id) local view_idx, tag_idx = utils.find_view(view_id) if view_idx == nil or tag_idx == nil then return end local tag = M.state.tags[tag_idx] if M.config.refocus_on_kill then if #tag.views == 0 then mez.view.set_focused(nil) else mez.view.set_focused(tag.views[#tag.views == view_idx and view_idx - 1 or view_idx]) end end end ---Switch to a tag by enabling all views for 1 tag, ---and disabling all the views for the old tag ---@param tag_idx number M.tag_enable = function (tag_idx) ---@param t number ---@param enabled boolean local set_tag_enable = function (t, enabled) local tag = M.state.tags[t] local focused = mez.view.get_focused_id() if not enabled and focused ~= nil then tag.last_focused = focused end for _, v in ipairs(tag.views) do mez.view.set_enabled(v, enabled) end end set_tag_enable(M.state.tag_id, false) set_tag_enable(tag_idx, true) M.state.tag_id = tag_idx end ---@param view_id number ---@param tag_id number M.send_view = function (view_id, tag_id) -- if view_id == 0 then view_id = mez.view.get_focused_id() end -- if tag_id == M.state.tag_id then return end -- -- local type, _, _ = utils.find_view(view_id) -- -- local tag = M.state.tags[tag_id] -- -- M.remove_view(view_id) -- -- if type == "floating" then -- table.insert(tag.floating, #tag.floating, view_id) -- else -- if tag.master == nil then -- tag.master = view_id -- else -- table.insert(tag.stack, #tag.stack, view_id) -- end -- end -- -- mez.view.set_enabled(view_id, false) -- M.tile_tag(M.state.tag_id) -- M.tile_tag(tag_id) end M.setup = function() --- Take a user config M.config = default_config M.state = { tag_id = 1, tags = {}, } -- Create all tags for the state for i = 1, M.config.tag_count do M.state.tags[i] = { views = {}, last_focused = nil } end mez.hook.add("ViewMapPre", { callback = function(view_id) M.add_view(view_id) end }) mez.hook.add("ViewUnmapPost", { callback = function(view_id) M.remove_view(view_id) end }) mez.input.add_keymap(M.config.mod_key, "j", { press = function () M.focus_next() end }) mez.input.add_keymap(M.config.mod_key, "k", { press = function () M.focus_prev() end }) local fullscreen = function() mez.view.toggle_fullscreen(0) end mez.input.add_keymap(M.config.mod_key.."|shift", "F", { press = fullscreen }) mez.hook.add("ViewRequestFullscreen", { callback = fullscreen }) for i = 1, M.config.tag_count do mez.input.add_keymap(M.config.mod_key, tostring(i), { press = function () M.tag_enable(i) end }) end mez.input.add_mousemap(M.config.mod_key, "BTN_LEFT", { press = function () return false end, drag = function(view_id, pos, _, offset) if view_id ~= nil then mez.view.set_geometry(view_id, { x = pos.x - offset.x, y = pos.y - offset.y }) end end }) ---@type {x: number, y: number}[] local move_all = {} mez.input.add_mousemap(M.config.mod_key, "BTN_MIDDLE", { press = function () move_all = {} for i, v in ipairs(M.state.tags[M.state.tag_id].views) do local geo = mez.view.get_geometry(v) move_all[i] = { x = geo.x, y = geo.y } end end, drag = function(_, pos, start, offset) for i, v in ipairs(M.state.tags[M.state.tag_id].views) do local geo = move_all[i] mez.view.set_geometry(v, { x = geo.x + (pos.x - start.x), y = geo.y + (pos.y - start.y) }) end end }) mez.input.add_mousemap(M.config.mod_key, "BTN_RIGHT", { drag = function(view_id, pos, start, offset) if view_id ~= nil then local geo = mez.view.get_geometry(view_id) local width = offset.x + pos.x - start.x local height = offset.y + pos.y - start.y if width <= 10 then width = 10 end if height <= 10 then height = 10 end mez.view.set_geometry(view_id, { width = width, height = height }) end end }) mez.input.add_mousemap(M.config.mod_key, "REL_WHEEL", { scroll = function (view_id, pos, delta, discrete_delta) delta = -delta / 250; mez.output.set_scale(0, mez.output.get_scale(0) + delta) print(mez.output.get_scale(0)) end }) mez.input.add_keymap(M.config.mod_key.."|shift", "equal", { press = function () print("pressed") local _, err = pcall(function () mez.output.set_scale(0, mez.output.get_scale(0) + 0.1) print(mez.output.get_scale(0)) end) if err then print(err) end end }) end return M