From 7acb30de712e3a7f2f9b564bc8acc67c85656fac Mon Sep 17 00:00:00 2001 From: Uli Schlachter Date: Sun, 21 Jun 2015 14:27:44 +0200 Subject: [PATCH] Documentation overhaul for wibox.widget.base Signed-off-by: Uli Schlachter --- lib/wibox/widget/base.lua | 129 +++++++++++++++++++++++++++++++++++--- 1 file changed, 119 insertions(+), 10 deletions(-) diff --git a/lib/wibox/widget/base.lua b/lib/wibox/widget/base.lua index 22b612a7..7ebd9a05 100644 --- a/lib/wibox/widget/base.lua +++ b/lib/wibox/widget/base.lua @@ -2,7 +2,7 @@ -- @author Uli Schlachter -- @copyright 2010 Uli Schlachter -- @release @AWESOME_VERSION@ --- @classmod wibox.widget.base +-- @module wibox.widget.base --------------------------------------------------------------------------- local debug = require("gears.debug") @@ -91,7 +91,8 @@ function base:buttons(_buttons) return self.widget_buttons end ---- Handle a button event on a widget. This is used internally. +-- Handle a button event on a widget. This is used internally and should not be +-- called directly. function base.handle_button(event, widget, x, y, button, modifiers, geometry) local function is_any(mod) return #mod == 1 and mod[1] == "Any" @@ -129,7 +130,7 @@ function base.handle_button(event, widget, x, y, button, modifiers, geometry) end --- Create widget placement information. This should be used for a widget's --- :layout() callback. +-- `:layout()` callback. -- @param widget The widget that should be placed. -- @param mat A cairo matrix transforming from the parent widget's coordinate -- system. For example, use cairo.Matrix.create_translate(1, 2) to draw a @@ -149,7 +150,7 @@ function base.place_widget_via_matrix(widget, mat, width, height) end --- Create widget placement information. This should be used for a widget's --- :layout() callback. +-- `:layout()` callback. -- @param widget The widget that should be placed. -- @param x The x coordinate for the widget. -- @param y The y coordinate for the widget. @@ -162,12 +163,120 @@ function base.place_widget_at(widget, x, y, width, height) return base.place_widget_via_matrix(widget, Matrix.create_translate(x, y), width, height) end ---- Create a new widget. All widgets have to be generated via this function so --- that the needed signals are added and mouse input handling is set up. --- @param proxy If this is set, the returned widget will be a proxy for this --- widget. It will be equivalent to this widget. --- @tparam[opt] string widget_name Name of the widget. If not set, it will be --- set automatically via `gears.object.modulename`. +--[[-- +Create a new widget. All widgets have to be generated via this function so that +the needed signals are added and mouse input handling is set up. + +The returned widget will have a :buttons member function that can be used to +register a set of mouse button events with the widget. + +To implement your own widget, you can implement some member functions on a +freshly-created widget. Note that all of these functions should be deterministic +in the sense that they will show the same behavior if they are repeatedly called +with the same arguments (same width and height). If your widget is updated and +needs to change, suitable signals have to be emitted. This will be explained +later. + +The first callback is :fit. This function is called to select the size of your +widget. The arguments to this function is the available space and it should +return its desired size. Note that this function only provides a hint which is +not necessarily followed. The widget must also be able to draw itself at +different sizes than the one requested. +
function widget:fit(context, width, height)
+  -- Find the maximum square available
+  local m = math.min(width, height)
+  return m, m
+end
+ +The next callback is :draw. As the name suggests, this function is called to +draw the widget. The arguments to this widget are the context that the widget is +drawn in, the cairo context on which it should be drawn and the widget's size. +The cairo context is set up in such a way that the widget as its top-left corner +at (0, 0) and its bottom-right corner at (width, height). In other words, no +special transformation needs to be done. Note that during this callback a +suitable clip will already be applied to the cairo context so that this callback +will not be able to draw outside of the area that was registered for the widget +by the layout that placed this widget. You should not call +cr:reset_clip(), as redraws will not be handled correctly in this +case. +
function widget:draw(wibox, cr, width, height)
+    cr:move_to(0, 0)
+    cr:line_to(width, height)
+    cr:move_to(0, height)
+    cr:line_to(width, 0)
+    cr:stroke()
+end
+ +There are two signals configured for a widget. When the result that :fit would +return changes, the widget::layout_changed signal has to be +emitted. If this actually causes layout changes, the affected areas will be +redrawn. The other signal is widget::redraw_needed. This signal +signals that :draw has to be called to redraw the widget, but it is safe to +assume that :fit does still return the same values as before. If in doubt, you +can emit both signals to be safe. + +If your widget only needs to draw something to the screen, the above is all that +is needed. The following callbacks can be used when implementing layouts which +place other widgets on the screen. + +The :layout callback is used to figure out which other widgets should be drawn +relative to this widget. Note that it is allowed to place widgets outside of the +extents of your own widget, for example at a negative position or at twice the +size of this widget. Use this mechanism if your widget needs to draw outside of +its own extents. If the result of this callback changes, +widget::layout_changed has to be emitted. You can use @{fit_widget} +to call the `:fit` callback of other widgets. Never call `:fit` directly! For +example, if you want to place another widget child inside of your +widget, you can do it like this: +
-- For readability
+local base = wibox.widget.base
+function widget:layout(width, height)
+    local result = {}
+    table.insert(result, base.place_widget_at(child, width/2, 0, width/2, height)
+    return result
+end
+ +Finally, if you want to influence how children are drawn, there are four +callbacks available that all get similar arguments: +
function widget:before_draw_children(context, cr, width, height)
+function widget:after_draw_children(context, cr, width, height)
+function widget:before_draw_child(context, index, child, cr, width, height)
+function widget:after_draw_child(context, index, child, cr, width, height)
+ +All of these are called with the same arguments as the :draw() method. Please +note that a larger clip will be active during these callbacks that also contains +the area of all children. These callbacks can be used to influence the way in +which children are drawn, but they should not cause the drawing to cover a +different area. As an example, these functions can be used to draw children +translucently: +
function widget:before_draw_children(wibox, cr, width, height)
+    cr:push_group()
+end
+function widget:after_draw_children(wibox, cr, width, height)
+    cr:pop_group_to_source()
+    cr:paint_with_alpha(0.5)
+end
+ +In pseudo-code, the call sequence for the drawing callbacks during a redraw +looks like this: +
widget:draw(wibox, cr, width, height)
+widget:before_draw_children(wibox, cr, width, height)
+for child do
+    widget:before_draw_child(wibox, cr, child_index, child, width, height)
+    cr:save()
+    -- Draw child and all of its children recursively, taking into account the
+    -- position and size given to base.place_widget_at() in :layout().
+    cr:restore()
+    widget:after_draw_child(wibox, cr, child_index, child, width, height)
+end
+widget:after_draw_children(wibox, cr, width, height)
+@param proxy If this is set, the returned widget will be a proxy for this + widget. It will be equivalent to this widget. This means it + looks the same on the screen. +@tparam[opt] string widget_name Name of the widget. If not set, it will be + set automatically via `gears.object.modulename`. +@see fit_widget +--]]-- function base.make_widget(proxy, widget_name) local ret = object()