diff --git a/objects/client.c b/objects/client.c
index 38a45cd6..7bb2d1f3 100644
--- a/objects/client.c
+++ b/objects/client.c
@@ -82,6 +82,8 @@
* To get all the clients for a screen use either `screen.clients` or
* `screen.tiled_clients`.
*
+ * @DOC_uml_nav_tables_client_EXAMPLE@
+ *
* @author Julien Danjou <julien@danjou.info>
* @copyright 2008-2009 Julien Danjou
* @coreclassmod client
@@ -129,7 +131,7 @@
* it is only useful when setting or getting these properties require code to
* executed.
*
- * @table awful.object
+ * @table awful.client.object
*/
/** When a client gains focus.
diff --git a/objects/screen.c b/objects/screen.c
index 05e82375..a5183ab9 100644
--- a/objects/screen.c
+++ b/objects/screen.c
@@ -40,6 +40,8 @@
* Furthermore to the classes described here, one can also use signals as
* described in @{signals}.
*
+ * @DOC_uml_nav_tables_screen_EXAMPLE@
+ *
* @author Julien Danjou <julien@danjou.info>
* @copyright 2008-2009 Julien Danjou
* @coreclassmod screen
diff --git a/objects/tag.c b/objects/tag.c
index 401a66a5..3f0dd75b 100644
--- a/objects/tag.c
+++ b/objects/tag.c
@@ -178,6 +178,8 @@
* the documentation generation, you get the real signal name by
* removing the starting dot.
*
+ * @DOC_uml_nav_tables_tag_EXAMPLE@
+ *
* @author Julien Danjou <julien@danjou.info>
* @copyright 2008-2009 Julien Danjou
* @coreclassmod tag
diff --git a/tests/examples/uml/nav_tables/client.lua b/tests/examples/uml/nav_tables/client.lua
new file mode 100644
index 00000000..e46a04d9
--- /dev/null
+++ b/tests/examples/uml/nav_tables/client.lua
@@ -0,0 +1,101 @@
+--DOC_GEN_OUTPUT --DOC_NO_USAGE --DOC_HIDE_ALL --DOC_ASTERISK --DOC_RAW_OUTPUT --DOC_GEN_IMAGE
+local module = ...
+
+module.generate_nav_table {
+ class = "client",
+ content = {
+ {
+ association = "aggregation",
+ class = "tag",
+ to_property = "c.tags",
+ from_property = "t:clients()",
+ left = {
+ msg = "Is tagged on",
+ card = "1..N",
+ },
+ right = {
+ msg = "Attached to",
+ card = "0..N",
+ },
+ },
+ {
+ association = "aggregation",
+ class = "screen",
+ to_property = "c.screen",
+ from_property = "s.clients",
+ left = {
+ msg = "Is on",
+ card = "1..1",
+ },
+ right = {
+ msg = "Has",
+ card = "0..N",
+ },
+ },
+ {
+ association = "aggregation",
+ class = "screen",
+ from_property = "s.hidden_clients",
+ left = {
+ msg = "Is on",
+ card = "1..1",
+ },
+ right = {
+ msg = "Has",
+ card = "0..N",
+ },
+ },
+ {
+ association = "aggregation",
+ class = "screen",
+ from_property = "s.tiled_clients",
+ left = {
+ msg = "Is on",
+ card = "1..1",
+ },
+ right = {
+ msg = "Has",
+ card = "0..N",
+ },
+ },
+ {
+ association = "aggregation",
+ class = "awful.key",
+ to_property = "c:keys()",
+ left = {
+ msg = "Has",
+ card = "0..N",
+ },
+ right = {
+ msg = "Attached to",
+ card = "0..N",
+ },
+ },
+ {
+ association = "aggregation",
+ class = "awful.button",
+ to_property = "c:buttons()",
+ left = {
+ msg = "Has",
+ card = "0..N",
+ },
+ right = {
+ msg = "Attached to",
+ card = "0..N",
+ },
+ },
+ {
+ association = "aggregation",
+ class = "mouse",
+ from_property = "mouse.current_client",
+ left = {
+ msg = "Is below",
+ card = "0..1",
+ },
+ right = {
+ msg = "Is over",
+ card = "0..1",
+ },
+ },
+ }
+}
diff --git a/tests/examples/uml/nav_tables/client.output.txt b/tests/examples/uml/nav_tables/client.output.txt
new file mode 100644
index 00000000..65bc1681
--- /dev/null
+++ b/tests/examples/uml/nav_tables/client.output.txt
@@ -0,0 +1,77 @@
+
+
+Core components relationship
+===
+
+
+ |
+ |
+
+
+ Legend: c: a client object, t: a tag object,
+ s: a screen object, k: an awful.key object,
+ b: a awful.button object, n: a naughty.notification object
+ |
+
+
diff --git a/tests/examples/uml/nav_tables/screen.lua b/tests/examples/uml/nav_tables/screen.lua
new file mode 100644
index 00000000..4e80253f
--- /dev/null
+++ b/tests/examples/uml/nav_tables/screen.lua
@@ -0,0 +1,101 @@
+--DOC_GEN_OUTPUT --DOC_NO_USAGE --DOC_HIDE_ALL --DOC_ASTERISK --DOC_RAW_OUTPUT --DOC_GEN_IMAGE
+local module = ...
+
+module.generate_nav_table {
+ class = "screen",
+ content = {
+ {
+ association = "aggregation",
+ class = "tag",
+ to_property = "s.tags",
+ from_property = "t.screen",
+ left = {
+ msg = "Has",
+ card = "0..N",
+ },
+ right = {
+ msg = "Attached to",
+ card = "1..1",
+ },
+ },
+ {
+ association = "composition",
+ class = "tag",
+ to_property = "s.selected_tag",
+ left = {
+ msg = "Has",
+ card = "0..1",
+ },
+ right = {
+ msg = "Is on",
+ card = "1..1",
+ },
+ },
+ {
+ association = "composition",
+ class = "tag",
+ to_property = "s.selected_tags",
+ left = {
+ msg = "Has",
+ card = "0..N",
+ },
+ right = {
+ msg = "Is on",
+ card = "1..1",
+ },
+ },
+ {
+ association = "aggregation",
+ class = "client",
+ from_property = "c.screen",
+ to_property = "s.clients",
+ left = {
+ msg = "Has",
+ card = "0..N",
+ },
+ right = {
+ msg = "Is on",
+ card = "1..1",
+ },
+ },
+ {
+ association = "aggregation",
+ class = "client",
+ to_property = "s.hidden_clients",
+ left = {
+ msg = "Has",
+ card = "1..1",
+ },
+ right = {
+ msg = "Is on",
+ card = "1..1",
+ },
+ },
+ {
+ association = "aggregation",
+ class = "client",
+ to_property = "s.tiled_clients",
+ left = {
+ msg = "Has",
+ card = "0..N",
+ },
+ right = {
+ msg = "Has",
+ card = "1..1",
+ },
+ },
+ {
+ association = "aggregation",
+ class = "naughty.notification",
+ from_property = "n.screen",
+ left = {
+ msg = "Displays",
+ card = "0..N",
+ },
+ right = {
+ msg = "Is displayed on",
+ card = "1..N",
+ },
+ },
+ }
+}
diff --git a/tests/examples/uml/nav_tables/screen.output.txt b/tests/examples/uml/nav_tables/screen.output.txt
new file mode 100644
index 00000000..d7b30785
--- /dev/null
+++ b/tests/examples/uml/nav_tables/screen.output.txt
@@ -0,0 +1,77 @@
+
+
+Core components relationship
+===
+
+
+ |
+ |
+
+
+ Legend: c: a client object, t: a tag object,
+ s: a screen object, k: an awful.key object,
+ b: a awful.button object, n: a naughty.notification object
+ |
+
+
diff --git a/tests/examples/uml/nav_tables/tag.lua b/tests/examples/uml/nav_tables/tag.lua
new file mode 100644
index 00000000..6637c617
--- /dev/null
+++ b/tests/examples/uml/nav_tables/tag.lua
@@ -0,0 +1,62 @@
+--DOC_GEN_OUTPUT --DOC_NO_USAGE --DOC_HIDE_ALL --DOC_ASTERISK --DOC_RAW_OUTPUT --DOC_GEN_IMAGE
+local module = ...
+
+module.generate_nav_table {
+ class = "tag",
+ content = {
+ {
+ association = "aggregation",
+ class = "client",
+ from_property = "c.tags",
+ to_property = "t:clients()",
+ right = {
+ msg = "Is tagged on",
+ card = "1..N",
+ },
+ left = {
+ msg = "Has",
+ card = "0..N",
+ },
+ },
+ {
+ association = "composition",
+ class = "screen",
+ to_property = "t.screen",
+ from_property = "s.tags",
+ left = {
+ msg = "Is displayed on",
+ card = "1..1",
+ },
+ right = {
+ msg = "Has",
+ card = "0..N",
+ },
+ },
+ {
+ association = "composition",
+ class = "screen",
+ from_property = "s.selected_tag",
+ left = {
+ msg = "Is on",
+ card = "1..1",
+ },
+ right = {
+ msg = "Has",
+ card = "0..N",
+ },
+ },
+ {
+ association = "composition",
+ class = "screen",
+ from_property = "s.selected_tags",
+ left = {
+ msg = "Is on",
+ card = "1..1",
+ },
+ right = {
+ msg = "Has",
+ card = "0..N",
+ },
+ },
+ }
+}
diff --git a/tests/examples/uml/nav_tables/tag.output.txt b/tests/examples/uml/nav_tables/tag.output.txt
new file mode 100644
index 00000000..55b9ac22
--- /dev/null
+++ b/tests/examples/uml/nav_tables/tag.output.txt
@@ -0,0 +1,62 @@
+
+
+Core components relationship
+===
+
+
+ |
+ |
+
+
+ Legend: c: a client object, t: a tag object,
+ s: a screen object, k: an awful.key object,
+ b: a awful.button object, n: a naughty.notification object
+ |
+
+
diff --git a/tests/examples/uml/template.lua b/tests/examples/uml/template.lua
new file mode 100644
index 00000000..1b24ede4
--- /dev/null
+++ b/tests/examples/uml/template.lua
@@ -0,0 +1,228 @@
+local file_path, image_path = ...
+require("_common_template")(...)
+local cairo = require("lgi").cairo
+local shape = require("gears.shape")
+local wibox = require("wibox")
+local beautiful = require("beautiful")
+
+-- Make the path relative.
+image_path = "../" .. image_path:match("/(images/[^/]+)$")
+
+-- This template generates an HTML table with how other classes are associated
+-- with a given class.
+
+local function gen_class(name)
+ return wibox.widget {
+ {
+ {
+ {
+ valign = "center",
+ align = "center",
+ markup = ""..name.."",
+ widget = wibox.widget.textbox
+ },
+ fg = "#ffffff",
+ bg = beautiful.bg_normal,
+ widget = wibox.container.background,
+ },
+ nil,
+ nil,
+ widget = wibox.layout.align.vertical,
+ },
+ shape = function(cr,w,h)
+ shape.partially_rounded_rect(cr,w,h, true,true,false,false,5)
+ end,
+ forced_width = 75,
+ border_width = 1,
+ border_strategy = "inner",
+ border_color = beautiful.border_color,
+ bg = "#00000000",
+ widget = wibox.container.background
+ }
+end
+
+local function gen_arrow(association)
+ local w = wibox.widget.base.make_widget()
+
+ function w:fit(_, width, _)
+ return width, 15
+ end
+
+ function w:draw(_, cr, width, height)
+ cr:set_line_width(1.5)
+ cr:move_to(0, height/2)
+ cr:line_to(width-(association == "association" and 0 or 40), height/2)
+ cr:stroke()
+
+ if association ~= "association" then
+ cr:set_antialias(cairo.ANTIALIAS_SUBPIXEL)
+ cr:set_line_width(1)
+ cr:translate(0,2)
+ width, height = width-2, height-4
+ cr:move_to(width-40, height/2)
+ cr:line_to(width-20, 0 )
+ cr:line_to(width , height/2)
+ cr:line_to(width-20, height )
+ cr:line_to(width-40, height/2)
+ cr:close_path()
+
+ if association == "composition" then
+ cr:fill()
+ else
+ cr:stroke()
+ end
+ end
+ end
+
+ w.forced_height = 15
+
+ return w
+end
+
+local function arrow_widget(dir)
+ local w = wibox.widget.base.make_widget()
+
+ function w:fit(_, width, _)
+ return width, 5
+ end
+
+ function w:draw(_, cr, width, height)
+
+ cr:translate(10, 0)
+ width = width - 20
+
+ cr:set_source_rgba(0,0,0,0.2)
+ cr:set_line_width(1)
+ cr:move_to(0, height/2)
+ cr:line_to(width,height/2)
+ cr:stroke()
+
+ if dir == "left" then
+ cr:move_to(height/2, 0)
+ cr:line_to(0, height/2)
+ cr:line_to(height/2, height)
+ cr:stroke()
+ else
+ cr:move_to(width-height/2, 0)
+ cr:line_to(width, height/2)
+ cr:line_to(width-height/2, height)
+ cr:stroke()
+ end
+ end
+
+ return w
+end
+
+local function gen_table_uml(entry, class1, class2, revert)
+ local left = revert and entry.right or entry.left
+ local right = revert and entry.left or entry.right
+
+ return wibox.widget {
+ gen_class(class2),
+ {
+ {
+ {
+ text = " "..left.card,
+ widget = wibox.widget.textbox
+ },
+ arrow_widget "left",
+ {
+ wrap = "char",
+ markup = left.msg.." .",
+ widget = wibox.widget.textbox
+ },
+ spacing = 5,
+ layout = wibox.layout.align.horizontal
+ },
+ gen_arrow(entry.composition),
+ {
+ {
+ wrap = "char",
+ markup = right.msg.." .",
+ widget = wibox.widget.textbox
+ },
+ arrow_widget "right",
+ {
+ text = right.card.." ",
+ widget = wibox.widget.textbox
+ },
+ spacing = 5,
+ layout = wibox.layout.align.horizontal
+ },
+ layout = wibox.layout.fixed.vertical,
+ },
+ gen_class(class1),
+ layout = wibox.layout.align.horizontal
+ }
+end
+
+local map = {
+ to = function(o) return "Acquire other objects from a "..o end,
+ from = function(o) return "Acquire a "..o.." from other objects" end
+}
+
+local function gen_table_header(title, o)
+ print([[ | '
+end
+
+local module = {}
+
+local counter = 1
+
+function module.generate_nav_table(t)
+ assert(t.content and t.class)
+
+ print("\n\nCore components relationship\n===\n")
+ print ''
+
+ -- Validate early to avoid debugging cryptic backtraces.
+ for _, tab in ipairs {"to", "from"} do
+ gen_table_header(tab, t.class)
+ for _, entry in ipairs(t.content) do
+ if entry[tab.."_property"] then
+ assert(entry.left and entry.right and entry.association)
+ assert(entry.class)
+ assert(entry.left.msg and entry.left.card)
+ assert(entry.right.msg and entry.right.card)
+ local path = image_path..counter..".svg"
+ local widget = gen_table_uml(entry, t.class, entry.class, false)
+ wibox.widget.draw_to_svg_file(widget, path, 320, 50)
+ get_table_row(path, entry.class, entry[tab.."_property"])
+ counter = counter + 1
+ end
+ end
+ get_table_footer()
+ end
+ print([[
+
+ Legend: c: a client object, t: a tag object,
+ s: a screen object, k: an awful.key object,
+ b: a awful.button object, n: a naughty.notification object
+ |
+
+
]])
+end
+
+loadfile(file_path)(module)
+
+-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80