GtkSourceView Insert spaces instead of tabs

タブ幅とスペース切り替えで上手く行かなかった理由が解った。
indent-width を弄くっただけではなんか変な動作になるのね。

indent-width Property が -1 なら tab-width Property に従う。
デフォルトが -1 なので最初から tab-width のみで指定する、つまり
gtk_source_view_set_indent_width ではなく
gtk_source_view_set_tab_width で指定する。

ただ tab-width は困ったことに guint (unsignde int のマクロ) である。
ちなみに WindowsSDK でのマクロは UINT、なら最初から uint でいいのに…
C 言語を作った人達は何故こんな長い型名にしてしまったのやら。

Python ってつまり guint が無い。
型として記憶するようだし、旧文字列フォーマッタにも %u が何故かあるが。
しかし試してみると PyGI は guint を long として扱うようだ。
gint, guint の違いを long と扱って吸収するようだ。

int で型チェックを行っているモジュールに渡す場合は当然弾かれるのだが。
その場合は abs(int_value), int(uint_value) キャストでイケるみたい。
つまり我が自作の inifile8.py とかを使う場合、ココでしばし悩んだ。

gtk_source_view_set_insert_spaces_instead_of_tabs
の真偽値でタブかスペースかを切り替え。

gtk_source_view_set_indent_on_tab
の真偽値では Shift+Tab での動作。
False にすると Shift+Tab でもインデントしたり BackSpace でインデントが先頭まで削除されたりでワケが解らないよ。
思えばそんな動作をするエディタもある、私的に Shift+Tab は逆インデントが直感的だと思うのだが逆にそうなっているエディタのほうが少ないという現実。

更に GtkSpinButton を使うと値が float だったりする。
しかし面白いことに guint のまま値を突っ込むことができる。
そうなるようにバインドされているだけだが Python って簡単だね。
C 言語で同じことやっちゃダメだよ。

実際にアプリを作っている人でないと気がつきもしないだろうな。
こんなに簡単だとメモリ内でどうなっているかとかが勉強できないよ。

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

from gi.repository import Gtk, Gio, GtkSource, Pango

class TabTest(Gtk.Window):
    def __init__(self):
        Gtk.Window.__init__(self)
        # GtkSourceView
        self.view = GtkSource.View()
        desc = Pango.font_description_from_string("Monospace 11")
        self.view.override_font(desc)
        self.view.set_show_line_numbers(True)
        self.view.set_wrap_mode(Gtk.WrapMode.CHAR)
        self.view.set_draw_spaces(GtkSource.DrawSpacesFlags.ALL)
        # Tab Width
        spin = Gtk.SpinButton.new_with_range(0.0, 100.0, 1.0)
        spin.set_value(self.view.get_tab_width()) # uint to float ?
        spin.connect("value-changed", self.on_spin_changed)
        # Indent of Tab or Space
        check = Gtk.CheckButton.new_with_mnemonic("Insert _spaces instead of tabs")
        check.set_active(self.view.get_insert_spaces_instead_of_tabs())
        check.connect("toggled", self.on_toggled)
        # Test Button
        button = Gtk.Button.new_with_label("Type is Integer ?")
        button.connect("clicked", self.on_clicked)
        # pack
        vbox = Gtk.VBox()
        vbox.pack_start(self.view, True, True, 0)
        vbox.pack_start(spin, False, True, 0)
        vbox.pack_start(check, False, True, 0)
        vbox.pack_start(button, False, False, 0)
        # self
        self.add(vbox)
        self.resize(300, 300)
        self.connect("delete-event", Gtk.main_quit)
        self.show_all()
        self.set_focus(self.view)

    def on_spin_changed(self, widget, data=None):
        """
            There is no need to UINT
            self.view.set_tab_width( abs(widget.get_value_as_int()) )
        """
        self.view.set_tab_width( widget.get_value_as_int() )

    def on_toggled(self, widget, data=None):
        self.view.set_insert_spaces_instead_of_tabs(widget.get_active())

    def on_clicked(self, widget, data=None):
        """
            tab-width Type Check
        """
        value = self.view.get_tab_width()
        widget.set_label("Type is {0}".format(type(value)))

if __name__ == "__main__":
    TabTest()
    Gtk.main()

てなわけで、なんとかなった。
memopoli 0.1.1 をめでたく公開、多分自分しか使わないと思うけど。