rabbit 3.0.0 → 3.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (154) hide show
  1. checksums.yaml +4 -4
  2. data/Rakefile +2 -1
  3. data/data/locale/en/LC_MESSAGES/rabbit.mo +0 -0
  4. data/data/locale/ja/LC_MESSAGES/rabbit.mo +0 -0
  5. data/doc/_config.yml +2 -2
  6. data/doc/_layouts/skeleton.html +0 -7
  7. data/doc/en/faq.rd +4 -2
  8. data/doc/en/install/homebrew.rd +8 -13
  9. data/doc/en/news.rd +158 -0
  10. data/doc/en/sample/hiki/rabbit.hiki +0 -4
  11. data/doc/en/sample/rd/rabbit.rd +0 -4
  12. data/doc/en/usage/rabbit-slide.rd +3 -3
  13. data/doc/images/screenshots/en/blue-circle-raw.png +0 -0
  14. data/doc/images/screenshots/en/blue-circle.png +0 -0
  15. data/doc/images/screenshots/en/clear-blue-raw.png +0 -0
  16. data/doc/images/screenshots/en/clear-blue.png +0 -0
  17. data/doc/images/screenshots/en/cozmixng-raw.png +0 -0
  18. data/doc/images/screenshots/en/cozmixng.png +0 -0
  19. data/doc/images/screenshots/en/dark-gradation-raw.png +0 -0
  20. data/doc/images/screenshots/en/dark-gradation.png +0 -0
  21. data/doc/images/screenshots/en/day-white-raw.png +0 -0
  22. data/doc/images/screenshots/en/day-white.png +0 -0
  23. data/doc/images/screenshots/en/debian-raw.png +0 -0
  24. data/doc/images/screenshots/en/debian.png +0 -0
  25. data/doc/images/screenshots/en/green-circle-raw.png +0 -0
  26. data/doc/images/screenshots/en/green-circle.png +0 -0
  27. data/doc/images/screenshots/en/night-black-raw.png +0 -0
  28. data/doc/images/screenshots/en/night-black.png +0 -0
  29. data/doc/images/screenshots/en/rabbit-raw.png +0 -0
  30. data/doc/images/screenshots/en/rabbit.png +0 -0
  31. data/doc/images/screenshots/en/ranguba-raw.png +0 -0
  32. data/doc/images/screenshots/en/ranguba.png +0 -0
  33. data/doc/images/screenshots/en/red-frame-raw.png +0 -0
  34. data/doc/images/screenshots/en/red-frame.png +0 -0
  35. data/doc/images/screenshots/en/ruby-gnome2-raw.png +0 -0
  36. data/doc/images/screenshots/en/ruby-gnome2.png +0 -0
  37. data/doc/images/screenshots/en/rubykaigi2011-raw.png +0 -0
  38. data/doc/images/screenshots/en/rubykaigi2011.png +0 -0
  39. data/doc/images/screenshots/ja/blue-circle-raw.png +0 -0
  40. data/doc/images/screenshots/ja/blue-circle.png +0 -0
  41. data/doc/images/screenshots/ja/clear-blue-raw.png +0 -0
  42. data/doc/images/screenshots/ja/clear-blue.png +0 -0
  43. data/doc/images/screenshots/ja/cozmixng-raw.png +0 -0
  44. data/doc/images/screenshots/ja/cozmixng.png +0 -0
  45. data/doc/images/screenshots/ja/dark-gradation-raw.png +0 -0
  46. data/doc/images/screenshots/ja/dark-gradation.png +0 -0
  47. data/doc/images/screenshots/ja/day-white-raw.png +0 -0
  48. data/doc/images/screenshots/ja/day-white.png +0 -0
  49. data/doc/images/screenshots/ja/debian-raw.png +0 -0
  50. data/doc/images/screenshots/ja/debian.png +0 -0
  51. data/doc/images/screenshots/ja/green-circle-raw.png +0 -0
  52. data/doc/images/screenshots/ja/green-circle.png +0 -0
  53. data/doc/images/screenshots/ja/night-black-raw.png +0 -0
  54. data/doc/images/screenshots/ja/night-black.png +0 -0
  55. data/doc/images/screenshots/ja/rabbit-raw.png +0 -0
  56. data/doc/images/screenshots/ja/rabbit.png +0 -0
  57. data/doc/images/screenshots/ja/ranguba-raw.png +0 -0
  58. data/doc/images/screenshots/ja/ranguba.png +0 -0
  59. data/doc/images/screenshots/ja/red-frame-raw.png +0 -0
  60. data/doc/images/screenshots/ja/red-frame.png +0 -0
  61. data/doc/images/screenshots/ja/ruby-gnome2-raw.png +0 -0
  62. data/doc/images/screenshots/ja/ruby-gnome2.png +0 -0
  63. data/doc/images/screenshots/ja/rubykaigi2011-raw.png +0 -0
  64. data/doc/images/screenshots/ja/rubykaigi2011.png +0 -0
  65. data/doc/index.html.en +1 -1
  66. data/doc/ja/faq.rd +2 -0
  67. data/doc/ja/install/homebrew.rd +8 -12
  68. data/doc/ja/news.rd +157 -0
  69. data/doc/ja/sample/hiki/rabbit.hiki +0 -4
  70. data/doc/ja/sample/rd/rabbit.rd +0 -4
  71. data/doc/ja/usage/rabbit-slide.rd +3 -3
  72. data/doc/ja/users.rd +7 -0
  73. data/lib/rabbit/action/toggle.rb +7 -0
  74. data/lib/rabbit/author-configuration.rb +3 -4
  75. data/lib/rabbit/canvas.rb +18 -6
  76. data/lib/rabbit/command/rabbit-slide.rb +59 -1
  77. data/lib/rabbit/command/rabbit-slide.ui +127 -49
  78. data/lib/rabbit/command/rabbit.rb +5 -9
  79. data/lib/rabbit/element/base.rb +1 -5
  80. data/lib/rabbit/element/image.rb +139 -89
  81. data/lib/rabbit/element/video.rb +3 -11
  82. data/lib/rabbit/error.rb +9 -3
  83. data/lib/rabbit/formatter.rb +1 -1
  84. data/lib/rabbit/frame.rb +102 -4
  85. data/lib/rabbit/gem-pusher.rb +29 -6
  86. data/lib/rabbit/image/base.rb +163 -28
  87. data/lib/rabbit/image/dia.rb +21 -14
  88. data/lib/rabbit/image/mermaid.rb +73 -0
  89. data/lib/rabbit/image/pdf.rb +22 -9
  90. data/lib/rabbit/image/svg.rb +1 -4
  91. data/lib/rabbit/image.rb +6 -6
  92. data/lib/rabbit/info-window.rb +106 -80
  93. data/lib/rabbit/keys.rb +6 -0
  94. data/lib/rabbit/menu.rb +2 -0
  95. data/lib/rabbit/parser/base.rb +2 -1
  96. data/lib/rabbit/parser/ext/blockdiag.rb +16 -14
  97. data/lib/rabbit/parser/ext/charty.rb +58 -0
  98. data/lib/rabbit/parser/ext/image.rb +38 -10
  99. data/lib/rabbit/parser/markdown/converter.rb +36 -30
  100. data/lib/rabbit/parser/rd/ext/block-verbatim.rb +33 -35
  101. data/lib/rabbit/parser/rd/ext/image.rb +23 -4
  102. data/lib/rabbit/parser/rd/rd2rabbit-lib.rb +3 -1
  103. data/lib/rabbit/parser/rd.rb +1 -1
  104. data/lib/rabbit/parser/wiki/output.rb +9 -9
  105. data/lib/rabbit/parser.rb +2 -2
  106. data/lib/rabbit/progress.rb +1 -1
  107. data/lib/rabbit/properties.rb +154 -0
  108. data/lib/rabbit/rabbit.rb +3 -1
  109. data/lib/rabbit/relative-size.rb +28 -0
  110. data/lib/rabbit/renderer/base.rb +6 -0
  111. data/lib/rabbit/renderer/display/drawing-area-base.rb +1 -2
  112. data/lib/rabbit/renderer/display/drawing-area-primitive.rb +1 -0
  113. data/lib/rabbit/renderer/display/info.rb +6 -1
  114. data/lib/rabbit/renderer/display/key-handler.rb +27 -2
  115. data/lib/rabbit/renderer/engine/cairo.rb +24 -3
  116. data/lib/rabbit/renderer/screen.rb +0 -1
  117. data/lib/rabbit/slide-configuration.rb +16 -8
  118. data/lib/rabbit/task/slide.rb +6 -33
  119. data/lib/rabbit/theme/background-image-toolkit/background-image-toolkit.rb +38 -0
  120. data/lib/rabbit/theme/clear-blue/clear-blue.rb +4 -2
  121. data/lib/rabbit/theme/edge-info-toolkit/edge-info-toolkit.rb +12 -2
  122. data/lib/rabbit/theme/image/image.rb +3 -0
  123. data/lib/rabbit/theme/image-slide-number/image-slide-number.rb +8 -3
  124. data/lib/rabbit/theme/image-timer/image-timer.rb +8 -3
  125. data/lib/rabbit/theme/pdf/pdf.rb +1 -1
  126. data/lib/rabbit/theme/slide-footer-info/slide-footer-info.rb +2 -0
  127. data/lib/rabbit/theme/tag/tag.rb +9 -2
  128. data/lib/rabbit/theme-configuration.rb +3 -4
  129. data/lib/rabbit/utils.rb +25 -2
  130. data/lib/rabbit/version.rb +2 -2
  131. data/lib/rabbit/video-window.rb +14 -3
  132. data/{test/test-slideshare.rb → lib/rabbit/yaml-loader.rb} +20 -15
  133. data/po/en/rabbit.edit.po +123 -121
  134. data/po/en/rabbit.po +28 -26
  135. data/po/fr/rabbit.edit.po +122 -120
  136. data/po/fr/rabbit.po +27 -25
  137. data/po/ja/rabbit.edit.po +156 -125
  138. data/po/ja/rabbit.po +34 -30
  139. data/rabbit.gemspec +0 -1
  140. data/sample/can_rabbit.rd +0 -24
  141. data/sample/rabbit-en.hiki +0 -4
  142. data/sample/rabbit-en.md +13 -0
  143. data/sample/rabbit-en.rd +10 -4
  144. data/sample/rabbit.hiki +0 -4
  145. data/sample/rabbit.md +21 -0
  146. data/sample/rabbit.rd +20 -4
  147. data/test/command/test-rabbit.rb +1 -0
  148. data/test/parser/test-markdown.rb +2 -2
  149. data/test/test-slide-configuration.rb +4 -2
  150. metadata +30 -46
  151. data/doc/css/jquery-ui/themes/ui-lightness.css +0 -573
  152. data/doc/javascripts/jquery-ui.js +0 -11544
  153. data/doc/javascripts/jquery.js +0 -7179
  154. data/lib/rabbit/slideshare.rb +0 -192
@@ -14,7 +14,6 @@ module Rabbit
14
14
  include TextRenderer
15
15
 
16
16
  attr_reader :filename
17
- attr_reader :normalized_width, :normalized_height
18
17
  attr_reader :relative_width, :relative_height
19
18
  attr_reader :relative_margin_top, :relative_margin_bottom
20
19
  attr_reader :relative_margin_left, :relative_margin_right
@@ -34,7 +33,6 @@ module Rabbit
34
33
  instance_variable_set("@#{name}", true_value?(prop[name]))
35
34
  end
36
35
  %w(width height
37
- normalized_width normalized_height
38
36
  relative_width relative_height
39
37
  relative_margin_top relative_margin_bottom
40
38
  relative_margin_left relative_margin_right
@@ -44,7 +42,7 @@ module Rabbit
44
42
  begin
45
43
  instance_variable_set("@#{name}", prop[name] && Integer(prop[name]))
46
44
  rescue ArgumentError
47
- raise InvalidImageSizeError.new(filename, name, prop[name])
45
+ raise InvalidSizeError.new(filename, name, prop[name])
48
46
  end
49
47
  end
50
48
 
@@ -126,12 +124,10 @@ module Rabbit
126
124
  iw = base_w
127
125
  ih = base_h
128
126
  else
129
- nw = make_normalized_size(@normalized_width)
130
- nh = make_normalized_size(@normalized_height)
131
127
  rw = make_relative_size(@relative_width, base_w)
132
128
  rh = make_relative_size(@relative_height, base_h)
133
- iw = nw || rw || base_w
134
- ih = nh || rh || base_h
129
+ iw = rw || base_w
130
+ ih = rh || base_h
135
131
  end
136
132
  resize(iw, ih)
137
133
  end
@@ -151,10 +147,6 @@ module Rabbit
151
147
  end
152
148
  end
153
149
 
154
- def make_normalized_size(size)
155
- size && screen_size(size)
156
- end
157
-
158
150
  def make_relative_size(size, parent_size)
159
151
  size && parent_size && ((size / 100.0) * parent_size).ceil
160
152
  end
data/lib/rabbit/error.rb CHANGED
@@ -1,4 +1,4 @@
1
- # Copyright (C) 2004-2017 Kouhei Sutou <kou@cozmixng.org>
1
+ # Copyright (C) 2004-2022 Sutou Kouhei <kou@cozmixng.org>
2
2
  #
3
3
  # This program is free software; you can redistribute it and/or modify
4
4
  # it under the terms of the GNU General Public License as published by
@@ -87,6 +87,12 @@ module Rabbit
87
87
  end
88
88
  end
89
89
 
90
+ class MermaidCanNotHandleError < ImageLoadWithExternalCommandError
91
+ def initialize(command, additional_info=nil)
92
+ super("Mermaid", command, additional_info)
93
+ end
94
+ end
95
+
90
96
  class UnknownPropertyError < Error
91
97
  attr_reader :name
92
98
  def initialize(name)
@@ -181,7 +187,7 @@ module Rabbit
181
187
  end
182
188
  end
183
189
 
184
- class InvalidImageSizeError < Error
190
+ class InvalidSizeError < Error
185
191
  attr_reader :filename, :prop_name, :value
186
192
  def initialize(filename, prop_name, value)
187
193
  @filename = filename
@@ -193,7 +199,7 @@ module Rabbit
193
199
  :value => value,
194
200
  }
195
201
  super(_("invalid value of size property \"%{prop_name}\" " \
196
- "of image \"%{filename}\": %{value}") % params)
202
+ "of \"%{filename}\": %{value}") % params)
197
203
  end
198
204
  end
199
205
 
@@ -131,7 +131,7 @@ EOC
131
131
  end
132
132
  end
133
133
 
134
- class Weigth
134
+ class Weight
135
135
  private
136
136
  def css_name
137
137
  "font-weight"
data/lib/rabbit/frame.rb CHANGED
@@ -2,13 +2,16 @@ require "forwardable"
2
2
  require "rabbit/gtk"
3
3
  require "rexml/text"
4
4
 
5
+ begin
6
+ require "vte3"
7
+ rescue LoadError
8
+ end
9
+
5
10
  require "rabbit/rabbit"
6
11
  require "rabbit/utils"
7
12
 
8
13
  module Rabbit
9
-
10
14
  class Frame
11
-
12
15
  include ScreenInfo
13
16
  extend Forwardable
14
17
 
@@ -31,6 +34,9 @@ module Rabbit
31
34
  @logger = logger
32
35
  @canvas = canvas
33
36
  @geometry = nil
37
+ @notebook = nil
38
+ @terminal = nil
39
+ @running = true
34
40
  end
35
41
 
36
42
  def destroyed?
@@ -38,6 +44,7 @@ module Rabbit
38
44
  end
39
45
 
40
46
  def quit
47
+ @running = false
41
48
  @window.destroy unless destroyed?
42
49
  @window = nil
43
50
  true
@@ -87,6 +94,8 @@ module Rabbit
87
94
  init_window(width, height, window_type)
88
95
  @fullscreen = false
89
96
  @main_window = main_window
97
+ @terminal.show if @terminal
98
+ @notebook.show if @notebook
90
99
  @window.show
91
100
  @canvas.post_init_gui
92
101
  end
@@ -99,6 +108,21 @@ module Rabbit
99
108
  true
100
109
  end
101
110
 
111
+ def toggle_terminal
112
+ return if @terminal.nil?
113
+ terminal_page = @notebook.page_num(@terminal)
114
+ if @notebook.current_page == terminal_page
115
+ @notebook.current_page = 0
116
+ else
117
+ @notebook.current_page = terminal_page
118
+ end
119
+ end
120
+
121
+ def in_terminal?
122
+ return false if @terminal.nil?
123
+ @notebook.current_page == @notebook.page_num(@terminal)
124
+ end
125
+
102
126
  private
103
127
  def init_window(width, height, window_type=nil)
104
128
  window_type ||= :toplevel
@@ -106,9 +130,29 @@ module Rabbit
106
130
  @window.set_default_size(width, height)
107
131
  @window.parse_geometry(@geometry) if @geometry
108
132
  @window.set_app_paintable(true)
133
+ if defined?(Vte::Terminal)
134
+ init_notebook
135
+ end
109
136
  set_window_signal
110
137
  setup_dnd
111
- @canvas.attach_to(self, @window)
138
+ @canvas.attach_to(self, @window, @notebook)
139
+ if defined?(Vte::Terminal)
140
+ init_terminal
141
+ end
142
+ end
143
+
144
+ def init_notebook
145
+ @notebook = Gtk::Notebook.new
146
+ @notebook.show_tabs = false
147
+ provider = Gtk::CssProvider.new
148
+ provider.load(data: <<-CSS)
149
+ notebook {
150
+ border-width: 0px;
151
+ }
152
+ CSS
153
+ @notebook.style_context.add_provider(provider,
154
+ Gtk::StyleProvider::PRIORITY_USER)
155
+ @window.add(@notebook)
112
156
  end
113
157
 
114
158
  def set_window_signal
@@ -160,6 +204,47 @@ module Rabbit
160
204
  true
161
205
  end
162
206
  end
207
+
208
+ def init_terminal
209
+ @terminal = Vte::Terminal.new
210
+ # TODO: Support theme
211
+ terminal_font_description = ENV["RABBIT_TERMINAL_FONT_DESCRIPTION"]
212
+ if terminal_font_description
213
+ @terminal.font_desc =
214
+ Pango::FontDescription.new(terminal_font_description)
215
+ end
216
+ terminal_color_foreground = ENV["RABBIT_TERMINAL_COLOR_FOREGROUND"]
217
+ if terminal_color_foreground
218
+ @terminal.color_foreground = terminal_color_foreground
219
+ end
220
+ terminal_color_background = ENV["RABBIT_TERMINAL_COLOR_BACKGROUND"]
221
+ if terminal_color_background
222
+ @terminal.color_background = terminal_color_background
223
+ end
224
+ @terminal.enable_sixel = true if @terminal.respond_to?(:enable_sixel=)
225
+ @notebook.add(@terminal)
226
+ pid = nil
227
+ in_terminal = false
228
+ @notebook.signal_connect(:switch_page) do |_, page,|
229
+ if page == @terminal
230
+ if @running
231
+ pid = @terminal.spawn if pid.nil?
232
+ @canvas.pre_terminal unless in_terminal
233
+ in_terminal = true
234
+ end
235
+ else
236
+ @canvas.post_terminal if in_terminal
237
+ in_terminal = false
238
+ end
239
+ end
240
+ @terminal.signal_connect(:child_exited) do
241
+ pid = nil
242
+ terminal_page = @notebook.page_num(@terminal)
243
+ if @notebook.current_page == terminal_page
244
+ @canvas.activate("ToggleTerminal")
245
+ end
246
+ end
247
+ end
163
248
  end
164
249
 
165
250
  class NullFrame
@@ -184,10 +269,16 @@ module Rabbit
184
269
  def iconify_available?
185
270
  false
186
271
  end
272
+
273
+ def toggle_terminal
274
+ end
275
+
276
+ def in_terminal?
277
+ false
278
+ end
187
279
  end
188
280
 
189
281
  class EmbedFrame < Frame
190
-
191
282
  def update_title(new_title)
192
283
  end
193
284
 
@@ -199,6 +290,13 @@ module Rabbit
199
290
  false
200
291
  end
201
292
 
293
+ def toggle_terminal
294
+ end
295
+
296
+ def in_terminal?
297
+ false
298
+ end
299
+
202
300
  def init_gui(width, height, main_window, window_type=nil)
203
301
  @window = Gtk::EventBox.new
204
302
  @window.set_size_request(width, height)
@@ -1,4 +1,4 @@
1
- # Copyright (C) 2016 Kouhei Sutou <kou@cozmixng.org>
1
+ # Copyright (C) 2016-2023 Sutou Kouhei <kou@cozmixng.org>
2
2
  #
3
3
  # This program is free software; you can redistribute it and/or modify
4
4
  # it under the terms of the GNU General Public License as published by
@@ -15,11 +15,11 @@
15
15
  # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
16
16
 
17
17
  require "rake"
18
- require "yaml"
19
18
  require "open-uri"
20
19
 
21
20
  require "rabbit/gettext"
22
21
  require "rabbit/password-reader"
22
+ require "rabbit/yaml-loader"
23
23
 
24
24
  module Rabbit
25
25
  class GemPusher
@@ -35,12 +35,13 @@ module Rabbit
35
35
  credentials_path = File.expand_path("~/.gem/credentials")
36
36
  credentials_path_exist = File.exist?(credentials_path)
37
37
  if credentials_path_exist
38
- credentials = YAML.load(File.read(credentials_path))
38
+ credentials = YAMLLoader.load(File.read(credentials_path))
39
39
  else
40
40
  credentials = {}
41
41
  end
42
42
  unless credentials.key?(@user.to_sym)
43
43
  credentials[@user.to_sym] = retrieve_api_key
44
+ FileUtils.mkdir_p(File.dirname(credentials_path))
44
45
  File.open(credentials_path, "w") do |credentials_file|
45
46
  credentials_file.print(credentials.to_yaml)
46
47
  end
@@ -57,10 +58,32 @@ module Rabbit
57
58
  prompt = _("Enter password on RubyGems.org [%{user}]: ") % {:user => @user}
58
59
  reader = PasswordReader.new(prompt)
59
60
  password = reader.read
60
- open("https://rubygems.org/api/v1/api_key.yaml",
61
- :http_basic_authentication => [@user, password]) do |response|
62
- YAML.load(response.read)[:rubygems_api_key]
61
+ begin
62
+ URI.open("https://rubygems.org/api/v1/api_key.yaml",
63
+ :http_basic_authentication => [@user, password]) do |response|
64
+ YAMLLoader.load(response.read)[:rubygems_api_key]
65
+ end
66
+ rescue OpenURI::HTTPError => error
67
+ if mfa_error?(error)
68
+ prompt = _("Enter OTP on RubyGems.org [%{user}]: ") % {:user => @user}
69
+ # TODO: We don't need to hide input.
70
+ reader = PasswordReader.new(prompt)
71
+ otp = reader.read
72
+ URI.open("https://rubygems.org/api/v1/api_key.yaml",
73
+ :http_basic_authentication => [@user, password],
74
+ "OTP" => otp) do |response|
75
+ YAMLLoader.load(response.read)[:rubygems_api_key]
76
+ end
77
+ else
78
+ raise
79
+ end
63
80
  end
64
81
  end
82
+
83
+ def mfa_error?(error)
84
+ return false unless error.message.start_with?("401 ")
85
+ body = error.io.read
86
+ body.start_with?("You have enabled multifactor authentication")
87
+ end
65
88
  end
66
89
  end
@@ -1,20 +1,64 @@
1
+ # Copyright (C) 2004-2022 Sutou Kouhei <kou@cozmixng.org>
2
+ #
3
+ # This program is free software; you can redistribute it and/or modify
4
+ # it under the terms of the GNU General Public License as published by
5
+ # the Free Software Foundation; either version 2 of the License, or
6
+ # (at your option) any later version.
7
+ #
8
+ # This program is distributed in the hope that it will be useful,
9
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
10
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11
+ # GNU General Public License for more details.
12
+ #
13
+ # You should have received a copy of the GNU General Public License along
14
+ # with this program; if not, write to the Free Software Foundation, Inc.,
15
+ # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
16
+
17
+ require "forwardable"
18
+ require "digest/sha2"
19
+
1
20
  require "gdk_pixbuf2"
2
21
 
3
- require "rabbit/utils"
4
22
  require "rabbit/image-data-loader"
23
+ require "rabbit/properties"
5
24
 
6
25
  module Rabbit
7
26
  module ImageManipulable
8
-
9
27
  class Base
10
28
  extend ModuleLoader
11
29
 
12
- attr_reader :width, :height, :original_width, :original_height
30
+ class << self
31
+ def delegate
32
+ extend Forwardable
33
+
34
+ def_delegators(:@delegated_loader,
35
+ :draw,
36
+ :ensure_resize,
37
+ :height,
38
+ :internal_pixbuf,
39
+ :keep_ratio,
40
+ :keep_ratio=,
41
+ :keep_ratio?,
42
+ :original_height,
43
+ :original_width,
44
+ :pixbuf,
45
+ :resize,
46
+ :update_size,
47
+ :width)
48
+ end
49
+ end
50
+
51
+ attr_reader :filename
52
+ attr_reader :properties
53
+ attr_reader :original_width
54
+ attr_reader :original_height
13
55
  attr_reader :animation
14
56
 
15
- def initialize(filename, props)
57
+ def initialize(filename, props, canvas: nil)
16
58
  @filename = filename
17
- @props = normalize_props(props)
59
+ @properties = Properties.new(props)
60
+ @canvas = canvas
61
+ initialize_keep_ratio
18
62
  @animation = nil
19
63
  @animation_iterator = nil
20
64
  @animation_timeout = nil
@@ -24,29 +68,57 @@ module Rabbit
24
68
  end
25
69
 
26
70
  def [](key)
27
- @props[normalize_prop_key(key)]
71
+ @properties[key]
28
72
  end
29
73
 
30
74
  def []=(key, value)
31
- @props[normalize_prop_key(key)] = value
75
+ @properties[key] = value
32
76
  end
33
77
 
34
- def keep_ratio
35
- self["keep_ratio"]
78
+ def keep_ratio?
79
+ @properties.keep_ratio
36
80
  end
81
+ # For backward compatibility
82
+ alias_method :keep_ratio, :keep_ratio?
37
83
 
38
84
  def keep_ratio=(value)
39
- self["keep_ratio"] = value
85
+ @properties.keep_ratio = value
40
86
  end
41
87
 
42
88
  def pixbuf
43
89
  @pixbuf
44
90
  end
45
91
 
92
+ def width
93
+ (relative_clip_width&.resolve(@width) || @width) -
94
+ (relative_clip_x&.resolve(@width) || 0)
95
+ end
96
+
97
+ def height
98
+ (relative_clip_height&.resolve(@height) || @height) -
99
+ (relative_clip_y&.resolve(@height) || 0)
100
+ end
101
+
102
+ def relative_clip_x
103
+ @properties.get_relative_size("relative_clip_x", @filename)
104
+ end
105
+
106
+ def relative_clip_y
107
+ @properties.get_relative_size("relative_clip_y", @filename)
108
+ end
109
+
110
+ def relative_clip_width
111
+ @properties.get_relative_size("relative_clip_width", @filename)
112
+ end
113
+
114
+ def relative_clip_height
115
+ @properties.get_relative_size("relative_clip_height", @filename)
116
+ end
117
+
46
118
  def resize(w, h)
47
119
  if w.nil? and h.nil?
48
120
  return
49
- elsif keep_ratio
121
+ elsif keep_ratio?
50
122
  if w and h.nil?
51
123
  h = (original_height * w.to_f / original_width).ceil
52
124
  elsif w.nil? and h
@@ -65,10 +137,7 @@ module Rabbit
65
137
  end
66
138
 
67
139
  def draw(canvas, x, y, params={})
68
- default_params = {
69
- :width => width,
70
- :height => height,
71
- }
140
+ default_params = default_draw_params(x, y)
72
141
  target_pixbuf = pixbuf
73
142
  if @animation_iterator
74
143
  @animation_iterator.advance
@@ -79,20 +148,15 @@ module Rabbit
79
148
  end
80
149
 
81
150
  private
82
- def normalize_props(props)
83
- normalized_props = {}
84
- (props || {}).each do |key, value|
85
- normalized_props[normalize_prop_key(key)] = value
86
- end
87
- keep_ratio_key = normalize_prop_key("keep_ratio")
88
- unless normalized_props.has_key?(keep_ratio_key)
89
- normalized_props[keep_ratio_key] = true
151
+ def initialize_keep_ratio
152
+ return unless @properties["keep_ratio"].nil?
153
+ # For backward compatibility
154
+ keep_scale = @properties["keep_scale"]
155
+ if keep_scale.nil?
156
+ @properties["keep_ratio"] = true
157
+ else
158
+ @properties["keep_ratio"] = keep_scale
90
159
  end
91
- normalized_props
92
- end
93
-
94
- def normalize_prop_key(key)
95
- key.to_s.gsub(/-/, "_")
96
160
  end
97
161
 
98
162
  def load_data(data)
@@ -129,6 +193,77 @@ module Rabbit
129
193
  end
130
194
  end
131
195
  end
196
+
197
+ def default_draw_params(x, y)
198
+ _relative_clip_x = relative_clip_x
199
+ _relative_clip_y = relative_clip_y
200
+ _relative_clip_width = relative_clip_width
201
+ _relative_clip_height = relative_clip_height
202
+ if _relative_clip_x or
203
+ _relative_clip_y or
204
+ _relative_clip_width or
205
+ _relative_clip_height
206
+ clip_x = _relative_clip_x&.resolve(@width) || 0
207
+ clip_y = _relative_clip_y&.resolve(@height) || 0
208
+ clip_width = _relative_clip_width&.resolve(@width) || @width
209
+ clip_height = _relative_clip_height&.resolve(@height) || @height
210
+ uncliped_width = width - (clip_width - clip_x) + @width
211
+ uncliped_height = height - (clip_height - clip_y) + @height
212
+ {
213
+ width: uncliped_width,
214
+ height: uncliped_height,
215
+ clip_x: x + clip_x,
216
+ clip_y: y + clip_y,
217
+ clip_width: clip_width,
218
+ clip_height: clip_height,
219
+ }
220
+ else
221
+ {
222
+ width: width,
223
+ height: height,
224
+ }
225
+ end
226
+ end
227
+
228
+ # TODO: Move to more suitable location
229
+ def cache_processed_data(canvas, input, extension)
230
+ tmp_dir_name = canvas&.tmp_dir_name
231
+ return yield unless tmp_dir_name
232
+ hash = compute_hash(input)
233
+ cached_path = File.join(tmp_dir_name, "#{hash}.#{extension}")
234
+ unless File.exist?(cached_path)
235
+ processed_path = yield
236
+ FileUtils.cp(processed_path, cached_path)
237
+ end
238
+ cached_path
239
+ end
240
+
241
+ def compute_hash(input)
242
+ digest = Digest::SHA2.new
243
+ add_data = lambda do |data|
244
+ case data
245
+ when Array
246
+ data.each do |element|
247
+ add_data.call(element)
248
+ end
249
+ when Hash
250
+ data.each do |key, value|
251
+ add_data.call(key)
252
+ add_data.call(value)
253
+ end
254
+ when String
255
+ digest << data
256
+ when IO
257
+ loop do
258
+ chunk = data.read(4096)
259
+ break if chunk.nil?
260
+ digest << chunk
261
+ end
262
+ end
263
+ end
264
+ add_data.call(input)
265
+ digest.hexdigest
266
+ end
132
267
  end
133
268
  end
134
269
  end
@@ -1,6 +1,19 @@
1
- require "forwardable"
1
+ # Copyright (C) 2004-2022 Sutou Kouhei <kou@cozmixng.org>
2
+ #
3
+ # This program is free software; you can redistribute it and/or modify
4
+ # it under the terms of the GNU General Public License as published by
5
+ # the Free Software Foundation; either version 2 of the License, or
6
+ # (at your option) any later version.
7
+ #
8
+ # This program is distributed in the hope that it will be useful,
9
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
10
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11
+ # GNU General Public License for more details.
12
+ #
13
+ # You should have received a copy of the GNU General Public License along
14
+ # with this program; if not, write to the Free Software Foundation, Inc.,
15
+ # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
2
16
 
3
- require "rabbit/utils"
4
17
  require "rabbit/image/base"
5
18
 
6
19
  module Rabbit
@@ -11,7 +24,6 @@ module Rabbit
11
24
 
12
25
  DIA_COMMANDS = %w(dia)
13
26
 
14
- extend Forwardable
15
27
  include SystemRunner
16
28
 
17
29
  class << self
@@ -33,26 +45,21 @@ module Rabbit
33
45
  end
34
46
  end
35
47
 
36
- def_delegators(:@svg_loader, :keep_ratio, :keep_ratio=)
37
- def_delegators(:@svg_loader, :pixbuf, :internal_pixbuf)
38
- def_delegators(:@svg_loader, :width, :height)
39
- def_delegators(:@svg_loader, :original_width, :original_height)
40
- def_delegators(:@svg_loader, :resize, :ensure_resize)
41
- def_delegators(:@svg_loader, :update_size)
48
+ delegate
42
49
 
43
- def initialize(filename, keep_ratio)
44
- init_svg_loader(filename, keep_ratio)
50
+ def initialize(filename, props, canvas: nil)
51
+ init_delegated_loader(filename, props, canvas)
45
52
  super
46
53
  end
47
54
 
48
55
  private
49
- def init_svg_loader(filename, keep_ratio)
50
- @svg_file = Tempfile.new(["rabbit-loader-dia", ".svg"])
56
+ def init_delegated_loader(filename, props, canvas)
57
+ @svg_file = Tempfile.new(["rabbit-image-loader-dia", ".svg"])
51
58
  args = ["--export=#{@svg_file.path}"]
52
59
  args << "--filter=svg"
53
60
  args << filename
54
61
  if DIA_COMMANDS.any? {|dia| run(dia, *args)}
55
- @svg_loader = SVG.new(@svg_file.path, keep_ratio)
62
+ @delegated_loader = SVG.new(@svg_file.path, props)
56
63
  else
57
64
  raise DiaCanNotHandleError.new("dia #{args.join(' ')}",
58
65
  DIA_COMMANDS)