home *** CD-ROM | disk | FTP | other *** search
- package RISCOS::DrawFile::Object;
-
- require RISCOS::DrawFile::Common;
-
- use strict;
- use vars qw ($VERSION @ISA);
-
- $VERSION = 0.04;
- @ISA = 'RISCOS::DrawFile::Common';
-
- ### use SelfLoader;
- sub RISCOS::DrawFile::Object::new ($);
- sub RISCOS::DrawFile::Object::PrePack ;
- sub RISCOS::DrawFile::Object::Layer ($);
- sub RISCOS::DrawFile::Object::PackType ;
- sub RISCOS::DrawFile::Object::PackTypeSizeBBox ;
- sub RISCOS::DrawFile::Object::Type ;
- sub RISCOS::DrawFile::Object::Write ;
- 1;
- ### __DATA__
- # 0.02 does copy constructors.
- # 0.03 PrePack does BBox not BBoxCalc
- # 0.04 SelfLoader
-
- sub new ($) {
- my $proto = shift;
- my $class = ref($proto) || $proto;
-
- my ($self, $type) = ({});
- # It is defined and it is not a reference to something.
- if (defined $_[0]) {
- unless (ref $_[0]) {
- $type = unpack ('I', $_[0])
- } elsif (ref ($_[0]) eq $class) {
- return [$_[0]->Clone()]; # All done
- }
- }
-
- if (defined $_[1]) {
- my ($split, $spare);
- if (ref $_[1] eq 'ARRAY') {
- $split = $_[1];
- } elsif (ref $_[1] eq 'CODE' && defined $type) {
- # Call the bit of code, which will return an array.
- $split = [&{$_[1]} ($type)];
- } else {
- $split = [];
- }
- ($type, $self->{'__LAYER'}, $self->{'__FLAGS'}, $spare) = @$split;
- if ($spare) {
- warn "Reserved type byte is $spare (expected 0) in object type $type"
- if $^W;
- }
- $self->{'__SPARE'} = $spare;
- }
-
- bless ($self, $class);
- wantarray ? ($self, $type) : $self;
- }
-
- # Mostly for the fonttable object to ennumerate fonts.
- # Text objects should push fontnames into the hashref in $_[0]
- sub PrePack {
- my $self = shift;
- $self->BBox (@_);
- }
-
- sub Layer ($) {
- my $self = shift;
- my $layer = $self->{'__LAYER'};
- $self->{'__LAYER'} = $_[0] if @_;
- $layer;
- }
-
- sub PackType {
- my $self = shift;
- my $type = defined $_[0] ? $_[0] : $self->{'__TYPE'};
- return pack 'I', $type
- unless defined $self->{'__LAYER'};
- pack ('C4', $type, $self->{'__LAYER'}, $self->{'__FLAGS'},
- $self->{'__SPARE'} | 0);
- }
-
- sub PackTypeSizeBBox {
- my $self = shift;
- my $type = shift;
- my $size = shift;
- my $bbox;
- if (defined ($_[0])) {
- $bbox = pack 'i4', (ref $_[0] ? @{$_[0]} : @_);
- } else {
- # Need to cope with BBox returning undef or 0 (eg empty path objects)
- $bbox = $self->BBox();
- $bbox = $bbox ? pack 'i4', @$bbox
- : pack 'x16';
- # Can't combine the x16 template, as @{undef} is not ();
- }
- $self->PackType($type) . pack ('I', (defined $size ? $size
- : $self->Size()))
- . $bbox;
- }
-
- sub Type {
- my $self = shift;
- $self->{'__TYPE'};
- }
-
- sub Write {
- my $self = shift;
- print {$_[0]} $self->Pack (@_);
- }
-
- # The extended tag is described by the following structure:
- #
- # typedef unsigned char draw_tagtyp;
- # typedef unsigned char draw_layer;
- # typedef unsigned char draw_objflags;
- #
- # struct draw_extag /* Extended object tag */
- # {
- # draw_tagtyp tag; /* Basic object type */
- # draw_layer layer; /* Object layer, 0 to 31 */
- # draw_objflags flag; /* Object flags */
- # unsigned char spare; /* For future expansion */
- # };
- #
- # The following bits in flag are used at present:
- #
- # #define flag_NODISPLAY 1 /* Never displayed */
- # #define flag_LOCKED 2 /* Object is locked */
- # #define flag_HIDDEN 4 /* Temporarily hidden */
-
- 1;
- __END__
-
- =head1 NAME
-
- RISCOS::DrawFile::Object
-
- =head1 SYNOPSIS
-
- Abstract base class for DrawFile objects.
-
- =head1 DESCRIPTION
-
- C<RISCOS::DrawFile::Object> provdes an abstract base class for DrawFile objects
- to inherit from. It provides various methods, some of which are inherited from
- C<RISCOS::DrawFile::Common> and hence are also can be used on entire DrawFiles.
- See C<L<RISCOS::DrawFile::OpaqueObject>> for a minimal usable implementation of
- a DrawFile object.
-
- =head2 Methods
-
- =over 4
-
- =item new <data>, [<split function>, ...]
-
- Create a new DrawFile object. If C<data> is not a reference it is assumed to be
- packed data, and the first 4 bytes are interpreted as an integer to get the
- object type. If a second argument is provided, a reference to code is assumed
- to be a split function with the same interface as drawplus_split_type, and will
- be called to split the extended object tag. If the second argument is a
- reference to an array it is assumed to give (type, layer, flags, spare), and
- these values are used in place of any derived from the first 4 bytes.
-
- If I<data> is a reference to an object of the same class as the new object will
- become then it is C<Clone()>ed and a list containing the clone returned. This
- allows all derived classes to easily implement a copy constructor.
-
- In scalar context C<new> returns a blessed reference to the new object. In
- array context C<new> returns a list (object, type, fonttable). I<object> can be
- a reference to a list of objects, and I<fonttable> is normally C<undef>. See
- C<RISCOS::DrawFile::FontTable> for the procedure to return a fonttable if found.
-
- Subclasses are expected to treat I<data> as based on its type. If a subclass
- recieves a reference to a list rather than a single blessed reference then it
- should return immediately with that list, as C<new> has been used as a copy
- constructor.
-
- =over 4
-
- =item scalar
-
- raw bytes from a DrawFile
-
- =item scalar reference
-
- raw bytes from a DrawFile, with type, length and bounding box stripped
-
- =item array reference
-
- object dependent list of parameters to construct a new object
-
- =back
-
- If a second argument is proviced C<new> sets the Layer, Flags and Spare members
- of the object to the supplied/split values. C<new> B<never> sets the Type member
- of the object - it is the responsibility of the derived class to store the Type
- member as if it needs to retain this information.
-
- =item PrePack <hash_reference>
-
- is provided as a hook to perform calculations immediately before saving a
- DrawFile. The hash reference is used to store the names of fonts needed in the
- FontTable, keys are font names, values the number of text objects that use that
- font (see C<PrePack> in C<RISCOS::DrawFile::Text> if you really must
- know). The default C<PrePack> calls C<BBox> and returns this value. This ensures
- that if any objects have been changed then their containing groups' bounding
- boxes will be upadated to reflect this. Derived classes should maintain this
- behaviour.
-
- =item Type
-
- returns the objects type. The default method looks in 'C<__TYPE>', which relies
- on the derived class storing it there. If your derived class does not need to
- store the Type you B<must> override this method, typically with something like
-
- sub Type { 2; }
-
- Most classes don't need to store the type, as most classes deal with only one
- type of object. Exceptions include C<OpaqueObject>, which stores all unknown
- object types, and C<Text>, which implements normal text (type 1) and
- transformed text (type 12).
-
- =item Layer [<new_layer>]
-
- returns the current layer. If an argument is provided it is used to set the
- ojbects layer, and the old layer is returned.
-
- =item PackType [<type>]
-
- packs the object's tag (type) into a 4 byte string. If the object has a layer
- defined then DrawPlus extended tag format is used.
-
- The tag is taken from the first argument if supplied, else it is looked up as
- 'C<__TYPE>'. Note that C<new> in C<RISCOS::DrawFile::Object> does not set
- '<__TYPE>', instead returning the value to the derived class.
-
- =item PackTypeSizeBBox <tag>, <size>, <bounding_box>
-
- returns a 24 byte string for the header common to all DrawFile objects
- (apart from FontTables).
-
- I<type> is passed to C<PackType> and the method C<Size> is called if I<size> is
- undefined. If I<bounding_box> is defined then the object bounding box is taken
- from it - if I<bounding_box> is an array reference should point to 4 values,
- otherwise arguments three to six are taken to be the bounding box. If
- I<bounding_box> is undefined then the method C<BBox> is called, and (0,0,0,0)
- used if this returns C<undef>.
-
- Usually C<PackTypeSizeBBox> can be called with B<no> arguments and it will do
- the right thing.
-
- =item Write <filehandle>, <fonttable>, ...
-
- writes the object to the given filehandle. The default implementation C<print>s
- the result of calling C<Pack> with the remainder of the argument list. C<Write>
- should return true unless there was an error.
-
- =back
-
- =head2 Methods supplied by C<RISCOS::DrawFile::Common>
-
- =over 4
-
- =item Clone
-
- returns a copy of this object.
-
- =item BBox
-
- returns a reference to an array giving the bounding box, or C<undef> if there is
- is no bounding box for this object (I<i.e.> font tables, empty paths, option
- objects). Note that option objects and empty paths store a bounding box of
- (0,0,0,0) when saved. C<BBox> will attempt to call C<BBox_Calc> (which the
- derived class B<must> provide) if the bounding box is currently unknown.
-
- As the returned array reference B<is> the internal copy of the bounding box it
- must not be modified.
-
- =item Inside <bbox>
-
- =item InsideOrTouching <bbox>
-
- =item Intersect <bbox>
-
- =item IntersectOrTouching <bbox>
-
- =item Outside <bbox>
-
- return a reference to the object if it has the correct relationship with the
- bounding box (passed as an array reference), C<undef> if it does not.
-
- =back
-
- =head2 Methods derived classes must supply
-
- In addition to the overriding above methods where appropriate (in particular
- C<Type>) derived classes must provide the following methods
-
- =over 4
-
- =item BBox_Calc
-
- (re)calculates the bounding box, returning a reference to an array, or undef if
- there is no bounding box. As it has no idea about the data it contains
- C<OpaqueObject> simply returns the bounding box it was given when it was called.
-
- =item Size
-
- returns the size of the object when saved in a DrawFile
-
- =item Pack <undef>, fonttable, ...
-
- returns a scalar containing the object packed ready to save into a DrawFile.
-
- =back
-
- =head1 BUGS
-
- Not tested enough.
-
- =head1 AUTHOR
-
- Nicholas Clark <F<nick@unfortu.net>>
-