Module: Shellfie::Rendering::TextPainter

Included in:
Shellfie::RasterPainter
Defined in:
lib/shellfie/rendering/text_painter.rb

Instance Method Summary collapse

Instance Method Details

#color_with_opacity(color, opacity, allow_rgba) ⇒ Object



167
168
169
170
171
172
173
174
175
176
177
178
# File 'lib/shellfie/rendering/text_painter.rb', line 167

def color_with_opacity(color, opacity, allow_rgba)
  return color unless allow_rgba && opacity < 1.0

  if color.to_s.match?(/\A#[0-9a-fA-F]{6}\z/)
    r = color[1, 2].to_i(16)
    g = color[3, 2].to_i(16)
    b = color[5, 2].to_i(16)
    "rgba(#{r},#{g},#{b},#{opacity})"
  else
    color
  end
end

#content_origin_y(geometry) ⇒ Object



154
155
156
157
# File 'lib/shellfie/rendering/text_painter.rb', line 154

def content_origin_y(geometry)
  base_y = geometry[:margin] + geometry[:scaled_title_bar] + geometry[:scaled_padding]
  base_y - (geometry[:scroll_offset].to_f * geometry[:scaled_line_height]).round
end

#draw_content(convert, geometry) ⇒ Object



9
10
11
12
13
14
15
16
17
18
19
20
# File 'lib/shellfie/rendering/text_painter.rb', line 9

def draw_content(convert, geometry)
  content_y = content_origin_y(geometry)
  draw_selected_backgrounds(convert, geometry, content_y)

  geometry[:lines].each_with_index do |line, index|
    top = content_y + index * geometry[:scaled_line_height]
    baseline = top + geometry[:scaled_font_size]
    x = geometry[:margin] + geometry[:scaled_padding]

    draw_line_segments(convert, line[:segments], x, baseline, geometry)
  end
end

#draw_line_segments(convert, segments, x, baseline, geometry) ⇒ Object



22
23
24
25
26
# File 'lib/shellfie/rendering/text_painter.rb', line 22

def draw_line_segments(convert, segments, x, baseline, geometry)
  positioned_segments = position_segments(segments, x, baseline, geometry)
  draw_segment_backgrounds(convert, positioned_segments)
  draw_positioned_segments(convert, positioned_segments, geometry)
end

#draw_positioned_segments(convert, positioned_segments, geometry) ⇒ Object



64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
# File 'lib/shellfie/rendering/text_painter.rb', line 64

def draw_positioned_segments(convert, positioned_segments, geometry)
  positioned_segments.each do |item|
    draw_text(
      convert,
      item[:text],
      item[:x],
      item[:top],
      item[:foreground],
      geometry[:scaled_font_size],
      geometry[:font_config],
      bold: item[:segment].bold,
      italic: item[:segment].italic
    )
    draw_text_decoration(
      convert,
      item[:segment],
      item[:x],
      item[:width],
      item[:top] + geometry[:scaled_font_size],
      geometry
    )
  end
end

#draw_segment_backgrounds(convert, positioned_segments) ⇒ Object



51
52
53
54
55
56
57
58
59
60
61
62
# File 'lib/shellfie/rendering/text_painter.rb', line 51

def draw_segment_backgrounds(convert, positioned_segments)
  positioned_segments
    .select { |item| item[:background] }
    .group_by { |item| item[:background] }
    .each do |background, items|
      convert.fill background
      ImageMagickCommandBuilder.rectangles(
        convert,
        items.map { |item| { x1: item[:x], y1: item[:top], x2: item[:x] + item[:width], y2: item[:bottom] } }
      )
    end
end

#draw_selected_backgrounds(convert, geometry, content_y) ⇒ Object



135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
# File 'lib/shellfie/rendering/text_painter.rb', line 135

def draw_selected_backgrounds(convert, geometry, content_y)
  rectangles = geometry[:lines].each_with_index.each_with_object([]) do |(line, index), result|
    next unless line[:selected]

    x = geometry[:margin] + geometry[:scaled_padding]
    top = content_y + index * geometry[:scaled_line_height]
    result << {
      x1: x,
      y1: top,
      x2: x + geometry[:scaled_width] - geometry[:scaled_padding] * 2,
      y2: top + geometry[:scaled_line_height]
    }
  end
  return if rectangles.empty?

  convert.fill theme.colors[:selection]
  ImageMagickCommandBuilder.rectangles(convert, rectangles)
end

#draw_text(convert, text, x, y, color, font_size, font_config, bold: false, italic: false) ⇒ Object



100
101
102
103
104
105
106
107
108
109
110
# File 'lib/shellfie/rendering/text_painter.rb', line 100

def draw_text(convert, text, x, y, color, font_size, font_config, bold: false, italic: false)
  convert.gravity "NorthWest"
  convert.fill color
  convert.stroke "none"
  font = font_resolver.resolve(font_config, italic: italic)
  convert.font font if font
  convert.pointsize font_size
  convert.weight(bold ? 700 : 400)
  convert.style(italic ? "Italic" : "Normal")
  convert.annotate "+#{x}+#{y}", escape_text(text)
end

#draw_text_decoration(convert, segment, x, width, baseline, geometry) ⇒ Object



112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
# File 'lib/shellfie/rendering/text_painter.rb', line 112

def draw_text_decoration(convert, segment, x, width, baseline, geometry)
  return unless segment.underline || segment.strikethrough || segment.overline

  line_width = [(geometry[:scaled_font_size] / 12.0).ceil, 1].max
  convert.stroke segment_colors(segment).first
  convert.strokewidth line_width

  if segment.underline
    y = baseline + (geometry[:scaled_font_size] * 0.12).ceil
    ImageMagickCommandBuilder.line(convert, x, y, x + width, y)
  end
  if segment.strikethrough
    y = baseline - (geometry[:scaled_font_size] * 0.35).ceil
    ImageMagickCommandBuilder.line(convert, x, y, x + width, y)
  end
  if segment.overline
    y = baseline - geometry[:scaled_font_size]
    ImageMagickCommandBuilder.line(convert, x, y, x + width, y)
  end

  convert.stroke "none"
end

#escape_text(text) ⇒ Object



180
181
182
183
184
# File 'lib/shellfie/rendering/text_painter.rb', line 180

def escape_text(text)
  text.to_s
    .encode("UTF-8", invalid: :replace, undef: :replace, replace: "?")
    .gsub(/[\u0000-\u001f\u007f]/, " ")
end

#fit_text(text, max_width, font_size) ⇒ Object



159
160
161
162
163
164
165
# File 'lib/shellfie/rendering/text_painter.rb', line 159

def fit_text(text, max_width, font_size)
  return "" if max_width <= 0
  return text if TextMetrics.pixel_width(text, font_size) <= max_width

  max_cells = [(max_width / (font_size * 0.6)).floor - 3, 0].max
  "#{TextMetrics.take_cells(text, max_cells)}..."
end

#position_segments(segments, x, baseline, geometry) ⇒ Object



28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
# File 'lib/shellfie/rendering/text_painter.rb', line 28

def position_segments(segments, x, baseline, geometry)
  current_x = x
  segments.each_with_object([]) do |segment, result|
    text = segment.text.to_s
    next if text.empty?

    width = TextMetrics.pixel_width(text, geometry[:scaled_font_size])
    top = baseline - geometry[:scaled_font_size]
    foreground, background = segment_colors(segment)
    result << {
      segment: segment,
      text: text,
      x: current_x,
      width: width,
      top: top,
      bottom: top + geometry[:scaled_line_height],
      foreground: foreground,
      background: background
    }
    current_x += width
  end
end

#segment_colors(segment) ⇒ Object



88
89
90
91
92
93
94
95
96
97
98
# File 'lib/shellfie/rendering/text_painter.rb', line 88

def segment_colors(segment)
  foreground = segment.foreground ? theme.color_for(segment.foreground) : theme.colors[:foreground]
  background = segment.background ? theme.color_for(segment.background) : nil

  if segment.reverse
    foreground, background = background || theme.colors[:background], foreground
  end

  foreground = color_with_opacity(foreground, 0.6, true) if segment.dim
  [foreground, background]
end