rabbit 3.0.0 → 3.0.2

Sign up to get free protection for your applications and to get access to all the features.
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)