File: gtk_form_dsl_select.rb

package info (click to toggle)
mikutter 5.0.4%2Bdfsg1-2
  • links: PTS, VCS
  • area: main
  • in suites: bookworm
  • size: 9,700 kB
  • sloc: ruby: 21,307; sh: 181; makefile: 19
file content (125 lines) | stat: -rw-r--r-- 3,524 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
# -*- coding: utf-8 -*-

module Gtk::FormDSL
  class SelectBuilder
    # ==== Args
    # [label_text] ラベルテキスト
    # [config_key] 設定のキー
    def initialize(formdsl, label_text, config_key, values = {}, mode: :auto)
      @formdsl = formdsl
      @label_text = label_text
      @config_key = config_key
      @options = values.to_a
      @mode = mode
    end

    # セレクトボックスに要素を追加する
    # ==== Args
    # [value] 選択されたらセットされる値
    # [text] ラベルテキスト。 _&block_ がなければ使われる。
    # [&block] Plugin::Settings のインスタンス内で評価され、そのインスタンスが内容として使われる
    def option(value, text = nil, &block)
      @options ||= []
      @options << if block
                    grid = @formdsl.create_inner_setting
                    grid.instance_eval(&block)
                    [value, text, grid].freeze
                  else
                    [value, text].freeze
                  end
      self
    end

    # optionメソッドで追加された項目をウィジェットに組み立てる
    # ==== Return
    # Array[Gtk::Widget]
    def build
      if @mode == :auto && !widget?
        build_combo
      else
        build_list
      end
    end

    def method_missing(*args, &block)
      @formdsl.method_missing(*args, &block)
    end

  private

    def widget?
      @options.any? { |_, _, w| w }
    end

    def build_combo
      label = Gtk::Label.new @label_text
      combo = Gtk::ComboBoxText.new
      @options.each { |_, text| combo.append text, text }
      _, combo.active_id = @options.find { |value,| value == @formdsl[@config_key] }
      combo.ssc :changed do
        @formdsl[@config_key], = @options[combo.active]
      end

      [label, combo]
    end

    def build_list
      list = Gtk::ListBox.new
      list.hexpand = true
      list.selection_mode = :none
      list.set_header_func do |row, before|
        before.nil? or next
        row.header = Gtk::Label.new.tap do |w|
          w.markup = "<b>#{@label_text}</b>"
          w.margin = 6
          w.margin_start = 12
          w.halign = :start
        end
      end
      list.ssc :row_activated do |_, row|
        row.child.each do |w|
          if w.is_a? Gtk::CheckButton
            w.clicked
          else
            w.can_focus? and w.has_focus = true
          end
        end
      end

      @group = Gtk::RadioButton.new
      @options.each do |value, text, widget|
        box = Gtk::Box.new(:vertical)
        box.margin = box.spacing = 12

        if widget
          # textの指定がなく、子widgetの中にLabelが1つだけ存在する場合は内容をRadioButtonに移動させる
          if text.nil?
            labels = widget.children.filter { |w| w.is_a?(Gtk::Label) }
            if labels.size == 1
              text = labels.first.label
              widget.remove(labels.first)
            end
          end
          box << build_check(value, text)

          widget.margin = 0
          widget.margin_start = 24
          box << widget
        else
          box << build_check(value, text)
        end

        list << box
      end

      [Gtk::Frame.new << list]
    end

    def build_check(value, text)
      Gtk::RadioButton.new(label: text, member: @group).tap do |w|
        @formdsl[@config_key] == value and w.active = true
        w.ssc(:toggled) { w.active? and @formdsl[@config_key] = value }
      end
    end
  end
end