Merge pull request #923 from Elv13/widget_api_refactor

Widget api refactor
This commit is contained in:
Emmanuel Lepage Vallée 2016-05-30 23:22:40 -04:00
commit fc659b79ce
95 changed files with 3572 additions and 2285 deletions

View File

@ -84,14 +84,14 @@ install:
- travis_retry sudo luarocks install lua-discount - travis_retry sudo luarocks install lua-discount
# Instal luacov-coveralls for code coverage testing. # Instal luacov-coveralls for code coverage testing.
- if [ "$DO_COVERAGE" = "true" ]; then sudo luarocks install luacov-coveralls; fi - if [ "$DO_COVERAGE" = "true" ]; then sudo luarocks install luacov-coveralls; else export DO_COVERAGE=0; fi
# Determine custom version. # Determine custom version.
- export AWESOME_VERSION="${TRAVIS_BRANCH}-g$(git rev-parse --short HEAD)" - export AWESOME_VERSION="${TRAVIS_BRANCH}-g$(git rev-parse --short HEAD)"
- 'if [ "$TRAVIS_PULL_REQUEST" != false ]; then AWESOME_VERSION="${AWESOME_VERSION}-PR${TRAVIS_PULL_REQUEST}"; fi' - 'if [ "$TRAVIS_PULL_REQUEST" != false ]; then AWESOME_VERSION="${AWESOME_VERSION}-PR${TRAVIS_PULL_REQUEST}"; fi'
script: script:
- export CMAKE_ARGS="-DLUA_LIBRARY=${LUALIBRARY} -DLUA_INCLUDE_DIR=${LUAINCLUDE} -D OVERRIDE_VERSION=$AWESOME_VERSION" - export CMAKE_ARGS="-DLUA_LIBRARY=${LUALIBRARY} -DLUA_INCLUDE_DIR=${LUAINCLUDE} -D OVERRIDE_VERSION=$AWESOME_VERSION -D DO_COVERAGE=${DO_COVERAGE}"
- | - |
if [ -n "$BUILD_IN_DIR" ]; then if [ -n "$BUILD_IN_DIR" ]; then
SOURCE_DIRECTORY="$PWD" SOURCE_DIRECTORY="$PWD"

View File

@ -300,13 +300,13 @@ if(GENERATE_DOC)
# Load the common documentation # Load the common documentation
include(docs/load_ldoc.cmake) include(docs/load_ldoc.cmake)
# Generate some images and examples
include(docs/generate_examples.cmake)
# Use `include`, rather than `add_subdirectory`, to keep the variables # Use `include`, rather than `add_subdirectory`, to keep the variables
# The file is a valid CMakeLists.txt and can be executed directly if only # The file is a valid CMakeLists.txt and can be executed directly if only
# the image artefacts are needed. # the image artefacts are needed.
include(tests/examples/CMakeLists.txt) include(tests/examples/CMakeLists.txt)
# Generate the widget lists
include(docs/widget_lists.cmake)
endif() endif()
# {{{ Configure files # {{{ Configure files
@ -345,8 +345,18 @@ set(AWESOME_ADDITIONAL_FILES
foreach(file ${AWESOME_ADDITIONAL_FILES}) foreach(file ${AWESOME_ADDITIONAL_FILES})
configure_file(${SOURCE_DIR}/${file} configure_file(${SOURCE_DIR}/${file}
${BUILD_DIR}/${file} ${BUILD_DIR}/${file}
COPYONLY) @ONLY)
endforeach() endforeach()
#}}} #}}}
# The examples coverage need to be done again after the configure_file has
# inserted the additional code. Otherwise, the result will be off, rendering
# the coverage useless as a tool to track untested code.
if(GENERATE_DOC AND DO_COVERAGE)
message(STATUS "Running tests again with coverage")
set(USE_LCOV 1)
include(tests/examples/CMakeLists.txt)
endif()
# vim: filetype=cmake:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80:foldmethod=marker # vim: filetype=cmake:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80:foldmethod=marker

View File

@ -115,7 +115,7 @@ mykeyboardlayout = awful.widget.keyboardlayout()
-- {{{ Wibox -- {{{ Wibox
-- Create a textclock widget -- Create a textclock widget
mytextclock = awful.widget.textclock() mytextclock = wibox.widget.textclock()
-- Create a wibox for each screen and add it -- Create a wibox for each screen and add it
mywibox = {} mywibox = {}

View File

@ -3,7 +3,35 @@
This system provide an alternative to the system used in Awesome 3.5 and is This system provide an alternative to the system used in Awesome 3.5 and is
inspired by the one once used by Awesome 3.2-3.4 and Qt QML system. inspired by the one once used by Awesome 3.2-3.4 and Qt QML system.
## A simple layout ## The default widgets
### Widgets
Awesome provide 2 collections of widgets:
* `wibox.widget`: Generic widgets, containers and layouts
* `awful.widget`: The Awesome specific widgets
@DOC_widget_WIDGET_LIST@
### Containers
Containers are widget wrapping another widget. It can be used to add decorations
or to modify the content of the child widget.
@DOC_container_WIDGET_LIST@
### Layouts
Layouts are collection of children widgets. They place them according to rules
and usually provide some options.
@DOC_layout_WIDGET_LIST@
## Placing widgets
### A simple layout
* Display `my_first_widget` only on screen one * Display `my_first_widget` only on screen one
* Add a background color to `my_third_widget` * Add a background color to `my_third_widget`
@ -17,7 +45,7 @@ Code:
{ -- Add a background color/pattern for my_third_widget { -- Add a background color/pattern for my_third_widget
my_third_widget, my_third_widget,
bg = beautiful.bg_focus, bg = beautiful.bg_focus,
widget = wibox.widget.background, widget = wibox.container.background,
}, },
layout = wibox.layout.fixed.horizontal, layout = wibox.layout.fixed.horizontal,
} }
@ -29,12 +57,12 @@ logic expression can be used as long as it return a valid widget, or a
declarative layout, or `nil`. declarative layout, or `nil`.
## Define widgets inline and place them ### Define widgets inline and place them
* Create a `wibox.widget.textbox` with various properties * Create a `wibox.widget.textbox` with various properties
* Force the textbox size using `wibox.layout.constraint` * Force the textbox size using `wibox.layout.constraint`
* Add a margin around another textbox * Add a margin around another textbox
* Add a `wibox.widget.background` (for visualization) * Add a `wibox.container.background` (for visualization)
Code: Code:
@ -48,7 +76,7 @@ Code:
widget = wibox.widget.textbox widget = wibox.widget.textbox
}, },
bg = "#ff0000", bg = "#ff0000",
widget = wibox.widget.background, widget = wibox.container.background,
}, },
width = 300, width = 300,
strategy = "min", strategy = "min",
@ -62,13 +90,13 @@ Code:
widget = wibox.widget.textbox widget = wibox.widget.textbox
}, },
bg = "#0000ff", bg = "#0000ff",
widget = wibox.widget.background widget = wibox.container.background
}, },
left = 10, left = 10,
right = 10, right = 10,
top = 1, top = 1,
bottom = 2, bottom = 2,
layout = wibox.layout.margin layout = wibox.container.margin
}, },
layout = wibox.layout.fixed.horizontal, layout = wibox.layout.fixed.horizontal,
} }
@ -78,7 +106,7 @@ Result:
![Example2 screenshot](../images/widgetlayout1.png) ![Example2 screenshot](../images/widgetlayout1.png)
## Use an `wibox.layout.align` layout ### Use an `wibox.layout.align` layout
The `wibox.layout.align` is a little different. While most layouts will The `wibox.layout.align` is a little different. While most layouts will
ignore any `nil` lines, the `align` layout rely on them so `left`, `middle` ignore any `nil` lines, the `align` layout rely on them so `left`, `middle`
and `right` can be defined and `right` can be defined
@ -94,7 +122,7 @@ Code:
## Define new widgets ### Define new widgets
New trivial widgets can be created directly in the layout declaration. Here New trivial widgets can be created directly in the layout declaration. Here
is a simple circle widget: is a simple circle widget:
@ -126,7 +154,7 @@ For more information about how to draw widgets, refer to the `Cairo` api:
* [Pango text](https://developer.gnome.org/pango/stable/) * [Pango text](https://developer.gnome.org/pango/stable/)
## Externally defined widgets and layouts ### Externally defined widgets and layouts
This is useful when the widget is provided by an external module or when it This is useful when the widget is provided by an external module or when it
requires complex manipulations which would make the declaration unreadable. requires complex manipulations which would make the declaration unreadable.
@ -146,7 +174,7 @@ Code:
## Accessing widgets ### Accessing widgets
For each widget or container, it is possible to add an `identifier` attribute For each widget or container, it is possible to add an `identifier` attribute
so the widget can be accessed later. so the widget can be accessed later.
@ -188,7 +216,7 @@ Code:
## Extending the system ### Extending the system
This system is very flexible. Each section attribute (the entries with string This system is very flexible. Each section attribute (the entries with string
keys) is directly linked to the layout or widget API. When setting the keys) is directly linked to the layout or widget API. When setting the
@ -221,7 +249,7 @@ used directly in the layout declaration. This example will update the textbox
every 3 seconds to show the CPU usage. every 3 seconds to show the CPU usage.
## Handling sections ### Handling sections
The system allows sections to be defined externally, then composed into The system allows sections to be defined externally, then composed into
the final layout declaration. Here is an example re-using one of the above the final layout declaration. Here is an example re-using one of the above

View File

@ -29,11 +29,9 @@
-- @name swap_widgets -- @name swap_widgets
-- @class function -- @class function
--- Get all children of this layout. --- Get all direct children of this layout.
-- @param layout The layout you are modifying. -- @param layout The layout you are modifying.
-- @return a list of all widgets -- @property children
-- @name get_children
-- @class function
--- Reset a ratio layout. This removes all widgets from the layout. --- Reset a ratio layout. This removes all widgets from the layout.
-- @param layout The layout you are modifying. -- @param layout The layout you are modifying.

35
docs/common/object.ldoc Normal file
View File

@ -0,0 +1,35 @@
--- Disonnect to a signal.
-- @tparam string name The name of the signal
-- @tparam function func The callback that should be disconnected
-- @see add_signal
-- @function disconnect_signal
--- Emit a signal.
--
-- @tparam string name The name of the signal
-- @param ... Extra arguments for the callback functions. Each connected
-- function receives the object as first argument and then any extra arguments
-- that are given to emit_signal()
-- @function emit_signal
--- Add a signal to an object. All signals must be added before they can be used.
--
-- @tparam string name The name of the new signal.
-- @function add_signal
--- Connect to a signal.
-- @tparam string name The name of the signal
-- @tparam function func The callback to call when the signal is emitted
-- @see add_signal
-- @function connect_signal
--- Connect to a signal weakly. This allows the callback function to be garbage
-- collected and automatically disconnects the signal when that happens.
--
-- **Warning:**
-- Only use this function if you really, really, really know what you
-- are doing.
-- @tparam string name The name of the signal
-- @tparam function func The callback to call when the signal is emitted
-- @function weak_connect_signal

110
docs/common/widget.ldoc Normal file
View File

@ -0,0 +1,110 @@
--- Get a widex index.
-- @param widget The widget to look for
-- @param[opt] recursive Also check sub-widgets
-- @param[opt] ... Aditional widgets to add at the end of the "path"
-- @return The index
-- @return The parent layout
-- @return The path between "self" and "widget"
-- @function index
--- Get all direct and indirect children widgets.
-- This will scan all containers recursively to find widgets
-- Warning: This method it prone to stack overflow id the widget, or any of its
-- children, contain (directly or indirectly) itself.
-- @treturn table The children
-- @function get_all_children
--- Set a declarative widget hierarchy description.
-- See [The declarative layout system](../documentation/03-declarative-layout.md.html)
-- @param args An array containing the widgets disposition
-- @function setup
--- Force a widget height.
-- @property forced_height
-- @tparam number|nil height The height (`nil` for automatic)
--- Force a widget width.
-- @property forced_width
-- @tparam number|nil width The width (`nil` for automatic)
--- The widget opacity (transparency).
-- @property opacity
-- @tparam[opt=1] number opacity The opacity (between 0 and 1)
--- The widget visibility.
-- @property visible
-- @param boolean
--- Set/get a widget's buttons.
-- @param _buttons The table of buttons that should bind to the widget.
-- @function buttons
--- When the layout (size) change.
-- This signal is emited when the previous results of `:layout()` and `:fit()`
-- are no longer valid.
-- @signal widget::layout_changed
-- @see widget::redraw_needed
--- When the widget content changed.
-- Unless this signal is emitted, `:layout()` and `:fit()` must return the same
-- result when called with the same arguments. In case this isn't the case,
-- use `widget::layout_changed`.
-- @signal widget::redraw_needed
--- When a mouse button is pressed over the widget.
-- The position of the mouse press relative to the widget while geometry
-- contains the geometry of the widget relative to the wibox.
-- @signal button::press
-- @tparam table widget The widget
-- @tparam number lx The relative horizontal position.
-- @tparam number ly The relative vertical position.
-- @tparam number button The button number.
-- @tparam table mods The modifiers (mod4, mod1 (alt), Control, Shift)
-- @tparam table geometry
-- @tparam number geometry.x The vertical position
-- @tparam number geometry.y The horizontal position
-- @tparam number geometry.width The widget
-- @tparam number geometry.height The height
-- @tparam drawable geometry.drawable The `drawable`
-- @see mouse
--- When a mouse button is released over the widget.
-- The position of the mouse press relative to the widget while geometry
-- contains the geometry of the widget relative to the wibox.
-- @signal button::release
-- @tparam table widget The widget
-- @tparam number lx The relative horizontal position.
-- @tparam number ly The relative vertical position.
-- @tparam number button The button number.
-- @tparam table mods The modifiers (mod4, mod1 (alt), Control, Shift)
-- @tparam table geometry
-- @tparam number geometry.x The vertical position
-- @tparam number geometry.y The horizontal position
-- @tparam number geometry.width The widget
-- @tparam number geometry.height The height
-- @tparam drawable geometry.drawable The `drawable`
-- @see mouse
--- When the mouse enter a widget.
-- @signal mouse::enter
-- @tparam table widget The widget
-- @tparam table geometry
-- @tparam number geometry.x The vertical position
-- @tparam number geometry.y The horizontal position
-- @tparam number geometry.width The widget
-- @tparam number geometry.height The height
-- @tparam drawable geometry.drawable The `drawable`
-- @see mouse
--- When the mouse leave a widget.
-- @signal mouse::leave
-- @tparam table widget The widget
-- @tparam table geometry
-- @tparam number geometry.x The vertical position
-- @tparam number geometry.y The horizontal position
-- @tparam number geometry.width The widget
-- @tparam number geometry.height The height
-- @tparam drawable geometry.drawable The `drawable`
-- @see mouse

View File

@ -82,6 +82,7 @@ file = {
'../lib/gears/init.lua', '../lib/gears/init.lua',
'../lib/wibox/layout/init.lua', '../lib/wibox/layout/init.lua',
'../lib/wibox/widget/init.lua', '../lib/wibox/widget/init.lua',
'../lib/wibox/container/init.lua',
-- Ignore some parts of the widget library -- Ignore some parts of the widget library
'../lib/awful/widget/init.lua', '../lib/awful/widget/init.lua',

View File

@ -1,51 +0,0 @@
# Get and update the LUA_PATH so the scripts can be executed without Awesome
execute_process(COMMAND lua -e print\(package.path\) OUTPUT_VARIABLE LUA_PATH_)
set(ENV{LUA_PATH} "${SOURCE_DIR}/lib/?;${SOURCE_DIR}/lib/?.lua;${LUA_PATH_}")
file(MAKE_DIRECTORY "${BUILD_DIR}/doc/images")
set(ENV{BUILD_DIRECTORY} "${BUILD_DIR}/")
set(ENV{AWESOME_LIB_DIR} "${SOURCE_DIR}/lib/")
#
# Shape API
#
foreach (SHAPE_NAME "circle" "arrow" "rounded_rect" "hexagon" "infobubble"
"powerline" "isosceles_triangle" "cross" "octogon" "parallelogram"
"losange" "partially_rounded_rect" "radial_progress" "rounded_bar"
"rectangle" "rectangular_tag")
set(SHAPE_FILE "${SOURCE_DIR}/tests/shape/${SHAPE_NAME}.lua")
set(SHAPE_SVG "${BUILD_DIR}/doc/images/shape_${SHAPE_NAME}.svg")
# Generate some SVG for the documentation and load the examples for the doc
execute_process(
COMMAND lua ${SOURCE_DIR}/tests/shape/test-shape.lua ${SHAPE_FILE} ${SHAPE_SVG} ${SOURCE_DIR}/.luacov
ERROR_VARIABLE SHAPE_ERROR
)
if (NOT SHAPE_ERROR STREQUAL "")
message(${SHAPE_ERROR})
message(FATAL_ERROR ${SHAPE_NAME} " SVG generation failed, bye")
endif()
# Set the SVG paths for the doc
set(SHAPE_${SHAPE_NAME}_SVG "../images/shape_${SHAPE_NAME}.svg")
# Use the .lua as code example
file(READ ${SHAPE_FILE} SHAPE_EXAMPLE)
STRING(REGEX REPLACE "\n" ";" SHAPE_EXAMPLE "${SHAPE_EXAMPLE}")
SET(SHAPE_COMMENTED
"![Shape example](../images/shape_${SHAPE_NAME}.svg)\n--\n-- @usage"
)
foreach (EXAMPLE_FILE ${SHAPE_EXAMPLE})
if(NOT EXAMPLE_FILE MATCHES "^.+--DOC_HIDE$")
SET(SHAPE_COMMENTED ${SHAPE_COMMENTED}\n--${EXAMPLE_FILE})
endif()
endforeach()
set(SHAPE_${SHAPE_NAME}_EXAMPLE ${SHAPE_COMMENTED})
endforeach()
# vim: filetype=cmake:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80:foldmethod=marker

48
docs/widget_lists.cmake Normal file
View File

@ -0,0 +1,48 @@
# This file gather the different default example screenshots and create an HTML
# table. Those tables are re-used in the official documentation.
# Ldoc wont parse the HTML content and discount tables are disabled, so here is
# some raw HTML
function(add_to_table name namespace group current_table new_table)
set(${new_table} "${current_table}\n\
<tr>\n\
<td>
<a href='../classes/${namespace}${name}.html'>${namespace}${name}</a>
</td>\n\
<td><img src='../images/AUTOGEN_wibox_${group}_defaults_${name}.svg' /></td>\n\
</tr>\n\
" PARENT_SCOPE)
endfunction()
# Use the generated "defaults" images to build a list
function(generate_widget_list name)
file(GLOB ex_files RELATIVE "${SOURCE_DIR}/tests/examples/wibox/${name}/defaults"
"${SOURCE_DIR}/tests/examples/wibox/${name}/defaults/*")
# Add the table header
set(MY_LIST "<table class='widget_list' border=1>\n\
<tr style='font-weight: bold;'>\n\
<th align='center'>Name</th>\n\
<th align='center'>Example</th>\n\
</tr>"
)
# Loop all examples (and assume an image exist for them)
foreach(ex_file_name ${ex_files})
string(REGEX REPLACE "\\.lua" "" ex_file_name ${ex_file_name})
if(NOT ${ex_file_name} STREQUAL "template")
add_to_table(${ex_file_name} "wibox.${name}." "${name}" "${MY_LIST}" MY_LIST)
endif()
endforeach()
# Add the table footer
set(MY_LIST "${MY_LIST}</table>\n\n")
set(DOC_${name}_WIDGET_LIST ${MY_LIST} PARENT_SCOPE)
endfunction()
generate_widget_list( "container" )
generate_widget_list( "layout" )
generate_widget_list( "widget" )

View File

@ -195,7 +195,7 @@ local function group_label(group, color)
) )
) )
) )
local margin = wibox.layout.margin() local margin = wibox.container.margin()
margin:set_widget(textbox) margin:set_widget(textbox)
margin:set_top(widget.group_margin) margin:set_top(widget.group_margin)
return margin return margin
@ -315,7 +315,7 @@ local function create_wibox(s, available_groups)
else else
available_width_px = available_width_px - item.max_width available_width_px = available_width_px - item.max_width
end end
local column_margin = wibox.layout.margin() local column_margin = wibox.container.margin()
column_margin:set_widget(item.layout) column_margin:set_widget(item.layout)
column_margin:set_left(widget.group_margin) column_margin:set_left(widget.group_margin)
columns:add(column_margin) columns:add(column_margin)

View File

@ -249,7 +249,7 @@ function menu:exec(num, opts)
self.active_child:hide() self.active_child:hide()
end end
self.active_child = self.child[num] self.active_child = self.child[num]
if not self.active_child.visible then if not self.active_child:get_visible() then
self.active_child:show() self.active_child:show()
end end
elseif type(cmd) == "string" then elseif type(cmd) == "string" then
@ -384,7 +384,7 @@ function menu:add(args, index)
item.width = item.width or theme.width item.width = item.width or theme.width
item.height = item.height or theme.height item.height = item.height or theme.height
wibox.widget.base.check_widget(item.widget) wibox.widget.base.check_widget(item.widget)
item._background = wibox.widget.background() item._background = wibox.container.background()
item._background:set_widget(item.widget) item._background:set_widget(item.widget)
item._background:set_fg(item.theme.fg_normal) item._background:set_fg(item.theme.fg_normal)
item._background:set_bg(item.theme.bg_normal) item._background:set_bg(item.theme.bg_normal)
@ -431,7 +431,7 @@ function menu:delete(num)
local item = self.items[num] local item = self.items[num]
if not item then return end if not item then return end
item.widget:disconnect_signal("mouse::enter", item._mouse) item.widget:disconnect_signal("mouse::enter", item._mouse)
item.widget.visible = false item.widget:set_visible(false)
table.remove(self.items, num) table.remove(self.items, num)
if self.sel == num then if self.sel == num then
self:item_leave(self.sel) self:item_leave(self.sel)
@ -516,7 +516,7 @@ function menu.entry(parent, args) -- luacheck: no unused args
end, 1)) end, 1))
-- Set icon if needed -- Set icon if needed
local icon, iconbox local icon, iconbox
local margin = wibox.layout.margin() local margin = wibox.container.margin()
margin:set_widget(label) margin:set_widget(label)
if args.icon then if args.icon then
icon = surface.load(args.icon) icon = surface.load(args.icon)

View File

@ -204,8 +204,8 @@ function titlebar.widget.button(c, name, selector, action)
local ret = imagebox() local ret = imagebox()
if titlebar.enable_tooltip then if titlebar.enable_tooltip then
ret.tooltip = atooltip({ objects = {ret}, delay_show = 1 }) ret._private.tooltip = atooltip({ objects = {ret}, delay_show = 1 })
ret.tooltip:set_text(name) ret._private.tooltip:set_text(name)
end end
local function update() local function update()

View File

@ -10,7 +10,7 @@
-- How to create a tooltip? -- How to create a tooltip?
-- --- -- ---
-- --
-- myclock = awful.widget.textclock({}, "%T", 1) -- myclock = wibox.widget.textclock({}, "%T", 1)
-- myclock_t = awful.tooltip({ -- myclock_t = awful.tooltip({
-- objects = { myclock }, -- objects = { myclock },
-- timer_function = function() -- timer_function = function()
@ -48,7 +48,7 @@ local a_placement = require("awful.placement")
local abutton = require("awful.button") local abutton = require("awful.button")
local beautiful = require("beautiful") local beautiful = require("beautiful")
local textbox = require("wibox.widget.textbox") local textbox = require("wibox.widget.textbox")
local background = require("wibox.widget.background") local background = require("wibox.container.background")
local dpi = require("beautiful").xresources.apply_dpi local dpi = require("beautiful").xresources.apply_dpi
local setmetatable = setmetatable local setmetatable = setmetatable
local ipairs = ipairs local ipairs = ipairs
@ -265,7 +265,7 @@ tooltip.new = function(args)
-- Add margin. -- Add margin.
local m_lr = args.margin_leftright or dpi(5) local m_lr = args.margin_leftright or dpi(5)
local m_tb = args.margin_topbottom or dpi(3) local m_tb = args.margin_topbottom or dpi(3)
self.marginbox = wibox.layout.margin(self.background, m_lr, m_lr, m_tb, m_tb) self.marginbox = wibox.container.margin(self.background, m_lr, m_lr, m_tb, m_tb)
-- Add tooltip to objects -- Add tooltip to objects
if args.objects then if args.objects then

View File

@ -60,6 +60,36 @@ function util.deprecate(see)
gears_debug.print_warning(msg .. ".\n" .. tb) gears_debug.print_warning(msg .. ".\n" .. tb)
end end
--- Create a class proxy with deprecation messages.
-- This is useful when a class has moved somewhere else.
-- @tparam table fallback The new class
-- @tparam string old_name The old class name
-- @tparam string new_name The new class name
-- @treturn table A proxy class.
function util.deprecate_class(fallback, old_name, new_name)
local message = old_name.." has been renamed to "..new_name
local function call(_,...)
util.deprecate(message)
return fallback(...)
end
local function index(_, k)
util.deprecate(message)
return fallback[k]
end
local function newindex(_, k, v)
util.deprecate(message)
fallback[k] = v
end
return setmetatable({}, {__call = call, __index = index, __newindex = newindex})
end
--- Get a valid color for Pango markup --- Get a valid color for Pango markup
-- @param color The color. -- @param color The color.
-- @tparam string fallback The color to return if the first is invalid. (default: black) -- @tparam string fallback The color to return if the first is invalid. (default: black)
@ -336,13 +366,22 @@ function util.table.join(...)
return ret return ret
end end
--- Override elements in the first table by the one in the second --- Override elements in the first table by the one in the second.
--
-- Note that this method doesn't copy entries found in `__index`.
-- @tparam table t the table to be overriden -- @tparam table t the table to be overriden
-- @tparam table set the table used to override members of `t` -- @tparam table set the table used to override members of `t`
-- @tparam[opt=false] boolean raw Use rawset (avoid the metatable)
-- @treturn table t (for convenience) -- @treturn table t (for convenience)
function util.table.crush(t, set) function util.table.crush(t, set, raw)
for k, v in pairs(set) do if raw then
t[k] = v for k, v in pairs(set) do
rawset(t, k, v)
end
else
for k, v in pairs(set) do
t[k] = v
end
end end
return t return t

View File

@ -7,26 +7,7 @@
-- @module awful.wibox -- @module awful.wibox
--------------------------------------------------------------------------- ---------------------------------------------------------------------------
local util = require("awful.util") local util = require("awful.util")
local wibar = require("awful.wibar")
local function call(_,...) return util.deprecate_class(require("awful.wibar"), "awful.wibox", "awful.wibar")
util.deprecate("awful.wibox has been renamed to awful.wibar")
return wibar(...)
end
local function index(_, k)
util.deprecate("awful.wibox has been renamed to awful.wibar")
return wibar[k]
end
local function newindex(_, k, v)
util.deprecate("awful.wibox has been renamed to awful.wibar")
wibar[k] = v
end
return setmetatable({}, {__call = call, __index = index, __newindex = newindex})
-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80 -- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80

View File

@ -60,9 +60,9 @@ function common.list_update(w, buttons, label, data, objects)
else else
ib = wibox.widget.imagebox() ib = wibox.widget.imagebox()
tb = wibox.widget.textbox() tb = wibox.widget.textbox()
bgb = wibox.widget.background() bgb = wibox.container.background()
tbm = wibox.layout.margin(tb, dpi(4), dpi(4)) tbm = wibox.container.margin(tb, dpi(4), dpi(4))
ibm = wibox.layout.margin(ib, dpi(4)) ibm = wibox.container.margin(ib, dpi(4))
l = wibox.layout.fixed.horizontal() l = wibox.layout.fixed.horizontal()
-- All of this is added in a fixed widget -- All of this is added in a fixed widget

View File

@ -1,279 +1,17 @@
--------------------------------------------------------------------------- ---------------------------------------------------------------------------
--- A graph widget. --- This module has been moved to `wibox.widget.graph`
-- --
-- @author Julien Danjou &lt;julien@danjou.info&gt; -- @author Julien Danjou &lt;julien@danjou.info&gt;
-- @copyright 2009 Julien Danjou -- @copyright 2009 Julien Danjou
-- @release @AWESOME_VERSION@ -- @release @AWESOME_VERSION@
-- @classmod awful.widget.graph -- @classmod awful.widget.graph
--------------------------------------------------------------------------- ---------------------------------------------------------------------------
local util = require("awful.util")
local setmetatable = setmetatable return util.deprecate_class(
local ipairs = ipairs require("wibox.widget.graph"),
local math = math "awful.widget.graph",
local table = table "wibox.widget.graph"
local type = type )
local color = require("gears.color")
local base = require("wibox.widget.base")
local graph = { mt = {} }
--- Set the graph border color.
-- If the value is nil, no border will be drawn.
--
-- @function set_border_color
-- @param graph The graph.
-- @param color The border color to set.
--- Set the graph foreground color.
--
-- @function set_color
-- @param graph The graph.
-- @param color The graph color.
-- @see gears.color.create_pattern
--- Set the graph background color.
--
-- @function set_background_color
-- @param graph The graph.
-- @param color The graph background color.
--- Set the maximum value the graph should handle.
-- If "scale" is also set, the graph never scales up below this value, but it
-- automatically scales down to make all data fit.
--
-- @function set_max_value
-- @param graph The graph.
-- @param value The value.
--- Set the graph to automatically scale its values. Default is false.
--
-- @function set_scale
-- @param graph The graph.
-- @param scale A boolean value
--- Set the graph to draw stacks. Default is false.
--
-- @function set_stack
-- @param graph The graph.
-- @param stack A boolean value.
--- Set the graph stacking colors. Order matters.
--
-- @function set_stack_colors
-- @param graph The graph.
-- @param stack_colors A table with stacking colors.
local properties = { "width", "height", "border_color", "stack",
"stack_colors", "color", "background_color",
"max_value", "scale" }
function graph.draw(_graph, _, cr, width, height)
local max_value = _graph._data.max_value
local values = _graph._data.values
cr:set_line_width(1)
-- Draw the background first
cr:set_source(color(_graph._data.background_color or "#000000aa"))
cr:paint()
-- Account for the border width
cr:save()
if _graph._data.border_color then
cr:translate(1, 1)
width, height = width - 2, height - 2
end
-- Draw a stacked graph
if _graph._data.stack then
if _graph._data.scale then
for _, v in ipairs(values) do
for _, sv in ipairs(v) do
if sv > max_value then
max_value = sv
end
end
end
end
for i = 0, width do
local rel_i = 0
local rel_x = i + 0.5
if _graph._data.stack_colors then
for idx, col in ipairs(_graph._data.stack_colors) do
local stack_values = values[idx]
if stack_values and i < #stack_values then
local value = stack_values[#stack_values - i] + rel_i
cr:move_to(rel_x, height * (1 - (rel_i / max_value)))
cr:line_to(rel_x, height * (1 - (value / max_value)))
cr:set_source(color(col or "#ff0000"))
cr:stroke()
rel_i = value
end
end
end
end
else
if _graph._data.scale then
for _, v in ipairs(values) do
if v > max_value then
max_value = v
end
end
end
-- Draw the background on no value
if #values ~= 0 then
-- Draw reverse
for i = 0, #values - 1 do
local value = values[#values - i]
if value >= 0 then
value = value / max_value
cr:move_to(i + 0.5, height * (1 - value))
cr:line_to(i + 0.5, height)
end
end
cr:set_source(color(_graph._data.color or "#ff0000"))
cr:stroke()
end
end
-- Undo the cr:translate() for the border
cr:restore()
-- Draw the border last so that it overlaps already drawn values
if _graph._data.border_color then
-- We decremented these by two above
width, height = width + 2, height + 2
-- Draw the border
cr:rectangle(0.5, 0.5, width - 1, height - 1)
cr:set_source(color(_graph._data.border_color or "#ffffff"))
cr:stroke()
end
end
function graph.fit(_graph)
return _graph._data.width, _graph._data.height
end
--- Add a value to the graph
--
-- @param value The value to be added to the graph
-- @param group The stack color group index.
function graph:add_value(value, group)
value = value or 0
local values = self._data.values
local max_value = self._data.max_value
value = math.max(0, value)
if not self._data.scale then
value = math.min(max_value, value)
end
if self._data.stack and group then
if not self._data.values[group]
or type(self._data.values[group]) ~= "table"
then
self._data.values[group] = {}
end
values = self._data.values[group]
end
table.insert(values, value)
local border_width = 0
if self._data.border_color then border_width = 2 end
-- Ensure we never have more data than we can draw
while #values > self._data.width - border_width do
table.remove(values, 1)
end
self:emit_signal("widget::redraw_needed")
return self
end
--- Clear the graph.
function graph:clear()
self._data.values = {}
self:emit_signal("widget::redraw_needed")
return self
end
--- Set the graph height.
-- @param height The height to set.
function graph:set_height(height)
if height >= 5 then
self._data.height = height
self:emit_signal("widget::layout_changed")
end
return self
end
--- Set the graph width.
-- @param width The width to set.
function graph:set_width(width)
if width >= 5 then
self._data.width = width
self:emit_signal("widget::layout_changed")
end
return self
end
-- Build properties function
for _, prop in ipairs(properties) do
if not graph["set_" .. prop] then
graph["set_" .. prop] = function(_graph, value)
if _graph._data[prop] ~= value then
_graph._data[prop] = value
_graph:emit_signal("widget::redraw_needed")
end
return _graph
end
end
if not graph["get_" .. prop] then
graph["get_" .. prop] = function(_graph)
return _graph._data[prop]
end
end
end
--- Create a graph widget.
-- @param args Standard widget() arguments. You should add width and height
-- key to set graph geometry.
-- @return A graph widget.
function graph.new(args)
args = args or {}
local width = args.width or 100
local height = args.height or 20
if width < 5 or height < 5 then return end
local _graph = base.make_widget()
_graph._data = { width = width, height = height, values = {}, max_value = 1 }
-- Set methods
_graph.add_value = graph["add_value"]
_graph.clear = graph["clear"]
_graph.draw = graph.draw
_graph.fit = graph.fit
for _, prop in ipairs(properties) do
_graph["set_" .. prop] = graph["set_" .. prop]
_graph["get_" .. prop] = graph["get_" .. prop]
end
return _graph
end
function graph.mt:__call(...)
return graph.new(...)
end
return setmetatable(graph, graph.mt)
-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80 -- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80

View File

@ -1,230 +1,17 @@
--------------------------------------------------------------------------- ---------------------------------------------------------------------------
--- A progressbar widget. --- This module has been moved to `wibox.widget.progressbar`
-- --
-- @author Julien Danjou &lt;julien@danjou.info&gt; -- @author Julien Danjou &lt;julien@danjou.info&gt;
-- @copyright 2009 Julien Danjou -- @copyright 2009 Julien Danjou
-- @release @AWESOME_VERSION@ -- @release @AWESOME_VERSION@
-- @classmod awful.widget.progressbar -- @classmod awful.widget.progressbar
--------------------------------------------------------------------------- ---------------------------------------------------------------------------
local util = require("awful.util")
local setmetatable = setmetatable return util.deprecate_class(
local ipairs = ipairs require("wibox.widget.progressbar"),
local math = math "awful.widget.progressbar",
local base = require("wibox.widget.base") "wibox.widget.progressbar"
local color = require("gears.color") )
local progressbar = { mt = {} }
local data = setmetatable({}, { __mode = "k" })
--- Set the progressbar border color.
-- If the value is nil, no border will be drawn.
--
-- @function set_border_color
-- @param progressbar The progressbar.
-- @param color The border color to set.
--- Set the progressbar foreground color.
--
-- @function set_color
-- @param progressbar The progressbar.
-- @param color The progressbar color.
--- Set the progressbar background color.
--
-- @function set_background_color
-- @param progressbar The progressbar.
-- @param color The progressbar background color.
--- Set the progressbar to draw vertically. Default is false.
--
-- @function set_vertical
-- @param progressbar The progressbar.
-- @param vertical A boolean value.
--- Set the progressbar to draw ticks. Default is false.
--
-- @function set_ticks
-- @param progressbar The progressbar.
-- @param ticks A boolean value.
--- Set the progressbar ticks gap.
--
-- @function set_ticks_gap
-- @param progressbar The progressbar.
-- @param value The value.
--- Set the progressbar ticks size.
--
-- @function set_ticks_size
-- @param progressbar The progressbar.
-- @param value The value.
--- Set the maximum value the progressbar should handle.
--
-- @function set_max_value
-- @param progressbar The progressbar.
-- @param value The value.
local properties = { "width", "height", "border_color",
"color", "background_color",
"vertical", "value", "max_value",
"ticks", "ticks_gap", "ticks_size" }
function progressbar.draw(pbar, _, cr, width, height)
local ticks_gap = data[pbar].ticks_gap or 1
local ticks_size = data[pbar].ticks_size or 4
-- We want one pixel wide lines
cr:set_line_width(1)
local value = data[pbar].value
local max_value = data[pbar].max_value
if value >= 0 then
value = value / max_value
end
local over_drawn_width = width
local over_drawn_height = height
local border_width = 0
if data[pbar].border_color then
-- Draw border
cr:rectangle(0.5, 0.5, width - 1, height - 1)
cr:set_source(color(data[pbar].border_color))
cr:stroke()
over_drawn_width = width - 2 -- remove 2 for borders
over_drawn_height = height - 2 -- remove 2 for borders
border_width = 1
end
cr:rectangle(border_width, border_width,
over_drawn_width, over_drawn_height)
cr:set_source(color(data[pbar].color or "#ff0000"))
cr:fill()
-- Cover the part that is not set with a rectangle
if data[pbar].vertical then
local rel_height = over_drawn_height * (1 - value)
cr:rectangle(border_width,
border_width,
over_drawn_width,
rel_height)
cr:set_source(color(data[pbar].background_color or "#000000aa"))
cr:fill()
-- Place smaller pieces over the gradient if ticks are enabled
if data[pbar].ticks then
for i=0, height / (ticks_size+ticks_gap)-border_width do
local rel_offset = over_drawn_height / 1 - (ticks_size+ticks_gap) * i
if rel_offset >= rel_height then
cr:rectangle(border_width,
rel_offset,
over_drawn_width,
ticks_gap)
end
end
cr:set_source(color(data[pbar].background_color or "#000000aa"))
cr:fill()
end
else
local rel_x = over_drawn_width * value
cr:rectangle(border_width + rel_x,
border_width,
over_drawn_width - rel_x,
over_drawn_height)
cr:set_source(color(data[pbar].background_color or "#000000aa"))
cr:fill()
if data[pbar].ticks then
for i=0, width / (ticks_size+ticks_gap)-border_width do
local rel_offset = over_drawn_width / 1 - (ticks_size+ticks_gap) * i
if rel_offset <= rel_x then
cr:rectangle(rel_offset,
border_width,
ticks_gap,
over_drawn_height)
end
end
cr:set_source(color(data[pbar].background_color or "#000000aa"))
cr:fill()
end
end
end
function progressbar.fit(pbar)
return data[pbar].width, data[pbar].height
end
--- Set the progressbar value.
-- @param value The progress bar value between 0 and 1.
function progressbar:set_value(value)
value = value or 0
local max_value = data[self].max_value
data[self].value = math.min(max_value, math.max(0, value))
self:emit_signal("widget::redraw_needed")
return self
end
--- Set the progressbar height.
-- @param height The height to set.
function progressbar:set_height(height)
data[self].height = height
self:emit_signal("widget::layout_changed")
return self
end
--- Set the progressbar width.
-- @param width The width to set.
function progressbar:set_width(width)
data[self].width = width
self:emit_signal("widget::layout_changed")
return self
end
-- Build properties function
for _, prop in ipairs(properties) do
if not progressbar["set_" .. prop] then
progressbar["set_" .. prop] = function(pbar, value)
data[pbar][prop] = value
pbar:emit_signal("widget::redraw_needed")
return pbar
end
end
end
--- Create a progressbar widget.
-- @param args Standard widget() arguments. You should add width and height
-- key to set progressbar geometry.
-- @return A progressbar widget.
function progressbar.new(args)
args = args or {}
local width = args.width or 100
local height = args.height or 20
args.type = "imagebox"
local pbar = base.make_widget()
data[pbar] = { width = width, height = height, value = 0, max_value = 1 }
-- Set methods
for _, prop in ipairs(properties) do
pbar["set_" .. prop] = progressbar["set_" .. prop]
end
pbar.draw = progressbar.draw
pbar.fit = progressbar.fit
return pbar
end
function progressbar.mt:__call(...)
return progressbar.new(...)
end
return setmetatable(progressbar, progressbar.mt)
-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80 -- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80

View File

@ -1,52 +1,17 @@
--------------------------------------------------------------------------- ---------------------------------------------------------------------------
--- Text clock widget. -- This widget has moved to `wibox.widget.textclock`
-- --
-- @author Julien Danjou &lt;julien@danjou.info&gt; -- @author Julien Danjou &lt;julien@danjou.info&gt;
-- @copyright 2009 Julien Danjou -- @copyright 2008-2009 Julien Danjou
-- @release @AWESOME_VERSION@ -- @release @AWESOME_VERSION@
-- @classmod awful.widget.textclock -- @classmod awful.widget.textclock
--------------------------------------------------------------------------- ---------------------------------------------------------------------------
local util = require("awful.util")
local setmetatable = setmetatable return util.deprecate_class(
local os = os require("wibox.widget.textclock"),
local textbox = require("wibox.widget.textbox") "awful.widget.textclock",
local timer = require("gears.timer") "wibox.widget.textclock"
local DateTime = require("lgi").GLib.DateTime )
local textclock = { mt = {} }
--- This lowers the timeout so that it occurs "correctly". For example, a timeout
-- of 60 is rounded so that it occurs the next time the clock reads ":00 seconds".
local function calc_timeout(real_timeout)
return real_timeout - os.time() % real_timeout
end
--- Create a textclock widget. It draws the time it is in a textbox.
--
-- @param format The time format. Default is " %a %b %d, %H:%M ".
-- @param timeout How often update the time. Default is 60.
-- @return A textbox widget.
function textclock.new(format, timeout)
format = format or " %a %b %d, %H:%M "
timeout = timeout or 60
local w = textbox()
local t
function w._textclock_update_cb()
w:set_markup(DateTime.new_now_local():format(format))
t.timeout = calc_timeout(timeout)
t:again()
return true -- Continue the timer
end
t = timer.weak_start_new(timeout, w._textclock_update_cb)
t:emit_signal("timeout")
return w
end
function textclock.mt:__call(...)
return textclock.new(...)
end
return setmetatable(textclock, textclock.mt)
-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80 -- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80

View File

@ -230,7 +230,7 @@ end
-- --
-- @tparam[opt=2] integer level Level for `debug.getinfo(level, "S")`. -- @tparam[opt=2] integer level Level for `debug.getinfo(level, "S")`.
-- Typically 2 or 3. -- Typically 2 or 3.
-- @treturn string The module name, e.g. "wibox.widget.background". -- @treturn string The module name, e.g. "wibox.container.background".
function object.modulename(level) function object.modulename(level)
return debug.getinfo(level, "S").source:gsub(".*/lib/", ""):gsub("/", "."):gsub("%.lua", "") return debug.getinfo(level, "S").source:gsub(".*/lib/", ""):gsub("/", "."):gsub("%.lua", "")
end end

View File

@ -28,13 +28,15 @@ local module = {}
--- Add a rounded rectangle to the current path. --- Add a rounded rectangle to the current path.
-- Note: If the radius is bigger than either half side, it will be reduced. -- Note: If the radius is bigger than either half side, it will be reduced.
-- --
-- @SHAPE_rounded_rect_EXAMPLE@ -- @DOC_gears_shape_rounded_rect_EXAMPLE@
-- --
-- @param cr A cairo content -- @param cr A cairo content
-- @tparam number width The rectangle width -- @tparam number width The rectangle width
-- @tparam number height The rectangle height -- @tparam number height The rectangle height
-- @tparam number radius the corner radius -- @tparam number radius the corner radius
function module.rounded_rect(cr, width, height, radius) function module.rounded_rect(cr, width, height, radius)
radius = radius or 10
if width / 2 < radius then if width / 2 < radius then
radius = width / 2 radius = width / 2
end end
@ -53,7 +55,7 @@ end
--- Add a rectangle delimited by 2 180 degree arcs to the path. --- Add a rectangle delimited by 2 180 degree arcs to the path.
-- --
-- @SHAPE_rounded_bar_EXAMPLE@ -- @DOC_gears_shape_rounded_bar_EXAMPLE@
-- --
-- @param cr A cairo content -- @param cr A cairo content
-- @param width The rectangle width -- @param width The rectangle width
@ -64,7 +66,7 @@ end
--- A rounded rect with only some of the corners rounded. --- A rounded rect with only some of the corners rounded.
-- --
-- @SHAPE_partially_rounded_rect_EXAMPLE@ -- @DOC_gears_shape_partially_rounded_rect_EXAMPLE@
-- --
-- @param cr A cairo context -- @param cr A cairo context
-- @tparam number width The shape width -- @tparam number width The shape width
@ -117,7 +119,7 @@ end
--- A rounded rectangle with a triangle at the top. --- A rounded rectangle with a triangle at the top.
-- --
-- @SHAPE_infobubble_EXAMPLE@ -- @DOC_gears_shape_infobubble_EXAMPLE@
-- --
-- @param cr A cairo context -- @param cr A cairo context
-- @tparam number width The shape width -- @tparam number width The shape width
@ -152,7 +154,7 @@ end
--- A rectangle terminated by an arrow. --- A rectangle terminated by an arrow.
-- --
-- @SHAPE_rectangular_tag_EXAMPLE@ -- @DOC_gears_shape_rectangular_tag_EXAMPLE@
-- --
-- @param cr A cairo context -- @param cr A cairo context
-- @tparam number width The shape width -- @tparam number width The shape width
@ -179,7 +181,7 @@ end
--- A simple arrow shape. --- A simple arrow shape.
-- --
-- @SHAPE_arrow_EXAMPLE@ -- @DOC_gears_shape_arrow_EXAMPLE@
-- --
-- @param cr A cairo context -- @param cr A cairo context
-- @tparam number width The shape width -- @tparam number width The shape width
@ -206,7 +208,7 @@ end
--- A squeezed hexagon filling the rectangle. --- A squeezed hexagon filling the rectangle.
-- --
-- @SHAPE_hexagon_EXAMPLE@ -- @DOC_gears_shape_hexagon_EXAMPLE@
-- --
-- @param cr A cairo context -- @param cr A cairo context
-- @tparam number width The shape width -- @tparam number width The shape width
@ -224,7 +226,7 @@ end
--- Double arrow popularized by the vim-powerline module. --- Double arrow popularized by the vim-powerline module.
-- --
-- @SHAPE_powerline_EXAMPLE@ -- @DOC_gears_shape_powerline_EXAMPLE@
-- --
-- @param cr A cairo context -- @param cr A cairo context
-- @tparam number width The shape width -- @tparam number width The shape width
@ -252,7 +254,7 @@ end
--- An isosceles triangle. --- An isosceles triangle.
-- --
-- @SHAPE_isosceles_triangle_EXAMPLE@ -- @DOC_gears_shape_isosceles_triangle_EXAMPLE@
-- --
-- @param cr A cairo context -- @param cr A cairo context
-- @tparam number width The shape width -- @tparam number width The shape width
@ -266,7 +268,7 @@ end
--- A cross (**+**) symbol. --- A cross (**+**) symbol.
-- --
-- @SHAPE_cross_EXAMPLE@ -- @DOC_gears_shape_cross_EXAMPLE@
-- --
-- @param cr A cairo context -- @param cr A cairo context
-- @tparam number width The shape width -- @tparam number width The shape width
@ -293,7 +295,7 @@ end
--- A similar shape to the `rounded_rect`, but with sharp corners. --- A similar shape to the `rounded_rect`, but with sharp corners.
-- --
-- @SHAPE_octogon_EXAMPLE@ -- @DOC_gears_shape_octogon_EXAMPLE@
-- --
-- @param cr A cairo context -- @param cr A cairo context
-- @tparam number width The shape width -- @tparam number width The shape width
@ -316,7 +318,7 @@ end
--- A circle shape. --- A circle shape.
-- --
-- @SHAPE_circle_EXAMPLE@ -- @DOC_gears_shape_circle_EXAMPLE@
-- --
-- @param cr A cairo context -- @param cr A cairo context
-- @tparam number width The shape width -- @tparam number width The shape width
@ -329,7 +331,7 @@ end
--- A simple rectangle. --- A simple rectangle.
-- --
-- @SHAPE_rectangle_EXAMPLE@ -- @DOC_gears_shape_rectangle_EXAMPLE@
-- --
-- @param cr A cairo context -- @param cr A cairo context
-- @tparam number width The shape width -- @tparam number width The shape width
@ -341,7 +343,7 @@ end
--- A diagonal parallelogram with the bottom left corner at x=0 and top right --- A diagonal parallelogram with the bottom left corner at x=0 and top right
-- at x=width. -- at x=width.
-- --
-- @SHAPE_parallelogram_EXAMPLE@ -- @DOC_gears_shape_parallelogram_EXAMPLE@
-- --
-- @param cr A cairo context -- @param cr A cairo context
-- @tparam number width The shape width -- @tparam number width The shape width
@ -358,7 +360,7 @@ end
--- A losange. --- A losange.
-- --
-- @SHAPE_losange_EXAMPLE@ -- @DOC_gears_shape_losange_EXAMPLE@
-- --
-- @param cr A cairo context -- @param cr A cairo context
-- @tparam number width The shape width -- @tparam number width The shape width
@ -377,7 +379,7 @@ end
-- Note that this shape is not closed and thus filling it doesn't make much -- Note that this shape is not closed and thus filling it doesn't make much
-- sense. -- sense.
-- --
-- @SHAPE_radial_progress_EXAMPLE@ -- @DOC_gears_shape_radial_progress_EXAMPLE@
-- --
-- @param cr A cairo context -- @param cr A cairo context
-- @tparam number w The shape width -- @tparam number w The shape width

View File

@ -522,7 +522,7 @@ function naughty.notify(args)
-- create textbox -- create textbox
local textbox = wibox.widget.textbox() local textbox = wibox.widget.textbox()
local marginbox = wibox.layout.margin() local marginbox = wibox.container.margin()
marginbox:set_margins(margin) marginbox:set_margins(margin)
marginbox:set_widget(textbox) marginbox:set_widget(textbox)
textbox:set_valign("middle") textbox:set_valign("middle")
@ -538,7 +538,7 @@ function naughty.notify(args)
if actions then if actions then
for action, callback in pairs(actions) do for action, callback in pairs(actions) do
local actiontextbox = wibox.widget.textbox() local actiontextbox = wibox.widget.textbox()
local actionmarginbox = wibox.layout.margin() local actionmarginbox = wibox.container.margin()
actionmarginbox:set_margins(margin) actionmarginbox:set_margins(margin)
actionmarginbox:set_widget(actiontextbox) actionmarginbox:set_widget(actiontextbox)
actiontextbox:set_valign("middle") actiontextbox:set_valign("middle")
@ -582,7 +582,7 @@ function naughty.notify(args)
-- if we have an icon, use it -- if we have an icon, use it
if icon then if icon then
iconbox = wibox.widget.imagebox() iconbox = wibox.widget.imagebox()
iconmargin = wibox.layout.margin(iconbox, margin, margin, margin, margin) iconmargin = wibox.container.margin(iconbox, margin, margin, margin, margin)
if icon_size then if icon_size then
local scaled = cairo.ImageSurface(cairo.Format.ARGB32, icon_size, icon_size) local scaled = cairo.ImageSurface(cairo.Format.ARGB32, icon_size, icon_size)
local cr = cairo.Context(scaled) local cr = cairo.Context(scaled)

View File

@ -0,0 +1,292 @@
---------------------------------------------------------------------------
-- A container capable of changing the background color, foreground color
-- widget shape.
--
--@DOC_wibox_container_defaults_background_EXAMPLE@
-- @author Uli Schlachter
-- @copyright 2010 Uli Schlachter
-- @release @AWESOME_VERSION@
-- @classmod wibox.container.background
---------------------------------------------------------------------------
local base = require("wibox.widget.base")
local color = require("gears.color")
local surface = require("gears.surface")
local beautiful = require("beautiful")
local cairo = require("lgi").cairo
local util = require("awful.util")
local setmetatable = setmetatable
local type = type
local unpack = unpack or table.unpack -- luacheck: globals unpack (compatibility with Lua 5.1)
local background = { mt = {} }
-- Draw this widget
function background:draw(context, cr, width, height)
if not self._private.widget or not self._private.widget:get_visible() then
return
end
-- Keep the shape path in case there is a border
self._private.path = nil
if self._private.shape then
-- Only add the offset if there is something to draw
local offset = ((self._private.shape_border_width and self._private.shape_border_color)
and self._private.shape_border_width or 0) / 2
cr:translate(offset, offset)
self._private.shape(cr, width - 2*offset, height - 2*offset, unpack(self._private.shape_args or {}))
cr:translate(-offset, -offset)
self._private.path = cr:copy_path()
cr:clip()
end
if self._private.background then
cr:set_source(self._private.background)
cr:paint()
end
if self._private.bgimage then
if type(self._private.bgimage) == "function" then
self._private.bgimage(context, cr, width, height,unpack(self._private.bgimage_args))
else
local pattern = cairo.Pattern.create_for_surface(self._private.bgimage)
cr:set_source(pattern)
cr:paint()
end
end
end
-- Draw the border
function background:after_draw_children(_, cr)
-- Draw the border
if self._private.path and self._private.shape_border_width and self._private.shape_border_width > 0 then
cr:append_path(self._private.path)
cr:set_source(color(self._private.shape_border_color or self._private.foreground or beautiful.fg_normal))
cr:set_line_width(self._private.shape_border_width)
cr:stroke()
self._private.path = nil
end
end
-- Prepare drawing the children of this widget
function background:before_draw_children(_, cr)
if self._private.foreground then
cr:set_source(self._private.foreground)
end
-- Clip the shape
if self._private.path and self._private.shape_clip then
cr:append_path(self._private.path)
cr:clip()
end
end
-- Layout this widget
function background:layout(_, width, height)
if self._private.widget then
return { base.place_widget_at(self._private.widget, 0, 0, width, height) }
end
end
-- Fit this widget into the given area
function background:fit(context, width, height)
if not self._private.widget then
return 0, 0
end
return base.fit_widget(self, context, self._private.widget, width, height)
end
--- The widget displayed in the background widget.
-- @property widget
-- @tparam widget widget The widget to be disaplayed inside of the background
-- area
function background:set_widget(widget)
if widget then
base.check_widget(widget)
end
self._private.widget = widget
self:emit_signal("widget::layout_changed")
end
function background:get_widget()
return self._private.widget
end
-- Get children element
-- @treturn table The children
function background:get_children()
return {self._private.widget}
end
-- Replace the layout children
-- This layout only accept one children, all others will be ignored
-- @tparam table children A table composed of valid widgets
function background:set_children(children)
self:set_widget(children[1])
end
--- The background color/pattern/gradient to use.
--@DOC_wibox_container_background_bg_EXAMPLE@
-- @property bg
-- @param bg A color string, pattern or gradient
-- @see gears.color
function background:set_bg(bg)
if bg then
self._private.background = color(bg)
else
self._private.background = nil
end
self:emit_signal("widget::redraw_needed")
end
function background:get_bg()
return self._private.background
end
--- The foreground (text) color/pattern/gradient to use.
--@DOC_wibox_container_background_fg_EXAMPLE@
-- @property fg
-- @param fg A color string, pattern or gradient
-- @see gears.color
function background:set_fg(fg)
if fg then
self._private.foreground = color(fg)
else
self._private.foreground = nil
end
self:emit_signal("widget::redraw_needed")
end
function background:get_fg()
return self._private.foreground
end
--- The background shap e.
--
-- Use `set_shape` to set additional shape paramaters.
--
--@DOC_wibox_container_background_shape_EXAMPLE@
-- @property shape
-- @param shape A function taking a context, width and height as arguments
-- @see gears.shape
-- @see set_shape
--- Set the background shape.
--
-- Any other arguments will be passed to the shape function
-- @param shape A function taking a context, width and height as arguments
-- @see gears.shape
-- @see shape
function background:set_shape(shape, ...)
self._private.shape = shape
self._private.shape_args = {...}
self:emit_signal("widget::redraw_needed")
end
function background:get_shape()
return self._private.shape
end
--- When a `shape` is set, also draw a border.
--
-- See `wibox.container.background.shape` for an usage example.
-- @property shape_border_width
-- @tparam number width The border width
function background:set_shape_border_width(width)
self._private.shape_border_width = width
self:emit_signal("widget::redraw_needed")
end
function background:get_shape_border_width()
return self._private.shape_border_width
end
--- When a `shape` is set, also draw a border.
--
-- See `wibox.container.background.shape` for an usage example.
-- @property shape_border_color
-- @param[opt=self._private.foreground] fg The border color, pattern or gradient
-- @see gears.color
function background:set_shape_border_color(fg)
self._private.shape_border_color = fg
self:emit_signal("widget::redraw_needed")
end
function background:get_shape_border_color()
return self._private.shape_border_color
end
--- When a `shape` is set, make sure nothing is drawn outside of it.
--@DOC_wibox_container_background_clip_EXAMPLE@
-- @property shape_clip
-- @tparam boolean value If the shape clip is enable
function background:set_shape_clip(value)
self._private.shape_clip = value
self:emit_signal("widget::redraw_needed")
end
function background:get_shape_clip()
return self._private.shape_clip or false
end
--- The background image to use
-- If `image` is a function, it will be called with `(context, cr, width, height)`
-- as arguments. Any other arguments passed to this method will be appended.
-- @property bgimage
-- @param image A background image or a function
-- @see gears.surface
function background:set_bgimage(image, ...)
self._private.bgimage = type(image) == "function" and image or surface.load(image)
self._private.bgimage_args = {...}
self:emit_signal("widget::redraw_needed")
end
function background:get_bgimage()
return self._private.bgimage
end
--- Returns a new background container.
--
-- A background container applies a background and foreground color
-- to another widget.
-- @param[opt] widget The widget to display.
-- @param[opt] bg The background to use for that widget.
-- @param[opt] shape A `gears.shape` compatible shape function
-- @function wibox.container.background
local function new(widget, bg, shape)
local ret = base.make_widget(nil, nil, {
enable_properties = true,
})
util.table.crush(ret, background, true)
ret._private.shape = shape
ret:set_widget(widget)
ret:set_bg(bg)
return ret
end
function background.mt:__call(...)
return new(...)
end
--@DOC_widget_COMMON@
--@DOC_object_COMMON@
return setmetatable(background, background.mt)
-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80

View File

@ -0,0 +1,171 @@
---------------------------------------------------------------------------
--
--@DOC_wibox_container_defaults_constraint_EXAMPLE@
-- @author Lukáš Hrázký
-- @copyright 2012 Lukáš Hrázký
-- @release @AWESOME_VERSION@
-- @classmod wibox.container.constraint
---------------------------------------------------------------------------
local setmetatable = setmetatable
local base = require("wibox.widget.base")
local util = require("awful.util")
local math = math
local constraint = { mt = {} }
-- Layout a constraint layout
function constraint:layout(_, width, height)
if self._private.widget then
return { base.place_widget_at(self._private.widget, 0, 0, width, height) }
end
end
-- Fit a constraint layout into the given space
function constraint:fit(context, width, height)
local w, h
if self._private.widget then
w = self._private.strategy(width, self._private.width)
h = self._private.strategy(height, self._private.height)
w, h = base.fit_widget(self, context, self._private.widget, w, h)
else
w, h = 0, 0
end
w = self._private.strategy(w, self._private.width)
h = self._private.strategy(h, self._private.height)
return w, h
end
--- The widget to be constrained.
-- @property widget
-- @tparam widget widget The widget
function constraint:set_widget(widget)
self._private.widget = widget
self:emit_signal("widget::layout_changed")
end
function constraint:get_widget()
return self._private.widget
end
--- Get the number of children element
-- @treturn table The children
function constraint:get_children()
return {self._private.widget}
end
--- Replace the layout children
-- This layout only accept one children, all others will be ignored
-- @tparam table children A table composed of valid widgets
function constraint:set_children(children)
self:set_widget(children[1])
end
--- Set the strategy to use for the constraining. Valid values are 'max',
-- 'min' or 'exact'. Throws an error on invalid values.
-- @property strategy
function constraint:set_strategy(val)
local func = {
min = function(real_size, limit)
return limit and math.max(limit, real_size) or real_size
end,
max = function(real_size, limit)
return limit and math.min(limit, real_size) or real_size
end,
exact = function(real_size, limit)
return limit or real_size
end
}
if not func[val] then
error("Invalid strategy for constraint layout: " .. tostring(val))
end
self._private.strategy = func[val]
self:emit_signal("widget::layout_changed")
end
function constraint:get_strategy()
return self._private.strategy
end
--- Set the maximum width to val. nil for no width limit.
-- @property height
-- @param number
function constraint:set_width(val)
self._private.width = val
self:emit_signal("widget::layout_changed")
end
function constraint:get_width()
return self._private.width
end
--- Set the maximum height to val. nil for no height limit.
-- @property width
-- @param number
function constraint:set_height(val)
self._private.height = val
self:emit_signal("widget::layout_changed")
end
function constraint:get_height()
return self._private.height
end
--- Reset this layout. The widget will be unreferenced, strategy set to "max"
-- and the constraints set to nil.
function constraint:reset()
self._private.width = nil
self._private.height = nil
self:set_strategy("max")
self:set_widget(nil)
end
--- Returns a new constraint container.
-- This container will constraint the size of a
-- widget according to the strategy. Note that this will only work for layouts
-- that respect the widget's size, eg. fixed layout. In layouts that don't
-- (fully) respect widget's requested size, the inner widget still might get
-- drawn with a size that does not fit the constraint, eg. in flex layout.
-- @param[opt] widget A widget to use.
-- @param[opt] strategy How to constraint the size. 'max' (default), 'min' or
-- 'exact'.
-- @param[opt] width The maximum width of the widget. nil for no limit.
-- @param[opt] height The maximum height of the widget. nil for no limit.
-- @treturn table A new constraint container
-- @function wibox.container.constraint
local function new(widget, strategy, width, height)
local ret = base.make_widget(nil, nil, {enable_properties = true})
util.table.crush(ret, constraint, true)
ret:set_strategy(strategy or "max")
ret:set_width(width)
ret:set_height(height)
if widget then
ret:set_widget(widget)
end
return ret
end
function constraint.mt:__call(...)
return new(...)
end
--@DOC_widget_COMMON@
--@DOC_object_COMMON@
return setmetatable(constraint, constraint.mt)
-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80

View File

@ -0,0 +1,20 @@
---------------------------------------------------------------------------
--- Collection of containers that can be used in widget boxes
--
-- @author Uli Schlachter
-- @copyright 2010 Uli Schlachter
-- @release @AWESOME_VERSION@
-- @classmod wibox.container
---------------------------------------------------------------------------
local base = require("wibox.widget.base")
return setmetatable({
rotate = require("wibox.container.rotate");
margin = require("wibox.container.margin");
mirror = require("wibox.container.mirror");
constraint = require("wibox.container.constraint");
scroll = require("wibox.container.scroll");
background = require("wibox.container.background");
}, {__call = function(_, args) return base.make_widget_declarative(args) end})
-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80

View File

@ -0,0 +1,219 @@
---------------------------------------------------------------------------
--
--@DOC_wibox_container_defaults_margin_EXAMPLE@
-- @author Uli Schlachter
-- @copyright 2010 Uli Schlachter
-- @release @AWESOME_VERSION@
-- @classmod wibox.container.margin
---------------------------------------------------------------------------
local pairs = pairs
local setmetatable = setmetatable
local base = require("wibox.widget.base")
local gcolor = require("gears.color")
local cairo = require("lgi").cairo
local util = require("awful.util")
local margin = { mt = {} }
-- Draw a margin layout
function margin:draw(_, cr, width, height)
local x = self._private.left
local y = self._private.top
local w = self._private.right
local h = self._private.bottom
local color = self._private.color
if not self._private.widget or width <= x + w or height <= y + h then
return
end
if color then
cr:set_source(color)
cr:rectangle(0, 0, width, height)
cr:rectangle(x, y, width - x - w, height - y - h)
cr:set_fill_rule(cairo.FillRule.EVEN_ODD)
cr:fill()
end
end
-- Layout a margin layout
function margin:layout(_, width, height)
if self._private.widget then
local x = self._private.left
local y = self._private.top
local w = self._private.right
local h = self._private.bottom
return { base.place_widget_at(self._private.widget, x, y, width - x - w, height - y - h) }
end
end
-- Fit a margin layout into the given space
function margin:fit(context, width, height)
local extra_w = self._private.left + self._private.right
local extra_h = self._private.top + self._private.bottom
local w, h = 0, 0
if self._private.widget then
w, h = base.fit_widget(self, context, self._private.widget, width - extra_w, height - extra_h)
end
if self._private.draw_empty == false and (w == 0 or h == 0) then
return 0, 0
end
return w + extra_w, h + extra_h
end
--- The widget to be wrapped the the margins.
-- @property widget
-- @tparam widget widget The widget
function margin:set_widget(widget)
if widget then
base.check_widget(widget)
end
self._private.widget = widget
self:emit_signal("widget::layout_changed")
end
function margin:get_widget()
return self._private.widget
end
-- Get the number of children element
-- @treturn table The children
function margin:get_children()
return {self._private.widget}
end
-- Replace the layout children
-- This layout only accept one children, all others will be ignored
-- @tparam table children A table composed of valid widgets
function margin:set_children(children)
self:set_widget(children[1])
end
--- Set all the margins to val.
-- @property margins
-- @tparam number val The margin value
function margin:set_margins(val)
if self._private.left == val and
self._private.right == val and
self._private.top == val and
self._private.bottom == val then
return
end
self._private.left = val
self._private.right = val
self._private.top = val
self._private.bottom = val
self:emit_signal("widget::layout_changed")
end
--- Set the margins color to create a border.
-- @property color
-- @param color A color used to fill the margin.
function margin:set_color(color)
self._private.color = color and gcolor(color)
self:emit_signal("widget::redraw_needed")
end
function margin:get_color()
return self._private.color
end
--- Draw the margin even if the content size is 0x0 (default: true)
-- @function draw_empty
-- @tparam boolean draw_empty Draw nothing is content is 0x0 or draw the margin anyway
function margin:set_draw_empty(draw_empty)
self._private.draw_empty = draw_empty
self:emit_signal("widget::layout_changed")
end
function margin:get_draw_empty()
return self._private.draw_empty
end
--- Reset this layout. The widget will be unreferenced, the margins set to 0
-- and the color erased
function margin:reset()
self:set_widget(nil)
self:set_margins(0)
self:set_color(nil)
end
--- Set the left margin that this layout adds to its widget.
-- @param margin The new margin to use.
-- @property left
--- Set the right margin that this layout adds to its widget.
-- @param margin The new margin to use.
-- @property right
--- Set the top margin that this layout adds to its widget.
-- @param margin The new margin to use.
-- @property top
--- Set the bottom margin that this layout adds to its widget.
-- @param margin The new margin to use.
-- @property bottom
-- Create setters for each direction
for _, v in pairs({ "left", "right", "top", "bottom" }) do
margin["set_" .. v] = function(layout, val)
if layout._private[v] == val then return end
layout._private[v] = val
layout:emit_signal("widget::layout_changed")
end
margin["get_" .. v] = function(layout)
return layout._private[v]
end
end
--- Returns a new margin container.
-- @param[opt] widget A widget to use.
-- @param[opt] left A margin to use on the left side of the widget.
-- @param[opt] right A margin to use on the right side of the widget.
-- @param[opt] top A margin to use on the top side of the widget.
-- @param[opt] bottom A margin to use on the bottom side of the widget.
-- @param[opt] color A color for the margins.
-- @param[opt] draw_empty whether or not to draw the margin when the content is empty
-- @treturn table A new margin container
-- @function wibox.container.margin
local function new(widget, left, right, top, bottom, color, draw_empty)
local ret = base.make_widget(nil, nil, {enable_properties = true})
util.table.crush(ret, margin, true)
ret:set_left(left or 0)
ret:set_right(right or 0)
ret:set_top(top or 0)
ret:set_bottom(bottom or 0)
ret:set_draw_empty(draw_empty)
ret:set_color(color)
if widget then
ret:set_widget(widget)
end
return ret
end
function margin.mt:__call(...)
return new(...)
end
--@DOC_widget_COMMON@
--@DOC_object_COMMON@
return setmetatable(margin, margin.mt)
-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80

View File

@ -0,0 +1,140 @@
---------------------------------------------------------------------------
--
--@DOC_wibox_container_defaults_mirror_EXAMPLE@
-- @author dodo
-- @copyright 2012 dodo
-- @release @AWESOME_VERSION@
-- @classmod wibox.container.mirror
---------------------------------------------------------------------------
local type = type
local error = error
local ipairs = ipairs
local setmetatable = setmetatable
local base = require("wibox.widget.base")
local matrix = require("gears.matrix")
local util = require("awful.util")
local mirror = { mt = {} }
-- Layout this layout
function mirror:layout(_, width, height)
if not self._private.widget then return end
local m = matrix.identity
local t = { x = 0, y = 0 } -- translation
local s = { x = 1, y = 1 } -- scale
if self._private.horizontal then
t.x = width
s.x = -1
end
if self._private.vertical then
t.y = height
s.y = -1
end
m = m:translate(t.x, t.y)
m = m:scale(s.x, s.y)
return { base.place_widget_via_matrix(self._private.widget, m, width, height) }
end
-- Fit this layout into the given area
function mirror:fit(context, ...)
if not self._private.widget then
return 0, 0
end
return base.fit_widget(self, context, self._private.widget, ...)
end
--- The widget to be reflected.
-- @property widget
-- @tparam widget widget The widget
function mirror:set_widget(widget)
if widget then
base.check_widget(widget)
end
self._private.widget = widget
self:emit_signal("widget::layout_changed")
end
function mirror:get_widget()
return self._private.widget
end
--- Get the number of children element
-- @treturn table The children
function mirror:get_children()
return {self._private.widget}
end
--- Replace the layout children
-- This layout only accept one children, all others will be ignored
-- @tparam table children A table composed of valid widgets
function mirror:set_children(children)
self:set_widget(children[1])
end
--- Reset this layout. The widget will be removed and the axes reset.
function mirror:reset()
self._private.horizontal = false
self._private.vertical = false
self:set_widget(nil)
end
function mirror:set_reflection(reflection)
if type(reflection) ~= 'table' then
error("Invalid type of reflection for mirror layout: " ..
type(reflection) .. " (should be a table)")
end
for _, ref in ipairs({"horizontal", "vertical"}) do
if reflection[ref] ~= nil then
self._private[ref] = reflection[ref]
end
end
self:emit_signal("widget::layout_changed")
end
--- Get the reflection of this mirror layout.
-- @property reflection
-- @param table reflection A table of booleans with the keys "horizontal", "vertical".
-- @param boolean reflection.horizontal
-- @param boolean reflection.vertical
function mirror:get_reflection()
return { horizontal = self._private.horizontal, vertical = self._private.vertical }
end
--- Returns a new mirror container.
-- A mirror container mirrors a given widget. Use
-- `:set_widget()` to set the widget and
-- `:set_horizontal()` and `:set_vertical()` for the direction.
-- horizontal and vertical are by default false which doesn't change anything.
-- @param[opt] widget The widget to display.
-- @param[opt] reflection A table describing the reflection to apply.
-- @treturn table A new mirror container
-- @function wibox.container.mirror
local function new(widget, reflection)
local ret = base.make_widget(nil, nil, {enable_properties = true})
ret._private.horizontal = false
ret._private.vertical = false
util.table.crush(ret, mirror, true)
ret:set_widget(widget)
ret:set_reflection(reflection or {})
return ret
end
function mirror.mt:__call(...)
return new(...)
end
--@DOC_widget_COMMON@
--@DOC_object_COMMON@
return setmetatable(mirror, mirror.mt)
-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80

View File

@ -0,0 +1,159 @@
---------------------------------------------------------------------------
-- A container rotating the conained widget by 90 degrees.
--
--@DOC_wibox_container_defaults_rotate_EXAMPLE@
-- @author Uli Schlachter
-- @copyright 2010 Uli Schlachter
-- @release @AWESOME_VERSION@
-- @classmod wibox.container.rotate
---------------------------------------------------------------------------
local error = error
local pi = math.pi
local setmetatable = setmetatable
local tostring = tostring
local base = require("wibox.widget.base")
local matrix = require("gears.matrix")
local util = require("awful.util")
local rotate = { mt = {} }
local function transform(layout, width, height)
local dir = layout:get_direction()
if dir == "east" or dir == "west" then
return height, width
end
return width, height
end
-- Layout this layout
function rotate:layout(_, width, height)
if not self._private.widget or not self._private.widget._private.visible then
return
end
local dir = self:get_direction()
local m = matrix.identity
if dir == "west" then
m = m:rotate(pi / 2)
m = m:translate(0, -width)
elseif dir == "south" then
m = m:rotate(pi)
m = m:translate(-width, -height)
elseif dir == "east" then
m = m:rotate(3 * pi / 2)
m = m:translate(-height, 0)
end
-- Since we rotated, we might have to swap width and height.
-- transform() does that for us.
return { base.place_widget_via_matrix(self._private.widget, m, transform(self, width, height)) }
end
-- Fit this layout into the given area
function rotate:fit(context, width, height)
if not self._private.widget then
return 0, 0
end
return transform(self, base.fit_widget(self, context, self._private.widget, transform(self, width, height)))
end
--- The widget to be rotated.
-- @property widget
-- @tparam widget widget The widget
function rotate:set_widget(widget)
if widget then
base.check_widget(widget)
end
self._private.widget = widget
self:emit_signal("widget::layout_changed")
end
function rotate:get_widget()
return self._private.widget
end
--- Get the number of children element
-- @treturn table The children
function rotate:get_children()
return {self._private.widget}
end
--- Replace the layout children
-- This layout only accept one children, all others will be ignored
-- @tparam table children A table composed of valid widgets
function rotate:set_children(children)
self:set_widget(children[1])
end
--- Reset this layout. The widget will be removed and the rotation reset.
function rotate:reset()
self._private.direction = nil
self:set_widget(nil)
end
--@DOC_widget_COMMON@
--@DOC_object_COMMON@
--- The direction of this rotating container.
-- Valid values are:
--
-- * *north*
-- * *east*
-- * *south*
-- * *north*
--
--@DOC_wibox_container_rotate_angle_EXAMPLE@
-- @property direction
-- @tparam string dir The direction
function rotate:set_direction(dir)
local allowed = {
north = true,
east = true,
south = true,
west = true
}
if not allowed[dir] then
error("Invalid direction for rotate layout: " .. tostring(dir))
end
self._private.direction = dir
self:emit_signal("widget::layout_changed")
end
--- Get the direction of this rotating layout
function rotate:get_direction()
return self._private.direction or "north"
end
--- Returns a new rotate container.
-- A rotate container rotates a given widget. Use
-- :set_widget() to set the widget and :set_direction() for the direction.
-- The default direction is "north" which doesn't change anything.
-- @param[opt] widget The widget to display.
-- @param[opt] dir The direction to rotate to.
-- @treturn table A new rotate container.
-- @function wibox.container.rotate
local function new(widget, dir)
local ret = base.make_widget(nil, nil, {enable_properties = true})
util.table.crush(ret, rotate, true)
ret:set_widget(widget)
ret:set_direction(dir or "north")
return ret
end
function rotate.mt:__call(...)
return new(...)
end
return setmetatable(rotate, rotate.mt)
-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80

View File

@ -0,0 +1,519 @@
---------------------------------------------------------------------------
-- @author Uli Schlachter (based on ideas from Saleur Geoffrey)
-- @copyright 2015 Uli Schlachter
-- @release @AWESOME_VERSION@
-- @classmod wibox.container.scroll
---------------------------------------------------------------------------
local cache = require("gears.cache")
local timer = require("gears.timer")
local hierarchy = require("wibox.hierarchy")
local base = require("wibox.widget.base")
local lgi = require("lgi")
local GLib = lgi.GLib
local scroll = {}
local scroll_mt = { __index = scroll }
local _need_scroll_redraw
-- "Strip" a context so that we can use it for our own drawing
local function cleanup_context(context)
local skip = { wibox = true, drawable = true, client = true, position = true }
local res = {}
for k, v in pairs(context) do
if not skip[k] then
res[k] = v
end
end
return res
end
-- Create a hierarchy (and some more stuff) for drawing the given widget. This
-- allows "some stuff" to be re-used instead of re-created all the time.
local hierarchy_cache = cache.new(function(context, widget, width, height)
context = cleanup_context(context)
local layouts = setmetatable({}, { __mode = "k" })
-- Create a widget hierarchy and update when needed
local hier
local function do_pending_updates(layout)
layouts[layout] = true
hier:update(context, widget, width, height, nil)
end
local function emit(signal)
-- Make the scroll layouts redraw
for w in pairs(layouts) do
w:emit_signal(signal)
end
end
local function redraw_callback()
emit("widget::redraw_needed")
end
local function layout_callback()
emit("widget::redraw_needed")
emit("widget::layout_changed")
end
hier = hierarchy.new(context, widget, width, height, redraw_callback, layout_callback, nil)
return hier, do_pending_updates, context
end)
--- Calculate all the information needed for scrolling.
-- @param self The instance of the scrolling layout.
-- @param context A widget context under which we are fit/drawn.
-- @param width The available width
-- @param height The available height
-- @return A table with the following entries
-- @field fit_width The width that should be returned from :fit
-- @field fit_height The height that should be returned from :fit
-- @field surface_width The width for showing the child widget
-- @field surface_height The height for showing the child widget
-- @field first_x The x offset for drawing the child the first time
-- @field first_y The y offset for drawing the child the first time
-- @field[opt] second_x The x offset for drawing the child the second time
-- @field[opt] second_y The y offset for drawing the child the second time
-- @field hierarchy The wibox.hierarchy instance representing "everything"
-- @field context The widget context for drawing the hierarchy
local function calculate_info(self, context, width, height)
local result = {}
assert(self._private.widget)
-- First, get the size of the widget (and the size of extra space)
local surface_width, surface_height = width, height
local extra_width, extra_height, extra = 0, 0, self._private.expand and self._private.extra_space or 0
local w, h
if self._private.dir == "h" then
w, h = base.fit_widget(self, context, self._private.widget, self._private.space_for_scrolling, height)
surface_width = w
extra_width = extra
else
w, h = base.fit_widget(self, context, self._private.widget, width, self._private.space_for_scrolling)
surface_height = h
extra_height = extra
end
result.fit_width, result.fit_height = w, h
if self._private.dir == "h" then
if self._private.max_size then
result.fit_width = math.min(w, self._private.max_size)
end
else
if self._private.max_size then
result.fit_height = math.min(h, self._private.max_size)
end
end
if w > width or h > height then
-- There is less space available than we need, we have to scroll
_need_scroll_redraw(self)
surface_width, surface_height = surface_width + extra_width, surface_height + extra_height
local x, y = 0, 0
local function get_scroll_offset(size, visible_size)
return self._private.step_function(self._private.timer:elapsed(), size, visible_size, self._private.speed, self._private.extra_space)
end
if self._private.dir == "h" then
x = -get_scroll_offset(surface_width - extra, width)
else
y = -get_scroll_offset(surface_height - extra, height)
end
result.first_x, result.first_y = x, y
-- Was the extra space already included elsewhere?
local extra_spacer = self._private.expand and 0 or self._private.extra_space
if self._private.dir == "h" then
x = x + surface_width + extra_spacer
else
y = y + surface_height + extra_spacer
end
result.second_x, result.second_y = x, y
else
result.first_x, result.first_y = 0, 0
end
result.surface_width, result.surface_height = surface_width, surface_height
-- Get the hierarchy and subscribe ourselves to updates
local hier, do_pending_updates, ctx = hierarchy_cache:get(context,
self._private.widget, surface_width, surface_height)
result.hierarchy = hier
result.context = ctx
do_pending_updates(self)
return result
end
-- Draw this scrolling layout.
-- @param context The context in which we are drawn.
-- @param cr The cairo context to draw to.
-- @param width The available width.
-- @param height The available height.
function scroll:draw(context, cr, width, height)
if not self._private.widget then
return
end
local info = calculate_info(self, context, width, height)
-- Draw the first instance of the child
cr:save()
cr:translate(info.first_x, info.first_y)
cr:rectangle(0, 0, info.surface_width, info.surface_height)
cr:clip()
info.hierarchy:draw(info.context, cr)
cr:restore()
-- If there is one, draw the second instance (same code as above, minus the
-- clip)
if info.second_x and info.second_y then
cr:translate(info.second_x, info.second_y)
cr:rectangle(0, 0, info.surface_width, info.surface_height)
cr:clip()
info.hierarchy:draw(info.context, cr)
end
end
-- Fit the scroll layout into the given space.
-- @param context The context in which we are fit.
-- @param width The available width.
-- @param height The available height.
function scroll:fit(context, width, height)
if not self._private.widget then
return 0, 0
end
local info = calculate_info(self, context, width, height)
return info.fit_width, info.fit_height
end
-- Internal function used for triggering redraws for scrolling.
-- The purpose is to start a timer for redrawing the widget for scrolling.
-- Redrawing works by simply emitting the `widget::redraw_needed` signal.
-- Pausing is implemented in this function: We just don't start a timer.
-- This function must be idempotent (calling it multiple times right after
-- another does not make a difference).
_need_scroll_redraw = function(self)
if not self._private.paused and not self._private.scroll_timer then
self._private.scroll_timer = timer.start_new(1 / self._private.fps, function()
self._private.scroll_timer = nil
self:emit_signal("widget::redraw_needed")
end)
end
end
--- Pause the scrolling animation.
-- @see continue
function scroll:pause()
if self._private.paused then
return
end
self._private.paused = true
self._private.timer:stop()
end
--- Continue the scrolling animation.
-- @see pause
function scroll:continue()
if not self._private.paused then
return
end
self._private.paused = false
self._private.timer:continue()
self:emit_signal("widget::redraw_needed")
end
--- Reset the scrolling state to its initial condition.
-- For must scroll step functions, the effect of this function should be to
-- display the widget without any scrolling applied.
-- This function does not undo the effect of @{pause}.
function scroll:reset_scrolling()
self._private.timer:start()
if self._private.paused then
self._private.timer:stop()
end
end
--- Set the direction in which this widget scroll.
-- @param dir Either "h" for horizontal scrolling or "v" for vertical scrolling
function scroll:set_direction(dir)
if dir == self._private.dir then
return
end
if dir ~= "h" and dir ~= "v" then
error("Invalid direction, can only be 'h' or 'v'")
end
self._private.dir = dir
self:emit_signal("widget::layout_changed")
self:emit_signal("widget::redraw_needed")
end
--- The widget to be scrolled.
-- @property widget
-- @tparam widget widget The widget
function scroll:set_widget(widget)
if widget == self._private.widget then
return
end
if widget then
base.check_widget(widget)
end
self._private.widget = widget
self:emit_signal("widget::layout_changed")
self:emit_signal("widget::redraw_needed")
end
function scroll:get_widget()
return self._private.widget
end
--- Get the number of children element
-- @treturn table The children
function scroll:get_children()
return {self._private.widget}
end
--- Replace the layout children
-- This layout only accept one children, all others will be ignored
-- @tparam table children A table composed of valid widgets
function scroll:set_children(children)
self:set_widget(children[1])
end
--- Specify the expand mode that is used for extra space.
-- @tparam boolean expand If true, the widget is expanded to include the extra
-- space. If false, the extra space is simply left empty.
-- @see set_extra_space
function scroll:set_expand(expand)
if expand == self._private.expand then
return
end
self._private.expand = expand
self:emit_signal("widget::redraw_needed")
end
--- Set the number of frames per second that this widget should draw.
-- @tparam number fps The number of frames per second
function scroll:set_fps(fps)
if fps == self._private.fps then
return
end
self._private.fps = fps
-- No signal needed: If we are scrolling, the next redraw will apply the new
-- FPS, else it obviously doesn't make a difference.
end
--- Set the amount of extra space that should be included in the scrolling. This
-- extra space will likely be left empty between repetitions of the widgets.
-- @tparam number extra_space The amount of extra space
-- @see set_expand
function scroll:set_extra_space(extra_space)
if extra_space == self._private.extra_space then
return
end
self._private.extra_space = extra_space
self:emit_signal("widget::redraw_needed")
end
--- Set the speed of the scrolling animation. The exact meaning depends on the
-- step function that is used, but for the simplest step functions, this will be
-- in pixels per second.
-- @tparam number speed The speed for the animation
function scroll:set_speed(speed)
if speed == self._private.speed then
return
end
self._private.speed = speed
self:emit_signal("widget::redraw_needed")
end
--- Set the maximum size of this widget in the direction set by
-- @{set_direction}. If the child widget is smaller than this size, no scrolling
-- is done. If the child widget is larger, then only this size will be visible
-- and the rest is made visible via scrolling.
-- @tparam number max_size The maximum size of this widget or nil for unlimited.
function scroll:set_max_size(max_size)
if max_size == self._private.max_size then
return
end
self._private.max_size = max_size
self:emit_signal("widget::layout_changed")
end
--- Set the step function that determines the exact behaviour of the scrolling
-- animation.
-- The step function is called with five arguments:
--
-- * The time in seconds since the state of the animation
-- * The size of the child widget
-- * The size of the visible part of the widget
-- * The speed of the animation. This should have a linear effect on this
-- function's behaviour.
-- * The extra space configured by @{set_extra_space}. This was not yet added to
-- the size of the child widget, but should likely be added to it in most
-- cases.
--
-- The step function should return a single number. This number is the offset at
-- which the widget is drawn and should be between 0 and `size+extra_space`.
-- @tparam function step_function A step function.
-- @see step_functions
function scroll:set_step_function(step_function)
-- Call the step functions once to see if it works
step_function(0, 42, 10, 10, 5)
if step_function == self._private.step_function then
return
end
self._private.step_function = step_function
self:emit_signal("widget::redraw_needed")
end
--- Set an upper limit for the space for scrolling.
-- This restricts the child widget's maximal size.
-- @tparam number space_for_scrolling The space for scrolling
function scroll:set_space_for_scrolling(space_for_scrolling)
if space_for_scrolling == self._private.space_for_scrolling then
return
end
self._private.space_for_scrolling = space_for_scrolling
self:emit_signal("widget::layout_changed")
end
local function get_layout(dir, widget, fps, speed, extra_space, expand, max_size, step_function, space_for_scrolling)
local ret = base.make_widget(nil, nil, {enable_properties = true})
ret._priavte.paused = false
ret._private.timer = GLib.Timer()
ret._private.scroll_timer = nil
setmetatable(ret, scroll_mt)
ret:set_direction(dir)
ret:set_widget(widget)
ret:set_fps(fps or 20)
ret:set_speed(speed or 10)
ret:set_extra_space(extra_space or 0)
ret:set_expand(expand)
ret:set_max_size(max_size)
ret:set_step_function(step_function or scroll.step_functions.linear_increase)
ret:set_space_for_scrolling(space_for_scrolling or 2^1024)
return ret
end
--- Get a new horizontal scrolling container.
-- @param[opt] widget The widget that should be scrolled
-- @param[opt=20] fps The number of frames per second
-- @param[opt=10] speed The speed of the animation
-- @param[opt=0] extra_space The amount of extra space to include
-- @tparam[opt=false] boolean expand Should the widget be expanded to include the
-- extra space?
-- @param[opt] max_size The maximum size of the child widget
-- @param[opt=step_functions.linear_increase] step_function The step function to be used
-- @param[opt=2^1024] space_for_scrolling The space for scrolling
function scroll.horizontal(widget, fps, speed, extra_space, expand, max_size, step_function, space_for_scrolling)
return get_layout("h", widget, fps, speed, extra_space, expand, max_size, step_function, space_for_scrolling)
end
--- Get a new vertical scrolling container.
-- @param[opt] widget The widget that should be scrolled
-- @param[opt=20] fps The number of frames per second
-- @param[opt=10] speed The speed of the animation
-- @param[opt=0] extra_space The amount of extra space to include
-- @tparam[opt=false] boolean expand Should the widget be expanded to include the
-- extra space?
-- @param[opt] max_size The maximum size of the child widget
-- @param[opt=step_functions.linear_increase] step_function The step function to be used
-- @param[opt=2^1024] space_for_scrolling The space for scrolling
function scroll.vertical(widget, fps, speed, extra_space, expand, max_size, step_function, space_for_scrolling)
return get_layout("v", widget, fps, speed, extra_space, expand, max_size, step_function, space_for_scrolling)
end
--- A selection of step functions
-- @see set_step_function
scroll.step_functions = {}
--- A step function that scrolls the widget in an increasing direction with
-- constant speed.
function scroll.step_functions.linear_increase(elapsed, size, _, speed, extra_space)
return (elapsed * speed) % (size + extra_space)
end
--- A step function that scrolls the widget in an decreasing direction with
-- constant speed.
function scroll.step_functions.linear_decrease(elapsed, size, _, speed, extra_space)
return (-elapsed * speed) % (size + extra_space)
end
--- A step function that scrolls the widget to its end and back to its
-- beginning, then back to its end, etc. The speed is constant.
function scroll.step_functions.linear_back_and_forth(elapsed, size, visible_size, speed)
local state = ((elapsed * speed) % (2 * size)) / size
state = state <= 1 and state or 2 - state
return (size - visible_size) * state
end
--- A step function that scrolls the widget to its end and back to its
-- beginning, then back to its end, etc. The speed is null at the ends and
-- maximal in the middle.
function scroll.step_functions.nonlinear_back_and_forth(elapsed, size, visible_size, speed)
local state = ((elapsed * speed) % (2 * size)) / size
local negate = false
if state > 1 then
negate = true
state = state - 1
end
if state < 1/3 then
-- In the first 1/3rd of time, do a quadratic increase in speed
state = 2 * state * state
elseif state < 2/3 then
-- In the center, do a linear increase. That means we need:
-- If state is 1/3, result is 2/9 = 2 * 1/3 * 1/3
-- If state is 2/3, result is 7/9 = 1 - 2 * (1 - 2/3) * (1 - 2/3)
state = 5/3*state - 3/9
else
-- In the last 1/3rd of time, do a quadratic decrease in speed
state = 1 - 2 * (1 - state) * (1 - state)
end
if negate then
state = 1 - state
end
return (size - visible_size) * state
end
--- A step function that scrolls the widget to its end and back to its
-- beginning, then back to its end, etc. The speed is null at the ends and
-- maximal in the middle. At both ends the widget stands still for a moment.
function scroll.step_functions.waiting_nonlinear_back_and_forth(elapsed, size, visible_size, speed)
local state = ((elapsed * speed) % (2 * size)) / size
local negate = false
if state > 1 then
negate = true
state = state - 1
end
if state < 1/5 or state > 4/5 then
-- One fifth of time, nothing moves
state = state < 1/5 and 0 or 1
else
state = (state - 1/5) * 5/3
if state < 1/3 then
-- In the first 1/3rd of time, do a quadratic increase in speed
state = 2 * state * state
elseif state < 2/3 then
-- In the center, do a linear increase. That means we need:
-- If state is 1/3, result is 2/9 = 2 * 1/3 * 1/3
-- If state is 2/3, result is 7/9 = 1 - 2 * (1 - 2/3) * (1 - 2/3)
state = 5/3*state - 3/9
else
-- In the last 1/3rd of time, do a quadratic decrease in speed
state = 1 - 2 * (1 - state) * (1 - state)
end
end
if negate then
state = 1 - state
end
return (size - visible_size) * state
end
--@DOC_widget_COMMON@
--@DOC_object_COMMON@
return scroll
-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80

View File

@ -259,7 +259,7 @@ end
-- @param cr The cairo context that is used for drawing. -- @param cr The cairo context that is used for drawing.
function hierarchy:draw(context, cr) function hierarchy:draw(context, cr)
local widget = self:get_widget() local widget = self:get_widget()
if not widget.visible then if not widget._private.visible then
return return
end end
@ -272,7 +272,7 @@ function hierarchy:draw(context, cr)
-- Draw if needed -- Draw if needed
if not empty_clip(cr) then if not empty_clip(cr) then
local opacity = widget.opacity local opacity = widget:get_opacity()
local function call(func, extra_arg1, extra_arg2) local function call(func, extra_arg1, extra_arg2)
if not func then return end if not func then return end
if not extra_arg2 then if not extra_arg2 then

View File

@ -24,6 +24,7 @@ local base = require("wibox.widget.base")
-- wibox -- wibox
local wibox = { mt = {}, object = {} } local wibox = { mt = {}, object = {} }
wibox.layout = require("wibox.layout") wibox.layout = require("wibox.layout")
wibox.container = require("wibox.container")
wibox.widget = require("wibox.widget") wibox.widget = require("wibox.widget")
wibox.drawable = require("wibox.drawable") wibox.drawable = require("wibox.drawable")
wibox.hierarchy = require("wibox.hierarchy") wibox.hierarchy = require("wibox.hierarchy")

View File

@ -1,4 +1,6 @@
--------------------------------------------------------------------------- ---------------------------------------------------------------------------
--
--@DOC_wibox_layout_defaults_align_EXAMPLE@
-- @author Uli Schlachter -- @author Uli Schlachter
-- @copyright 2010 Uli Schlachter -- @copyright 2010 Uli Schlachter
-- @release @AWESOME_VERSION@ -- @release @AWESOME_VERSION@
@ -14,7 +16,7 @@ local base = require("wibox.widget.base")
local align = {} local align = {}
--- Calculate the layout of an align layout. -- Calculate the layout of an align layout.
-- @param context The context in which we are drawn. -- @param context The context in which we are drawn.
-- @param width The available width. -- @param width The available width.
-- @param height The available height. -- @param height The available height.
@ -30,7 +32,7 @@ function align:layout(context, width, height)
-- allowed. -- allowed.
local size_first = 0 local size_first = 0
-- start with all the space given by the parent, subtract as we go along -- start with all the space given by the parent, subtract as we go along
local size_remains = self.dir == "y" and height or width local size_remains = self._private.dir == "y" and height or width
-- This is only set & used if expand ~= "inside" and we have second width. -- This is only set & used if expand ~= "inside" and we have second width.
-- It contains the size allocated to the second widget. -- It contains the size allocated to the second widget.
local size_second local size_second
@ -39,84 +41,84 @@ function align:layout(context, width, height)
-- if it is, we prioritize the first widget by not doing this block also, -- if it is, we prioritize the first widget by not doing this block also,
-- if the second widget doesn't exist, we will prioritise the first one -- if the second widget doesn't exist, we will prioritise the first one
-- instead -- instead
if self._expand ~= "inside" and self.second then if self._private.expand ~= "inside" and self._private.second then
local w, h = base.fit_widget(self, context, self.second, width, height) local w, h = base.fit_widget(self, context, self._private.second, width, height)
size_second = self.dir == "y" and h or w size_second = self._private.dir == "y" and h or w
-- if all the space is taken, skip the rest, and draw just the middle -- if all the space is taken, skip the rest, and draw just the middle
-- widget -- widget
if size_second >= size_remains then if size_second >= size_remains then
return { base.place_widget_at(self.second, 0, 0, width, height) } return { base.place_widget_at(self._private.second, 0, 0, width, height) }
else else
-- the middle widget is sized first, the outside widgets are given -- the middle widget is sized first, the outside widgets are given
-- the remaining space if available we will draw later -- the remaining space if available we will draw later
size_remains = floor((size_remains - size_second) / 2) size_remains = floor((size_remains - size_second) / 2)
end end
end end
if self.first then if self._private.first then
local w, h, _ = width, height, nil local w, h, _ = width, height, nil
-- we use the fit function for the "inside" and "none" modes, but -- we use the fit function for the "inside" and "none" modes, but
-- ignore it for the "outside" mode, which will force it to expand -- ignore it for the "outside" mode, which will force it to expand
-- into the remaining space -- into the remaining space
if self._expand ~= "outside" then if self._private.expand ~= "outside" then
if self.dir == "y" then if self._private.dir == "y" then
_, h = base.fit_widget(self, context, self.first, width, size_remains) _, h = base.fit_widget(self, context, self._private.first, width, size_remains)
size_first = h size_first = h
-- for "inside", the third widget will get a chance to use the -- for "inside", the third widget will get a chance to use the
-- remaining space, then the middle widget. For "none" we give -- remaining space, then the middle widget. For "none" we give
-- the third widget the remaining space if there was no second -- the third widget the remaining space if there was no second
-- widget to take up any space (as the first if block is skipped -- widget to take up any space (as the first if block is skipped
-- if this is the case) -- if this is the case)
if self._expand == "inside" or not self.second then if self._private.expand == "inside" or not self._private.second then
size_remains = size_remains - h size_remains = size_remains - h
end end
else else
w, _ = base.fit_widget(self, context, self.first, size_remains, height) w, _ = base.fit_widget(self, context, self._private.first, size_remains, height)
size_first = w size_first = w
if self._expand == "inside" or not self.second then if self._private.expand == "inside" or not self._private.second then
size_remains = size_remains - w size_remains = size_remains - w
end end
end end
else else
if self.dir == "y" then if self._private.dir == "y" then
h = size_remains h = size_remains
else else
w = size_remains w = size_remains
end end
end end
table.insert(result, base.place_widget_at(self.first, 0, 0, w, h)) table.insert(result, base.place_widget_at(self._private.first, 0, 0, w, h))
end end
-- size_remains will be <= 0 if first used all the space -- size_remains will be <= 0 if first used all the space
if self.third and size_remains > 0 then if self._private.third and size_remains > 0 then
local w, h, _ = width, height, nil local w, h, _ = width, height, nil
if self._expand ~= "outside" then if self._private.expand ~= "outside" then
if self.dir == "y" then if self._private.dir == "y" then
_, h = base.fit_widget(self, context, self.third, width, size_remains) _, h = base.fit_widget(self, context, self._private.third, width, size_remains)
-- give the middle widget the rest of the space for "inside" mode -- give the middle widget the rest of the space for "inside" mode
if self._expand == "inside" then if self._private.expand == "inside" then
size_remains = size_remains - h size_remains = size_remains - h
end end
else else
w, _ = base.fit_widget(self, context, self.third, size_remains, height) w, _ = base.fit_widget(self, context, self._private.third, size_remains, height)
if self._expand == "inside" then if self._private.expand == "inside" then
size_remains = size_remains - w size_remains = size_remains - w
end end
end end
else else
if self.dir == "y" then if self._private.dir == "y" then
h = size_remains h = size_remains
else else
w = size_remains w = size_remains
end end
end end
local x, y = width - w, height - h local x, y = width - w, height - h
table.insert(result, base.place_widget_at(self.third, x, y, w, h)) table.insert(result, base.place_widget_at(self._private.third, x, y, w, h))
end end
-- here we either draw the second widget in the space set aside for it -- here we either draw the second widget in the space set aside for it
-- in the beginning, or in the remaining space, if it is "inside" -- in the beginning, or in the remaining space, if it is "inside"
if self.second and size_remains > 0 then if self._private.second and size_remains > 0 then
local x, y, w, h = 0, 0, width, height local x, y, w, h = 0, 0, width, height
if self._expand == "inside" then if self._private.expand == "inside" then
if self.dir == "y" then if self._private.dir == "y" then
h = size_remains h = size_remains
x, y = 0, size_first x, y = 0, size_first
else else
@ -125,62 +127,76 @@ function align:layout(context, width, height)
end end
else else
local _ local _
if self.dir == "y" then if self._private.dir == "y" then
_, h = base.fit_widget(self, context, self.second, width, size_second) _, h = base.fit_widget(self, context, self._private.second, width, size_second)
y = floor( (height - h)/2 ) y = floor( (height - h)/2 )
else else
w, _ = base.fit_widget(self, context, self.second, size_second, height) w, _ = base.fit_widget(self, context, self._private.second, size_second, height)
x = floor( (width -w)/2 ) x = floor( (width -w)/2 )
end end
end end
table.insert(result, base.place_widget_at(self.second, x, y, w, h)) table.insert(result, base.place_widget_at(self._private.second, x, y, w, h))
end end
return result return result
end end
--- Set the layout's first widget. This is the widget that is at the left/top --- Set the layout's first widget.
-- This is the widget that is at the left/top
-- @property first
function align:set_first(widget) function align:set_first(widget)
if self.first == widget then if self._private.first == widget then
return return
end end
self.first = widget self._private.first = widget
self:emit_signal("widget::layout_changed") self:emit_signal("widget::layout_changed")
end end
--- Set the layout's second widget. This is the centered one. --- Set the layout's second widget. This is the centered one.
-- @property second
function align:set_second(widget) function align:set_second(widget)
if self.second == widget then if self._private.second == widget then
return return
end end
self.second = widget self._private.second = widget
self:emit_signal("widget::layout_changed") self:emit_signal("widget::layout_changed")
end end
--- Set the layout's third widget. This is the widget that is at the right/bottom --- Set the layout's third widget.
-- This is the widget that is at the right/bottom
-- @property third
function align:set_third(widget) function align:set_third(widget)
if self.third == widget then if self._private.third == widget then
return return
end end
self.third = widget self._private.third = widget
self:emit_signal("widget::layout_changed") self:emit_signal("widget::layout_changed")
end end
--- Get all children of this layout for _, prop in ipairs {"first", "second", "third", "expand" } do
-- @treturn table a list of all widgets align["get_"..prop] = function(self)
function align:get_children() return self._private[prop]
return util.from_sparse {self.first, self.second, self.third} end
end
--- All direct children of this layout.
-- This can be used to replace all 3 widgets at once.
-- @treturn table a list of all widgets
-- @property children
function align:get_children()
return util.from_sparse {self._private.first, self._private.second, self._private.third}
end end
--- Replace the layout children
-- This layout only accept three children, all others will be ignored
-- @tparam table children A table composed of valid widgets
function align:set_children(children) function align:set_children(children)
self:set_first(children[1]) self:set_first(children[1])
self:set_second(children[2]) self:set_second(children[2])
self:set_third(children[3]) self:set_third(children[3])
end end
--- Fit the align layout into the given space. The align layout will -- Fit the align layout into the given space. The align layout will
-- ask for the sum of the sizes of its sub-widgets in its direction -- ask for the sum of the sizes of its sub-widgets in its direction
-- and the largest sized sub widget in the other direction. -- and the largest sized sub widget in the other direction.
-- @param context The context in which we are fit. -- @param context The context in which we are fit.
@ -190,18 +206,18 @@ function align:fit(context, orig_width, orig_height)
local used_in_dir = 0 local used_in_dir = 0
local used_in_other = 0 local used_in_other = 0
for _, v in pairs{self.first, self.second, self.third} do for _, v in pairs{self._private.first, self._private.second, self._private.third} do
local w, h = base.fit_widget(self, context, v, orig_width, orig_height) local w, h = base.fit_widget(self, context, v, orig_width, orig_height)
local max = self.dir == "y" and w or h local max = self._private.dir == "y" and w or h
if max > used_in_other then if max > used_in_other then
used_in_other = max used_in_other = max
end end
used_in_dir = used_in_dir + (self.dir == "y" and h or w) used_in_dir = used_in_dir + (self._private.dir == "y" and h or w)
end end
if self.dir == "y" then if self._private.dir == "y" then
return used_in_other, used_in_dir return used_in_other, used_in_dir
end end
return used_in_dir, used_in_other return used_in_dir, used_in_other
@ -221,11 +237,13 @@ end
-- * "none" - All widgets are sized using their fit function, drawn to only the -- * "none" - All widgets are sized using their fit function, drawn to only the
-- returned space, or remaining space, whichever is smaller. Center widget -- returned space, or remaining space, whichever is smaller. Center widget
-- gets priority. -- gets priority.
-- @property expand
function align:set_expand(mode) function align:set_expand(mode)
if mode == "none" or mode == "outside" then if mode == "none" or mode == "outside" then
self._expand = mode self._private.expand = mode
else else
self._expand = "inside" self._private.expand = "inside"
end end
self:emit_signal("widget::layout_changed") self:emit_signal("widget::layout_changed")
end end
@ -238,12 +256,12 @@ function align:reset()
end end
local function get_layout(dir, first, second, third) local function get_layout(dir, first, second, third)
local ret = base.make_widget() local ret = base.make_widget(nil, nil, {enable_properties = true})
ret.dir = dir ret._private.dir = dir
for k, v in pairs(align) do for k, v in pairs(align) do
if type(v) == "function" then if type(v) == "function" then
ret[k] = v rawset(ret, k, v)
end end
end end
@ -268,9 +286,9 @@ end
function align.horizontal(left, middle, right) function align.horizontal(left, middle, right)
local ret = get_layout("x", left, middle, right) local ret = get_layout("x", left, middle, right)
ret.set_left = ret.set_first rawset(ret, "set_left" , ret.set_first )
ret.set_middle = ret.set_second rawset(ret, "set_middle", ret.set_second )
ret.set_right = ret.set_third rawset(ret, "set_right" , ret.set_third )
return ret return ret
end end
@ -285,13 +303,17 @@ end
function align.vertical(top, middle, bottom) function align.vertical(top, middle, bottom)
local ret = get_layout("y", top, middle, bottom) local ret = get_layout("y", top, middle, bottom)
ret.set_top = ret.set_first rawset(ret, "set_top" , ret.set_first )
ret.set_middle = ret.set_second rawset(ret, "set_middle", ret.set_second )
ret.set_bottom = ret.set_third rawset(ret, "set_bottom", ret.set_third )
return ret return ret
end end
--@DOC_widget_COMMON@
--@DOC_object_COMMON@
return align return align
-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80 -- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80

View File

@ -1,140 +1,18 @@
--------------------------------------------------------------------------- ---------------------------------------------------------------------------
-- This class has been moved to `wibox.container.`
--
-- @author Lukáš Hrázký -- @author Lukáš Hrázký
-- @copyright 2012 Lukáš Hrázký -- @copyright 2012 Lukáš Hrázký
-- @release @AWESOME_VERSION@ -- @release @AWESOME_VERSION@
-- @classmod wibox.layout.constraint -- @classmod wibox.layout.constraint
--------------------------------------------------------------------------- ---------------------------------------------------------------------------
local pairs = pairs local util = require("awful.util")
local type = type
local setmetatable = setmetatable
local base = require("wibox.widget.base")
local math = math
local constraint = { mt = {} } return util.deprecate_class(
require("wibox.container.constraint"),
--- Layout a constraint layout "wibox.layout.constraint",
function constraint:layout(_, width, height) "wibox.container.constraint"
if self.widget then )
return { base.place_widget_at(self.widget, 0, 0, width, height) }
end
end
--- Fit a constraint layout into the given space
function constraint:fit(context, width, height)
local w, h
if self.widget then
w = self._strategy(width, self._width)
h = self._strategy(height, self._height)
w, h = base.fit_widget(self, context, self.widget, w, h)
else
w, h = 0, 0
end
w = self._strategy(w, self._width)
h = self._strategy(h, self._height)
return w, h
end
--- Set the widget that this layout adds a constraint on.
function constraint:set_widget(widget)
self.widget = widget
self:emit_signal("widget::layout_changed")
end
--- Get the number of children element
-- @treturn table The children
function constraint:get_children()
return {self.widget}
end
--- Replace the layout children
-- This layout only accept one children, all others will be ignored
-- @tparam table children A table composed of valid widgets
function constraint:set_children(children)
self:set_widget(children[1])
end
--- Set the strategy to use for the constraining. Valid values are 'max',
-- 'min' or 'exact'. Throws an error on invalid values.
function constraint:set_strategy(val)
local func = {
min = function(real_size, limit)
return limit and math.max(limit, real_size) or real_size
end,
max = function(real_size, limit)
return limit and math.min(limit, real_size) or real_size
end,
exact = function(real_size, limit)
return limit or real_size
end
}
if not func[val] then
error("Invalid strategy for constraint layout: " .. tostring(val))
end
self._strategy = func[val]
self:emit_signal("widget::layout_changed")
end
--- Set the maximum width to val. nil for no width limit.
function constraint:set_width(val)
self._width = val
self:emit_signal("widget::layout_changed")
end
--- Set the maximum height to val. nil for no height limit.
function constraint:set_height(val)
self._height = val
self:emit_signal("widget::layout_changed")
end
--- Reset this layout. The widget will be unreferenced, strategy set to "max"
-- and the constraints set to nil.
function constraint:reset()
self._width = nil
self._height = nil
self:set_strategy("max")
self:set_widget(nil)
end
--- Returns a new constraint layout. This layout will constraint the size of a
-- widget according to the strategy. Note that this will only work for layouts
-- that respect the widget's size, eg. fixed layout. In layouts that don't
-- (fully) respect widget's requested size, the inner widget still might get
-- drawn with a size that does not fit the constraint, eg. in flex layout.
-- @param[opt] widget A widget to use.
-- @param[opt] strategy How to constraint the size. 'max' (default), 'min' or
-- 'exact'.
-- @param[opt] width The maximum width of the widget. nil for no limit.
-- @param[opt] height The maximum height of the widget. nil for no limit.
local function new(widget, strategy, width, height)
local ret = base.make_widget()
for k, v in pairs(constraint) do
if type(v) == "function" then
ret[k] = v
end
end
ret:set_strategy(strategy or "max")
ret:set_width(width)
ret:set_height(height)
if widget then
ret:set_widget(widget)
end
return ret
end
function constraint.mt:__call(...)
return new(...)
end
return setmetatable(constraint, constraint.mt)
-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80 -- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80

View File

@ -1,4 +1,6 @@
--------------------------------------------------------------------------- ---------------------------------------------------------------------------
--
--@DOC_wibox_layout_defaults_fixed_EXAMPLE@
-- @author Uli Schlachter -- @author Uli Schlachter
-- @copyright 2010 Uli Schlachter -- @copyright 2010 Uli Schlachter
-- @release @AWESOME_VERSION@ -- @release @AWESOME_VERSION@
@ -21,28 +23,28 @@ local fixed = {}
-- @param height The available height. -- @param height The available height.
function fixed:layout(context, width, height) function fixed:layout(context, width, height)
local result = {} local result = {}
local pos,spacing = 0, self._spacing local pos,spacing = 0, self._private.spacing
for k, v in pairs(self.widgets) do for k, v in pairs(self._private.widgets) do
local x, y, w, h, _ local x, y, w, h, _
if self.dir == "y" then if self._private.dir == "y" then
x, y = 0, pos x, y = 0, pos
w, h = width, height - pos w, h = width, height - pos
if k ~= #self.widgets or not self._fill_space then if k ~= #self._private.widgets or not self._private.fill_space then
_, h = base.fit_widget(self, context, v, w, h); _, h = base.fit_widget(self, context, v, w, h);
end end
pos = pos + h + spacing pos = pos + h + spacing
else else
x, y = pos, 0 x, y = pos, 0
w, h = width - pos, height w, h = width - pos, height
if k ~= #self.widgets or not self._fill_space then if k ~= #self._private.widgets or not self._private.fill_space then
w, _ = base.fit_widget(self, context, v, w, h); w, _ = base.fit_widget(self, context, v, w, h);
end end
pos = pos + w + spacing pos = pos + w + spacing
end end
if (self.dir == "y" and pos-spacing > height) or if (self._private.dir == "y" and pos-spacing > height) or
(self.dir ~= "y" and pos-spacing > width) then (self._private.dir ~= "y" and pos-spacing > width) then
break break
end end
table.insert(result, base.place_widget_at(v, x, y, w, h)) table.insert(result, base.place_widget_at(v, x, y, w, h))
@ -58,7 +60,7 @@ function fixed:add(...)
assert(args.n > 0, "need at least one widget to add") assert(args.n > 0, "need at least one widget to add")
for i=1, args.n do for i=1, args.n do
base.check_widget(args[i]) base.check_widget(args[i])
table.insert(self.widgets, args[i]) table.insert(self._private.widgets, args[i])
end end
self:emit_signal("widget::layout_changed") self:emit_signal("widget::layout_changed")
end end
@ -68,9 +70,9 @@ end
-- @tparam number index The widget index to remove -- @tparam number index The widget index to remove
-- @treturn boolean index If the operation is successful -- @treturn boolean index If the operation is successful
function fixed:remove(index) function fixed:remove(index)
if not index or index < 1 or index > #self.widgets then return false end if not index or index < 1 or index > #self._private.widgets then return false end
table.remove(self.widgets, index) table.remove(self._private.widgets, index)
self:emit_signal("widget::layout_changed") self:emit_signal("widget::layout_changed")
@ -104,14 +106,10 @@ function fixed:remove_widgets(...)
return #args > (recursive and 1 or 0) and ret return #args > (recursive and 1 or 0) and ret
end end
--- Get all children of this layout
-- @treturn table a list of all widgets
function fixed:get_children() function fixed:get_children()
return self.widgets return self._private.widgets
end end
--- Replace the layout children
-- @tparam table children A table composed of valid widgets
function fixed:set_children(children) function fixed:set_children(children)
self:reset() self:reset()
if #children > 0 then if #children > 0 then
@ -136,12 +134,12 @@ function fixed:replace_widget(widget, widget2, recursive)
end end
function fixed:swap(index1, index2) function fixed:swap(index1, index2)
if not index1 or not index2 or index1 > #self.widgets if not index1 or not index2 or index1 > #self._private.widgets
or index2 > #self.widgets then or index2 > #self._private.widgets then
return false return false
end end
local widget1, widget2 = self.widgets[index1], self.widgets[index2] local widget1, widget2 = self._private.widgets[index1], self._private.widgets[index2]
self:set(index1, widget2) self:set(index1, widget2)
self:set(index2, widget1) self:set(index2, widget1)
@ -175,11 +173,11 @@ function fixed:swap_widgets(widget1, widget2, recursive)
end end
function fixed:set(index, widget2) function fixed:set(index, widget2)
if (not widget2) or (not self.widgets[index]) then return false end if (not widget2) or (not self._private.widgets[index]) then return false end
base.check_widget(widget2) base.check_widget(widget2)
self.widgets[index] = widget2 self._private.widgets[index] = widget2
self:emit_signal("widget::layout_changed") self:emit_signal("widget::layout_changed")
@ -191,10 +189,10 @@ end
-- @param widget The widget -- @param widget The widget
-- @treturn boolean If the operation is successful -- @treturn boolean If the operation is successful
function fixed:insert(index, widget) function fixed:insert(index, widget)
if not index or index < 1 or index > #self.widgets + 1 then return false end if not index or index < 1 or index > #self._private.widgets + 1 then return false end
base.check_widget(widget) base.check_widget(widget)
table.insert(self.widgets, index, widget) table.insert(self._private.widgets, index, widget)
self:emit_signal("widget::layout_changed") self:emit_signal("widget::layout_changed")
return true return true
@ -208,10 +206,10 @@ function fixed:fit(context, orig_width, orig_height)
local width, height = orig_width, orig_height local width, height = orig_width, orig_height
local used_in_dir, used_max = 0, 0 local used_in_dir, used_max = 0, 0
for _, v in pairs(self.widgets) do for _, v in pairs(self._private.widgets) do
local w, h = base.fit_widget(self, context, v, width, height) local w, h = base.fit_widget(self, context, v, width, height)
local in_dir, max local in_dir, max
if self.dir == "y" then if self._private.dir == "y" then
max, in_dir = w, h max, in_dir = w, h
height = height - in_dir height = height - in_dir
else else
@ -224,7 +222,7 @@ function fixed:fit(context, orig_width, orig_height)
used_in_dir = used_in_dir + in_dir used_in_dir = used_in_dir + in_dir
if width <= 0 or height <= 0 then if width <= 0 or height <= 0 then
if self.dir == "y" then if self._private.dir == "y" then
used_in_dir = orig_height used_in_dir = orig_height
else else
used_in_dir = orig_width used_in_dir = orig_width
@ -233,36 +231,38 @@ function fixed:fit(context, orig_width, orig_height)
end end
end end
local spacing = self._spacing * (#self.widgets-1) local spacing = self._private.spacing * (#self._private.widgets-1)
if self.dir == "y" then if self._private.dir == "y" then
return used_max, used_in_dir + spacing return used_max, used_in_dir + spacing
end end
return used_in_dir + spacing, used_max return used_in_dir + spacing, used_max
end end
function fixed:reset() function fixed:reset()
self.widgets = {} self._private.widgets = {}
self:emit_signal("widget::layout_changed") self:emit_signal("widget::layout_changed")
end end
--- Set the layout's fill_space property. If this property is true, the last --- Set the layout's fill_space property. If this property is true, the last
-- widget will get all the space that is left. If this is false, the last widget -- widget will get all the space that is left. If this is false, the last widget
-- won't be handled specially and there can be space left unused. -- won't be handled specially and there can be space left unused.
-- @property fill_space
function fixed:fill_space(val) function fixed:fill_space(val)
if self._fill_space ~= val then if self._private.fill_space ~= val then
self._fill_space = not not val self._private.fill_space = not not val
self:emit_signal("widget::layout_changed") self:emit_signal("widget::layout_changed")
end end
end end
local function get_layout(dir, widget1, ...) local function get_layout(dir, widget1, ...)
local ret = base.make_widget() local ret = base.make_widget(nil, nil, {enable_properties = true})
util.table.crush(ret, fixed) util.table.crush(ret, fixed, true)
ret.dir = dir ret._private.dir = dir
ret.widgets = {} ret._private.widgets = {}
ret:set_spacing(0) ret:set_spacing(0)
ret:fill_space(false) ret:fill_space(false)
@ -292,14 +292,24 @@ function fixed.vertical(...)
end end
--- Add spacing between each layout widgets --- Add spacing between each layout widgets
-- @param spacing Spacing between widgets. -- @property spacing
-- @tparam number spacing Spacing between widgets.
function fixed:set_spacing(spacing) function fixed:set_spacing(spacing)
if self._spacing ~= spacing then if self._private.spacing ~= spacing then
self._spacing = spacing self._private.spacing = spacing
self:emit_signal("widget::layout_changed") self:emit_signal("widget::layout_changed")
end end
end end
function fixed:get_spacing()
return self._private.spacing or 0
end
--@DOC_widget_COMMON@
--@DOC_object_COMMON@
return fixed return fixed
-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80 -- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80

View File

@ -1,4 +1,6 @@
--------------------------------------------------------------------------- ---------------------------------------------------------------------------
--
--@DOC_wibox_layout_defaults_flex_EXAMPLE@
-- @author Uli Schlachter -- @author Uli Schlachter
-- @copyright 2010 Uli Schlachter -- @copyright 2010 Uli Schlachter
-- @release @AWESOME_VERSION@ -- @release @AWESOME_VERSION@
@ -50,24 +52,24 @@ local flex = {}
function flex:layout(_, width, height) function flex:layout(_, width, height)
local result = {} local result = {}
local pos,spacing = 0, self._spacing local pos,spacing = 0, self._private.spacing
local num = #self.widgets local num = #self._private.widgets
local total_spacing = (spacing*(num-1)) local total_spacing = (spacing*(num-1))
local space_per_item local space_per_item
if self.dir == "y" then if self._private.dir == "y" then
space_per_item = height / num - total_spacing/num space_per_item = height / num - total_spacing/num
else else
space_per_item = width / num - total_spacing/num space_per_item = width / num - total_spacing/num
end end
if self._max_widget_size then if self._private.max_widget_size then
space_per_item = math.min(space_per_item, self._max_widget_size) space_per_item = math.min(space_per_item, self._private.max_widget_size)
end end
for _, v in pairs(self.widgets) do for _, v in pairs(self._private.widgets) do
local x, y, w, h local x, y, w, h
if self.dir == "y" then if self._private.dir == "y" then
x, y = 0, util.round(pos) x, y = 0, util.round(pos)
w, h = width, floor(space_per_item) w, h = width, floor(space_per_item)
else else
@ -79,8 +81,8 @@ function flex:layout(_, width, height)
pos = pos + space_per_item + spacing pos = pos + space_per_item + spacing
if (self.dir == "y" and pos-spacing >= height) or if (self._private.dir == "y" and pos-spacing >= height) or
(self.dir ~= "y" and pos-spacing >= width) then (self._private.dir ~= "y" and pos-spacing >= width) then
break break
end end
end end
@ -97,39 +99,41 @@ function flex:fit(context, orig_width, orig_height)
local used_in_other = 0 local used_in_other = 0
-- Figure out the maximum size we can give out to sub-widgets -- Figure out the maximum size we can give out to sub-widgets
local sub_height = self.dir == "x" and orig_height or orig_height / #self.widgets local sub_height = self._private.dir == "x" and orig_height or orig_height / #self._private.widgets
local sub_width = self.dir == "y" and orig_width or orig_width / #self.widgets local sub_width = self._private.dir == "y" and orig_width or orig_width / #self._private.widgets
for _, v in pairs(self.widgets) do for _, v in pairs(self._private.widgets) do
local w, h = base.fit_widget(self, context, v, sub_width, sub_height) local w, h = base.fit_widget(self, context, v, sub_width, sub_height)
local max = self.dir == "y" and w or h local max = self._private.dir == "y" and w or h
if max > used_in_other then if max > used_in_other then
used_in_other = max used_in_other = max
end end
used_in_dir = used_in_dir + (self.dir == "y" and h or w) used_in_dir = used_in_dir + (self._private.dir == "y" and h or w)
end end
if self._max_widget_size then if self._private.max_widget_size then
used_in_dir = math.min(used_in_dir, used_in_dir = math.min(used_in_dir,
#self.widgets * self._max_widget_size) #self._private.widgets * self._private.max_widget_size)
end end
local spacing = self._spacing * (#self.widgets-1) local spacing = self._private.spacing * (#self._private.widgets-1)
if self.dir == "y" then if self._private.dir == "y" then
return used_in_other, used_in_dir + spacing return used_in_other, used_in_dir + spacing
end end
return used_in_dir + spacing, used_in_other return used_in_dir + spacing, used_in_other
end end
--- Set the maximum size the widgets in this layout will take (that is, --- Set the maximum size the widgets in this layout will take.
-- maximum width for horizontal and maximum height for vertical). --That is, maximum width for horizontal and maximum height for vertical.
-- @param val The maximum size of the widget. -- @property max_widget_size
-- @param number
function flex:set_max_widget_size(val) function flex:set_max_widget_size(val)
if self._max_widget_size ~= val then if self._private.max_widget_size ~= val then
self._max_widget_size = val self._private.max_widget_size = val
self:emit_signal("widget::layout_changed") self:emit_signal("widget::layout_changed")
end end
end end
@ -137,9 +141,9 @@ end
local function get_layout(dir, widget1, ...) local function get_layout(dir, widget1, ...)
local ret = fixed[dir](widget1, ...) local ret = fixed[dir](widget1, ...)
util.table.crush(ret, flex) util.table.crush(ret, flex, true)
ret.fill_space = nil ret._private.fill_space = nil
return ret return ret
end end
@ -160,6 +164,10 @@ function flex.vertical(...)
return get_layout("vertical", ...) return get_layout("vertical", ...)
end end
--@DOC_widget_COMMON@
--@DOC_object_COMMON@
return flex return flex
-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80 -- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80

View File

@ -1,198 +1,18 @@
--------------------------------------------------------------------------- ---------------------------------------------------------------------------
-- This class has been moved to `wibox.container.margin`
--
-- @author Uli Schlachter -- @author Uli Schlachter
-- @copyright 2010 Uli Schlachter -- @copyright 2010 Uli Schlachter
-- @release @AWESOME_VERSION@ -- @release @AWESOME_VERSION@
-- @classmod wibox.layout.margin -- @classmod wibox.layout.margin
--------------------------------------------------------------------------- ---------------------------------------------------------------------------
local pairs = pairs local util = require("awful.util")
local type = type
local setmetatable = setmetatable
local base = require("wibox.widget.base")
local gcolor = require("gears.color")
local cairo = require("lgi").cairo
local margin = { mt = {} } return util.deprecate_class(
require("wibox.container.margin"),
-- Draw a margin layout "wibox.layout.margin",
function margin:draw(_, cr, width, height) "wibox.container.margin"
local x = self.left )
local y = self.top
local w = self.right
local h = self.bottom
local color = self.color
if not self.widget or width <= x + w or height <= y + h then
return
end
if color then
cr:set_source(color)
cr:rectangle(0, 0, width, height)
cr:rectangle(x, y, width - x - w, height - y - h)
cr:set_fill_rule(cairo.FillRule.EVEN_ODD)
cr:fill()
end
end
-- Layout a margin layout
function margin:layout(_, width, height)
if self.widget then
local x = self.left
local y = self.top
local w = self.right
local h = self.bottom
return { base.place_widget_at(self.widget, x, y, width - x - w, height - y - h) }
end
end
-- Fit a margin layout into the given space
function margin:fit(context, width, height)
local extra_w = self.left + self.right
local extra_h = self.top + self.bottom
local w, h = 0, 0
if self.widget then
w, h = base.fit_widget(self, context, self.widget, width - extra_w, height - extra_h)
end
if self._draw_empty == false and (w == 0 or h == 0) then
return 0, 0
end
return w + extra_w, h + extra_h
end
--- Set the widget that this layout adds a margin on.
function margin:set_widget(widget)
if widget then
base.check_widget(widget)
end
self.widget = widget
self:emit_signal("widget::layout_changed")
end
-- Get the number of children element
-- @treturn table The children
function margin:get_children()
return {self.widget}
end
-- Replace the layout children
-- This layout only accept one children, all others will be ignored
-- @tparam table children A table composed of valid widgets
function margin:set_children(children)
self:set_widget(children[1])
end
--- Set all the margins to val.
-- @tparam number val The margin value
function margin:set_margins(val)
if self.left == val and
self.right == val and
self.top == val and
self.bottom == val then
return
end
self.left = val
self.right = val
self.top = val
self.bottom = val
self:emit_signal("widget::layout_changed")
end
--- Set the margins color to create a border.
-- @param color A color used to fill the margin.
function margin:set_color(color)
self.color = color and gcolor(color)
self:emit_signal("widget::redraw_needed")
end
--- Draw the margin even if the content size is 0x0 (default: true)
-- @tparam boolean draw_empty Draw nothing is content is 0x0 or draw the margin anyway
function margin:set_draw_empty(draw_empty)
self._draw_empty = draw_empty
self:emit_signal("widget::layout_changed")
end
--- Reset this layout. The widget will be unreferenced, the margins set to 0
-- and the color erased
function margin:reset()
self:set_widget(nil)
self:set_margins(0)
self:set_color(nil)
end
--- Set the left margin that this layout adds to its widget.
-- @param layout The layout you are modifying.
-- @param margin The new margin to use.
-- @name set_left
-- @class function
--- Set the right margin that this layout adds to its widget.
-- @param layout The layout you are modifying.
-- @param margin The new margin to use.
-- @name set_right
-- @class function
--- Set the top margin that this layout adds to its widget.
-- @param layout The layout you are modifying.
-- @param margin The new margin to use.
-- @name set_top
-- @class function
--- Set the bottom margin that this layout adds to its widget.
-- @param layout The layout you are modifying.
-- @param margin The new margin to use.
-- @name set_bottom
-- @class function
-- Create setters for each direction
for _, v in pairs({ "left", "right", "top", "bottom" }) do
margin["set_" .. v] = function(layout, val)
if layout[v] == val then return end
layout[v] = val
layout:emit_signal("widget::layout_changed")
end
end
--- Returns a new margin layout.
-- @param[opt] widget A widget to use.
-- @param[opt] left A margin to use on the left side of the widget.
-- @param[opt] right A margin to use on the right side of the widget.
-- @param[opt] top A margin to use on the top side of the widget.
-- @param[opt] bottom A margin to use on the bottom side of the widget.
-- @param[opt] color A color for the margins.
-- @param[opt] draw_empty whether or not to draw the margin when the content is empty
local function new(widget, left, right, top, bottom, color, draw_empty)
local ret = base.make_widget()
for k, v in pairs(margin) do
if type(v) == "function" then
ret[k] = v
end
end
ret:set_left(left or 0)
ret:set_right(right or 0)
ret:set_top(top or 0)
ret:set_bottom(bottom or 0)
ret:set_draw_empty(draw_empty)
ret:set_color(color)
if widget then
ret:set_widget(widget)
end
return ret
end
function margin.mt:__call(...)
return new(...)
end
return setmetatable(margin, margin.mt)
-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80 -- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80

View File

@ -1,127 +1,18 @@
--------------------------------------------------------------------------- ---------------------------------------------------------------------------
-- This class has been moved to `wibox.container.mirror`
--
-- @author dodo -- @author dodo
-- @copyright 2012 dodo -- @copyright 2012 dodo
-- @release @AWESOME_VERSION@ -- @release @AWESOME_VERSION@
-- @classmod wibox.layout.mirror -- @classmod wibox.layout.mirror
--------------------------------------------------------------------------- ---------------------------------------------------------------------------
local type = type local util = require("awful.util")
local error = error
local pairs = pairs
local ipairs = ipairs
local setmetatable = setmetatable
local base = require("wibox.widget.base")
local matrix = require("gears.matrix")
local mirror = { mt = {} } return util.deprecate_class(
require("wibox.container.mirror"),
--- Layout this layout "wibox.layout.mirror",
function mirror:layout(_, width, height) "wibox.container.mirror"
if not self.widget then return end )
local m = matrix.identity
local t = { x = 0, y = 0 } -- translation
local s = { x = 1, y = 1 } -- scale
if self.horizontal then
t.x = width
s.x = -1
end
if self.vertical then
t.y = height
s.y = -1
end
m = m:translate(t.x, t.y)
m = m:scale(s.x, s.y)
return { base.place_widget_via_matrix(self.widget, m, width, height) }
end
--- Fit this layout into the given area
function mirror:fit(context, ...)
if not self.widget then
return 0, 0
end
return base.fit_widget(self, context, self.widget, ...)
end
--- Set the widget that this layout mirrors.
-- @param widget The widget to mirror
function mirror:set_widget(widget)
if widget then
base.check_widget(widget)
end
self.widget = widget
self:emit_signal("widget::layout_changed")
end
--- Get the number of children element
-- @treturn table The children
function mirror:get_children()
return {self.widget}
end
--- Replace the layout children
-- This layout only accept one children, all others will be ignored
-- @tparam table children A table composed of valid widgets
function mirror:set_children(children)
self:set_widget(children[1])
end
--- Reset this layout. The widget will be removed and the axes reset.
function mirror:reset()
self.horizontal = false
self.vertical = false
self:set_widget(nil)
end
--- Set the reflection of this mirror layout.
-- @param reflection a table which contains new values for horizontal and/or vertical (booleans)
function mirror:set_reflection(reflection)
if type(reflection) ~= 'table' then
error("Invalid type of reflection for mirror layout: " ..
type(reflection) .. " (should be a table)")
end
for _, ref in ipairs({"horizontal", "vertical"}) do
if reflection[ref] ~= nil then
self[ref] = reflection[ref]
end
end
self:emit_signal("widget::layout_changed")
end
--- Get the reflection of this mirror layout.
-- @return a table of booleans with the keys "horizontal", "vertical".
function mirror:get_reflection()
return { horizontal = self.horizontal, vertical = self.vertical }
end
--- Returns a new mirror layout. A mirror layout mirrors a given widget. Use
-- :set_widget() to set the widget and
-- :set_horizontal() and :set_vertical() for the direction.
-- horizontal and vertical are by default false which doesn't change anything.
-- @param[opt] widget The widget to display.
-- @param[opt] reflection A table describing the reflection to apply.
local function new(widget, reflection)
local ret = base.make_widget()
ret.horizontal = false
ret.vertical = false
for k, v in pairs(mirror) do
if type(v) == "function" then
ret[k] = v
end
end
ret:set_widget(widget)
ret:set_reflection(reflection or {})
return ret
end
function mirror.mt:__call(...)
return new(...)
end
return setmetatable(mirror, mirror.mt)
-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80 -- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80

View File

@ -2,6 +2,8 @@
--- A layout filling all the available space. Each widget is assigned a --- A layout filling all the available space. Each widget is assigned a
-- ratio (percentage) of the total space. Multiple methods are available to -- ratio (percentage) of the total space. Multiple methods are available to
-- ajust this ratio. -- ajust this ratio.
--
--@DOC_wibox_layout_defaults_ratio_EXAMPLE@
-- @author Emmanuel Lepage Vallee -- @author Emmanuel Lepage Vallee
-- @copyright 2016 Emmanuel Lepage Vallee -- @copyright 2016 Emmanuel Lepage Vallee
-- @release @AWESOME_VERSION@ -- @release @AWESOME_VERSION@
@ -23,9 +25,9 @@ local ratio = {}
local function gen_sum(self, i_s, i_e) local function gen_sum(self, i_s, i_e)
local sum, new_w = 0,0 local sum, new_w = 0,0
for i = i_s or 1, i_e or #self.widgets do for i = i_s or 1, i_e or #self._private.widgets do
if self._ratios[i] then if self._private.ratios[i] then
sum = sum + self._ratios[i] sum = sum + self._private.ratios[i]
else else
new_w = new_w + 1 new_w = new_w + 1
end end
@ -40,24 +42,24 @@ end
-- specific ratio must be enforced for a widget, it has to be done with the -- specific ratio must be enforced for a widget, it has to be done with the
-- `ajust_ratio` method after each insertion or deletion -- `ajust_ratio` method after each insertion or deletion
local function normalize(self) local function normalize(self)
local count = #self.widgets local count = #self._private.widgets
if count == 0 then return end if count == 0 then return end
-- Instead of adding "if" everywhere, just handle this common case -- Instead of adding "if" everywhere, just handle this common case
if count == 1 then if count == 1 then
self._ratios = { 1 } self._private.ratios = { 1 }
return return
end end
local sum, new_w = gen_sum(self) local sum, new_w = gen_sum(self)
local old_count = #self.widgets - new_w local old_count = #self._private.widgets - new_w
local to_add = (sum == 0) and 1 or (sum / old_count) local to_add = (sum == 0) and 1 or (sum / old_count)
-- Make sure all widgets have a ratio -- Make sure all widgets have a ratio
for i=1, #self.widgets do for i=1, #self._private.widgets do
if not self._ratios[i] then if not self._private.ratios[i] then
self._ratios[i] = to_add self._private.ratios[i] = to_add
end end
end end
@ -66,9 +68,9 @@ local function normalize(self)
local delta, new_sum = (1 - sum) / count,0 local delta, new_sum = (1 - sum) / count,0
-- Increase or decrease each ratio so it the sum become 1 -- Increase or decrease each ratio so it the sum become 1
for i=1, #self.widgets do for i=1, #self._private.widgets do
self._ratios[i] = self._ratios[i] + delta self._private.ratios[i] = self._private.ratios[i] + delta
new_sum = new_sum + self._ratios[i] new_sum = new_sum + self._private.ratios[i]
end end
-- Floating points is not an exact science, but it should still be close -- Floating points is not an exact science, but it should still be close
@ -78,18 +80,18 @@ end
function ratio:layout(_, width, height) function ratio:layout(_, width, height)
local result = {} local result = {}
local pos,spacing = 0, self._spacing local pos,spacing = 0, self._private.spacing
for k, v in ipairs(self.widgets) do for k, v in ipairs(self._private.widgets) do
local space local space
local x, y, w, h local x, y, w, h
if self.dir == "y" then if self._private.dir == "y" then
space = height * self._ratios[k] space = height * self._private.ratios[k]
x, y = 0, util.round(pos) x, y = 0, util.round(pos)
w, h = width, floor(space) w, h = width, floor(space)
else else
space = width * self._ratios[k] space = width * self._private.ratios[k]
x, y = util.round(pos), 0 x, y = util.round(pos), 0
w, h = floor(space), height w, h = floor(space), height
end end
@ -100,8 +102,8 @@ function ratio:layout(_, width, height)
-- Make sure all widgets fit in the layout, if they aren't, something -- Make sure all widgets fit in the layout, if they aren't, something
-- went wrong -- went wrong
if (self.dir == "y" and util.round(pos) >= height) or if (self._private.dir == "y" and util.round(pos) >= height) or
(self.dir ~= "y" and util.round(pos) >= width) then (self._private.dir ~= "y" and util.round(pos) >= width) then
break break
end end
end end
@ -116,14 +118,14 @@ end
-- @tparam number increment An floating point value between -1 and 1 where the -- @tparam number increment An floating point value between -1 and 1 where the
-- end result is within 0 and 1 -- end result is within 0 and 1
function ratio:inc_ratio(index, increment) function ratio:inc_ratio(index, increment)
if #self.widgets == 1 or (not index) or (not self._ratios[index]) if #self._private.widgets == 1 or (not index) or (not self._private.ratios[index])
or increment < -1 or increment > 1 then or increment < -1 or increment > 1 then
return return
end end
assert(self._ratios[index]) assert(self._private.ratios[index])
self:set_ratio(index, self._ratios[index] + increment) self:set_ratio(index, self._private.ratios[index] + increment)
end end
--- Increment the ratio of the first instance of `widget` --- Increment the ratio of the first instance of `widget`
@ -144,22 +146,22 @@ end
-- @tparam number index The index of the widget to change -- @tparam number index The index of the widget to change
-- @tparam number percent An floating point value between 0 and 1 -- @tparam number percent An floating point value between 0 and 1
function ratio:set_ratio(index, percent) function ratio:set_ratio(index, percent)
if not percent or #self.widgets == 1 or not index or not self.widgets[index] if not percent or #self._private.widgets == 1 or not index or not self._private.widgets[index]
or percent < 0 or percent > 1 then or percent < 0 or percent > 1 then
return return
end end
local old = self._ratios[index] local old = self._private.ratios[index]
-- Remove what has to be cleared from all widget -- Remove what has to be cleared from all widget
local delta = ( (percent-old) / (#self.widgets-1) ) local delta = ( (percent-old) / (#self._private.widgets-1) )
for k in pairs(self.widgets) do for k in pairs(self._private.widgets) do
self._ratios[k] = self._ratios[k] - delta self._private.ratios[k] = self._private.ratios[k] - delta
end end
-- Set the new ratio -- Set the new ratio
self._ratios[index] = percent self._private.ratios[index] = percent
-- As some widgets may now have a slightly negative ratio, normalize again -- As some widgets may now have a slightly negative ratio, normalize again
normalize(self) normalize(self)
@ -172,7 +174,7 @@ end
-- @treturn number The index (between 0 and 1) -- @treturn number The index (between 0 and 1)
function ratio:get_ratio(index) function ratio:get_ratio(index)
if not index then return end if not index then return end
return self._ratios[index] return self._private.ratios[index]
end end
--- Set the ratio of `widget` to `percent`. --- Set the ratio of `widget` to `percent`.
@ -191,7 +193,7 @@ end
-- @tparam number itself The ratio for "widget" -- @tparam number itself The ratio for "widget"
-- @tparam number after The sum of the ratio after the widget -- @tparam number after The sum of the ratio after the widget
function ratio:ajust_ratio(index, before, itself, after) function ratio:ajust_ratio(index, before, itself, after)
if not self.widgets[index] or not before or not itself or not after then if not self._private.widgets[index] or not before or not itself or not after then
return return
end end
@ -202,21 +204,21 @@ function ratio:ajust_ratio(index, before, itself, after)
if sum > 1.01 or sum < -0.99 then return end if sum > 1.01 or sum < -0.99 then return end
-- Compute the before and after offset to be applied to each widgets -- Compute the before and after offset to be applied to each widgets
local before_count, after_count = index-1, #self.widgets - index local before_count, after_count = index-1, #self._private.widgets - index
local b, a = gen_sum(self, 1, index-1), gen_sum(self, index+1) local b, a = gen_sum(self, 1, index-1), gen_sum(self, index+1)
local db, da = (before - b)/before_count, (after - a)/after_count local db, da = (before - b)/before_count, (after - a)/after_count
-- Apply the new ratio -- Apply the new ratio
self._ratios[index] = itself self._private.ratios[index] = itself
-- Equality split the delta among widgets before and after -- Equality split the delta among widgets before and after
for i = 1, index -1 do for i = 1, index -1 do
self._ratios[i] = self._ratios[i] + db self._private.ratios[i] = self._private.ratios[i] + db
end end
for i = index+1, #self.widgets do for i = index+1, #self._private.widgets do
self._ratios[i] = self._ratios[i] + da self._private.ratios[i] = self._private.ratios[i] + da
end end
-- Remove potential negative ratio -- Remove potential negative ratio
@ -243,7 +245,7 @@ function ratio:add(...)
assert(args.n > 0, "need at least one widget to add") assert(args.n > 0, "need at least one widget to add")
for i=1, args.n do for i=1, args.n do
base.check_widget(args[i]) base.check_widget(args[i])
table.insert(self.widgets, args[i]) table.insert(self._private.widgets, args[i])
end end
normalize(self) normalize(self)
@ -254,10 +256,10 @@ end
-- @tparam number index The widget index to remove -- @tparam number index The widget index to remove
-- @treturn boolean index If the operation is successful -- @treturn boolean index If the operation is successful
function ratio:remove(index) function ratio:remove(index)
if not index or not self.widgets[index] then return false end if not index or not self._private.widgets[index] then return false end
table.remove(self._ratios, index) table.remove(self._private.ratios, index)
table.remove(self.widgets, index) table.remove(self._private.widgets, index)
normalize(self) normalize(self)
@ -270,11 +272,11 @@ end
-- @tparam number index The position -- @tparam number index The position
-- @param widget The widget -- @param widget The widget
function ratio:insert(index, widget) function ratio:insert(index, widget)
if not index or index < 1 or index > #self.widgets + 1 then return false end if not index or index < 1 or index > #self._private.widgets + 1 then return false end
base.check_widget(widget) base.check_widget(widget)
table.insert(self.widgets, index, widget) table.insert(self._private.widgets, index, widget)
normalize(self) normalize(self)
@ -284,11 +286,11 @@ end
local function get_layout(dir, widget1, ...) local function get_layout(dir, widget1, ...)
local ret = flex[dir](widget1, ...) local ret = flex[dir](widget1, ...)
util.table.crush(ret, ratio) util.table.crush(ret, ratio, true)
ret.fill_space = nil ret._private.fill_space = nil
ret._ratios = {} ret._private.ratios = {}
return ret return ret
end end
@ -307,6 +309,10 @@ function ratio.vertical(...)
return get_layout("vertical", ...) return get_layout("vertical", ...)
end end
--@DOC_widget_COMMON@
--@DOC_object_COMMON@
return ratio return ratio
-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80 -- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80

View File

@ -1,137 +1,18 @@
--------------------------------------------------------------------------- ---------------------------------------------------------------------------
-- This class has been moved to `wibox.container.rotate`
--
-- @author Uli Schlachter -- @author Uli Schlachter
-- @copyright 2010 Uli Schlachter -- @copyright 2010 Uli Schlachter
-- @release @AWESOME_VERSION@ -- @release @AWESOME_VERSION@
-- @classmod wibox.layout.rotate -- @classmod wibox.layout.rotate
--------------------------------------------------------------------------- ---------------------------------------------------------------------------
local error = error local util = require("awful.util")
local pairs = pairs
local pi = math.pi
local type = type
local setmetatable = setmetatable
local tostring = tostring
local base = require("wibox.widget.base")
local matrix = require("gears.matrix")
local rotate = { mt = {} } return util.deprecate_class(
require("wibox.container.rotate"),
local function transform(layout, width, height) "wibox.layout.rotate",
local dir = layout:get_direction() "wibox.container.rotate"
if dir == "east" or dir == "west" then )
return height, width
end
return width, height
end
--- Layout this layout
function rotate:layout(_, width, height)
if not self.widget or not self.widget.visible then
return
end
local dir = self:get_direction()
local m = matrix.identity
if dir == "west" then
m = m:rotate(pi / 2)
m = m:translate(0, -width)
elseif dir == "south" then
m = m:rotate(pi)
m = m:translate(-width, -height)
elseif dir == "east" then
m = m:rotate(3 * pi / 2)
m = m:translate(-height, 0)
end
-- Since we rotated, we might have to swap width and height.
-- transform() does that for us.
return { base.place_widget_via_matrix(self.widget, m, transform(self, width, height)) }
end
--- Fit this layout into the given area
function rotate:fit(context, width, height)
if not self.widget then
return 0, 0
end
return transform(self, base.fit_widget(self, context, self.widget, transform(self, width, height)))
end
--- Set the widget that this layout rotates.
function rotate:set_widget(widget)
if widget then
base.check_widget(widget)
end
self.widget = widget
self:emit_signal("widget::layout_changed")
end
--- Get the number of children element
-- @treturn table The children
function rotate:get_children()
return {self.widget}
end
--- Replace the layout children
-- This layout only accept one children, all others will be ignored
-- @tparam table children A table composed of valid widgets
function rotate:set_children(children)
self:set_widget(children[1])
end
--- Reset this layout. The widget will be removed and the rotation reset.
function rotate:reset()
self.direction = nil
self:set_widget(nil)
end
--- Set the direction of this rotating layout. Valid values are "north", "east",
-- "south" and "west". On an invalid value, this function will throw an error.
function rotate:set_direction(dir)
local allowed = {
north = true,
east = true,
south = true,
west = true
}
if not allowed[dir] then
error("Invalid direction for rotate layout: " .. tostring(dir))
end
self.direction = dir
self:emit_signal("widget::layout_changed")
end
--- Get the direction of this rotating layout
function rotate:get_direction()
return self.direction or "north"
end
--- Returns a new rotate layout. A rotate layout rotates a given widget. Use
-- :set_widget() to set the widget and :set_direction() for the direction.
-- The default direction is "north" which doesn't change anything.
-- @param[opt] widget The widget to display.
-- @param[opt] dir The direction to rotate to.
local function new(widget, dir)
local ret = base.make_widget()
for k, v in pairs(rotate) do
if type(v) == "function" then
ret[k] = v
end
end
ret:set_widget(widget)
ret:set_direction(dir or "north")
return ret
end
function rotate.mt:__call(...)
return new(...)
end
return setmetatable(rotate, rotate.mt)
-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80 -- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80

View File

@ -1,509 +1,17 @@
--------------------------------------------------------------------------- ---------------------------------------------------------------------------
-- This class has been moved to `wibox.container.scroll`
--
-- @author Uli Schlachter (based on ideas from Saleur Geoffrey) -- @author Uli Schlachter (based on ideas from Saleur Geoffrey)
-- @copyright 2015 Uli Schlachter -- @copyright 2015 Uli Schlachter
-- @release @AWESOME_VERSION@ -- @release @AWESOME_VERSION@
-- @classmod wibox.layout.scroll -- @classmod wibox.layout.scroll
--------------------------------------------------------------------------- ---------------------------------------------------------------------------
local util = require("awful.util")
local cache = require("gears.cache") return util.deprecate_class(
local timer = require("gears.timer") require("wibox.container.scroll"),
local hierarchy = require("wibox.hierarchy") "wibox.layout.scroll",
local base = require("wibox.widget.base") "wibox.container.scroll"
local lgi = require("lgi") )
local GLib = lgi.GLib
local scroll = {}
local scroll_mt = { __index = scroll }
local _need_scroll_redraw
-- "Strip" a context so that we can use it for our own drawing
local function cleanup_context(context)
local skip = { wibox = true, drawable = true, client = true, position = true }
local res = {}
for k, v in pairs(context) do
if not skip[k] then
res[k] = v
end
end
return res
end
-- Create a hierarchy (and some more stuff) for drawing the given widget. This
-- allows "some stuff" to be re-used instead of re-created all the time.
local hierarchy_cache = cache.new(function(context, widget, width, height)
context = cleanup_context(context)
local layouts = setmetatable({}, { __mode = "k" })
-- Create a widget hierarchy and update when needed
local hier
local function do_pending_updates(layout)
layouts[layout] = true
hier:update(context, widget, width, height, nil)
end
local function emit(signal)
-- Make the scroll layouts redraw
for w in pairs(layouts) do
w:emit_signal(signal)
end
end
local function redraw_callback()
emit("widget::redraw_needed")
end
local function layout_callback()
emit("widget::redraw_needed")
emit("widget::layout_changed")
end
hier = hierarchy.new(context, widget, width, height, redraw_callback, layout_callback, nil)
return hier, do_pending_updates, context
end)
--- Calculate all the information needed for scrolling.
-- @param self The instance of the scrolling layout.
-- @param context A widget context under which we are fit/drawn.
-- @param width The available width
-- @param height The available height
-- @return A table with the following entries
-- @field fit_width The width that should be returned from :fit
-- @field fit_height The height that should be returned from :fit
-- @field surface_width The width for showing the child widget
-- @field surface_height The height for showing the child widget
-- @field first_x The x offset for drawing the child the first time
-- @field first_y The y offset for drawing the child the first time
-- @field[opt] second_x The x offset for drawing the child the second time
-- @field[opt] second_y The y offset for drawing the child the second time
-- @field hierarchy The wibox.hierarchy instance representing "everything"
-- @field context The widget context for drawing the hierarchy
local function calculate_info(self, context, width, height)
local result = {}
assert(self.widget)
-- First, get the size of the widget (and the size of extra space)
local surface_width, surface_height = width, height
local extra_width, extra_height, extra = 0, 0, self.expand and self.extra_space or 0
local w, h
if self.dir == "h" then
w, h = base.fit_widget(self, context, self.widget, self.space_for_scrolling, height)
surface_width = w
extra_width = extra
else
w, h = base.fit_widget(self, context, self.widget, width, self.space_for_scrolling)
surface_height = h
extra_height = extra
end
result.fit_width, result.fit_height = w, h
if self.dir == "h" then
if self.max_size then
result.fit_width = math.min(w, self.max_size)
end
else
if self.max_size then
result.fit_height = math.min(h, self.max_size)
end
end
if w > width or h > height then
-- There is less space available than we need, we have to scroll
_need_scroll_redraw(self)
surface_width, surface_height = surface_width + extra_width, surface_height + extra_height
local x, y = 0, 0
local function get_scroll_offset(size, visible_size)
return self.step_function(self.timer:elapsed(), size, visible_size, self.speed, self.extra_space)
end
if self.dir == "h" then
x = -get_scroll_offset(surface_width - extra, width)
else
y = -get_scroll_offset(surface_height - extra, height)
end
result.first_x, result.first_y = x, y
-- Was the extra space already included elsewhere?
local extra_spacer = self.expand and 0 or self.extra_space
if self.dir == "h" then
x = x + surface_width + extra_spacer
else
y = y + surface_height + extra_spacer
end
result.second_x, result.second_y = x, y
else
result.first_x, result.first_y = 0, 0
end
result.surface_width, result.surface_height = surface_width, surface_height
-- Get the hierarchy and subscribe ourselves to updates
local hier, do_pending_updates, ctx = hierarchy_cache:get(context,
self.widget, surface_width, surface_height)
result.hierarchy = hier
result.context = ctx
do_pending_updates(self)
return result
end
--- Draw this scrolling layout.
-- @param context The context in which we are drawn.
-- @param cr The cairo context to draw to.
-- @param width The available width.
-- @param height The available height.
function scroll:draw(context, cr, width, height)
if not self.widget then
return
end
local info = calculate_info(self, context, width, height)
-- Draw the first instance of the child
cr:save()
cr:translate(info.first_x, info.first_y)
cr:rectangle(0, 0, info.surface_width, info.surface_height)
cr:clip()
info.hierarchy:draw(info.context, cr)
cr:restore()
-- If there is one, draw the second instance (same code as above, minus the
-- clip)
if info.second_x and info.second_y then
cr:translate(info.second_x, info.second_y)
cr:rectangle(0, 0, info.surface_width, info.surface_height)
cr:clip()
info.hierarchy:draw(info.context, cr)
end
end
--- Fit the scroll layout into the given space.
-- @param context The context in which we are fit.
-- @param width The available width.
-- @param height The available height.
function scroll:fit(context, width, height)
if not self.widget then
return 0, 0
end
local info = calculate_info(self, context, width, height)
return info.fit_width, info.fit_height
end
-- Internal function used for triggering redraws for scrolling.
-- The purpose is to start a timer for redrawing the widget for scrolling.
-- Redrawing works by simply emitting the `widget::redraw_needed` signal.
-- Pausing is implemented in this function: We just don't start a timer.
-- This function must be idempotent (calling it multiple times right after
-- another does not make a difference).
_need_scroll_redraw = function(self)
if not self.paused and not self.scroll_timer then
self.scroll_timer = timer.start_new(1 / self.fps, function()
self.scroll_timer = nil
self:emit_signal("widget::redraw_needed")
end)
end
end
--- Pause the scrolling animation.
-- @see continue
function scroll:pause()
if self.paused then
return
end
self.paused = true
self.timer:stop()
end
--- Continue the scrolling animation.
-- @see pause
function scroll:continue()
if not self.paused then
return
end
self.paused = false
self.timer:continue()
self:emit_signal("widget::redraw_needed")
end
--- Reset the scrolling state to its initial condition.
-- For must scroll step functions, the effect of this function should be to
-- display the widget without any scrolling applied.
-- This function does not undo the effect of @{pause}.
function scroll:reset_scrolling()
self.timer:start()
if self.paused then
self.timer:stop()
end
end
--- Set the direction in which this widget scroll.
-- @param dir Either "h" for horizontal scrolling or "v" for vertical scrolling
function scroll:set_direction(dir)
if dir == self.dir then
return
end
if dir ~= "h" and dir ~= "v" then
error("Invalid direction, can only be 'h' or 'v'")
end
self.dir = dir
self:emit_signal("widget::layout_changed")
self:emit_signal("widget::redraw_needed")
end
--- Set the widget which we scroll.
-- @tparam widget widget The widget that we should display
function scroll:set_widget(widget)
if widget == self.widget then
return
end
if widget then
base.check_widget(widget)
end
self.widget = widget
self:emit_signal("widget::layout_changed")
self:emit_signal("widget::redraw_needed")
end
--- Get the number of children element
-- @treturn table The children
function scroll:get_children()
return {self.widget}
end
--- Replace the layout children
-- This layout only accept one children, all others will be ignored
-- @tparam table children A table composed of valid widgets
function scroll:set_children(children)
self:set_widget(children[1])
end
--- Specify the expand mode that is used for extra space.
-- @tparam boolean expand If true, the widget is expanded to include the extra
-- space. If false, the extra space is simply left empty.
-- @see set_extra_space
function scroll:set_expand(expand)
if expand == self.expand then
return
end
self.expand = expand
self:emit_signal("widget::redraw_needed")
end
--- Set the number of frames per second that this widget should draw.
-- @tparam number fps The number of frames per second
function scroll:set_fps(fps)
if fps == self.fps then
return
end
self.fps = fps
-- No signal needed: If we are scrolling, the next redraw will apply the new
-- FPS, else it obviously doesn't make a difference.
end
--- Set the amount of extra space that should be included in the scrolling. This
-- extra space will likely be left empty between repetitions of the widgets.
-- @tparam number extra_space The amount of extra space
-- @see set_expand
function scroll:set_extra_space(extra_space)
if extra_space == self.extra_space then
return
end
self.extra_space = extra_space
self:emit_signal("widget::redraw_needed")
end
--- Set the speed of the scrolling animation. The exact meaning depends on the
-- step function that is used, but for the simplest step functions, this will be
-- in pixels per second.
-- @tparam number speed The speed for the animation
function scroll:set_speed(speed)
if speed == self.speed then
return
end
self.speed = speed
self:emit_signal("widget::redraw_needed")
end
--- Set the maximum size of this widget in the direction set by
-- @{set_direction}. If the child widget is smaller than this size, no scrolling
-- is done. If the child widget is larger, then only this size will be visible
-- and the rest is made visible via scrolling.
-- @tparam number max_size The maximum size of this widget or nil for unlimited.
function scroll:set_max_size(max_size)
if max_size == self.max_size then
return
end
self.max_size = max_size
self:emit_signal("widget::layout_changed")
end
--- Set the step function that determines the exact behaviour of the scrolling
-- animation.
-- The step function is called with five arguments:
--
-- * The time in seconds since the state of the animation
-- * The size of the child widget
-- * The size of the visible part of the widget
-- * The speed of the animation. This should have a linear effect on this
-- function's behaviour.
-- * The extra space configured by @{set_extra_space}. This was not yet added to
-- the size of the child widget, but should likely be added to it in most
-- cases.
--
-- The step function should return a single number. This number is the offset at
-- which the widget is drawn and should be between 0 and `size+extra_space`.
-- @tparam function step_function A step function.
-- @see step_functions
function scroll:set_step_function(step_function)
-- Call the step functions once to see if it works
step_function(0, 42, 10, 10, 5)
if step_function == self.step_function then
return
end
self.step_function = step_function
self:emit_signal("widget::redraw_needed")
end
--- Set an upper limit for the space for scrolling.
-- This restricts the child widget's maximal size.
-- @tparam number space_for_scrolling The space for scrolling
function scroll:set_space_for_scrolling(space_for_scrolling)
if space_for_scrolling == self.space_for_scrolling then
return
end
self.space_for_scrolling = space_for_scrolling
self:emit_signal("widget::layout_changed")
end
local function get_layout(dir, widget, fps, speed, extra_space, expand, max_size, step_function, space_for_scrolling)
local ret = base.make_widget()
ret.paused = false
ret.timer = GLib.Timer()
ret.scroll_timer = nil
setmetatable(ret, scroll_mt)
ret:set_direction(dir)
ret:set_widget(widget)
ret:set_fps(fps or 20)
ret:set_speed(speed or 10)
ret:set_extra_space(extra_space or 0)
ret:set_expand(expand)
ret:set_max_size(max_size)
ret:set_step_function(step_function or scroll.step_functions.linear_increase)
ret:set_space_for_scrolling(space_for_scrolling or 2^1024)
return ret
end
--- Get a new horizontal scrolling layout.
-- @param[opt] widget The widget that should be scrolled
-- @param[opt=20] fps The number of frames per second
-- @param[opt=10] speed The speed of the animation
-- @param[opt=0] extra_space The amount of extra space to include
-- @tparam[opt=false] boolean expand Should the widget be expanded to include the
-- extra space?
-- @param[opt] max_size The maximum size of the child widget
-- @param[opt=step_functions.linear_increase] step_function The step function to be used
-- @param[opt=2^1024] space_for_scrolling The space for scrolling
function scroll.horizontal(widget, fps, speed, extra_space, expand, max_size, step_function, space_for_scrolling)
return get_layout("h", widget, fps, speed, extra_space, expand, max_size, step_function, space_for_scrolling)
end
--- Get a new vertical scrolling layout.
-- @param[opt] widget The widget that should be scrolled
-- @param[opt=20] fps The number of frames per second
-- @param[opt=10] speed The speed of the animation
-- @param[opt=0] extra_space The amount of extra space to include
-- @tparam[opt=false] boolean expand Should the widget be expanded to include the
-- extra space?
-- @param[opt] max_size The maximum size of the child widget
-- @param[opt=step_functions.linear_increase] step_function The step function to be used
-- @param[opt=2^1024] space_for_scrolling The space for scrolling
function scroll.vertical(widget, fps, speed, extra_space, expand, max_size, step_function, space_for_scrolling)
return get_layout("v", widget, fps, speed, extra_space, expand, max_size, step_function, space_for_scrolling)
end
--- A selection of step functions
-- @see set_step_function
scroll.step_functions = {}
--- A step function that scrolls the widget in an increasing direction with
-- constant speed.
function scroll.step_functions.linear_increase(elapsed, size, _, speed, extra_space)
return (elapsed * speed) % (size + extra_space)
end
--- A step function that scrolls the widget in an decreasing direction with
-- constant speed.
function scroll.step_functions.linear_decrease(elapsed, size, _, speed, extra_space)
return (-elapsed * speed) % (size + extra_space)
end
--- A step function that scrolls the widget to its end and back to its
-- beginning, then back to its end, etc. The speed is constant.
function scroll.step_functions.linear_back_and_forth(elapsed, size, visible_size, speed)
local state = ((elapsed * speed) % (2 * size)) / size
state = state <= 1 and state or 2 - state
return (size - visible_size) * state
end
--- A step function that scrolls the widget to its end and back to its
-- beginning, then back to its end, etc. The speed is null at the ends and
-- maximal in the middle.
function scroll.step_functions.nonlinear_back_and_forth(elapsed, size, visible_size, speed)
local state = ((elapsed * speed) % (2 * size)) / size
local negate = false
if state > 1 then
negate = true
state = state - 1
end
if state < 1/3 then
-- In the first 1/3rd of time, do a quadratic increase in speed
state = 2 * state * state
elseif state < 2/3 then
-- In the center, do a linear increase. That means we need:
-- If state is 1/3, result is 2/9 = 2 * 1/3 * 1/3
-- If state is 2/3, result is 7/9 = 1 - 2 * (1 - 2/3) * (1 - 2/3)
state = 5/3*state - 3/9
else
-- In the last 1/3rd of time, do a quadratic decrease in speed
state = 1 - 2 * (1 - state) * (1 - state)
end
if negate then
state = 1 - state
end
return (size - visible_size) * state
end
--- A step function that scrolls the widget to its end and back to its
-- beginning, then back to its end, etc. The speed is null at the ends and
-- maximal in the middle. At both ends the widget stands still for a moment.
function scroll.step_functions.waiting_nonlinear_back_and_forth(elapsed, size, visible_size, speed)
local state = ((elapsed * speed) % (2 * size)) / size
local negate = false
if state > 1 then
negate = true
state = state - 1
end
if state < 1/5 or state > 4/5 then
-- One fifth of time, nothing moves
state = state < 1/5 and 0 or 1
else
state = (state - 1/5) * 5/3
if state < 1/3 then
-- In the first 1/3rd of time, do a quadratic increase in speed
state = 2 * state * state
elseif state < 2/3 then
-- In the center, do a linear increase. That means we need:
-- If state is 1/3, result is 2/9 = 2 * 1/3 * 1/3
-- If state is 2/3, result is 7/9 = 1 - 2 * (1 - 2/3) * (1 - 2/3)
state = 5/3*state - 3/9
else
-- In the last 1/3rd of time, do a quadratic decrease in speed
state = 1 - 2 * (1 - state) * (1 - state)
end
end
if negate then
state = 1 - state
end
return (size - visible_size) * state
end
return scroll
-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80 -- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80

View File

@ -8,6 +8,7 @@
-- The indices are going from 1 (the bottom of the stack) up to the top of -- The indices are going from 1 (the bottom of the stack) up to the top of
-- the stack. The order can be changed either using `:swap` or `:raise`. -- the stack. The order can be changed either using `:swap` or `:raise`.
-- --
--@DOC_wibox_layout_defaults_stack_EXAMPLE@
-- @author Emmanuel Lepage Vallee -- @author Emmanuel Lepage Vallee
-- @copyright 2016 Emmanuel Lepage Vallee -- @copyright 2016 Emmanuel Lepage Vallee
-- @release @AWESOME_VERSION@ -- @release @AWESOME_VERSION@
@ -52,17 +53,16 @@ local stack = {mt={}}
-- @class function -- @class function
--- Add spacing between each layout widgets --- Add spacing between each layout widgets
-- @param spacing Spacing between widgets. -- @property spacing
-- @name set_spacing -- @tparam number spacing Spacing between widgets.
-- @class function
function stack:layout(_, width, height) function stack:layout(_, width, height)
local result = {} local result = {}
local spacing = self._spacing local spacing = self._private.spacing
for _, v in pairs(self.widgets) do for _, v in pairs(self._private.widgets) do
table.insert(result, base.place_widget_at(v, spacing, spacing, width - 2*spacing, height - 2*spacing)) table.insert(result, base.place_widget_at(v, spacing, spacing, width - 2*spacing, height - 2*spacing))
if self._top_only then break end if self._private.top_only then break end
end end
return result return result
@ -70,9 +70,9 @@ end
function stack:fit(context, orig_width, orig_height) function stack:fit(context, orig_width, orig_height)
local max_w, max_h = 0,0 local max_w, max_h = 0,0
local spacing = self._spacing local spacing = self._private.spacing
for _, v in pairs(self.widgets) do for _, v in pairs(self._private.widgets) do
local w, h = base.fit_widget(self, context, v, orig_width, orig_height) local w, h = base.fit_widget(self, context, v, orig_width, orig_height)
max_w, max_h = math.max(max_w, w+2*spacing), math.max(max_h, h+2*spacing) max_w, max_h = math.max(max_w, w+2*spacing), math.max(max_h, h+2*spacing)
end end
@ -80,26 +80,25 @@ function stack:fit(context, orig_width, orig_height)
return math.min(max_w, orig_width), math.min(max_h, orig_height) return math.min(max_w, orig_width), math.min(max_h, orig_height)
end end
--- Get if only the first stack widget is drawn --- If only the first stack widget is drawn
-- @return If the only the first stack widget is drawn -- @property top_only
function stack:get_display_top_only()
return self._top_only function stack:get_top_only()
return self._private.top_only
end end
--- Only draw the first widget of the stack, ignore others function stack:set_top_only(top_only)
-- @tparam boolean top_only Only draw the top stack widget self._private.top_only = top_only
function stack:set_display_top_only(top_only)
self._top_only = top_only
end end
--- Raise a widget at `index` to the top of the stack --- Raise a widget at `index` to the top of the stack
-- @tparam number index the widget index to raise -- @tparam number index the widget index to raise
function stack:raise(index) function stack:raise(index)
if (not index) or self.widgets[index] then return end if (not index) or self._private.widgets[index] then return end
local w = self.widgets[index] local w = self._private.widgets[index]
table.remove(self.widgets, index) table.remove(self._private.widgets, index)
table.insert(self.widgets, w) table.insert(self._private.widgets, w)
self:emit_signal("widget::layout_changed") self:emit_signal("widget::layout_changed")
end end
@ -130,7 +129,7 @@ end
local function new(...) local function new(...)
local ret = fixed.horizontal(...) local ret = fixed.horizontal(...)
util.table.crush(ret, stack) util.table.crush(ret, stack, true)
return ret return ret
end end
@ -139,5 +138,9 @@ function stack.mt:__call(_, ...)
return new(...) return new(...)
end end
--@DOC_widget_COMMON@
--@DOC_object_COMMON@
return setmetatable(stack, stack.mt) return setmetatable(stack, stack.mt)
-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80 -- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80

View File

@ -1,224 +1,17 @@
--------------------------------------------------------------------------- ---------------------------------------------------------------------------
-- A container capable of changing the background color, foreground color -- This class has been moved to `wibox.container.background`
-- widget shape. --
-- @author Uli Schlachter -- @author Uli Schlachter
-- @copyright 2010 Uli Schlachter -- @copyright 2010 Uli Schlachter
-- @release @AWESOME_VERSION@ -- @release @AWESOME_VERSION@
-- @classmod wibox.widget.background -- @classmod wibox.widget.background
--------------------------------------------------------------------------- ---------------------------------------------------------------------------
local util = require("awful.util")
local base = require("wibox.widget.base") return util.deprecate_class(
local color = require("gears.color") require("wibox.container.background"),
local surface = require("gears.surface") "wibox.widget.background",
local beautiful = require("beautiful") "wibox.container.background"
local cairo = require("lgi").cairo )
local setmetatable = setmetatable
local pairs = pairs
local type = type
local unpack = unpack or table.unpack -- luacheck: globals unpack (compatibility with Lua 5.1)
local background = { mt = {} }
-- Draw this widget
function background:draw(context, cr, width, height)
if not self.widget or not self.widget.visible then
return
end
-- Keep the shape path in case there is a border
self._path = nil
if self._shape then
-- Only add the offset if there is something to draw
local offset = ((self._shape_border_width and self._shape_border_color)
and self._shape_border_width or 0) / 2
cr:translate(offset, offset)
self._shape(cr, width - 2*offset, height - 2*offset, unpack(self._shape_args or {}))
cr:translate(-offset, -offset)
self._path = cr:copy_path()
cr:clip()
end
if self.background then
cr:set_source(self.background)
cr:paint()
end
if self.bgimage then
if type(self.bgimage) == "function" then
self.bgimage(context, cr, width, height,unpack(self.bgimage_args))
else
local pattern = cairo.Pattern.create_for_surface(self.bgimage)
cr:set_source(pattern)
cr:paint()
end
end
end
-- Draw the border
function background:after_draw_children(_, cr)
-- Draw the border
if self._path and self._shape_border_width and self._shape_border_width > 0 then
cr:append_path(self._path)
cr:set_source(color(self._shape_border_color or self.foreground or beautiful.fg_normal))
cr:set_line_width(self._shape_border_width)
cr:stroke()
self._path = nil
end
end
-- Prepare drawing the children of this widget
function background:before_draw_children(_, cr)
if self.foreground then
cr:set_source(self.foreground)
end
-- Clip the shape
if self._path and self._shape_clip then
cr:append_path(self._path)
cr:clip()
end
end
-- Layout this widget
function background:layout(_, width, height)
if self.widget then
return { base.place_widget_at(self.widget, 0, 0, width, height) }
end
end
-- Fit this widget into the given area
function background:fit(context, width, height)
if not self.widget then
return 0, 0
end
return base.fit_widget(self, context, self.widget, width, height)
end
--- Set the widget that is drawn on top of the background
-- @tparam widget widget The widget to be disaplayed inside of the background
-- area
function background:set_widget(widget)
if widget then
base.check_widget(widget)
end
self.widget = widget
self:emit_signal("widget::layout_changed")
end
-- Get children element
-- @treturn table The children
function background:get_children()
return {self.widget}
end
-- Replace the layout children
-- This layout only accept one children, all others will be ignored
-- @tparam table children A table composed of valid widgets
function background:set_children(children)
self:set_widget(children[1])
end
--- Set the background to use.
--@DOC_wibox_widget_background_bg_EXAMPLE@
-- @param bg A color string, pattern or gradient (see `gears.color`)
function background:set_bg(bg)
if bg then
self.background = color(bg)
else
self.background = nil
end
self:emit_signal("widget::redraw_needed")
end
--- Set the foreground to use.
--@DOC_wibox_widget_background_fg_EXAMPLE@
-- @param fg A color string, pattern or gradient (see `gears.color`)
function background:set_fg(fg)
if fg then
self.foreground = color(fg)
else
self.foreground = nil
end
self:emit_signal("widget::redraw_needed")
end
--- Set the background shape.
--
-- Any other arguments will be passed to the shape function
--@DOC_wibox_widget_background_shape_EXAMPLE@
-- @param shape A function taking a context, width and height as arguments
function background:set_shape(shape, ...)
self._shape = shape
self._shape_args = {...}
self:emit_signal("widget::redraw_needed")
end
--- When a `shape` is set, also draw a border.
--
-- See `wibox.widget.background.set_shape` for an usage example.
-- @tparam number width The border width
function background:set_shape_border_width(width)
self._shape_border_width = width
self:emit_signal("widget::redraw_needed")
end
--- When a `shape` is set, also draw a border.
--
-- See `wibox.widget.background.set_shape` for an usage example.
-- @param[opt=self.foreground] fg The border color, pattern or gradient
function background:set_shape_border_color(fg)
self._shape_border_color = fg
self:emit_signal("widget::redraw_needed")
end
--- When a `shape` is set, make sure nothing is drawn outside of it.
--@DOC_wibox_widget_background_clip_EXAMPLE@
-- @tparam boolean value If the shape clip is enable
function background:set_shape_clip(value)
self._shape_clip = value
self:emit_signal("widget::redraw_needed")
end
--- Set the background image to use
-- If `image` is a function, it will be called with `(context, cr, width, height)`
-- as arguments. Any other arguments passed to this method will be appended.
-- @param image A background image or a function
function background:set_bgimage(image, ...)
self.bgimage = type(image) == "function" and image or surface.load(image)
self.bgimage_args = {...}
self:emit_signal("widget::redraw_needed")
end
--- Returns a new background layout. A background layout applies a background
-- and foreground color to another widget.
-- @param[opt] widget The widget to display.
-- @param[opt] bg The background to use for that widget.
-- @param[opt] shape A `gears.shape` compatible shape function
local function new(widget, bg, shape)
local ret = base.make_widget()
for k, v in pairs(background) do
if type(v) == "function" then
ret[k] = v
end
end
ret._shape = shape
ret:set_widget(widget)
ret:set_bg(bg)
return ret
end
function background.mt:__call(...)
return new(...)
end
return setmetatable(background, background.mt)
-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80 -- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80

View File

@ -2,7 +2,7 @@
-- @author Uli Schlachter -- @author Uli Schlachter
-- @copyright 2010 Uli Schlachter -- @copyright 2010 Uli Schlachter
-- @release @AWESOME_VERSION@ -- @release @AWESOME_VERSION@
-- @module wibox.widget.base -- @classmod wibox.widget.base
--------------------------------------------------------------------------- ---------------------------------------------------------------------------
local object = require("gears.object") local object = require("gears.object")
@ -24,60 +24,102 @@ base.widget = {}
--- Set/get a widget's buttons. --- Set/get a widget's buttons.
-- @param _buttons The table of buttons that should bind to the widget. -- @param _buttons The table of buttons that should bind to the widget.
-- @function buttons
function base.widget:buttons(_buttons) function base.widget:buttons(_buttons)
if _buttons then if _buttons then
self.widget_buttons = _buttons self._private.widget_buttons = _buttons
end end
return self.widget_buttons return self._private.widget_buttons
end end
--- Set a widget's visible property --- Set a widget's visible property
-- @tparam boolean b Wether the widget is visible at all -- @tparam boolean b Wether the widget is visible at all
-- @function set_visible
function base.widget:set_visible(b) function base.widget:set_visible(b)
if b ~= self.visible then if b ~= self._private.visible then
self.visible = b self._private.visible = b
self:emit_signal("widget::layout_changed") self:emit_signal("widget::layout_changed")
-- In case something ignored fit and drew the widget anyway -- In case something ignored fit and drew the widget anyway
self:emit_signal("widget::redraw_needed") self:emit_signal("widget::redraw_needed")
end end
end end
--- Get if the widget is visible.
-- @treturn boolean If the widget is visible
-- @function get_visible
function base.widget:get_visible()
return self._private.visible or false
end
--- Set a widget's opacity --- Set a widget's opacity
-- @tparam number o The opacity to use (a number from 0 to 1). 0 is fully -- @tparam number o The opacity to use (a number from 0 to 1). 0 is fully
-- transparent while 1 is fully opaque. -- transparent while 1 is fully opaque.
-- @function set_opacity
function base.widget:set_opacity(o) function base.widget:set_opacity(o)
if o ~= self.opacity then if o ~= self._private.opacity then
self.opacity = o self._private.opacity = o
self:emit_signal("widget::redraw") self:emit_signal("widget::redraw")
end end
end end
--- Get the widget opacity.
-- @treturn number The opacity (between 0 and 1)
-- @function get_opacity
function base.widget:get_opacity()
return self._private.opacity
end
--- Set the widget's width --- Set the widget's width
-- @tparam number|nil s The width that the widget has. `nil` means to apply the -- @tparam number|nil s The width that the widget has. `nil` means to apply the
-- default mechanism of calling the `:fit` method. A number overrides the result -- default mechanism of calling the `:fit` method. A number overrides the result
-- from `:fit`. -- from `:fit`.
function base.widget:set_width(s) -- @function set_width
if s ~= self._forced_width then function base.widget:set_forced_width(s)
self._forced_width = s if s ~= self._private.forced_width then
self._private.forced_width = s
self:emit_signal("widget::layout_changed") self:emit_signal("widget::layout_changed")
end end
end end
--- Get the widget forced width.
-- Note that widgets instances can be placed at different places simultaneously,
-- therefore, they can have multiple width and width simultaneously. If there
-- is no forced size, then the only way to get the widget actual size is when
-- there is a `mouse::enter`, `mouse::leave` or button events.
-- @treturn nil|number The forced width (nil if automatic)
-- @function get_forced_widget
function base.widget:get_forced_width()
return self._private.forced_width
end
--- Set the widget's height --- Set the widget's height
-- @tparam number|nil s The height that the widget has. `nil` means to apply the -- @tparam number|nil s The height that the widget has. `nil` means to apply the
-- default mechanism of calling the `:fit` method. A number overrides the result -- default mechanism of calling the `:fit` method. A number overrides the result
-- from `:fit`. -- from `:fit`.
function base.widget:set_height(s) -- @function set_height
if s ~= self._forced_height then function base.widget:set_forced_height(s)
self._forced_height = s if s ~= self._private.forced_height then
self._private.forced_height = s
self:emit_signal("widget::layout_changed") self:emit_signal("widget::layout_changed")
end end
end end
--- Get the widget forced height.
-- Note that widgets instances can be placed at different places simultaneously,
-- therefore, they can have multiple width and height simultaneously. If there
-- is no forced size, then the only way to get the widget actual size is when
-- there is a `mouse::enter`, `mouse::leave` or button events.
-- @treturn nil|number The forced height (nil if automatic)
-- @function get_forced_height
function base.widget:get_forced_height()
return self._private.forced_height
end
--- Get all direct children widgets --- Get all direct children widgets
-- This method should be re-implemented by the relevant widgets -- This method should be re-implemented by the relevant widgets
-- @treturn table The children -- @treturn table The children
-- @function get_children
function base.widget:get_children() function base.widget:get_children()
return {} return {}
end end
@ -86,6 +128,7 @@ end
-- The default implementation does nothing, this must be re-implemented by -- The default implementation does nothing, this must be re-implemented by
-- all layout and container widgets. -- all layout and container widgets.
-- @tparam table children A table composed of valid widgets -- @tparam table children A table composed of valid widgets
-- @function set_children
function base.widget:set_children(children) -- luacheck: no unused function base.widget:set_children(children) -- luacheck: no unused
-- Nothing on purpose -- Nothing on purpose
end end
@ -98,24 +141,26 @@ local function digg_children(ret, tlw)
end end
end end
--- Get all direct and indirect children widgets --- Get all direct and indirect children widgets.
-- This will scan all containers recursively to find widgets -- This will scan all containers recursively to find widgets
-- Warning: This method it prone to stack overflow id the widget, or any of its -- Warning: This method it prone to stack overflow id the widget, or any of its
-- children, contain (directly or indirectly) itself. -- children, contain (directly or indirectly) itself.
-- @treturn table The children -- @treturn table The children
-- @function get_all_children
function base.widget:get_all_children() function base.widget:get_all_children()
local ret = {} local ret = {}
digg_children(ret, self) digg_children(ret, self)
return ret return ret
end end
--- Get a widex index --- Get a widex index.
-- @param widget The widget to look for -- @param widget The widget to look for
-- @param[opt] recursive Also check sub-widgets -- @param[opt] recursive Also check sub-widgets
-- @param[opt] ... Aditional widgets to add at the end of the "path" -- @param[opt] ... Aditional widgets to add at the end of the "path"
-- @return The index -- @return The index
-- @return The parent layout -- @return The parent layout
-- @return The path between "self" and "widget" -- @return The path between "self" and "widget"
-- @function index
function base.widget:index(widget, recursive, ...) function base.widget:index(widget, recursive, ...)
local widgets = self:get_children() local widgets = self:get_children()
@ -143,12 +188,12 @@ local widget_dependencies = setmetatable({}, { __mode = "kv" })
-- Get the cache of the given kind for this widget. This returns a gears.cache -- Get the cache of the given kind for this widget. This returns a gears.cache
-- that calls the callback of kind `kind` on the widget. -- that calls the callback of kind `kind` on the widget.
local function get_cache(widget, kind) local function get_cache(widget, kind)
if not widget._widget_caches[kind] then if not widget._private.widget_caches[kind] then
widget._widget_caches[kind] = cache.new(function(...) widget._private.widget_caches[kind] = cache.new(function(...)
return protected_call(widget[kind], widget, ...) return protected_call(widget[kind], widget, ...)
end) end)
end end
return widget._widget_caches[kind] return widget._private.widget_caches[kind]
end end
-- Special value to skip the dependency recording that is normally done by -- Special value to skip the dependency recording that is normally done by
@ -177,7 +222,7 @@ local clear_caches
function clear_caches(widget) function clear_caches(widget)
local deps = widget_dependencies[widget] or {} local deps = widget_dependencies[widget] or {}
widget_dependencies[widget] = {} widget_dependencies[widget] = {}
widget._widget_caches = {} widget._private.widget_caches = {}
for w in pairs(deps) do for w in pairs(deps) do
clear_caches(w) clear_caches(w)
end end
@ -187,6 +232,7 @@ end
--- Figure out the geometry in device coordinate space. This gives only tight --- Figure out the geometry in device coordinate space. This gives only tight
-- bounds if no rotations by non-multiples of 90° are used. -- bounds if no rotations by non-multiples of 90° are used.
-- @function wibox.widget.base.rect_to_device_geometry
function base.rect_to_device_geometry(cr, x, y, width, height) function base.rect_to_device_geometry(cr, x, y, width, height)
return matrix.transform_rectangle(cr.matrix, x, y, width, height) return matrix.transform_rectangle(cr.matrix, x, y, width, height)
end end
@ -200,10 +246,11 @@ end
-- @param width The available width for the widget -- @param width The available width for the widget
-- @param height The available height for the widget -- @param height The available height for the widget
-- @return The width and height that the widget wants to use -- @return The width and height that the widget wants to use
-- @function wibox.widget.base.fit_widget
function base.fit_widget(parent, context, widget, width, height) function base.fit_widget(parent, context, widget, width, height)
record_dependency(parent, widget) record_dependency(parent, widget)
if not widget.visible then if not widget._private.visible then
return 0, 0 return 0, 0
end end
@ -225,8 +272,8 @@ function base.fit_widget(parent, context, widget, width, height)
end end
-- Apply forced size and handle nil's -- Apply forced size and handle nil's
w = widget._forced_width or w or 0 w = widget._private.forced_width or w or 0
h = widget._forced_height or h or 0 h = widget._private.forced_height or h or 0
-- Also sanitize the output. -- Also sanitize the output.
w = math.max(0, math.min(w, width)) w = math.max(0, math.min(w, width))
@ -244,10 +291,11 @@ end
-- @param width The available width for the widget -- @param width The available width for the widget
-- @param height The available height for the widget -- @param height The available height for the widget
-- @return The result from the widget's `:layout` callback. -- @return The result from the widget's `:layout` callback.
-- @function wibox.widget.base.layout_widget
function base.layout_widget(parent, context, widget, width, height) function base.layout_widget(parent, context, widget, width, height)
record_dependency(parent, widget) record_dependency(parent, widget)
if not widget.visible then if not widget._private.visible then
return return
end end
@ -262,6 +310,7 @@ end
-- Handle a button event on a widget. This is used internally and should not be -- Handle a button event on a widget. This is used internally and should not be
-- called directly. -- called directly.
-- @function wibox.widget.base.handle_button
function base.handle_button(event, widget, x, y, button, modifiers, geometry) function base.handle_button(event, widget, x, y, button, modifiers, geometry)
x = x or y -- luacheck: no unused x = x or y -- luacheck: no unused
local function is_any(mod) local function is_any(mod)
@ -282,7 +331,7 @@ function base.handle_button(event, widget, x, y, button, modifiers, geometry)
-- Find all matching button objects -- Find all matching button objects
local matches = {} local matches = {}
for _, v in pairs(widget.widget_buttons) do for _, v in pairs(widget._private.widget_buttons) do
local match = true local match = true
-- Is it the right button? -- Is it the right button?
if v.button ~= 0 and v.button ~= button then match = false end if v.button ~= 0 and v.button ~= button then match = false end
@ -310,6 +359,7 @@ end
-- @param height The height of the widget in its own coordinate system. That is, -- @param height The height of the widget in its own coordinate system. That is,
-- after applying the transformation matrix. -- after applying the transformation matrix.
-- @return An opaque object that can be returned from :layout() -- @return An opaque object that can be returned from :layout()
-- @function wibox.widget.base.place_widget_via_matrix
function base.place_widget_via_matrix(widget, mat, width, height) function base.place_widget_via_matrix(widget, mat, width, height)
return { return {
_widget = widget, _widget = widget,
@ -329,6 +379,7 @@ end
-- @param height The height of the widget in its own coordinate system. That is, -- @param height The height of the widget in its own coordinate system. That is,
-- after applying the transformation matrix. -- after applying the transformation matrix.
-- @return An opaque object that can be returned from :layout() -- @return An opaque object that can be returned from :layout()
-- @function wibox.widget.base.place_widget_at
function base.place_widget_at(widget, x, y, width, height) function base.place_widget_at(widget, x, y, width, height)
return base.place_widget_via_matrix(widget, matrix.create_translate(x, y), width, height) return base.place_widget_via_matrix(widget, matrix.create_translate(x, y), width, height)
end end
@ -424,12 +475,17 @@ end
-- Only available when the declarative system is used -- Only available when the declarative system is used
local function get_children_by_id(self, name) local function get_children_by_id(self, name)
return self._by_id[name] or {} if rawget(self, "_private") then
return self._private.by_id[name] or {}
else
return rawget(self, "_by_id")[name] or {}
end
end end
--- Set a declarative widget hierarchy description. --- Set a declarative widget hierarchy description.
-- See [The declarative layout system](../documentation/03-declarative-layout.md.html) -- See [The declarative layout system](../documentation/03-declarative-layout.md.html)
-- @param args An array containing the widgets disposition -- @param args An array containing the widgets disposition
-- @function setup
function base.widget:setup(args) function base.widget:setup(args)
local f,ids = self.set_widget or self.add or self.set_first,{} local f,ids = self.set_widget or self.add or self.set_first,{}
local w, id = drill(ids, args) local w, id = drill(ids, args)
@ -438,13 +494,20 @@ function base.widget:setup(args)
-- Avoid being dropped by wibox metatable -> drawin -- Avoid being dropped by wibox metatable -> drawin
rawset(self, id, w) rawset(self, id, w)
end end
rawset(self, "_by_id", ids)
if rawget(self, "_private") then
self._private.by_id = ids
else
rawset(self, "_by_id", ids)
end
rawset(self, "get_children_by_id", get_children_by_id) rawset(self, "get_children_by_id", get_children_by_id)
end end
--- Create a widget from a declarative description --- Create a widget from a declarative description
-- See [The declarative layout system](../documentation/03-declarative-layout.md.html) -- See [The declarative layout system](../documentation/03-declarative-layout.md.html)
-- @param args An array containing the widgets disposition -- @param args An array containing the widgets disposition
-- @function wibox.widget.base.make_widget_declarative
function base.make_widget_declarative(args) function base.make_widget_declarative(args)
local ids = {} local ids = {}
@ -454,10 +517,16 @@ function base.make_widget_declarative(args)
local w, id = drill(ids, args) local w, id = drill(ids, args)
local mt = {} local mt = getmetatable(w) or {}
local orig_string = tostring(w) local orig_string = tostring(w)
rawset(w, "_by_id", ids)
if rawget(w, "_private") then
w._private.by_id = ids
else
rawset(w, "_by_id", ids)
end
rawset(w, "get_children_by_id", get_children_by_id) rawset(w, "get_children_by_id", get_children_by_id)
mt.__tostring = function() mt.__tostring = function()
@ -474,9 +543,18 @@ end
-- looks the same on the screen. -- looks the same on the screen.
-- @tparam[opt] string widget_name Name of the widget. If not set, it will be -- @tparam[opt] string widget_name Name of the widget. If not set, it will be
-- set automatically via `gears.object.modulename`. -- set automatically via `gears.object.modulename`.
-- @tparam[opt={}] table args Widget settings
-- @tparam[opt=false] boolean args.enable_properties Enable automatic getters and
-- setters calls.
-- @tparam[opt=nil] table args.class The widget class
-- @see fit_widget -- @see fit_widget
function base.make_widget(proxy, widget_name) -- @function wibox.widget.base.make_widget
local ret = object() function base.make_widget(proxy, widget_name, args)
args = args or {}
local ret = object {
enable_properties = args.enable_properties,
class = args.class,
}
-- This signal is used by layouts to find out when they have to update. -- This signal is used by layouts to find out when they have to update.
ret:add_signal("widget::layout_changed") ret:add_signal("widget::layout_changed")
@ -495,21 +573,24 @@ function base.make_widget(proxy, widget_name)
ret:emit_signal("widget::redraw_needed") ret:emit_signal("widget::redraw_needed")
end) end)
-- Create a table used to store the widgets internal data
rawset(ret, "_private", {})
-- No buttons yet -- No buttons yet
ret.widget_buttons = {} ret._private.widget_buttons = {}
-- Widget is visible -- Widget is visible
ret.visible = true ret._private.visible = true
-- Widget is fully opaque -- Widget is fully opaque
ret.opacity = 1 ret._private.opacity = 1
-- Differentiate tables from widgets -- Differentiate tables from widgets
ret.is_widget = true rawset(ret, "is_widget", true)
-- Size is not restricted/forced -- Size is not restricted/forced
ret._forced_width = nil ret._private.forced_width = nil
ret._forced_height = nil ret._private.forced_height = nil
-- Make buttons work -- Make buttons work
ret:connect_signal("button::press", function(...) ret:connect_signal("button::press", function(...)
@ -520,12 +601,12 @@ function base.make_widget(proxy, widget_name)
end) end)
if proxy then if proxy then
ret.fit = function(_, context, width, height) rawset(ret, "fit", function(_, context, width, height)
return base.fit_widget(ret, context, proxy, width, height) return base.fit_widget(ret, context, proxy, width, height)
end end)
ret.layout = function(_, _, width, height) rawset(ret, "layout", function(_, _, width, height)
return { base.place_widget_at(proxy, 0, 0, width, height) } return { base.place_widget_at(proxy, 0, 0, width, height) }
end end)
proxy:connect_signal("widget::layout_changed", function() proxy:connect_signal("widget::layout_changed", function()
ret:emit_signal("widget::layout_changed") ret:emit_signal("widget::layout_changed")
end) end)
@ -542,12 +623,12 @@ function base.make_widget(proxy, widget_name)
-- Add functions -- Add functions
for k, v in pairs(base.widget) do for k, v in pairs(base.widget) do
ret[k] = v rawset(ret, k, v)
end end
-- Add __tostring method to metatable. -- Add __tostring method to metatable.
ret.widget_name = widget_name or object.modulename(3) rawset(ret, "widget_name", widget_name or object.modulename(3))
local mt = {} local mt = getmetatable(ret) or {}
local orig_string = tostring(ret) local orig_string = tostring(ret)
mt.__tostring = function() mt.__tostring = function()
return string.format("%s (%s)", ret.widget_name, orig_string) return string.format("%s (%s)", ret.widget_name, orig_string)
@ -556,12 +637,14 @@ function base.make_widget(proxy, widget_name)
end end
--- Generate an empty widget which takes no space and displays nothing --- Generate an empty widget which takes no space and displays nothing
-- @function wibox.widget.base.empty_widget
function base.empty_widget() function base.empty_widget()
return base.make_widget() return base.make_widget()
end end
--- Do some sanity checking on widget. This function raises a lua error if --- Do some sanity checking on widget. This function raises a lua error if
-- widget is not a valid widget. -- widget is not a valid widget.
-- @function wibox.widget.base.check_widget
function base.check_widget(widget) function base.check_widget(widget)
assert(type(widget) == "table", "Type should be table, but is " .. tostring(type(widget))) assert(type(widget) == "table", "Type should be table, but is " .. tostring(type(widget)))
assert(widget.is_widget, "Argument is not a widget!") assert(widget.is_widget, "Argument is not a widget!")

291
lib/wibox/widget/graph.lua Normal file
View File

@ -0,0 +1,291 @@
---------------------------------------------------------------------------
--- A graph widget.
--
--@DOC_wibox_widget_defaults_graph_EXAMPLE@
-- @author Julien Danjou &lt;julien@danjou.info&gt;
-- @copyright 2009 Julien Danjou
-- @release @AWESOME_VERSION@
-- @classmod wibox.widget.graph
---------------------------------------------------------------------------
local setmetatable = setmetatable
local ipairs = ipairs
local math = math
local table = table
local type = type
local color = require("gears.color")
local base = require("wibox.widget.base")
local beautiful = require("beautiful")
local graph = { mt = {} }
--- Set the graph border color.
-- If the value is nil, no border will be drawn.
--
-- @property border_color
-- @tparam geats.color border_color The border color to set.
--- Set the graph foreground color.
--
-- @property color
-- @tparam color color The graph color.
-- @see gears.color.create_pattern
--- Set the graph background color.
--
-- @property background_color
-- @tparam gears.color background_color The graph background color.
--- Set the maximum value the graph should handle.
-- If "scale" is also set, the graph never scales up below this value, but it
-- automatically scales down to make all data fit.
--
-- @property max_value
-- @param number
--- Set the graph to automatically scale its values. Default is false.
--
-- @property scale
-- @param boolean
--- Set the graph to draw stacks. Default is false.
--
-- @property stack
-- @param boolean
--- Set the graph stacking colors. Order matters.
--
-- @property stack_colors
-- @param stack_colors A table with stacking colors.
--- The graph background color.
-- @beautiful beautiful.graph_bg
--- The graph foreground color.
-- @beautiful beautiful.graph_fg
--- The graph border color.
-- @beautiful beautiful.graph_border_color
local properties = { "width", "height", "border_color", "stack",
"stack_colors", "color", "background_color",
"max_value", "scale" }
function graph.draw(_graph, _, cr, width, height)
local max_value = _graph._private.max_value
local values = _graph._private.values
cr:set_line_width(1)
-- Draw the background first
cr:set_source(color(_graph._private.background_color or beautiful.graph_bg or "#000000aa"))
cr:paint()
-- Account for the border width
cr:save()
if _graph._private.border_color then
cr:translate(1, 1)
width, height = width - 2, height - 2
end
-- Draw a stacked graph
if _graph._private.stack then
if _graph._private.scale then
for _, v in ipairs(values) do
for _, sv in ipairs(v) do
if sv > max_value then
max_value = sv
end
end
end
end
for i = 0, width do
local rel_i = 0
local rel_x = i + 0.5
if _graph._private.stack_colors then
for idx, col in ipairs(_graph._private.stack_colors) do
local stack_values = values[idx]
if stack_values and i < #stack_values then
local value = stack_values[#stack_values - i] + rel_i
cr:move_to(rel_x, height * (1 - (rel_i / max_value)))
cr:line_to(rel_x, height * (1 - (value / max_value)))
cr:set_source(color(col or beautiful.graph_fg or "#ff0000"))
cr:stroke()
rel_i = value
end
end
end
end
else
if _graph._private.scale then
for _, v in ipairs(values) do
if v > max_value then
max_value = v
end
end
end
-- Draw the background on no value
if #values ~= 0 then
-- Draw reverse
for i = 0, #values - 1 do
local value = values[#values - i]
if value >= 0 then
value = value / max_value
cr:move_to(i + 0.5, height * (1 - value))
cr:line_to(i + 0.5, height)
end
end
cr:set_source(color(_graph._private.color or beautiful.graph_fg or "#ff0000"))
cr:stroke()
end
end
-- Undo the cr:translate() for the border
cr:restore()
-- Draw the border last so that it overlaps already drawn values
if _graph._private.border_color then
-- We decremented these by two above
width, height = width + 2, height + 2
-- Draw the border
cr:rectangle(0.5, 0.5, width - 1, height - 1)
cr:set_source(color(_graph._private.border_color or beautiful.graph_border_color or "#ffffff"))
cr:stroke()
end
end
function graph.fit(_graph)
return _graph._private.width, _graph._private.height
end
--- Add a value to the graph
--
-- @param value The value to be added to the graph
-- @param group The stack color group index.
function graph:add_value(value, group)
value = value or 0
local values = self._private.values
local max_value = self._private.max_value
value = math.max(0, value)
if not self._private.scale then
value = math.min(max_value, value)
end
if self._private.stack and group then
if not self._private.values[group]
or type(self._private.values[group]) ~= "table"
then
self._private.values[group] = {}
end
values = self._private.values[group]
end
table.insert(values, value)
local border_width = 0
if self._private.border_color then border_width = 2 end
-- Ensure we never have more data than we can draw
while #values > self._private.width - border_width do
table.remove(values, 1)
end
self:emit_signal("widget::redraw_needed")
return self
end
--- Clear the graph.
function graph:clear()
self._private.values = {}
self:emit_signal("widget::redraw_needed")
return self
end
--- Set the graph height.
-- @param height The height to set.
function graph:set_height(height)
if height >= 5 then
self._private.height = height
self:emit_signal("widget::layout_changed")
end
return self
end
--- Set the graph width.
-- @param width The width to set.
function graph:set_width(width)
if width >= 5 then
self._private.width = width
self:emit_signal("widget::layout_changed")
end
return self
end
-- Build properties function
for _, prop in ipairs(properties) do
if not graph["set_" .. prop] then
graph["set_" .. prop] = function(_graph, value)
if _graph._private[prop] ~= value then
_graph._private[prop] = value
_graph:emit_signal("widget::redraw_needed")
end
return _graph
end
end
if not graph["get_" .. prop] then
graph["get_" .. prop] = function(_graph)
return _graph._private[prop]
end
end
end
--- Create a graph widget.
-- @param args Standard widget() arguments. You should add width and height
-- key to set graph geometry.
-- @return A new graph widget.
-- @function wibox.widget.graph
function graph.new(args)
args = args or {}
local width = args.width or 100
local height = args.height or 20
if width < 5 or height < 5 then return end
local _graph = base.make_widget(nil, nil, {enable_properties = true})
_graph._private.width = width
_graph._private.height = height
_graph._private.values = {}
_graph._private.max_value = 1
-- Set methods
_graph.add_value = graph["add_value"]
_graph.clear = graph["clear"]
_graph.draw = graph.draw
_graph.fit = graph.fit
for _, prop in ipairs(properties) do
_graph["set_" .. prop] = graph["set_" .. prop]
_graph["get_" .. prop] = graph["get_" .. prop]
end
return _graph
end
function graph.mt:__call(...)
return graph.new(...)
end
--@DOC_widget_COMMON@
--@DOC_object_COMMON@
return setmetatable(graph, graph.mt)
-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80

View File

@ -1,4 +1,6 @@
--------------------------------------------------------------------------- ---------------------------------------------------------------------------
--
--@DOC_wibox_widget_defaults_imagebox_EXAMPLE@
-- @author Uli Schlachter -- @author Uli Schlachter
-- @copyright 2010 Uli Schlachter -- @copyright 2010 Uli Schlachter
-- @release @AWESOME_VERSION@ -- @release @AWESOME_VERSION@
@ -7,23 +9,23 @@
local base = require("wibox.widget.base") local base = require("wibox.widget.base")
local surface = require("gears.surface") local surface = require("gears.surface")
local util = require("awful.util")
local setmetatable = setmetatable local setmetatable = setmetatable
local pairs = pairs
local type = type local type = type
local print = print local print = print
local unpack = unpack or table.unpack -- luacheck: globals unpack (compatibility with Lua 5.1) local unpack = unpack or table.unpack -- luacheck: globals unpack (compatibility with Lua 5.1)
local imagebox = { mt = {} } local imagebox = { mt = {} }
--- Draw an imagebox with the given cairo context in the given geometry. -- Draw an imagebox with the given cairo context in the given geometry.
function imagebox:draw(_, cr, width, height) function imagebox:draw(_, cr, width, height)
if not self._image then return end if not self._private.image then return end
if width == 0 or height == 0 then return end if width == 0 or height == 0 then return end
if not self.resize_forbidden then if not self._private.resize_forbidden then
-- Let's scale the image so that it fits into (width, height) -- Let's scale the image so that it fits into (width, height)
local w = self._image:get_width() local w = self._private.image:get_width()
local h = self._image:get_height() local h = self._private.image:get_height()
local aspect = width / w local aspect = width / w
local aspect_h = height / h local aspect_h = height / h
if aspect > aspect_h then aspect = aspect_h end if aspect > aspect_h then aspect = aspect_h end
@ -32,22 +34,22 @@ function imagebox:draw(_, cr, width, height)
end end
-- Set the clip -- Set the clip
if self._clip_shape then if self._private.clip_shape then
cr:clip(self._clip_shape(cr, width, height, unpack(self._clip_args))) cr:clip(self._private.clip_shape(cr, width, height, unpack(self._private.clip_args)))
end end
cr:set_source_surface(self._image, 0, 0) cr:set_source_surface(self._private.image, 0, 0)
cr:paint() cr:paint()
end end
--- Fit the imagebox into the given geometry -- Fit the imagebox into the given geometry
function imagebox:fit(_, width, height) function imagebox:fit(_, width, height)
if not self._image then if not self._private.image then
return 0, 0 return 0, 0
end end
local w = self._image:get_width() local w = self._private.image:get_width()
local h = self._image:get_height() local h = self._private.image:get_height()
if w > width then if w > width then
h = h * width / w h = h * width / w
@ -62,7 +64,7 @@ function imagebox:fit(_, width, height)
return 0, 0 return 0, 0
end end
if not self.resize_forbidden then if not self._private.resize_forbidden then
local aspect = width / w local aspect = width / w
local aspect_h = height / h local aspect_h = height / h
@ -76,9 +78,11 @@ function imagebox:fit(_, width, height)
end end
--- Set an imagebox' image --- Set an imagebox' image
-- @property image
-- @param image Either a string or a cairo image surface. A string is -- @param image Either a string or a cairo image surface. A string is
-- interpreted as the path to a png image file. -- interpreted as the path to a png image file.
-- @return true on success, false if the image cannot be used -- @return true on success, false if the image cannot be used
function imagebox:set_image(image) function imagebox:set_image(image)
if type(image) == "string" then if type(image) == "string" then
image = surface.load(image) image = surface.load(image)
@ -98,19 +102,28 @@ function imagebox:set_image(image)
end end
end end
if self._image == image then if self._private.image == image then
-- The image could have been modified, so better redraw -- The image could have been modified, so better redraw
self:emit_signal("widget::redraw_needed") self:emit_signal("widget::redraw_needed")
return return
end end
self._image = image self._private.image = image
self:emit_signal("widget::redraw_needed") self:emit_signal("widget::redraw_needed")
self:emit_signal("widget::layout_changed") self:emit_signal("widget::layout_changed")
return true return true
end end
--- Set a clip shape for this imagebox
-- A clip shape define an area where the content is displayed and one where it
-- is trimmed.
--
-- @property clip_shape
-- @param clip_shape A `gears_shape` compatible shape function
-- @see gears.shape
-- @see set_clip_shape
--- Set a clip shape for this imagebox --- Set a clip shape for this imagebox
-- A clip shape define an area where the content is displayed and one where it -- A clip shape define an area where the content is displayed and one where it
-- is trimmed. -- is trimmed.
@ -118,35 +131,37 @@ end
-- Any other parameters will be passed to the clip shape function -- Any other parameters will be passed to the clip shape function
-- --
-- @param clip_shape A `gears_shape` compatible shape function -- @param clip_shape A `gears_shape` compatible shape function
-- @see gears.shape
-- @see clip_shape
function imagebox:set_clip_shape(clip_shape, ...) function imagebox:set_clip_shape(clip_shape, ...)
self._clip_shape = clip_shape self._private.clip_shape = clip_shape
self._clip_args = {...} self._private.clip_args = {...}
self:emit_signal("widget::redraw_needed") self:emit_signal("widget::redraw_needed")
end end
--- Should the image be resized to fit into the available space? --- Should the image be resized to fit into the available space?
-- @property resize
-- @param allowed If false, the image will be clipped, else it will be resized -- @param allowed If false, the image will be clipped, else it will be resized
-- to fit into the available space. -- to fit into the available space.
function imagebox:set_resize(allowed) function imagebox:set_resize(allowed)
self.resize_forbidden = not allowed self._private.resize_forbidden = not allowed
self:emit_signal("widget::redraw_needed") self:emit_signal("widget::redraw_needed")
self:emit_signal("widget::layout_changed") self:emit_signal("widget::layout_changed")
end end
--- Returns a new imagebox --- Returns a new imagebox.
-- Any other arguments will be passed to the clip shape function -- Any other arguments will be passed to the clip shape function
-- @param image the image to display, may be nil -- @param image the image to display, may be nil
-- @param resize_allowed If false, the image will be clipped, else it will be resized -- @param resize_allowed If false, the image will be clipped, else it will be resized
-- to fit into the available space. -- to fit into the available space.
-- @param clip_shape A `gears.shape` compatible function -- @param clip_shape A `gears.shape` compatible function
-- @treturn table A new `imagebox`
-- @function wibox.widget.imagebox
local function new(image, resize_allowed, clip_shape) local function new(image, resize_allowed, clip_shape)
local ret = base.make_widget() local ret = base.make_widget(nil, nil, {enable_properties = true})
for k, v in pairs(imagebox) do util.table.crush(ret, imagebox, true)
if type(v) == "function" then
ret[k] = v
end
end
if image then if image then
ret:set_image(image) ret:set_image(image)
@ -155,8 +170,8 @@ local function new(image, resize_allowed, clip_shape)
ret:set_resize(resize_allowed) ret:set_resize(resize_allowed)
end end
ret._clip_shape = clip_shape ret._private.clip_shape = clip_shape
ret._clip_args = {} ret._private.clip_args = {}
return ret return ret
end end
@ -165,6 +180,10 @@ function imagebox.mt:__call(...)
return new(...) return new(...)
end end
--@DOC_widget_COMMON@
--@DOC_object_COMMON@
return setmetatable(imagebox, imagebox.mt) return setmetatable(imagebox, imagebox.mt)
-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80 -- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80

View File

@ -12,6 +12,9 @@ return setmetatable({
imagebox = require("wibox.widget.imagebox"); imagebox = require("wibox.widget.imagebox");
background = require("wibox.widget.background"); background = require("wibox.widget.background");
systray = require("wibox.widget.systray"); systray = require("wibox.widget.systray");
textclock = require("wibox.widget.textclock");
progressbar = require("wibox.widget.progressbar");
graph = require("wibox.widget.graph");
}, {__call = function(_, args) return base.make_widget_declarative(args) end}) }, {__call = function(_, args) return base.make_widget_declarative(args) end})
-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80 -- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80

View File

@ -0,0 +1,243 @@
---------------------------------------------------------------------------
--- A progressbar widget.
--
--@DOC_wibox_widget_defaults_progressbar_EXAMPLE@
-- @author Julien Danjou &lt;julien@danjou.info&gt;
-- @copyright 2009 Julien Danjou
-- @release @AWESOME_VERSION@
-- @classmod wibox.widget.progressbar
---------------------------------------------------------------------------
local setmetatable = setmetatable
local ipairs = ipairs
local math = math
local base = require("wibox.widget.base")
local color = require("gears.color")
local beautiful = require("beautiful")
local progressbar = { mt = {} }
local data = setmetatable({}, { __mode = "k" })
--- Set the progressbar border color.
-- If the value is nil, no border will be drawn.
--
-- @function set_border_color
-- @param progressbar The progressbar.
-- @param color The border color to set.
--- Set the progressbar foreground color.
--
-- @function set_color
-- @param progressbar The progressbar.
-- @param color The progressbar color.
--- Set the progressbar background color.
--
-- @function set_background_color
-- @param progressbar The progressbar.
-- @param color The progressbar background color.
--- Set the progressbar to draw vertically. Default is false.
--
-- @function set_vertical
-- @param progressbar The progressbar.
-- @param vertical A boolean value.
--- Set the progressbar to draw ticks. Default is false.
--
-- @function set_ticks
-- @param progressbar The progressbar.
-- @param ticks A boolean value.
--- Set the progressbar ticks gap.
--
-- @function set_ticks_gap
-- @param progressbar The progressbar.
-- @param value The value.
--- Set the progressbar ticks size.
--
-- @function set_ticks_size
-- @param progressbar The progressbar.
-- @param value The value.
--- Set the maximum value the progressbar should handle.
--
-- @function set_max_value
-- @param progressbar The progressbar.
-- @param value The value.
--- The progressbar background color.
-- @beautiful beautiful.graph_bg
--- The progressbar foreground color.
-- @beautiful beautiful.graph_fg
--- The progressbar border color.
-- @beautiful beautiful.graph_border_color
local properties = { "width", "height", "border_color",
"color", "background_color",
"vertical", "value", "max_value",
"ticks", "ticks_gap", "ticks_size" }
function progressbar.draw(pbar, _, cr, width, height)
local ticks_gap = data[pbar].ticks_gap or 1
local ticks_size = data[pbar].ticks_size or 4
-- We want one pixel wide lines
cr:set_line_width(1)
local value = data[pbar].value
local max_value = data[pbar].max_value
if value >= 0 then
value = value / max_value
end
local over_drawn_width = width
local over_drawn_height = height
local border_width = 0
local col = data[pbar].border_color or beautiful.progressbar_border_color
if col then
-- Draw border
cr:rectangle(0.5, 0.5, width - 1, height - 1)
cr:set_source(color(col))
cr:stroke()
over_drawn_width = width - 2 -- remove 2 for borders
over_drawn_height = height - 2 -- remove 2 for borders
border_width = 1
end
cr:rectangle(border_width, border_width,
over_drawn_width, over_drawn_height)
cr:set_source(color(data[pbar].color or beautiful.progressbar_fg or "#ff0000"))
cr:fill()
-- Cover the part that is not set with a rectangle
if data[pbar].vertical then
local rel_height = over_drawn_height * (1 - value)
cr:rectangle(border_width,
border_width,
over_drawn_width,
rel_height)
cr:set_source(color(data[pbar].background_color or beautiful.progressbar_bg or "#000000aa"))
cr:fill()
-- Place smaller pieces over the gradient if ticks are enabled
if data[pbar].ticks then
for i=0, height / (ticks_size+ticks_gap)-border_width do
local rel_offset = over_drawn_height / 1 - (ticks_size+ticks_gap) * i
if rel_offset >= rel_height then
cr:rectangle(border_width,
rel_offset,
over_drawn_width,
ticks_gap)
end
end
cr:set_source(color(data[pbar].background_color or beautiful.progressbar_bg or "#000000aa"))
cr:fill()
end
else
local rel_x = over_drawn_width * value
cr:rectangle(border_width + rel_x,
border_width,
over_drawn_width - rel_x,
over_drawn_height)
cr:set_source(color(data[pbar].background_color or "#000000aa"))
cr:fill()
if data[pbar].ticks then
for i=0, width / (ticks_size+ticks_gap)-border_width do
local rel_offset = over_drawn_width / 1 - (ticks_size+ticks_gap) * i
if rel_offset <= rel_x then
cr:rectangle(rel_offset,
border_width,
ticks_gap,
over_drawn_height)
end
end
cr:set_source(color(data[pbar].background_color or "#000000aa"))
cr:fill()
end
end
end
function progressbar.fit(pbar)
return data[pbar].width, data[pbar].height
end
--- Set the progressbar value.
-- @param value The progress bar value between 0 and 1.
function progressbar:set_value(value)
value = value or 0
local max_value = data[self].max_value
data[self].value = math.min(max_value, math.max(0, value))
self:emit_signal("widget::redraw_needed")
return self
end
--- Set the progressbar height.
-- @param height The height to set.
function progressbar:set_height(height)
data[self].height = height
self:emit_signal("widget::layout_changed")
return self
end
--- Set the progressbar width.
-- @param width The width to set.
function progressbar:set_width(width)
data[self].width = width
self:emit_signal("widget::layout_changed")
return self
end
-- Build properties function
for _, prop in ipairs(properties) do
if not progressbar["set_" .. prop] then
progressbar["set_" .. prop] = function(pbar, value)
data[pbar][prop] = value
pbar:emit_signal("widget::redraw_needed")
return pbar
end
end
end
--- Create a progressbar widget.
-- @param args Standard widget() arguments. You should add width and height
-- key to set progressbar geometry.
-- @return A progressbar widget.
-- @function wibox.widget.progressbar
function progressbar.new(args)
args = args or {}
local width = args.width or 100
local height = args.height or 20
args.type = "imagebox"
local pbar = base.make_widget()
data[pbar] = { width = width, height = height, value = 0, max_value = 1 }
-- Set methods
for _, prop in ipairs(properties) do
pbar["set_" .. prop] = progressbar["set_" .. prop]
end
pbar.draw = progressbar.draw
pbar.fit = progressbar.fit
return pbar
end
function progressbar.mt:__call(...)
return progressbar.new(...)
end
return setmetatable(progressbar, progressbar.mt)
-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80

View File

@ -7,6 +7,7 @@
local wbase = require("wibox.widget.base") local wbase = require("wibox.widget.base")
local beautiful = require("beautiful") local beautiful = require("beautiful")
local util = require("awful.util")
local capi = { local capi = {
awesome = awesome, awesome = awesome,
screen = screen screen = screen
@ -23,6 +24,14 @@ local base_size = nil
local reverse = false local reverse = false
local display_on_screen = "primary" local display_on_screen = "primary"
--- The systray background color.
-- @beautiful beautiful.bg_systray
-- @param string The color (string like "#ff0000" only)
--- The systray icon spacing.
-- @beautiful beautiful.systray_icon_spacing
-- @tparam[opt=0] integer The icon spacing
local function should_display_on(s) local function should_display_on(s)
if display_on_screen == "primary" then if display_on_screen == "primary" then
return s == capi.screen.primary return s == capi.screen.primary
@ -138,12 +147,16 @@ function systray:set_screen(s)
end end
end end
--- Create the systray widget.
-- Note that this widget can only exist once.
-- @tparam boolean revers Show in the opposite direction
-- @treturn table The new `systray` widget
-- @function wibox.widget.systray
local function new(revers) local function new(revers)
local ret = wbase.make_widget() local ret = wbase.make_widget()
for k, v in pairs(systray) do util.table.crush(ret, systray, true)
ret[k] = v
end
if revers then if revers then
ret:set_reverse(true) ret:set_reverse(true)

View File

@ -1,4 +1,6 @@
--------------------------------------------------------------------------- ---------------------------------------------------------------------------
--
--@DOC_wibox_widget_defaults_textbox_EXAMPLE@
-- @author Uli Schlachter -- @author Uli Schlachter
-- @author dodo -- @author dodo
-- @copyright 2010, 2011 Uli Schlachter, dodo -- @copyright 2010, 2011 Uli Schlachter, dodo
@ -10,54 +12,56 @@ local base = require("wibox.widget.base")
local gdebug = require("gears.debug") local gdebug = require("gears.debug")
local beautiful = require("beautiful") local beautiful = require("beautiful")
local lgi = require("lgi") local lgi = require("lgi")
local util = require("awful.util")
local Pango = lgi.Pango local Pango = lgi.Pango
local PangoCairo = lgi.PangoCairo local PangoCairo = lgi.PangoCairo
local type = type
local setmetatable = setmetatable local setmetatable = setmetatable
local pairs = pairs
local textbox = { mt = {} } local textbox = { mt = {} }
--- The textbox font.
-- @beautiful beautiful.font
--- Set the DPI of a Pango layout --- Set the DPI of a Pango layout
local function setup_dpi(box, dpi) local function setup_dpi(box, dpi)
if box.dpi ~= dpi then if box._private.dpi ~= dpi then
box.dpi = dpi box._private.dpi = dpi
box._ctx:set_resolution(dpi) box._private.ctx:set_resolution(dpi)
box._layout:context_changed() box._private.layout:context_changed()
end end
end end
--- Setup a pango layout for the given textbox and dpi --- Setup a pango layout for the given textbox and dpi
local function setup_layout(box, width, height, dpi) local function setup_layout(box, width, height, dpi)
box._layout.width = Pango.units_from_double(width) box._private.layout.width = Pango.units_from_double(width)
box._layout.height = Pango.units_from_double(height) box._private.layout.height = Pango.units_from_double(height)
setup_dpi(box, dpi) setup_dpi(box, dpi)
end end
--- Draw the given textbox on the given cairo context in the given geometry -- Draw the given textbox on the given cairo context in the given geometry
function textbox:draw(context, cr, width, height) function textbox:draw(context, cr, width, height)
setup_layout(self, width, height, context.dpi) setup_layout(self, width, height, context.dpi)
cr:update_layout(self._layout) cr:update_layout(self._private.layout)
local _, logical = self._layout:get_pixel_extents() local _, logical = self._private.layout:get_pixel_extents()
local offset = 0 local offset = 0
if self._valign == "center" then if self._private.valign == "center" then
offset = (height - logical.height) / 2 offset = (height - logical.height) / 2
elseif self._valign == "bottom" then elseif self._private.valign == "bottom" then
offset = height - logical.height offset = height - logical.height
end end
cr:move_to(0, offset) cr:move_to(0, offset)
cr:show_layout(self._layout) cr:show_layout(self._private.layout)
end end
local function do_fit_return(self) local function do_fit_return(self)
local _, logical = self._layout:get_pixel_extents() local _, logical = self._private.layout:get_pixel_extents()
if logical.width == 0 or logical.height == 0 then if logical.width == 0 or logical.height == 0 then
return 0, 0 return 0, 0
end end
return logical.width, logical.height return logical.width, logical.height
end end
--- Fit the given textbox -- Fit the given textbox
function textbox:fit(context, width, height) function textbox:fit(context, width, height)
setup_layout(self, width, height, context.dpi) setup_layout(self, width, height, context.dpi)
return do_fit_return(self) return do_fit_return(self)
@ -92,8 +96,8 @@ end
function textbox:get_preferred_size_at_dpi(dpi) function textbox:get_preferred_size_at_dpi(dpi)
local max_lines = 2^20 local max_lines = 2^20
setup_dpi(self, dpi) setup_dpi(self, dpi)
self._layout.width = -1 -- no width set self._private.layout.width = -1 -- no width set
self._layout.height = -max_lines -- show this many lines per paragraph self._private.layout.height = -max_lines -- show this many lines per paragraph
return do_fit_return(self) return do_fit_return(self)
end end
@ -106,8 +110,8 @@ end
function textbox:get_height_for_width_at_dpi(width, dpi) function textbox:get_height_for_width_at_dpi(width, dpi)
local max_lines = 2^20 local max_lines = 2^20
setup_dpi(self, dpi) setup_dpi(self, dpi)
self._layout.width = Pango.units_from_double(width) self._private.layout.width = Pango.units_from_double(width)
self._layout.height = -max_lines -- show this many lines per paragraph self._private.layout.height = -max_lines -- show this many lines per paragraph
local _, h = do_fit_return(self) local _, h = do_fit_return(self)
return h return h
end end
@ -121,7 +125,7 @@ end
-- @treturn[2] boolean false -- @treturn[2] boolean false
-- @treturn[2] string Error message explaining why the markup was invalid. -- @treturn[2] string Error message explaining why the markup was invalid.
function textbox:set_markup_silently(text) function textbox:set_markup_silently(text)
if self._markup == text then if self._private.markup == text then
return true return true
end end
@ -131,9 +135,9 @@ function textbox:set_markup_silently(text)
return false, parsed.message or tostring(parsed) return false, parsed.message or tostring(parsed)
end end
self._markup = text self._private.markup = text
self._layout.text = parsed self._private.layout.text = parsed
self._layout.attributes = attr self._private.layout.attributes = attr
self:emit_signal("widget::redraw_needed") self:emit_signal("widget::redraw_needed")
self:emit_signal("widget::layout_changed") self:emit_signal("widget::layout_changed")
return true return true
@ -141,9 +145,12 @@ end
--- Set the text of the textbox (with --- Set the text of the textbox (with
-- [Pango markup](https://developer.gnome.org/pango/stable/PangoMarkupFormat.html)). -- [Pango markup](https://developer.gnome.org/pango/stable/PangoMarkupFormat.html)).
-- @property markup
-- @tparam string text The text to set. This can contain pango markup (e.g. -- @tparam string text The text to set. This can contain pango markup (e.g.
-- `<b>bold</b>`). You can use `awful.util.escape` to escape -- `<b>bold</b>`). You can use `awful.util.escape` to escape
-- parts of it. -- parts of it.
-- @see text
function textbox:set_markup(text) function textbox:set_markup(text)
local success, message = self:set_markup_silently(text) local success, message = self:set_markup_silently(text)
if not success then if not success then
@ -151,96 +158,117 @@ function textbox:set_markup(text)
end end
end end
function textbox:get_markup()
return self._private.markup
end
--- Set a textbox' text. --- Set a textbox' text.
-- @property text
-- @param text The text to display. Pango markup is ignored and shown as-is. -- @param text The text to display. Pango markup is ignored and shown as-is.
-- @see markup
function textbox:set_text(text) function textbox:set_text(text)
if self._layout.text == text and self._layout.attributes == nil then if self._private.layout.text == text and self._private.layout.attributes == nil then
return return
end end
self._markup = nil self._private.markup = nil
self._layout.text = text self._private.layout.text = text
self._layout.attributes = nil self._private.layout.attributes = nil
self:emit_signal("widget::redraw_needed") self:emit_signal("widget::redraw_needed")
self:emit_signal("widget::layout_changed") self:emit_signal("widget::layout_changed")
end end
function textbox:get_text()
return self._private.layout.text
end
--- Set a textbox' ellipsize mode. --- Set a textbox' ellipsize mode.
-- @property ellipsize
-- @param mode Where should long lines be shortened? "start", "middle" or "end" -- @param mode Where should long lines be shortened? "start", "middle" or "end"
function textbox:set_ellipsize(mode) function textbox:set_ellipsize(mode)
local allowed = { none = "NONE", start = "START", middle = "MIDDLE", ["end"] = "END" } local allowed = { none = "NONE", start = "START", middle = "MIDDLE", ["end"] = "END" }
if allowed[mode] then if allowed[mode] then
if self._layout:get_ellipsize() == allowed[mode] then if self._private.layout:get_ellipsize() == allowed[mode] then
return return
end end
self._layout:set_ellipsize(allowed[mode]) self._private.layout:set_ellipsize(allowed[mode])
self:emit_signal("widget::redraw_needed") self:emit_signal("widget::redraw_needed")
self:emit_signal("widget::layout_changed") self:emit_signal("widget::layout_changed")
end end
end end
--- Set a textbox' wrap mode. --- Set a textbox' wrap mode.
-- @property wrap
-- @param mode Where to wrap? After "word", "char" or "word_char" -- @param mode Where to wrap? After "word", "char" or "word_char"
function textbox:set_wrap(mode) function textbox:set_wrap(mode)
local allowed = { word = "WORD", char = "CHAR", word_char = "WORD_CHAR" } local allowed = { word = "WORD", char = "CHAR", word_char = "WORD_CHAR" }
if allowed[mode] then if allowed[mode] then
if self._layout:get_wrap() == allowed[mode] then if self._private.layout:get_wrap() == allowed[mode] then
return return
end end
self._layout:set_wrap(allowed[mode]) self._private.layout:set_wrap(allowed[mode])
self:emit_signal("widget::redraw_needed") self:emit_signal("widget::redraw_needed")
self:emit_signal("widget::layout_changed") self:emit_signal("widget::layout_changed")
end end
end end
--- Set a textbox' vertical alignment --- The textbox' vertical alignment
-- @property valign
-- @param mode Where should the textbox be drawn? "top", "center" or "bottom" -- @param mode Where should the textbox be drawn? "top", "center" or "bottom"
function textbox:set_valign(mode) function textbox:set_valign(mode)
local allowed = { top = true, center = true, bottom = true } local allowed = { top = true, center = true, bottom = true }
if allowed[mode] then if allowed[mode] then
if self._valign == mode then if self._private.valign == mode then
return return
end end
self._valign = mode self._private.valign = mode
self:emit_signal("widget::redraw_needed") self:emit_signal("widget::redraw_needed")
self:emit_signal("widget::layout_changed") self:emit_signal("widget::layout_changed")
end end
end end
--- Set a textbox' horizontal alignment --- Set a textbox' horizontal alignment.
-- @property align
-- @param mode Where should the textbox be drawn? "left", "center" or "right" -- @param mode Where should the textbox be drawn? "left", "center" or "right"
function textbox:set_align(mode) function textbox:set_align(mode)
local allowed = { left = "LEFT", center = "CENTER", right = "RIGHT" } local allowed = { left = "LEFT", center = "CENTER", right = "RIGHT" }
if allowed[mode] then if allowed[mode] then
if self._layout:get_alignment() == allowed[mode] then if self._private.layout:get_alignment() == allowed[mode] then
return return
end end
self._layout:set_alignment(allowed[mode]) self._private.layout:set_alignment(allowed[mode])
self:emit_signal("widget::redraw_needed") self:emit_signal("widget::redraw_needed")
self:emit_signal("widget::layout_changed") self:emit_signal("widget::layout_changed")
end end
end end
--- Set a textbox' font --- Set a textbox' font
-- @property font
-- @param font The font description as string -- @param font The font description as string
function textbox:set_font(font) function textbox:set_font(font)
self._layout:set_font_description(beautiful.get_font(font)) self._private.layout:set_font_description(beautiful.get_font(font))
self:emit_signal("widget::redraw_needed") self:emit_signal("widget::redraw_needed")
self:emit_signal("widget::layout_changed") self:emit_signal("widget::layout_changed")
end end
-- Returns a new textbox --- Create a new textbox.
-- @tparam[opt=""] string text The textbox content
-- @tparam[opt=false] boolean ignore_markup Ignore the pango/HTML markup
-- @treturn table A new textbox widget
-- @function wibox.widget.textbox
local function new(text, ignore_markup) local function new(text, ignore_markup)
local ret = base.make_widget() local ret = base.make_widget(nil, nil, {enable_properties = true})
for k, v in pairs(textbox) do util.table.crush(ret, textbox, true)
if type(v) == "function" then
ret[k] = v
end
end
ret._dpi = -1 ret._private.dpi = -1
ret._ctx = PangoCairo.font_map_get_default():create_context() ret._private.ctx = PangoCairo.font_map_get_default():create_context()
ret._layout = Pango.Layout.new(ret._ctx) ret._private.layout = Pango.Layout.new(ret._private.ctx)
ret:set_ellipsize("end") ret:set_ellipsize("end")
ret:set_wrap("word_char") ret:set_wrap("word_char")
@ -263,6 +291,10 @@ function textbox.mt.__call(_, ...)
return new(...) return new(...)
end end
--@DOC_widget_COMMON@
--@DOC_object_COMMON@
return setmetatable(textbox, textbox.mt) return setmetatable(textbox, textbox.mt)
-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80 -- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80

View File

@ -0,0 +1,57 @@
---------------------------------------------------------------------------
--- Text clock widget.
--
-- @author Julien Danjou &lt;julien@danjou.info&gt;
-- @copyright 2009 Julien Danjou
-- @release @AWESOME_VERSION@
-- @classmod wibox.widget.textclock
---------------------------------------------------------------------------
local setmetatable = setmetatable
local os = os
local textbox = require("wibox.widget.textbox")
local timer = require("gears.timer")
local DateTime = require("lgi").GLib.DateTime
local textclock = { mt = {} }
--- This lowers the timeout so that it occurs "correctly". For example, a timeout
-- of 60 is rounded so that it occurs the next time the clock reads ":00 seconds".
local function calc_timeout(real_timeout)
return real_timeout - os.time() % real_timeout
end
--- Create a textclock widget. It draws the time it is in a textbox.
--
-- @tparam[opt=" %a %b %d, %H:%M "] string format The time format.
-- @tparam[opt=60] number timeout How often update the time (in seconds).
-- @treturn table A textbox widget.
-- @function wibox.widget.textclock
function textclock.new(format, timeout)
format = format or " %a %b %d, %H:%M "
timeout = timeout or 60
local w = textbox()
local t
function w._private.textclock_update_cb()
w:set_markup(DateTime.new_now_local():format(format))
t.timeout = calc_timeout(timeout)
t:again()
return true -- Continue the timer
end
t = timer.weak_start_new(timeout, w._private.textclock_update_cb)
t:emit_signal("timeout")
return w
end
function textclock.mt:__call(...)
return textclock.new(...)
end
--@DOC_widget_COMMON@
--@DOC_object_COMMON@
return setmetatable(textclock, textclock.mt)
-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80

View File

@ -82,17 +82,18 @@ assert:register("assertion", "widget_layout", widget_layout, "assertion.widget_l
return { return {
widget_stub = function(width, height) widget_stub = function(width, height)
local w = object() local w = object()
w._private = {}
w:add_signal("widget::redraw_needed") w:add_signal("widget::redraw_needed")
w:add_signal("widget::layout_changed") w:add_signal("widget::layout_changed")
w.is_widget = true w.is_widget = true
w.visible = true w._private.visible = true
w.opacity = 1 w._private.opacity = 1
if width or height then if width or height then
w.fit = function() w.fit = function()
return width or 10, height or 10 return width or 10, height or 10
end end
end end
w._widget_caches = {} w._private.widget_caches = {}
return w return w
end, end,

View File

@ -13,7 +13,7 @@ return { create_wibox = function()
-- Widgets that are aligned to the right -- Widgets that are aligned to the right
local right_layout = wibox.layout.fixed.horizontal() local right_layout = wibox.layout.fixed.horizontal()
local textclock = awful.widget.textclock() local textclock = wibox.widget.textclock()
right_layout:add(textclock) right_layout:add(textclock)
right_layout:add(awful.widget.layoutbox(1)) right_layout:add(awful.widget.layoutbox(1))

View File

@ -144,11 +144,16 @@ function(run_test test_path namespace template escaped_content)
get_filename_component(${test_path} TEST_FILE_NAME NAME) get_filename_component(${test_path} TEST_FILE_NAME NAME)
set(IMAGE_PATH "${IMAGE_DIR}/AUTOGEN${namespace}_${TEST_FILE_NAME}") set(IMAGE_PATH "${IMAGE_DIR}/AUTOGEN${namespace}_${TEST_FILE_NAME}")
# Use the example testing as coverage source
if (USE_LCOV)
set(LCOV_PATH ${SOURCE_DIR}/.luacov)
endif()
# Execute the script, leave the image extension decision to the test # Execute the script, leave the image extension decision to the test
# SVG is preferred, but PNG is better suited for some tests, like bitmap # SVG is preferred, but PNG is better suited for some tests, like bitmap
# patterns. # patterns.
execute_process( execute_process(
COMMAND lua ${template} ${test_path} ${IMAGE_PATH} ${SOURCE_DIR}/.luacov COMMAND lua ${template} ${test_path} ${IMAGE_PATH} ${LCOV_PATH}
OUTPUT_VARIABLE TEST_OUTPUT OUTPUT_VARIABLE TEST_OUTPUT
ERROR_VARIABLE TEST_ERROR ERROR_VARIABLE TEST_ERROR
) )

View File

@ -30,7 +30,7 @@ local function show(cr, skip_fill)
cr:clip() cr:clip()
end end
local cr = get_surface(svgpath) local cr = get_surface(svgpath..".svg")
cr:translate(3,3) cr:translate(3,3)
loadfile(filepath)(shape, cr, show) loadfile(filepath)(shape, cr, show)

View File

@ -1,5 +1,29 @@
local lgi = require("lgi") local lgi = require("lgi")
local Pango = lgi.Pango local Pango = lgi.Pango
local cairo = lgi.cairo
-- A simple Awesome logo
local function logo()
local img = cairo.ImageSurface.create(cairo.Format.ARGB32, 22, 22)
local cr = cairo.Context(img)
-- Awesome default #555555
cr:set_source_rgb(0.21568627451, 0.21568627451, 0.21568627451)
cr:paint()
cr:set_source_rgb(1,1,1)
cr:rectangle(0, 7, 15, 1)
cr:fill()
cr:rectangle(15, 15, 1, 7)
cr:fill()
cr:rectangle(8, 15, 7, 1)
cr:fill()
return img
end
-- Default theme for the documentation examples -- Default theme for the documentation examples
local module = { local module = {
@ -10,9 +34,17 @@ local module = {
border_width = 1.5 , border_width = 1.5 ,
-- Fake resources handling -- Fake resources handling
xresources = require("beautiful.xresources") xresources = require("beautiful.xresources"),
awesome_icon = logo()
} }
module.graph_bg = module.bg_normal
module.graph_fg = module.bg_highlight
module.progressbar_bg = module.bg_normal
module.progressbar_fg = module.bg_highlight
local f = Pango.FontDescription.from_string("sans 8") local f = Pango.FontDescription.from_string("sans 8")
function module.get_font() function module.get_font()

View File

@ -10,17 +10,17 @@ parent : setup {
{ {
text_widget, text_widget,
bg = '#ff0000', bg = '#ff0000',
widget = wibox.widget.background widget = wibox.container.background
}, },
{ {
text_widget, text_widget,
bg = '#00ff00', bg = '#00ff00',
widget = wibox.widget.background widget = wibox.container.background
}, },
{ {
text_widget, text_widget,
bg = '#0000ff', bg = '#0000ff',
widget = wibox.widget.background widget = wibox.container.background
}, },
spacing = 10, spacing = 10,
layout = wibox.layout.fixed.vertical layout = wibox.layout.fixed.vertical

View File

@ -13,7 +13,7 @@ parent : setup {
shape = gears.shape.circle, shape = gears.shape.circle,
bg = beautiful.bg_normal, bg = beautiful.bg_normal,
shape_border_color = beautiful.border_color, shape_border_color = beautiful.border_color,
widget = wibox.widget.background widget = wibox.container.background
}, },
{ {
-- To solve this, clip the content -- To solve this, clip the content
@ -25,7 +25,7 @@ parent : setup {
shape = gears.shape.circle, shape = gears.shape.circle,
bg = beautiful.bg_normal, bg = beautiful.bg_normal,
shape_border_color = beautiful.border_color, shape_border_color = beautiful.border_color,
widget = wibox.widget.background widget = wibox.container.background
}, },
spacing = 10, spacing = 10,
layout = wibox.layout.fixed.vertical layout = wibox.layout.fixed.vertical

View File

@ -10,17 +10,17 @@ parent : setup {
{ {
text_widget, text_widget,
fg = '#ff0000', fg = '#ff0000',
widget = wibox.widget.background widget = wibox.container.background
}, },
{ {
text_widget, text_widget,
fg = '#00ff00', fg = '#00ff00',
widget = wibox.widget.background widget = wibox.container.background
}, },
{ {
text_widget, text_widget,
fg = '#0000ff', fg = '#0000ff',
widget = wibox.widget.background widget = wibox.container.background
}, },
spacing = 10, spacing = 10,
layout = wibox.layout.fixed.vertical layout = wibox.layout.fixed.vertical

View File

@ -14,7 +14,7 @@ parent : setup {
bg = beautiful.bg_normal, bg = beautiful.bg_normal,
shape_border_color = beautiful.border_color, shape_border_color = beautiful.border_color,
shape_border_width = beautiful.border_width, shape_border_width = beautiful.border_width,
widget = wibox.widget.background widget = wibox.container.background
}, },
{ {
-- To solve this, use a margin -- To solve this, use a margin
@ -27,13 +27,13 @@ parent : setup {
right = 10, right = 10,
top = 3, top = 3,
bottom = 3, bottom = 3,
widget = wibox.layout.margin widget = wibox.container.margin
}, },
shape = gears.shape.hexagon, shape = gears.shape.hexagon,
bg = beautiful.bg_normal, bg = beautiful.bg_normal,
shape_border_color = beautiful.border_color, shape_border_color = beautiful.border_color,
shape_border_width = beautiful.border_width, shape_border_width = beautiful.border_width,
widget = wibox.widget.background widget = wibox.container.background
}, },
spacing = 10, spacing = 10,
layout = wibox.layout.fixed.vertical layout = wibox.layout.fixed.vertical

View File

@ -0,0 +1,24 @@
--DOC_HIDE_ALL
local wibox = require("wibox")
local gears = {shape = require("gears.shape")}
local beautiful = require("beautiful")
return {
text = "Before",
align = "center",
valign = "center",
widget = wibox.widget.textbox,
},
{
{
text = "After",
align = "center",
valign = "center",
widget = wibox.widget.textbox,
},
shape = gears.shape.circle,
shape_border_width = 5,
shape_border_color = "#ff0000",
bg = beautiful.bg_highlight,
widget = wibox.container.background
}

View File

@ -0,0 +1,27 @@
--DOC_HIDE_ALL
local wibox = require("wibox")
return {
text = "Some long text",
align = "center",
valign = "center",
widget = wibox.widget.textbox,
},
{
{
{
{
text = "Some long text",
align = "center",
valign = "center",
widget = wibox.widget.textbox,
},
strategy = "max",
height = 8,
width = 50,
widget = wibox.container.constraint
},
layout = wibox.layout.fixed.horizontal,
},
layout = wibox.layout.fixed.vertical,
}

View File

@ -0,0 +1,54 @@
--DOC_HIDE_ALL
local wibox = require("wibox")
local beautiful = require("beautiful")
return {
nil,
{
nil,
{
{
text = "Before",
align = "center",
valign = "center",
widget = wibox.widget.textbox,
},
bg = beautiful.bg_highlight,
widget = wibox.container.background
},
nil,
expand = "none",
layout = wibox.layout.align.horizontal,
},
nil,
expand = "none",
layout = wibox.layout.align.vertical,
},
{
nil,
{
nil,
{
{
{
text = "After",
align = "center",
valign = "center",
widget = wibox.widget.textbox,
},
bg = beautiful.bg_highlight,
widget = wibox.container.background
},
top = 5,
left = 20,
color = "#ff0000",
widget = wibox.container.margin,
},
nil,
expand = "none",
layout = wibox.layout.align.horizontal,
},
nil,
expand = "none",
layout = wibox.layout.align.vertical,
}

View File

@ -0,0 +1,19 @@
--DOC_HIDE_ALL
local wibox = require("wibox")
return {
text = "Before",
align = "center",
valign = "center",
widget = wibox.widget.textbox,
},
{
{
text = "After",
align = "center",
valign = "center",
widget = wibox.widget.textbox,
},
reflection = {horizontal = true},
widget = wibox.container.mirror
}

View File

@ -0,0 +1,19 @@
--DOC_HIDE_ALL
local wibox = require("wibox")
return {
text = "Before",
align = "center",
valign = "center",
widget = wibox.widget.textbox,
},
{
{
text = "After",
align = "center",
valign = "center",
widget = wibox.widget.textbox,
},
direction = "east",
widget = wibox.container.rotate
}

View File

@ -0,0 +1,92 @@
local file_path, image_path, luacovpath = ...
-- Set the global shims
-- luacheck: globals awesome client tag drawin screen
awesome = require( "awesome" )
client = require( "client" )
tag = require( "tag" )
drawin = require( "drawin" )
screen = require( "screen" )
-- Force luacheck to be silent about setting those as unused globals
assert(awesome and client and tag)
local beautiful = require( "beautiful" )
local wibox = require( "wibox" )
local surface = require( "gears.surface" )
local shape = require( "gears.shape" )
-- If luacov is available, use it. Else, do nothing.
pcall(function()
require("luacov.runner")(luacovpath)
end)
-- Let the test request a size and file format
local before, after = loadfile(file_path)()
local container = wibox.widget {
{
{
{
before,
shape_border_color = beautiful.border_color,
shape_border_width = beautiful.border_width,
shape = shape.rounded_rect,
widget = wibox.container.background,
},
strategy = 'exact',
width = 70,
height = 40,
widget = wibox.container.constraint
},
{
{
{
text = " ",
widget = wibox.widget.textbox,
},
bg = beautiful.bg_normal,
shape_border_color = beautiful.border_color,
shape_border_width = beautiful.border_width,
widget = wibox.container.background,
shape = shape.transform(shape.arrow)
: rotate_at(15,15,math.pi/2)
: translate(0,-8)
: scale(0.9, 0.9),
},
strategy = 'exact',
width = 42,
height = 40,
widget = wibox.container.constraint
},
{
{
after,
shape_border_color = beautiful.border_color,
shape_border_width = beautiful.border_width,
shape = shape.rounded_rect,
widget = wibox.container.background,
},
strategy = 'exact',
width = 70,
height = 40,
widget = wibox.container.constraint
},
layout = wibox.layout.align.horizontal
},
margins = 10,
widget = wibox.container.margin,
}
-- Emulate the event loop for 10 iterations
for _ = 1, 10 do
awesome:emit_signal("refresh")
end
-- Get the example fallback size (the tests can return a size if the want)
local f_w, f_h = container:fit({dpi=96}, 9999, 9999)
-- Save to the output file
local img = surface.widget_to_svg(container, image_path..".svg", f_w, f_h)
img:finish()

View File

@ -0,0 +1,66 @@
local parent = ... --DOC_HIDE
local wibox = require("wibox") --DOC_HIDE
local gears = {shape = require("gears.shape")} --DOC_HIDE
local beautiful = require("beautiful") --DOC_HIDE
local function create_arrow(text) --DOC_HIDE
return { --DOC_HIDE
{ --DOC_HIDE
{ --DOC_HIDE
text = text, --DOC_HIDE
align = "center", --DOC_HIDE
valign = "center", --DOC_HIDE
widget = wibox.widget.textbox, --DOC_HIDE
}, --DOC_HIDE
shape = gears.shape.arrow, --DOC_HIDE
bg = beautiful.bg_normal, --DOC_HIDE
shape_border_color = beautiful.border_color, --DOC_HIDE
shape_border_width = beautiful.border_width, --DOC_HIDE
widget = wibox.container.background --DOC_HIDE
}, --DOC_HIDE
strategy = 'exact', --DOC_HIDE
width = 70, --DOC_HIDE
height = 70, --DOC_HIDE
widget = wibox.container.constraint --DOC_HIDE
} --DOC_HIDE
end --DOC_HIDE
local normal = create_arrow("Normal")
local north = wibox.container {
create_arrow("North"),
direction = "north",
widget = wibox.container.rotate
}
local south = wibox.container {
create_arrow("South"),
direction = "south",
widget = wibox.container.rotate
}
local east = wibox.container {
create_arrow("East"),
direction = "east",
widget = wibox.container.rotate
}
local west = wibox.container {
create_arrow("West"),
direction = "west",
widget = wibox.container.rotate
}
parent : setup { --DOC_HIDE
normal, --DOC_HIDE
north, --DOC_HIDE
south, --DOC_HIDE
east, --DOC_HIDE
west, --DOC_HIDE
spacing = 10, --DOC_HIDE
layout = wibox.layout.fixed.horizontal --DOC_HIDE
} --DOC_HIDE

View File

@ -0,0 +1,10 @@
local generic_widget = ... --DOC_HIDE
local wibox = require("wibox") --DOC_HIDE
return --DOC_HIDE
wibox.widget {
generic_widget( "first" ),
generic_widget( "second" ),
generic_widget( "third" ),
layout = wibox.layout.align.horizontal
}

View File

@ -0,0 +1,10 @@
local generic_widget = ... --DOC_HIDE
local wibox = require("wibox") --DOC_HIDE
return --DOC_HIDE
wibox.widget {
generic_widget( "first" ),
generic_widget( "second" ),
generic_widget( "third" ),
layout = wibox.layout.fixed.horizontal
}

View File

@ -0,0 +1,10 @@
local generic_widget = ... --DOC_HIDE
local wibox = require("wibox") --DOC_HIDE
return --DOC_HIDE
wibox.widget {
generic_widget( "first" ),
generic_widget( "second" ),
generic_widget( "third" ),
layout = wibox.layout.flex.horizontal
}

View File

@ -0,0 +1,13 @@
local generic_widget = ... --DOC_HIDE
local wibox = require("wibox") --DOC_HIDE
local w = wibox.widget {
generic_widget( "first" ),
generic_widget( "second" ),
generic_widget( "third" ),
layout = wibox.layout.ratio.horizontal
}
w:ajust_ratio(2, 0.44, 0.33, 0.22)
return w --DOC_HIDE

View File

@ -0,0 +1,10 @@
local generic_widget = ... --DOC_HIDE
local wibox = require("wibox") --DOC_HIDE
return --DOC_HIDE
wibox.widget {
generic_widget( "first" ),
generic_widget( "second" ),
generic_widget( "third" ),
layout = wibox.layout.stack
}

View File

@ -0,0 +1,62 @@
local file_path, image_path, luacovpath = ...
-- Set the global shims
-- luacheck: globals awesome client tag drawin screen
awesome = require( "awesome" )
client = require( "client" )
tag = require( "tag" )
drawin = require( "drawin" )
screen = require( "screen" )
-- Force luacheck to be silent about setting those as unused globals
assert(awesome and client and tag)
local wibox = require( "wibox" )
local surface = require( "gears.surface" )
local color = require( "gears.color" )
local beautiful = require( "beautiful" )
-- If luacov is available, use it. Else, do nothing.
pcall(function()
require("luacov.runner")(luacovpath)
end)
-- Create a generic rectangle widget to show layout disposition
local function generic_widget(text)
return {
{
{
draw = function(_, _, cr, width, height)
cr:set_source(color(beautiful.bg_normal))
cr:set_line_width(3)
cr:rectangle(0, 0, width, height)
cr:fill_preserve()
cr:set_source(color(beautiful.border_color))
cr:stroke()
end,
widget = wibox.widget.base.make_widget
},
text and {
align = "center",
valign = "center",
text = text,
widget = wibox.widget.textbox
} or nil,
widget = wibox.layout.stack
},
margins = 5,
widget = wibox.container.margin,
}
end
-- Let the test request a size and file format
local widget, w, h = loadfile(file_path)(generic_widget)
-- Emulate the event loop for 10 iterations
for _ = 1, 10 do
awesome:emit_signal("refresh")
end
-- Save to the output file
local img = surface["widget_to_svg"](widget, image_path..".svg", w or 200, h or 30)
img:finish()

View File

@ -0,0 +1,22 @@
local parent = ... --DOC_HIDE
local wibox = require("wibox") --DOC_HIDE
local data = { --DOC_HIDE
3, 5, 6,4, 11,15,19,29,17,17,14,0,0,3,1,0,0, 22, 17,7, 1,0,0,5, --DOC_HIDE
3, 5, 6,4, 11,15,19,29,17,17,14,0,0,3,1,0,0, 22, 17,7, 1,0,0,5, --DOC_HIDE
3, 5, 6,4, 11,15,19,29,17,17,14,0,0,3,1,0,0, 22, 17,7, 1,0,0,5, --DOC_HIDE
3, 5, 6,4, 11,15,19,29,17,17,14,0,0,3,1,0,0, 22, 17,7, 1,0,0,5, --DOC_HIDE
3, 5, 6,4, 11,15,19,29,17,17,14,0,0,3,1,0,0, 22, 17,7, 1,0,0,5, --DOC_HIDE
} --DOC_HIDE
local w = --DOC_HIDE
wibox.widget {
max_value = 29,
widget = wibox.widget.graph
}
parent:add( w ) --DOC_HIDE
for _, v in ipairs(data) do --DOC_HIDE
w:add_value(v) --DOC_HIDE
end --DOC_HIDE

View File

@ -0,0 +1,13 @@
local parent = ... --DOC_HIDE
local wibox = require( "wibox" ) --DOC_HIDE
local beautiful = require( "beautiful" ) --DOC_HIDE
parent:add( --DOC_HIDE
wibox.widget {
image = beautiful.awesome_icon,
resize = false,
widget = wibox.widget.imagebox
}
) --DOC_HIDE

View File

@ -0,0 +1,12 @@
local parent = ... --DOC_HIDE
local wibox = require("wibox") --DOC_HIDE
parent:add( --DOC_HIDE
wibox.widget {
max_value = 1,
value = 0.33,
widget = wibox.widget.progressbar
}
) --DOC_HIDE

View File

@ -0,0 +1,13 @@
local parent = ... --DOC_HIDE
local wibox = require("wibox") --DOC_HIDE
parent:add( --DOC_HIDE
wibox.widget{
markup = "This <i>is</i> a <b>textbox</b>!!!",
align = "center",
valign = "center",
widget = wibox.widget.textbox
}
) --DOC_HIDE

View File

@ -30,14 +30,14 @@ table.insert(steps, function()
widget = wibox.widget.textbox, widget = wibox.widget.textbox,
}, },
bg = "#ff0000", bg = "#ff0000",
widget = wibox.widget.background widget = wibox.container.background
}, },
{ {
{ {
widget = button, widget = button,
}, },
bg = "#ff00ff", bg = "#ff00ff",
widget = wibox.widget.background widget = wibox.container.background
}, },
{ {
{ {
@ -45,14 +45,14 @@ table.insert(steps, function()
widget = wibox.widget.textbox, widget = wibox.widget.textbox,
}, },
bg = "#0000ff", bg = "#0000ff",
widget = wibox.widget.background widget = wibox.container.background
}, },
layout = wibox.layout.flex.vertical layout = wibox.layout.flex.vertical
} }
awful.placement.centered(w) awful.placement.centered(w)
img = button._image img = button._private.image
assert(img) assert(img)
return true return true
@ -68,7 +68,7 @@ table.insert(steps, function()
end) end)
table.insert(steps, function() table.insert(steps, function()
assert(button._image ~= img) assert(button._private.image ~= img)
return true return true
end) end)
@ -77,14 +77,14 @@ end)
table.insert(steps, function() table.insert(steps, function()
root.fake_input("button_release", 1) root.fake_input("button_release", 1)
assert(button._image ~= img) assert(button._private.image ~= img)
return true return true
end) end)
-- Test a button press/release outside of the widget -- Test a button press/release outside of the widget
table.insert(steps, function() table.insert(steps, function()
assert(button._image == img) assert(button._private.image == img)
root.fake_input("button_press", 1) root.fake_input("button_press", 1)
@ -92,14 +92,14 @@ table.insert(steps, function()
end) end)
table.insert(steps, function() table.insert(steps, function()
assert(button._image ~= img) assert(button._private.image ~= img)
return true return true
end) end)
table.insert(steps, function() table.insert(steps, function()
-- just make sure the button is not released for nothing -- just make sure the button is not released for nothing
assert(button._image ~= img) assert(button._private.image ~= img)
-- test if the button is released when the mouse move out -- test if the button is released when the mouse move out
awful.placement.right(mouse--[[, {parent = w}]]) awful.placement.right(mouse--[[, {parent = w}]])
@ -109,7 +109,7 @@ table.insert(steps, function()
end) end)
table.insert(steps, function() table.insert(steps, function()
assert(button._image == img) assert(button._private.image == img)
return true return true
end) end)

View File

@ -63,7 +63,7 @@ collectable(wibox.layout.align.horizontal())
-- Then some random widgets from awful -- Then some random widgets from awful
collectable(awful.widget.launcher({ image = cairo.ImageSurface(cairo.Format.ARGB32, 20, 20), command = "bash" })) collectable(awful.widget.launcher({ image = cairo.ImageSurface(cairo.Format.ARGB32, 20, 20), command = "bash" }))
collectable(awful.widget.prompt()) collectable(awful.widget.prompt())
collectable(awful.widget.textclock()) collectable(wibox.widget.textclock())
collectable(awful.widget.layoutbox(1)) collectable(awful.widget.layoutbox(1))
-- Some widgets do things via timer.delayed_call -- Some widgets do things via timer.delayed_call