月別アーカイブ: 2009年5月

ラジオメニューとトグルボタンの同期

Y901x 0.1.2 公開しました。
こんな Windows 用のノリでやっていても良いものかと思い始めた今日この頃。

っっって…指定倍率変更の計算が間違えているのに今気がついた!
せっかくまとめて listbox クラスにしたのにセパレータサイズを足していた。
あーあ明日もごまかすために更新だ、更新が特定期間に集中する原因はコレです。

ところで。

ラジオメニューとトグルボタンは UIManager から同期させられないっぽい。
と以前書いたけどツールバーならあっさりできるようで。

#!/usr/bin/env python
#-*- coding:utf-8 -*-

import gtk

ui_str = """<ui>
    <menubar name="MenuBar">
        <menu action="Rep">
            <menuitem action="non"/>
            <menuitem action="one"/>
            <menuitem action="all"/>
            <menuitem action="rdm"/>
        </menu>
    </menubar>
    <toolbar name="Toolbar">
        <toolitem action="one"/>
        <toolitem action="all"/>
        <toolitem action="rdm"/>
    </toolbar>
</ui>"""

class BtnBox(gtk.Window):
    def __init__(self):
        gtk.Window.__init__(self)
        #
        # GtkUIManager 作成
        self.uimanager = gtk.UIManager()
        #
        # GtkActionGroup 作成
        self.actiongroup = gtk.ActionGroup("sasakimamenu")
        #
        # GtkAccelGroup を得てウインドウに突っ込む
        # 何もグループを作らなくてもコレやらないと後のアクセラレータ指定が効かない
        accelgroup = self.uimanager.get_accel_group()
        self.add_accel_group(accelgroup)
        #
        # GtkActionEntry を作成して突っ込む
        # 得にグループにしないものはココでまとめて作成
        # name, stock_id, label, accelerator, tooltip, callback
        self.ac0 = [("Rep", None, "リピート(_R)")]
        self.actiongroup.add_actions(self.ac0)
        #
        # GtkRadioActionEntry の List を作成
        # name, stock_id, label, accelerator, tooltip, value
        self.ac1 = [("non", None, "無し", "0", "無し", 0),
                    ("one", None, "シングル", "1", "シングル", 1),
                    ("all", None, "オール", "2", "オール", 2),
                    ("rdm", None, "ランダム", "3", "ランダム", 3) ]
        # GtkRadioAction を突っ込む
        # entries, value=0, on_change=None, user_data=None
        self.actiongroup.add_radio_actions(self.ac1, 0, self.on_loop_change)
        #
        # GtkUIManager の更新
        self.uimanager.insert_action_group(self.actiongroup, 0)
        self.uimanager.add_ui_from_string(ui_str)
        self.uimanager.ensure_update()
        # menubar を抜き出す
        menubar = self.uimanager.get_widget("/MenuBar")
        # toolbar を抜き出す
        toolbar = self.uimanager.get_widget('/Toolbar')
        # pack
        vbox = gtk.VBox()
        vbox.pack_start(menubar, False)
        vbox.pack_start(toolbar, False,False)
        self.add(vbox)
        self.connect("delete-event", gtk.main_quit)
        self.resize(320, 150)
        self.show_all()
        self.val = 0

    def on_loop_change(self, action, current):
        # コレは無理だった
        num = action.get_current_value()
        if num == self.val:
            action.set_current_value(0)
        else:
            self.val = num

if __name__ == "__main__":
    w = BtnBox()
    gtk.main()

repeat

得に何をするわけでもなく action を共通にすれば同期してくれるわ。
だけどアクティブなボタンを再度押すとオフにするといった処理は無理か。
ボタンオブジェクトを抜いて clicked シグナルを処理すればよさげだけど。

コレ上手く使えないかな?いまここ。

Linux のゴミ箱

Y901x 0.1.1 バグ修正を公開しました。
ココにリネーム方法を書いたのに少し書き換えた私がアホだった…

ところで

何を今頃気がついたが os.remove でファイル削除するとゴミ箱に入らずに消滅する。
そういえば UNIX には元々ゴミ箱なんて無かった、つーか rm で削除すると消滅ですがな。

何か Nautilus に慣れてしまってゴミ箱に入るものだとうっかりしていた。
Windows ShellAPI の SHFileOperation みたいな方法は無いのだろうか?

ちなみに Ubuntu のゴミ箱に捨てたファイルは以下にある。

~/.local/share/Trash/files

しかし調べてみるとディストリビューションによって下記もあるようで。

~/.Trash
~/.Trash-0

ゴミ箱 – Wikipedia

規格の範囲でファイルマネージャ毎に決めているっぽい。
FreeDesktop.org での規格なら xdg-trash とか、無いか…

Ubuntu — Details of package xdg-utils in jaunty

ついでに、メニューのインストールには xdg-desktop-menu を本当は使わなきゃいけないのね。
make や dpkg は勝手にそれをやってくれるということでいいのかな。
Y901x のインストールスクリプトは言うまでもなく直で突っ込んでいる、知らなかったよ。
Ubuntu 限定に近いから別にイイんだが真似しないほうがいいよあの方法は。

Ubuntu日本語フォーラム / HOWTO: CLIからゴミ箱を使う

こういうのがあるのか。
端末からゴミ箱利用はかなり微妙だけど保険にはなるかも。
間違えて Blog の画像を全部消したコトがある私はそう思う。
でもレンタルサーバーで FTP ソフトを使ったら全く意味が無いとも。

コレをインストールしてもらえば…だからソレはやりたくない。
よし決めた、面倒だから当面は消滅のままでいいや!これが私の(略

GTK+ はキーの長押しを認識できないようで

Y901 というアプリは上下矢印キーの長押しでリスト選択位置の移動のみを行っていた。
キーを離し WM_KEYUP メッセージを捕まえた所で選択位置のファイルを再生開始していた。
当然 Y901x でもそうしたいわけだ。

しかし…とにかくコレを動かして上下どちらかの矢印キーを押しっ放しにしてみる。

#!/usr/bin/env python
#-*- coding:utf-8 -*-

import gtk

class KeyUpDown(gtk.Window):
    def __init__(self):
        gtk.Window.__init__(self)
        self.tv = gtk.TextView()
        sw = gtk.ScrolledWindow()
        sw.set_policy(gtk.POLICY_NEVER, gtk.POLICY_AUTOMATIC)
        sw.add(self.tv)
        self.add(sw)
        # GDK イベントの有効化を行っておく
        self.set_events(gtk.gdk.KEY_PRESS_MASK | gtk.gdk.KEY_RELEASE_MASK)
        self.connect("key_press_event", self.on_key_press)
        self.connect("key_release_event", self.on_key_release)
        self.connect("delete-event", gtk.main_quit)
        self.resize(300, 400)
        self.show_all()

    def on_key_press(self, widget, event):
        if event.keyval == 65362 or event.keyval == 65364:
            buf = self.tv.get_buffer()
            s = "押した\n"
            it = buf.get_end_iter()
            buf.insert(it, s, len(s))

    def on_key_release(self, widget, event):
        if event.keyval == 65362 or event.keyval == 65364:
            buf = self.tv.get_buffer()
            s = "離した\n"
            it = buf.get_end_iter()
            buf.insert(it, s, len(s))

if __name__ == "__main__":
    w = KeyUpDown()
    gtk.main()

updown

つまり key_press_event シグナルは必ず key_release_event シグナルと交互に発生する。
Windows のように WM_KEYDOWN イベントのみが起こるというわけではないようだ。
キーを離し WM_KEYUP メッセージを捕まえるように key_release_event を…

できない!

まいった、何か方法を見つけるまで今までどうり一つ上下移動のみにするしかない。
つーかこの現実が解るまで「あれぇ?なんで???」と苦しんだ私であった。

それとラジオメニューとトグルボタンは UIManager から同期させられないっぽい。
しかたがないのでリピート用のトグルボタンを排除するという暴挙で解決!
パッと見て状態が解ればいいんだからステータスバーに表示、これが私のクオリティ。

追記、長押し判定する方法がありました
GTK+ Cancel Long Keypress | PaePoi

PopupMenu と MouseGesture の同居に困った

PopupMenu と MouseGesture の同居に困った

GTK+ のアプリは基本的にマウスの右ボタンダウンでポップアップメニューが出る。
しかしもはや Linux 標準アプリになった Firefox はボタンアップで出る。
マウスジェスチャ機能があるからだ、当然 Opera も同様。

ということで違和感が無い人も多いと思うので遠慮なくボタンアップでポップアップを実装
…しようとしたんだけど完全な振り分け方法を思いつけなくてココだけで半日使った。

popup

まあとにかくここは上手くいったと思う、やはりデカいので入れ子にしたのは妥協だ。

しかし困った、入れ子のメニューは何故か右クリック時しかシグナルを吐いてくれない。
入れ子にしていないメニューは左クリックでもキチンとシグナルを吐くのにどういうこと?

GTK+ 製である Firefox はどうだ…ってコイツの右メニューには入れ子が無かったわ。
Totem で試すとしっかり右クリックで入れ子にも反応する、ますます解らなくなったぞ。
実装方法が変わると違うかも…何か方法があるはずだがよく解らない。

そうそう、試しに右ボタンダウンで出すように実装したら普通にシグナルを吐く。
どういうことかはバックアップしているのを試すと解ると思う。

それと画面 W クリックでフルスクリーンだが。
右メニューやダイアログを出しフォーカスが移ると GNOME メニューがコンニチハ。
これはどうすれば防げるか、Totem はそんなの出ないんだよなぁ…

gtk.gdk.Window

GDK にも何故か fullscreen メソッドがあるんだがもう何がなんだか解らん。
試しに入れてみたけど違いが無いみたいだけど。

せっかくリピートメニューと RadioAction を作ったのに実装する時間がなかったわい。
バックアップを置いておきますんで、くそぉ進まなかった。

y901x-buckup2.zip

GtkDialog 上の GtkEntry で Enter して OK に

GtkDialog 上の GtkEntry で Enter したら OK ということにしたい。
あれ?なんかウイジェットのデフォルト機能ではできないっぽいんですけど。
実は方法があるかもしれないけど自分で作って上手く言った例を貼っておく。
単に GtkEntry の activate シグナルを処理しているだけですけど。

その前に説明が必要だろうけど Y901x にリネーム機能を付ける。
Windows 版 Y901 と同じ方法です、ダイアログを出して名前変更して Enter。
という流れにしたいんだが方法が見つからなかったのでやってみたということで。

よく考えると GTK+ アプリはダイアログの値変更を即摘要という感じなのが多い。
Linux 屋はそういう方向を好むのかな?乗り換え組には結構違和感がある。

右クリックメニューもマウスボタンダウンで出るし、でも慣れると素早い操作ができて楽。
逆に慣れてしまって Windows を使う時に間違えてしかたがない。

つーことで、自分が使っているアトリビュートな変数名とかはそのまんまだけどこんな。
Python は関数内に関数が入れられるから一つの関数に収められて便利だよね。

def rename(self):
    if self.p_filename == "":
        return
    name = self.p_filename
    label = gtk.Label()
    label.set_text(self.p_filename)
    entry = gtk.Entry()
    entry.set_text(self.p_filename)
    d = gtk.Dialog( "リネーム",
                    self.w,
                    gtk.DIALOG_MODAL,# | gtk.DIALOG_DESTROY_WITH_PARENT,
                    (gtk.STOCK_CANCEL, gtk.RESPONSE_REJECT,
                    gtk.STOCK_OK, gtk.RESPONSE_ACCEPT) )
    d.vbox.pack_start(label, False)
    d.vbox.pack_start(entry, False)
    d.show_all()
    # GtkEntry にて Enter キーで OK ボタンを押す処理
    def dlg_ok(self):
        d.response(gtk.RESPONSE_ACCEPT)
    entry.connect("activate", dlg_ok)
    # 再生中ならポーズ、リピート中だと次に行ってしまう
    is_play = False
    if self.player.get_state(1)[1] == gst.STATE_PLAYING:
        is_play = True
        self.player.set_state(gst.STATE_PAUSED)
    # 開始
    if d.run() == gtk.RESPONSE_ACCEPT:
        text = entry.get_text()
        if text == self.p_filename:
            self.messagebox("変更されていません")
        else:
            if  text in os.listdir(self.p_path):
                self.messagebox("同一ファイル名が見つかりました")
            else:
                newname = self.p_path + "/" + text
                self.clear()
                while gtk.events_pending():
                    gtk.main_iteration()
                os.rename(self.p_path + "/" + self.p_filename, newname)
                while gtk.events_pending():
                    gtk.main_iteration()
                self.set_uri("file://" + newname)
    d.destroy()
    if is_play:
        self.player.set_state(gst.STATE_PLAYING)

koion

○いおんってこんな話か…微妙だ。
出てくる名前がジミヘンとかベック…まあ作る人見る人もソッチ系じゃないのでベタになるか。
せめてランディ・ローズあたりの名が出りゃ面白…という私はおっさんだが Dee は名曲だぞ。

YouTube – dee- randy rhoads (studio out-takes)

って話が違いすぎるので置いておいて。
とりあえず今日作れたとこまでをココにバックアップ、明日には出せるかな?
なんたってシーゲイトの HDD をまだ使っていますんで、今の所なんともないなぁ、、、、、
Wordpress は tar.gz で Upload すると何故か tar の前の拡張子が消滅するので zip にて。

y901x-buckup1.zip