etti 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,223 @@
1
+ <?xml version="1.0" encoding="UTF-8" standalone="no"?>
2
+ <!-- Created with Inkscape (http://www.inkscape.org/) -->
3
+
4
+ <svg
5
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
6
+ xmlns:cc="http://creativecommons.org/ns#"
7
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
8
+ xmlns:svg="http://www.w3.org/2000/svg"
9
+ xmlns="http://www.w3.org/2000/svg"
10
+ xmlns:xlink="http://www.w3.org/1999/xlink"
11
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
12
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
13
+ width="16"
14
+ height="16.000002"
15
+ id="svg30198"
16
+ version="1.1"
17
+ inkscape:version="0.48.4 r9939"
18
+ sodipodi:docname="Neues Dokument 29">
19
+ <defs
20
+ id="defs30200">
21
+ <linearGradient
22
+ id="linearGradient33157">
23
+ <stop
24
+ style="stop-color:#999999;stop-opacity:1;"
25
+ offset="0"
26
+ id="stop33159" />
27
+ <stop
28
+ style="stop-color:#515151;stop-opacity:1;"
29
+ offset="1"
30
+ id="stop33161" />
31
+ </linearGradient>
32
+ <linearGradient
33
+ xlink:href="#linearGradient1887"
34
+ y2="218.54164"
35
+ x2="173.72397"
36
+ y1="209.14064"
37
+ x1="163.85936"
38
+ gradientTransform="matrix(1.102855,0,0,1.148517,-167.5042,-41.73143)"
39
+ gradientUnits="userSpaceOnUse"
40
+ id="linearGradient5795"
41
+ inkscape:collect="always" />
42
+ <linearGradient
43
+ id="linearGradient1887">
44
+ <stop
45
+ id="stop1888"
46
+ offset="0.0000000"
47
+ style="stop-color:#fffdf8;stop-opacity:1.0000000;" />
48
+ <stop
49
+ id="stop1889"
50
+ offset="1.0000000"
51
+ style="stop-color:#cdccc7;stop-opacity:1.0000000;" />
52
+ </linearGradient>
53
+ <linearGradient
54
+ xlink:href="#linearGradient3480"
55
+ y2="217.25519"
56
+ x2="173.03127"
57
+ y1="207.75523"
58
+ x1="161.28645"
59
+ gradientTransform="matrix(1.102855,0,0,1.148517,-168.0557,-42.30568)"
60
+ gradientUnits="userSpaceOnUse"
61
+ id="linearGradient5797"
62
+ inkscape:collect="always" />
63
+ <linearGradient
64
+ id="linearGradient3480">
65
+ <stop
66
+ id="stop3482"
67
+ offset="0.0000000"
68
+ style="stop-color:#646464;stop-opacity:1.0000000;" />
69
+ <stop
70
+ id="stop3484"
71
+ offset="1.0000000"
72
+ style="stop-color:#000000;stop-opacity:1.0000000;" />
73
+ </linearGradient>
74
+ <linearGradient
75
+ xlink:href="#linearGradient3480"
76
+ y2="213"
77
+ x2="176"
78
+ y1="213"
79
+ x1="160"
80
+ gradientTransform="translate(-150.459,-11.45)"
81
+ gradientUnits="userSpaceOnUse"
82
+ id="linearGradient5799"
83
+ inkscape:collect="always" />
84
+ <linearGradient
85
+ id="linearGradient30225">
86
+ <stop
87
+ id="stop30227"
88
+ offset="0.0000000"
89
+ style="stop-color:#646464;stop-opacity:1.0000000;" />
90
+ <stop
91
+ id="stop30229"
92
+ offset="1.0000000"
93
+ style="stop-color:#000000;stop-opacity:1.0000000;" />
94
+ </linearGradient>
95
+ <linearGradient
96
+ inkscape:collect="always"
97
+ xlink:href="#linearGradient1887"
98
+ id="linearGradient30283"
99
+ gradientUnits="userSpaceOnUse"
100
+ gradientTransform="matrix(1.102855,0,0,1.148517,-167.5042,-41.73143)"
101
+ x1="163.85936"
102
+ y1="209.14064"
103
+ x2="173.72397"
104
+ y2="218.54164" />
105
+ <linearGradient
106
+ inkscape:collect="always"
107
+ xlink:href="#linearGradient3480"
108
+ id="linearGradient30285"
109
+ gradientUnits="userSpaceOnUse"
110
+ gradientTransform="matrix(1.102855,0,0,1.148517,-168.0557,-42.30568)"
111
+ x1="161.28645"
112
+ y1="207.75523"
113
+ x2="173.03127"
114
+ y2="217.25519" />
115
+ <linearGradient
116
+ inkscape:collect="always"
117
+ xlink:href="#linearGradient3480"
118
+ id="linearGradient30287"
119
+ gradientUnits="userSpaceOnUse"
120
+ gradientTransform="translate(-150.459,-11.45)"
121
+ x1="160"
122
+ y1="213"
123
+ x2="176"
124
+ y2="213" />
125
+ <linearGradient
126
+ inkscape:collect="always"
127
+ xlink:href="#linearGradient3480"
128
+ id="linearGradient31074"
129
+ gradientUnits="userSpaceOnUse"
130
+ gradientTransform="translate(188.50009,316.86218)"
131
+ x1="160"
132
+ y1="213"
133
+ x2="176"
134
+ y2="213" />
135
+ <linearGradient
136
+ inkscape:collect="always"
137
+ xlink:href="#linearGradient3480"
138
+ id="linearGradient31079"
139
+ gradientUnits="userSpaceOnUse"
140
+ gradientTransform="matrix(1.102855,0,0,1.148517,170.90339,286.0065)"
141
+ x1="161.28645"
142
+ y1="207.75523"
143
+ x2="173.03127"
144
+ y2="217.25519" />
145
+ <linearGradient
146
+ inkscape:collect="always"
147
+ xlink:href="#linearGradient33157"
148
+ id="linearGradient33163"
149
+ x1="348.78534"
150
+ y1="524.80157"
151
+ x2="359.47076"
152
+ y2="539.90277"
153
+ gradientUnits="userSpaceOnUse" />
154
+ </defs>
155
+ <sodipodi:namedview
156
+ id="base"
157
+ pagecolor="#ffffff"
158
+ bordercolor="#666666"
159
+ borderopacity="1.0"
160
+ inkscape:pageopacity="0.0"
161
+ inkscape:pageshadow="2"
162
+ inkscape:zoom="41.056383"
163
+ inkscape:cx="9.4231888"
164
+ inkscape:cy="5.4834939"
165
+ inkscape:document-units="px"
166
+ inkscape:current-layer="layer1"
167
+ showgrid="false"
168
+ fit-margin-top="0"
169
+ fit-margin-left="0"
170
+ fit-margin-right="0"
171
+ fit-margin-bottom="0"
172
+ inkscape:window-width="1920"
173
+ inkscape:window-height="1145"
174
+ inkscape:window-x="0"
175
+ inkscape:window-y="33"
176
+ inkscape:window-maximized="1" />
177
+ <metadata
178
+ id="metadata30203">
179
+ <rdf:RDF>
180
+ <cc:Work
181
+ rdf:about="">
182
+ <dc:format>image/svg+xml</dc:format>
183
+ <dc:type
184
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
185
+ <dc:title></dc:title>
186
+ </cc:Work>
187
+ </rdf:RDF>
188
+ </metadata>
189
+ <g
190
+ inkscape:label="Ebene 1"
191
+ inkscape:groupmode="layer"
192
+ id="layer1"
193
+ transform="translate(-346,-524.36218)">
194
+ <path
195
+ transform="translate(346,524.36218)"
196
+ style="fill:#ffffff;fill-opacity:1;stroke:none"
197
+ d="m 2.5331018,0.5334664 7.1608842,0 4.018863,4.0432203 0,10.9361803 -11.1797472,0 z"
198
+ id="rect33165"
199
+ inkscape:connector-curvature="0"
200
+ sodipodi:nodetypes="cccccc" />
201
+ <path
202
+ id="path33149"
203
+ style="fill:none;stroke:url(#linearGradient33163);stroke-width:0.75000000000000000;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
204
+ d="m 352.14167,539.41271 c 0,-0.11371 0,-14.76117 0,-14.76117 m 3.66666,14.8654 c 0,-0.0821 0,-10.65848 0,-10.65848 m -7.64661,8.02872 c 0.0861,0 11.17761,0 11.17761,0 m -11.03147,-3 c 0.0861,0 11.17761,0 11.17761,0 m -11.17761,-3 c 0.0861,0 11.17761,0 11.17761,0 m -11.30473,-3 c 0.0569,0 7.38862,0 7.38862,0" />
205
+ <path
206
+ inkscape:connector-curvature="0"
207
+ id="path5602"
208
+ d="m 349.5,538.86218 9,0 0,-9"
209
+ style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:square;stroke-linejoin:miter;stroke-opacity:0.29807693" />
210
+ <path
211
+ inkscape:connector-curvature="0"
212
+ sodipodi:nodetypes="cccccc"
213
+ id="path4679"
214
+ d="m 348.5,524.86218 7,0 4,4 0,11 -11,0 0,-15 z"
215
+ style="color:#000000;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:url(#linearGradient31079);stroke-width:1.00000106999999994;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dashoffset:0;marker:none;display:inline" />
216
+ <path
217
+ inkscape:connector-curvature="0"
218
+ sodipodi:nodetypes="cccc"
219
+ id="path4681"
220
+ d="m 355.5,524.86218 4,4 -4,0 0,-4 z"
221
+ style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:url(#linearGradient31074);stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1" />
222
+ </g>
223
+ </svg>
@@ -0,0 +1,15 @@
1
+ # encoding: UTF-8
2
+
3
+ module Etti
4
+ class Colors
5
+ def initialize
6
+ @bg = [0.9, 0.9, 0.9]
7
+ @border = [0, 0, 0]
8
+ @selection = [0.5, 0.25, 0.0]
9
+ @text_normal = [0.0, 0.1, 1.0, 0.4]
10
+ @text_highlit = [0.1, 0.2, 1.0, 0.4]
11
+ end
12
+ attr_reader :bg, :border, :selection
13
+ attr_reader :text_normal, :text_highlit
14
+ end
15
+ end
@@ -0,0 +1,12 @@
1
+ #encoding: UTF-8
2
+
3
+ module Etti
4
+ class DndData
5
+ def initialize type, data
6
+ @type = type
7
+ @data = data
8
+ end
9
+
10
+ attr_reader :type, :data
11
+ end
12
+ end
@@ -0,0 +1,14 @@
1
+ #encoding: UTF-8
2
+
3
+ module Etti
4
+ module Element
5
+ class Base
6
+ def initialize x=nil, y=nil
7
+ @x = x || 0.0
8
+ @y = y || 0.0
9
+ @rotation = 0.0
10
+ @color = [0.0, 0.0, 0.0, 1.0]
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,109 @@
1
+ #encoding: UTF-8
2
+
3
+ module Etti
4
+ module Element
5
+ class Data < Etti::Element::Text
6
+ SHOW_AS_TEXT = 0
7
+ SHOW_AS_QR = 1
8
+ QR_ERROR_LEVELS = [:low, :medium, :quarter, :high]
9
+ QR_ENCODING = [:numeric, :alphanumeric, :ascii, :kanji]
10
+ def initialize dataGroup, text, x=nil, y=nil, size=nil
11
+ super text, x, y, size
12
+ @dataGroup = dataGroup
13
+ @qrWidth = 10.0
14
+ @qrHeight = 10.0
15
+ @qrVersion = 1
16
+ @qrErrorCorrection = :low
17
+ @qrEncoding = :ascii
18
+ @showAs = SHOW_AS_TEXT
19
+ end
20
+ attr_reader :dataGroup
21
+
22
+
23
+ def set_by_name name, val
24
+ if name == 'qrWidth' then @qrWidth = val.to_f; return;
25
+ elsif name == 'qrHeight' then @qrHeight = val.to_f; return;
26
+ elsif name == 'qrVersion' then @qrVersion = val.to_i; return;
27
+ elsif name == 'qrErrorCorrection' then @qrErrorCorrection = QR_ERROR_LEVELS[val.to_i]; return;
28
+ elsif name == 'qrEncoding' then @qrEncoding = QR_ENCODING[val.to_i]; return;
29
+ elsif name == 'showAs' then @showAs = val; return; end
30
+ super name, val
31
+ end
32
+
33
+
34
+ def get_by_name name
35
+ if name == 'qrWidth' then return @qrWidth;
36
+ elsif name == 'qrHeight' then return @qrHeight;
37
+ elsif name == 'qrVersion' then return @qrVersion;
38
+ elsif name == 'qrErrorCorrection' then return QR_ERROR_LEVELS.index @qrErrorCorrection;
39
+ elsif name == 'qrEncoding' then return QR_ENCODING.index @qrEncoding;
40
+ elsif name == 'showAs' then return @showAs; end
41
+ super name
42
+ end
43
+
44
+
45
+ def draw_selection view
46
+ if @showAs == SHOW_AS_TEXT
47
+ super
48
+ return
49
+ end
50
+ cc = Cairo::Context.new view.backBuffer
51
+ cc.antialias = :none
52
+ cc.line_width = 1.0
53
+ cc.set_dash [6, 6], 0
54
+ cc.set_source_rgb *$colors.selection
55
+
56
+ xd, yd = *view.pos_to_view(@x, @y)
57
+
58
+ cc.translate xd, yd
59
+ cc.rotate @rotation * Math::PI / 180.0 unless @rotation.near 0.0
60
+ height = @qrHeight * view.scale
61
+ cc.rectangle 0, -height, @qrWidth * view.scale, @qrHeight * view.scale
62
+ cc.stroke
63
+ end
64
+
65
+
66
+ def at_pos view, x, y
67
+ return super if @showAs == SHOW_AS_TEXT
68
+ ext = Rectangle.new @x, @y - @qrHeight, @qrWidth, @qrHeight
69
+ a = -@rotation * Math::PI / 180.0
70
+ xr = (x - @x) * Math.cos(a) - (y - @y) * Math.sin(a)
71
+ yr = (y - @y) * Math.cos(a) + (x - @x) * Math.sin(a)
72
+ ext.in(xr + @x, yr + @y)
73
+ end
74
+
75
+
76
+ def redraw view, cc
77
+ return if @text.nil?
78
+ cc.save
79
+ cc.set_source_rgba *@color
80
+ xd, yd = *view.pos_to_view(@x, @y)
81
+ cc.translate xd, yd
82
+ cc.rotate @rotation * Math::PI / 180.0
83
+ cc.antialias = :subpixel
84
+
85
+ if @showAs == SHOW_AS_TEXT
86
+ cc.font_size = @size * view.scale
87
+ cc.show_text @text
88
+ else
89
+ qr = QREncoder.encode @text, :version => @qrVersion,
90
+ :correction => @qrErrorCorrection,
91
+ :mode => @qrEncoding
92
+ width = qr.width
93
+ height = @qrHeight * view.scale
94
+ pw = @qrWidth * view.scale / width
95
+ ph = @qrHeight * view.scale / width
96
+ qr.pixels.each_with_index do |row_data, row|
97
+ row_data.each_with_index do |pixel, col|
98
+ next if pixel == 0
99
+ cc.rectangle col * pw, row * ph - height, pw, ph
100
+ cc.fill.stroke
101
+ end
102
+ end
103
+ end
104
+ cc.stroke
105
+ cc.restore
106
+ end
107
+ end
108
+ end
109
+ end
@@ -0,0 +1,74 @@
1
+ #encoding: UTF-8
2
+
3
+ module Etti
4
+ module Element
5
+ class Text < Etti::Element::Base
6
+ def initialize text, x=nil, y=nil, size=nil
7
+ super x, y
8
+ @text = text || ''
9
+ @size = size || 4.0
10
+ end
11
+
12
+ def set_by_name name, val
13
+ if name == 'text' then @text = val; return; end
14
+ if name == 'pos_x' then @x = val.to_f; return; end
15
+ if name == 'pos_y' then @y = val.to_f; return; end
16
+ if name == 'size' then @size = val.to_f; return; end
17
+ if name == 'rotation' then @rotation = val.to_f; return; end
18
+ if name == 'color' then @color = val; return; end
19
+ end
20
+
21
+
22
+ def get_by_name name
23
+ if name == 'text' then return @text;
24
+ elsif name == 'pos_x' then return @x;
25
+ elsif name == 'pos_y' then return @y;
26
+ elsif name == 'size' then return @size;
27
+ elsif name == 'rotation' then return @rotation;
28
+ elsif name == 'color' then return @color; end
29
+ end
30
+
31
+
32
+ def redraw
33
+
34
+ end
35
+
36
+
37
+ def draw_selection view
38
+ cc = Cairo::Context.new view.backBuffer
39
+ cc.antialias = :none
40
+ cc.line_width = 1.0
41
+ cc.set_dash [6, 6], 0
42
+ cc.set_source_rgb *$colors.selection
43
+
44
+ cc.font_size = @size * view.scale
45
+ ext = cc.text_extents @text
46
+ xd, yd = *view.pos_to_view(@x, @y)
47
+
48
+ cc.translate xd, yd
49
+ cc.rotate @rotation * Math::PI / 180.0 unless @rotation.near 0.0
50
+ cc.rectangle 0, ext.y_bearing, ext.width, ext.height
51
+ cc.stroke
52
+ end
53
+
54
+
55
+ def at_pos view, x, y
56
+ ext = get_extent view
57
+ a = -@rotation * Math::PI / 180.0
58
+ xr = (x - @x) * Math.cos(a) - (y - @y) * Math.sin(a)
59
+ yr = (y - @y) * Math.cos(a) + (x - @x) * Math.sin(a)
60
+ ext.in(xr + @x, yr + @y)
61
+ end
62
+
63
+
64
+ def get_extent view
65
+ cc = Cairo::Context.new view.backBuffer
66
+ cc.font_size = @size * view.scale
67
+ ext = cc.text_extents @text
68
+ w = ext.width() / view.scale
69
+ y = @y + (ext.y_bearing() / view.scale)
70
+ Rectangle.new @x, y, w, @size
71
+ end
72
+ end
73
+ end
74
+ end
@@ -0,0 +1,67 @@
1
+ #encoding: UTF-8
2
+
3
+ module Etti
4
+ module FileReader
5
+
6
+ include GetText
7
+ GetText.bindtextdomain 'etti', :path => Etti::LOCALE_PATH
8
+
9
+ # message codes from the callback
10
+ OK = 1
11
+ WARNING = 2
12
+ ERROR = 4
13
+ # return values to the callback
14
+ YES = 1
15
+ YES_ALLWAYS = 2
16
+ NO = 4
17
+ NO_ALLWAYAS = 8
18
+
19
+ # path = path to the data file
20
+ # separator = the separator for the split function to each line
21
+ # max_slices = the maximum number of slices each line split to
22
+ # callback {} = block to pass warnings and errors to
23
+ def data_read path, separator, max_slices, &callback
24
+ unless File.readable? path
25
+ callback.call ERROR, _("%s\n is not readable") % path
26
+ return
27
+ end
28
+
29
+ fm = FileMagic.mime
30
+ mime = fm.file path
31
+ unless mime.start_with? 'text/plain;'
32
+ answer = callback.call(WARNING,
33
+ _("Files other then plain text are not supported.\n" +
34
+ "Should the file be loaded anyway?"))
35
+ return if answer != YES
36
+ end
37
+
38
+ file = File.new path, 'r'
39
+
40
+ # warn the user if the file is bigger then 1 MB
41
+ size = file.size
42
+ if size > 1_000_000
43
+ mb = sprintf "%.3f", size.to_f / 1_000_000
44
+ answer= callback.call(WARNING,
45
+ _("The selected file is very big (%s MB)\n" +
46
+ "Do you really want to open it?") % mb)
47
+ if answer != YES
48
+ file.close
49
+ return
50
+ else
51
+ if remind
52
+ end
53
+ end
54
+ end
55
+
56
+ lines = []
57
+ cols = 0
58
+ file.each do |line|
59
+ toc = line.strip.split(separator, max_slices)
60
+ lines << toc
61
+ cols = cols.max toc.length
62
+ end
63
+ [lines, cols]
64
+ end
65
+ module_function :data_read
66
+ end
67
+ end
@@ -0,0 +1,8 @@
1
+
2
+
3
+ class Array
4
+ def extract_args!
5
+ last.is_a?(::Hash) ? pop : {}
6
+ end unless [].respond_to?(:extract_args!)
7
+ end
8
+
@@ -0,0 +1,94 @@
1
+ # monkey patches
2
+
3
+ module Cairo
4
+ class Context
5
+ def shadow_mp x, y, width, height, size, sd=nil
6
+ sides = 0
7
+ if sd.nil?
8
+ sides = 15
9
+ else
10
+ sides += 1 if sd.include? 'l'
11
+ sides += 2 if sd.include? 'r'
12
+ sides += 4 if sd.include? 't'
13
+ sides += 8 if sd.include? 'b'
14
+ end
15
+
16
+ # borders #
17
+ # left
18
+ if sides & 1 > 0
19
+ pat = Cairo::LinearPattern.new x, y, x - size, y
20
+ shadow_pattern_add_stopps pat
21
+ self.rectangle x - size, y, size, height
22
+ self.set_source pat
23
+ self.fill
24
+ end
25
+
26
+ # right
27
+ if sides & 2 > 0
28
+ pat = Cairo::LinearPattern.new x + width, y, x + width + size, y
29
+ shadow_pattern_add_stopps pat
30
+ self.rectangle x + width, y, x + width + size, height
31
+ self.set_source pat
32
+ self.fill
33
+ end
34
+
35
+ # top
36
+ if sides & 4 > 0
37
+ pat = Cairo::LinearPattern.new x, y, x, y - size
38
+ shadow_pattern_add_stopps pat
39
+ self.rectangle x, y - size, width, size
40
+ self.set_source pat
41
+ self.fill
42
+ end
43
+
44
+ # bottom
45
+ if sides & 8 > 0
46
+ pat = Cairo::LinearPattern.new x, y + height, x, y + height + size
47
+ shadow_pattern_add_stopps pat
48
+ self.rectangle x, y + height, width, y + height + size
49
+ self.set_source pat
50
+ self.fill
51
+ end
52
+
53
+ # corners #
54
+ # top left
55
+ if sides & 5 > 0
56
+ pat = Cairo::RadialPattern.new x, y, 0, x, y, size
57
+ shadow_pattern_add_stopps pat
58
+ self.rectangle x - size, y - size, size, size
59
+ self.set_source(pat).fill
60
+ end
61
+
62
+ # top right
63
+ if sides & 6 > 0
64
+ pat = Cairo::RadialPattern.new x + width, y, 0, x + width, y, size
65
+ shadow_pattern_add_stopps pat
66
+ self.rectangle x + width, y - size, size, size
67
+ self.set_source(pat).fill
68
+ end
69
+
70
+ # bottom left
71
+ if sides & 9 > 0
72
+ pat = Cairo::RadialPattern.new x, y + height, 0, x, y + height, size
73
+ shadow_pattern_add_stopps pat
74
+ self.rectangle x - size, y + height, size, size
75
+ self.set_source(pat).fill
76
+ end
77
+
78
+ # bottom right
79
+ if sides & 10 > 0
80
+ pat = Cairo::RadialPattern.new x + width, y + height, 0, x + width, y + height, size
81
+ shadow_pattern_add_stopps pat
82
+ self.rectangle x + width, y + height, size, size
83
+ self.set_source(pat).fill
84
+ end
85
+ end
86
+
87
+ private
88
+ def shadow_pattern_add_stopps pat
89
+ pat.add_color_stop_rgba 0.0, 0.4, 0.4, 0.4, 0.6
90
+ pat.add_color_stop_rgba 1.0, 1, 1, 1, 0
91
+ end
92
+
93
+ end
94
+ end
@@ -0,0 +1,7 @@
1
+
2
+
3
+ module Gtk
4
+ class EventBox
5
+ attr_accessor :dnd_data
6
+ end
7
+ end