X-Git-Url: https://git.madduck.net/etc/awesome.git/blobdiff_plain/308b7b12020a59b5d0269772028c25a826ac10c0..ae4b9b272802c0690b711644508d63a538a3e1cd:/layout/termfair.lua

diff --git a/layout/termfair.lua b/layout/termfair.lua
index 6bb3e40..33b7ffc 100644
--- a/layout/termfair.lua
+++ b/layout/termfair.lua
@@ -4,134 +4,237 @@
      Licensed under GNU General Public License v2 
       * (c) 2014,      projektile                 
       * (c) 2013,      Luke Bonham                
+      * (c) 2010,      Nicolas Estibals           
       * (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 math     = { ceil  = math.ceil,
+                   floor = math.floor,
+                   max   = math.max }
+local screen   = screen
+local tonumber = tonumber
 
 local termfair  = { name = "termfair" }
+termfair.center = { name = "centerfair" }
 
-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) or 0
-    if useless_gap < 0 then useless_gap = 0 end
-
-    -- A global border can be defined with
-    -- beautiful.global_border_width
-    local global_border = tonumber(beautiful.global_border_width) or 0
-    if global_border < 0 then global_border = 0 end
-
-    -- Screen.
+local function do_fair(p, orientation)
+    local t = p.tag or screen[p.screen].selected_tag
     local wa = p.workarea
     local cls = p.clients
 
-    -- Borders are factored in.
-    wa.height = wa.height - (global_border * 2)
-    wa.width = wa.width - (global_border * 2)
-    wa.x = wa.x + global_border
-    wa.y = wa.y + global_border
-
-    -- How many vertical columns?
-    local t = tag.selected(p.screen)
-    local num_x = termfair.nmaster or tag.getnmaster(t)
-
-    -- Do at least "desired_y" rows.
-    local desired_y = termfair.ncol or tag.getncol(t)
-
-    if #cls > 0
-    then
-        local num_y = math.max(math.ceil(#cls / num_x), desired_y)
+    if #cls == 0 then return end
+
+    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 |
+        --   +---+---+---+      +---+---+---+      +---+---+---+
+
+        -- How many vertical columns? Read from nmaster on the tag.
+        local num_x = tonumber(termfair.nmaster) or t.master_count
+        local ncol  = tonumber(termfair.ncol) or t.column_count
+
+        if num_x <= 2 then num_x = 2 end
+        if ncol  <= 1 then ncol  = 1 end
+        local width = math.floor(wa.width/num_x)
+
+        local num_y     = math.max(math.ceil(#cls / num_x), ncol)
+        local height    = math.floor(wa.height/num_y)
         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 width = math.floor((wa.width - (num_x + 1)*useless_gap) / num_x)
-        local height = math.floor((wa.height - (num_y + 1)*useless_gap) / num_y)
 
         -- 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.
-        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
 
-            -- Calc geometry.
+            -- Calculate geometry.
             local g = {}
-            if this_x == (num_x - 1)
-            then
-                g.width = wa.width - (num_x - 1)*width - (num_x + 1)*useless_gap - 2*c.border_width
+            if this_x == (num_x - 1) then
+                g.width = wa.width - (num_x - 1)*width
             else
-                g.width = width - 2*c.border_width
+                g.width = width
             end
-            if this_y == (num_y - 1)
-            then
-                g.height = wa.height - (num_y - 1)*height - (num_y + 1)*useless_gap - 2*c.border_width
+
+            if this_y == (num_y - 1) then
+                g.height = wa.height - (num_y - 1)*height
             else
-                g.height = height - 2*c.border_width
+                g.height = height
             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
+            if g.width  < 1 then g.width  = 1 end
+            if g.height < 1 then g.height = 1 end
+
+            p.geometries[c] = g
 
-            end
-            c:geometry(g)
             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.
-                if remaining_clients < num_x
-                then
+                if remaining_clients < num_x then
                     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 t.master_count
+        local ncol  = tonumber(termfair.center.ncol) or t.column_count
+
+        if num_x <= 2 then num_x = 2 end
+        if ncol  <= 1 then ncol  = 1 end
+
+        local width = math.floor(wa.width / num_x)
+
+        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) / 2
+            for i = 1, #cls do
+                local g = { y = wa.y }
+                g.width  = width
+                g.height = wa.height
+                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
+                p.geometries[cls[i]] = g
+            end
+        else
+            -- More clients than the number of columns, let's arrange it!
+            -- Master client deserves a special treatement
+            local g = {}
+            g.width = wa.width - (num_x - 1)*width
+            g.height = wa.height
+            if g.width < 1 then g.width = 1 end
+            if g.height < 1 then g.height = 1 end
+            g.x = wa.x
+            g.y = wa.y
+            p.geometries[cls[1]] = g
+
+            -- Treat the other clients
+
+            -- Compute distribution of clients among columns
+            local num_y = {}
+            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
+
+            -- Compute geometry of the other clients
+            local nclient = 2 -- we start with the 2nd client
+            local wx = g.x + g.width
+            for i = 1, (num_x-1) do
+                local height = math.floor(wa.height / num_y[i])
+                local wy = wa.y
+                for j = 0, (num_y[i]-2) do
+                    local g = {}
+                    g.x = wx
+                    g.y = wy
+                    g.height = height
+                    g.width = width
+                    if g.width < 1 then g.width = 1 end
+                    if g.height < 1 then g.height = 1 end
+                    p.geometries[cls[nclient]] = g
+                    nclient = nclient + 1
+                    wy = wy + height
+                end
+                local g = {}
+                g.x = wx
+                g.y = wy
+                g.height = wa.height - (num_y[i] - 1)*height
+                g.width = width
+                if g.width < 1 then g.width = 1 end
+                if g.height < 1 then g.height = 1 end
+                p.geometries[cls[nclient]] = g
+                nclient = nclient + 1
+                wx = wx + width
+            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