123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384 |
- -- @author cedlemo
- local setmetatable = setmetatable
- local ipairs = ipairs
- local math = math
- local table = table
- local type = type
- local string = string
- local color = require("gears.color")
- local base = require("wibox.widget.base")
- local helpers = require("blingbling.helpers")
- local superproperties = require('blingbling.superproperties')
- ---Graph widget.
- --@module blingbling.linegraph
- local linegraph = { mt = {} }
- local data = setmetatable({}, { __mode = "k" })
- ---Fill all the widget (width * height) with this color (default is none ).
- --@usage mygraph:set_background_color(string) -->"#rrggbbaa"
- --@name set_background_color
- --@class function
- --@param color a string "#rrggbbaa" or "#rrggbb"
- ---Fill the graph area background with this color (default is none).
- --@usage mygraph:set_graph_background_color(string) -->"#rrggbbaa"
- --@name set_graph_background_color
- --@class function
- --@param color a string "#rrggbbaa" or "#rrggbb"
- ---Set rounded corners for background and graph background.
- --@usage mygraph:set_rounded_size(a) -> a in [0,1]
- --@name set_rounded_size
- --@class function
- --@param rounded_size float in [0,1]
- ---Define the top and bottom margin for the graph area.
- --@usage mygraph:set_v_margin(integer)
- --@name set_v_margin
- --@class function
- --@param margin an integer for top and bottom margin
- ---Define the left and right margin for the graph area.
- --@usage mygraph:set_h_margin(integer)
- --@name set_h_margin
- --@class function
- --@param margin an integer for left and right margin
- ---Define the graph color.
- --@usage mygraph:set_graph_color(string) -->"#rrggbbaa"
- --@name set_graph_color
- --@class function
- --@param color a string "#rrggbbaa" or "#rrggbb"
- ---Define the graph outline.
- --@usage mygraph:set_graph_line_color(string) -->"#rrggbbaa"
- --@name set_graph_line_color
- --@class function
- --@param color a string "#rrggbbaa" or "#rrggbb"
- ---Display text on the graph or not.
- --@usage mygraph:set_show_text(boolean) --> true or false
- --@name set_show_text
- --@class function
- --@param boolean true or false (default is false)
- ---Define the color of the text.
- --@usage mygraph:set_text_color(string) -->"#rrggbbaa"
- --@name set_text_color
- --@class function
- --@param color a string "#rrggbbaa" or "#rrggbb" defaul is white
- ---Define the background color of the text.
- --@usage mygraph:set_text_background_color(string) -->"#rrggbbaa"
- --@name set_text_background_color
- --@class function
- --@param color a string "#rrggbbaa" or "#rrggbb"
- ---Define the text's font .
- --@usage mygraph:set_font(string)
- --@name set_font
- --@class function
- --@param font a string that contains the font name family and weight
- ---Define the text font size.
- --@usage mygraph:set_font_size(integer)
- --@name set_font_size
- --@class function
- --@param size the font size
- ---Define the template of the text to display.
- --@usage mygraph:set_label(string)
- --By default the text is : (value_send_to_the_widget *100) .. "%"
- --static string: example set_label("CPU usage:") will display "CUP usage:" on the graph
- --dynamic string: use $percent in the string example set_label("Load $percent %") will display "Load 10%"
- --@name set_label
- --@class function
- --@param text the text to display
- local properties = { "width", "height", "h_margin", "v_margin",
- "background_color",
- "graph_background_border", "graph_background_color",
- "rounded_size", "graph_color", "graph_line_color",
- "show_text", "text_color", "font_size", "font",
- "text_background_color", "label"
- }
- function linegraph.draw(graph, wibox, cr, width, height)
- local max_value = data[graph].max_value
- local values = data[graph].values
- -- Set the values we need
- local value = data[graph].value
-
- local graph_border_width = 0
- if data[graph].graph_background_border then
- graph_border_width = 1
- end
-
- local v_margin = superproperties.v_margin
- if data[graph].v_margin and data[graph].v_margin <= data[graph].height/4 then
- v_margin = data[graph].v_margin
- end
-
- local h_margin = superproperties.h_margin
- if data[graph].h_margin and data[graph].h_margin <= data[graph].width / 3 then
- h_margin = data[graph].h_margin
- end
-
- local background_color = data[graph].background_color or superproperties.background_color
- local rounded_size = data[graph].rounded_size or superproperties.rounded_size
- local graph_background_color = data[graph].graph_background_color or superproperties.graph_background_color
- local graph_background_border = data[graph].graph_background_border or superproperties.graph_background_border
- local graph_color = data[graph].graph_color or superproperties.graph_color
- local graph_line_color = data[graph].graph_line_color or superproperties.graph_line_color
- local text_color = data[graph].text_color or superproperties.text_color
- local text_background_color = data[graph].text_background_color or superproperties.text_background_color
- local font_size =data[graph].font_size or superproperties.font_size
- local font = data[graph].font or superproperties.font
-
- local line_width = 1
- cr:set_line_width(line_width)
- cr:set_antialias("subpixel")
- helpers.draw_rounded_corners_rectangle( cr,
- 0, --x
- 0, --y
- data[graph].width,
- data[graph].height,
- background_color,
- rounded_size
- )
- -- Draw the graph background
- --if background_border is set, graph background must not be drawn on it
- local h_padding = 0
- local v_padding = 0
- if background_border ~= nil and h_margin < 1 then
- h_padding = 1
- else
- h_padding = h_margin + 1
- end
- if background_border ~= nil and v_margin < 1 then
- v_padding = 1
- else
- v_padding = v_margin + 1
- end
- helpers.draw_rounded_corners_rectangle(cr,
- h_padding, --x
- v_padding, --y
- data[graph].width - h_padding,
- data[graph].height - v_padding ,
- graph_background_color,
- rounded_size,
- graph_background_border)
- helpers.clip_rounded_corners_rectangle(cr,
- h_padding, --x
- v_padding, --y
- data[graph].width - h_padding,
- data[graph].height - v_padding,
- rounded_size
- )
- --Drawn the graph
- --if graph_background_border is set, graph must not be drawn on it
- --find nb values we can draw every column_length px
- --if rounded, make sure that graph don't begin or end outside background
- --check for the less value between hight and height to calculate the space for rounded size:
- local column_length = 6
-
- if data[graph].height > data[graph].width then
- less_value = data[graph].width/2
- else
- less_value = data[graph].height/2
- end
- max_column=math.ceil((data[graph].width - (2*h_padding +2*(rounded_size * less_value)))/column_length)
- --Check if the table graph values is empty / not initialized
- --if next(data[graph].values) == nil then
- if #data[graph].values == 0 or #data[graph].values ~= max_column then
- -- initialize graph_values with empty values:
- data[graph].values={}
- for i=1,max_column do
- --the following line feed the graph with random value if you uncomment it and comment the line after it
- --data[graph].values[i]=math.random(0,100) / 100
- data[graph].values[i]=0
- end
- end
- --Fill the graph
- x=data[graph].width -(h_padding + rounded_size * less_value)
- y=data[graph].height-(v_padding)
-
- cr:new_path()
- cr:move_to(x,y)
- cr:line_to(x,y)
- for i=1,max_column do
- y_range=data[graph].height - (2 * v_margin)
- y= data[graph].height - (v_padding + ((data[graph].values[i]) * y_range))
- cr:line_to(x,y)
- x=x-column_length
- end
- y=data[graph].height - (v_padding )
- cr:line_to(x + column_length ,y)
- cr:line_to(width - h_padding,data[graph].height - (v_padding ))
- cr:close_path()
-
- r,g,b,a=helpers.hexadecimal_to_rgba_percent(graph_color)
- cr:set_source_rgba(r, g, b, a)
- cr:fill()
-
- --Draw the graph line
- r,g,b,a=helpers.hexadecimal_to_rgba_percent(graph_line_color)
- cr:set_source_rgba(r, g, b,a)
- x=data[graph].width - (h_padding + rounded_size * less_value)
- y=data[graph].height-(v_padding)
- cr:new_path()
- cr:move_to(x,y )
- cr:line_to(x,y )
- for i=1,max_column do
- y_range=data[graph].height - (2 * h_margin + 1)
- y= data[graph].height - (v_margin + ((data[graph].values[i]) * y_range))
- cr:line_to(x,y )
- x=x-column_length
- end
- x=x + column_length
- y=data[graph].height - (v_padding )
- cr:line_to(x ,y )
- cr:stroke()
-
- if data[graph].show_text == true then
- --Draw Text and it's background
- cr:set_font_size(font_size)
- if type(font) == "string" then
- cr:select_font_face(font,nil,nil)
- elseif type(font) == "table" then
- cr:select_font_face(font.family or "Sans", font.slang or "normal", font.weight or "normal")
- end
-
- local value = data[graph].values[1] * 100
- if data[graph].label then
- text=string.gsub(data[graph].label,"$percent", value)
- else
- text=value .. "%"
- end
- helpers.draw_text_and_background(cr,
- text,
- h_padding + rounded_size * less_value,
- data[graph].height/2 ,
- text_background_color,
- text_color,
- false,
- true,
- false,
- false)
- end
- end
- function linegraph.fit(graph, width, height)
- return data[graph].width, data[graph].height
- end
- ---Add a value to the graph.
- --For compatibility between old and new awesome widget, add_value can be replaced by set_value
- --@usage mygraph:add_value(a) or mygraph:set_value(a)
- --@param graph the graph
- --@param value The value between 0 and 1.
- --@param group The stack color group index.
- local function add_value(graph, value, group)
- if not graph then return end
- local value = value or 0
- local values = data[graph].values
-
- if string.find(value, "nan") then
- value=0
- end
-
- local values = data[graph].values
- table.remove(values, #values)
- table.insert(values,1,value)
- graph:emit_signal("widget::updated")
- return graph
- end
- ---Set the graph height.
- --@param height The height to set.
- function linegraph:set_height( height)
- if height >= 5 then
- data[self].height = height
- self:emit_signal("widget::updated")
- end
- return self
- end
- ---Set the graph width.
- --@param width The width to set.
- function linegraph:set_width( width)
- if width >= 5 then
- data[self].width = width
- self:emit_signal("widget::updated")
- end
- return self
- end
- -- Build properties function
- for _, prop in ipairs(properties) do
- if not linegraph["set_" .. prop] then
- linegraph["set_" .. prop] = function(graph, value)
- data[graph][prop] = value
- graph:emit_signal("widget::updated")
- return graph
- 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 linegraph.new(args)
-
- local args = args or {}
- args.width = args.width or 100
- args.height = args.height or 20
- if args.width < 5 or args.height < 5 then return end
- local graph = base.make_widget()
- data[graph] = {}
- for _, v in ipairs(properties) do
- data[graph][v] = args[v]
- end
- data[graph].values = {}
-
- -- Set methods
- graph.set_value = add_value
- graph.add_value = add_value
- graph.draw = linegraph.draw
- graph.fit = linegraph.fit
- for _, prop in ipairs(properties) do
- graph["set_" .. prop] = linegraph["set_" .. prop]
- end
- return graph
- end
- function linegraph.mt:__call(...)
- return linegraph.new(...)
- end
- return setmetatable(linegraph, linegraph.mt)
|