Merge pull request #2510 from Elv13/xmas_2k18_4

Add the popup widget take 2 (only relevant commits)
This commit is contained in:
Emmanuel Lepage Vallée 2019-01-24 23:24:22 -05:00 committed by GitHub
commit c87e7aad56
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 1142 additions and 4 deletions

View File

@ -1,7 +1,6 @@
# The declarative layout system
# The AwesomeWM widget system
The declarative layout system provides an alternative to the imperative system.
It is inspired by the one used by Awesome 3.2-3.4 and the Qt QML style.
This document explains how to define, place and manage widgets.
## The default widgets
@ -29,7 +28,127 @@ configurable rules.
@DOC_layout_WIDGET_LIST@
## Placing widgets
### The different type of widget boxes (Wibox)
The Awesome API uses the word "wibox" (widget box) to describe an area of the
screen filled with widgets. There are many subvariants of wiboxes with
specialized roles such as widget bars or tooltips. All variants mostly share the
same characteristics, but add some extra features to make those specialized
widget boxes easier to work with.
@DOC_awful_popup_wiboxtypes_EXAMPLE@
The normal `wibox` is the base class for each of these types. It is extremely
flexible and allows to place just about anything on the screen. However it
requires a lot of repetitive boilerplate code to use directly. For example,
the user needs to compute the optimal size by hand or use `awful.placement`.
The `awful.wibar` specialization allows to attach a `wibox` to a screen edge
and prevents clients from using this area when tiled.
The `awful.popup` allows to easily place widgets on the screen. It automatically
resizes itself to fit the optimal widget size. It also has helper properties
and methods to make it easy to place it on the screen. It supports absolute
positioning, relative positioning, and manual positioning.
The `awful.tooltip` is a very simple `wibox` that allows to display text next
to an object such as the mouse.
Finally, the `awful.titlebar`, while not technically a real `wibox`, acts
exactly the same way and allows to attach widgets on each side of clients.
## The different syntaxes to initiate widgets
Awesome provides 2 totally different API access styles to manage widgets. Both
suit different use cases. Under the hood, both produce the
exact same code. Consider the declarative API to be compiled into the
imperative syntax when loaded. Also note that in contrast to technologies such
as QML, it is interpreted only once and isn't automatically updated when
values change.
The **imperative** widget initialization is similar to QtWidgets, GTK and Win32.
You create the object, then set the property and add the widget as a child to
another already declared widget. It is quite simple to use but very verbose
and full of boilerplate code. The imperative API also offers properties both
with accessors or directly. It is useful when creating highly dynamic layouts
where widgets are added and removed over the course of their lifecycle.
The **declarative** syntax resembles HTML style code
written in JSON or YAML. The widget instances are created automatically and
the hierarchy is related to the table nesting (indentation). It is preferred
when creating static layouts that won't change over the course of their
lifecycle.
Here is the same code written in both the imperative and declarative style
**Imperative with accessors**
Code:
local bg = wibox.container.background()
bg:set_bg("#ff0000")
local tb1 = wibox.widget.textbox()
local tb2 = wibox.widget.textbox("bar")
tb1:set_text("foo")
tb2:set_text("bar")
local l = wibox.layout.fixed.vertical()
l:add(tb1)
l:add(tb2)
bg:set_widget(l)
**Imperative with properties**
Code:
local bg = wibox.container.background()
bg.bg = "#ff0000"
local tb1 = wibox.widget.textbox("foo")
local tb2 = wibox.widget.textbox("bar")
tb1.text = "foo"
tb2.text = "bar"
local l = wibox.layout.fixed.vertical()
l:add(tb1)
l:add(tb2)
bg.widget = l
**Declarative**
Code:
local bg = wibox.widget {
{
{
text = "foo",
widget = wibox.widget.textbox
},
{
text = "bar",
widget = wibox.widget.textbox
},
layout = wibox.layout.fixed.vertical
},
bg = "#ff0000",
widget = wibox.container.background
}
The Awesome documentation mostly uses the declarative style for consistency,
but both are **always** available. Note that each style can be mixed with other
styles, but this creates very confusing code and should be avoided.
## Creating and placing widgets using the declarative style
The examples below explain in detail how to use the declarative layout system.
The imperative system is quite self explanatory and the respective widget API
documentation should be enough for most.
### A simple layout

View File

@ -59,6 +59,7 @@ return
ewmh = require("awful.ewmh");
titlebar = require("awful.titlebar");
rules = require("awful.rules");
popup = require("awful.popup");
spawn = spawn;
}

467
lib/awful/popup.lua Normal file
View File

@ -0,0 +1,467 @@
---------------------------------------------------------------------------
--- An auto-resized, free floating or modal wibox built around a widget.
--
-- This type of widget box (wibox) is auto closed when being clicked on and is
-- automatically resized to the size of its main widget.
--
-- Note that the widget itself should have a finite size. If something like a
-- `wibox.layout.flex` is used, then the size would be unlimited and an error
-- will be printed. The `wibox.layout.fixed`, `wibox.container.constraint`,
-- `forced_width` and `forced_height` are recommended.
--
--@DOC_awful_popup_simple_EXAMPLE@
--
-- Here is an example of how to create an alt-tab like dialog by leveraging
-- the `awful.widget.tasklist`.
--
--@DOC_awful_popup_alttab_EXAMPLE@
--
-- @author Emmanuel Lepage Vallee
-- @copyright 2016 Emmanuel Lepage Vallee
-- @classmod awful.popup
---------------------------------------------------------------------------
local wibox = require( "wibox" )
local util = require( "awful.util" )
local placement = require( "awful.placement" )
local xresources= require("beautiful.xresources")
local timer = require( "gears.timer" )
local capi = {mouse = mouse}
local module = {}
local main_widget = {}
-- Get the optimal direction for the wibox
-- This (try to) avoid going offscreen
local function set_position(self)
-- First, if there is size to be applied, do it
if self._private.next_width then
self.width = self._private.next_width
self._private.next_width = nil
end
if self._private.next_height then
self.height = self._private.next_height
self._private.next_height = nil
end
local pf = self._private.placement
if pf == false then return end
if pf then
pf(self, {bounding_rect = self.screen.geometry})
return
end
local geo = self._private.widget_geo
if not geo then return end
local _, pos_name, anchor_name = placement.next_to(self, {
preferred_positions = self._private.preferred_directions,
geometry = geo,
preferred_anchors = self._private.preferred_anchors,
offset = self._private.offset or { x = 0, y = 0},
})
if pos_name ~= self._private.current_position then
local old = self._private.current_position
self._private.current_position = pos_name
self:emit_signal("property::current_position", pos_name, old)
end
if anchor_name ~= self._private.current_anchor then
local old = self._private.current_anchor
self._private.current_anchor = anchor_name
self:emit_signal("property::current_anchor", anchor_name, old)
end
end
-- Set the wibox size taking into consideration the limits
local function apply_size(self, width, height, set_pos)
local prev_geo = self:geometry()
width = math.max(self._private.minimum_width or 1, math.ceil(width or 1))
height = math.max(self._private.minimum_height or 1, math.ceil(height or 1))
if self._private.maximum_width then
width = math.min(self._private.maximum_width, width)
end
if self._private.maximum_height then
height = math.min(self._private.maximum_height, height)
end
self._private.next_width, self._private.next_height = width, height
if set_pos or width ~= prev_geo.width or height ~= prev_geo.height then
set_position(self)
end
end
-- Layout this widget
function main_widget:layout(context, width, height)
if self._private.widget then
local w, h = wibox.widget.base.fit_widget(
self,
context,
self._private.widget,
self._wb._private.maximum_width or 9999,
self._wb._private.maximum_height or 9999
)
timer.delayed_call(function()
apply_size(self._wb, w, h, true)
end)
return { wibox.widget.base.place_widget_at(self._private.widget, 0, 0, width, height) }
end
end
-- Set the widget that is drawn on top of the background
function main_widget:set_widget(widget)
if widget then
wibox.widget.base.check_widget(widget)
end
self._private.widget = widget
self:emit_signal("widget::layout_changed")
end
function main_widget:get_widget()
return self._private.widget
end
function main_widget:get_children_by_id(name)
return self._wb:get_children_by_id(name)
end
local popup = {}
--- Set the preferred popup position relative to its parent.
--
-- This allows, for example, to have a submenu that goes on the right of the
-- parent menu. If there is no space on the right, it tries on the left and so
-- on.
--
-- Valid directions are:
--
-- * left
-- * right
-- * top
-- * bottom
--
-- The basic use case for this method is to give it a parent wibox:
--
-- @DOC_awful_popup_position1_EXAMPLE@
--
-- As demonstrated by this second example, it is also possible to use a widget
-- as a parent object:
--
-- @DOC_awful_popup_position2_EXAMPLE@
--
-- @property preferred_positions
-- @tparam table|string preferred_positions A position name or an ordered
-- table of positions
-- @see awful.placement.next_to
-- @see awful.popup.preferred_anchors
function popup:set_preferred_positions(pref_pos)
self._private.preferred_directions = pref_pos
set_position(self)
end
--- Set the preferred popup anchors relative to the parent.
--
-- The possible values are:
--
-- * front
-- * middle
-- * back
--
-- For details information, see the `awful.placement.next_to` documentation.
--
-- In this example, it is possible to see the effect of having a fallback
-- preferred anchors when the popup would otherwise not fit:
--
-- @DOC_awful_popup_anchors_EXAMPLE@
--
-- @property preferred_anchors
-- @tparam table|string preferred_anchors Either a single anchor name or a table
-- ordered by priority.
-- @see awful.placement.next_to
-- @see awful.popup.preferred_positions
function popup:set_preferred_anchors(pref_anchors)
self._private.preferred_anchors = pref_anchors
set_position(self)
end
--- The current position relative to the parent object.
--
-- If there is a parent object (widget, wibox, wibar, client or the mouse), then
-- this property returns the current position. This is determined using
-- `preferred_positions`. It is usually the preferred position, but when there
-- isn't enough space, it can also be one of the fallback.
--
-- @property current_position
-- @tparam string current_position Either "left", "right", "top" or "bottom"
function popup:get_current_position()
return self._private.current_position
end
--- Get the current anchor relative to the parent object.
--
-- If there is a parent object (widget, wibox, wibar, client or the mouse), then
-- this property returns the current anchor. The anchor is the "side" of the
-- parent object on which the popup is based on. It will "grow" in the
-- opposite direction from the anchor.
--
-- @property current_anchor
-- @tparam string current_anchor Either "front", "middle", "back"
function popup:get_current_anchor()
return self._private.current_anchor
end
--- Move the wibox to a position relative to `geo`.
-- This will try to avoid overlapping the source wibox and auto-detect the right
-- direction to avoid going off-screen.
--
-- @param[opt=mouse] obj An object such as a wibox, client or a table entry
-- returned by `wibox:find_widgets()`.
-- @see awful.placement.next_to
-- @see awful.popup.preferred_positions
-- @see awful.popup.preferred_anchors
-- @treturn table The new geometry
function popup:move_next_to(obj)
if self._private.is_relative == false then return end
self._private.widget_geo = obj
obj = obj or capi.mouse
if obj._apply_size_now then
obj:_apply_size_now(false)
end
self.visible = true
self:_apply_size_now(true)
self._private.widget_geo = nil
end
--- Bind the popup to a widget button press.
--
-- @tparam widget widget The widget
-- @tparam[opt=1] number button The button index
function popup:bind_to_widget(widget, button)
if not self._private.button_for_widget then
self._private.button_for_widget = {}
end
self._private.button_for_widget[widget] = button or 1
widget:connect_signal("button::press", self._private.show_fct)
end
--- Unbind the popup from a widget button.
-- @tparam widget widget The widget
function popup:unbind_to_widget(widget)
widget:disconnect_signal("button::press", self._private.show_fct)
end
--- Hide the popup when right clicked.
--
-- @property hide_on_right_click
-- @tparam[opt=false] boolean hide_on_right_click
function popup:set_hide_on_right_click(value)
self[value and "connect_signal" or "disconnect_signal"](
self, "button::press", self._private.hide_fct
)
end
--- The popup minimum width.
-- @property minimum_width
-- @tparam[opt=1] number The minimum width
--- The popup minimum height.
-- @property minimum_height
-- @tparam[opt=1] number The minimum height
--- The popup minimum width.
-- @property maxmimum_width
-- @tparam[opt=1] number The maxmimum width
--- The popup maximum height.
-- @property maximum_height
-- @tparam[opt=1] number The maximum height
for _, orientation in ipairs {"_width", "_height"} do
for _, limit in ipairs {"minimum", "maximum"} do
popup["set_"..limit..orientation] = function(self, value)
self._private[limit..orientation] = value
self._private.container:emit_signal("widget::layout_changed")
end
end
end
--- The distance between the popup and its parent (if any).
--
-- Here is an example of 5 popups stacked one below the other with an y axis
-- offset (spacing).
--
-- @DOC_awful_popup_position3_EXAMPLE@
-- @property offset
-- @tparam table|number offset An integer value or a `{x=, y=}` table.
-- @tparam[opt=offset] number offset.x The horizontal distance.
-- @tparam[opt=offset] number offset.y The vertical distance.
function popup:set_offset(offset)
if type(offset) == "number" then
offset = {
x = offset or 0,
y = offset or 0,
}
end
local oldoff = self._private.offset or {x=0, y=0}
if oldoff.x == offset.x and oldoff.y == offset.y then return end
offset.x, offset.y = offset.x or oldoff.x or 0, offset.y or oldoff.y or 0
self._private.offset = offset
self:_apply_size_now(false)
end
--- Set the placement function.
-- @tparam[opt=next_to] function|string|boolean The placement function or name
-- (or false to disable placement)
-- @property placement
-- @param function
function popup:set_placement(f)
if type(f) == "string" then
f = placement[f]
end
self._private.placement = f
self:_apply_size_now(false)
end
-- For the tests and the race condition when 2 popups are placed next to each
-- other.
function popup:_apply_size_now(skip_set)
if not self.widget then return end
local w, h = wibox.widget.base.fit_widget(
self.widget,
{dpi= self.screen.dpi or xresources.get_dpi()},
self.widget,
self._private.maximum_width or 9999,
self._private.maximum_height or 9999
)
-- It is important to do it for the obscure reason that calling `w:geometry()`
-- is actually mutating the state due to quantum determinism thanks to XCB
-- async nature... It is only true the very first time `w:geometry()` is
-- called
self.width = math.max(1, math.ceil(w or 1))
self.height = math.max(1, math.ceil(h or 1))
apply_size(self, w, h, skip_set ~= false)
end
function popup:set_widget(wid)
self._private.widget = wid
self._private.container:set_widget(wid)
end
function popup:get_widget()
return self._private.widget
end
--- Create a new popup build around a passed in widget.
-- @tparam[opt=nil] table args
--@DOC_wibox_constructor_COMMON@
-- @tparam function args.placement The `awful.placement` function
-- @tparam string|table args.preferred_positions
-- @tparam string|table args.preferred_anchors
-- @tparam table|number args.offset The X and Y offset compared to the parent object
-- @tparam boolean args.hide_on_right_click Whether or not to hide the popup on
-- right clicks.
-- @function awful.popup
local function create_popup(_, args)
assert(args)
-- Temporarily remove the widget
local original_widget = args.widget
args.widget = nil
assert(original_widget, "The `awful.popup` requires a `widget` constructor argument")
local child_widget = wibox.widget.base.make_widget_from_value(original_widget)
local ii = wibox.widget.base.make_widget(child_widget, "awful.popup", {
enable_properties = true
})
util.table.crush(ii, main_widget, true)
-- Create a wibox to host the widget
local w = wibox(args or {})
rawset(w, "_private", {
container = ii,
preferred_directions = { "right", "left", "top", "bottom" },
preferred_anchors = { "back", "front", "middle" },
widget = child_widget
})
util.table.crush(w, popup)
ii:set_widget(child_widget)
-- Create the signal handlers
function w._private.show_fct(wdg, _, _, button, _, geo)
if button == w._private.button_for_widget[wdg] then
w:move_next_to(geo)
end
end
function w._private.hide_fct()
w.visible = false
end
-- Restore
args.widget = original_widget
-- Cross-link the wibox and widget
ii._wb = w
wibox.set_widget(w, ii)
--WARNING The order is important
-- First, apply the limits to avoid a flicker with large width or height
-- when set_position is called before the limits
for _,v in ipairs{"minimum_width", "minimum_height", "maximum_height",
"maximum_width", "offset", "placement","preferred_positions",
"preferred_anchors", "hide_on_right_click"} do
if args[v] ~= nil then
w["set_"..v](w, args[v])
end
end
-- Default to visible
if args.visible ~= false then
w.visible = true
end
return w
end
--@DOC_wibox_COMMON@
return setmetatable(module, {__call = create_popup})

View File

@ -0,0 +1,59 @@
--DOC_GEN_IMAGE --DOC_HIDE
local awful = { --DOC_HIDE --DOC_NO_USAGE
popup = require("awful.popup"), --DOC_HIDE
placement = require("awful.placement"), --DOC_HIDE
widget = {clienticon =require("awful.widget.clienticon"), --DOC_HIDE
tasklist = require("awful.widget.tasklist")} --DOC_HIDE
} --DOC_HIDE
local gears = { shape = require("gears.shape") } --DOC_HIDE
local wibox = require("wibox") --DOC_HIDE
local beautiful = require("beautiful") --DOC_HIDE
for _=1, 6 do --DOC_HIDE
local c = client.gen_fake {x = 80, y = 55, width=75, height=50} --DOC_HIDE
c.icon = beautiful.awesome_icon --DOC_HIDE
c.minimized = true --DOC_HIDE
end --DOC_HIDE
local tasklist_buttons = nil --DOC_HIDE
awful.popup {
widget = awful.widget.tasklist {
screen = screen[1],
filter = awful.widget.tasklist.filter.allscreen,
buttons = tasklist_buttons,
style = {
shape = gears.shape.rounded_rect,
},
layout = {
spacing = 5,
forced_num_rows = 2,
layout = wibox.layout.grid.horizontal
},
widget_template = {
{
{
id = "clienticon",
widget = awful.widget.clienticon,
},
margins = 4,
widget = wibox.container.margin,
},
id = "background_role",
forced_width = 48,
forced_height = 48,
widget = wibox.container.background,
create_callback = function(self, c, index, objects) --luacheck: no unused
self:get_children_by_id("clienticon")[1].client = c
end,
},
},
border_color = "#777777",
border_width = 2,
ontop = true,
placement = awful.placement.centered,
shape = gears.shape.rounded_rect
}
--DOC_HIDE vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80

View File

@ -0,0 +1,70 @@
--DOC_GEN_IMAGE --DOC_HIDE
local awful = { --DOC_HIDE --DOC_NO_USAGE
popup = require("awful.popup"), --DOC_HIDE
placement = require("awful.placement"), --DOC_HIDE
widget = {clienticon =require("awful.widget.clienticon"), --DOC_HIDE
tasklist = require("awful.widget.tasklist")} --DOC_HIDE
} --DOC_HIDE
local wibox = require("wibox") --DOC_HIDE
screen[1]._resize {width = 320, height = 240} --DOC_HIDE
screen._add_screen {x = 330, y = 0, width = 320, height = 240} --DOC_HIDE
local p = awful.popup { --DOC_HIDE
widget = wibox.widget { --DOC_HIDE
text = "Parent wibox", --DOC_HIDE
forced_width = 100, --DOC_HIDE
forced_height = 50, --DOC_HIDE
widget = wibox.widget.textbox --DOC_HIDE
}, --DOC_HIDE
border_color = "#777777", --DOC_HIDE
border_width = 2, --DOC_HIDE
ontop = true, --DOC_HIDE
screen = screen[1], --DOC_HIDE
placement = awful.placement.top, --DOC_HIDE
} --DOC_HIDE
p:_apply_size_now() --DOC_HIDE
local p2 = awful.popup {
widget = wibox.widget {
text = "A popup",
forced_height = 100,
widget = wibox.widget.textbox
},
border_color = "#777777",
border_width = 2,
preferred_positions = "right",
preferred_anchors = {"front", "back"},
}
p2:move_next_to(p) --DOC_HIDE
local p3 = awful.popup { --DOC_HIDE
widget = wibox.widget { --DOC_HIDE
text = "Parent wibox2", --DOC_HIDE
forced_width = 100, --DOC_HIDE
forced_height = 50, --DOC_HIDE
widget = wibox.widget.textbox --DOC_HIDE
}, --DOC_HIDE
border_color = "#777777", --DOC_HIDE
border_width = 2, --DOC_HIDE
ontop = true, --DOC_HIDE
screen = screen[2], --DOC_HIDE
placement = awful.placement.bottom, --DOC_HIDE
} --DOC_HIDE
p3:_apply_size_now() --DOC_HIDE
local p4 = awful.popup {
widget = wibox.widget {
text = "A popup2",
forced_height = 100,
widget = wibox.widget.textbox
},
border_color = "#777777",
border_width = 2,
preferred_positions = "right",
screen = screen[2], --DOC_HIDE
preferred_anchors = {"front", "back"},
}
p4:move_next_to(p3) --DOC_HIDE
--DOC_HIDE vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80

View File

@ -0,0 +1,38 @@
--DOC_GEN_IMAGE --DOC_HIDE
local awful = { --DOC_HIDE --DOC_NO_USAGE
popup = require("awful.popup"), --DOC_HIDE
placement = require("awful.placement"), --DOC_HIDE
widget = {clienticon =require("awful.widget.clienticon"), --DOC_HIDE
tasklist = require("awful.widget.tasklist")} --DOC_HIDE
} --DOC_HIDE
local wibox = require("wibox") --DOC_HIDE
local p = awful.popup { --DOC_HIDE
widget = wibox.widget { --DOC_HIDE
text = "Parent wibox", --DOC_HIDE
forced_width = 100, --DOC_HIDE
forced_height = 100, --DOC_HIDE
widget = wibox.widget.textbox --DOC_HIDE
}, --DOC_HIDE
border_color = "#777777", --DOC_HIDE
border_width = 2, --DOC_HIDE
ontop = true, --DOC_HIDE
placement = awful.placement.centered, --DOC_HIDE
} --DOC_HIDE
p:_apply_size_now() --DOC_HIDE
for _, v in ipairs {"left", "right", "bottom", "top"} do
local p2 = awful.popup {
widget = wibox.widget {
text = "On the "..v,
widget = wibox.widget.textbox
},
border_color = "#777777",
border_width = 2,
preferred_positions = v,
ontop = true,
}
p2:move_next_to(p)
end
--DOC_HIDE vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80

View File

@ -0,0 +1,61 @@
--DOC_GEN_IMAGE --DOC_HIDE
local awful = { --DOC_HIDE --DOC_NO_USAGE
popup = require("awful.popup"), --DOC_HIDE
placement = require("awful.placement"), --DOC_HIDE
widget = {clienticon =require("awful.widget.clienticon"), --DOC_HIDE
tasklist = require("awful.widget.tasklist")} --DOC_HIDE
} --DOC_HIDE
local gears = { shape = require("gears.shape"), timer=require("gears.timer") } --DOC_HIDE
local wibox = require("wibox") --DOC_HIDE
local beautiful = require("beautiful") --DOC_HIDE
local p = awful.popup { --DOC_HIDE
widget = wibox.widget { --DOC_HIDE
{ text = "Item", widget = wibox.widget.textbox }, --DOC_HIDE
{ text = "Item", widget = wibox.widget.textbox }, --DOC_HIDE
{ text = "Item", widget = wibox.widget.textbox }, --DOC_HIDE
{ --DOC_HIDE
{ --DOC_HIDE
text = "Selected", --DOC_HIDE
widget = wibox.widget.textbox --DOC_HIDE
}, --DOC_HIDE
bg = beautiful.bg_highlight, --DOC_HIDE
widget = wibox.container.background --DOC_HIDE
}, --DOC_HIDE
{ text = "Item", widget = wibox.widget.textbox }, --DOC_HIDE
{ text = "Item", widget = wibox.widget.textbox }, --DOC_HIDE
forced_width = 100, --DOC_HIDE
widget = wibox.layout.fixed.vertical --DOC_HIDE
}, --DOC_HIDE
border_color = "#ff0000", --DOC_HIDE
border_width = 2, --DOC_HIDE
placement = awful.placement.centered, --DOC_HIDE
} --DOC_HIDE
p:_apply_size_now() --DOC_HIDE
awesome.emit_signal("refresh") --DOC_HIDE
p._drawable._do_redraw() --DOC_HIDE
--DOC_HIDE Necessary as the widgets are drawn later
gears.timer.delayed_call(function() --DOC_HIDE
-- Get the 4th textbox --DOC_HIDE
local list = p:find_widgets(30, 40) --DOC_HIDE
mouse.coords {x= 120, y=125} --DOC_HIDE
mouse.push_history() --DOC_HIDE
local textboxinstance = list[#list] --DOC_HIDE
for _, v in ipairs {"left", "right"} do
local p2 = awful.popup {
widget = wibox.widget {
text = "On the "..v,
forced_height = 100,
widget = wibox.widget.textbox
},
border_color = "#0000ff",
preferred_positions = v,
border_width = 2,
}
p2:move_next_to(textboxinstance, v)
end
end) --DOC_HIDE
--DOC_HIDE vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80

View File

@ -0,0 +1,34 @@
--DOC_GEN_IMAGE --DOC_HIDE
local awful = { --DOC_HIDE --DOC_NO_USAGE
popup = require("awful.popup"), --DOC_HIDE
placement = require("awful.placement"), --DOC_HIDE
widget = {clienticon =require("awful.widget.clienticon"), --DOC_HIDE
tasklist = require("awful.widget.tasklist")} --DOC_HIDE
} --DOC_HIDE
local wibox = require("wibox") --DOC_HIDE
local beautiful = require("beautiful") --DOC_HIDE
local previous = nil
for i=1, 5 do
local p2 = awful.popup {
widget = wibox.widget {
text = "Hello world! "..i.." aaaa.",
widget = wibox.widget.textbox
},
border_color = beautiful.border_color,
preferred_positions = "bottom",
border_width = 2,
preferred_anchors = "back",
placement = (not previous) and awful.placement.top or nil,
offset = {
y = 10,
},
}
p2:_apply_size_now() --DOC_HIDE
p2:move_next_to(previous)
previous = p2
previous:_apply_size_now() --DOC_HIDE
end
--DOC_HIDE vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80

View File

@ -0,0 +1,42 @@
--DOC_GEN_IMAGE --DOC_HIDE
local awful = { placement = require("awful.placement"), --DOC_HIDE
popup = require("awful.popup") } --DOC_HIDE --DOC_NO_USAGE
local gears = { shape = require("gears.shape") } --DOC_HIDE
local wibox = require("wibox") --DOC_HIDE
awful.popup {
widget = {
{
{
text = "foobar",
widget = wibox.widget.textbox
},
{
{
text = "foobar",
widget = wibox.widget.textbox
},
bg = "#ff00ff",
clip = true,
shape = gears.shape.rounded_bar,
widget = wibox.widget.background
},
{
value = 0.5,
forced_height = 30,
forced_width = 100,
widget = wibox.widget.progressbar
},
layout = wibox.layout.fixed.vertical,
},
margins = 10,
widget = wibox.container.margin
},
border_color = "#00ff00",
border_width = 5,
placement = awful.placement.top_left,
shape = gears.shape.rounded_rect,
visible = true,
}
--DOC_HIDE vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80

View File

@ -0,0 +1,247 @@
--DOC_GEN_IMAGE
--DOC_HIDE_ALL
--DOC_NO_USAGE
local awful = require("awful")
local gears = require("gears")
local wibox = require("wibox")
local beautiful = require("beautiful") --DOC_HIDE
screen[1]._resize {width = 640, height = 480}
-- This example is used to show the various type of wibox awesome provides
-- and mimic the default config look
local c = client.gen_fake {hide_first=true}
c:geometry {
x = 50,
y = 350,
height = 100,
width = 150,
}
c._old_geo = {c:geometry()}
c:set_label("A client")
local wb = awful.wibar {
position = "top",
}
-- Create the same number of tags as the default config
awful.tag({ "1", "2", "3", "4", "5", "6", "7", "8", "9" }, screen[1], awful.layout.layouts[1])
-- Only bother with widgets that are visible by default
local mykeyboardlayout = awful.widget.keyboardlayout()
local mytextclock = wibox.widget.textclock()
local mylayoutbox = awful.widget.layoutbox(screen[1])
local mytaglist = awful.widget.taglist(screen[1], awful.widget.taglist.filter.all, {})
local mytasklist = awful.widget.tasklist(screen[1], awful.widget.tasklist.filter.currenttags, {})
wb:setup {
layout = wibox.layout.align.horizontal,
{ -- Left widgets
layout = wibox.layout.fixed.horizontal,
awful.titlebar.widget.iconwidget(c), --looks close enough
mytaglist,
},
mytasklist, -- Middle widget
{ -- Right widgets
layout = wibox.layout.fixed.horizontal,
mykeyboardlayout,
mytextclock,
mylayoutbox,
},
}
-- The popup
awful.popup {
widget = wibox.widget {
--TODO use the layoutlist for this example
awful.widget.taglist {
filter = awful.widget.taglist.filter.all,
screen = 1,
base_layout = wibox.widget {
spacing = 5,
forced_num_cols = 5,
layout = wibox.layout.grid.vertical,
},
widget_template = {
{
--TODO use the layoutlist for this example
-- {
-- id = 'icon_role',
-- forced_height = 22,
-- forced_width = 22,
-- widget = wibox.widget.imagebox,
-- },
{
id = "text_role",
forced_height = 22,
forced_width = 22,
widget = wibox.widget.textbox
},
margins = 4,
widget = wibox.container.margin,
},
id = 'background_role',
forced_width = 24,
forced_height = 24,
shape = gears.shape.rounded_rect,
widget = wibox.container.background,
},
},
margins = 4,
widget = wibox.container.margin,
},
border_color = beautiful.border_color,
border_width = beautiful.border_width,
placement = awful.placement.centered,
ontop = true,
shape = gears.shape.rounded_rect
}
-- poor copy of awful.widget.calendar_widget until I fix its API to be less
-- insane.
local p10 = awful.popup {
widget = {
wibox.widget.calendar.month(os.date('*t')),
top = 30,
margins = 10,
layout = wibox.container.margin
},
preferred_anchors = "middle",
border_width = 2,
border_color = beautiful.border_color,
hide_on_right_click = true,
placement = function(d) return awful.placement.top_right(d, {
honor_workarea = true,
}) end,
shape = gears.shape.infobubble,
}
awesome.emit_signal("refresh")
p10:bind_to_widget(mytextclock)
-- The titlebar
local top_titlebar = awful.titlebar(c, {
height = 20,
bg_normal = "#ff0000",
})
top_titlebar : setup {
{ -- Left
awful.titlebar.widget.iconwidget(c),
layout = wibox.layout.fixed.horizontal
},
{ -- Middle
{ -- Title
align = "center",
widget = awful.titlebar.widget.titlewidget(c)
},
layout = wibox.layout.flex.horizontal
},
{ -- Right
awful.titlebar.widget.floatingbutton (c),
awful.titlebar.widget.maximizedbutton(c),
awful.titlebar.widget.stickybutton (c),
awful.titlebar.widget.ontopbutton (c),
awful.titlebar.widget.closebutton (c),
layout = wibox.layout.fixed.horizontal()
},
layout = wibox.layout.align.horizontal
}
-- Normal wiboxes
wibox {
width = 50,
height = 50,
shape = gears.shape.octogon,
color = "#0000ff",
x = 570,
y = 410,
border_width = 2,
border_color = beautiful.border_color,
}
-- The tooltip
mouse.coords{x=50, y= 100}
mouse.push_history()
local tt = awful.tooltip {
text = "A tooltip!",
visible = true,
}
tt.bg = beautiful.bg_normal
-- Extra information overlay
local overlay_w = wibox {
bg = "#00000000",
visible = true,
ontop = true,
}
awful.placement.maximize(overlay_w)
local canvas = wibox.layout.manual()
canvas.forced_height = 480
canvas.forced_width = 640
overlay_w:set_widget(canvas)
local function create_info(text, x, y, width, height)
canvas:add_at(wibox.widget {
{
{
text = text,
align = "center",
ellipsize = "none",
widget = wibox.widget.textbox
},
margins = 10,
widget = wibox.container.margin
},
forced_width = width,
forced_height = height,
shape = gears.shape.rectangle,
shape_border_width = 1,
shape_border_color = beautiful.border_color,
bg = "#ffff0055",
widget = wibox.container.background
}, {x = x, y = y})
end
local function create_line(x1, y1, x2, y2)
return canvas:add_at(wibox.widget {
fit = function()
return x2-x1+6, y2-y1+6
end,
draw = function(_, _, cr)
cr:set_source_rgb(0,0,0)
cr:set_line_width(1)
cr:arc(1.5, 1.5, 1.5, 0, math.pi*2)
cr:arc(x2-x1+1.5, y2-y1+1.5, 1.5, 0, math.pi*2)
cr:fill()
cr:move_to(1.5,1.5)
cr:line_to(x2-x1+1.5, y2-y1+1.5)
cr:stroke()
end,
layout = wibox.widget.base.make_widget,
}, {x=x1, y=y1})
end
create_info("awful.wibar", 200, 50, 100, 30)
create_info("awful.titlebar", 250, 350, 100, 30)
create_info("awful.tooltip", 30, 130, 100, 30)
create_info("awful.popup", 450, 240, 100, 30)
create_info("Standard `wibox1`", 420, 420, 130, 30)
create_line(250, 10, 250, 55)
create_line(75, 100, 75, 135)
create_line(545, 432, 575, 432)
create_line(500, 165, 500, 245)
create_line(390, 250, 450, 250)
create_line(190, 365, 255, 365)
--DOC_HIDE vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80