File: modelviewer.rb

package info (click to toggle)
mikutter 4.1.3%2Bdfsg1-1
  • links: PTS, VCS
  • area: main
  • in suites: bullseye
  • size: 9,260 kB
  • sloc: ruby: 20,126; sh: 183; makefile: 19
file content (174 lines) | stat: -rw-r--r-- 5,766 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
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
# frozen_string_literal: true

UserConfig[:profile_icon_size] ||= 48
UserConfig[:profile_icon_margin] ||= 4

Plugin.create :modelviewer do
  defdsl :defmodelviewer do |model_class, &block|
    model_class = Diva::Model(model_class) unless model_class.is_a?(Class)
    filter_modelviewer_models do |models|
      models << model_class.spec
      [models]
    end
    intent(model_class,
           label: _('%{model}の詳細') % {model: model_class.spec&.name || model_class.name},
           slug: :"modelviewer:#{model_class.slug}"
          ) do |token|
      model = token.model
      tab_slug = :"modelviewer:#{model_class.slug}:#{model.uri.hash}"
      cluster_slug = :"modelviewer-cluster:#{model_class.slug}:#{model.uri.hash}"
      if Plugin::GUI::Tab.exist?(tab_slug)
        Plugin::GUI::Tab.instance(tab_slug).active!
      else
        tab(tab_slug, _('%{title}について') % {title: model.title}) do
          set_icon model.icon if model.respond_to?(:icon)
          set_deletable true
          temporary_tab true
          shrink
          nativewidget Plugin[:modelviewer].header(token, &block)
          expand
          Plugin[:modelviewer].cluster_initialize(model, cluster(cluster_slug))
          active!
        end
      end
    end
  end

  # プロフィールタブを定義する
  # ==== Args
  # [slug] タブスラッグ
  # [title] タブのタイトル
  defdsl :deffragment do |model_class, slug, title=slug.to_s, &block|
    model_class = Diva::Model(model_class) unless model_class.is_a?(Class)
    add_event_filter(:"modelviewer_#{model_class.slug}_fragments") do |tabs, model|
      i_fragment = Plugin::GUI::Fragment.instance(:"modelviewer-fragment:#{slug}:#{model.uri}", title)
      i_fragment.instance_eval_with_delegate(self, model, &block)
      tabs << i_fragment
      [tabs, model]
    end
  end

  on_gui_child_reordered do |i_cluster, i_fragment, order|
    kind, = i_fragment.slug.to_s.split(':', 2)
    if kind == 'modelviewer-fragment'
      _, cluster_kind, = i_cluster.slug.to_s.split(':', 3)
      store("order-#{cluster_kind}", i_cluster.children.map { |f| f.slug.to_s.split(':', 3)[1] })
    end
  end

  def cluster_initialize(model, i_cluster)
    _, cluster_kind, = i_cluster.slug.to_s.split(':', 3)
    order = at("order-#{cluster_kind}", [])
    fragments = Plugin.collect(:"modelviewer_#{model.class.slug}_fragments", Pluggaloid::COLLECT, model).sort_by { |i_fragment|
      _, fragment_kind, = i_fragment.slug.to_s.split(':', 3)
      order.index(fragment_kind) || Float::INFINITY
    }.to_a
    fragments.each(&i_cluster.method(:add_child))
    fragments.first&.active!
  end

  def header(intent_token, &column_generator)
    model = intent_token.model
    eventbox = ::Gtk::EventBox.new
    eventbox.ssc(:visibility_notify_event){
      eventbox.style = background_color
      false
    }

    icon_alignment = Gtk::Alignment.new(0.5, 0, 0, 0)
                       .set_padding(*[UserConfig[:profile_icon_margin]]*4)

    eventbox.add(
      ::Gtk::VBox.new(false, 0).
        add(
          ::Gtk::HBox.new
            .closeup(icon_alignment.add(model_icon(model)))
            .add(
              ::Gtk::VBox.new
                .closeup(title_widget(model, intent_token))
                .closeup(header_table(model, column_generator.(model)))
            )
        )
    )
  end

  def model_icon(model)
    return ::Gtk::EventBox.new unless model.respond_to?(:icon)
    icon = ::Gtk::EventBox.new.add(::Gtk::WebIcon.new(model.icon, UserConfig[:profile_icon_size], UserConfig[:profile_icon_size]).tooltip(_('アイコンを開く')))
    icon.ssc(:button_press_event) do |this, event|
      Plugin.call(:open, model.icon)
      true
    end
    icon.ssc(:realize) do |this|
      this.window.set_cursor(Gdk::Cursor.new(Gdk::Cursor::HAND2))
      false
    end
    icon
  end

  # modelのtitleを表示する
  # ==== Args
  # [model] 表示するmodel
  # [intent_token] ユーザを開くときに利用するIntent
  # ==== Return
  # ユーザの名前の部分のGtkコンテナ
  def title_widget(model, intent_token)
    score = [
      Plugin::Score::HyperLinkNote.new(
        description: model.title,
        uri: model.uri
      )
    ]
    ::Gtk::IntelligentTextview.new(score, style: style)
  end

  # modelのtitleを表示する
  # ==== Args
  # [model] 表示するmodel
  # [intent_token] ユーザを開くときに利用するIntent
  # ==== Return
  # ユーザの名前の部分のGtkコンテナ
  def cell_widget(model_or_str)
    case model_or_str
    when Diva::Model
      ::Gtk::IntelligentTextview.new(
        Plugin[:modelviewer].score_of(model_or_str),
        style: style
      )
    else
      ::Gtk::IntelligentTextview.new(model_or_str.to_s, style: style)
    end
  end

  def header_table(model, header_columns)
    ::Gtk::Table.new(2, header_columns.size).tap{|table|
      header_columns.each_with_index do |column, index|
        key, value = column
        table.
          attach(::Gtk::Label.new(key.to_s).right, 0, 1, index, index+1).
          attach(cell_widget(value), 1, 2, index, index+1)
      end
    }.set_row_spacing(0, 4).
      set_row_spacing(1, 4).
      set_column_spacing(0, 16)
  end

  def style
    -> do
      Gtk::Style.new().tap do |bg_style|
        color = UserConfig[:mumble_basic_bg]
        bg_style.set_bg(Gtk::STATE_ACTIVE, *color)
        bg_style.set_bg(Gtk::STATE_NORMAL, *color)
        bg_style.set_bg(Gtk::STATE_SELECTED, *color)
        bg_style.set_bg(Gtk::STATE_PRELIGHT, *color)
        bg_style.set_bg(Gtk::STATE_INSENSITIVE, *color)
      end
    end
  end

  def background_color
    style = ::Gtk::Style.new()
    style.set_bg(::Gtk::STATE_NORMAL, 0xFF ** 2, 0xFF ** 2, 0xFF ** 2)
    style
  end
end