# -*- coding: utf-8 -*-

module Plugin::Settings; end

require 'mui/gtk_form_dsl'
require 'mui/gtk_form_dsl_multi_select'
require 'mui/gtk_form_dsl_select'

require 'gtk3'

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

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

  def create_inner_setting
    self.class.new(@plugin)
  end

  def initialize(plugin)
    super()
    self.orientation = :vertical
    self.row_spacing = 12
    self.column_spacing = 12
    self.margin = 12

    type_strict plugin => Plugin
    @plugin = plugin
  end

  def [](key)
    Plugin::Settings::Listener[key].get
  end

  def []=(key, value)
    Plugin::Settings::Listener[key].set(value)
  end

  def add_event(event_name, **kwrest, &)
    kwrest[:tags] = [*kwrest[:tags], default_handler_tag]
    Plugin[:settings].add_event(event_name, **kwrest, &)
  end

  def add_event_filter(event_name, **kwrest, &)
    kwrest[:tags] = [*kwrest[:tags], default_handler_tag]
    Plugin[:settings].add_event_filter(event_name, **kwrest, &)
  end

  # マジックメソッドを追加する。
  # on_?name :: add_event(name)
  # filter_?name :: add_event_filter(name)
  def method_missing(method, *, **kwrest, &)
    method_name = method.to_s
    if method_name.start_with?('on')
      event_name = method_name[(method_name[2] == '_' ? 3 : 2)..(method_name.size)]
      add_event(event_name.to_sym, *, **kwrest, &)
    elsif method_name.start_with?('filter')
      event_name = method_name[(method_name[6] == '_' ? 7 : 6)..(method_name.size)]
      add_event_filter(event_name.to_sym, **kwrest, &)
    elsif kwrest.empty?
      super
    end
  end

  def respond_to_missing?(method, include_private)
    method_name = method.to_s
    method_name.start_with?('on') || method_name.start_with?('filter') || super
  end

  private

  def default_handler_tag
    @default_handler_tag ||= Plugin[:settings].handler_tag.tap do |tag|
      ssc(:destroy) do
        Plugin[:settings].detach(tag)
        false
      end
    end
  end
end
