I have updated my patch, it is attached.

I took the organization of adaptile but integrated it into Vile.

The code got a little more complex because the various orientations
where never implemented.  As for hinting, the width is the only thing
that was being taken into consideration and I didn't try to do anything
with height yet so that needs to be implemented.

Please try it out and let me know...  I think I tested about everything.

For the people wanting to understand what is going on...

Since awesome tile is layed out like MasterWindow|OtherWindows and the
OtherWindows can have multiple columns, then what was easiest for me was
to just have data on each column (without loss of generality we can
assume this is true for rows in horizontal splits).  Thus, each column
has a number of rows.  This is determined by the number of "other"
windows which are to be distributed among those columns.  The trickiest
part is to figure out for a given selected client, what the column it
belongs to is and what it's index in that column is.  The reason this is
tricky is because imagine this scenario where 'x' represents a window
and | represents the columns and ignore the master window for now, it's
behavior is well known as it is a single column.  So, suppose we have 5
other window and three columns, well, 5/3 = 1 so each column has at
least 1 windows there are 2 other clients, which need to be distributed.
and they get split evenly among the rightmost columns, thus we see
something like this:

| |x|x|
|x|x|x|

Luckily using some algebra I was able to calculate which column a client
was in so the mouse / keyboard input works.  Again, if you are a first
time to this layout, do change the amount of space a client takes up
you can bind a key to the function: awful.client.incwfact([val])

table.insert(globalkeys, key({ modMask, "Shift" }   , "h"       , function () 
awful.client.incwfact(-.1) end))
table.insert(globalkeys, key({ modMask, "Shift" }   , "l"       , function () 
awful.client.incwfact(.1) end))


From 0d4b4eb2d6cc3e24f760f21edd3988bb517bec8e Mon Sep 17 00:00:00 2001
From: [email protected] <[email protected]>
Date: Tue, 13 Jan 2009 13:31:37 -0600
Subject: [PATCH] vile is a Variable tILE layout that allows the user to select 
a single
 client window and resize that in it's layout.  This means that the slave
 windows do not necissarily need to be the same size all the time.

Fixed the bug where having only master or other windows would not
display full screen.

Added mouse resizing to the layout.

Updated vile to incorporate the style used by adaptile.

Merged the vile layout with the adaptile layout and fixed mouse support.

Fixed a bug
---
 lib/awful/client.lua.in           |  120 +++++++++++++++++++++++++
 lib/awful/layout/init.lua.in      |    8 ++
 lib/awful/layout/suit/init.lua.in |    2 +
 lib/awful/layout/suit/vile.lua.in |  177 +++++++++++++++++++++++++++++++++++++
 lib/awful/mouse.lua.in            |   73 +++++++++++++++
 5 files changed, 380 insertions(+), 0 deletions(-)
 create mode 100644 lib/awful/layout/suit/vile.lua.in

diff --git a/lib/awful/client.lua.in b/lib/awful/client.lua.in
index 65103a8..6aa2fa4 100644
--- a/lib/awful/client.lua.in
+++ b/lib/awful/client.lua.in
@@ -593,6 +593,126 @@ function floating.delete(c)
     data.floating[c] = nil
 end
 
+local function normalize(set, max)
+    total = 0
+    if max then
+        for i = 1,max do
+            total = total + set[i]
+        end
+        for i = 1,max do
+            set[i] = set[i] / total
+        end
+    else
+        for i,v in ipairs(set) do
+            total = total + v
+        end
+
+        for i,v in ipairs(set) do
+            set[i] = v / total
+        end
+    end
+end
+
+-- Calculate which {index, column} the client belongs to given the index
+function idx(c)
+    local c = c or capi.client.focus
+    local clients = tiled(c.screen)
+    local idx = nil
+    for k, cl in ipairs(clients) do
+        if cl == c then
+            idx = k
+            break
+        end
+    end
+
+    local nmaster = tag.getnmaster(t)
+    if idx <= nmaster then
+        return {idx = idx, col=0, max=nmaster}
+    end
+    local nother = #clients - nmaster
+    idx = idx - nmaster
+
+    -- rather than regenerate the column number we can calculate it
+    -- based on the how the tiling algorithm places clients we calculate
+    -- the column, we could easily use the for loop in the program but we can
+    -- calculate it.
+    local ncol = tag.getncol(t)
+    -- minimum number of clients per column
+    local percol = math.floor(nother / ncol)
+    -- number of columns with an extra client
+    local overcol = math.mod(nother, ncol)
+    -- number of columns filled with [percol] clients
+    local regcol = ncol - overcol
+
+    local col = math.floor( (idx - 1) / percol) + 1
+    if  col > regcol then
+        -- col = math.floor( (idx - (percol*regcol) - 1) / (percol + 1) ) + 
regcol + 1
+        -- simplified
+        col = math.floor( (idx + regcol + percol) / (percol+1) )
+        -- calculate the index in the column
+        idx = idx - percol*regcol - (col - regcol - 1) * (percol+1)
+        percol = percol+1
+    else
+        idx = idx - percol*(col-1)
+    end
+
+    return {idx = idx, col=col, max=percol}
+end
+
+
+-- Set the window by index (or the currently selected window) 
+function setwfact(wfact, c)
+    local t = t or tag.selected()
+
+    -- get the currently selected window
+    local c =  c or capi.client.focus
+    local w = idx(c)
+
+    local cls = tiled(t.screen)
+    local nmaster = tag.getnmaster(t)
+
+    -- n is the number of windows currently visible for which we have to be 
concerned with the properties
+    local data = tag.getproperty(t, "windowfact") or {}
+    local colfact = data[w.col]
+
+    colfact[w.idx] = wfact
+    rest = 1-wfact
+
+    -- calculate the current denominator
+    local total = 0
+    for i = 1,w.max do
+        if i ~= w.idx then
+            total = total + colfact[i]
+        end
+    end
+
+    -- normalize the windows
+    for i = 1,w.max do
+        if i ~= w.idx then
+            colfact[i] = (colfact[i] * rest) / total
+        end
+    end
+end
+
+-- Change the width factor of a window (indexed by number)
+function incwfact(add, c)
+    local c = c or capi.client.focus
+    local t = tag.selected()
+
+    local w = idx(c)
+
+    local nmaster = tag.getnmaster(t)
+    local data = tag.getproperty(t, "windowfact") or {}
+    local colfact = data[w.col]
+    curr = colfact[w.idx] or 1
+    colfact[w.idx] = curr + add
+
+    -- keep our ratios normalized
+    normalize(colfact, w.max)
+    capi.hooks.arrange()(t.screen)
+end
+
+
 -- Register standards hooks
 hooks.focus.register(focus.history.add)
 hooks.unmanage.register(focus.history.delete)
diff --git a/lib/awful/layout/init.lua.in b/lib/awful/layout/init.lua.in
index bf45763..70e8ea7 100644
--- a/lib/awful/layout/init.lua.in
+++ b/lib/awful/layout/init.lua.in
@@ -70,6 +70,14 @@ local layouts_name =
     [suit.tile.left]       = "tileleft",
     [suit.tile.bottom]     = "tilebottom",
     [suit.tile.top]        = "tiletop",
+    [suit.vile]            = "vile",
+    [suit.vile.left]       = "vileleft",
+    [suit.vile.bottom]     = "vilebottom",
+    [suit.vile.top]        = "viletop",
+    [suit.adaptile]            = "adaptile",
+    [suit.adaptile.left]       = "adaptileleft",
+    [suit.adaptile.bottom]     = "adaptilebottom",
+    [suit.adaptile.top]        = "adaptiletop",
     [suit.fair]            = "fairv",
     [suit.fair.horizontal] = "fairh",
     [suit.max]             = "max",
diff --git a/lib/awful/layout/suit/init.lua.in 
b/lib/awful/layout/suit/init.lua.in
index ae83edf..20e1550 100644
--- a/lib/awful/layout/suit/init.lua.in
+++ b/lib/awful/layout/suit/init.lua.in
@@ -1,5 +1,7 @@
 require("awful.layout.suit.max")
 require("awful.layout.suit.tile")
+require("awful.layout.suit.vile")
+require("awful.layout.suit.adaptile")
 require("awful.layout.suit.fair")
 require("awful.layout.suit.floating")
 require("awful.layout.suit.magnifier")
diff --git a/lib/awful/layout/suit/vile.lua.in 
b/lib/awful/layout/suit/vile.lua.in
new file mode 100644
index 0000000..4c9b5e6
--- /dev/null
+++ b/lib/awful/layout/suit/vile.lua.in
@@ -0,0 +1,177 @@
+---------------------------------------------------------------------------
+-- @author Donald Ephraim Curtis &lt;[email protected]&gt;
+-- @author Julien Danjou &lt;[email protected]&gt;
+-- @copyright 2009 Donald Ephraim Curtis
+-- @copyright 2009 Maxime Coste
+-- @copyright 2008 Julien Danjou
+-- @release @AWESOME_VERSION@
+---------------------------------------------------------------------------
+
+-- Grab environment we need
+local setmetatable = setmetatable
+local ipairs = ipairs
+local math = math
+local client = require("awful.client")
+local tag = require("awful.tag")
+local capi =
+{
+    screen = screen
+}
+
+--- Tiled layouts module for awful
+module("awful.layout.suit.vile")
+local function tile_group(cls, wa, orientation, fact, group)
+    -- get our orientation right
+    local height = "height"
+    local width = "width"
+    local x = "x"
+    local y = "y"
+    if orientation == "top" or orientation == "bottom" then
+        height = "width"
+        width = "height"
+        x = "y"
+        y = "x"
+    end
+
+    -- make this more generic (not just width)
+    available = wa[width] - (group.coord - wa[x])
+
+    -- find our total values
+    local total_fact = 0
+    local min_fact = 1
+    local size = group.size
+    for c = group.first,group.last do
+        -- determine the width/height based on the size_hint
+        local i = c - group.first +1
+        local size_hints = cls[c].size_hints
+        local size_hint = size_hints["min_"..width] or 
size_hints["base_"..width] or 0
+        size_hint = size_hint + cls[c].border_width*2
+        size = math.max(size_hint, size)
+
+        -- calculate the height
+        if not fact[i] then
+            fact[i] = min_fact
+        else
+            min_fact = math.min(fact[i],min_fact)
+        end
+        total_fact = total_fact + fact[i]
+    end
+    size = math.min(size, available)
+
+    local coord = wa[y]
+    local geom = {}
+    local used_size = 0
+    local unused = wa[height]
+    for c = group.first,group.last do
+        local i = c - group.first +1
+        geom[width] = size
+        geom[height] = math.floor(unused * fact[i] / total_fact)
+        geom[x] = group.coord
+        geom[y] = coord
+        geom = cls[c]:geometry(geom)
+        coord = coord + geom[height]
+        unused = unused - geom[height]
+        total_fact = total_fact - fact[i]
+        used_size = math.max(used_size, geom[width])
+    end
+
+    return used_size
+
+end
+
+local function vile(_, screen, orientation)
+    orientation = orientation or "right"
+
+    -- this handles are different orientations
+    local height = "height"
+    local width = "width"
+    local x = "x"
+    local y = "y"
+    if orientation == "top" or orientation == "bottom" then
+        height = "width"
+        width = "height"
+        x = "y"
+        y = "x"
+    end
+
+    local t = tag.selected()
+    local cls = client.tiled(screen)
+    local nmaster = tag.getnmaster(t)
+    local nother = #cls - nmaster
+
+    local mwfact = tag.getmwfact(t)
+    local wa = capi.screen[screen].workarea
+    local ncol = tag.getncol(t)
+
+    local data = tag.getproperty(t,"windowfact")
+
+    if not data then
+        data = {}
+        tag.setproperty(t,"windowfact", data)
+    end
+
+    --
+    local coord = wa[x]
+    local place_master = true
+    if orientation == "left" or orientation == "top" then
+        -- if we are on the left or top we need to render the other windows 
first
+        place_master = false
+    end
+
+    -- this was easier than writing functions because there is a lot of data 
we need
+    for d = 1,2 do
+        if place_master and nmaster > 0 then
+            local size = wa[width]
+            if nother > 0 then
+                size = math.min(wa[width] * mwfact, wa[width] - (coord - 
wa[x]))
+            end
+            if not data[0] then
+                data[0] = {}
+            end
+            coord = coord + tile_group(cls, wa, orientation, data[0], 
{first=1, last=nmaster, coord = coord, size = size})
+        end
+
+        if not place_master then
+            local last = nmaster
+
+            -- we have to modify the work area size to consider left and top 
views
+            local wasize = wa[width]
+            if orientation == "left" or orientation == "top" then
+                wasize = wa[width] - wa[width]*mwfact
+            end
+            for i = 1,ncol do
+                -- Try to get equal width among remaining columns
+                local size = math.min( (wasize - (coord - wa[x])) / (ncol - i 
+ 1) )
+                local first = last + 1
+                last = last + math.floor((#cls - last)/(ncol - i + 1))
+                -- tile the column and update our current x coordinate
+                if not data[i] then
+                    data[i] = {}
+                end
+                coord = coord + tile_group(cls, wa, orientation, data[i], { 
first = first, last = last, coord = coord, size = size })
+            end
+        end
+        place_master = not place_master
+    end
+
+end
+
+--- The main tile algo, on left.
+-- @param screen The screen number to tile.
+function left(screen)
+    return vile(nil, screen, "left")
+end
+
+--- The main tile algo, on bottom.
+-- @param screen The screen number to tile.
+function bottom(screen)
+    return vile(nil, screen, "bottom")
+end
+
+--- The main tile algo, on top.
+-- @param screen The screen number to tile.
+function top(screen)
+    return vile(nil, screen, "top")
+end
+
+setmetatable(_M, { __call = vile })
diff --git a/lib/awful/mouse.lua.in b/lib/awful/mouse.lua.in
index 4390506..ac2fb68 100644
--- a/lib/awful/mouse.lua.in
+++ b/lib/awful/mouse.lua.in
@@ -392,6 +392,73 @@ local function client_resize_tiled(c, lay)
                           end, cursor)
 end
 
+local function client_resize_viled(c, lay)
+    local wa = capi.screen[c.screen].workarea
+    local mwfact = tag.getmwfact()
+    local cursor
+    if lay == layout.suit.vile then
+        capi.mouse.coords({ x = wa.x + wa.width * mwfact })
+        cursor = "sb_h_double_arrow"
+    elseif lay == layout.suit.vile.left then
+        capi.mouse.coords({ x = wa.x + wa.width * (1 - mwfact) })
+        cursor = "sb_h_double_arrow"
+    elseif lay == layout.suit.vile.bottom then
+        capi.mouse.coords({ y = wa.y + wa.height * mwfact })
+        cursor = "sb_v_double_arrow"
+    else
+        capi.mouse.coords({ y = wa.y + wa.height * (1 - mwfact) })
+        cursor = "sb_v_double_arrow"
+    end
+
+    capi.mousegrabber.run(function (mouse)
+                              for k, v in ipairs(mouse.buttons) do
+                                  if v then
+                                      local fact_x = (mouse.x - wa.x) / 
wa.width
+                                      local fact_y = (mouse.y - wa.y) / 
wa.height
+                                      local mwfact
+
+                                      local g = c:geometry()
+
+
+                                      -- we have to make sure we're not on the 
last visible client where we have to use different settings.
+                                      local wfact
+                                      local wfact_x, wfact_y
+                                      if (g.y+g.height+15) > (wa.y+wa.height) 
then
+                                          wfact_y = (g.y + g.height - mouse.y) 
/ wa.height
+                                      else
+                                          wfact_y = (mouse.y - g.y) / wa.height
+                                      end
+
+                                      if (g.x+g.width+15) > (wa.x+wa.width) 
then
+                                          wfact_x = (g.x + g.width - mouse.x) 
/ wa.width
+                                      else
+                                          wfact_x = (mouse.x - g.x) / wa.width
+                                      end
+
+
+                                      if lay == layout.suit.vile then
+                                          mwfact = fact_x
+                                          wfact = wfact_y
+                                      elseif lay == layout.suit.vile.left then
+                                          mwfact = 1 - fact_x
+                                          wfact = wfact_y
+                                      elseif lay == layout.suit.vile.bottom 
then
+                                          mwfact = fact_y
+                                          wfact = wfact_x
+                                      else
+                                          mwfact = 1 - fact_y
+                                          wfact = wfact_x
+                                      end
+
+                                      tag.setmwfact(math.min(math.max(mwfact, 
0.01), 0.99), tag.selected(c.screen))
+                                      
aclient.setwfact(math.min(math.max(wfact,0.01), 0.99), c)
+                                      return true
+                                  end
+                              end
+                              return false
+                          end, cursor)
+end
+
 local function client_resize_floating(c, corner, fixed_x, fixed_y)
     local corner, x, y = client.corner(c, corner)
     local g = c:geometry()
@@ -483,6 +550,12 @@ function client.resize(c, corner)
         or lay == layout.suit.tile.top
         or lay == layout.suit.tile.bottom then
         return client_resize_tiled(c, lay)
+    elseif lay == layout.suit.vile
+        or lay == layout.suit.vile.left
+        or lay == layout.suit.vile.top
+        or lay == layout.suit.vile.bottom 
+        then
+        return client_resize_viled(c, lay)
     elseif lay == layout.suit.magnifier then
         return client_resize_magnifier(c, corner)
     end
-- 
1.6.1

Attachment: pgpR3nH6i2TQS.pgp
Description: PGP signature

Reply via email to