wibox.layout.align: make the middle widget really centered
[awesome.git] / lib / wibox / layout / align.lua.in
blob5a4766ad99c78f35c9ab3ce270958153e8124a6f
1 ---------------------------------------------------------------------------
2 -- @author Uli Schlachter
3 -- @copyright 2010 Uli Schlachter
4 -- @release @AWESOME_VERSION@
5 ---------------------------------------------------------------------------
7 local setmetatable = setmetatable
8 local table = table
9 local pairs = pairs
10 local type = type
11 local base = require("wibox.layout.base")
12 local widget_base = require("wibox.widget.base")
14 -- wibox.layout.align
15 local align = {}
17 --- Draw an align layout.
18 -- @param wibox The wibox that this widget is drawn to.
19 -- @param cr The cairo context to use.
20 -- @param width The available width.
21 -- @param height The available height.
22 -- @return The total space needed by the layout.
23 function align:draw(wibox, cr, width, height)
24 local size_first = 0
25 local size_third = 0
26 local size_limit = self.dir == "y" and height or width
28 if self.first then
29 local w, h, _ = width, height, nil
30 if self.dir == "y" then
31 _, h = self.first:fit(w, h)
32 size_first = h
33 else
34 w, _ = self.first:fit(w, h)
35 size_first = w
36 end
37 base.draw_widget(wibox, cr, self.first, 0, 0, w, h)
38 end
40 if self.third and size_first < size_limit then
41 local w, h, x, y, _
42 if self.dir == "y" then
43 w, h = width, height - size_first
44 _, h = self.third:fit(w, h)
45 x, y = 0, height - h
46 size_third = h
47 else
48 w, h = width - size_first, height
49 w, _ = self.third:fit(w, h)
50 x, y = width - w, 0
51 size_third = w
52 end
53 base.draw_widget(wibox, cr, self.third, x, y, w, h)
54 end
56 if self.second and size_first + size_third < size_limit then
57 local x, y, w, h
58 if self.dir == "y" then
59 w, h = width, size_limit - size_first - size_third
60 local real_w, real_h = self.second:fit(w, h)
61 x, y = 0, size_first + h / 2 - real_h / 2
62 w, h = real_w, real_h
63 else
64 w, h = size_limit - size_first - size_third, height
65 local real_w, real_h = self.second:fit(w, h)
66 x, y = size_first + w / 2 - real_w / 2, 0
67 w, h = real_w, real_h
68 end
69 base.draw_widget(wibox, cr, self.second, x, y, w, h)
70 end
71 end
73 local function widget_changed(layout, old_w, new_w)
74 if old_w then
75 old_w:disconnect_signal("widget::updated", layout._emit_updated)
76 end
77 if new_w then
78 widget_base.check_widget(new_w)
79 new_w:connect_signal("widget::updated", layout._emit_updated)
80 end
81 layout._emit_updated()
82 end
84 --- Set the layout's first widget. This is the widget that is at the left/top
85 function align:set_first(widget)
86 widget_changed(self, self.first, widget)
87 self.first = widget
88 end
90 --- Set the layout's second widget. This is the centered one.
91 function align:set_second(widget)
92 widget_changed(self, self.second, widget)
93 self.second = widget
94 end
96 --- Set the layout's third widget. This is the widget that is at the right/bottom
97 function align:set_third(widget)
98 widget_changed(self, self.third, widget)
99 self.third = widget
102 --- Fit the align layout into the given space. The align layout will
103 -- take all available space in its direction and the maximum size of
104 -- it's all three inner widgets in the other axis.
105 -- @param orig_width The available width.
106 -- @param orig_height The available height.
107 function align:fit(orig_width, orig_height)
108 local used_max = 0
110 for k, v in pairs{self.first, self.second, self.third} do
111 local w, h = v:fit(orig_width, orig_height)
113 local max = self.dir == "y" and w or h
115 if max > used_max then
116 used_max = max
120 if self.dir == "y" then
121 return used_max, orig_height
123 return orig_width, used_max
126 function align:reset()
127 for k, v in pairs({ "first", "second", "third" }) do
128 self[v] = nil
130 self:emit_signal("widget::updated")
133 local function get_layout(dir)
134 local ret = widget_base.make_widget()
135 ret.dir = dir
136 ret._emit_updated = function()
137 ret:emit_signal("widget::updated")
140 for k, v in pairs(align) do
141 if type(v) == "function" then
142 ret[k] = v
146 return ret
149 --- Returns a new horizontal align layout. An align layout can display up to
150 -- three widgets. The widget set via :set_left() is left-aligned. :set_right()
151 -- sets a widget which will be right-aligned. The remaining space between those
152 -- two will be given to the widget set via :set_middle().
153 function align.horizontal()
154 local ret = get_layout("x")
156 ret.set_left = ret.set_first
157 ret.set_middle = ret.set_second
158 ret.set_right = ret.set_third
160 return ret
163 --- Returns a new vertical align layout. An align layout can display up to
164 -- three widgets. The widget set via :set_top() is top-aligned. :set_bottom()
165 -- sets a widget which will be bottom-aligned. The remaining space between those
166 -- two will be given to the widget set via :set_middle().
167 function align.vertical()
168 local ret = get_layout("y")
170 ret.set_top = ret.set_first
171 ret.set_middle = ret.set_second
172 ret.set_bottom = ret.set_third
174 return ret
177 return align
179 -- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80