p1788 0.1.0 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,1249 @@
1
+ /* Copyright (C) 2022 Théotime Bollengier <theotime.bollengier@ensta-bretagne.fr>
2
+ *
3
+ * This file is part of P1788. <https://gitlab.ensta-bretagne.fr/bollenth/p1788>
4
+ *
5
+ * P1788 is free software: you can redistribute it and/or modify it
6
+ * under the terms of the GNU General Public License as published
7
+ * by the Free Software Foundation, either version 3 of the License,
8
+ * or (at your option) any later version.
9
+ *
10
+ * P1788 is distributed in the hope that it will be useful,
11
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13
+ * See the GNU General Public License for more details.
14
+ *
15
+ * You should have received a copy of the GNU General Public License
16
+ * along with P1788. If not, see <https://www.gnu.org/licenses/>. 
17
+ */
18
+
19
+ /* TODO
20
+ * wrapper:
21
+ * - commands
22
+ * - color
23
+ * reset figure
24
+ * do not repeat commands, ex: stroke on then stroke of
25
+ */
26
+
27
+ #include <ruby.h>
28
+ #include "p1788.hh"
29
+ #include "figure.hh"
30
+
31
+
32
+ VALUE c_Figure;
33
+
34
+
35
+ static ID id_width;
36
+ static ID id_height;
37
+ static ID id_xrange;
38
+ static ID id_yrange;
39
+ static ID id_with_decorations;
40
+ static ID id_title;
41
+ static ID id_xlabel;
42
+ static ID id_ylabel;
43
+ static ID id_background_color;
44
+ static ID id_decoration_color;
45
+ static ID id_decoration_font;
46
+ static ID id_decoration_font_size;
47
+ static ID id_decoration_line_width;
48
+ static ID id_label_font_size;
49
+ static ID id_title_font_size;
50
+ static ID id_title_in_bold;
51
+
52
+
53
+ static void p1788_figure_free(void *p)
54
+ {
55
+ P1788Figure::Figure *f = (P1788Figure::Figure*)p;
56
+ delete f;
57
+ }
58
+
59
+
60
+ static size_t p1788_figure_size(const void* p)
61
+ {
62
+ P1788Figure::Figure *f = (P1788Figure::Figure*)p;
63
+ return f->allocated_size();
64
+ }
65
+
66
+
67
+ static const rb_data_type_t p1788_figure_type = {
68
+ .wrap_struct_name = "P1788::Figure",
69
+ .function = {
70
+ .dmark = NULL,
71
+ .dfree = p1788_figure_free,
72
+ .dsize = p1788_figure_size,
73
+ },
74
+ .parent = NULL,
75
+ .data = NULL,
76
+ .flags = RUBY_TYPED_FREE_IMMEDIATELY
77
+ };
78
+
79
+
80
+ static VALUE p1788_figure_alloc(VALUE klass)
81
+ {
82
+ P1788Figure::Figure *f = new P1788Figure::Figure();
83
+ return TypedData_Wrap_Struct(klass, &p1788_figure_type, f);
84
+ }
85
+
86
+
87
+ static inline P1788Figure::Figure& p1788_figure_rb2ref(VALUE obj) {
88
+ P1788Figure::Figure *f;
89
+ TypedData_Get_Struct(obj, P1788Figure::Figure, &p1788_figure_type, f);
90
+ return *f;
91
+ }
92
+
93
+
94
+ static const char *color_regexp = "^((\\#(\\h{8}))|(((\\#(\\h{6}))|([krgybmcwtKRGYBMCWT]))(\\.\\d+)?))$";
95
+ // match[] 12 3 456 7 8 9
96
+
97
+ /* Tango colors */
98
+ #define P1788_FIGURE_COLOR_k 0x00000000
99
+ #define P1788_FIGURE_COLOR_r 0xCC000000
100
+ #define P1788_FIGURE_COLOR_g 0x4E9A0600
101
+ #define P1788_FIGURE_COLOR_y 0xC4A00000
102
+ #define P1788_FIGURE_COLOR_b 0x3465A400
103
+ #define P1788_FIGURE_COLOR_m 0x75507B00
104
+ #define P1788_FIGURE_COLOR_c 0x06989A00
105
+ #define P1788_FIGURE_COLOR_w 0xD3D7CF00
106
+ #define P1788_FIGURE_COLOR_K 0x55575300
107
+ #define P1788_FIGURE_COLOR_R 0xEF292900
108
+ #define P1788_FIGURE_COLOR_G 0x8AE23400
109
+ #define P1788_FIGURE_COLOR_Y 0xFCE94F00
110
+ #define P1788_FIGURE_COLOR_B 0x739FCF00
111
+ #define P1788_FIGURE_COLOR_M 0xAD7FA800
112
+ #define P1788_FIGURE_COLOR_C 0x34E2E200
113
+ #define P1788_FIGURE_COLOR_W 0xFFFFFF00
114
+
115
+
116
+ static unsigned int p1788_figure_parse_color(VALUE c)
117
+ {
118
+ if (RB_TYPE_P(c, T_FIXNUM) | RB_TYPE_P(c, T_BIGNUM))
119
+ return NUM2UINT(c);
120
+ if (!RB_TYPE_P(c, T_STRING))
121
+ rb_raise(rb_eTypeError, "expecting a string or an integer, not a %" PRIsVALUE,
122
+ rb_class_name(rb_class_of(c)));
123
+ unsigned int col = 0;
124
+ VALUE cr = rb_str_new_static(color_regexp, 62);
125
+ VALUE regexp = rb_class_new_instance(1, &cr, rb_cRegexp);
126
+ VALUE match = rb_funcallv(c, id_match, 1, &regexp);
127
+ if (NIL_P(match))
128
+ rb_raise(rb_eRuntimeError, "cannot parse \"%" PRIsVALUE "\" as a color", c);
129
+ VALUE m;
130
+
131
+ /* Full hexa */
132
+ m = rb_funcall(match, id_brackets, 1, INT2NUM(3));
133
+ if (m != Qnil)
134
+ col = NUM2UINT(rb_funcall(m, id_to_i, 1, INT2NUM(16)));
135
+ else {
136
+ /* Alpha */
137
+ m = rb_funcall(match, id_brackets, 1, INT2NUM(9));
138
+ if (m != Qnil)
139
+ col |= std::min(255, std::max(0, (int)round(255.0*NUM2DBL(rb_funcall(m, id_to_f, 0)))));
140
+ else
141
+ col |= 0x000000ff;
142
+ /* Color hexa */
143
+ m = rb_funcall(match, id_brackets, 1, INT2NUM(7));
144
+ if (m != Qnil)
145
+ col |= NUM2UINT(rb_funcall(m, id_to_i, 1, INT2NUM(16))) << 8;
146
+ /* Color leter */
147
+ m = rb_funcall(match, id_brackets, 1, INT2NUM(8));
148
+ if (m != Qnil) {
149
+ switch (*StringValuePtr(m)) {
150
+ case 'k': col |= P1788_FIGURE_COLOR_k; break;
151
+ case 'r': col |= P1788_FIGURE_COLOR_r; break;
152
+ case 'g': col |= P1788_FIGURE_COLOR_g; break;
153
+ case 'y': col |= P1788_FIGURE_COLOR_y; break;
154
+ case 'b': col |= P1788_FIGURE_COLOR_b; break;
155
+ case 'm': col |= P1788_FIGURE_COLOR_m; break;
156
+ case 'c': col |= P1788_FIGURE_COLOR_c; break;
157
+ case 'w': col |= P1788_FIGURE_COLOR_w; break;
158
+ case 'K': col |= P1788_FIGURE_COLOR_K; break;
159
+ case 'R': col |= P1788_FIGURE_COLOR_R; break;
160
+ case 'G': col |= P1788_FIGURE_COLOR_G; break;
161
+ case 'Y': col |= P1788_FIGURE_COLOR_Y; break;
162
+ case 'B': col |= P1788_FIGURE_COLOR_B; break;
163
+ case 'M': col |= P1788_FIGURE_COLOR_M; break;
164
+ case 'C': col |= P1788_FIGURE_COLOR_C; break;
165
+ case 'W': col |= P1788_FIGURE_COLOR_W; break;
166
+ default:
167
+ col &= 0xffffff00;
168
+ }
169
+ }
170
+ }
171
+ return col;
172
+ }
173
+
174
+
175
+ static inline VALUE p1788_cppstring_to_rbstring_utf8(const std::string& cppstring) {
176
+ return rb_str_freeze(rb_utf8_str_new(cppstring.c_str(), cppstring.size()));
177
+ }
178
+
179
+
180
+ static std::string p1788_rbstring_to_cppstring(VALUE rbstring) {
181
+ if (!RB_TYPE_P(rbstring, T_STRING))
182
+ rb_raise(rb_eTypeError, "expecting a string, not a %" PRIsVALUE, rb_class_name(rb_class_of(rbstring)));
183
+ return std::string(StringValuePtr(rbstring), RSTRING_LEN(rbstring));
184
+ }
185
+
186
+
187
+ /* Return the number of bytes allocated for the figure.
188
+ * @!visibility private
189
+ * @return [Integer]
190
+ */
191
+ static VALUE p1788_figure_allocated_size(VALUE self)
192
+ {
193
+ P1788Figure::Figure& f = p1788_figure_rb2ref(self);
194
+ return SIZET2NUM(p1788_figure_size(&f));
195
+ }
196
+
197
+
198
+ /* The title to be drawn on top of the figure.
199
+ * Set the title to _nil_ to remove the title.
200
+ * @return [String, nil]
201
+ * @!parse [ruby] module P1788; class Figure; attr_accessor :title; end; end
202
+ */
203
+ static VALUE p1788_figure_get_title(VALUE self)
204
+ {
205
+ P1788Figure::Figure& f = p1788_figure_rb2ref(self);
206
+ const std::string& t = f.title();
207
+ if (t.empty())
208
+ return Qnil;
209
+ return p1788_cppstring_to_rbstring_utf8(t);
210
+ }
211
+
212
+
213
+ static VALUE p1788_figure_set_title(VALUE self, VALUE str)
214
+ {
215
+ P1788Figure::Figure& f = p1788_figure_rb2ref(self);
216
+ if (NIL_P(str))
217
+ f.set_title("");
218
+ else
219
+ f.set_title(p1788_rbstring_to_cppstring(rb_funcallv(str, id_to_s, 0, NULL)));
220
+ return self;
221
+ }
222
+
223
+
224
+ /* The label to be drawn below the horizontal axis.
225
+ * Set the label to _nil_ to remove it.
226
+ * @return [String, nil]
227
+ * @!parse [ruby] module P1788; class Figure; attr_accessor :xlabel; end; end
228
+ */
229
+ static VALUE p1788_figure_get_xlabel(VALUE self)
230
+ {
231
+ P1788Figure::Figure& f = p1788_figure_rb2ref(self);
232
+ const std::string& t = f.xlabel();
233
+ if (t.empty())
234
+ return Qnil;
235
+ return p1788_cppstring_to_rbstring_utf8(t);
236
+ }
237
+
238
+
239
+ static VALUE p1788_figure_set_xlabel(VALUE self, VALUE str)
240
+ {
241
+ P1788Figure::Figure& f = p1788_figure_rb2ref(self);
242
+ if (NIL_P(str))
243
+ f.set_xlabel("");
244
+ else
245
+ f.set_xlabel(p1788_rbstring_to_cppstring(rb_funcallv(str, id_to_s, 0, NULL)));
246
+ return self;
247
+ }
248
+
249
+
250
+ /* The label to be drawn on the left of the vertical axis.
251
+ * Set the label to _nil_ to remove it.
252
+ * @return [String, nil]
253
+ * @!parse [ruby] module P1788; class Figure; attr_accessor :ylabel; end; end
254
+ */
255
+ static VALUE p1788_figure_get_ylabel(VALUE self)
256
+ {
257
+ P1788Figure::Figure& f = p1788_figure_rb2ref(self);
258
+ const std::string& t = f.ylabel();
259
+ if (t.empty())
260
+ return Qnil;
261
+ return p1788_cppstring_to_rbstring_utf8(t);
262
+ }
263
+
264
+
265
+ static VALUE p1788_figure_set_ylabel(VALUE self, VALUE str)
266
+ {
267
+ P1788Figure::Figure& f = p1788_figure_rb2ref(self);
268
+ if (NIL_P(str))
269
+ f.set_ylabel("");
270
+ else
271
+ f.set_ylabel(p1788_rbstring_to_cppstring(rb_funcallv(str, id_to_s, 0, NULL)));
272
+ return self;
273
+ }
274
+
275
+
276
+ /* The font used to display the title, labels and graduations.
277
+ * Set the font to _nil_ to reset it to its default ("Sans").
278
+ * @return [String, nil]
279
+ * @!parse [ruby] module P1788; class Figure; attr_accessor :decoration_font; end; end
280
+ */
281
+ static VALUE p1788_figure_get_decoration_font(VALUE self)
282
+ {
283
+ P1788Figure::Figure& f = p1788_figure_rb2ref(self);
284
+ const std::string& t = f.graduation_font();
285
+ if (t.empty())
286
+ return Qnil;
287
+ return p1788_cppstring_to_rbstring_utf8(t);
288
+ }
289
+
290
+
291
+ static VALUE p1788_figure_set_decoration_font(VALUE self, VALUE str)
292
+ {
293
+ P1788Figure::Figure& f = p1788_figure_rb2ref(self);
294
+ if (NIL_P(str))
295
+ f.set_graduation_font("");
296
+ else
297
+ f.set_graduation_font(p1788_rbstring_to_cppstring(rb_funcallv(str, id_to_s, 0, NULL)));
298
+ return self;
299
+ }
300
+
301
+
302
+ /* Size of the font used to display the title, labels and graduations.
303
+ * @return [Float]
304
+ * @!parse [ruby] module P1788; class Figure; attr_accessor :decoration_font_size; end; end
305
+ */
306
+ static VALUE p1788_figure_get_decoration_font_size(VALUE self)
307
+ {
308
+ P1788Figure::Figure& f = p1788_figure_rb2ref(self);
309
+ return DBL2NUM(f.graduation_font_size());
310
+ }
311
+
312
+
313
+ static VALUE p1788_figure_set_decoration_font_size(VALUE self, VALUE s)
314
+ {
315
+ P1788Figure::Figure& f = p1788_figure_rb2ref(self);
316
+ if (NIL_P(s))
317
+ f.set_graduation_font_size(0.0);
318
+ else
319
+ f.set_graduation_font_size((float)NUM2DBL(rb_funcallv(s, id_to_f, 0, NULL)));
320
+ return self;
321
+ }
322
+
323
+
324
+ /* Size of the font used to display the title.
325
+ *
326
+ * If set to _nil_, the title will automatically be drawn at 1.23 times the decoration font size.
327
+ * @return [Float, nil]
328
+ * @!parse [ruby] module P1788; class Figure; attr_accessor :title_font_size; end; end
329
+ */
330
+ static VALUE p1788_figure_get_title_font_size(VALUE self)
331
+ {
332
+ double s = p1788_figure_rb2ref(self).title_font_size_as_set();
333
+ if (s <= 0.0)
334
+ return Qnil;
335
+ return DBL2NUM(s);
336
+ }
337
+
338
+
339
+ static VALUE p1788_figure_set_title_font_size(VALUE self, VALUE s)
340
+ {
341
+ P1788Figure::Figure& f = p1788_figure_rb2ref(self);
342
+ if (NIL_P(s))
343
+ f.set_title_font_size(0.0);
344
+ else
345
+ f.set_title_font_size((float)NUM2DBL(rb_funcallv(s, id_to_f, 0, NULL)));
346
+ return self;
347
+ }
348
+
349
+
350
+ /* Size of the font used to display the labels.
351
+ *
352
+ * If set to _nil_, the labels will automatically be drawn at 1.1 times the decoration font size.
353
+ * @return [Float, nil]
354
+ * @!parse [ruby] module P1788; class Figure; attr_accessor :label_font_size; end; end
355
+ */
356
+ static VALUE p1788_figure_get_label_font_size(VALUE self)
357
+ {
358
+ double s = p1788_figure_rb2ref(self).label_font_size_as_set();
359
+ if (s <= 0.0)
360
+ return Qnil;
361
+ return DBL2NUM(s);
362
+ }
363
+
364
+
365
+ static VALUE p1788_figure_set_label_font_size(VALUE self, VALUE s)
366
+ {
367
+ P1788Figure::Figure& f = p1788_figure_rb2ref(self);
368
+ if (NIL_P(s))
369
+ f.set_label_font_size(0.0);
370
+ else
371
+ f.set_label_font_size((float)NUM2DBL(rb_funcallv(s, id_to_f, 0, NULL)));
372
+ return self;
373
+ }
374
+
375
+
376
+ /* Line width for drawing the frame around the figure.
377
+ * @return [Float]
378
+ * @!parse [ruby] module P1788; class Figure; attr_accessor :decoration_line_width; end; end
379
+ */
380
+ static VALUE p1788_figure_get_decoration_line_width(VALUE self)
381
+ {
382
+ P1788Figure::Figure& f = p1788_figure_rb2ref(self);
383
+ return DBL2NUM(f.graduation_stroke_width());
384
+ }
385
+
386
+
387
+ static VALUE p1788_figure_set_decoration_line_width(VALUE self, VALUE w)
388
+ {
389
+ P1788Figure::Figure& f = p1788_figure_rb2ref(self);
390
+ f.set_graduation_stroke_width((float)NUM2DBL(rb_funcallv(w, id_to_f, 0, NULL)));
391
+ return self;
392
+ }
393
+
394
+
395
+ /* Color of the decoration (frame, graduations, title and axis labels).
396
+ *
397
+ * The color is encoded into a 32-bit integer that can be split in hexadecimal as: 0xRRGGBBAA,
398
+ * for the red, green, blue and alpha channels.
399
+ *
400
+ * This attribute can also be set to a string, like `"#cc000080"`, `"#cc0000.5"`,`"r.5"` or `"W"`.
401
+ * @return [Integer]
402
+ * @!parse [ruby] module P1788; class Figure; attr_accessor :decoration_color; end; end
403
+ */
404
+ static VALUE p1788_figure_get_decoration_color(VALUE self)
405
+ {
406
+ return UINT2NUM(p1788_figure_rb2ref(self).graduation_color());
407
+ }
408
+
409
+ static VALUE p1788_figure_set_decoration_color(VALUE self, VALUE c)
410
+ {
411
+ unsigned int n = p1788_figure_parse_color(c);
412
+ p1788_figure_rb2ref(self).set_graduation_color(n);
413
+ return self;
414
+ }
415
+
416
+
417
+ /* Background color of the figure.
418
+ *
419
+ * The color is encoded into a 32-bit integer that can be split in hexadecimal as: 0xRRGGBBAA,
420
+ * for the red, green, blue and alpha channels.
421
+ *
422
+ * This attribute can also be set to a string, like `"#cc000080"`, `"#cc0000.5"`,`"r.5"` or `"W"`.
423
+ * @return [Integer]
424
+ * @!parse [ruby] module P1788; class Figure; attr_accessor :background_color; end; end
425
+ */
426
+ static VALUE p1788_figure_get_background_color(VALUE self)
427
+ {
428
+ return UINT2NUM(p1788_figure_rb2ref(self).background_color());
429
+ }
430
+
431
+ static VALUE p1788_figure_set_background_color(VALUE self, VALUE c)
432
+ {
433
+ unsigned int n = p1788_figure_parse_color(c);
434
+ p1788_figure_rb2ref(self).set_background_color(n);
435
+ return self;
436
+ }
437
+
438
+
439
+ /* The width of the output image, in pixels.
440
+ * Set the width to _nil_ or 0 to get automatic sizing.
441
+ * @return [Integer, nil]
442
+ * @!parse [ruby] module P1788; class Figure; attr_accessor :width; end; end
443
+ */
444
+ static VALUE p1788_figure_get_width(VALUE self)
445
+ {
446
+ P1788Figure::Figure& f = p1788_figure_rb2ref(self);
447
+ int i = f.width();
448
+ if (i < 1)
449
+ return Qnil;
450
+ return INT2NUM(i);
451
+ }
452
+
453
+ static VALUE p1788_figure_set_width(VALUE self, VALUE w)
454
+ {
455
+ P1788Figure::Figure& f = p1788_figure_rb2ref(self);
456
+ if (NIL_P(w)) {
457
+ f.set_width(0);
458
+ return self;
459
+ }
460
+ int i = NUM2INT(rb_funcallv(w, id_to_i, 0, NULL));
461
+ if (i <= 0)
462
+ f.set_width(0);
463
+ else
464
+ f.set_width(i);
465
+ return self;
466
+ }
467
+
468
+
469
+ /* The height of the output image, in pixels.
470
+ * Set the height to _nil_ or 0 to get automatic sizing.
471
+ * @return [Integer, nil]
472
+ * @!parse [ruby] module P1788; class Figure; attr_accessor :height; end; end
473
+ */
474
+ static VALUE p1788_figure_get_height(VALUE self)
475
+ {
476
+ P1788Figure::Figure& f = p1788_figure_rb2ref(self);
477
+ int i = f.height();
478
+ if (i < 1)
479
+ return Qnil;
480
+ return INT2NUM(i);
481
+ }
482
+
483
+ static VALUE p1788_figure_set_height(VALUE self, VALUE h)
484
+ {
485
+ P1788Figure::Figure& f = p1788_figure_rb2ref(self);
486
+ if (NIL_P(h)) {
487
+ f.set_height(0);
488
+ return self;
489
+ }
490
+ int i = NUM2INT(rb_funcallv(h, id_to_i, 0, NULL));
491
+ if (i <= 0)
492
+ f.set_height(0);
493
+ else
494
+ f.set_height(i);
495
+ return self;
496
+ }
497
+
498
+
499
+ /* The horizontal range that will be displayed.
500
+ * Set _xrange_ to _nil_ or an empty interval to get automatic range adjustment.
501
+ * @return [Interval, nil]
502
+ * @!parse [ruby] module P1788; class Figure; attr_accessor :xrange; end; end
503
+ */
504
+ static VALUE p1788_figure_get_xrange(VALUE self)
505
+ {
506
+ P1788Figure::Figure& f = p1788_figure_rb2ref(self);
507
+ const Interval& r = f.xlim();
508
+ if (!Interval::is_common_interval(r))
509
+ return Qnil;
510
+ VALUE res;
511
+ P1788_NEW_RB_INTERVAL(res, r);
512
+ return res;
513
+ }
514
+
515
+ static VALUE p1788_figure_set_xrange(VALUE self, VALUE rng)
516
+ {
517
+ P1788Figure::Figure& f = p1788_figure_rb2ref(self);
518
+ if (NIL_P(rng))
519
+ f.set_xlimit(Interval());
520
+ else
521
+ f.set_xlimit(p1788_rbobj2interval(rng));
522
+ return self;
523
+ }
524
+
525
+
526
+ /* The vertical range that will be displayed.
527
+ * Set _yrange_ to _nil_ or an empty interval to get automatic range adjustment.
528
+ * @return [Interval, nil]
529
+ * @!parse [ruby] module P1788; class Figure; attr_accessor :yrange; end; end
530
+ */
531
+ static VALUE p1788_figure_get_yrange(VALUE self)
532
+ {
533
+ P1788Figure::Figure& f = p1788_figure_rb2ref(self);
534
+ const Interval& r = f.ylim();
535
+ if (!Interval::is_common_interval(r))
536
+ return Qnil;
537
+ VALUE res;
538
+ P1788_NEW_RB_INTERVAL(res, r);
539
+ return res;
540
+ }
541
+
542
+ static VALUE p1788_figure_set_yrange(VALUE self, VALUE rng)
543
+ {
544
+ P1788Figure::Figure& f = p1788_figure_rb2ref(self);
545
+ if (NIL_P(rng))
546
+ f.set_ylimit(Interval());
547
+ else
548
+ f.set_ylimit(p1788_rbobj2interval(rng));
549
+ return self;
550
+ }
551
+
552
+
553
+ /* Set the horizontal and vertical range that will be displayed.
554
+ *
555
+ * This is the same as calling both {xrange=} and {yrange=}.
556
+ * Set to _nil_ to reset ranges and get automatic display range according to the content.
557
+ * @param box [IntervalVector, nil] an interval vector with at least two elements, or nil
558
+ * @return [self]
559
+ */
560
+ static VALUE p1788_figure_set_range(VALUE self, VALUE box)
561
+ {
562
+ P1788Figure::Figure& f = p1788_figure_rb2ref(self);
563
+ if (NIL_P(box)) {
564
+ f.set_xlimit(Interval());
565
+ f.set_ylimit(Interval());
566
+ return self;
567
+ }
568
+ if (!is_an_interval_vector(box))
569
+ rb_raise(rb_eTypeError, "expecting a %" PRIsVALUE ", not a %" PRIsVALUE,
570
+ rb_class_name(c_IntervalVector), rb_class_name(rb_class_of(box)));
571
+ const IntervalVector& r = p1788_vector_rb2ref(box);
572
+ if (r.size() < 2)
573
+ rb_raise(rb_eRuntimeError, "the interval vector must have at least two elements (for the x an y axis)");
574
+ f.set_xlimit(r[0]);
575
+ f.set_ylimit(r[1]);
576
+ return self;
577
+ }
578
+
579
+
580
+ /* Draw decorations around the figure?.
581
+ *
582
+ * If set to _false_, no frame, ticks, title nor labels will be drawn around the figure,
583
+ * even if they are set. The output image size will be _width_ x _height_.
584
+ *
585
+ * If set to _true_, a frame and graduations will be drawn around the figure.
586
+ * If they are set, title and labels will also be drawn.
587
+ * The output image size will be larger than _width_ x _height_.
588
+ * @return [Boolean]
589
+ * @!parse [ruby] module P1788; class Figure; attr_accessor :with_decorations; end; end
590
+ */
591
+ static VALUE p1788_figure_get_with_decorations(VALUE self)
592
+ {
593
+ P1788Figure::Figure& f = p1788_figure_rb2ref(self);
594
+ return f.print_graduations() ? Qtrue : Qfalse;
595
+ }
596
+
597
+
598
+ static VALUE p1788_figure_set_with_decorations(VALUE self, VALUE b)
599
+ {
600
+ P1788Figure::Figure& f = p1788_figure_rb2ref(self);
601
+ f.set_print_graduations((NIL_P(b) || b == Qfalse) ? false : true);
602
+ return self;
603
+ }
604
+
605
+
606
+ /* Draw the title in a bold font?
607
+ *
608
+ * If {with_decorations} is set to _true_ and
609
+ * {title} is not _nil_ nor empty,
610
+ * the title will be drawn in bold or normal weight according
611
+ * to this attribute.
612
+ * @return [Boolean]
613
+ * @!parse [ruby] module P1788; class Figure; attr_accessor :title_in_bold; end; end
614
+ */
615
+ static VALUE p1788_figure_get_title_in_bold(VALUE self)
616
+ {
617
+ P1788Figure::Figure& f = p1788_figure_rb2ref(self);
618
+ return f.title_bold() ? Qtrue : Qfalse;
619
+ }
620
+
621
+
622
+ static VALUE p1788_figure_set_title_in_bold(VALUE self, VALUE b)
623
+ {
624
+ P1788Figure::Figure& f = p1788_figure_rb2ref(self);
625
+ f.set_title_bold((NIL_P(b) || b == Qfalse) ? false : true);
626
+ return self;
627
+ }
628
+
629
+
630
+ /* Returns the union of all the boxes that have ben sent to the figure for drwawing.
631
+ * @return [IntervalVector] a two interval vector, for _x_ and _y_.
632
+ */
633
+ static VALUE p1788_figure_content_range(VALUE self)
634
+ {
635
+ P1788Figure::Figure& f = p1788_figure_rb2ref(self);
636
+ P1788Figure::Box b;
637
+ f.find_unbounded_limits(b);
638
+
639
+ IntervalVector *v = new IntervalVector(2);
640
+ (*v)[0] = b.x;
641
+ (*v)[1] = b.y;
642
+ return p1788_vector_alloc_from_pointer(v);
643
+ }
644
+
645
+
646
+ /* Returns a range that would be nice to display, according to the content of the figure.
647
+ * @return [IntervalVector] a two interval vector, for _x_ and _y_.
648
+ */
649
+ static VALUE p1788_figure_nice_range(VALUE self)
650
+ {
651
+ P1788Figure::Figure& f = p1788_figure_rb2ref(self);
652
+ P1788Figure::Box b, c;
653
+ f.find_limits(c, b);
654
+
655
+ IntervalVector *v = new IntervalVector(2);
656
+ (*v)[0] = b.x;
657
+ (*v)[1] = b.y;
658
+ return p1788_vector_alloc_from_pointer(v);
659
+ }
660
+
661
+
662
+ #ifdef CAIRO_HAS_PNG_FUNCTIONS
663
+ /* Generate the figure and write the output image in PNG format to file _file_name_.
664
+ * @param file_name [String] name of the file to write the image to.
665
+ * @return [self]
666
+ */
667
+ static VALUE p1788_figure_write_png(VALUE self, VALUE file_name)
668
+ {
669
+ file_name = rb_funcallv(file_name, id_to_s, 0, NULL);
670
+ if (RSTRING_LEN(file_name) < 1)
671
+ rb_raise(rb_eRuntimeError, "file name is empty");
672
+ file_name = rb_funcallv(rb_cFile, rb_intern("absolute_path"), 1, &file_name);
673
+ P1788Figure::Figure& f = p1788_figure_rb2ref(self);
674
+ std::string cppfname = p1788_rbstring_to_cppstring(file_name);
675
+ try {
676
+ f.write_png(cppfname);
677
+ } catch (const std::exception &e) {
678
+ rb_raise(rb_eRuntimeError, "%s", e.what());
679
+ }
680
+ return self;
681
+ }
682
+
683
+ /* Generate the figure and return its content as a string in the PNG format.
684
+ * @return [String]
685
+ */
686
+ static VALUE p1788_figure_to_png(VALUE self)
687
+ {
688
+ P1788Figure::Figure& f = p1788_figure_rb2ref(self);
689
+ std::string s;
690
+ try {
691
+ s = std::move(f.to_png());
692
+ } catch (const std::exception &e) {
693
+ rb_raise(rb_eRuntimeError, "%s", e.what());
694
+ }
695
+ return rb_usascii_str_new(s.c_str(), s.size());
696
+ }
697
+ #endif
698
+
699
+
700
+ #ifdef CAIRO_HAS_SVG_SURFACE
701
+ /* Generate the figure and write the output image in SVG format to file _file_name_.
702
+ * @param file_name [String] name of the file to write the image to.
703
+ * @return [self]
704
+ */
705
+ static VALUE p1788_figure_write_svg(VALUE self, VALUE file_name)
706
+ {
707
+ file_name = rb_funcallv(file_name, id_to_s, 0, NULL);
708
+ if (RSTRING_LEN(file_name) < 1)
709
+ rb_raise(rb_eRuntimeError, "file name is empty");
710
+ file_name = rb_funcallv(rb_cFile, rb_intern("absolute_path"), 1, &file_name);
711
+ P1788Figure::Figure& f = p1788_figure_rb2ref(self);
712
+ std::string cppfname = p1788_rbstring_to_cppstring(file_name);
713
+ try {
714
+ f.write_svg(cppfname);
715
+ } catch (const std::exception &e) {
716
+ rb_raise(rb_eRuntimeError, "%s", e.what());
717
+ }
718
+ return self;
719
+ }
720
+
721
+ /* Generate the figure and return its content as a string in the SVG format.
722
+ * @return [String]
723
+ */
724
+ static VALUE p1788_figure_to_svg(VALUE self)
725
+ {
726
+ P1788Figure::Figure& f = p1788_figure_rb2ref(self);
727
+ std::string s;
728
+ try {
729
+ s = std::move(f.to_svg());
730
+ } catch (const std::exception &e) {
731
+ rb_raise(rb_eRuntimeError, "%s", e.what());
732
+ }
733
+ return rb_usascii_str_new(s.c_str(), s.size());
734
+ }
735
+ #endif
736
+
737
+
738
+ #ifdef CAIRO_HAS_PDF_SURFACE
739
+ /* Generate the figure and write the output image in PDF format to file _file_name_.
740
+ * @param file_name [String] name of the file to write the image to.
741
+ * @return [self]
742
+ */
743
+ static VALUE p1788_figure_write_pdf(VALUE self, VALUE file_name)
744
+ {
745
+ file_name = rb_funcallv(file_name, id_to_s, 0, NULL);
746
+ if (RSTRING_LEN(file_name) < 1)
747
+ rb_raise(rb_eRuntimeError, "file name is empty");
748
+ file_name = rb_funcallv(rb_cFile, rb_intern("absolute_path"), 1, &file_name);
749
+ P1788Figure::Figure& f = p1788_figure_rb2ref(self);
750
+ std::string cppfname = p1788_rbstring_to_cppstring(file_name);
751
+ try {
752
+ f.write_pdf(cppfname);
753
+ } catch (const std::exception &e) {
754
+ rb_raise(rb_eRuntimeError, "%s", e.what());
755
+ }
756
+ return self;
757
+ }
758
+
759
+ /* Generate the figure and return its content as a string in the PDF format.
760
+ * @return [String]
761
+ */
762
+ static VALUE p1788_figure_to_pdf(VALUE self)
763
+ {
764
+ P1788Figure::Figure& f = p1788_figure_rb2ref(self);
765
+ std::string s;
766
+ try {
767
+ s = std::move(f.to_pdf());
768
+ } catch (const std::exception &e) {
769
+ rb_raise(rb_eRuntimeError, "%s", e.what());
770
+ }
771
+ return rb_usascii_str_new(s.c_str(), s.size());
772
+ }
773
+ #endif
774
+
775
+
776
+ /* Tell the figure to draw new objects (boxes) with a border.
777
+ * @see stroke_off
778
+ * @see stroke_width=
779
+ * @see stroke_color=
780
+ * @see stroke?
781
+ * @return [self]
782
+ */
783
+ static VALUE p1788_figure_stroke_on(VALUE self)
784
+ {
785
+ p1788_figure_rb2ref(self).cmd_stroke(true);
786
+ return self;
787
+ }
788
+
789
+
790
+ /* Tell the figure to draw new objects (boxes) without border.
791
+ * @see stroke_on
792
+ * @see stroke?
793
+ * @return [self]
794
+ */
795
+ static VALUE p1788_figure_stroke_off(VALUE self)
796
+ {
797
+ p1788_figure_rb2ref(self).cmd_stroke(false);
798
+ return self;
799
+ }
800
+
801
+
802
+ /* Returns _true_ if new objects (boxes) will be drawned with a border.
803
+ * @see stroke_on
804
+ * @see stroke_off
805
+ * @return [Boolean]
806
+ */
807
+ static VALUE p1788_figure_get_stroke_onoff(VALUE self)
808
+ {
809
+ return p1788_figure_rb2ref(self).do_stroke() ? Qtrue : Qfalse;
810
+ }
811
+
812
+
813
+ /* Tell the figure to fill new objects (boxes) with the fill color.
814
+ * @see fill_off
815
+ * @see fill_color=
816
+ * @see fill?
817
+ * @return [self]
818
+ */
819
+ static VALUE p1788_figure_fill_on(VALUE self)
820
+ {
821
+ p1788_figure_rb2ref(self).cmd_fill(true);
822
+ return self;
823
+ }
824
+
825
+
826
+ /* Tell the figure not to fill new objects (boxes).
827
+ * @see fill_on
828
+ * @see fill?
829
+ * @return [self]
830
+ */
831
+ static VALUE p1788_figure_fill_off(VALUE self)
832
+ {
833
+ p1788_figure_rb2ref(self).cmd_fill(false);
834
+ return self;
835
+ }
836
+
837
+
838
+ /* Returns _true_ if new objects (boxes) will be filled.
839
+ * @see fill_on
840
+ * @see fill_off
841
+ * @return [Boolean]
842
+ */
843
+ static VALUE p1788_figure_get_fill_onoff(VALUE self)
844
+ {
845
+ return p1788_figure_rb2ref(self).do_fill() ? Qtrue : Qfalse;
846
+ }
847
+
848
+
849
+ /* Set the line width of the new objects (boxes) that will be drawned.
850
+ * @see stroke_on
851
+ * @see stroke_color=
852
+ * @return [self]
853
+ */
854
+ static VALUE p1788_figure_set_stroke_width(VALUE self, VALUE w)
855
+ {
856
+ p1788_figure_rb2ref(self).cmd_stroke_width(NUM2DBL(w));
857
+ return self;
858
+ }
859
+
860
+
861
+ /* Returns the current line width used to draw the border of objects (boxes).
862
+ * @see stroke_width=
863
+ * @return [Float]
864
+ */
865
+ static VALUE p1788_figure_get_stroke_width(VALUE self)
866
+ {
867
+ return DBL2NUM(p1788_figure_rb2ref(self).stroke_width());
868
+ }
869
+
870
+
871
+ /* Set the border color of the new objects (boxes) that will be drawned.
872
+ *
873
+ * The color is encoded into a 32-bit integer that can be split in hexadecimal as: 0xRRGGBBAA,
874
+ * for the red, green, blue and alpha channels.
875
+ *
876
+ * The color can also be set to a string, like `"#cc000080"`, `"#cc0000.5"`,`"r.5"` or `"W"`.
877
+ * @param c [Integer, String]
878
+ * @see stroke_on
879
+ * @see stroke_width=
880
+ * @return [self]
881
+ */
882
+ static VALUE p1788_figure_set_stroke_color(VALUE self, VALUE c)
883
+ {
884
+ unsigned int n = p1788_figure_parse_color(c);
885
+ p1788_figure_rb2ref(self).cmd_stroke_color(n);
886
+ return self;
887
+ }
888
+
889
+
890
+ /* Returns the current color used to draw the border of objects (boxes).
891
+ * The color is encoded into a 32-bit integer that can be split in hexadecimal as: 0xRRGGBBAA,
892
+ * for the red, green, blue and alpha channels.
893
+ * @see stroke_color=
894
+ * @return [Integer]
895
+ */
896
+ static VALUE p1788_figure_get_stroke_color(VALUE self)
897
+ {
898
+ return UINT2NUM(p1788_figure_rb2ref(self).stroke_color());
899
+ }
900
+
901
+
902
+ /* Set the fill color of the new objects (boxes) that will be drawned.
903
+ *
904
+ * The color is encoded into a 32-bit integer that can be split in hexadecimal as: 0xRRGGBBAA,
905
+ * for the red, green, blue and alpha channels.
906
+ *
907
+ * The color can also be set to a string, like `"#cc000080"`, `"#cc0000.5"`,`"r.5"` or `"W"`.
908
+ * @param c [Integer, String]
909
+ * @see fill_on
910
+ * @return [self]
911
+ */
912
+ static VALUE p1788_figure_set_fill_color(VALUE self, VALUE c)
913
+ {
914
+ unsigned int n = p1788_figure_parse_color(c);
915
+ p1788_figure_rb2ref(self).cmd_fill_color(n);
916
+ return self;
917
+ }
918
+
919
+
920
+ /* Returns the current color used to fill objects (boxes).
921
+ * The color is encoded into a 32-bit integer that can be split in hexadecimal as: 0xRRGGBBAA,
922
+ * for the red, green, blue and alpha channels.
923
+ * @see fill_color=
924
+ * @return [Integer]
925
+ */
926
+ static VALUE p1788_figure_get_fill_color(VALUE self)
927
+ {
928
+ return UINT2NUM(p1788_figure_rb2ref(self).fill_color());
929
+ }
930
+
931
+
932
+ static const char *format_regexp = "^((_|([^\\[\\]]+))?(\\[(_|([^\\[\\]]+))?\\])?)$";
933
+ // match[] 12 3 4 5 6
934
+
935
+
936
+ static void p1788_figure_parse_format(P1788Figure::Figure& f, VALUE str)
937
+ {
938
+ if (!RB_TYPE_P(str, T_STRING))
939
+ rb_raise(rb_eTypeError, "expecting a string as format, not a %" PRIsVALUE,
940
+ rb_class_name(rb_class_of(str)));
941
+ VALUE cr = rb_str_new_static(format_regexp, 41);
942
+ VALUE regexp = rb_class_new_instance(1, &cr, rb_cRegexp);
943
+ VALUE match = rb_funcallv(str, id_match, 1, &regexp);
944
+ if (NIL_P(match))
945
+ rb_raise(rb_eRuntimeError, "cannot parse \"%" PRIsVALUE "\" as a format", str);
946
+ VALUE m;
947
+
948
+ /* Stroke */
949
+ m = rb_funcall(match, id_brackets, 1, INT2NUM(2));
950
+ if (NIL_P(m)) // no stroke
951
+ f.cmd_stroke(false);
952
+ else {
953
+ f.cmd_stroke(true);
954
+ m = rb_funcall(match, id_brackets, 1, INT2NUM(3));
955
+ if (m != Qnil)
956
+ f.cmd_stroke_color(p1788_figure_parse_color(m));
957
+ }
958
+
959
+ /* Fill */
960
+ m = rb_funcall(match, id_brackets, 1, INT2NUM(5));
961
+ if (NIL_P(m)) // no fill
962
+ f.cmd_fill(false);
963
+ else {
964
+ f.cmd_fill(true);
965
+ m = rb_funcall(match, id_brackets, 1, INT2NUM(6));
966
+ if (m != Qnil)
967
+ f.cmd_fill_color(p1788_figure_parse_color(m));
968
+ }
969
+ }
970
+
971
+
972
+ /* Draw a single box.
973
+ * @return [self]
974
+ * @overload draw_box(box, format=nil)
975
+ * @param box [IntervalVector] an interval vector with at least two elements (for the _x_ and _y_ axis)
976
+ * @param format [String] an optional string in the form `"border_color[fill_color]"`
977
+ */
978
+ static VALUE p1788_figure_draw_box(int argc, VALUE *argv, VALUE self)
979
+ {
980
+ VALUE rbox, rformat;
981
+ rb_scan_args(argc, argv, "11", &rbox, &rformat);
982
+ P1788Figure::Figure& f = p1788_figure_rb2ref(self);
983
+ if (rformat != Qnil)
984
+ p1788_figure_parse_format(f, rformat);
985
+ f.cmd_draw_box(p1788_vector_rb2ref(rbox));
986
+ return self;
987
+ }
988
+
989
+
990
+ /* Draw multiple boxes at once.
991
+ * @return [self]
992
+ * @overload draw_boxes(array_of_boxes, format=nil)
993
+ * @param array_of_boxes [Array<IntervalVector>] an array of interval vectors each with at least two elements (for the _x_ and _y_ axis)
994
+ * @param format [String] an optional string in the form `"border_color[fill_color]"`
995
+ */
996
+ static VALUE p1788_figure_draw_boxes(int argc, VALUE *argv, VALUE self)
997
+ {
998
+ VALUE rboxes, rformat;
999
+ rb_scan_args(argc, argv, "11", &rboxes, &rformat);
1000
+ P1788Figure::Figure& f = p1788_figure_rb2ref(self);
1001
+ if (!RB_TYPE_P(rboxes, T_ARRAY))
1002
+ rb_raise(rb_eTypeError, "expecting an array of %" PRIsVALUE ", not a %" PRIsVALUE,
1003
+ rb_class_name(c_IntervalVector), rb_class_name(rb_class_of(rboxes)));
1004
+ if (rformat != Qnil)
1005
+ p1788_figure_parse_format(f, rformat);
1006
+ const size_t l = rb_array_len(rboxes);
1007
+ if (l < 1) return self;
1008
+ std::vector<P1788Figure::Box> bv;
1009
+ bv.reserve(l);
1010
+ for (size_t i = 0; i < l; i++) {
1011
+ VALUE e = rb_ary_entry(rboxes, i);
1012
+ if (!is_an_interval_vector(e))
1013
+ rb_raise(rb_eTypeError, "expecting interval vectors in the array, not %" PRIsVALUE,
1014
+ rb_class_name(rb_class_of(e)));
1015
+ const IntervalVector& iv = p1788_vector_rb2ref(e);
1016
+ if (!(iv.size() < 2 || Interval::is_empty(iv[0]) || Interval::is_empty(iv[1])))
1017
+ bv.emplace_back(iv[0], iv[1]);
1018
+ }
1019
+ if (bv.size() > 0)
1020
+ f.cmd_draw_boxes(std::move(bv));
1021
+ return self;
1022
+ }
1023
+
1024
+
1025
+ /* Reset the figure to its default, clearing all boxes, labels, etc.
1026
+ * After a reset, the figure state is the same than after `Figure.new()`.
1027
+ * @return [self]
1028
+ */
1029
+ static VALUE p1788_figure_reset(VALUE self)
1030
+ {
1031
+ p1788_figure_rb2ref(self).reset();
1032
+ return self;
1033
+ }
1034
+
1035
+
1036
+ static const char *extension_regexp = "\\.((png|PNG)|(svg|SVG)|(pdf|PDF))$";
1037
+ // match[] 12 3 4
1038
+
1039
+
1040
+ /* Generate the figure and write the output image to file _file_name_.
1041
+ * The output format (either _png_, _svg_ or _pdf_) is deduced from the extension of the file.
1042
+ * @return [self]
1043
+ * @param file_name [String] name of the file to write the image to, ending with '.png', '.svg' or '.pdf'.
1044
+ */
1045
+ static VALUE p1788_figure_write(VALUE self, VALUE file_name)
1046
+ {
1047
+ file_name = rb_funcallv(file_name, id_to_s, 0, NULL);
1048
+ if (RSTRING_LEN(file_name) < 1)
1049
+ rb_raise(rb_eRuntimeError, "file name is empty");
1050
+ VALUE cr = rb_str_new_static(extension_regexp, 34);
1051
+ VALUE regexp = rb_class_new_instance(1, &cr, rb_cRegexp);
1052
+ VALUE match = rb_funcallv(file_name, id_match, 1, &regexp);
1053
+ if (NIL_P(match))
1054
+ rb_raise(rb_eRuntimeError, "cannot deduce format from file name \"%" PRIsVALUE "\"", file_name);
1055
+ VALUE m;
1056
+ m = rb_funcall(match, id_brackets, 1, INT2NUM(2));
1057
+ if (m != Qnil) {
1058
+ #ifdef CAIRO_HAS_PNG_FUNCTIONS
1059
+ return p1788_figure_write_png(self, file_name);
1060
+ #else
1061
+ rb_raise(rb_eRuntimeError, "no support for PNG, sorry");
1062
+ #endif
1063
+ }
1064
+ m = rb_funcall(match, id_brackets, 1, INT2NUM(3));
1065
+ if (m != Qnil) {
1066
+ #ifdef CAIRO_HAS_SVG_SURFACE
1067
+ return p1788_figure_write_svg(self, file_name);
1068
+ #else
1069
+ rb_raise(rb_eRuntimeError, "no support for SVG, sorry");
1070
+ #endif
1071
+ }
1072
+ m = rb_funcall(match, id_brackets, 1, INT2NUM(4));
1073
+ if (m != Qnil) {
1074
+ #ifdef CAIRO_HAS_PDF_SURFACE
1075
+ return p1788_figure_write_pdf(self, file_name);
1076
+ #else
1077
+ rb_raise(rb_eRuntimeError, "no support for PDF, sorry");
1078
+ #endif
1079
+ }
1080
+ return self;
1081
+ }
1082
+
1083
+
1084
+ /* Returns a new {Figure}
1085
+ * @return [Figure]
1086
+ * @overload new(width: nil, height: nil, xrange: nil, yrange: nil, with_decorations: true, title: nil, xlabel: nil, ylabel: nil, background_color: 't', decoration_color: 'k', decoration_font: 'Sans', decoration_font_size: 11, decoration_line_width: 1, label_font_size: nil, title_font_size: nil, title_in_bold: false)
1087
+ * @param width [Integer, nil] Width of the frame of the output image. See {width=}.
1088
+ * @param height [Integer, nil] Height of the frame of the output image. See {height=}.
1089
+ * @param xrange [Interval, nil] The horizontal range that will be displayed. See {xrange=}.
1090
+ * @param yrange [Interval, nil] The vertical range that will be displayed. See {yrange=}.
1091
+ * @param with_decorations [Boolean, nil] Draw frame, graduations, labels and title around the figure? See {with_decorations=}.
1092
+ * @param title [String, nil] The title of the figure. See {title=}.
1093
+ * @param xlabel [String, nil] The label for the horizontal axis. See {xlabel=}.
1094
+ * @param ylabel [String, nil] The label for the vertical axis. See {ylabel=}.
1095
+ * @param background_color [Integer, String, nil] Background color of the figure. Default is transparent. See {background_color=}.
1096
+ * @param decoration_color [Integer, String, nil] Color of the frame, labels and title. Defaults to black. See {decoration_color=}.
1097
+ * @param decoration_font [Integer, String, nil] Font for labels, title and graduations. Defaults to "Sans". See {decoration_font=}.
1098
+ * @param decoration_font_size [Float, nil] Font size for the graduations. Defaults to 11. See {decoration_font_size=}.
1099
+ * @param decoration_line_width [Float, nil] Line width of the frame of the figure. Defaults to 1. See {decoration_line_width=}.
1100
+ * @param label_font_size [Float, nil] Font size for the labels. Defaults to 1.1 times _decoration_font_size_. See {label_font_size=}.
1101
+ * @param title_font_size [Float, nil] Font size for the title. Defaults to 1.23 times _decoration_font_size_. See {title_font_size=}.
1102
+ * @param title_in_bold [Boolean] Draw the title in bold or not?. Defaults to _false_. See {title_in_bold=}.
1103
+ */
1104
+ static VALUE p1788_figure_initialize(int argc, VALUE *argv, VALUE self)
1105
+ {
1106
+ const ID kwkeys[] = {
1107
+ id_width,
1108
+ id_height,
1109
+ id_xrange,
1110
+ id_yrange,
1111
+ id_with_decorations,
1112
+ id_title,
1113
+ id_xlabel,
1114
+ id_ylabel,
1115
+ id_background_color,
1116
+ id_decoration_color,
1117
+ id_decoration_font,
1118
+ id_decoration_font_size,
1119
+ id_decoration_line_width,
1120
+ id_label_font_size,
1121
+ id_title_font_size,
1122
+ id_title_in_bold
1123
+ };
1124
+ VALUE kwvalues[] = {Qundef, Qundef, Qundef, Qundef, Qundef, Qundef, Qundef, Qundef, Qundef, Qundef, Qundef, Qundef, Qundef, Qundef, Qundef, Qundef};
1125
+ VALUE kw;
1126
+
1127
+ rb_scan_args(argc, argv, ":", &kw);
1128
+ if (NIL_P(kw))
1129
+ return self;
1130
+
1131
+ rb_get_kwargs(kw, kwkeys, 0, 16, kwvalues);
1132
+
1133
+ if (kwvalues[0] != Qundef) p1788_figure_set_width(self, kwvalues[0]);
1134
+ if (kwvalues[1] != Qundef) p1788_figure_set_height(self, kwvalues[1]);
1135
+ if (kwvalues[2] != Qundef) p1788_figure_set_xrange(self, kwvalues[2]);
1136
+ if (kwvalues[3] != Qundef) p1788_figure_set_yrange(self, kwvalues[3]);
1137
+ if (kwvalues[4] != Qundef) p1788_figure_set_with_decorations(self, kwvalues[4]);
1138
+ if (kwvalues[5] != Qundef) p1788_figure_set_title(self, kwvalues[5]);
1139
+ if (kwvalues[6] != Qundef) p1788_figure_set_xlabel(self, kwvalues[6]);
1140
+ if (kwvalues[7] != Qundef) p1788_figure_set_ylabel(self, kwvalues[7]);
1141
+ if (kwvalues[8] != Qundef) p1788_figure_set_background_color(self, kwvalues[8]);
1142
+ if (kwvalues[9] != Qundef) p1788_figure_set_decoration_color(self, kwvalues[9]);
1143
+ if (kwvalues[10] != Qundef) p1788_figure_set_decoration_font(self, kwvalues[10]);
1144
+ if (kwvalues[11] != Qundef) p1788_figure_set_decoration_font_size(self, kwvalues[11]);
1145
+ if (kwvalues[12] != Qundef) p1788_figure_set_decoration_line_width(self, kwvalues[12]);
1146
+ if (kwvalues[13] != Qundef) p1788_figure_set_label_font_size(self, kwvalues[13]);
1147
+ if (kwvalues[14] != Qundef) p1788_figure_set_title_font_size(self, kwvalues[14]);
1148
+ if (kwvalues[15] != Qundef) p1788_figure_set_title_in_bold(self, kwvalues[15]);
1149
+
1150
+ return self;
1151
+ }
1152
+
1153
+
1154
+ void Init_p1788_figure()
1155
+ {
1156
+ id_width = rb_intern("width");
1157
+ id_height = rb_intern("height");
1158
+ id_xrange = rb_intern("xrange");
1159
+ id_yrange = rb_intern("yrange");
1160
+ id_with_decorations = rb_intern("with_decorations");
1161
+ id_title = rb_intern("title");
1162
+ id_xlabel = rb_intern("xlabel");
1163
+ id_ylabel = rb_intern("ylabel");
1164
+ id_background_color = rb_intern("background_color");
1165
+ id_decoration_color = rb_intern("decoration_color");
1166
+ id_decoration_font = rb_intern("decoration_font");
1167
+ id_decoration_font_size = rb_intern("decoration_font_size");
1168
+ id_decoration_line_width = rb_intern("decoration_line_width");
1169
+ id_label_font_size = rb_intern("label_font_size");
1170
+ id_title_font_size = rb_intern("title_font_size");
1171
+ id_title_in_bold = rb_intern("title_in_bold");
1172
+
1173
+ c_Figure = rb_define_class_under(m_P1788, "Figure", rb_cObject);
1174
+ rb_define_alloc_func(c_Figure, p1788_figure_alloc);
1175
+ rb_undef_method(rb_class_of(c_Figure), "allocate");
1176
+ rb_define_method(c_Figure, "initialize", p1788_figure_initialize, -1);
1177
+
1178
+ /* Attributes */
1179
+ rb_define_method(c_Figure, "with_decorations", p1788_figure_get_with_decorations, 0);
1180
+ rb_define_method(c_Figure, "with_decorations=", p1788_figure_set_with_decorations, 1);
1181
+ rb_define_method(c_Figure, "decoration_font", p1788_figure_get_decoration_font, 0);
1182
+ rb_define_method(c_Figure, "decoration_font=", p1788_figure_set_decoration_font, 1);
1183
+ rb_define_method(c_Figure, "decoration_font_size", p1788_figure_get_decoration_font_size, 0);
1184
+ rb_define_method(c_Figure, "decoration_font_size=", p1788_figure_set_decoration_font_size, 1);
1185
+ rb_define_method(c_Figure, "title_font_size", p1788_figure_get_title_font_size, 0);
1186
+ rb_define_method(c_Figure, "title_font_size=", p1788_figure_set_title_font_size, 1);
1187
+ rb_define_method(c_Figure, "label_font_size", p1788_figure_get_label_font_size, 0);
1188
+ rb_define_method(c_Figure, "label_font_size=", p1788_figure_set_label_font_size, 1);
1189
+ rb_define_method(c_Figure, "decoration_line_width", p1788_figure_get_decoration_line_width, 0);
1190
+ rb_define_method(c_Figure, "decoration_line_width=", p1788_figure_set_decoration_line_width, 1);
1191
+ rb_define_method(c_Figure, "decoration_color", p1788_figure_get_decoration_color, 0);
1192
+ rb_define_method(c_Figure, "decoration_color=", p1788_figure_set_decoration_color, 1);
1193
+ rb_define_method(c_Figure, "background_color", p1788_figure_get_background_color, 0);
1194
+ rb_define_method(c_Figure, "background_color=", p1788_figure_set_background_color, 1);
1195
+ rb_define_method(c_Figure, "title_in_bold", p1788_figure_get_title_in_bold, 0);
1196
+ rb_define_method(c_Figure, "title_in_bold=", p1788_figure_set_title_in_bold, 1);
1197
+ rb_define_method(c_Figure, "title", p1788_figure_get_title, 0);
1198
+ rb_define_method(c_Figure, "title=", p1788_figure_set_title, 1);
1199
+ rb_define_method(c_Figure, "xlabel", p1788_figure_get_xlabel, 0);
1200
+ rb_define_method(c_Figure, "xlabel=", p1788_figure_set_xlabel, 1);
1201
+ rb_define_method(c_Figure, "ylabel", p1788_figure_get_ylabel, 0);
1202
+ rb_define_method(c_Figure, "ylabel=", p1788_figure_set_ylabel, 1);
1203
+ rb_define_method(c_Figure, "width", p1788_figure_get_width, 0);
1204
+ rb_define_method(c_Figure, "width=", p1788_figure_set_width, 1);
1205
+ rb_define_method(c_Figure, "height", p1788_figure_get_height, 0);
1206
+ rb_define_method(c_Figure, "height=", p1788_figure_set_height, 1);
1207
+ rb_define_method(c_Figure, "xrange", p1788_figure_get_xrange, 0);
1208
+ rb_define_method(c_Figure, "xrange=", p1788_figure_set_xrange, 1);
1209
+ rb_define_method(c_Figure, "yrange", p1788_figure_get_yrange, 0);
1210
+ rb_define_method(c_Figure, "yrange=", p1788_figure_set_yrange, 1);
1211
+
1212
+ /* Statefull commands */
1213
+ rb_define_method(c_Figure, "stroke_on", p1788_figure_stroke_on, 0);
1214
+ rb_define_method(c_Figure, "stroke_off", p1788_figure_stroke_off, 0);
1215
+ rb_define_method(c_Figure, "stroke?", p1788_figure_get_stroke_onoff, 0);
1216
+ rb_define_method(c_Figure, "stroke_width=", p1788_figure_set_stroke_width, 1);
1217
+ rb_define_method(c_Figure, "stroke_width", p1788_figure_get_stroke_width, 0);
1218
+ rb_define_method(c_Figure, "stroke_color=", p1788_figure_set_stroke_color, 1);
1219
+ rb_define_method(c_Figure, "stroke_color", p1788_figure_get_stroke_color, 0);
1220
+ rb_define_method(c_Figure, "fill_on", p1788_figure_fill_on, 0);
1221
+ rb_define_method(c_Figure, "fill_off", p1788_figure_fill_off, 0);
1222
+ rb_define_method(c_Figure, "fill?", p1788_figure_get_fill_onoff, 0);
1223
+ rb_define_method(c_Figure, "fill_color=", p1788_figure_set_fill_color, 1);
1224
+ rb_define_method(c_Figure, "fill_color", p1788_figure_get_fill_color, 0);
1225
+ rb_define_method(c_Figure, "draw_box", p1788_figure_draw_box, -1);
1226
+ rb_define_method(c_Figure, "draw_boxes", p1788_figure_draw_boxes, -1);
1227
+ rb_define_method(c_Figure, "reset!", p1788_figure_reset, 0);
1228
+
1229
+ /* Figure generation and output */
1230
+ rb_define_method(c_Figure, "allocated_size", p1788_figure_allocated_size, 0);
1231
+ rb_define_method(c_Figure, "content_range", p1788_figure_content_range, 0);
1232
+ rb_define_method(c_Figure, "nice_range", p1788_figure_nice_range, 0);
1233
+ rb_define_method(c_Figure, "write", p1788_figure_write, 1);
1234
+ rb_define_method(c_Figure, "set_range", p1788_figure_set_range, 1);
1235
+ #ifdef CAIRO_HAS_PNG_FUNCTIONS
1236
+ rb_define_method(c_Figure, "write_png", p1788_figure_write_png, 1);
1237
+ rb_define_method(c_Figure, "to_png", p1788_figure_to_png, 0);
1238
+ #endif
1239
+ #ifdef CAIRO_HAS_SVG_SURFACE
1240
+ rb_define_method(c_Figure, "write_svg", p1788_figure_write_svg, 1);
1241
+ rb_define_method(c_Figure, "to_svg", p1788_figure_to_svg, 0);
1242
+ #endif
1243
+ #ifdef CAIRO_HAS_PDF_SURFACE
1244
+ rb_define_method(c_Figure, "write_pdf", p1788_figure_write_pdf, 1);
1245
+ rb_define_method(c_Figure, "to_pdf", p1788_figure_to_pdf, 0);
1246
+ #endif
1247
+ }
1248
+
1249
+