aboutsummaryrefslogtreecommitdiffstats
path: root/core/addon/settings/builder.rb
blob: 99d984c79316f9b8592aa5a3facf683d0f59333b (plain)
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
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
# -*- coding: utf-8 -*-

miquire :core, 'plugin'

require 'gtk2'

=begin rdoc
プラグインに、簡単に設定ファイルを定義する機能を提供する。
以下の例は、このクラスを利用してプラグインの設定画面を定義する例。
  Plugin.create(:test) do
    settings("設定") do
      boolean "チェックする", :test_check
    end
  end

settingsの中身は、 Plugin::Setting のインスタンスの中で実行される。
つまり、 Plugin::Setting のインスタンスメソッドは、 _settings{}_ の中で実行できるメソッドと同じです。
例ではbooleanメソッドを呼び出して、真偽値を入力させるウィジェットを配置させるように定義している
(チェックボックス)。明確にウィジェットを設定できるわけではなくて、値の意味を定義するだけなので、
前後関係などに影響されてウィジェットが変わる場合があるかも。
=end
class Plugin::Setting < Gtk::VBox

  # 複数行テキスト
  # ==== Args
  # [label] ラベル
  # [config] 設定のキー
  def multitext(label, config)
    container = Gtk::HBox.new(false, 0)
    input = Gtk::TextView.new
    input.wrap_mode = Gtk::TextTag::WRAP_CHAR
    input.border_width = 2
    input.accepts_tab = false
    input.editable = true
    input.width_request = HYDE
    input.buffer.text = Listener[config].get || ''
    container.pack_start(Gtk::Label.new(label), false, true, 0) if label
    container.pack_start(Gtk::Alignment.new(1.0, 0.5, 0, 0).add(input), true, true, 0)
    input.buffer.ssc('changed'){ |widget|
      Listener[config].set widget.text }
    closeup container
    container
  end

  # 特定範囲の数値入力
  # ==== Args
  # [label] ラベル
  # [config] 設定のキー
  # [min] 最低値。これより小さい数字は入力できないようになる
  # [max] 最高値。これより大きい数字は入力できないようになる
  def adjustment(name, config, min, max)
    container = Gtk::HBox.new(false, 0)
    container.pack_start(Gtk::Label.new(name), false, true, 0)
    adj = Gtk::Adjustment.new((Listener[config].get or min), min*1.0, max*1.0, 1.0, 5.0, 0.0)
    spinner = Gtk::SpinButton.new(adj, 0, 0)
    adj.signal_connect('value-changed'){ |widget, e|
      Listener[config].set widget.value.to_i
      false
    }
    closeup container.pack_start(Gtk::Alignment.new(1.0, 0.5, 0, 0).add(spinner), true, true, 0)
    container
  end

  # 真偽値入力
  # ==== Args
  # [label] ラベル
  # [config] 設定のキー
  def boolean(label, config)
    input = Gtk::CheckButton.new(label)
    input.active = Listener[config].get
    input.signal_connect('toggled'){ |widget|
      Listener[config].set widget.active? }
    closeup input
    input end

  # ファイルを選択する
  # ==== Args
  # [label] ラベル
  # [config] 設定のキー
  # [current] 初期のディレクトリ
  def fileselect(label, config, current=Dir.pwd)
    container = input(label, config)
    input = container.children.last.children.first
    button = Gtk::Button.new('参照')
    container.pack_start(button, false)
    button.signal_connect('clicked'){ |widget|
      dialog = Gtk::FileChooserDialog.new("Open File",
                                          widget.get_ancestor(Gtk::Window),
                                          Gtk::FileChooser::ACTION_OPEN,
                                          nil,
                                          [Gtk::Stock::CANCEL, Gtk::Dialog::RESPONSE_CANCEL],
                                          [Gtk::Stock::OPEN, Gtk::Dialog::RESPONSE_ACCEPT])
      dialog.current_folder = File.expand_path(current)
      if dialog.run == Gtk::Dialog::RESPONSE_ACCEPT
        Listener[config].set dialog.filename
        input.text = dialog.filename
      end
      dialog.destroy
    }
    container
  end

  # 一行テキストボックス
  # ==== Args
  # [label] ラベル
  # [config] 設定のキー
  def input(label, config)
    container = Gtk::HBox.new(false, 0)
    input = Gtk::Entry.new
    input.text = Listener[config].get || ""
    container.pack_start(Gtk::Label.new(label), false, true, 0) if label
    container.pack_start(Gtk::Alignment.new(1.0, 0.5, 0, 0).add(input), true, true, 0)
    input.signal_connect('changed'){ |widget|
      Listener[config].set widget.text }
    closeup container
    container
  end

  # 一行テキストボックス(非表示)
  # ==== Args
  # [label] ラベル
  # [config] 設定のキー
  def inputpass(label, config)
    container = Gtk::HBox.new(false, 0)
    input = Gtk::Entry.new
    input.visibility = false
    input.text = Listener[config].get
    container.pack_start(Gtk::Label.new(label), false, true, 0) if label
    container.pack_start(Gtk::Alignment.new(1.0, 0.5, 0, 0).add(input), true, true, 0)
    input.signal_connect('changed'){ |widget|
      Listener[config].set widget.text }
    closeup container
    container
  end

  # 設定のグループ。関連の強い設定をカテゴライズできる。
  # ==== Args
  # [title] ラベル
  # [&block] ブロック
  def settings(title)
    group = Gtk::Frame.new.set_border_width(8)
    if(title.is_a?(Gtk::Widget))
      group.set_label_widget(title)
    else
      group.set_label(title) end
    box = Plugin::Setting.new.set_border_width(4)
    box.instance_eval(&Proc.new)
    closeup group.add(box)
    group
  end

  # 〜についてダイアログを出すためのボタン。押すとダイアログが出てくる
  # ==== Args
  # [label] ラベル
  # [options]
  #   設定値。以下のキーを含むハッシュ。
  #   _:name_ :: ソフトウェア名
  #   _:version_ :: バージョン
  #   _:copyright_ :: コピーライト
  #   _:comments_ :: コメント
  #   _:license_ :: ライセンス
  #   _:website_ :: Webページ
  #   _:logo_ :: ロゴ画像のフルパス
  #   _:authors_ :: 作者の名前。通常Twitter screen name(Array)
  #   _:artists_ :: デザイナとかの名前。通常Twitter screen name(Array)
  #   _:documenters_ :: ドキュメントかいた人とかの名前。通常Twitter screen name(Array)
  def about(label, options={})
    about = Gtk::Button.new("#{Environment::NAME} について")
    about.signal_connect("clicked"){
      dialog = Gtk::AboutDialog.new.show
      options.each { |key, value|
        dialog.__send__("#{key}=", about_converter[key][value]) }
      dialog.signal_connect('response') { dialog.destroy } }
    closeup about
    about end

  # フォントを決定させる。押すとフォント、サイズを設定するダイアログが出てくる。
  # ==== Args
  # [label] ラベル
  # [config] 設定のキー
  def font(label, config)
    closeup container = Gtk::HBox.new(false, 0).add(Gtk::Label.new(label).left).closeup(fontselect(label, config))
    container end

  # 色を決定させる。押すと色を設定するダイアログが出てくる。
  # ==== Args
  # [label] ラベル
  # [config] 設定のキー
  def color(label, config)
    closeup container = Gtk::HBox.new(false, 0).add(Gtk::Label.new(label).left).closeup(colorselect(label, config))
    container end

  # フォントと色を決定させる。
  # ==== Args
  # [label] ラベル
  # [font] フォントの設定のキー
  # [color] 色の設定のキー
  def fontcolor(label, font, color)
    closeup container = font(label, font).closeup(colorselect(label, color))
    container end

  # 要素を1つ選択させる
  # ==== Args
  # [label] ラベル
  # [config] 設定のキー
  # [default]
  #   連想配列で、 _値_ => _ラベル_ の形式で、デフォルト値を与える。
  #   _block_ と同時に与えれられたら、 _default_ の値が先に入って、 _block_ は後に入る。
  # [&block] 内容
  def select(label, config, default = {})
    builder = Plugin::Setting::Select.new(default)
    builder.instance_eval(&Proc.new) if block_given?
    closeup container = builder.build(label, config)
    container end

  private
  def about_converter
    Hash.new(ret_nth).merge!( :logo => lambda{ |value| Gtk::WebIcon.new(value).pixbuf rescue nil } ) end
  memoize :about_converter

  def colorselect(label, config)
    color = Listener[config].get
    button = Gtk::ColorButton.new((color and Gdk::Color.new(*color)))
    button.title = label
    button.signal_connect('color-set'){ |w|
      Listener[config].set w.color.to_a }
    button end

  def fontselect(label, config)
    button = Gtk::FontButton.new(Listener[config].get)
    button.title = label
    button.signal_connect('font-set'){ |w|
      Listener[config].set w.font_name }
    button end

end

require File.expand_path File.join(File.dirname(__FILE__), 'select')
require File.expand_path File.join(File.dirname(__FILE__), 'listener')