Programming」カテゴリーアーカイブ

mpv: rotate

mpv をスクリプトで拡張をまとめてページを作ろうとして、欲が出た。
動画の回転を Eye of GNOME や Totem に合わせたい。
具体的には Ctrl+R で 90° ずつ時計回り、Shift 追加で逆回り。

今まで Ctrl+E を逆回りに割り当てていたけど、やはりおかしい。
それに割り当てする値は 0-359 以内にしないとエラーになる。
input.conf ではどうにもならない、Lua スクリプトを書く。

-- ~/.config/mpv/scripts/mpv_rotate.lua

-- input.conf に 'Ctrl+r add video-rotate 90' でもいいけど
-- 0-359 以内にしないとエラーなのとキーを Eye of GNOME に合わせたかったので

function on_rotate_right()
    angle = mp.get_property('options/video-rotate')
    num = tonumber(angle) + 90
    if num > 270 then
        num = 0
    end
    mp.osd_message('angle:'..tostring(num)..'°')
    mp.set_property_number('options/video-rotate', num)
end

function on_rotate_left()
    angle = mp.get_property('options/video-rotate')
    num = tonumber(angle) - 90
    if num < 0 then
        num = 270
    end
    mp.osd_message('angle:'..tostring(num)..'°')
    mp.set_property_number('options/video-rotate', num)
end

mp.add_key_binding('Ctrl+r', 'rotate_right', on_rotate_right)
mp.add_key_binding('Ctrl+Shift+r', 'rotate_left', on_rotate_left)

osd も入れて。

よし問題なく動くぞ。
macOS な人は逆回転を command+L にすれば Preview.app と同じになる。

ついでに、time-pos プロパティをゼロにすれば先頭に巻き戻しできるけど。
最後まで再生してポーズ状態からだとポーズのまま、即再生させたいのよ筆者は。

-- ~/.config/mpv/scripts/mpv_go_home.lua

-- Home キーで先頭に巻き戻して再生する
-- 最後まで再生しポーズ状態になっていても即再生できるように

function on_go_home()
    mp.set_property_number('time-pos', 0)
    if mp.get_property_bool('pause') then
        mp.set_property_bool('pause', false)
    end
end
mp.add_key_binding('Home', 'go_home_func', on_go_home)

できた。

いやいや input.conf がスッカラカンに。
自分で拡張できるアプリって面白いよね。

PHP8: match switch

そういえば PHP8 について調べなきゃ。
と書いて一ヶ月もたっていたわい。

【PHP8.0】PHP8.0の新機能 – Qiita

変更というよりひたすら機能強化みたい。
筆者に関係ありそうなのは match くらいしかないな。
str_starts_with や str_contains は正規表現でいいし。

#!/usr/bin/env php

<?php

$text = "最初含む最後";

if (preg_match('/含む/', $text)) echo "@含む@";
if (preg_match('/^最初/', $text)) echo "@最初@";
if (preg_match('/最後$/', $text)) echo "@最後@".PHP_EOL;;

//=> @含む@@最初@@最後@

?>

ね。

match は Python 3.10 にも追加されたし流行なのだろうか。
Python と同じ感じなのか試してみよう。

#!/usr/bin/env php

<?php

function switch_func($num) {
    switch($num) {
        case 1:
            echo 'one;';
            //break;
        case 1:
            echo 'once again;';
            //break;
        default:
            echo 'default;';
    }
}

function match_func($num) {
    $s = match($num) {
        1 => 'one;',
        1 => 'once again;',
        default => 'default;'
    };
    echo $s;
}

switch_func(1);
echo PHP_EOL;;
match_func(1);

/* output
one;once again;default;
one;
*/

?>

全然違った。

PHP の match は値を返す式で最後にセミコロン必須。
switch とはそもそもの書式が違うので混同するはずがない。
break が不要なのとマッチしなかった場合の処理があるのは Python と同じ。

match 式内で echo とかはできない、戻り値が必要な場面に限定される。
けれどそういう場合 if や switch より圧倒的に短いコードになるね。
Python の match もこんな感じにすれば良かったのに。

GTK4: TextView

Fedora 36 には adwaita-1-demo が最初から入っていると以前書いた。
GTK Demo(gtk4-demo) は gnome-softwere から入手できるので入れてみる。

demo

なんか勝手に 4 ヶも入ってしまったけどまあいい。
こっちはソースが直接見られるので解りやすいですね。

demo

TextView は文字列中に Widget を入れることができるのか。
よし PyGObject でやってみよう。

#!/usr/bin/env python3

import gi
gi.require_version('Gtk', '4.0')
from gi.repository import Gtk

class Win(Gtk.ApplicationWindow):
    '''
        GTK4: TextView in Button
    '''
    def __init__(self, a):
        Gtk.ApplicationWindow.__init__(self, application=a)
        # Button
        button = Gtk.Button(label='Button')
        button.connect('clicked', self.on_button_clicked)
        # TextView
        self.view = Gtk.TextView()
        buf = self.view.get_buffer()
        it = buf.get_start_iter()
        buf.insert(it, 'This')
        anchor = buf.create_child_anchor(it)
        self.view.add_child_at_anchor(button, anchor)
        buf.insert(it, 'click!')
        # pack
        sw = Gtk.ScrolledWindow()
        sw.set_child(self.view)
        self.set_child(sw)
        self.set_default_size(400, 300)

    def on_button_clicked(self, button):
        with open(__file__) as f:
            s = f.read()
            self.view.props.buffer.set_text(s)

def app_activate(a):
    w = Win(a)
    w.present()

app = Gtk.Application()
app.connect('activate', app_activate)
app.run()

demo

マジでできた、必要性は疑問だけど。
他 tag の利用方法なんかもコレで解るね。
GTK4 はこんな感じで勉強すればいいと思います。

ところで SVG エディタなんだけど。
Vectornator という Mac のアプリを使うことにしました。
M1 Mac なのに Raw 現像専用じゃもったいない。

GTK4: Clipboard

ビックリ、Fedora 36 に何故か Python2 が入っていた!

gimp

Gimp にくっ付いてきたのか、PyGtk まで。
てか Gimp で使う Python って 2 のままなのかよ。

そりゃ Gimp 自体が GTK2 だし。
GTK って今は GNU Tool Kit という意味だし。
もしかして開発止まっている?
別の SVG エディタを探すか、mac で探したほうがいいような。

ということで平日は軽く GTK4 でクリップボード。

#!/usr/bin/env python3

import gi
gi.require_version('Gtk', '4.0')
from gi.repository import Gtk, Gdk

class Win(Gtk.ApplicationWindow):
    '''
        GTK4: Clipboard Copy and Peast
    '''
    def __init__(self, a):
        Gtk.ApplicationWindow.__init__(self, application=a)
        # Copy Button
        cbutton = Gtk.Button(label='Copy')
        cbutton.connect('clicked', self.on_button_c_clicked)
        # Paste Button
        pbutton = Gtk.Button(label='Paste')
        pbutton.connect('clicked', self.on_button_p_clicked)
        # Entry
        self.entry = Gtk.Entry()
        #pack
        box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
        box.append(cbutton)
        box.append(pbutton)
        box.append(self.entry)
        self.set_child(box)

    def on_button_c_clicked(self, button):
        # entry text
        text = self.entry.get_buffer().get_text()
        clipboard = button.get_clipboard()
        clipboard.set(text)

    def on_button_p_clicked(self, button):
        clipboard = button.get_clipboard()
        clipboard.read_text_async(None, self.on_read_text_async)

    def on_read_text_async(self, clipboard, res):
        text = clipboard.read_text_finish(res)
        self.entry.get_buffer().set_text(text, -1)

def app_activate(a):
    w = Win(a)
    w.present()

app = Gtk.Application()
app.connect('activate', app_activate)
app.run()

文字列以外はあまり使わないと思うので文字列特化。

最初 init で文字列を入れようとしたけど全然駄目だった。
クリップボードは init を抜けてから操作しましょう。

GtkClipboard が GdkClipboard に代わっているけど GTK3 とほぼ同じ。
get_clipboard はどの Widget でもいいみたい、変な感じだけど。
set_text がバインドされていなくて戸惑うけど実はコレでいい。
読み込みは非同期にしないと上手くいかないみたい。

WordPress が 6.0 になった動作確認書き込みでした。

GNOME Adw

GNOME には GTK+ だけでなく Adw というものもあります。

Adw ? 1

モダンな GNOME アプリを作る GTK4 ベースな部品だそうです。
Fedora 36 にはデモアプリが最初から入っています、以下のコマンドで。

$ adwaita-1-demo

adw_demo

この demo のソースは以下にあります。

demo ? main ? GNOME / libadwaita ? GitLab

他にサンプルコードが以下にありました。

examples ? 2bf94101 ? GNOME / libadwaita ? GitLab

かなーり解り辛いです、Linux はこんなもんです。
細かいことはリンク先のソースや英語を読んでもらうとして。

#!/usr/bin/env python3

import gi
gi.require_version('Gtk', '4.0')
gi.require_version('Adw', '1')
from gi.repository import Gtk, Adw

class Win(Adw.ApplicationWindow):
    '''
        Adw: Sample Code
    '''
    def __init__(self, a):
        # Set Adwaita Style
        manager = Adw.StyleManager.get_default()
        manager.set_color_scheme(Adw.ColorScheme.DEFAULT)
        # init
        Gtk.ApplicationWindow.__init__(self, application=a)
        # TitleBar
        titlebar = Adw.HeaderBar()
        # Tab
        view = Adw.TabView()
        tabbar = Adw.TabBar(view=view, autohide=False)
        # First Page
        label = Gtk.Label(label='First Page\nPress Alt+2')
        page1 = view.append(label)
        page1.set_title('tab1')
        # Second Page
        button = Gtk.Button(label='This is Button\nShow Toast', vexpand=True, halign=Gtk.Align.START)
        button.connect('clicked', self.on_button_clicked)
        page2 = view.append(button)
        page2.set_title('tab2')
        # Toast
        self.toast = Adw.ToastOverlay(child=view)
        # pack
        box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
        box.append(titlebar)
        box.append(tabbar)
        box.append(self.toast)
        self.set_content(box)
        self.set_default_size(400, 300)

    def on_button_clicked(self, button):
        toast = Adw.Toast(title='This is a Toast Message')#, priority=Adw.ToastPriority.HIGH, timeout=0)
        self.toast.add_toast(toast)

def app_activate(a):
    w = Win(a)
    w.present()

app = Gtk.Application()
app.connect('activate', app_activate)
app.run()

色々試してみました。

adw

まず Adw.StyleManager で DEFAULT を指定します。
無くても動きますがコレをやらないとこの見た目にはなりません。

AdwWindow という GtkWindow のサブクラスがあります。
なんとタイトルバーがありません、set_titlebar 関数すら省かれている。
GtkBox と AdwHeaderBar を使えばタイトルバーは再現できるようです。
GtkHeaderBar を入れても普通に動きます。

部品設置には set_child ではなく set_content を使います。
普通に GtkWidget が配置できます、何故関数名を変えたのか解りません。
正直、存在意義がよく解らないけど理由があるんだろうなって。

Adw.TabView

AdwTabView は設置しただけでリンク先のショートカットが有効になる。
便利だけれど AdwTabBar を配置すると Ctrl+PageDown は動作しなかった。
いや普通 Alt+数値キーですよね、Google Chrome や Gedit もそうですし。

Adw.Toast

GtkOverLay を駆使するより簡単にアプリ内 Notify が可能です。
Adw.StyleManager を指定しないと背景が無い残念な Notify になる。
これは便利ですね、ただ Nautilus のように上から出せないのかな?

これ以外は demo をご覧ください。
サンプルコードはこの demo くらいしかありませんでした。