Linux Mint 19.1 BETA がリリースされました!19.1 までもうすぐですね!
roadtoalinuxmintuser

theming

roundup
Linux Mint 18.3 : Conky の Lua スクリプトの書き方 Part2 00:34
アイキャッチ

Conky で直線を描く方法


直線を描くには知っておくべき関数がいくつかあります。まずは cairo_set_line_width (cr,1) です。ここや他の例にもあるように cairo の関数は cairo_なになに(cr, 引数1, 引数2, ...) という形式をとります。main 関数で cr を初期化し、cairo の関数を使うときは必ず ( の次に cr と続けます。

ラインキャップ(先端の形状):
cairo_set_line_cap  (cr, CAIRO_LINE_CAP_BUTT)
または
cairo_set_line_cap (cr, CAIRO_LINE_CAP_ROUND)
または
cairo_set_line_cap (cr, CAIRO_LINE_CAP_SQUARE)

BUTT、ROUND、SQUARE の違いは画像を見ると一目瞭然です。デフォルトでは BUTT になっています:
set_line_cap
前回、cairo_set_source_rgba(cr,1,1,1,1) という関数を使いました。この関数で色を指定したら、次は cairo_move_to(cr,100,100) 関数を使って直線の開始点を指定する必要が有ります。それでは太さ 2 ピクセルの白色の直線を Conky ウィンドウの左上から 100 ピクセル右、100 ピクセル下の位置から引いてみましょう:
line_width=2
line_cap=CAIRO_LINE_CAP_BUTT
red,green,blue,alpha=1,1,1,1
startx=100
starty=100
----------------------------
cairo_set_line_width (cr,line_width)
cairo_set_line_cap (cr, line_cap)
cairo_set_source_rgba (cr,red,green,blue,alpha)
cairo_move_to (cr,startx,starty)

実はこれでは足りません。開始点は指定しているものの、終止点を指定しないからです。終止点を指定するには Conky ウィンドウの絶対的な座標で指定する方法 cairo_line_to (cr,200,100) と開始点からの相対的な座標で指定する方法 cairo_rel_line_to (cr,100,0) の 2 つがあります。この場合、どちらを使っても同じ結果になります。cairo_rel_line_to (cr,100,0) では開始点から右に 100 ピクセル、開始点から下に 0 ピクセルの位置まで直線を描くように指定しています。終止点を指定したら cairo_stroke (cr) を最後につけて実際に直線を描画します:
line_width=2
line_cap=CAIRO_LINE_CAP_BUTT
red,green,blue,alpha=1,1,1,1
startx=100
starty=100
endx=200
endy=100
----------------------------
cairo_set_line_width (cr,line_width)
cairo_set_line_cap (cr, line_cap)
cairo_set_source_rgba (cr,red,green,blue,alpha)
cairo_move_to (cr,startx,starty)
cairo_line_to (cr,endx,endy)
cairo_stroke (cr)

.conkyrc もこちらのものに変えてください(どうやら図形を描画するのに double_buffer = true という設定は必須のようです):

conky.config = {
-- Conky settings -- #
background = false,
update_interval = 1,
cpu_avg_samples = 2,
net_avg_samples = 2,
override_utf8_locale = true,
double_buffer = true,
no_buffers = true,
text_buffer_size = 32768,
imlib_cache_size = 0,

-- Window specifications -- #
own_window = true,
own_window_type = 'dock',
own_window_argb_visual = true,
own_window_argb_value = 0,
own_window_transparent = yes,
--own_window_hints = 'undecorated,below,sticky,skip_taskbar,skip_pager',
own_window_class = 'Conky',
border_inner_margin = 50,
border_outer_margin = 0,
--border_width = 1,

-- position & minimum_size -- #
gap_x = 5,
gap_y = 60,
minimum_height = 500,
minimum_width = 500,
alignment = 'top_right',

-- Graphics settings -- #
draw_shades = false,
draw_outline = false,
draw_borders = false,
draw_graph_borders = false,

-- Text settings -- #
double_buffer = true,
no_buffers = true,
use_xft = true,
font = 'Ubuntu Mono:size=12',
xftalpha = 0.8,
out_to_console = false,
out_to_stderr = false,
extra_newline = false,

stippled_borders = 0,
uppercase = false,
use_spacer = 'none',

-- Graph settings -- #
show_graph_scale = false,
show_graph_range = false,

-- Load lua script -- #
lua_load = '~/.conky/test/script.lua',
lua_draw_hook_post = 'main'
}

conky.text = [[


]]

範囲を選択_035
線の太さについても考慮しなくてはなりません。1 より大きい値を指定すると線の太さだけでなく、見え方にも影響を与えます。例えば、先の太さを 10 に指定したら、片方の端から 5 ピクセル、もう片方の端から 5 ピクセル飛び出てしまいます。つまり、直線の左上の座標は実際には (100,95) となり、左下は (100,105) になります。また、線というより矩形になってしまいます。

描画したい図形の座標や諸々の値を指定するために変数や文字を使うんだなとわかれば、あとは描きたいものの複雑さ次第です。

例えば、CPU 使用率のインジケーターを直線で表示したい場合は、まずお馴染みの cpu_perc=tonumber(conky_parse("${cpu}")) を使います。Conky の変数 ${cpu} をパース(conky_parse)して、数値に変換したら(tonumber)、変数(cpu_perc)に格納します。このように何個も () があるとつけ忘れやすいので注意します。

以下に例を示します。これは 0 から 100 までの値を出力します。すでに書いた 100 ピクセルの直線のコードを少し書き改めるだけです:
cpu_perc=tonumber(conky_parse("${cpu}"))
line_width=2
line_cap=CAIRO_LINE_CAP_BUTT
red,green,blue,alpha=1,1,1,1
startx=100
starty=100
endx=startx+cpu_perc
endy=starty
----------------------------
cairo_set_line_width (cr,line_width)
cairo_set_line_cap (cr, line_cap)
cairo_set_source_rgba (cr,red,green,blue,alpha)
cairo_move_to (cr,startx,starty)
cairo_line_to (cr,endx,endy)
cairo_stroke (cr)


endx=startx+cpu_perc の位置まで直線を描いています。Conky の変数 ${cpu} の値に応じて直線の終止点が変わります。endx=100+cpu_perc と書かず endx=startx+cpu_perc と書いていたり、endy=100 と書かず endy=starty と書いたりしている点にも留意してください。変数を上でまとめれば後で編集しやすくなります。リテラルではなくなるべく変数を使うことで時間の節約につながります。

直線を描くだけでなく、もっと多くのことが直線で出来ます。図形を描くのに直線を利用してみましょう。枠として描いたり、中を塗りつぶしたり出来ます。三角形を描くとしたら、線と線を結ぶ工程が必要です。これは以下の関数で出来ます:
cairo_set_line_join (cr, CAIRO_LINE_JOIN_MITER)
または
cairo_set_line_join (cr, CAIRO_LINE_JOIN_BEVEL)
または
cairo_set_line_join (cr, CAIRO_LINE_JOIN_ROUND)

set_line_join
デフォルトは MITER です。MITER は面取りしない、BEVEL は面取りする、ROUND は丸くするよう指定します。cairo_close_path(cr) 関数も直線をつなぎあわせて一続きの線を描くのに必要です。つまりこうなります:
line_width=20
line_cap=CAIRO_LINE_CAP_BUTT --we don't need this any more after closing the path
line_join=CAIRO_LINE_JOIN_MITER --but this will still affect how the lines look
red,green,blue,alpha=1,1,1,1
startx=100
starty=100
pointx=startx+100
pointy=starty+100
endx=pointx-100
endy=pointy
----------------------------
cairo_set_line_width (cr,line_width)
cairo_set_line_cap (cr, line_cap)
cairo_set_source_rgba (cr,red,green,blue,alpha)
cairo_move_to (cr,startx,starty)
cairo_line_to (cr,pointx,pointy)
cairo_line_to (cr,endx,endy)
cairo_line_to (cr,startx,starty)
cairo_set_line_join (cr, line_join)
cairo_close_path (cr)
cairo_stroke (cr)

範囲を選択_036
見てわかるように、cairo_move_to を繰り返し使う必要はありません。「パス」を描いているからです。これに関してはあたかなもペンでなぞっているように描けます。

最後に、描いたパスが視覚化されるように、cairo_stroke 関数を使う必要が有ります。

実際のところ、close_path を使うことで三角形の最後の線は描く必要がありません。close_path はいつでも最後の点から開始点までを結ぶからです。

もし三角形の中を塗りつぶしたければ cairo_stroke(cr) ではなく cairo_fill(cr) を使います。ただし、cairo_fill(cr) を使った場合、線の太さも面取りの設定も反映されなくなります。更に、cairo_fill では close_path 関数を使う必要はありません。というのも cairo_fill が塗りつぶす領域を生成するためにパスを自動で閉じるからです。close_path を使ったとしても冗長になるだけで何も悪さはしません。

もし、図形の枠を描いたあとで、塗りつぶしをしたい場合、例えば、枠と中で色を変えたい場合などには、cairo_fill の代わりに cairo_fill_preserve を使います。そして枠の色をセットしたあと、cairo_stroke で枠を描画します:
cairo_set_line_width (cr,20)
cairo_move_to (cr,100,100)--start point
cairo_line_to (cr,200,200)--diagonal line down
cairo_line_to (cr,100,200)--horizontal line
cairo_close_path (cr)--draws vertical line back to start
cairo_set_source_rgba (cr,1,1,1,1)--white
cairo_fill_preserve (cr)--fills in the triangle in white
cairo_set_source_rgba (cr,1,0,0,1)--red
cairo_stroke (cr)--draws the triangle outline in red

範囲を選択_037
cairo のサンプル: https://www.cairographics.org/samples/

四角形・円・弧を描く


cairo は線以外にも以下のものが描けます:
  • 四角形
  • 曲線

四角形


三角形を直線で自力描いたように、四角形も自力で描くことは出来ますが、cairo には四角形を描画する機能が組み込まれています。cairo_rectangle(cr, x, y, width, height) です。x,y は四角形の左上の座標です。

三角形で書いたように四角形も書けます:
--settings
line_width=5
top_left_x=20
top_left_y=20
rec_width=100
rec_height=50
red=1
green=0
blue=0
alpha=1
--draw it
cairo_set_line_width (cr,line_width)
cairo_rectangle (cr,top_left_x,top_left_y,rec_width,rec_height)
cairo_set_source_rgba (cr,red,green,blue,alpha)
cairo_stroke(cr)

範囲を選択_038
塗りつぶしたければ cairo_stroke(cr) の代わりに cairo_fill(cr) を使います。もし枠と中で色を変えたい場合は、まず cairo_fill_preserve で塗りつぶしたあと、cairo_stroke で線を描きます:
--settings
line_width=5
top_left_x=20
top_left_y=20
rec_width=100
rec_height=50
fill_red=1
fill_green=1
fill_blue=1
fill_alpha=1
line_red=1
line_green=0
line_blue=0
line_alpha=1
--draw it
cairo_set_line_width (cr,line_width)
cairo_rectangle (cr,top_left_x,top_left_y,rec_width,rec_height)
cairo_set_source_rgba (cr,fill_red,fill_green,fill_blue,fill_alpha)
cairo_fill_preserve (cr)
cairo_set_source_rgba (cr,line_red,line_green,line_blue,line_alpha)
cairo_stroke (cr)

範囲を選択_039
四角形には直線の時にはあったラインキャップをセットする利点はありません。四角形には「緩い頂点」がないからです。cairo_close_path も使う必要はありません。cairo_stroke を使えば、自動的に閉じられるからです。しかし、直線の結合点を少し変えたければ以下のように角を丸めることが出来ます:
cairo_set_line_join (cr, CAIRO_LINE_JOIN_ROUND)
cairo_stroke (cr)

cairo_fill を使うときは線の太さ、ラインキャップ、結合の仕方は特に意味はありません。

円・弧を描く


弧に関しては cairo_arc(cr,center_x,center_y,radius,start_angle,end_angle) と cairo_arc_negative(cr,center_x,center_y,radius,start_angle,end_angle) の 2 つの関数が有ります。cairo_arc は時計回りに弧を描くのに対し、cairo_arc_negative は半時計回りに弧を描きます。弧を描く最初の困難は角度を度ではなくラジアンで表記することです。ラジアンと度の関係を知っておく必要が有ります:
ラジアンと度の関係
180°= π rad

lua には数学の関数がいくつか組み込まれています。その一つに math.pi があり、円周率を返してくれます。

もうひとつは 0 度が円の一番上ではないことです。むしろ 0 度は円の一番右です。円を描きたかったらこのことは問題ではありませんが、次のコードを書く必要が有ります:
center_x=100
center_y=100
radius=50
start_angle=0
end_angle=2*math.pi--same thing as 360 degrees
cairo_arc(cr,center_x,center_y,radius,start_angle,end_angle)
cairo_stroke(cr)

範囲を選択_040
何かを描くために stroke を使う時は毎回線の太さをセットする必要が有ります。stroke を使って線の末端を見るつもりなら、ラインキャップを変更すれば線の末端に反映されます。stroke に影響を与える他の因子は結合の種類です。複数の要素からひとつのパスを作成するつもりなら、曲線や直線に加えて弧は上の例で示したように一つのパスを作り、ひとまとまりになります。それよりも前に色やアルファ値をセットできます。

円を塗りつぶすには cairo_stroke から cairo_fill に変えます。

しかし、もし弧を描きたかったらラジアンと角度の設定を考慮する必要が有ります。例えば、一番上から一番右に 1/4 の円を描きたいとすると、コードはこのようになります:
center_x=100
center_y=100
radius=50
start_angle=0
end_angle=90
cairo_arc (cr,center_x,center_y,radius,(start_angle-90)*(math.pi/180),(end_angle-90)*(math.pi/180))
cairo_stroke (cr)

範囲を選択_041
ラジアンよりもむしろ度数で値を入力したいので、そのための計算式 (start_angle-90)*(math.pi/180) を cairo_arc 関数の引数に入れてみました。start_angle=0 で円の一番上から描くようにセットし、end_angle=90 で円の一番右まで描くようにセットしています。次に (math.pi/180) を掛けることでラジアンに変換しています。最後に cairo_stroke で描画します。

次のコードは弧の開始点から終止点までを直線で引くことになります。cairo_stroke でなく cairo_fill(cr) を使えば底が平らになり中が塗りつぶされます。
cairo_close_path (cr)
cairo_stroke (cr)

cairo_arc に開始角度を 270°、終始角度を 90°にセットすれば、上半分の円が得られます。start=270, end=450 (360+90) としても start=-90, end=90 としても結果は同じです:
範囲を選択_042
逆に cairo_arc_negative を使えば開始角度を 270°、終始角度を 90°にセットすると、下半分の円が得られます。

このことはパスを描くのに大切です。また、close_path あるいは fill 関数を使うことで終止点から開始点まで線を引くことを忘れないでください。パスが連続していないと予期せぬ結果になります。

arc あるいは arc_negative を使えばリング状のメーターを表示することができます。

バー状のメーターとリング状のメーターを描画する


Conky から cpu 使用率の値を取得しその値に応じて直線の長さを変えるコードを作成しました。今度は、ちょっと面白いものにするために、背景に色を付け、バーもその色とは異なる色にして、垂直方向のインジケータを作成します。まずは何からしたら良いでしょうか。まずは、lua における cairo の命令の順序を考える必要が有ります。スクリプトで、より下に書いたものが、すでに描画されたものより上に描画されます。

そういうことなので、まずは色付けされた背景を用意し、その上にインジケーターを描画するようにします。指定する必要のある項目は以下の通りです:
  • インジケーターをどこに表示するか
  • インジケーターの大きさ
  • 背景とインジケーターのそれぞれの色

そのための変数を書くとこうなるでしょう:
--SETTINGS FOR CPU INDICATOR BAR
bar_bottom_left_x= 50
bar_bottom_left_y= 200
bar_width= 30
bar_height= 100
--set bar background colors, 1,0,0,1 = fully opaque red
bar_bg_red=1
bar_bg_green=0
bar_bg_blue=0
bar_bg_alpha=1
--set indicator colors, 1,1,1,1 = fully opaque white
bar_in_red=1
bar_in_green=1
bar_in_blue=1
bar_in_alpha=1

スクリプト内の別のところで変数名が重複しないようにユニークな変数名にする必要が有ります。通常、変数名を見ればどんな値が格納されるの変わるような名前が良いです。何度も何度も長い変数名を書くのは面倒かもしれませんが、スクリプトを実行しても、変数を上書きしてしまったがためにうまく動作しないよりはマシです。背景を描画するのはかなり単純で、矩形を塗りつぶすことで実現します。唯一注意すべきことは底の座標と幅と高さをセットするとき、高さが負の値になることです。では実際に cairo_rectangle 関数を使って試してみましょう:
--draw background
cairo_set_source_rgba (cr,bar_bg_red,bar_bg_green,bar_bg_blue,bar_bg_alpha)
cairo_rectangle (cr,bar_bottom_left_x,bar_bottom_left_y,bar_width,-bar_height)
cairo_fill (cr)

赤く塗りつぶされた四角形が描けたので、次はインジケーターを作成していきます。まずは、value=tonumber(conky_parse("${cpu}")) で CPU 使用率を変数に格納します。変数の値を使ってインジケーターの高さに反映します。少々複雑なりますが、計算が必要になってきます。

高さ 100 ピクセルのインジケーターを描画したければ、単純に取得した CPU 使用率をそのまま使えば良くなります。というのも CPU 使用率は 0 から 100 までの値をとるからです。しかし、高さ 200 ピクセルあるいは 50 ピクセルのインジケーターを作成したい場合は取得した CPU 使用率を適切に増やしたり減らしたりしないといけません。CPU 使用率の最大値は 100 だとわかっているので、max_value=100 とし bar_height=200 もしくは bar_height=50 とすれば、倍率は scale=bar_height/max_value で計算できます。

bar_height=200 であれば scale=2 となります。つまり、 CPU 使用率が 1 増えればバーは 2 ピクセル増えます。CPU 使用率 100% では長さ 200 ピクセルになります。望むとおりの結果です。そこで、indicator_height=scale*value で取得したあと描画する四角形に組み込みます。以上の議論をまとめるとこうなります:
--draw indicator
cairo_set_source_rgba (cr,bar_in_red,bar_in_green,bar_in_blue,bar_in_alpha)--set indicator color
value=tonumber(conky_parse("${cpu}"))
max_value=100
scale=bar_height/max_value
indicator_height=scale*value
cairo_rectangle (cr,bar_bottom_left_x,bar_bottom_left_y,bar_width,-indicator_height)
cairo_fill (cr)


これで CPU 使用率インジケーターが動作しているはずです。
バーを増やそうと思って何度も何度もコードをコピー & ペーストしたり、変数を編集したりするのは面倒です。しかし、コピー & ペーストするよりもインジケーターバーを描画するコードを関数としてひとまとめにするほうがより手っ取り早い方法です。この話は後ほどすることにします。

インジケーターに CPU 使用率を選んだのは他でもなく、頻繁に変化するので動作している様子がよくわかるからです。リング状のメーターを作成するのはバーを作成したのととても似ています。ただし、Conky から取得した CPU 使用率を使って cairo_arc 関数に渡す角度を変化させます。背景となるリングを着色し、インジケーターとなるリングは別の色をつけます。リングの大きさは変数を変更すれば変更できます。CPU 使用率が 0 の時はリングは一番上を示し、CPU 使用率が増えるに連れて時計回りに 100% になるまでバーが伸びるようにします。今回作成するのは完全な円で、最初と最後は結びます。

時計回りにするので cairo_arc を使います。四角形の時とは異なり、メーターを描くのに cairo_stroke を使っていきます。なので caro_set_line_width の値はセットしておく必要が有ります。メーターの太さに関わってきます。まずは、どんなリングを描きたいか諸々の設定を決めましょう。ラインキャップは設定する必要が有りますが、線をつなげているわけではないので線の結合の種類は指定しなくて大丈夫です。

弧の関数は cairo_arc (cr,center_x,center_y,radius,start_angle,end_angle) でした:
--SETTINGS
--rings size
ring_center_x=200
ring_center_y=200
ring_radius=50
ring_width=20
--colors
--set background colors, 1,0,0,1 = fully opaque red
ring_bg_red=1
ring_bg_green=0
ring_bg_blue=0
ring_bg_alpha=1
--set indicator colors, 1,1,1,1 = fully opaque white
ring_in_red=1
ring_in_green=1
ring_in_blue=1
ring_in_alpha=1
--indicator value settings
value=conky_parse("${cpu}")
max_value=100

インジケーターバーの時と同様に、まずは背景となるリングを描いていきます:
--draw background
cairo_set_line_width (cr,ring_width)
cairo_set_source_rgba (cr,ring_bg_red,ring_bg_green,ring_bg_blue,ring_bg_alpha)
cairo_arc (cr,ring_center_x,ring_center_y,ring_radius,0,2*math.pi)
cairo_stroke (cr)

line_width についての注意点なのですが、円または弧を描画するときの線の太さは直線の場合と全く同じ挙動を示します。線の太さの半分がそれぞれ内側・外側に描画されます。つまり、半径 50 ピクセル、線の太さ 20 ピクセルの円または弧であれば、円の中心点から線の内端までは 40 ピクセルになり、円の外端までは60ピクセルになります。

背景を赤くした円を作成したので、value 変数に格納されている cpu 使用率の値をインジケーターのバーの動きに適用する方法を検討しなければなりません。この場合は、cpu 使用率に比例して変化するのは弧の末端角度です。再度、インジケーターの弧を正しい割合で動かすのに計算が少し必要です:
degrees=360
scale=degrees/max_value--ie for every 1% increase in cpu% the arc should move an additional 3.6 degrees
end_angle=value*scale

あるいは end_angle=value*(360/max_value) と書くことも出来ます。これで、すべて cairo_arc に渡す準備が出来ました:
--draw indicator
cairo_set_line_width (cr,ring_width)
end_angle=value*(360/max_value)
cairo_set_source_rgba (cr,ring_in_red,ring_in_green,ring_in_blue,ring_in_alpha)
cairo_arc (cr,ring_center_x,ring_center_y,ring_radius,0,(end_angle-90)*(math.pi/180))
cairo_stroke (cr)

実は上のコードを試してもうまく行かないことに気づくでしょう。間違いが起こるとどうなるか見てもらうためにやってみました。

どこで計算を間違っていたのでしょうか。end_angle の値がどうなっているか print で出力してみます:
--draw indicator
cairo_set_line_width (cr,ring_width)
end_angle=value*(360/max_value)
print (end_angle)
cairo_set_source_rgba (cr,ring_in_red,ring_in_green,ring_in_blue,ring_in_alpha)
cairo_arc (cr,ring_center_x,ring_center_y,ring_radius,0,(end_angle-90)*(math.pi/180))
cairo_stroke (cr)

cpu 使用率も同時に見れるように conky.text = [[ ... ]] 内に ${cpu} を記述することにしました。もっとも print(value, end_angle) を使えば両方共端末で見ることは出来ますが。。。

計算結果は問題ないように思えます。なので cairo_arc (cr,ring_center_x,ring_center_y,ring_radius,0,(end_angle-90)*(math.pi/180)) のどこかで誤りがあるに違いありません。それは開始角でした 0 のままにしており、cairo_arc 関数のトリッキーな挙動を考慮していませんでした。実際期待していた値よりも 90°進んでいたのです。そこでこのように修正します:
cairo_set_line_width (cr,ring_width)
end_angle=value*(360/max_value)
--print (end_angle)
cairo_set_source_rgba (cr,ring_in_red,ring_in_green,ring_in_blue,ring_in_alpha)
cairo_arc (cr,ring_center_x,ring_center_y,ring_radius,(-90)*(math.pi/180),(end_angle-90)*(math.pi/180))
cairo_stroke (cr)

これでリング状のメーターの完成です:


参考元: Using Lua scripts in conky (Part 03), (Part 04), (Part 05)
| Linux |
<< NEW | TOP | OLD>>
スポンサーサイト 00:34
| - |

Show some apps list:


miku

Follow on your feed reader:


About this blog:

Linux Mint-centric chronicle.
Since 2009.
Info 再開しました。更新日は月一です。

roadtoapython

roadtorubyist

git

Amazon: