Hi all,

after an agreement with Gregor, I've pretty much rewrote his layout
functions based on his last RFC (see '[RFC] vertical.topdown and a few
code changes' thread).

What this basically brings are 2D layouts and a few API changes. It
turned out to not be so easy and there are some quirks I'll try to
cover here.

Included is Gregor's RFC patch, on which it is based, although not much
is left of it :)

I've attached a sample testing file which you can simply do to see what
it can do :)

There are basically two functions that do all the work, one for all
fixed layouts (everything but flex) and one for flex. That means one
function handles both horizontal and vertical, this ensures things can
only break on one place :). I'm not very happy with how its done
though. Basically there are two auxiliary functions, one that returns a
table's/widget's attribute by its name, and one that returns the
appropriate attribute from the other dimension (ie. for width it
returns height, for x returns y, etc.). By passing one of these two
functions to the layout function you define whether it will calculate
horizontal or vertical. The code is not very beautiful, but practical.
If anyone has any idea how to improve it, bring it on :) (the only way
is probably using __index in the metatable, but I can't set it to a
widget).

From now on, when I talk about width/height/x/y, I'm talking about
horizontal layout. The same thing applies inversely to the vertical
layout too. Don't think about it too hard, it can twist your brain by
90 degrees (several times :D).

I also introduced two new attributes to the tables that contain a
widget set and a layout function, width and height. These variables are
used to set the bounds for the widgets in the table. This helps to lay
out the widgets in 2D properly. Another thing it does (and thats the
reason I introduced them) is that if you set a height of a horizontal
layout, it will resize all its widgets' height to this value. This is
the only way you can set height of widgets in a flex layout. Before,
horizontal flex layout took all vertical space. But if you would put it
inside a vertical.topdown, there would be no way to put anything under
it cos it would leave no space. See the default rc, it is used there
(try commenting it out). Lastly, flex layout sets width to all its
subtables before laying them out, so if you put vertical.topdown inside
horizontal.flex, all its widgets will be horizontally flexed too :)
neat! (see attached test file, bottommost wibox for demonstation).

Some things to note:
- If you nest rightleft into a leftright, it will align it properly to
the right. If you nest leftright into a rightleft, it will put it on
the left end of the right-aligned block (which is good)

- It doesn't matter in which order you put leftright layouted tables,
rightleft layouted tables and widgets (except for the order of course,
but the right/left alignment doesn't change)

- it matters where you put the center layout. the point where it will
be placed is the center of the current free space. If you put it in the
beginning, it will be the center of the whole area. If you put it at
the end, it will be the center of the free space between all widgets
placed before it. Also, center layout covers no space. It means that
any widgets you put in a table after it can end up overlapping it.

- Flex layouts always need to be placed at the end, because they take
up all the space. Nothing you put after them will be displayed.


I didn't update the default layout function. IMHO it is not useful for
anything (ie. if I fix it, it will still be broken :). I've talked with
Gregor about it and he agrees. He wanted to default to the parent's
layout, but the reason for it is fixed now. I suggest using leftright
as default. It is most common, lays widgets properly unlike current
default and can save a few lines in people's configs. Also there would
be less code to maintain. Would it be ok to put the code to single file
awful/widget/layout.lua instead of the layout folder with init.lua and
default.lua inside?

Also, let me know how I can document the layout functions themselves.
Should I document the arguments? the user is only supposed to put them
in a table, not care about the arguments or anything.

Any comments, suggestions and improvements are welcome. Test file
included, do go on and play with it a bit :D

lukash
>From 099ec5b4342b0d1f1ac3f7088beb821661160934 Mon Sep 17 00:00:00 2001
From: Gregor Best <g...@intepi.net>
Date: Tue, 8 Sep 2009 22:49:18 +0200
Subject: [PATCH 1/2] vertical.topdown and a few code changes

This commit merges the code common to horizontal.{leftright|rightleft}
and vertical.{topdown|bottomup} and adds calls to
horizontal.{leftright|rightleft} and vertical.topdown. vertical.bottomup
and vertical.flex are missing at the moment because I did not yet have
the time to merge the flex layouts and the topdown layout needs more
testing and a few fixes.

Signed-off-by: Gregor Best <g...@intepi.net>
---
 lib/awful/widget/layout/horizontal.lua.in |  188 ---------------------
 lib/awful/widget/layout/init.lua.in       |  252 ++++++++++++++++++++++++++++-
 lib/awful/widget/layout/vertical.lua.in   |  101 ------------
 3 files changed, 249 insertions(+), 292 deletions(-)
 delete mode 100644 lib/awful/widget/layout/horizontal.lua.in
 delete mode 100644 lib/awful/widget/layout/vertical.lua.in

diff --git a/lib/awful/widget/layout/horizontal.lua.in b/lib/awful/widget/layout/horizontal.lua.in
deleted file mode 100644
index 0914fab..0000000
--- a/lib/awful/widget/layout/horizontal.lua.in
+++ /dev/null
@@ -1,188 +0,0 @@
--------------------------------------------------
--- @author Gregor Best <farha...@googlemail.com>
--- @copyright 2009 Gregor Best
--- @release @AWESOME_VERSION@
--------------------------------------------------
-
--- Grab environment
-local ipairs = ipairs
-local type = type
-local table = table
-local math = math
-local util = require("awful.util")
-local default = require("awful.widget.layout.default")
-local margins = awful.widget.layout.margins
-
---- Horizontal widget layout
-module("awful.widget.layout.horizontal")
-
-local function horizontal(direction, bounds, widgets, screen)
-    local geometries = { }
-    local x = 0
-
-    -- we are only interested in tables and widgets
-    local keys = util.table.keys_filter(widgets, "table", "widget")
-
-    for _, k in ipairs(keys) do
-        local v = widgets[k]
-        if type(v) == "table" then
-            local layout = v.layout or default
-            if margins[v] then
-                bounds.width = bounds.width - (margins[v].left or 0) - (margins[v].right or 0)
-                bounds.height = bounds.height - (margins[v].top or 0) - (margins[v].bottom or 0)
-            end
-            local g = layout(bounds, v, screen)
-            if margins[v] then
-                x = x + (margins[v].left or 0)
-            end
-            for _, v in ipairs(g) do
-                v.x = v.x + x
-                v.y = v.y + (margins[v] and (margins[v].top and margins[v].top or 0) or 0)
-                table.insert(geometries, v)
-            end
-            bounds = g.free
-            if margins[v] then
-                x = x + g.free.x + (margins[v].right or 0)
-                bounds.width = bounds.width - (margins[v].right or 0) - (margins[v].left or 0)
-            else
-                x = x + g.free.x
-            end
-        elseif type(v) == "widget" then
-            local g
-            if v.visible then
-                g = v:extents(screen)
-                if margins[v] then
-                    g.width = g.width + (margins[v].left or 0) + (margins[v].right or 0)
-                    g.height = g.height + (margins[v].top or 0) + (margins[v].bottom or 0)
-                end
-            else
-                g = {
-                    width  = 0,
-                    height = 0,
-                }
-            end
-
-            if v.resize and g.width > 0 and g.height > 0 then
-                local ratio = g.width / g.height
-                g.width = math.floor(bounds.height * ratio)
-                g.height = bounds.height
-            end
-
-            if g.width > bounds.width then
-                g.width = bounds.width
-            end
-            g.height = bounds.height
-
-            if margins[v] then
-                g.y = (margins[v].top or 0)
-            else
-                g.y = 0
-            end
-
-            if direction == "leftright" then
-                if margins[v] then
-                    g.x = x + (margins[v].left or 0)
-                else
-                    g.x = x
-                end
-                x = x + g.width
-            else
-                if margins[v] then
-                    g.x = x + bounds.width - g.width + (margins[v].left or 0)
-                else
-                    g.x = x + bounds.width - g.width
-                end
-            end
-            bounds.width = bounds.width - g.width
-
-            table.insert(geometries, g)
-        end
-    end
-
-    geometries.free = util.table.clone(bounds)
-    geometries.free.x = x
-    geometries.free.y = 0
-
-    return geometries
-end
-
-function flex(bounds, widgets, screen)
-    local geometries = {
-        free = util.table.clone(bounds)
-    }
-    -- the flex layout always uses the complete available place, thus we return
-    -- no usable free area
-    geometries.free.width = 0
-
-    -- we are only interested in tables and widgets
-    local keys = util.table.keys_filter(widgets, "table", "widget")
-    local nelements = 0
-
-    for _, k in ipairs(keys) do
-        local v = widgets[k]
-        if type(v) == "table" then
-            nelements = nelements + 1
-        elseif type(v) == "widget" then
-            local g = v:extents()
-            if v.resize and g.width > 0 and g.height > 0 then
-                bounds.width = bounds.width - bounds.height
-            elseif g.width > 0 and g.height > 0 then
-                nelements = nelements + 1
-            end
-        end
-    end
-
-    nelements = (nelements == 0) and 1 or nelements
-
-    local x = 0
-    local width = bounds.width / nelements
-
-    for _, k in ipairs(util.table.keys(widgets)) do
-        local v = widgets[k]
-        if type(v) == "table" then
-            local layout = v.layout or default
-            local g = layout(bounds, v, screen)
-            for _, v in ipairs(g) do
-                v.x = v.x + x
-                table.insert(geometries, v)
-            end
-            bounds = g.free
-        elseif type(v) == "widget" then
-            local g = v:extents(screen)
-            g.resize = v.resize
-
-            if v.resize and g.width > 0 and g.height > 0 then
-                g.width = bounds.height
-                g.height = bounds.height
-                g.x = x
-                g.y = bounds.y
-                x = x + g.width
-            elseif g.width > 0 and g.height > 0 then
-                g.x = x
-                g.y = bounds.y
-                g.width = math.floor(width + 0.5)
-                g.height = bounds.height
-                x = x + width
-            else
-                g.x = 0
-                g.y = 0
-                g.width = 0
-                g.height = 0
-            end
-
-            table.insert(geometries, g)
-        end
-    end
-
-    return geometries
-end
-
-function leftright(...)
-    return horizontal("leftright", ...)
-end
-
-function rightleft(...)
-    return horizontal("rightleft", ...)
-end
-
--- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=80
diff --git a/lib/awful/widget/layout/init.lua.in b/lib/awful/widget/layout/init.lua.in
index f4535ee..3e38fef 100644
--- a/lib/awful/widget/layout/init.lua.in
+++ b/lib/awful/widget/layout/init.lua.in
@@ -1,5 +1,11 @@
 local setmetatable = setmetatable
 local require = require
+local ipairs = ipairs
+local type = type
+local table = table
+local math = math
+local util = require("awful.util")
+local default = require("awful.widget.layout.default")
 
 -- Widget layouts
 module("awful.widget.layout")
@@ -16,8 +22,248 @@ module("awful.widget.layout")
 -- @class table
 margins = setmetatable({}, { __mode = 'k' })
 
-require("awful.widget.layout.horizontal")
-require("awful.widget.layout.vertical")
-require("awful.widget.layout.default")
+horizontal = { }
+vertical   = { }
 
+local function linear(direction, bounds, widgets, screen)
+    local geometries = { }
+    if direction == "topdown" or direction == "bottomup" then
+        geometries.free = util.table.clone(bounds)
+    end
+    local x = 0
+    local y = 0
+    local maxw = 0
+
+    -- we are only interested in tables and widgets
+    local keys = util.table.keys_filter(widgets, "table", "widget")
+
+    for _, k in ipairs(keys) do
+        local v = widgets[k]
+        if type(v) == "table" then
+            local layout = v.layout or default
+            if margins[v] then
+                bounds.width = bounds.width - (margins[v].left or 0) - (margins[v].right or 0)
+                bounds.height = bounds.height - (margins[v].top or 0) - (margins[v].bottom or 0)
+            end
+            local g = layout(bounds, v, screen)
+            if margins[v] then
+                if direction == "leftright" or direction == "rightleft" then
+                    x = x + (margins[v].left or 0)
+                else
+                    y = y + (margins[v].top or 0)
+                end
+            end
+            for _, v in ipairs(g) do
+                if direction == "leftright" or direction == "rightleft" then
+                    v.x = v.x + x
+                    v.y = v.y + (margins[v] and (margins[v].top and margins[v].top or 0) or 0)
+                else
+                    v.x = v.x + (margins[v] and (margins[v].left and margins[v].left or 0) or 0)
+                    v.y = v.y + y
+                end
+                maxw = math.max(maxw, v.x + v.width)
+                table.insert(geometries, v)
+            end
+            bounds = g.free
+            if margins[v] then
+                if direction == "leftright" or direction == "rightleft" then
+                    x = x + g.free.x + (margins[v].right or 0)
+                    bounds.width = bounds.width - (margins[v].right or 0) - (margins[v].left or 0)
+                else
+                    y = y + g.free.y + (margins[v].bottom or 0)
+                    bounds.height = bounds.height - (margins[v].top or 0) - (margins[v].bottom or 0)
+                end
+            else
+                if direction == "leftright" or direction == "rightleft" then
+                    x = x + g.free.x
+                else
+                    y = y + g.free.y
+                end
+            end
+        elseif type(v) == "widget" then
+            local g
+            if v.visible then
+                g = v:extents(screen)
+                if margins[v] then
+                    g.width = g.width + (margins[v].left or 0) + (margins[v].right or 0)
+                    g.height = g.height + (margins[v].top or 0) + (margins[v].bottom or 0)
+                end
+            else
+                g = {
+                    width  = 0,
+                    height = 0,
+                }
+            end
+
+            if v.resize and g.width > 0 and g.height > 0 then
+                if direction == "leftright" or direction == "rightleft" then
+                    local ratio = g.width / g.height
+                    g.width = math.floor(bounds.height * ratio)
+                    g.height = bounds.height
+                else
+                    local ratio = g.height / g.width
+                    g.height = math.floor(bounds.width * ratio)
+                    g.width = bounds.width
+                end
+            end
+
+            if direction == "leftright" or direction == "rightleft" then
+                g.width = math.min(g.width, bounds.width)
+                -- g.height = bounds.height
+            else
+                g.height = math.min(g.height, bounds.height)
+            end
+
+            if direction == "leftright" or direction == "rightleft" then
+                if margins[v] then
+                    g.y = (margins[v].top or 0)
+                else
+                    g.y = 0
+                end
+            else
+                if margins[v] then
+                    g.x = (margins[v].left or 0)
+                else
+                    g.x = 0
+                end
+            end
+
+            if direction == "leftright" then
+                if margins[v] then
+                    g.x = x + (margins[v].left or 0)
+                else
+                    g.x = x
+                end
+                x = x + g.width
+            elseif direction == "rightleft" then
+                if margins[v] then
+                    g.x = x + bounds.width - g.width + (margins[v].left or 0)
+                else
+                    g.x = x + bounds.width - g.width
+                end
+            elseif direction == "topdown" then
+                if margins[v] then
+                    g.y = y + (margins[v].top or 0)
+                else
+                    g.y = y
+                end
+                y = y + g.height
+            end
+
+            if direction == "leftright" or direction == "rightleft" then
+                bounds.width = bounds.width - g.width
+            else
+                bounds.height = bounds.height - g.height
+            end
+
+            if direction == "topdown" or direction == "bottomup" then
+                maxw = math.max(maxw, g.x + g.width)
+            end
+
+            table.insert(geometries, g)
+        end
+    end
+
+    if direction == "leftright" or direction == "rightleft" then
+        geometries.free = util.table.clone(bounds)
+        geometries.free.x = x
+    else
+        geometries.free.x = maxw
+        geometries.free.width = geometries.free.width - maxw
+    end
+    geometries.free.y = y
+
+    return geometries
+end
+
+function horizontal.leftright(...)
+    return linear("leftright", ...)
+end
+
+function horizontal.rightleft(...)
+    return linear("rightleft", ...)
+end
+
+function vertical.topdown(...)
+    return linear("topdown", ...)
+end
+
+function vertical.center(...)
+    local g = vertical.topdown(...)
+    for k, v in ipairs(g) do
+        v.y = v.y + (g.free.height / (#g + 1)) - (v.height / (#g + 1))
+    end
+    return g
+end
+
+function horizontal.flex(bounds, widgets, screen)
+    local geometries = {
+        free = util.table.clone(bounds)
+    }
+    -- the flex layout always uses the complete available place, thus we return
+    -- no usable free area
+    geometries.free.width = 0
+
+    -- we are only interested in tables and widgets
+    local keys = util.table.keys_filter(widgets, "table", "widget")
+    local nelements = 0
+
+    for _, k in ipairs(keys) do
+        local v = widgets[k]
+        if type(v) == "table" then
+            nelements = nelements + 1
+        elseif type(v) == "widget" then
+            local g = v:extents()
+            if v.resize and g.width > 0 and g.height > 0 then
+                bounds.width = bounds.width - bounds.height
+            elseif g.width > 0 and g.height > 0 then
+                nelements = nelements + 1
+            end
+        end
+    end
+
+    nelements = (nelements == 0) and 1 or nelements
+
+    local x = 0
+    local width = bounds.width / nelements
+
+    for _, k in ipairs(util.table.keys(widgets)) do
+        local v = widgets[k]
+        if type(v) == "table" then
+            local layout = v.layout or default
+            local g = layout(bounds, v, screen)
+            for _, v in ipairs(g) do
+                v.x = v.x + x
+                table.insert(geometries, v)
+            end
+            bounds = g.free
+        elseif type(v) == "widget" then
+            local g = v:extents(screen)
+            g.resize = v.resize
+
+            if v.resize and g.width > 0 and g.height > 0 then
+                g.width = bounds.height
+                g.height = bounds.height
+                g.x = x
+                g.y = bounds.y
+                x = x + g.width
+            elseif g.width > 0 and g.height > 0 then
+                g.x = x
+                g.y = bounds.y
+                g.width = math.floor(width + 0.5)
+                g.height = bounds.height
+                x = x + width
+            else
+                g.x = 0
+                g.y = 0
+                g.width = 0
+                g.height = 0
+            end
+
+            table.insert(geometries, g)
+        end
+    end
+
+    return geometries
+end
 -- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=80
diff --git a/lib/awful/widget/layout/vertical.lua.in b/lib/awful/widget/layout/vertical.lua.in
deleted file mode 100644
index 5a17684..0000000
--- a/lib/awful/widget/layout/vertical.lua.in
+++ /dev/null
@@ -1,101 +0,0 @@
--------------------------------------------------
--- @author Gregor Best <farha...@googlemail.com>
--- @copyright 2009 Gregor Best
--- @release @AWESOME_VERSION@
--------------------------------------------------
-
--- Grab environment
-local ipairs = ipairs
-local type = type
-local table = table
-local math = math
-local util = require("awful.util")
-local default = require("awful.widget.layout.default")
-
---- Vertical widget layout
-module("awful.widget.layout.vertical")
-
-function flex(bounds, widgets, screen)
-    local geometries = {
-        free = util.table.clone(bounds)
-    }
-
-    local y = 0
-
-    -- we are only interested in tables and widgets
-    local keys = util.table.keys_filter(widgets, "table", "widget")
-    local nelements = 0
-    for _, k in ipairs(keys) do
-        local v = widgets[k]
-        if type(v) == "table" then
-            nelements = nelements + 1
-        else
-            local e = v:extents()
-            if v.visible and e.width > 0 and e.height > 0 then
-                nelements = nelements + 1
-            end
-        end
-    end
-    if nelements == 0 then return geometries end
-    local height = math.floor(bounds.height / nelements)
-
-    for _, k in ipairs(keys) do
-        local v = widgets[k]
-        if type(v) == "table" then
-            local layout = v.layout or default
-            -- we need to modify the height a bit because vertical layouts always span the
-            -- whole height
-            nbounds = util.table.clone(bounds)
-            nbounds.height = height
-            local g = layout(nbounds, v, screen)
-            for _, w in ipairs(g) do
-                w.y = w.y + y
-                table.insert(geometries, w)
-            end
-            y = y + height
-        elseif type(v) == "widget" then
-            local g
-            if v.visible then
-                g = v:extents(screen)
-            else
-                g = {
-                    ["width"] = 0,
-                    ["height"] = 0
-                }
-            end
-
-            g.ratio = 1
-            if g.height > 0 and g.width > 0 then
-                g.ratio = g.width / g.height
-            end
-            g.height = height
-            if v.resize then
-                g.width = g.height * g.ratio
-            end
-            g.width = math.min(g.width, bounds.width)
-            geometries.free.x = math.max(geometries.free.x, g.width)
-
-            g.x = 0
-            g.y = y
-            y = y + g.height
-            bounds.height = bounds.height - g.height
-
-            table.insert(geometries, g)
-        end
-    end
-
-    local maxw = 0
-    local maxx = 0
-    for _, v in ipairs(geometries) do
-        if v.width > maxw then maxw = v.width end
-        if v.x > maxx then maxx = v.x end
-    end
-
-    geometries.free.width = geometries.free.width - maxw
-    geometries.free.x = geometries.free.x + maxw
-
-    geometries.free.height = nelements * height
-    geometries.free.y = 0
-
-    return geometries
-end
-- 
1.6.4

>From a714c3f269c5ba8c1c48b1b8f4138953327914c6 Mon Sep 17 00:00:00 2001
From: Lukas Hrazky <lukk...@email.cz>
Date: Fri, 25 Sep 2009 20:33:37 +0200
Subject: [PATCH 2/2] rewrite of horizontal and vertical widget layouts

Signed-off-by: Lukas Hrazky <lukk...@email.cz>
---
 awesomerc.lua.in                    |   17 +-
 lib/awful/widget/layout/init.lua.in |  535 ++++++++++++++++++++++-------------
 2 files changed, 347 insertions(+), 205 deletions(-)

diff --git a/awesomerc.lua.in b/awesomerc.lua.in
index 0ab8f9d..39dbbc3 100644
--- a/awesomerc.lua.in
+++ b/awesomerc.lua.in
@@ -134,17 +134,18 @@ for s = 1, screen.count() do
     mywibox[s] = awful.wibox({ position = "top", screen = s })
     -- Add widgets to the wibox - order matters
     mywibox[s].widgets = {
+        mylauncher,
+        mytaglist[s],
+        mypromptbox[s],
         {
-            mylauncher,
-            mytaglist[s],
-            mypromptbox[s],
-            layout = awful.widget.layout.horizontal.leftright
+            s == 1 and mysystray or nil,
+            mytextclock,
+            mylayoutbox[s],
+            layout = awful.widget.layout.horizontal.rightleft
         },
-        mylayoutbox[s],
-        mytextclock,
-        s == 1 and mysystray or nil,
         mytasklist[s],
-        layout = awful.widget.layout.horizontal.rightleft
+        layout = awful.widget.layout.horizontal.leftright,
+        height = mywibox[s].height
     }
 end
 -- }}}
diff --git a/lib/awful/widget/layout/init.lua.in b/lib/awful/widget/layout/init.lua.in
index 3e38fef..1f45611 100644
--- a/lib/awful/widget/layout/init.lua.in
+++ b/lib/awful/widget/layout/init.lua.in
@@ -1,11 +1,19 @@
+-------------------------------------------------
+-- @author Gregor Best <farha...@googlemail.com>, Lukas Hrazky <lukk...@email.cz>
+-- @copyright 2009 Gregor Best, Lukas Hrazky
+-- @release @AWESOME_VERSION@
+-------------------------------------------------
+
 local setmetatable = setmetatable
 local require = require
 local ipairs = ipairs
+local pairs = pairs
 local type = type
 local table = table
 local math = math
 local util = require("awful.util")
 local default = require("awful.widget.layout.default")
+local dbg = require("mydbg")
 
 -- Widget layouts
 module("awful.widget.layout")
@@ -25,245 +33,378 @@ margins = setmetatable({}, { __mode = 'k' })
 horizontal = { }
 vertical   = { }
 
-local function linear(direction, bounds, widgets, screen)
-    local geometries = { }
-    if direction == "topdown" or direction == "bottomup" then
-        geometries.free = util.table.clone(bounds)
+
+-- Returns and eventually sets a property of a table or a widget.
+-- Returns property 'prop' of item 'item'. If 'value' is not nil, sets it to the 'prop'
+-- before returning it. Handles eventual item == nil by returning 0.
+-- Its used in in generic layout functions as an accessor to geometries' and margins'
+-- values. This one is used for horizontal layouts, returning the same property
+-- that's passed to it.
+-- @param item The item to get the property from.
+-- @param prop The porperty returned.
+-- @param value Optional value to set to the property.
+-- @returns Property 'prop' of item 'item'.
+local function regular_val(item, prop, value)
+    if type(item) ~= "table" and type(item) ~= "widget" then
+        return 0
+    end
+
+    -- result in case the property is not there. for margins, we want to return 0,
+    -- but for others, we want to return nil
+    local res
+    if (prop == "top") or (prop == "bottom") or (prop == "left") or (prop == "right") then
+        res = 0
+    end
+
+    item[prop] = value or item[prop]
+    return item[prop] or res
+end
+
+
+-- Returns and eventually sets a property of a table or a widget.
+-- Returns the opposite property to property 'prop' of item 'item' (ie. 'x' to 'y',
+-- 'height' to 'width', etc...) If 'value' is not nil, sets it to the 'prop' before
+-- returning it. Handles eventual item == nil by returning 0.
+-- Its used in in generic layout functions as an accessor to geometries' and margins'
+-- values. This one is used for vertical layouts, returning the opposite property to
+-- the one that's passed to it.
+-- @param item The item to get the property from.
+-- @param prop The porperty returned.
+-- @param value Optional value to set to the property.
+-- @returns Property 'prop' of item 'item'.
+local function switched_val(item, prop, value)
+    if type(item) ~= "table" and type(item) ~= "widget" then
+        return 0
+    end
+
+    local i
+    -- result in case the property is not there. for margins, we want to return 0,
+    -- but for others, we want to return nil
+    local res
+
+    if prop == "x" then
+        i = "y"
+    elseif prop == "y" then
+        i = "x"
+    elseif prop == "width" then
+        i = "height"
+    elseif prop == "height" then
+        i = "width"
+    elseif prop == "top" then
+        i = "left"
+        res = 0
+    elseif prop == "bottom" then
+        i = "right"
+        res = 0
+    elseif prop == "left" then
+        i = "top"
+        res = 0
+    elseif prop == "right" then
+        i = "bottom"
+        res = 0
+    end
+
+    item[i] = value or item[i]
+    return item[i] or res
+end
+
+
+-- Calculates geometries for fixed layouts.
+-- This generic function is used for all layouts exept flex.
+-- It is written for horizontal layouts, but by using special function 'val' to access
+-- all the geometry attributes, it is used for vertical layouts too. In that case, 'val'
+-- returns 'y' for 'x', 'width' for 'height', etc.
+-- @param val A function that defines whether horzintal or vertical arrangement will be
+-- calculated. See regular_val and switched_val funcitons.
+-- @param bounds The geometry of the bounds for the layout.
+-- @param widgets The table of the widgets to layout, can be nested.
+-- @param screen The screen of the wibox.
+-- @return A table of geometries of all the widgets.
+local function fixed(val, bounds, widgets, screen)
+    -- the table for the geometries which will be returned
+    -- we clone the bounds to the 'total' attribute. bounds are used to keep the free space
+    -- throughout this function. at the end, 'total' is modified to represent the space taken
+    -- by all widgets
+    local geometries = {total = util.table.clone(bounds)}
+    -- the height of the heighest widget, will be the height of the total space taken
+    local maxh = 0
+
+    -- set bounds width and height to what is preset in the widgets table (if there is something)
+    -- we don't need to use val() function here since we're treating both directions the same way
+    if widgets.width and widgets.width < bounds.width then
+        bounds.width = widgets.width
+    end
+    if widgets.height and widgets.height < bounds.height then
+        bounds.height = widgets.height
     end
-    local x = 0
-    local y = 0
-    local maxw = 0
 
-    -- we are only interested in tables and widgets
-    local keys = util.table.keys_filter(widgets, "table", "widget")
+    for _, v in pairs(widgets) do
+        if type(v) == "table" or type(v) == "widget" then
+            -- we can shrink the bounds by the horizontal margins right now, they affect our free
+            -- space directly (vertical don't, they are different for every item in 'widgets')
+            val(bounds, "width", val(bounds, "width") - val(margins[v], "left") - val(margins[v], "right"))
+            val(bounds, "x", val(bounds, "x") + val(margins[v], "left"))
+        end
 
-    for _, k in ipairs(keys) do
-        local v = widgets[k]
         if type(v) == "table" then
+            -- create new bounds for the table and shrink it by the vertical margins
+            local t_bounds = util.table.clone(bounds)
+            val(t_bounds, "height", val(t_bounds, "height") - val(margins[v], "top") - val(margins[v], "bottom"))
+            val(t_bounds, "y", val(t_bounds, "y") + val(margins[v], "top"))
+
+            -- if the 'widgets' table has height set and the table itself doesn't, we set it
+            local w_height = val(widgets, "height")
+            val(v, "height", val(v, "height") or w_height)
+
+            -- call the layout function recursively on this table
             local layout = v.layout or default
-            if margins[v] then
-                bounds.width = bounds.width - (margins[v].left or 0) - (margins[v].right or 0)
-                bounds.height = bounds.height - (margins[v].top or 0) - (margins[v].bottom or 0)
-            end
-            local g = layout(bounds, v, screen)
-            if margins[v] then
-                if direction == "leftright" or direction == "rightleft" then
-                    x = x + (margins[v].left or 0)
-                else
-                    y = y + (margins[v].top or 0)
-                end
-            end
-            for _, v in ipairs(g) do
-                if direction == "leftright" or direction == "rightleft" then
-                    v.x = v.x + x
-                    v.y = v.y + (margins[v] and (margins[v].top and margins[v].top or 0) or 0)
-                else
-                    v.x = v.x + (margins[v] and (margins[v].left and margins[v].left or 0) or 0)
-                    v.y = v.y + y
-                end
-                maxw = math.max(maxw, v.x + v.width)
-                table.insert(geometries, v)
+            local g = layout(t_bounds, v, screen)
+
+            -- restore the table's original height
+            val(v, "height", w_height)
+
+            -- subtract the space taken by the table from our bounds
+            val(bounds, "width", val(bounds, "width") - val(g.total, "width"))
+            -- we only move the 'x' coord if the taken space is on the left side of our bounds
+            if val(g.total, "x") == val(bounds, "x") then
+                val(bounds, "x", val(bounds, "x") + val(g.total, "width") + val(margins[v], "right"))
             end
-            bounds = g.free
-            if margins[v] then
-                if direction == "leftright" or direction == "rightleft" then
-                    x = x + g.free.x + (margins[v].right or 0)
-                    bounds.width = bounds.width - (margins[v].right or 0) - (margins[v].left or 0)
-                else
-                    y = y + g.free.y + (margins[v].bottom or 0)
-                    bounds.height = bounds.height - (margins[v].top or 0) - (margins[v].bottom or 0)
-                end
-            else
-                if direction == "leftright" or direction == "rightleft" then
-                    x = x + g.free.x
-                else
-                    y = y + g.free.y
-                end
+
+            -- update the maximum height with this new table
+            maxh = math.max(maxh, val(g.total, "height") + val(margins[v], "top") + val(margins[v], "bottom"))
+
+            -- insert all geometries from the table to our geometries
+            for _, w in ipairs(g) do
+                table.insert(geometries, w)
             end
+
         elseif type(v) == "widget" then
-            local g
+            local g = {x = 0, y = 0, width = 0, height = 0}
+
             if v.visible then
+                -- get the geometry of the widget
                 g = v:extents(screen)
-                if margins[v] then
-                    g.width = g.width + (margins[v].left or 0) + (margins[v].right or 0)
-                    g.height = g.height + (margins[v].top or 0) + (margins[v].bottom or 0)
-                end
-            else
-                g = {
-                    width  = 0,
-                    height = 0,
-                }
-            end
 
-            if v.resize and g.width > 0 and g.height > 0 then
-                if direction == "leftright" or direction == "rightleft" then
-                    local ratio = g.width / g.height
-                    g.width = math.floor(bounds.height * ratio)
-                    g.height = bounds.height
-                else
-                    local ratio = g.height / g.width
-                    g.height = math.floor(bounds.width * ratio)
-                    g.width = bounds.width
+                -- resize to fit the height available if requested
+                if v.resize and g.width > 0 and g.height > 0 then
+                    local ratio = val(g, "width") / val(g, "height")
+                    val(g, "width", math.floor(val(bounds, "height") * ratio))
+                    val(g, "height", val(bounds, "height"))
                 end
-            end
 
-            if direction == "leftright" or direction == "rightleft" then
-                g.width = math.min(g.width, bounds.width)
-                -- g.height = bounds.height
-            else
-                g.height = math.min(g.height, bounds.height)
-            end
+                -- set the coords, apply the top margin
+                val(g, "y", val(bounds, "y") + val(margins[v], "top"))
+                val(g, "x", val(bounds, "x"))
 
-            if direction == "leftright" or direction == "rightleft" then
-                if margins[v] then
-                    g.y = (margins[v].top or 0)
-                else
-                    g.y = 0
-                end
-            else
-                if margins[v] then
-                    g.x = (margins[v].left or 0)
-                else
-                    g.x = 0
-                end
-            end
+                -- limit the width of the widget to what's available
+                val(g, "width", math.min(val(g, "width"), val(bounds, "width")))
 
-            if direction == "leftright" then
-                if margins[v] then
-                    g.x = x + (margins[v].left or 0)
-                else
-                    g.x = x
-                end
-                x = x + g.width
-            elseif direction == "rightleft" then
-                if margins[v] then
-                    g.x = x + bounds.width - g.width + (margins[v].left or 0)
-                else
-                    g.x = x + bounds.width - g.width
-                end
-            elseif direction == "topdown" then
-                if margins[v] then
-                    g.y = y + (margins[v].top or 0)
-                else
-                    g.y = y
-                end
-                y = y + g.height
-            end
+                -- if the 'widgets' table has height set, we set it to the widget
+                val(g, "height", val(widgets, "height")
+                    and (val(widgets, "height") - val(margins[v], "top") - val(margins[v], "bottom"))
+                    or val(g, "height"))
 
-            if direction == "leftright" or direction == "rightleft" then
-                bounds.width = bounds.width - g.width
-            else
-                bounds.height = bounds.height - g.height
-            end
+                -- limit the height of the widget to what's available
+                val(g, "height", math.min(val(g, "height"),
+                    val(bounds, "height") - val(margins[v], "top") - val(margins[v], "bottom")))
 
-            if direction == "topdown" or direction == "bottomup" then
-                maxw = math.max(maxw, g.x + g.width)
+                -- subtract the space taken by the widget from our bounds
+                val(bounds, "width", val(bounds, "width") - val(g, "width"))
+                -- move bounds right by the widget's width
+                val(bounds, "x", val(bounds, "x") + val(g, "width") + val(margins[v], "right"))
+
+                -- update the maximum height with height of this widget
+                maxh = math.max(maxh, val(g, "height") + val(margins[v], "top") + val(margins[v], "bottom"))
             end
 
             table.insert(geometries, g)
         end
     end
+    
+    -- calculate the total space taken by the widgets
+    val(geometries.total, "width", val(geometries.total, "width") - val(bounds, "width"))
+    val(geometries.total, "height", maxh)
 
-    if direction == "leftright" or direction == "rightleft" then
-        geometries.free = util.table.clone(bounds)
-        geometries.free.x = x
-    else
-        geometries.free.x = maxw
-        geometries.free.width = geometries.free.width - maxw
+    return geometries
+end
+
+
+-- Calculates geometries for flex layouts.
+-- This generic function is used for all flex layouts.
+-- It is written for horizontal layouts, but by using special function 'val' to access
+-- all the geometry attributes, it is used for vertical layouts too. In that case, 'val'
+-- returns 'y' for 'x', 'width' for 'height', etc.
+-- @param val A function that defines whether horzintal or vertical arrangement will be
+-- calculated. See regular_val and switched_val funcitons.
+-- @param bounds The geometry of the bounds for the layout.
+-- @param widgets The table of the widgets to layout, can be nested.
+-- @param screen The screen of the wibox.
+-- @return A table of geometries of all the widgets.
+function flex(val, bounds, widgets, screen)
+    -- the table for the geometries which will be returned
+    -- we clone the bounds to the 'total' attribute. bounds are used to keep the free space
+    -- throughout this function. at the end, 'total' is modified to represent the space taken
+    -- by all widgets
+    local geometries = {total = util.table.clone(bounds)}
+    -- the height of the heighest widget, will be the height of the total space taken
+    local maxh = 0
+    -- the number of widgets/tables in 'widgets' argument
+    local n = 0
+
+    -- set bounds width and height to what is preset in the widgets table (if there is something)
+    -- we don't need to use val() function here since we're treating both directions the same way
+    if widgets.width and widgets.width < bounds.width then
+        bounds.width = widgets.width
+    end
+    if widgets.height and widgets.height < bounds.height then
+        bounds.height = widgets.height
     end
-    geometries.free.y = y
+
+    -- count the widgets/tables
+    for _, v in pairs(widgets) do
+        if type(v) == "table" or (type(v) == "widget" and v.visible) then
+            n = n + 1
+        end
+    end
+
+    -- if we have nothing to draw, set taken.height to 0 and return
+    if n == 0 then
+        val(geometries.total, "height", 0)
+        return geometries
+    end
+
+    -- calculate the width. these vars keep the floating numbers, while bounds keep the
+    -- rounded ones and are set from these on each iteration to ensure proper rounding
+    local width = (val(widgets, "width") or val(bounds, "width")) / n
+    local x = val(bounds, "x")
+
+    for _, v in pairs(widgets) do
+        -- someone give me freaking continue
+        if type(v) == "widget" and not v.visible then
+            table.insert(geometries, {x = 0, y = 0, width = 0, height = 0})
+        elseif type(v) == "widget" or type(v) == "table" then
+            -- do the floating magic, calculate real_width which will be set to the geometries
+            x = x + width
+            local real_width = math.floor(x - val(bounds, "x"))
+
+            if type(v) == "table" then
+                -- create new bounds for the table and shrink it by the vertical margins
+                local t_bounds = util.table.clone(bounds)
+                val(t_bounds, "width", real_width)
+
+                -- backup the width of the table so we can restore it
+                local t_width = val(v, "width")
+                -- set the table's width so it can flex what's inside it
+                val(v, "width", real_width)
+
+                -- if the 'widgets' table has height set and the table itself doesn't, we set it
+                local w_height = val(widgets, "height")
+                val(v, "height", val(v, "height") or w_height)
+
+                -- call the layout function recursively on this table
+                local layout = v.layout or default
+                local g = layout(t_bounds, v, screen)
+
+                -- restore the table's original width and height
+                val(v, "width", t_width)
+                val(v, "height", w_height)
+
+                -- update the maximum height with this new table
+                maxh = math.max(maxh, val(g.total, "height"))
+
+                for _, v in ipairs(g) do
+                    table.insert(geometries, v)
+                end
+            elseif type(v) == "widget" then
+                g = v:extents(screen)
+
+                -- resize to fit the width available if requested
+                if v.resize and g.width > 0 and g.height > 0 then
+                    local ratio = val(g, "height") / val(g, "width")
+                    val(g, "height", real_width * ratio)
+                end
+
+                -- set the widget geometry
+                val(g, "x", val(bounds, "x"))
+                val(g, "width", real_width)
+                val(g, "y", val(bounds, "y"))
+
+                -- if the 'widgets' table has height set, we set it to the widget
+                val(g, "height", val(widgets, "height") or val(g, "height"))
+
+                -- limit the height of the widget to what's available
+                val(g, "height", math.min(val(g, "height"), val(bounds, "height")))
+
+                -- update the maximum height
+                maxh = math.max(maxh, val(g, "height"))
+
+                table.insert(geometries, g)
+            end
+
+            -- update the bounds (move it to the right by the widget's width)
+            val(bounds, "width", val(bounds, "width") - real_width)
+            val(bounds, "x", math.floor(x))
+        end
+    end
+    
+    -- we have total already from the cloned bounds, just set the height to what we got
+    val(geometries.total, "width", val(geometries.total, "width") - val(bounds, "width"))
+    val(geometries.total, "height", maxh)
 
     return geometries
 end
 
+
 function horizontal.leftright(...)
-    return linear("leftright", ...)
+    return fixed(regular_val, ...)
+end
+
+function horizontal.rightleft(bounds, widgets, screen)
+    local g = fixed(regular_val, util.table.clone(bounds), widgets, screen)
+    for _, w in pairs(g) do
+        w.x = w.x + bounds.width - g.total.width
+    end
+    return g
 end
 
-function horizontal.rightleft(...)
-    return linear("rightleft", ...)
+function horizontal.center(bounds, widgets, screen)
+    local g = fixed(regular_val, util.table.clone(bounds), widgets, screen)
+    for _, w in ipairs(g) do
+        w.x = w.x + (bounds.width - g.total.width) / 2
+    end
+    g.total.x = 0
+    g.total.width = 0
+    return g
 end
 
 function vertical.topdown(...)
-    return linear("topdown", ...)
+    return fixed(switched_val, ...)
 end
 
-function vertical.center(...)
-    local g = vertical.topdown(...)
-    for k, v in ipairs(g) do
-        v.y = v.y + (g.free.height / (#g + 1)) - (v.height / (#g + 1))
+function vertical.bottomup(bounds, widgets, screen)
+    local g = fixed(switched_val, util.table.clone(bounds), widgets, screen)
+    for _, w in pairs(g) do
+        w.y = w.y + bounds.height - g.total.height
     end
     return g
 end
 
-function horizontal.flex(bounds, widgets, screen)
-    local geometries = {
-        free = util.table.clone(bounds)
-    }
-    -- the flex layout always uses the complete available place, thus we return
-    -- no usable free area
-    geometries.free.width = 0
-
-    -- we are only interested in tables and widgets
-    local keys = util.table.keys_filter(widgets, "table", "widget")
-    local nelements = 0
-
-    for _, k in ipairs(keys) do
-        local v = widgets[k]
-        if type(v) == "table" then
-            nelements = nelements + 1
-        elseif type(v) == "widget" then
-            local g = v:extents()
-            if v.resize and g.width > 0 and g.height > 0 then
-                bounds.width = bounds.width - bounds.height
-            elseif g.width > 0 and g.height > 0 then
-                nelements = nelements + 1
-            end
-        end
+function vertical.center(bounds, widgets, screen)
+    local g = fixed(switched_val, util.table.clone(bounds), widgets, screen)
+    for _, w in pairs(g) do
+        w.y = w.y + (bounds.height - g.total.height) / 2
     end
+    g.total.y = 0
+    g.total.height = 0
+    return g
+end
 
-    nelements = (nelements == 0) and 1 or nelements
-
-    local x = 0
-    local width = bounds.width / nelements
-
-    for _, k in ipairs(util.table.keys(widgets)) do
-        local v = widgets[k]
-        if type(v) == "table" then
-            local layout = v.layout or default
-            local g = layout(bounds, v, screen)
-            for _, v in ipairs(g) do
-                v.x = v.x + x
-                table.insert(geometries, v)
-            end
-            bounds = g.free
-        elseif type(v) == "widget" then
-            local g = v:extents(screen)
-            g.resize = v.resize
-
-            if v.resize and g.width > 0 and g.height > 0 then
-                g.width = bounds.height
-                g.height = bounds.height
-                g.x = x
-                g.y = bounds.y
-                x = x + g.width
-            elseif g.width > 0 and g.height > 0 then
-                g.x = x
-                g.y = bounds.y
-                g.width = math.floor(width + 0.5)
-                g.height = bounds.height
-                x = x + width
-            else
-                g.x = 0
-                g.y = 0
-                g.width = 0
-                g.height = 0
-            end
-
-            table.insert(geometries, g)
-        end
-    end
+function horizontal.flex(...)
+    return flex(regular_val, ...)
+end
 
-    return geometries
+function vertical.flex(...)
+    return flex(switched_val, ...)
 end
+
 -- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=80
-- 
1.6.4

w1 = wibox({ position = "floating" })
w1:buttons(awful.util.table.join(awful.button({ }, 1, awful.mouse.wibox.move)))
w1.screen = 1
w1.ontop = true
w1:geometry({ x = 40, y = 20, width = 400, height = 60 })

w2 = wibox({ position = "floating" })
w2:buttons(awful.util.table.join(awful.button({ }, 1, awful.mouse.wibox.move)))
w2.screen = 1
w2.ontop = true
w2:geometry({ x = 40, y = 90, width = 400, height = 60 })

w3 = wibox({ position = "floating" })
w3:buttons(awful.util.table.join(awful.button({ }, 1, awful.mouse.wibox.move)))
w3.screen = 1
w3.ontop = true
w3:geometry({ x = 40, y = 160, width = 400, height = 60 })

w4 = wibox({ position = "floating" })
w4:buttons(awful.util.table.join(awful.button({ }, 1, awful.mouse.wibox.move)))
w4.screen = 1
w4.ontop = true
w4:geometry({ x = 40, y = 230, width = 303, height = 80 })

pb1 = awful.widget.progressbar({ height = 16, layout = awful.widget.layout.horizontal.nleftright })
pb1:set_color("#00FF00")
pb1:set_value(0.25)
pb2 = awful.widget.progressbar({ height = 16 })
pb2:set_color("#FF0000")
pb2:set_value(0.75)

i = widget({ type = "imagebox" })
i.image = image("/usr/share/icons/gargantuan/128x128/apps/firefox.png")

A = widget({ type = "textbox" })
A.text = "A"
A.border_width = 1
A.border_color = "#FF0000"
m1 = { left = 5, right = 10, top = 4, bottom = 2 }
awful.widget.layout.margins[A] = m1

B = widget({ type = "textbox" })
B.text = "BB"
B.border_width = 1
B.border_color = "#00FF00"

C = widget({ type = "textbox" })
C.text = "CCC"
C.border_width = 1
C.border_color = "#0000FF"

D = widget({ type = "textbox" })
D.text = "vvDDDvv"
D.border_width = 1
D.border_color = "#FFFF00"

E = widget({ type = "textbox" })
E.text = "~EEE~"
E.border_width = 1
E.border_color = "#00FFFF"

F = widget({ type = "textbox" })
F.text = "F"
F.border_width = 1
F.border_color = "#FF00FF"


---[[
w1.widgets = {
    {
        A,
        A,
        ["layout"] = awful.widget.layout.vertical.topdown
    },
    {
        {
            pb1,
            B,
            ["layout"] = awful.widget.layout.horizontal.leftright
        },
        pb2,
        C,
        ["layout"] = awful.widget.layout.vertical.topdown
    },
    D,
    {
        {
            E,
            E,
            {
                A,
                A,
                ["layout"] = awful.widget.layout.vertical.bottomup
            },
            ["layout"] = awful.widget.layout.vertical.topdown
        },
        {
            D,
            B,
            ["layout"] = awful.widget.layout.vertical.topdown
        },
        ["layout"] = awful.widget.layout.horizontal.rightleft
    },
    ["layout"] = awful.widget.layout.horizontal.leftright
}
--]]
--[[
w.widgets = {
    {
        E,
        E,
        ["layout"] = awful.widget.layout.vertical.topdown
    },
    D,
    ["layout"] = awful.widget.layout.horizontal.rightleft
}
--]]
---[[
local t1 = {
    F,
    ["layout"] = awful.widget.layout.vertical.topdown
}
local t2 = {
    F,
    ["layout"] = awful.widget.layout.vertical.topdown
}
local t3 = {
    F,
    ["layout"] = awful.widget.layout.vertical.topdown
}
local t4 = {
    F,
    ["layout"] = awful.widget.layout.vertical.topdown
}

awful.widget.layout.margins[t1] = m1
awful.widget.layout.margins[t2] = m1
awful.widget.layout.margins[t3] = m1
awful.widget.layout.margins[t4] = m1

w2.widgets = {
    {
        t1,
        t2,
        ["layout"] = awful.widget.layout.vertical.topdown
    },
    {
        {
            pb1,
            B,
            ["layout"] = awful.widget.layout.horizontal.leftright
        },
        pb2,
        C,
        ["layout"] = awful.widget.layout.vertical.topdown
    },
    D,
    {
        {
            E,
            E,
            {
                t3,
                t4,
                ["layout"] = awful.widget.layout.vertical.bottomup
            },
            ["layout"] = awful.widget.layout.vertical.topdown
        },
        {
            D,
            B,
            ["layout"] = awful.widget.layout.vertical.topdown
        },
        ["layout"] = awful.widget.layout.horizontal.rightleft
    },
    ["layout"] = awful.widget.layout.horizontal.leftright
}
--[[
w2.widgets = {
    A,
    B,
    A,
    C,
    t1,
    C,
    ["layout"] = awful.widget.layout.horizontal.leftright
}
--]]
---[[
w3.widgets = {
    {
        A,
        B,
        ["layout"] = awful.widget.layout.horizontal.rightleft
    },
    E,
    E,
    E,
    F,
    {
        {
            C,
            D,
            ["layout"] = awful.widget.layout.vertical.center
        },
        ["layout"] = awful.widget.layout.horizontal.center
    },
    ["layout"] = awful.widget.layout.horizontal.leftright
}
--]]
---[[
--i.resize = false
w4.widgets = {
    --i,
    D,
    {
        A,
        ["layout"] = awful.widget.layout.horizontal.leftright
    },
    {
        E,
        ["layout"] = awful.widget.layout.horizontal.rightleft
    },
    {
        B,
        C,
        {
            F,
            F,
            F,
            ["layout"] = awful.widget.layout.vertical.flex
        },
        {
            {
                F,
                F,
                F,
                F,
                ["layout"] = awful.widget.layout.vertical.flex
            },
            ["layout"] = awful.widget.layout.vertical.topdown
        },
        {
            F,
            F,
            F,
            F,
            F,
            F,
            F,
            ["layout"] = awful.widget.layout.vertical.topdown
        },
        ["layout"] = awful.widget.layout.horizontal.flex
    },
    ["layout"] = awful.widget.layout.horizontal.leftright,
    height = 45
}
--]]

Reply via email to