Home

Awesome

Radical menu system for AwesomeWM

=======================================

Warning If you use Awesome git master, please use the awesome3.6 branch

This is Radical, one of the largest Awesome extension module. It provide un unified interface to generate multiple types of menus.

Too many menus

News

December 2016

This module master branch is now for Awesome 4.0+. If you use Awesome 3.5, please use the awesome3.5 branch.

Installation

Installing Radical is simple, just move to ~/.config/awesome and clone the repository

cd ~/.config/awesome
git clone https://github.com/Elv13/radical.git

The require it at the top of your rc.lua:

    local radical = require("radical")

Usage

Unlike awful.menu, radical act like other Awesome 3.5 layouts. You need to add items one by one. This have the benefit of letting you interact with the items themselves programatically.

The most simple kind of menus, contexts one, can be created like this:

    local menu = radical.context{}
    menu:add_item {text="Screen 1",button1=function(_menu,item,mods) print("Hello World! ") end}
    menu:add_item {text="Screen 9",icon= beautiful.awesome_icon}
    menu:add_item {text="Sub Menu",sub_menu = function()
        local smenu = radical.context{}
        smenu:add_item{text="item 1"}
        smenu:add_item{text="item 2"}
        return smenu
    end}
    
    -- To add the menu to a widget:
    local mytextbox = wibox.widget.textbox()
    mytextbox:set_menu(menu, "button::pressed", 3) -- 3 = right mouse button, 1 = left mouse button
    
    -- To add a key binding on a "box" menu (and every other types)
    menu:add_key_binding({"Mod4"},",")

In this example, a simple 3 item menu is created with a dynamically generated submenu. Please note that generating submenus using function will generate it every time it is being shown. For static menus, it is faster to simply create them once and passing the submenu object to the "sub_menu" item property.

:set_menu can also take a lazy-loading function instead of a menu. The second and third parameters are not mandatory, the defaults are "button::pressed" and 1, respectively.

:add_key_binding will add a key binding. It can also take a function as 3rd parameter. However, it wont correctly place "context" menu as it have no idea where you expect them. It work better with "box" menus.

Menu types

The current valid types are:

Menu style

Each menus come in various styles for various applications. New style can also be created by beautiful themes. The current ones are:

Arrow also have a few types:

Note that both menu and items have a margins property to ajust details:

    my_menu.margins.left = 12
    local item = my_menu:add_item {test="Need room"}
    item.margins.top = 3

Item style

Like menus, items can have their own style. Valid values:

Menu layouts

On top of each styles, menu can also have different layouts to display items:

Item layout

Item layouts are how widgets (icons, label, prefix) are disposed in the item

Using styles and layouts

    local radical = require("radical")
    
    local m = radical.context {
        style      = radical.style.classic      ,
        item_style = radical.item.style.classic ,
        layout     = radical.layout.vertical    }
    

Tooltip

Radical also have its own styled tooltip widget. It can be used in menus, but also in every widgets using the set_tooltip method:


local mytextbox = wibox.widget.textbox()
mytextbox:set_tooltip("foo bar")

Options

Radical offer a (very, very) wide range of options to allow the creation of rich and novel menus. The options are available in 2 formats: menu wide and item specific. Menu wide options will take effect on all items and on the way the menu itself is being displayed while items ones apply only to a specific item. Multiple items can have multiple sets of options.

Menu options

NameDescriptionType
bg_headerHeader (see widgets section) colorString/gradient/pattern
bg_prefixPrefix background for item_styles that support itString/gradient/pattern
border_colorBorder colorString/gradient/pattern
item_border_colorAlternative border color for item separationString/gradient/pattern
border_widthBorder widthnumber
item_heightDefault height of itemsnumber
item_widthDefault width of itemsnumber
widthOriginal widthnumber
default_widthDefault menu widthnumber
icon_sizeIcon sizenumber
auto_resizeResize menu if items are too largeboolean
parent_geometrySet the menu parentgeometry array
arrow_typeSet the arrow type when use arrow stylesee "arrow_type" enum
visibleShow or hide the menuboolean
directionThe direction from which the arrow will point"left","right","top","bottom"
rowNumber of row (in grid layout)number
columnNumber of columns (in grid layout)number
layoutThe menu layout (default:vertical)see "Menu layouts" section
styleThe menu style (default:arrow)see "Menu style"
item_styleThe item style (default:basic)see "Item style"
filterFilter the menu when the user typeboolean
show_filterShow a filter widget at the bottomboolean
filter_stringDefault filter stringstring
fkeys_prefixDisplay F1-F12 indicators for easy navigationboolean
filter_prefixText to be shown at begenning of the filter stringstring
max_itemsMaximum number of items before showing scrollbarnumber
enable_keyboardEnable or disable keyboard navigation / hooksboolean
disable_markupDisable pango markup in items textboolean
xX position (absolute)number
yY position (absolute)number
sub_menu_onShow submenu on selection or when clickingsee "event" enum
select_onThe event used to trigger item selectionsee "event" enum
overlayA layer on top of the itemfunction(data,item,cr,w,h)
opacityMake this menu translucent (require a compositor)number (0 to 1)
icon_transformationHijack the icon drawing functionfunction(icon,data,item)
icon_per_stateCall icon_transformation when state changeboolean
disable_submenu_iconDo not show the submenu icon (arrow)boolean
marginsRead/Write table (left,right,top and bottom)dynamic table
visible_row_countNumber of visible items -(#max-(#total-#filtered))number
default_item_marginsDefault margins for items ({left=1,right=1...})array of direction
default_marginsDefault margins for the menu ({left=1,right=1...})array of direction

Item options

NameDescriptionType
textThe item textstring
heightThe item heightnumber
iconThe item iconstring or pattern
sub_menuAdd a submenu to this itemmenu or function
selectedSelect this itemboolean
checkableIs the item dual state (a checkbox)boolean
checkedIs the item checked or notboolean
prefix_widgetWidget to append at the begenning of the itemwidget
suffix_widgetWidget to append at the end of the itemwidget
styleCustom item_style for this itemitem_style
layoutCustom item_layout for this itemitem_layout
tooltipA tooltip shown on the side or bottomstring
button1Left mouse button actionfunction
button2Mid mouse button actionfunction
button3Right mouse button actionfunction
button4Scroll up actionfunction
button5Scroll down actionfunction
overlaySee menu.overlayfunction
marginsRead/Write table (left,right,top and bottom)dynamic table
infoshapesSee the infoshapes widget documentationarray of infoshapes
overlay_drawDraw a custom painter on top of the itemdraw function
fontSet a custom fontfont_string

Colors options

The colors option are available for both menus and items objects.

NameStateDescription
bg---Default background
fg---Default foreground
bg_disabledtheme.state.DISABLEDThe item cannot be interracted with
fg_disabledtheme.state.DISABLEDThe item cannot be interracted with
bg_urgenttheme.state.URGENTThe item request immediate attention
fg_urgenttheme.state.URGENTThe item request immediate attention
bg_focustheme.state.SELECTEDFocussed / Selected items
fg_focustheme.state.SELECTEDFocussed / Selected items
bg_pressedtheme.state.PRESSEDThe item is being pressed
fg_pressedtheme.state.PRESSEDThe item is being pressed
bg_hovertheme.state.HOVEREDThe mouse is over the item
fg_hovertheme.state.HOVEREDThe mouse is over the item
bg_changedtheme.state.CHANGEDThe item recently changed
fg_changedtheme.state.CHANGEDThe item recently changed
bg_usedtheme.state.USEDThe item is used
fg_usedtheme.state.USEDThe item is used
bg_checkedtheme.state.CHECKEDThe item is checked
fg_checkedtheme.state.CHECKEDThe item is checked
bg_alternatetheme.state.ALTERNATEAlternative to bg
fg_alternatetheme.state.ALTERNATEAlternative to fg
bg_highlighttheme.state.HIGHLIGHTThe item is hightlighted
fg_highlighttheme.state.HIGHLIGHTThe item is hightlighted

Common methods

All menus provide a bunch of methods. Most of them have been coverred above, but here is the list:

NameDescriptionArgumentsReturn
add_itemAdd new item to a menuarray of optionsitem
add_itemsAdd new items to a menuarray of items arraysarray
add_widgetAdd a new widget instead of an itema widget, args---
add_widgetsAdd new widgetsarray of widgets---
add_embeded_menuAdd an inline menu to another menuan "embed" menu---
add_key_bindingAdd a global key binding to a menumod array, key---
add_key_hookAdd a callback when a key is pressedmod, key, event, func---
clearRemove all items------
scroll_downIf the menu is cropped, scroll down------
scroll_upIf the menu is cropped, scroll up------
hideHide a menu and all sub menus------
swapSwap 2 itemsboth items---
moveMove an itemthe item, the new idx---
removeRemove the itemthe item---
appendAppend an existing (but unused) itemthe item---
add_prefix_widgetAdd a widget at the beginning of the menuthe widget---
add_suffix_widgetAdd a widget at the end of the menuthe widget---
add_colors_namespaceUse prefixed colors from beautifulthe namespace name---
add_colors_groupAdd a new color group (see below for details)the group name---

Signals

Menu also emit many signals, the syntax is usually PROPERTY_NAME::changed. Some others are item::moved, item::swapped, item::removed, item::appended

Here is an example of how to catch an "opacity" change:

    mymenu:connect_signal("opacity::changed",function(value)
        -- Do something
    end)

Most item_layout also repackage the default widget signals. It usually does the same as using the buttonX menu attributes, but is preferrable in some scenarios like when a modifier is applied.

NameDescriptionArguments
button::pressA button pressmenu,item,button_id,mods,geo
button::releaseA button releasemenu,item,button_id,mods,geo
mouse::enterWhen the mouse entermenu,item
mouse::leaveWhen the mouse leavemenu,item
long::hoverThe mouse is hover 1.5 secmenu,item
long::pressThe mouse is pressed 1.5 secmenu,item

mods is an array with the applied modifier as key. If the value is nil, then the modifier is not present. Usual modifiers are Control, Shift, mod1 (Alt) and mod4.

An example of how to use them:

    local menubar = radical.bar{}
    menubar:connect_signal("button::press",function(data,item,button,mods)
        if mods.Control then
            print("Foo menu pressed!",item.text,button,data.rowcount)
        end
    end)
    
    -- Also work on items
    menubar:add_item{text="bar"}:connect_signal("button::release",function(d,i,b,m)
        print("bar click released!")
    end)

Beautiful options

Radical also use the some of the same theme options as awful.menu, plus some:

NameDescriptionType
menu_heightMenu heightString/Gradient/Pattern
menu_widthMenu default/minimum widthNumber
menu_border_widthBorder widthNumber
menu_border_colorBorder colorString/Gradient/Pattern
menu_fg_normalText/Foreground colorString/Gradient/Pattern
menu_bg_focusSelected item colorString/Gradient/Pattern
menu_bg_headerHeader widget background colorString/Gradient/Pattern
menu_bg_alternateScrollbar and other widget colorString/Gradient/Pattern
menu_bg_normalDefault backgroundString/Gradient/Pattern
menu_bg_highlightHighlighted item backgroundString/Gradient/Pattern
menu_submenu_iconSub menu pixmap (aka >)Path/Pattern
menu_separator_colorMenu separator colorString/Gradient/Pattern
menu_opacityUse your favorite compositorNumber (0=0%, 1=100%)
menu_draw_underlayFunction returning the underlay pixmapfunction(array,width)
menu_icon_transformationThe function used to draw the iconfunction(image,data,item)
menu_corner_radiusArrow based menu corner radiusNumber (default = 10)
dock_corner_radiusThe dock menu type corner radiusNumber (default 10)
menu_outline_colorArrow menu outer border colorString/Gradient/Pattern
menu_checkbox_styleThe style used for checkboxes"holo" or "default"

Styling can also be done using the icon_transformation option. This feature allow masks such as desaturation, tinting, invert or some matrix to be applied on the pixmap before it is being drawn. This function take the path/surface as only parameter and return the transformed surface.

Other elements can be added to items such as prefix and siffixes. Those elements sometime need extra color groups. The add_color_group method allow to register such new category.

Some generic menu can also register beautiful namespaces using the add_colors_namespace method. For example, the tasklist namespace can be used by adding elements such as beautiful.tasklist_bg_urgent to your theme.

Extending Radical

Radical is not designed to be used "as is". Every menus are different. While common ones can be created without extending Radical capabilities, more advanced one most likely will. Good news, this is what Radical have been designed for. The previous generations proved to me that any lack or native extensibility will cause the code to bloat when it come to adding a feature. Radical horizontal design allow to add more modules and properties without having to touch the "core" files.

Object model

The Radical object model is similar to the Awesome one. Each objects have a set of signals developers can listen to to have changes notification. The big difference is that Radical object model automatically generate the properties themselves. If one desire to add a new one, it is possible to listen to item::added to apply it on the item or apply it directly on the menu itself depending if the property is for the menu or for an item. Here is an example how it work:

    local menu = radical.context{}
    
    -- Create the setter
    menu.set_foo = function(m,value)
        print("Setting value to:",value)
        m._foo_real = value
    end
    
    -- Create the getter
    menu.get_foo = function(m)
        print("Getter called, returning",m._foo_real)
    end
    
    -- The property is now created, this will call the setter:
    menu.foo = "my foo value"
    
    -- This will call the getter:
    print(menu.foo)
    
    -- The signals will be automatically generated
    data:connect_signal("foo::changed",function(m,value)
        print("foo changed:",value)
    end)
    
    -- New signals don't need to be registered and can be called right away
    data:connect_signal("my_new_signal::action_name",function(m,value1,value2,value3)
        print("Callback",m,value1,value2,value3)
    end)
    
    -- Manually emiting a signal
    menu:emit_signal("my_new_signal::action_name",value1,value2,value3)
    

State model

Radical support multiple states per item at once. The "current state" is the one with the smallest ID. A state ID is an integer from -inf to inf. More important states, like urgent versus checked can be implemented by using an appropriate ordering. The default set of states is subject to changes, so it is wiser to use a completely different range if someone want to replace the currents one. Each states can be assigned a background and foreground color using the radical.theme.register_color(id, radical_name, beautiful_name, true ) method. Toggling a state can be done using the item.state[] meta table:

    local my_state_name = 9999 -- <== The ID
    local menu = radical.context{}
    local item = menu:add_item{text="text"}
    
    -- Activate a state
    item.state[my_state_name] = true
    
    -- Desactivate a state
    item.state[my_state_name] = nil
    

Radical will take care of choosing the current state and redraw the item with the right background and foreground colors.

Layout

TODO

Style

TODO

Item layout

TODO

Item style

TODO