{"id":13896508,"url":"https://github.com/Elv13/radical","last_synced_at":"2025-07-17T12:34:04.298Z","repository":{"id":65553476,"uuid":"10003842","full_name":"Elv13/radical","owner":"Elv13","description":"An extensible menu subsystem for Awesome WM","archived":false,"fork":false,"pushed_at":"2018-11-11T02:23:11.000Z","size":4594,"stargazers_count":222,"open_issues_count":27,"forks_count":16,"subscribers_count":16,"default_branch":"master","last_synced_at":"2024-11-22T02:11:12.283Z","etag":null,"topics":["awesomewm"],"latest_commit_sha":null,"homepage":null,"language":"Lua","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Elv13.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2013-05-11T18:57:00.000Z","updated_at":"2024-09-29T17:49:42.000Z","dependencies_parsed_at":"2023-01-29T03:31:08.186Z","dependency_job_id":null,"html_url":"https://github.com/Elv13/radical","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Elv13%2Fradical","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Elv13%2Fradical/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Elv13%2Fradical/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Elv13%2Fradical/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Elv13","download_url":"https://codeload.github.com/Elv13/radical/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":226265521,"owners_count":17597222,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["awesomewm"],"created_at":"2024-08-06T18:02:58.483Z","updated_at":"2024-11-25T02:30:47.020Z","avatar_url":"https://github.com/Elv13.png","language":"Lua","funding_links":[],"categories":["Lua","Theming","Configuration Related"],"sub_categories":["Widget Libraries"],"readme":"# Radical menu system for AwesomeWM\n=======================================\n\n**Warning** If you use Awesome git master, please use the awesome3.6 branch\n\nThis is Radical, one of the largest Awesome extension module. It provide un\nunified interface to generate multiple types of menus.\n\n[![Too many menus](https://raw.github.com/Elv13/radical/master/screenshot/all.png)](https://raw.github.com/Elv13/radical/master/screenshot/all.png)\n\n## News\n\n### December 2016\n\nThis module master branch is now for Awesome 4.0+. If you use Awesome 3.5,\nplease use the `awesome3.5` branch.\n\n## Installation\n\nInstalling Radical is simple, just move to ~/.config/awesome and clone the\nrepository\n\n```sh\ncd ~/.config/awesome\ngit clone https://github.com/Elv13/radical.git\n```\n\nThe require it at the top of your rc.lua:\n\n```lua\n    local radical = require(\"radical\")\n```\n\n## Usage\n\nUnlike awful.menu, radical act like other Awesome 3.5 layouts. You need to add\nitems one by one. This have the benefit of letting you interact with the items\nthemselves programatically.\n\nThe most simple kind of menus, contexts one, can be created like this:\n\n```lua\n    local menu = radical.context{}\n    menu:add_item {text=\"Screen 1\",button1=function(_menu,item,mods) print(\"Hello World! \") end}\n    menu:add_item {text=\"Screen 9\",icon= beautiful.awesome_icon}\n    menu:add_item {text=\"Sub Menu\",sub_menu = function()\n        local smenu = radical.context{}\n        smenu:add_item{text=\"item 1\"}\n        smenu:add_item{text=\"item 2\"}\n        return smenu\n    end}\n    \n    -- To add the menu to a widget:\n    local mytextbox = wibox.widget.textbox()\n    mytextbox:set_menu(menu, \"button::pressed\", 3) -- 3 = right mouse button, 1 = left mouse button\n    \n    -- To add a key binding on a \"box\" menu (and every other types)\n    menu:add_key_binding({\"Mod4\"},\",\")\n```\n\nIn this example, a simple 3 item menu is created with a dynamically generated\nsubmenu. Please note that generating submenus using function will generate it\nevery time it is being shown. For static menus, it is faster to simply create\nthem once and passing the submenu object to the \"sub_menu\" item property.\n\n`:set_menu` can also take a lazy-loading function instead of a\nmenu. The second and third parameters are not mandatory, the defaults are\n`\"button::pressed\"` and `1`, respectively.\n\n`:add_key_binding` will add a key binding. It can also take a function as 3rd\nparameter. However, it wont correctly place \"context\" menu as it have no idea\nwhere you expect them. It work better with \"box\" menus.\n\n### Menu types\n\nThe current valid types are:\n\n * **Context:** Regular context menu\n * **Box:** Centered menus (think Windows alt-tab menu)\n * **Embed:** Menus in menus. This can be used as subsections in large menus\n * **Bar:** A compact horizontal wibox widget\n * **Flexbar:** An extensible horizontal wibox widget\n * **Dock:** OS X like dock with auto hiding and rectangular items\n\n### Menu style\n\nEach menus come in various styles for various applications. New style can also\nbe created by beautiful themes. The current ones are:\n\n * **Arrow:** Gnome3 and Mac OSX like menus with border radius and an arrow\n * **Classic:** Replicate awful.menu look\n\nArrow also have a few types:\n\n * radical.base.arrow_type.NONE\n * radical.base.arrow_type.PRETTY\n * radical.base.arrow_type.CENTERED\n\nNote that both menu and items have a `margins` property to ajust details:\n\n```lua\n    my_menu.margins.left = 12\n    local item = my_menu:add_item {test=\"Need room\"}\n    item.margins.top = 3\n```\n\n### Item style\n\nLike menus, items can have their own style. Valid values:\n\n * **Basic:** The most simple kind of items, no borders or special shape\n * **Classic:** 1px border at the end of each items\n * **Rounded:** A 3px border radius at each corner\n * **Arrow_alt:** \"Powerline\" arrow with alternating colors\n * **Arrow_prefix:** The item prefix are \"Powerlined\"\n * **Arrow_single:** The item start with a `\u003c` and end with a `\u003e`\n\n### Menu layouts\n\nOn top of each styles, menu can also have different layouts to display items:\n\n* **Vertical:** Items are displayed on top of each other\n* **Horizontal:** Items are displayed alongside each other\n* **Grid:** Items are displayed as a 2D array\n\n### Item layout\n\nItem layouts are how widgets (icons, label, prefix) are disposed in the item\n\n* **horizontal:** Default layout used by the context style\n* **icon:** Look like a desktop icon, used by horizontal menus\n* **centerred:** Align widgets at the center instead of using all space\n\n### Using styles and layouts\n\n```lua\n    local radical = require(\"radical\")\n    \n    local m = radical.context {\n        style      = radical.style.classic      ,\n        item_style = radical.item.style.classic ,\n        layout     = radical.layout.vertical    }\n    \n```\n\n\n### Tooltip\n\nRadical also have its own styled tooltip widget. It can be used in menus, but\nalso in every widgets using the `set_tooltip` method:\n\n```lua\n\nlocal mytextbox = wibox.widget.textbox()\nmytextbox:set_tooltip(\"foo bar\")\n\n```\n\n## Options\n\nRadical offer a (very, very) wide range of options to allow the creation of rich\nand novel menus. The options are available in 2 formats: menu wide and item\nspecific. Menu wide options will take effect on all items and on the way the\nmenu itself is being displayed while items ones apply only to a specific item.\nMultiple items can have multiple sets of options.\n\n### Menu options\n\n|         Name        | Description                                        | Type                          |\n| ------------------- | -------------------------------------------------- | ----------------------------- |\n| bg_header           | Header (see widgets section) color                 | String/gradient/pattern       |\n| bg_prefix           | Prefix background for item_styles that support it  | String/gradient/pattern       |\n| border_color        | Border color                                       | String/gradient/pattern       |\n| item_border_color   | Alternative border color for item separation       | String/gradient/pattern       |\n| border_width        | Border width                                       | number                        |\n| item_height         | Default height of items                            | number                        |\n| item_width          | Default width of items                             | number                        |\n| width               | Original width                                     | number                        |\n| default_width       | Default menu width                                 | number                        |\n| icon_size           | Icon size                                          | number                        |\n| auto_resize         | Resize menu if items are too large                 | boolean                       |\n| parent_geometry     | Set the menu parent                                | geometry array                |\n| arrow_type          | Set the arrow type when use arrow style            | see \"arrow_type\" enum         |\n| visible             | Show or hide the menu                              | boolean                       |\n| direction           | The direction from which the arrow will point      | \"left\",\"right\",\"top\",\"bottom\" |\n| row                 | Number of row (in grid layout)                     | number                        |\n| column              | Number of columns (in grid layout)                 | number                        |\n| layout              | The menu layout (default:vertical)                 | see \"Menu layouts\" section    |\n| style               | The menu style (default:arrow)                     | see \"Menu style\"              |\n| item_style          | The item style (default:basic)                     | see \"Item style\"              |\n| filter              | Filter the menu when the user type                 | boolean                       |\n| show_filter         | Show a filter widget at the bottom                 | boolean                       |\n| filter_string       | Default filter string                              | string                        |\n| fkeys_prefix        | Display F1-F12 indicators for easy navigation      | boolean                       |\n| filter_prefix       | Text to be shown at begenning of the filter string | string                        |\n| max_items           | Maximum number of items before showing scrollbar   | number                        |\n| enable_keyboard     | Enable or disable keyboard navigation / hooks      | boolean                       |\n| disable_markup      | Disable pango markup in items text                 | boolean                       |\n| x                   | X position (absolute)                              | number                        |\n| y                   | Y position (absolute)                              | number                        |\n| sub_menu_on         | Show submenu on selection or when clicking         | see \"event\" enum              |\n| select_on           | The event used to trigger item selection           | see \"event\" enum              |\n| overlay             | A layer on top of the item                         | function(data,item,cr,w,h)    |\n| opacity             | Make this menu translucent (require a compositor)  | number (0 to 1)               |\n| icon_transformation | Hijack the icon drawing function                   | function(icon,data,item)      |\n| icon_per_state      | Call icon_transformation when state change         | boolean                       |\n| disable_submenu_icon| Do not show the submenu icon (arrow)               | boolean                       |\n| margins             | Read/Write table (left,right,top and bottom)       | dynamic table                 |\n| visible_row_count   | Number of visible items -(#max-(#total-#filtered)) | number                        |\n| default_item_margins| Default margins for items ({left=1,right=1...})    | array of direction            |\n| default_margins     | Default margins for the menu ({left=1,right=1...}) | array of direction            |\n\n### Item options\n\n|      Name      |                 Description                  |        Type        |\n| -------------- | -------------------------------------------- | ------------------ |\n| text           | The item text                                | string             |\n| height         | The item height                              | number             |\n| icon           | The item icon                                | string or pattern  |\n| sub_menu       | Add a submenu to this item                   | menu or function   |\n| selected       | Select this item                             | boolean            |\n| checkable      | Is the item dual state (a checkbox)          | boolean            |\n| checked        | Is the item checked or not                   | boolean            |\n| prefix_widget  | Widget to append at the begenning of the item| widget             |\n| suffix_widget  | Widget to append at the end of the item      | widget             |\n| style          | Custom item_style for this item              | item_style         |\n| layout         | Custom item_layout for this item             | item_layout        |\n| tooltip        | A tooltip shown on the side or bottom        | string             |\n| button1        | Left mouse button action                     | function           |\n| button2        | Mid mouse button action                      | function           |\n| button3        | Right mouse button action                    | function           |\n| button4        | Scroll up action                             | function           |\n| button5        | Scroll down action                           | function           |\n| overlay        | See menu.overlay                             | function           |\n| margins        | Read/Write table (left,right,top and bottom) | dynamic table      |\n| infoshapes     | See the infoshapes widget documentation      | array of infoshapes|\n| overlay_draw   | Draw a custom painter on top of the item     | draw function      |\n| font           | Set a custom font                            | font_string        |\n\n### Colors options\n\nThe colors option are available for both menus and items objects.\n\n|     Name     |          State        |                  Description                  |\n| ------------ | --------------------- | --------------------------------------------- |\n| bg           |          ---          | Default background                            |\n| fg           |          ---          | Default foreground                            |\n| bg_disabled  | theme.state.DISABLED  | The item cannot be interracted with           |\n| fg_disabled  | theme.state.DISABLED  | The item cannot be interracted with           |\n| bg_urgent    | theme.state.URGENT    | The item request immediate attention          |\n| fg_urgent    | theme.state.URGENT    | The item request immediate attention          |\n| bg_focus     | theme.state.SELECTED  | Focussed / Selected items                     |\n| fg_focus     | theme.state.SELECTED  | Focussed / Selected items                     |\n| bg_pressed   | theme.state.PRESSED   | The item is being pressed                     |\n| fg_pressed   | theme.state.PRESSED   | The item is being pressed                     |\n| bg_hover     | theme.state.HOVERED   | The mouse is over the item                    |\n| fg_hover     | theme.state.HOVERED   | The mouse is over the item                    |\n| bg_changed   | theme.state.CHANGED   | The item recently changed                     |\n| fg_changed   | theme.state.CHANGED   | The item recently changed                     |\n| bg_used      | theme.state.USED      | The item is used                              |\n| fg_used      | theme.state.USED      | The item is used                              |\n| bg_checked   | theme.state.CHECKED   | The item is checked                           |\n| fg_checked   | theme.state.CHECKED   | The item is checked                           |\n| bg_alternate | theme.state.ALTERNATE | Alternative to bg                             |\n| fg_alternate | theme.state.ALTERNATE | Alternative to fg                             |\n| bg_highlight | theme.state.HIGHLIGHT | The item is hightlighted                      |\n| fg_highlight | theme.state.HIGHLIGHT | The item is hightlighted                      |\n\n### Common methods\n\nAll menus provide a bunch of methods. Most of them have been coverred above, but\nhere is the list:\n\n|        Name          |                 Description                  |       Arguments       | Return |\n| -------------------- | -------------------------------------------- | --------------------- | ------ |\n| add_item             | Add new item to a menu                       | array of options      | item   |\n| add_items            | Add new items to a menu                      | array of items arrays | array  |\n| add_widget           | Add a new widget instead of an item          | a widget, args        |  ---   |\n| add_widgets          | Add new widgets                              | array of widgets      |  ---   |\n| add_embeded_menu     | Add an inline menu to another menu           | an \"embed\" menu       |  ---   |\n| add_key_binding      | Add a global key binding to a menu           | mod array, key        |  ---   |\n| add_key_hook         | Add a callback when a key is pressed         | mod, key, event, func |  ---   |\n| clear                | Remove all items                             |           ---         |  ---   |\n| scroll_down          | If the menu is cropped, scroll down          |           ---         |  ---   |\n| scroll_up            | If the menu is cropped, scroll up            |           ---         |  ---   |\n| hide                 | Hide a menu and all sub menus                |           ---         |  ---   |\n| swap                 | Swap 2 items                                 | both items            |  ---   |\n| move                 | Move an item                                 | the item, the new idx |  ---   |\n| remove               | Remove the item                              | the item              |  ---   |\n| append               | Append an existing (but unused) item         | the item              |  ---   |\n| add_prefix_widget    | Add a widget at the beginning of the menu    | the widget            |  ---   |\n| add_suffix_widget    | Add a widget at the end of the menu          | the widget            |  ---   |\n| add_colors_namespace | Use prefixed colors from beautiful           | the namespace name    |  ---   |\n| add_colors_group     | Add a new color group (see below for details)| the group name        |  ---   |\n\n\n### Signals\n\nMenu also emit many signals, the syntax is usually `PROPERTY_NAME::changed`.\nSome others are `item::moved`, `item::swapped`, `item::removed`, `item::appended`\n\nHere is an example of how to catch an \"opacity\" change:\n\n```lua\n    mymenu:connect_signal(\"opacity::changed\",function(value)\n        -- Do something\n    end)\n```\n\nMost item_layout also repackage the default widget signals. It usually does the\nsame as using the `buttonX` menu attributes, but is preferrable in some scenarios\nlike when a modifier is applied.\n\n|       Name        |           Description         |           Arguments          |\n| ----------------- | ----------------------------- | ---------------------------- |\n| button::press     | A button press                | menu,item,button_id,mods,geo |\n| button::release   | A button release              | menu,item,button_id,mods,geo |\n| mouse::enter      | When the mouse enter          | menu,item                    |\n| mouse::leave      | When the mouse leave          | menu,item                    |\n| long::hover       | The mouse is hover 1.5 sec    | menu,item                    |\n| long::press       | The mouse is pressed 1.5 sec  | menu,item                    |\n\n`mods` is an array with the applied modifier as **key**. If the value is `nil`,\nthen the modifier is not present. Usual modifiers are `Control`, `Shift`, `mod1`\n(Alt) and `mod4`.\n\nAn example of how to use them:\n\n```lua\n    local menubar = radical.bar{}\n    menubar:connect_signal(\"button::press\",function(data,item,button,mods)\n        if mods.Control then\n            print(\"Foo menu pressed!\",item.text,button,data.rowcount)\n        end\n    end)\n    \n    -- Also work on items\n    menubar:add_item{text=\"bar\"}:connect_signal(\"button::release\",function(d,i,b,m)\n        print(\"bar click released!\")\n    end)\n```\n\n### Beautiful options\n\nRadical also use the some of the same theme options as awful.menu, plus some:\n\n|            Name              |              Description               |            Type           |\n| ---------------------------- | -------------------------------------  | ------------------------- |\n| menu_height                  | Menu height                            | String/Gradient/Pattern   |\n| menu_width                   | Menu default/minimum width             | Number                    |\n| menu_border_width            | Border width                           | Number                    |\n| menu_border_color            | Border color                           | String/Gradient/Pattern   |\n| menu_fg_normal               | Text/Foreground color                  | String/Gradient/Pattern   |\n| menu_bg_focus                | Selected item color                    | String/Gradient/Pattern   |\n| menu_bg_header               | Header widget background color         | String/Gradient/Pattern   |\n| menu_bg_alternate            | Scrollbar and other widget color       | String/Gradient/Pattern   |\n| menu_bg_normal               | Default background                     | String/Gradient/Pattern   |\n| menu_bg_highlight            | Highlighted item background            | String/Gradient/Pattern   |\n| menu_submenu_icon            | Sub menu pixmap (aka \u003e)                | Path/Pattern              |\n| menu_separator_color         | Menu separator color                   | String/Gradient/Pattern   |\n| menu_opacity                 | Use your favorite compositor           | Number (0=0%, 1=100%)     |\n| menu_draw_underlay           | Function returning the underlay pixmap | function(array,width)     |\n| menu_icon_transformation     | The function used to draw the icon     | function(image,data,item) |\n| menu_corner_radius           | Arrow based menu corner radius         | Number (default = 10)     |\n| dock_corner_radius           | The dock menu type corner radius       | Number (default 10)       |\n| menu_outline_color           | Arrow menu outer border color          | String/Gradient/Pattern   |\n| menu_checkbox_style          | The style used for checkboxes          | \"holo\" or \"default\"       |\n\n\nStyling can also be done using the icon_transformation option. This feature\nallow masks such as desaturation, tinting, invert or some matrix to be applied\non the pixmap before it is being drawn. This function take the path/surface as\nonly parameter and return the transformed surface.\n\nOther elements can be added to items such as prefix and siffixes.\nThose elements sometime need extra color groups. The `add_color_group` method\nallow to register such new category.\n\nSome generic menu can also register beautiful namespaces using the \n`add_colors_namespace` method. For example, the tasklist namespace can be used\nby adding elements such as `beautiful.tasklist_bg_urgent` to your theme.\n\n## Extending Radical\n\nRadical is not designed to be used \"as is\". Every menus are different. While\ncommon ones can be created without extending Radical capabilities, more advanced\none most likely will. Good news, this is what Radical have been designed for.\nThe previous generations proved to me that any lack or native extensibility\nwill cause the code to bloat when it come to adding a feature. Radical horizontal\ndesign allow to add more modules and properties without having to touch the \"core\"\nfiles.\n\n### Object model\n\nThe Radical object model is similar to the Awesome one. Each objects have a set\nof signals developers can listen to to have changes notification. The big\ndifference is that Radical object model automatically generate the properties\nthemselves. If one desire to add a new one, it is possible to listen to `item::added`\nto apply it on the item or apply it directly on the menu itself depending if the\nproperty is for the menu or for an item. Here is an example how it work:\n\n```lua\n    local menu = radical.context{}\n    \n    -- Create the setter\n    menu.set_foo = function(m,value)\n        print(\"Setting value to:\",value)\n        m._foo_real = value\n    end\n    \n    -- Create the getter\n    menu.get_foo = function(m)\n        print(\"Getter called, returning\",m._foo_real)\n    end\n    \n    -- The property is now created, this will call the setter:\n    menu.foo = \"my foo value\"\n    \n    -- This will call the getter:\n    print(menu.foo)\n    \n    -- The signals will be automatically generated\n    data:connect_signal(\"foo::changed\",function(m,value)\n        print(\"foo changed:\",value)\n    end)\n    \n    -- New signals don't need to be registered and can be called right away\n    data:connect_signal(\"my_new_signal::action_name\",function(m,value1,value2,value3)\n        print(\"Callback\",m,value1,value2,value3)\n    end)\n    \n    -- Manually emiting a signal\n    menu:emit_signal(\"my_new_signal::action_name\",value1,value2,value3)\n    \n```\n\n### State model\n\nRadical support multiple states per item at once. The \"current state\" is the one\nwith the smallest ID. A state ID is an integer from -inf to inf. More important\nstates, like `urgent` versus `checked` can be implemented by using an\nappropriate ordering. The default set of states is subject to changes, so it\nis wiser to use a completely different range if someone want to replace the\ncurrents one. Each states can be assigned a background and foreground color\nusing the `radical.theme.register_color(id, radical_name, beautiful_name, true )`\nmethod. Toggling a state can be done using the `item.state[]` meta table:\n\n```lua\n    local my_state_name = 9999 -- \u003c== The ID\n    local menu = radical.context{}\n    local item = menu:add_item{text=\"text\"}\n    \n    -- Activate a state\n    item.state[my_state_name] = true\n    \n    -- Desactivate a state\n    item.state[my_state_name] = nil\n    \n```\n\nRadical will take care of choosing the current state and redraw the item with\nthe right background and foreground colors.\n\n### Layout\n\nTODO\n\n### Style\n\nTODO\n\n### Item layout\n\nTODO\n\n### Item style\n\nTODO\n\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FElv13%2Fradical","html_url":"https://awesome.ecosyste.ms/projects/github.com%2FElv13%2Fradical","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FElv13%2Fradical/lists"}