Initial commit of OpenSPARC T2 design and verification files.
[OpenSPARC-T2-DV] / tools / perl-5.8.0 / lib / site_perl / 5.8.0 / Pastel / Graphics.pm
CommitLineData
86530b38
AT
1# $Id: Graphics.pm,v 1.13 2003/04/29 18:18:05 malay Exp $\r
2# Perl module for Pastel::Graphics\r
3# Author: Malay < curiouser@ccmb.res.in >\r
4# Copyright (c) 2003 by Malay. All rights reserved.\r
5# You may distribute this module under the same terms as perl itself\r
6\r
7=head1 NAME\r
8\r
9Pastel::Graphics - Graphics context.\r
10\r
11=head1 SYNOPSIS\r
12\r
13 use Pastel;\r
14\r
15 my $graphics = Pastel::Graphics->new(...);\r
16 $graphics->foo();\r
17 $graphics->bar();\r
18\r
19 $graphics->show(); #dump the graphics on STDOUT\r
20\r
21 -or-\r
22\r
23 my $string = $graphics->get_svg(); # get the graphic as string\r
24 print $string;\r
25\r
26=head1 DESCRIPTION\r
27\r
28C<Pastel::Graphics> is the main workhorse of Pastel. It is equivalent to\r
29Java Graphics2D class. Each program first has to create once instance\r
30of this class, then call methods on this and lastly dump the whole\r
31instance onto STDOUT or get it as string.\r
32\r
33The class provides the graphics context in that it hold all the\r
34necessary informations for drawing any graphics object correctly.\r
35\r
36All styles like fonts, color and strokes are set into this class by\r
37calling appropriate methods. Shapes and Strings are drawn by calling\r
38C<draw()> and C<draw_string()> methods. For a tutorial introduction see\r
39Pastel programming manual.\r
40\r
41There are certain shortcut methods that are inbuilt into this\r
42module. You can draw shapes without creating additional\r
43objects. Notable among these classes of methods are C<draw_3D_rect()>\r
44and C<draw_round_rect()> which are not availble from the\r
45L<Pastel::Geometry::Rectangle> class.\r
46\r
47=cut\r
48\r
49package Pastel::Graphics;\r
50@ISA = qw( Pastel::Mixin::Mixin); # requires _rearrange() function\r
51use strict;\r
52use Carp;\r
53\r
54my $_width = "800"; #Width of the SVG document\r
55my $_height = "600"; #Height of the SVG document\r
56\r
57my $_dtd =\r
58'<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20001102//EN" "http://www.w3.org/TR/2000/CR-SVG-20001102/DTD/svg-20001102.dtd">';\r
59\r
60sub new {\r
61 my $arg = shift;\r
62 my $class = ref($arg) || $arg;\r
63 my $self = {};\r
64 bless $self, $class;\r
65\r
66 $self->_init(@_);\r
67\r
68 return $self;\r
69\r
70}\r
71\r
72=head1 CONSTRUCTOR\r
73\r
74=head2 new()\r
75\r
76Creates and returns a new C<Pastel::Graphics> object.\r
77\r
78 Usage : $graphics = Pastel::Graphics->new(-width=>$w,\r
79 -height=>$h,\r
80 -DTD =>$dtd );\r
81\r
82 Args : $w - Optional. Width of the SVG document in pixels. If not\r
83 provided default is 800.\r
84 $h - Optional. Height of the SVG document in pixels. If not\r
85 provided the default is 600.\r
86 $dtd - Optional. DTD used for SVG document. You can pass your\r
87 own DTD.\r
88\r
89 Returns: Pastel::Graphics object\r
90\r
91=cut\r
92\r
93sub _init {\r
94\r
95 my ( $self, @args ) = @_;\r
96\r
97 my ( $w, $h, $dtd, $cgi ) =\r
98 $self->_rearrange( [ "WIDTH", "HEIGHT", "DTD", "CGI" ], @args );\r
99\r
100 $self->{width} = defined($w) ? $w : $_width;\r
101 $self->{height} = defined($h) ? $h : $_height;\r
102 $self->{dtd} = defined($dtd) ? $dtd : $_dtd;\r
103 $self->{CGI} = defined($cgi) ? $cgi : "true";\r
104 $self->{_temp} = ""; # To store SVG elements\r
105 $self->{_defs} = ""; # To store DEFS\r
106 $self->{_writer} = $self->_initialize_writer();\r
107 $self->{paint} = undef;\r
108 $self->{stroke} = undef;\r
109 $self->{defs} = {};\r
110}\r
111\r
112=head1 METHODS\r
113\r
114\r
115=head2 set_font()\r
116\r
117Set the font for all the graphics object. Any string drawn using\r
118C<draw_string()> after calling this method will be drawn using the\r
119font presently set using this method. Note that\r
120C<Pastel::Text::AttributedString> objects are immune to font\r
121context. To set the font of C<Pastel::Text::AttributedString> you need\r
122to set the font by setting it as attribute of the C<AttributedString>\r
123object.\r
124\r
125 Usage : set_font($font)\r
126\r
127 Args : $font is a Pastel::Font object. \r
128\r
129 Returns : Nothing. \r
130\r
131=cut\r
132\r
133sub set_font {\r
134 my ( $self, $arg ) = @_;\r
135 $self->{"font"} = $arg;\r
136 return $self;\r
137\r
138 # my ($self,%arg) = @_;\r
139 # if(defined ($arg{FAMILY})){$self->{FONT_FAMILY} = $arg{FAMILY};}\r
140 # if(defined ($arg{SIZE})){$self->{FONT_SIZE} = $arg{SIZE};}\r
141 # if(defined($arg{COLOR})){$self->{FONT_COLOR} = $arg{COLOR};}\r
142 # if(defined($arg{WEIGHT})){$self->{FONT_WEIGHT} = $arg{WEIGHT};}\r
143 # return $self;\r
144}\r
145\r
146sub set_fill_color {\r
147 my $self = shift;\r
148 $self->{COLOR} = shift;\r
149 return $self;\r
150}\r
151\r
152=head2 set_paint()\r
153\r
154Sets the color of the graphics context. Any drawing of shapes or text\r
155will be carried out using the color presently set in the graphics\r
156context. The color can be solid color of Pastel::Color object or a\r
157gradient implementing Pastel::GradientI interface.\r
158\r
159 Usage : set_paint($color)\r
160 \r
161 Args : $color is a Pastel::Color or Pastel::GradientI object.\r
162 \r
163 Returns : Nothing. \r
164\r
165=cut\r
166\r
167sub set_paint {\r
168 my $self = shift;\r
169 $self->{paint} = $_[0];\r
170}\r
171\r
172=head2 set_stroke()\r
173\r
174If the current graphics context has the stroke object set then all\r
175further drawings will be stroked. The stroke color will be the current\r
176color set using C<set_paint()> method. The swith off the stroking you\r
177need to unset the stroke by calling this method without any argument.\r
178\r
179Because stroking is done using the current color set in the graphics\r
180context, to draw an object with both stroke and fill where the\r
181stroke-color and the fill-color are different, you need to fill the\r
182object first and set a different color before you draw the object. To\r
183draw a rectangle with blue border and red fill you might do this:\r
184\r
185 $g = Pastel::Graphics->new();\r
186 $g->set_paint(Pastel::Color->red());\r
187 $g->set_stroke( Pastel::BasicStroke->new(-width=>5) );\r
188 my $rect = Pastel::Geometry::Rectangle(\r
189 -x=>20,-y=>30,\r
190 -width=>100,-height=>150\r
191 );\r
192 $g->fill($rect); # filled with red color\r
193 $g->set_paint(Pastel::Color->blue());\r
194 $g->draw($rect);\r
195\r
196 Usage : set_stroke($stroke) # set the stroke object\r
197 set_stroke() # unset stroking\r
198\r
199 Args : $stroke is a Pastel::BasicStroke object.\r
200 \r
201 Returns : Nothing. \r
202\r
203=cut\r
204\r
205sub set_stroke {\r
206 my $self = shift;\r
207 my $arg = shift;\r
208\r
209 #print STDERR "******STROKE called\n";\r
210 if ( defined($arg) ) {\r
211\r
212 #print "Inside CLEAR\n";\r
213 $self->{stroke} = $arg;\r
214 }\r
215 else {\r
216 if ( defined( $self->{stroke} ) ) {\r
217 $self->{stroke} = undef;\r
218 return;\r
219 }\r
220 }\r
221\r
222}\r
223\r
224\r
225=head2 get_font()\r
226\r
227Returns the current font object in the graphics context.\r
228\r
229 Usage : get_font();\r
230\r
231 Args : Nothing.\r
232\r
233 Returns : Pastel::Font object. \r
234\r
235=cut\r
236\r
237\r
238sub get_font {\r
239 my $self = shift;\r
240 if ( defined( $self->{font} ) ) {\r
241 return $self->{font};\r
242 }\r
243 else {\r
244 return undef;\r
245 }\r
246}\r
247\r
248\r
249=head2 get_paint()\r
250\r
251Returns the current paint object in the graphics context.\r
252\r
253 Usage : $g->get_paint()\r
254 \r
255 Args : Nothing.\r
256 \r
257 Returns : Pastel::Color or object implementing Pastel::GradientI interface. \r
258\r
259=cut\r
260\r
261sub get_paint {\r
262 my $self = shift;\r
263 if ( !defined( $self->{paint} ) ) {\r
264 $self->{paint} = Pastel::Color->black();\r
265 }\r
266 return $self->{paint};\r
267}\r
268\r
269=head2 get_stroke()\r
270\r
271Return the current stroke object in the graphics context. \r
272\r
273 Usage : get_stroke()\r
274\r
275 Args : Nothing.\r
276\r
277 Returns : Pastel::BasicStroke object if stroke is set or undef if not set.\r
278\r
279=cut\r
280\r
281sub get_stroke {\r
282 my $self = shift;\r
283 if ( !defined( $self->{stroke} ) ) {\r
284\r
285 # $self->{stroke} = Pastel::BasicStroke->new(-width=>1);\r
286 # return $self->{stroke};\r
287 return "";\r
288 }\r
289 else {\r
290 return $self->{stroke};\r
291 }\r
292}\r
293\r
294=head2 draw_rect()\r
295\r
296Shortcut function to draw a rectangle without creating additional\r
297object. The rectangle is stroked with the current C<BasicStroke>\r
298object. If the C<BasicStroke> is not set then the rectangle is created\r
299using an 1 pixel width line. The color of the line is determined by\r
300the current paint.\r
301\r
302 Usage : draw_rect($x, $y, $width, $height)\r
303\r
304 Args : $x - X coordinate of the top left corner vertice of rectangle.\r
305 $y - Y coordinate of the top left corner vertice of rectangle.\r
306 $width - Width of the rectangle.\r
307 $height- Height of the rectangle.\r
308\r
309 Returns : Nothing. \r
310\r
311=cut\r
312\r
313sub draw_rect {\r
314\r
315 my $self = shift;\r
316 my ( $x, $y, $width, $height ) =\r
317 $self->_rearrange( [ "X", "Y", "WIDTH", "HEIGHT" ], @_ );\r
318 my $color;\r
319 if ( $self->get_paint()->isa("Pastel::Color") ) {\r
320 $color = $self->get_paint()->to_svg_stroke();\r
321 }\r
322 else {\r
323 $color = "stroke:url(" . $self->get_paint()->get_ref() . ');';\r
324 $self->add_to_defs( $self->get_paint() );\r
325 }\r
326 my $stroke =\r
327 $self->get_stroke()\r
328 ? $self->get_stroke()\r
329 : Pastel::BasicStroke->new();\r
330\r
331 my $stroke_style = $stroke->to_svg();\r
332\r
333 my $half_width = $stroke->get_line_width() / 2;\r
334 $x = $x + $half_width;\r
335 $y = $y + $half_width;\r
336 $width = $width - ( 2 * $half_width );\r
337 $height = $height - ( 2 * $half_width );\r
338\r
339 $self->{_temp} .= (\r
340qq(<rect x="$x" y="$y" width="$width" height="$height" style="fill:none; $color$stroke_style" />)\r
341 );\r
342\r
343}\r
344\r
345=head2 fill_rect()\r
346\r
347Shortcut function to draw a filled rectangle without creating\r
348additional objects. The rectangle is filled with the current paint in\r
349the graphics context.\r
350\r
351 Usage : fill_rect($x, $y, $width, $height);\r
352\r
353 Args : $x - X coordinate of the top left corner of the rectangle.\r
354 $y - Y coordinate of the top left corner of the rectangle.\r
355 $width - Width of the rectangle in pixels.\r
356 $height- Height of the rectangle in pixels.\r
357 \r
358 Returns : Nothing\r
359\r
360=cut\r
361\r
362sub fill_rect {\r
363 my $self = shift;\r
364\r
365 # my $color = $self->get_paint()->to_svg_fill();\r
366 my $color;\r
367 if ( $self->get_paint()->isa("Pastel::Color") ) {\r
368 $color = $self->get_paint()->to_svg_fill();\r
369 }\r
370 else {\r
371 $color = "fill:url(" . $self->get_paint()->get_ref() . ')';\r
372 $self->add_to_defs( $self->get_paint() );\r
373 }\r
374\r
375 my ( $x, $y, $width, $height ) =\r
376 $self->_rearrange( [ "X", "Y", "WIDTH", "HEIGHT" ], @_ );\r
377 $self->{_temp} .= (\r
378qq(<rect x="$x" y="$y" width="$width" height="$height" style="$color;stroke:none"/>)\r
379 );\r
380\r
381}\r
382\r
383=head2 draw_round_rect()\r
384\r
385Shortcut fuction to draw open rectangle with rounded corners. The\r
386rectangle is stroked with the current stroke if it is set. Otherwise\r
387it is drawn with 1 pixel width line. The color is determined by the\r
388current paint object.\r
389\r
390 Usage : draw_round_rect($x, $y, $width, $height,\r
391 $arc_width, $arc_height);\r
392\r
393 Args : $x - X coordinate of the top left hand corner.\r
394 $y - Y coordinate of the top left hand corner.\r
395 $width - Width of the rectangle.\r
396 $height - Height of the rectangle.\r
397 $arc_width - Horizontal diameter of the arc at the four corners.\r
398 $arc_height - vertical diameter of the arc at the four corners.\r
399\r
400 Returns : Nothing\r
401\r
402=cut\r
403\r
404sub draw_round_rect {\r
405 my ( $self, @args ) = @_;\r
406\r
407 if ( @args < 6 ) {\r
408 croak 'Missing parameter in Pastel::Graphics::draw_round_rect()!\n';\r
409 }\r
410\r
411 #my $paint = $self->get_paint()->to_svg_stroke();\r
412 my $paint;\r
413 if ( $self->get_paint()->isa("Pastel::Color") ) {\r
414 $paint = $self->get_paint()->to_svg_stroke();\r
415 }\r
416 else {\r
417 $paint = "stroke:url(" . $self->get_paint()->get_ref() . ');';\r
418 $self->add_to_defs( $self->get_paint() );\r
419 }\r
420\r
421 my $stroke =\r
422 $self->get_stroke()\r
423 ? $self->get_stroke()\r
424 : Pastel::BasicStroke->new();\r
425\r
426 my $half_width = $stroke->get_line_width() / 2;\r
427\r
428 my $stroke_style = $stroke->to_svg();\r
429 my $x = $args[0] + $half_width;\r
430 my $y = $args[1] + $half_width;\r
431 my $width = $args[2] - ( 2 * $half_width );\r
432 my $height = $args[3] - ( 2 * $half_width );\r
433\r
434 $self->{_temp} .=\r
435qq(<rect x="$x" y="$y" width="$width" height="$height" rx="$args[4]" ry="$args[4]" style="fill:none;$paint$stroke_style" />);\r
436\r
437}\r
438\r
439=head2 draw_fill_round_rect()\r
440\r
441Draws a filled rectangle with rounded corners. The rectangle is filled\r
442with the current paint object in the graphics context.\r
443\r
444 Usage : $g->draw_fill_round_rect($x, $y, $width, $height,\r
445 $arc_width, $arc_height);\r
446\r
447 Args : $x - X coordinate of the top left hand corner.\r
448 $y - Y coordinate of the top left hand corner.\r
449 $width - Width of the rectangle.\r
450 $height - Height of the rectangle.\r
451 $arc_width - Horizontal diameter of the arc at the four corners.\r
452 $arc_height - vertical diameter of the arc at the four corners.\r
453\r
454\r
455 Returns : Nothing\r
456\r
457=cut\r
458\r
459sub draw_fill_round_rect {\r
460 my ( $self, @args ) = @_;\r
461\r
462 if ( @args < 6 ) {\r
463 croak 'Missing parameter in Pastel::Graphics::draw_fillround_rect()!\n';\r
464 }\r
465\r
466 # my $paint = $self->get_paint()->to_svg_fill();\r
467 my $paint;\r
468 if ( $self->get_paint()->isa("Pastel::Color") ) {\r
469 $paint = $self->get_paint()->to_svg_fill();\r
470 }\r
471 else {\r
472 $paint = "fill:url(" . $self->get_paint()->get_ref() . ')';\r
473 $self->add_to_defs( $self->get_paint() );\r
474 }\r
475\r
476 # my $stroke = $self->get_stroke()->to_svg();\r
477\r
478 $self->{_temp} .=\r
479qq(<rect x="$args[0]" y="$args[1]" width="$args[2]" height="$args[3]" rx="$args[4]" ry="$args[4]" style="$paint" />);\r
480\r
481}\r
482\r
483=head2 draw_3D_rect()\r
484\r
485Draws a highlighted 3D effect rectangle. \r
486\r
487 Usage : $g->draw_3D_rect($x, $y, $width, $height, $raised, $bevel);\r
488\r
489 Args : $x - Top left corner X coordinate of the rectangle.\r
490 $y - Top left corner Y coordinate of the rectangle.\r
491 $width - Width of the rectangle.\r
492 $height - Height of the rectangle.\r
493 $raised - Optional. Takes value "true" or "false". Default "true". \r
494 $bevel - Optional. Width of the bevel. Default 1.\r
495\r
496 Returns : Nothing\r
497\r
498=cut\r
499\r
500sub draw_3D_rect {\r
501 my ( $self, @args ) = @_;\r
502 if ( @args < 4 ) {\r
503 croak 'Missing parameter in Pastel::Graphics::draw_3D_rect()!\n';\r
504 }\r
505 my $raised;\r
506\r
507 if ( $args[4] && ( $args[4] =~ /true/i ) ) {\r
508 $raised = 1;\r
509 }\r
510 else {\r
511 $raised = 0;\r
512 }\r
513\r
514 my $bevel = 1;\r
515 if ( $args[5] ) {\r
516 $bevel = $args[5];\r
517 }\r
518 my ( $x, $y, $width, $height ) = (@args);\r
519\r
520 # print "***@args\n";\r
521 my $before_color = $self->get_paint();\r
522 my $current_color = $before_color;\r
523\r
524 if ( !$before_color->isa("Pastel::Color") ) {\r
525 $current_color = Pastel::Color->black();\r
526 }\r
527\r
528 my $brighter = $current_color->brighter();\r
529 my $darker = $current_color->darker();\r
530\r
531 my $s = "<path d=\"";\r
532 $self->set_paint( $raised ? $brighter : $darker );\r
533\r
534 $s .= "M" . $x . " " . $y;\r
535 $s .= "L" . eval( $x + $width ) . " " . $y;\r
536 $s .= "L" . eval( $x + $width - $bevel ) . " " . eval( $y + $bevel );\r
537 $s .= "H" . eval( $x + $bevel );\r
538 $s .= "V" . eval( $y + $height - $bevel );\r
539 $s .= "L" . $x . " " . eval( $y + $height );\r
540 $s .= "z" . "\" ";\r
541\r
542 $s .= "style=\"" . $self->get_paint()->to_svg_fill() . "\" />";\r
543\r
544 $self->set_paint( $raised ? $darker : $brighter );\r
545 $s .= "<path d=\"";\r
546 $s .= "M" . $x . " " . eval( $y + $height );\r
547 $s .= "L" . eval( $x + $bevel ) . " " . eval( $y + $height - $bevel );\r
548 $s .= "H" . eval( $x + $width - $bevel );\r
549 $s .= "V" . eval( $y + $bevel );\r
550 $s .= "L" . eval( $x + $width ) . " " . $y;\r
551 $s .= "V" . eval( $y + $height );\r
552 $s .= "z" . "\" style=\"" . $self->get_paint()->to_svg_fill() . "\" />";\r
553\r
554 $self->_buffer_add($s);\r
555\r
556 # $self->fill_rect($x + $stroke_width, $y + $height - $stroke_width,\r
557 # $width -$stroke_width, $stroke_width); $self->fill_rect($x +\r
558 # $width - $stroke_width, $y , $stroke_width, $height);\r
559\r
560 $self->set_paint($before_color);\r
561\r
562 # my $color = $self->get_paint()->to_svg_stroke();\r
563 # my $width = $self->get_stroke()->get_line_width();\r
564 # my $stroke = $self->get_stroke();\r
565 # $self->set_stroke( Pastel::BasicStroke->new( -width => 1 ) );\r
566 # if ($raised) {\r
567 # $self->set_paint( $self->get_paint()->brighter() );\r
568 # $self->draw_line( $args[0], $args[1], $args[0], $args[1] + $args[3] );\r
569 # $self->draw_line(\r
570 # $args[0] + 1,\r
571 # $args[1], $args[0] + $args[2] - 1,\r
572 # $args[1]\r
573 # );\r
574 # $self->set_paint( $self->get_paint()->darker() );\r
575 # $self->draw_line(\r
576 # $args[0] + 1,\r
577 # $args[1] + $args[3],\r
578 # $args[0] + $args[2],\r
579 # $args[1] + $args[3]\r
580 # );\r
581 # $self->draw_line(\r
582 # $args[0] + $args[2],\r
583 # $args[1],\r
584 # $args[0] + $args[2],\r
585 # $args[1] + $args[3] - 1\r
586 # );\r
587 # }\r
588 # else {\r
589\r
590 # # = $color->darker();\r
591 # }\r
592 # $self->set_paint($color);\r
593 # $self->set_stroke($stroke);\r
594\r
595}\r
596\r
597=head2 draw()\r
598\r
599Draws a C<Pastel::Shape> object. The object is stroked using the current\r
600stroke object in the graphics context using the current paint object\r
601in the graphics context. The method works for any object which is a\r
602subclass of C<Pastel::Shape>.\r
603\r
604If you subclass Pastel::Shape. The child class must implement\r
605C<get_shape()> method, which should return an instance of the graphics\r
606primitive (classes in C<Pastel::Geometry>).\r
607\r
608 Usage : draw($shape)\r
609\r
610 Args : $shape - an object subclassed from Pastel::Shape. All the\r
611 classes in Pastel::Geometry are subclass of Pastel::Shape.\r
612\r
613 Returns : Nothing\r
614\r
615=cut\r
616\r
617sub draw {\r
618 my $self = shift;\r
619 my $ob = shift;\r
620 my $data;\r
621 my $shape = $ob;\r
622\r
623 #if (defined ($self->{stroke}) ){\r
624 #print "***********Stroke defined********\n";\r
625 #my $stroke = $self->{stroke};\r
626 #my $stroked_ob = $stroke->create_stroked_shape($ob);\r
627 #$data = $stroked_$ob->_draw($self);\r
628 #}\r
629 #else{\r
630 if ( $ob->can("get_shape") ) {\r
631 $shape = $ob->get_shape();\r
632 }\r
633 $data = $shape->_draw($self);\r
634\r
635 #}\r
636\r
637 $self->_buffer_add($data);\r
638}\r
639\r
640=head2 draw_string();\r
641\r
642Draws the string supplied in the co-ordinates specified. Three types\r
643of strings can be drawn using this method. Native perl strings can be\r
644supplied which will be internally converted into suitable format. The\r
645entities are automatically escaped. You can even pass perl unicode\r
646strings directly into the method.\r
647\r
648The methods also accepts C<Pastel::String> objects which are nothing\r
649but an XML formatted container for the perl string.\r
650\r
651In both these above cases the font in which the string will drawn is\r
652the current font object in the graphics context. The strings will also\r
653be stroked with the current stroke in the graphics context and it will\r
654drawn in the current paint color. \r
655\r
656The method also accepts C<Pastel::Text::AttributedString> object. In\r
657Java you pass an C<AttributedCharacterIterator> into this method. In\r
658Pastel you pass the C<AttributedString> object\r
659itself. C<AttributedString> object are immune to current graphics\r
660context. If you want to change the stroke or color of the\r
661C<AttributedString> do so in the directly in the object.\r
662\r
663A major way in which C<Pastel> differs from C<Java2D> is that the\r
664coordinates can be arrays of numbers each determining the coordinated\r
665of each character in the string. See SVG specification for more\r
666details.\r
667\r
668 Usage : draw_string("perl string", $x, $y);\r
669 draw_string("perl string", \@x, \@y);\r
670 draw_string( $string,$x, $y);\r
671 draw_string( $string, \@x, \@y);\r
672\r
673\r
674 Args : The method takes 3 arguments. The first argument can be an\r
675 object of type Pastel::String or a pure perl string or\r
676 Pastel::Text::AttributedString. The string supplied is converted to\r
677 XML form automatically. All character code above 126 is converted to\r
678 "&xff;" form. "<", ">", "&" and other XML entities are automatically\r
679 created.\r
680\r
681 The second argument can be a single numerical value\r
682 indicating the X cordinate of the first character of the\r
683 string or the middle of the total length of the string or the\r
684 last character depending on text anchoring. This argument\r
685 also be a reference to an array indicating the X coordinates\r
686 of successive characters in the string.\r
687\r
688 The third argument can be a single numerical or a reference\r
689 to an array of numericals indicating the Y coordinate of the\r
690 baseline of the glyph used for drawing the font.\r
691\r
692=cut\r
693\r
694sub draw_string {\r
695 my ( $self, @args ) = @_;\r
696 my ( $string, $x, $y ) = $self->_rearrange( [ "TEXT", "X", "Y" ], @args );\r
697\r
698 my $data = ""; #Holds the SVG string;\r
699\r
700 unless ( ( defined($string) ) && ( defined($x) ) && ( defined($y) ) ) {\r
701 print 'Error: Graphics::drawstring(): Argument missing', "\n";\r
702 return;\r
703 }\r
704\r
705 if ( $string->isa("Pastel::Text::AttributedString") ) {\r
706\r
707 #print STDERR "AttributedString supplied\n";\r
708 $string->set_x($x);\r
709 $string->set_y($y);\r
710 $data = $string->to_svg();\r
711 }\r
712\r
713 # If $string is a string object calls its draw method\r
714 elsif ( ref($string) =~ m/String/ ) {\r
715\r
716 $string->set_x($x);\r
717 $string->set_y($y);\r
718\r
719 if ( defined( $self->{font} ) ) { # If the graphics object has a font\r
720 # First fontify it\r
721 $string->set_font( $self->get_font() );\r
722 $data = $string->draw($self);\r
723\r
724 }\r
725 else {\r
726 $data = $string->draw($self);\r
727 }\r
728 }\r
729\r
730 # If $string is a perl string, create a string object, fontify it\r
731 # by passing it to the font object and then call its draw method\r
732 else {\r
733 my $string = Pastel::String->new($string);\r
734 $string->set_x($x);\r
735 $string->set_y($y);\r
736\r
737 if ( defined( $self->{font} ) ) { # If the graphics object has font\r
738\r
739 # Set the font object of the String\r
740 my $fontified = $string->set_font( $self->{font} );\r
741 $data = $fontified->draw($self);\r
742 }\r
743 else { # If the graphics object doesn't have font object set\r
744 $data = $string->draw($self); # Just call the draw method\r
745 }\r
746 }\r
747\r
748 $self->_buffer_add($data); # Add the data to the print buffer\r
749\r
750}\r
751\r
752=head2 show()\r
753\r
754Dumps the graphics object as SVG on STDOUT.\r
755\r
756 Usage : show()\r
757 \r
758 Args : Nothing.\r
759 \r
760 Returns : Nothing.\r
761\r
762=cut\r
763\r
764sub show {\r
765 my $self = shift;\r
766 my $writer = $self->{_writer};\r
767 $self->_print_header();\r
768 $self->_print_svg_start();\r
769\r
770 if ( %{ $self->{defs} } ) {\r
771 $writer->print_svg('<defs>');\r
772\r
773 # for ( my $i = 0 ; $i < @{ $self->{defs} } ; $i++ ) {\r
774 # $writer->print_svg( ${ $self->{defs} }[$i]->to_svg() );\r
775 # }\r
776 $writer->print_svg( $self->_get_defs() );\r
777 $writer->print_svg('</defs>');\r
778 }\r
779\r
780 $writer->print_svg( $self->{_temp} );\r
781 $self->_print_footer();\r
782}\r
783\r
784\r
785sub fill {\r
786 my $self = shift;\r
787\r
788 my $shape = shift;\r
789\r
790 if ( !$shape->isa("Pastel::Shape") ) {\r
791 croak 'Error: Only a shape can be filled by Pastel::Graphics->fill()';\r
792 }\r
793\r
794 $shape->set_fill( $self->get_paint() );\r
795}\r
796\r
797sub add_to_defs {\r
798 my $self = shift;\r
799 my $object = shift;\r
800\r
801 # ${ $self->{defs} }[ @{ $self->{defs} } ] = $object;\r
802 # to keep only the unique element we just add the object with an id\r
803 my $id = $object->get_id();\r
804 $self->{defs}->{id} = $object;\r
805}\r
806\r
807sub _get_defs {\r
808 my $self = shift;\r
809 my $s = "";\r
810 if ( %{ $self->{defs} } ) {\r
811 foreach my $key ( keys %{ $self->{defs} } ) {\r
812 $s .= $self->{defs}->{$key}->to_svg();\r
813 }\r
814 }\r
815 return $s;\r
816}\r
817\r
818sub get_svg {\r
819 my $self = shift;\r
820 my $s = '<?xml version="1.0" encoding="iso-8859-1"?>';\r
821 $s .= "\n" . $self->{dtd} . "\n";\r
822 $s .= "<svg width=\""\r
823 . $self->{width}\r
824 . "\" height=\""\r
825 . $self->{height} . "\">";\r
826 if ( %{ $self->{defs} } ) {\r
827 $s .= "\n" . '<defs>' . "\n";\r
828\r
829 # for ( my $i = 0 ; $i < @{ $self->{defs} } ; $i++ ) {\r
830 # $s .= ${ $self->{defs} }[$i]->to_svg();\r
831 # }\r
832 $s .= $self->_get_defs();\r
833 $s .= "\n" . '</defs>' . "\n";\r
834 }\r
835 $s .= $self->{_temp};\r
836 $s .= "\n" . '</svg>';\r
837 return $s;\r
838}\r
839\r
840sub draw_polyline {\r
841 my @args = @_;\r
842 my $self = $args[0];\r
843 my @x = @{ $args[1] };\r
844 my @y = @{ $args[2] };\r
845\r
846 my $s = '<polyline style="fill:none; ';\r
847 $s .= $self->get_paint()->to_svg() . " ";\r
848 if ( $self->get_stroke() ) {\r
849 $s .= $self->get_stroke()->to_svg() . "\" ";\r
850 }\r
851 else {\r
852 $s .= Pastel::BasicStroke()->to_svg() . "\" ";\r
853 }\r
854 $s .= 'points="';\r
855\r
856 for ( my $i = 0 ; $i < @x ; $i++ ) {\r
857 $s .= $x[$i] . "," . $y[$i];\r
858 if ( $i != ( scalar(@x) - 1 ) ) {\r
859 $s .= " ";\r
860 }\r
861 }\r
862\r
863 # my $s .= '<path style="fill:none; ';\r
864 # $s .= $self->get_paint()->to_svg();\r
865 # $s .= " ".$self->get_stroke()->to_svg()."\" ";\r
866 # $s .= 'd="M'.$x[0].",".$y[0]." ";\r
867 # for ( my $i=0; $i < @x; $i++){\r
868 # $s .= "L".$x[$i].",".$y[$i];\r
869 # if( $i != (scalar(@x) - 1)){\r
870 # $s .=" ";\r
871 # }\r
872 # }\r
873\r
874 $s .= '" />';\r
875 $self->{_temp} .= $s . "\n";\r
876}\r
877\r
878sub draw_line {\r
879 my ( $self, @args ) = @_;\r
880 if ( @args < 4 ) {\r
881 croak "Missing parameters in Pastel::Graphics::draw_line()!\n";\r
882 }\r
883 my $color = $self->get_paint()->to_svg_stroke();\r
884 my $stroke = $self->get_stroke()->to_svg();\r
885 $self->{_temp} .=\r
886qq(<line x1="$args[0]" y1="$args[1]" x2="$args[2]" y2="$args[3]" style="fill:none; $color $stroke" />);\r
887}\r
888\r
889sub draw_oval {\r
890 my ( $self, @args ) = @_;\r
891 if ( @args < 4 ) {\r
892 croak "Missing parameters in Pastel::Graphics::draw_line()!\n";\r
893 }\r
894 my $color = $self->get_paint()->to_svg_stroke();\r
895 my $stroke = $self->get_stroke()->to_svg();\r
896\r
897 my $cx = $args[0] + ( $args[2] / 2 );\r
898 my $cy = $args[1] + ( $args[3] / 2 );\r
899 my $rx = $args[2] / 2;\r
900 my $ry = $args[3] / 2;\r
901 $self->{_temp} .=\r
902qq(<ellipse cx="$cx" cy="$cy" rx="$rx" ry="$ry" style="fill:none; $color $stroke" />);\r
903}\r
904\r
905sub fill_oval {\r
906 my ( $self, @args ) = @_;\r
907 if ( @args < 4 ) {\r
908 croak "Missing parameters in Pastel::Graphics::draw_line()!\n";\r
909 }\r
910 my $color = $self->get_paint()->to_svg_fill();\r
911 my $stroke = $self->get_stroke()->to_svg();\r
912\r
913 my $cx = $args[0] + ( $args[2] / 2 );\r
914 my $cy = $args[1] + ( $args[3] / 2 );\r
915 my $rx = $args[2] / 2;\r
916 my $ry = $args[3] / 2;\r
917 $self->{_temp} .=\r
918qq(<ellipse cx="$cx" cy="$cy" rx="$rx" ry="$ry" style="$color $stroke" />);\r
919}\r
920\r
921sub get_height {\r
922 return $_[0]->{height};\r
923}\r
924\r
925sub set_height {\r
926 if ( $_[1] ) { $_[0]->{height} = $_[1]; }\r
927}\r
928\r
929sub get_width {\r
930 return $_[0]->{width};\r
931}\r
932\r
933sub set_width {\r
934 if ( $_[1] ) { $_[0]->{width} = $_[1]; }\r
935}\r
936\r
937sub _buffer_add {\r
938 my $self = shift;\r
939 my $s = shift;\r
940 $self->{_temp} .= $s;\r
941}\r
942\r
943sub _initialize_writer {\r
944 my $self = shift;\r
945 my $writer = Pastel::Tools::Writer->new();\r
946 return $writer;\r
947}\r
948\r
949sub _print_header {\r
950 my $self = shift;\r
951 $self->{_writer}->print_svg('<?xml version="1.0" encoding="iso-8859-1"?>');\r
952 $self->{_writer}->print_svg( $self->{dtd} );\r
953}\r
954\r
955sub _print_footer {\r
956 my $self = shift;\r
957 $self->{_writer}->print_svg("</svg>");\r
958}\r
959\r
960sub _print_svg_start {\r
961 my $self = shift;\r
962 $self->{_writer}->print_svg( "<svg width=\""\r
963 . $self->{width}\r
964 . "\" height=\""\r
965 . $self->{height}\r
966 . "\">" );\r
967}\r
968\r
969sub message_err {\r
970 my $self = shift;\r
971 my $message = shift;\r
972 if ( ( $self->{DEBUG} =~ /^true$/i ) && ( $self->{CGI} ne "true" ) ) {\r
973 my $fh = $self->{ERROR_HANDLE};\r
974 print $fh "ERROR: $message\n";\r
975 }\r
976}\r
977\r
978=head1 SEE ALSO\r
979\r
980\r
981=head1 COPYRIGHTS\r
982\r
983Copyright (c) 2003 by Malay <curiouser@ccmb.res.in>. All rights reserved.\r
984\r
985This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself.\r
986\r
987=cut\r
988\r
9891;\r
990\r