From cd5e3326388ac53854590199370ed59b97fd08d6 Mon Sep 17 00:00:00 2001 From: moguno Date: Sun, 3 Jan 2016 12:22:38 +0900 Subject: [PATCH] =?UTF-8?q?SubPartsQuote=E3=81=AE=E6=8F=8F=E7=94=BB?= =?UTF-8?q?=E9=83=A8=E5=88=86=E3=82=92=E3=83=99=E3=83=BC=E3=82=B9=E3=82=AF?= =?UTF-8?q?=E3=83=A9=E3=82=B9=E3=81=AB=E5=88=87=E3=82=8A=E5=87=BA=E3=81=97?= =?UTF-8?q?=E3=81=A6=E4=BB=96=E3=81=8B=E3=82=89=E3=82=82=E4=BD=BF=E3=81=88?= =?UTF-8?q?=E3=82=8B=E3=82=88=E3=81=86=E3=81=AB=E3=81=97=E3=81=9F=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- core/mui/cairo_sub_parts_message_base.rb | 150 +++++++++++++++++++++++++++++++ core/mui/cairo_sub_parts_quote.rb | 146 +++--------------------------- 2 files changed, 161 insertions(+), 135 deletions(-) create mode 100644 core/mui/cairo_sub_parts_message_base.rb diff --git a/core/mui/cairo_sub_parts_message_base.rb b/core/mui/cairo_sub_parts_message_base.rb new file mode 100644 index 0000000..5290bd2 --- /dev/null +++ b/core/mui/cairo_sub_parts_message_base.rb @@ -0,0 +1,150 @@ +# -*- coding: utf-8 -*- + +require 'gtk2' +require 'cairo' + +# ナウい引用っぽくメッセージを作るサブパーツのベースクラス +# 継承して使おう +class Gdk::SubPartsMessageBase < Gdk::SubParts + attr_reader :icon_width, :icon_height + + # サブクラスでMessagesを返すように実装すること + # このメソッドはサブパーツの描画中に何回も呼ばれるので、キャッシュなどで高速化に努めてください + def messages + nil end + + # サブクラスで領域をクリックした時の処理を実装すること + def on_click(this, e, x, y, message) + end + + def initialize(*args) + super + @icon_width, @icon_height, @margin, @edge = 32, 32, 2, 8 end + + def render_messages + if not helper.destroyed? + helper.on_modify + helper.reset_height + helper.ssc(:click) { |this, e, x, y| + ofsty = helper.mainpart_height + helper.subparts.each { |part| + break if part == self + ofsty += part.height } + if ofsty <= y and (ofsty + height) >= y + my = 0 + messages.each { |m| + my += message_height(m) + if y <= ofsty + my + on_click(e, m) + break end } end } end end + + def render(context) + if messages and not messages.empty? + messages.inject(0) { |base_y, message| + render_single_message(message, context, base_y) } end end + + def height + if not helper.destroyed? and messages and not messages.empty? + messages.inject(0) { |s, m| s + message_height(m) } + else + 0 end end + + private + + def render_single_message(message, context, base_y) + render_outline(message, context, base_y) + render_header(message, context, base_y) + context.save { + context.translate(@margin + @edge, @margin + @edge + base_y) + context.set_source_pixbuf(main_icon(message)) + context.paint + context.translate(icon_width + @margin*2, header_left(message).size[1] / Pango::SCALE) + context.set_source_rgb(*([0,0,0]).map{ |c| c.to_f / 65536 }) + context.show_pango_layout(main_message(message, context)) } + + base_y + message_height(message) end + + def message_height(message) + [icon_height, (header_left(message).size[1] + main_message(message).size[1]) / Pango::SCALE].max + (@margin + @edge) * 2 + end + + # ヘッダ(左)のための Pango::Layout のインスタンスを返す + def header_left(message, context = dummy_context) + attr_list, text = Pango.parse_markup("#{Pango.escape(message[:user][:idname])} #{Pango.escape(message[:user][:name] || '')}") + layout = context.create_pango_layout + layout.attributes = attr_list + layout.font_description = Pango::FontDescription.new(UserConfig[:mumble_basic_font]) + layout.text = text + layout end + + # ヘッダ(右)のための Pango::Layout のインスタンスを返す + def header_right(message, context = dummy_context) + now = Time.now + hms = if message[:created].year == now.year && message[:created].month == now.month && message[:created].day == now.day + message[:created].strftime('%H:%M:%S'.freeze) + else + message[:created].strftime('%Y/%m/%d %H:%M:%S'.freeze) + end + attr_list, text = Pango.parse_markup("#{Pango.escape(hms)}".freeze) + layout = context.create_pango_layout + layout.attributes = attr_list + layout.font_description = Pango::FontDescription.new(UserConfig[:mumble_basic_font]) + layout.text = text + layout.alignment = Pango::ALIGN_RIGHT + layout end + + def render_header(message, context, base_y) + header_w = width - @icon_width - @margin*3 - @edge*2 + context.save{ + context.translate(@icon_width + @margin*2 + @edge, @margin + @edge + base_y) + context.set_source_rgb(0,0,0) + hl_layout, hr_layout = header_left(message, context), header_right(message, context) + context.show_pango_layout(hl_layout) + context.save{ + context.translate(header_w - hr_layout.size[0] / Pango::SCALE, 0) + if (hl_layout.size[0] / Pango::SCALE) > header_w - hr_layout.size[0] / Pango::SCALE - 20 + r, g, b = get_backgroundcolor + grad = Cairo::LinearPattern.new(-20, base_y, hr_layout.size[0] / Pango::SCALE + 20, base_y) + grad.add_color_stop_rgba(0.0, r, g, b, 0.0) + grad.add_color_stop_rgba(20.0 / (hr_layout.size[0] / Pango::SCALE + 20), r, g, b, 1.0) + grad.add_color_stop_rgba(1.0, r, g, b, 1.0) + context.rectangle(-20, base_y, hr_layout.size[0] / Pango::SCALE + 20, hr_layout.size[1] / Pango::SCALE + base_y) + context.set_source(grad) + context.fill() end + context.show_pango_layout(hr_layout) } } + end + + def main_message(message, context = dummy_context) + attr_list, text = Pango.parse_markup(Pango.escape(message.to_show)) + layout = context.create_pango_layout + layout.width = (width - @icon_width - @margin*3 - @edge*2) * Pango::SCALE + layout.attributes = attr_list + layout.wrap = Pango::WRAP_CHAR + layout.font_description = Pango::FontDescription.new(UserConfig[:mumble_reply_font]) + layout.text = text + layout end + + def render_outline(message, context, base_y) + mh = message_height(message) + context.save { + context.pseudo_blur(4) { + context.fill { + context.set_source_rgb(*([32767, 32767, 32767]).map{ |c| c.to_f / 65536 }) + context.rounded_rectangle(@edge, @edge + base_y, width - @edge*2, mh - @edge*2, 4) + } + } + context.fill { + context.set_source_rgb(*([65535, 65535, 65535]).map{ |c| c.to_f / 65536 }) + context.rounded_rectangle(@edge, @edge + base_y, width - @edge*2, mh - @edge*2, 4) + } + } + end + + def main_icon(message) + Gdk::WebImageLoader.pixbuf(message[:user][:profile_image_url], icon_width, icon_height){ |pixbuf| + helper.on_modify } end + + def get_backgroundcolor + [1.0, 1.0, 1.0] + end +end diff --git a/core/mui/cairo_sub_parts_quote.rb b/core/mui/cairo_sub_parts_quote.rb index e361693..9612292 100644 --- a/core/mui/cairo_sub_parts_quote.rb +++ b/core/mui/cairo_sub_parts_quote.rb @@ -1,152 +1,28 @@ # -*- coding: utf-8 -*- -miquire :mui, 'sub_parts_voter' +miquire :mui, 'sub_parts_message_base' require 'gtk2' require 'cairo' -class Gdk::SubPartsQuote < Gdk::SubParts +class Gdk::SubPartsQuote < Gdk::SubPartsMessageBase register - attr_reader :icon_width, :icon_height + def messages + @messages end + + def on_click(e, message) + case e.button + when 1 + Plugin.filtering(:command, {}).first[:smartthread][:exec].call(Struct.new(:messages).new([message])) + end end def initialize(*args) super - @icon_width, @icon_height, @margin, @edge = 32, 32, 2, 8 if helper.message.quoting? Thread.new(helper.message) { |m| m.quoting_messages(true) }.next{ |quoting| @messages = Messages.new(quoting).freeze render_messages - }.terminate('コメント付きリツイート描画中にエラーが発生しました') end end - - def render_messages - if not helper.destroyed? - helper.on_modify - helper.reset_height - helper.ssc(:click) { |this, e, x, y| - ofsty = helper.mainpart_height - helper.subparts.each { |part| - break if part == self - ofsty += part.height } - if ofsty <= y and (ofsty + height) >= y - case e.button - when 1 - my = 0 - @messages.each { |m| - my += message_height(m) - if y <= ofsty + my - Plugin.filtering(:command, {}).first[:smartthread][:exec].call(Struct.new(:messages).new([m])) - break end } end end } end end - - def render(context) - if @messages and not @messages.empty? - @messages.inject(0) { |base_y, message| - render_single_message(message, context, base_y) } end end - - def height - if not helper.destroyed? and @messages and not @messages.empty? - @messages.inject(0) { |s, m| s + message_height(m) } - else - 0 end end - - private - - def render_single_message(message, context, base_y) - render_outline(message, context, base_y) - render_header(message, context, base_y) - context.save { - context.translate(@margin + @edge, @margin + @edge + base_y) - context.set_source_pixbuf(main_icon(message)) - context.paint - context.translate(icon_width + @margin*2, header_left(message).size[1] / Pango::SCALE) - context.set_source_rgb(*([0,0,0]).map{ |c| c.to_f / 65536 }) - context.show_pango_layout(main_message(message, context)) } - - base_y + message_height(message) end - - def message_height(message) - [icon_height, (header_left(message).size[1] + main_message(message).size[1]) / Pango::SCALE].max + (@margin + @edge) * 2 - end - - # ヘッダ(左)のための Pango::Layout のインスタンスを返す - def header_left(message, context = dummy_context) - attr_list, text = Pango.parse_markup("#{Pango.escape(message[:user][:idname])} #{Pango.escape(message[:user][:name] || '')}") - layout = context.create_pango_layout - layout.attributes = attr_list - layout.font_description = Pango::FontDescription.new(UserConfig[:mumble_basic_font]) - layout.text = text - layout end - - # ヘッダ(右)のための Pango::Layout のインスタンスを返す - def header_right(message, context = dummy_context) - now = Time.now - hms = if message[:created].year == now.year && message[:created].month == now.month && message[:created].day == now.day - message[:created].strftime('%H:%M:%S'.freeze) - else - message[:created].strftime('%Y/%m/%d %H:%M:%S'.freeze) - end - attr_list, text = Pango.parse_markup("#{Pango.escape(hms)}".freeze) - layout = context.create_pango_layout - layout.attributes = attr_list - layout.font_description = Pango::FontDescription.new(UserConfig[:mumble_basic_font]) - layout.text = text - layout.alignment = Pango::ALIGN_RIGHT - layout end - - def render_header(message, context, base_y) - header_w = width - @icon_width - @margin*3 - @edge*2 - context.save{ - context.translate(@icon_width + @margin*2 + @edge, @margin + @edge + base_y) - context.set_source_rgb(0,0,0) - hl_layout, hr_layout = header_left(message, context), header_right(message, context) - context.show_pango_layout(hl_layout) - context.save{ - context.translate(header_w - hr_layout.size[0] / Pango::SCALE, 0) - if (hl_layout.size[0] / Pango::SCALE) > header_w - hr_layout.size[0] / Pango::SCALE - 20 - r, g, b = get_backgroundcolor - grad = Cairo::LinearPattern.new(-20, base_y, hr_layout.size[0] / Pango::SCALE + 20, base_y) - grad.add_color_stop_rgba(0.0, r, g, b, 0.0) - grad.add_color_stop_rgba(20.0 / (hr_layout.size[0] / Pango::SCALE + 20), r, g, b, 1.0) - grad.add_color_stop_rgba(1.0, r, g, b, 1.0) - context.rectangle(-20, base_y, hr_layout.size[0] / Pango::SCALE + 20, hr_layout.size[1] / Pango::SCALE + base_y) - context.set_source(grad) - context.fill() end - context.show_pango_layout(hr_layout) } } - end - - def main_message(message, context = dummy_context) - attr_list, text = Pango.parse_markup(Pango.escape(message.to_show)) - layout = context.create_pango_layout - layout.width = (width - @icon_width - @margin*3 - @edge*2) * Pango::SCALE - layout.attributes = attr_list - layout.wrap = Pango::WRAP_CHAR - layout.font_description = Pango::FontDescription.new(UserConfig[:mumble_reply_font]) - layout.text = text - layout end - - def render_outline(message, context, base_y) - mh = message_height(message) - context.save { - context.pseudo_blur(4) { - context.fill { - context.set_source_rgb(*([32767, 32767, 32767]).map{ |c| c.to_f / 65536 }) - context.rounded_rectangle(@edge, @edge + base_y, width - @edge*2, mh - @edge*2, 4) - } - } - context.fill { - context.set_source_rgb(*([65535, 65535, 65535]).map{ |c| c.to_f / 65536 }) - context.rounded_rectangle(@edge, @edge + base_y, width - @edge*2, mh - @edge*2, 4) - } - } - end - - def main_icon(message) - Gdk::WebImageLoader.pixbuf(message[:user][:profile_image_url], icon_width, icon_height){ |pixbuf| - helper.on_modify } end - - def get_backgroundcolor - [1.0, 1.0, 1.0] - end -end + }.terminate('コメント付きリツイート描画中にエラーが発生しました') end end end -- 2.6.0