]> git.madduck.net Git - etc/awesome.git/blobdiff - layout/termfair.lua

madduck's git repository

Every one of the projects in this repository is available at the canonical URL git://git.madduck.net/madduck/pub/<projectpath> — see each project's metadata for the exact URL.

All patches and comments are welcome. Please squash your changes to logical commits before using git-format-patch and git-send-email to patches@git.madduck.net. If you'd read over the Git project's submission guidelines and adhered to them, I'd be especially grateful.

SSH access, as well as push access can be individually arranged.

If you use my repositories frequently, consider adding the following snippet to ~/.gitconfig and using the third clone URL listed for each project:

[url "git://git.madduck.net/madduck/"]
  insteadOf = madduck:

fix #288
[etc/awesome.git] / layout / termfair.lua
index 62eef9ab6663d585a1054d33f361d024646b22eb..6d244606a87a96b284135dc1361be93c4f7df356 100644 (file)
 --[[
                                                   
      Licensed under GNU General Public License v2 
 --[[
                                                   
      Licensed under GNU General Public License v2 
+      * (c) 2014,      projektile                 
       * (c) 2013,      Luke Bonham                
       * (c) 2013,      Luke Bonham                
+      * (c) 2010,      Nicolas Estibals           
       * (c) 2010-2012, Peter Hofmann              
                                                   
 --]]
 
       * (c) 2010-2012, Peter Hofmann              
                                                   
 --]]
 
-local tag       = require("awful.tag")
-local beautiful = require("beautiful")
-local math      = { ceil  = math.ceil,
-                    floor = math.floor,
-                    max   = math.max }
-local tonumber  = tonumber
+local tag      = require("awful.tag")
+local math     = { ceil  = math.ceil,
+                   floor = math.floor,
+                   max   = math.max }
+local tonumber = tonumber
 
 
-local termfair =
-{
-    name    = "termfair",
-
-    -- You can set the number of columns and rows,
-    -- -- otherwise they are read from awful.tag
-    nmaster = 0, -- columns
-    ncol    = 0  -- rows
-}
-
-function termfair.arrange(p)
-    -- Layout with fixed number of vertical columns (read from nmaster).
-    -- New windows align from left to right. When a row is full, a now
-    -- one above it is created. Like this:
-
-    --        (1)                (2)                (3)
-    --   +---+---+---+      +---+---+---+      +---+---+---+
-    --   |   |   |   |      |   |   |   |      |   |   |   |
-    --   | 1 |   |   |  ->  | 2 | 1 |   |  ->  | 3 | 2 | 1 |  ->
-    --   |   |   |   |      |   |   |   |      |   |   |   |
-    --   +---+---+---+      +---+---+---+      +---+---+---+
-
-    --        (4)                (5)                (6)
-    --   +---+---+---+      +---+---+---+      +---+---+---+
-    --   | 4 |   |   |      | 5 | 4 |   |      | 6 | 5 | 4 |
-    --   +---+---+---+  ->  +---+---+---+  ->  +---+---+---+
-    --   | 3 | 2 | 1 |      | 3 | 2 | 1 |      | 3 | 2 | 1 |
-    --   +---+---+---+      +---+---+---+      +---+---+---+
-
-    -- A useless gap (like the dwm patch) can be defined with
-    -- beautiful.useless_gap_width.
-    local useless_gap = tonumber(beautiful.useless_gap_width)
-    if useless_gap == nil
-    then
-        useless_gap = 0
-    end
+local termfair  = { name = "termfair" }
+termfair.center = { name = "centerfair" }
 
 
+local function do_fair(p, orientation)
     -- Screen.
     -- Screen.
-    local wa = p.workarea
+    local wa  = p.workarea
     local cls = p.clients
 
     local cls = p.clients
 
-    -- How many vertical columns?
-    local t = tag.selected(p.screen)
-    local num_x
-    if termfair.nmaster ~= 0
-    then
-        num_x = termfair.nmaster
-    else
-        num_x = tag.getnmaster(t)
-    end
+    if #cls <= 0 then return end
 
 
-    -- Do at least "desired_y" rows.
-    local desired_y
-    if termfair.ncol ~= 0
-    then
-        desired_y = termfair.ncol
-    else
-        desired_y = tag.getncol(t)
-    end
+    -- Useless gaps.
+    local useless_gap = p.useless_gap or 0
+
+    if orientation == "west" then
+        -- Layout with fixed number of vertical columns (read from nmaster).
+        -- New windows align from left to right. When a row is full, a now
+        -- one above it is created. Like this:
+
+        --        (1)                (2)                (3)
+        --   +---+---+---+      +---+---+---+      +---+---+---+
+        --   |   |   |   |      |   |   |   |      |   |   |   |
+        --   | 1 |   |   |  ->  | 2 | 1 |   |  ->  | 3 | 2 | 1 |  ->
+        --   |   |   |   |      |   |   |   |      |   |   |   |
+        --   +---+---+---+      +---+---+---+      +---+---+---+
+
+        --        (4)                (5)                (6)
+        --   +---+---+---+      +---+---+---+      +---+---+---+
+        --   | 4 |   |   |      | 5 | 4 |   |      | 6 | 5 | 4 |
+        --   +---+---+---+  ->  +---+---+---+  ->  +---+---+---+
+        --   | 3 | 2 | 1 |      | 3 | 2 | 1 |      | 3 | 2 | 1 |
+        --   +---+---+---+      +---+---+---+      +---+---+---+
+
+        if #cls <= 0 then return end
 
 
-    if #cls > 0
-    then
-        local num_y = math.max(math.ceil(#cls / num_x), desired_y)
+        -- How many vertical columns? Read from nmaster on the tag.
+        local num_x = tonumber(termfair.nmaster) or tag.master_count
+        local ncol  = tonumber(termfair.ncol) or tag.column_count
+        local width = math.floor((wa.width - (num_x + 1)*useless_gap) / num_x)
+
+        if num_x <= 2 then num_x = 2 end
+        if ncol  <= 1 then ncol  = 1 end
+
+        local num_y     = math.max(math.ceil(#cls / num_x), ncol)
+        local height    = math.floor((wa.height - (num_y + 1)*useless_gap) / num_y)
         local cur_num_x = num_x
         local cur_num_x = num_x
-        local at_x = 0
-        local at_y = 0
+        local at_x      = 0
+        local at_y      = 0
+
         local remaining_clients = #cls
         local remaining_clients = #cls
-        local width = math.floor(wa.width / num_x)
-        local height = math.floor(wa.height / num_y)
 
         -- We start the first row. Left-align by limiting the number of
         -- available slots.
 
         -- We start the first row. Left-align by limiting the number of
         -- available slots.
-        if remaining_clients < num_x
-        then
+        if remaining_clients < num_x then
             cur_num_x = remaining_clients
         end
 
         -- Iterate in reversed order.
             cur_num_x = remaining_clients
         end
 
         -- Iterate in reversed order.
-        for i = #cls,1,-1
-        do
+        for i = #cls,1,-1 do
             -- Get x and y position.
             local c = cls[i]
             local this_x = cur_num_x - at_x - 1
             local this_y = num_y - at_y - 1
 
             -- Get x and y position.
             local c = cls[i]
             local this_x = cur_num_x - at_x - 1
             local this_y = num_y - at_y - 1
 
-            -- Calc geometry.
+            -- Calculate geometry.
             local g = {}
             local g = {}
-            if this_x == (num_x - 1)
-            then
-                g.width = wa.width - (num_x - 1) * width
+            if this_x == (num_x - 1) then
+                g.width = wa.width - (num_x - 1)*width - (num_x + 1)*useless_gap - 2*c.border_width
             else
             else
-                g.width = width
+                g.width = width - 2*c.border_width
             end
             end
-            if this_y == (num_y - 1)
-            then
-                g.height = wa.height - (num_y - 1) * height
+
+            if this_y == (num_y - 1) then
+                g.height = wa.height - (num_y - 1)*height - (num_y + 1)*useless_gap - 2*c.border_width
             else
             else
-                g.height = height
+                g.height = height - 2*c.border_width
             end
             end
-            g.x = wa.x + this_x * width
-            g.y = wa.y + this_y * height
-            if useless_gap > 0
-            then
-                -- Top and left clients are shrinked by two steps and
-                -- get moved away from the border. Other clients just
-                -- get shrinked in one direction.
-                if this_x == 0
-                then
-                    g.width = g.width - 2 * useless_gap
-                    g.x = g.x + useless_gap
-                else
-                    g.width = g.width - useless_gap
-                end
 
 
-                if this_y == 0
-                then
-                    g.height = g.height - 2 * useless_gap
-                    g.y = g.y + useless_gap
-                else
-                    g.height = g.height - useless_gap
-                end
+            g.x = wa.x + this_x*width
+            g.y = wa.y + this_y*height
+
+            if useless_gap > 0 then
+                -- All clients tile evenly.
+                g.x = g.x + (this_x + 1)*useless_gap
+                g.y = g.y + (this_y + 1)*useless_gap
             end
             end
+
+            if g.width < 1 then g.width = 1 end
+            if g.height < 1 then g.height = 1 end
+
             c:geometry(g)
             c:geometry(g)
+
             remaining_clients = remaining_clients - 1
 
             -- Next grid position.
             at_x = at_x + 1
             remaining_clients = remaining_clients - 1
 
             -- Next grid position.
             at_x = at_x + 1
-            if at_x == num_x
-            then
+            if at_x == num_x then
                 -- Row full, create a new one above it.
                 at_x = 0
                 at_y = at_y + 1
 
                 -- We start a new row. Left-align.
                 -- Row full, create a new one above it.
                 at_x = 0
                 at_y = at_y + 1
 
                 -- We start a new row. Left-align.
-                if remaining_clients < num_x
-                then
+                if remaining_clients < num_x then
                     cur_num_x = remaining_clients
                 end
             end
         end
                     cur_num_x = remaining_clients
                 end
             end
         end
+    elseif orientation == "center" then
+        -- Layout with fixed number of vertical columns (read from nmaster).
+        -- Cols are centerded until there is nmaster columns, then windows
+        -- are stacked in the slave columns, with at most ncol clients per
+        -- column if possible.
+
+        -- with nmaster=3 and ncol=1 you'll have
+        --        (1)                (2)                (3)
+        --   +---+---+---+      +-+---+---+-+      +---+---+---+
+        --   |   |   |   |      | |   |   | |      |   |   |   |
+        --   |   | 1 |   |  ->  | | 1 | 2 | | ->   | 1 | 2 | 3 |  ->
+        --   |   |   |   |      | |   |   | |      |   |   |   |
+        --   +---+---+---+      +-+---+---+-+      +---+---+---+
+
+        --        (4)                (5)
+        --   +---+---+---+      +---+---+---+
+        --   |   |   | 3 |      |   | 2 | 4 |
+        --   + 1 + 2 +---+  ->  + 1 +---+---+
+        --   |   |   | 4 |      |   | 3 | 5 |
+        --   +---+---+---+      +---+---+---+
+
+        -- How many vertical columns? Read from nmaster on the tag.
+        local num_x = tonumber(termfair.center.nmaster) or tag.master_count
+        local ncol  = tonumber(termfair.center.ncol) or tag.column_count
+        local width = math.floor((wa.width - (num_x + 1)*useless_gap) / num_x)
+
+        if num_x <= 2 then num_x = 2 end
+        if ncol  <= 1 then ncol  = 1 end
+
+        if #cls < num_x then
+            -- Less clients than the number of columns, let's center it!
+            local offset_x = wa.x + (wa.width - #cls*width - (#cls - 1)*useless_gap) / 2
+            local g = {}
+            g.y = wa.y + useless_gap
+            for i = 1, #cls do
+                local c = cls[i]
+                g.width = width - 2*c.border_width
+                g.height = wa.height - 2*useless_gap - 2*c.border_width
+                if g.width < 1 then g.width = 1 end
+                if g.height < 1 then g.height = 1 end
+                g.x = offset_x + (i - 1) * (width + useless_gap)
+                c:geometry(g)
+            end
+        else
+            -- More clients than the number of columns, let's arrange it!
+            -- Master client deserves a special treatement
+            local c = cls[1]
+            local g = {}
+            g.width = wa.width - (num_x - 1)*width - (num_x + 1)*useless_gap - 2*c.border_width
+            g.height = wa.height - 2*useless_gap - 2*c.border_width
+            if g.width < 1 then g.width = 1 end
+            if g.height < 1 then g.height = 1 end
+            g.x = wa.x + useless_gap
+            g.y = wa.y + useless_gap
+
+            c:geometry(g)
+
+            -- Treat the other clients
+
+            -- Compute distribution of clients among columns
+            local num_y ={}
+            do
+                local remaining_clients = #cls-1
+                local ncol_min = math.ceil(remaining_clients/(num_x-1))
+                if ncol >= ncol_min then
+                    for i = (num_x-1), 1, -1 do
+                        if (remaining_clients-i+1) < ncol then
+                            num_y[i] = remaining_clients-i + 1
+                        else
+                            num_y[i] = ncol
+                        end
+                        remaining_clients = remaining_clients - num_y[i]
+                    end
+                else
+                    local rem = remaining_clients % (num_x-1)
+                    if rem == 0 then
+                        for i = 1, num_x-1 do
+                            num_y[i] = ncol_min
+                        end
+                    else
+                        for i = 1, num_x-1 do
+                            num_y[i] = ncol_min - 1
+                        end
+                        for i = 0, rem-1 do
+                            num_y[num_x-1-i] = num_y[num_x-1-i] + 1
+                        end
+                    end
+                end
+            end
+
+            -- Compute geometry of the other clients
+            local nclient = 2 -- we start with the 2nd client
+            g.x = g.x + g.width + useless_gap + 2*c.border_width
+
+            for i = 1, (num_x-1) do
+                local height = math.floor((wa.height - (num_y[i] + 1)*useless_gap) / num_y[i])
+                g.y = wa.y + useless_gap
+                for j = 0, (num_y[i]-2) do
+                    local c = cls[nclient]
+                    g.height = height - 2*c.border_width
+                    g.width = width - 2*c.border_width
+                    if g.width < 1 then g.width = 1 end
+                    if g.height < 1 then g.height = 1 end
+                    c:geometry(g)
+                    nclient = nclient + 1
+                    g.y = g.y + height + useless_gap
+                end
+                local c = cls[nclient]
+                g.height = wa.height - (num_y[i] + 1)*useless_gap - (num_y[i] - 1)*height - 2*c.border_width
+                g.width = width - 2*c.border_width
+                if g.width < 1 then g.width = 1 end
+                if g.height < 1 then g.height = 1 end
+                c:geometry(g)
+                nclient = nclient + 1
+                g.x = g.x + width + useless_gap
+            end
+        end
     end
 end
 
     end
 end
 
+function termfair.center.arrange(p)
+    return do_fair(p, "center")
+end
+
+function termfair.arrange(p)
+    return do_fair(p, "west")
+end
+
 return termfair
 return termfair