| Summary | Package variables | Synopsis | Description | General documentation | Methods |
| new | No description | Code |
| parts | No description | Code |
| feature | No description | Code |
| factory | No description | Code |
| panel | No description | Code |
| point | No description | Code |
| scale | No description | Code |
| start | No description | Code |
| stop | No description | Code |
| end | No description | Code |
| length | No description | Code |
| score | No description | Code |
| strand | No description | Code |
| map_pt | No description | Code |
| map_no_trunc | No description | Code |
| add_feature | No description | Code |
| add_group | No description | Code |
| top | No description | Code |
| left | No description | Code |
| right | No description | Code |
| bottom | No description | Code |
| height | No description | Code |
| width | No description | Code |
| layout_height | No description | Code |
| layout_width | No description | Code |
| calculate_boundaries | No description | Code |
| bounds | No description | Code |
| box | No description | Code |
| unfilled_box | No description | Code |
| boxes | No description | Code |
| pad_top | No description | Code |
| pad_bottom | No description | Code |
| pad_left | No description | Code |
| pad_right | No description | Code |
| move | No description | Code |
| option | No description | Code |
| configure | No description | Code |
| color | No description | Code |
| connector | No description | Code |
| bump | No description | Code |
| fgcolor | No description | Code |
| fillcolor | No description | Code |
| bgcolor | No description | Code |
| font | No description | Code |
| fontcolor | No description | Code |
| font2color | No description | Code |
| tkcolor | No description | Code |
| connector_color | No description | Code |
| layout_sort | No description | Code |
| layout | No description | Code |
| collides | No description | Code |
| add_collision | No description | Code |
| _collision_keys | No description | Code |
| draw | No description | Code |
| level | No description | Code |
| draw_connectors | No description | Code |
| _connector | No description | Code |
| draw_connector | No description | Code |
| draw_hat_connector | No description | Code |
| draw_solid_connector | No description | Code |
| draw_dashed_connector | No description | Code |
| draw_quill_connector | No description | Code |
| filled_box | No description | Code |
| filled_oval | No description | Code |
| oval | No description | Code |
| filled_arrow | No description | Code |
| linewidth | No description | Code |
| fill | No description | Code |
| set_pen | No description | Code |
| draw_component | No description | Code |
| subseq | No description | Code |
| _subseq | No description | Code |
| keyglyph | No description | Code |
| make_key_feature | No description | Code |
| all_callbacks | No description | Code |
| default_factory | No description | Code |
| new | description | prev | next | Top |
my $class = shift; my %arg = @_; my $feature = $arg{-feature} or die "No feature"; my $factory = $arg{-factory} || $class->default_factory; my $level = $arg{-level} || 0; my $flip = $arg{-flip}; my $self = bless {},$class; $self->{feature} = $feature; $self->{factory} = $factory; $self->{level} = $level; $self->{flip}++ if $flip; $self->{top} = 0; my @subglyphs; my @subfeatures = $self->subseq($feature); if (@subfeatures) { # dynamic glyph resolution}
@subglyphs = map { $_->[0] } sort { $a->[1] <=> $b->[1] } map { [$_, $_->left ] } $factory->make_glyph($level+1,@subfeatures); $self->{parts} =\@ subglyphs; } my ($start,$stop) = ($self->start, $self->stop); if (defined $start && defined $stop) { ($start,$stop) = ($stop,$start) if $start > $stop; # sheer paranoia
# the +1 here is critical for allowing features to meet nicely at nucleotide resolution
my ($left,$right) = $factory->map_pt($start,$stop+1); $self->{left} = $left; $self->{width} = $right - $left + 1; } if (@subglyphs) { my $l = $subglyphs[0]->left; $self->{left} = $l if !defined($self->{left}) || $l < $self->{left}; my $right = ( sort { $b<=>$a } map {$_->right} @subglyphs)[0]; my $w = $right - $self->{left} + 1; $self->{width} = $w if !defined($self->{width}) || $w > $self->{width}; } $self->{point} = $arg{-point} ? $self->height : undef; #Handle glyphs that don't actually fill their space, but merely mark a point.
#They need to have their collision bounds altered. We will (for now)
#hard code them to be in the center of their feature.
# note: this didn't actually seem to work properly, all features were aligned on
# their right edges. It works to do it in individual point-like glyphs such as triangle.
# if($self->option('point')){
# my ($left,$right) = $factory->map_pt($self->start,$self->stop);
# my $center = int(($left+$right)/2 + 0.5);
# $self->{width} = $self->height;
# $self->{left} = $center - ($self->{width});
# $self->{right} = $center + ($self->{width});
# }
return $self;
| parts | description | prev | next | Top |
my $self = shift; return unless $self->{parts}; return wantarray ? @{$self->{parts}} : $self->{parts};}
| feature | description | prev | next | Top |
shift->{feature}}
| factory | description | prev | next | Top |
shift->{factory}}
| panel | description | prev | next | Top |
shift->factory->panel}
| point | description | prev | next | Top |
shift->{point}}
| scale | description | prev | next | Top |
shift->factory->scale}
| start | description | prev | next | Top |
my $self = shift; return $self->{start} if exists $self->{start}; $self->{start} = $self->{flip} ? $self->panel->end + 1 - $self->{feature}->end : $self->{feature}->start; # handle the case of features whose endpoints are undef}
# (this happens with wormbase clones where one or more clone end is not defined)
# in this case, we set the start to one minus the beginning of the panel
$self->{start} = $self->panel->offset - 1 unless defined $self->{start}; return $self->{start};
| stop | description | prev | next | Top |
my $self = shift; return $self->{stop} if exists $self->{stop}; $self->{stop} = $self->{flip} ? $self->panel->end + 1 - $self->{feature}->start : $self->{feature}->end; # handle the case of features whose endpoints are undef}
# (this happens with wormbase clones where one or more clone end is not defined)
# in this case, we set the start to one plus the end of the panel
$self->{stop} = $self->panel->offset + $self->panel->length + 1 unless defined $self->{stop}; return $self->{stop}
| end | description | prev | next | Top |
shift->stop}
| length | description | prev | next | Top |
my $self = shift; $self->stop - $self->start };}
| score | description | prev | next | Top |
my $self = shift; return $self->{score} if exists $self->{score}; return $self->{score} = ($self->{feature}->score || 0);}
| strand | description | prev | next | Top |
my $self = shift; return $self->{strand} if exists $self->{strand}; return $self->{strand} = ($self->{feature}->strand || 0);}
| map_pt | description | prev | next | Top |
shift->{factory}->map_pt(@_)}
| map_no_trunc | description | prev | next | Top |
shift->{factory}->map_no_trunc(@_)}
| add_feature | description | prev | next | Top |
my $self = shift; my $factory = $self->factory; for my $feature (@_) { if (ref $feature eq 'ARRAY') { $self->add_group(@$feature); } else { push @{$self->{parts}},$factory->make_glyph(0,$feature); } }}
| add_group | description | prev | next | Top |
my $self = shift; my @features = ref($_[0]) eq 'ARRAY' ? @{$_[0]} : @_; my $f = Bio::Graphics::Feature->new( -segments=>\@features, -type => 'group' ); $self->add_feature($f);}
| top | description | prev | next | Top |
my $self = shift; my $g = $self->{top}; $self->{top} = shift if @_; $g;}
| left | description | prev | next | Top |
my $self = shift; return $self->{left} - $self->pad_left;}
| right | description | prev | next | Top |
my $self = shift; return $self->left + $self->layout_width - 1;}
| bottom | description | prev | next | Top |
my $self = shift; $self->top + $self->layout_height - 1;}
| height | description | prev | next | Top |
my $self = shift; return $self->{height} if exists $self->{height}; my $baseheight = $self->option('height'); # what the factory says}
return $self->{height} = $baseheight;
| width | description | prev | next | Top |
my $self = shift; my $g = $self->{width}; $self->{width} = shift if @_; $g;}
| layout_height | description | prev | next | Top |
my $self = shift; return $self->layout;}
| layout_width | description | prev | next | Top |
my $self = shift; return $self->width + $self->pad_left + $self->pad_right;}
| calculate_boundaries | description | prev | next | Top |
return shift->bounds(@_);}
| bounds | description | prev | next | Top |
my $self = shift; my ($dx,$dy) = @_; $dx += 0; $dy += 0; ($dx + $self->{left}, $dy + $self->top + $self->pad_top, $dx + $self->{left} + $self->{width} - 1, $dy + $self->bottom - $self->pad_bottom);}
| box | description | prev | next | Top |
my $self = shift; return ($self->left,$self->top,$self->right,$self->bottom);}
| unfilled_box | description | prev | next | Top |
my $self = shift; my $gd = shift; my ($x1,$y1,$x2,$y2,$fg,$bg) = @_; my $linewidth = $self->option('linewidth') || 1; unless ($fg) { $fg ||= $self->fgcolor; $fg = $self->set_pen($linewidth,$fg) if $linewidth > 1; } unless ($bg) { $bg ||= $self->bgcolor; $bg = $self->set_pen($linewidth,$bg) if $linewidth > 1; } # draw a box}
$gd->rectangle($x1,$y1,$x2,$y2,$fg); # if the left end is off the end, then cover over
# the leftmost line
my ($width) = $gd->getBounds; $gd->line($x1,$y1+$linewidth,$x1,$y2-$linewidth,$bg) if $x1 < $self->panel->pad_left; $gd->line($x2,$y1+$linewidth,$x2,$y2-$linewidth,$bg) if $x2 > $width - $self->panel->pad_right;
| boxes | description | prev | next | Top |
my $self = shift; my ($left,$top) = @_; $top += 0; $left += 0; my @result; $self->layout; my @parts = $self->parts; @parts = $self if !@parts && $self->option('box_subparts') && $self->level>0; for my $part ($self->parts) { if (eval{$part->feature->primary_tag} eq 'group' or ($part->level == 0 && $self->option('box_subparts'))) { push @result,$part->boxes($left+$self->left+$self->pad_left,$top+$self->top+$self->pad_top); } else { my ($x1,$y1,$x2,$y2) = $part->box; push @result,[$part->feature,$x1,$top+$self->top+$self->pad_top+$y1, $x2,$top+$self->top+$self->pad_top+$y2]; } } return wantarray ? @result :\@ result;}
| pad_top | description | prev | next | Top |
my $self = shift; return 0;}
| pad_bottom | description | prev | next | Top |
my $self = shift; return 0;}
| pad_left | description | prev | next | Top |
my $self = shift; return 0;}
| pad_right | description | prev | next | Top |
my $self = shift; # this shouldn't be necessary}
my @parts = $self->parts or return 0; my $max = 0; foreach (@parts) { my $pr = $_->pad_right; $max = $pr if $max < $pr; } $max;
| move | description | prev | next | Top |
my $self = shift; my ($dx,$dy) = @_; $self->{left} += $dx; $self->{top} += $dy; # because the feature parts use *absolute* not relative addressing}
# we need to move each of the parts horizontally, but not vertically
$_->move($dx,0) foreach $self->parts;
| option | description | prev | next | Top |
my $self = shift; my $option_name = shift; my $factory = $self->factory; return unless $factory; $factory->option($self,$option_name,@{$self}{qw(partno total_parts)});}
| configure | description | prev | next | Top |
my $self = shift; my $factory = $self->factory; my $option_map = $factory->option_map; while (@_) { my $option_name = shift; my $option_value = shift; ($option_name = lc $option_name) =~ s/^-//; $option_map->{$option_name} = $option_value; }}
| color | description | prev | next | Top |
my $self = shift; my $color = shift; my $index = $self->option($color); # turn into a color index}
return $self->factory->translate_color($index) if defined $index; return 0;
| connector | description | prev | next | Top |
return shift->option('connector',@_);}
| bump | description | prev | next | Top |
my $self = shift; return $self->option('bump');}
| fgcolor | description | prev | next | Top |
my $self = shift; my $color = $self->option('fgcolor'); my $index = defined $color ? $color : $self->option('color'); $index = 'black' unless defined $index; $self->factory->translate_color($index);}
| fillcolor | description | prev | next | Top |
my $self = shift; return $self->bgcolor;}
| bgcolor | description | prev | next | Top |
my $self = shift; my $bgcolor = $self->option('bgcolor'); my $index = defined $bgcolor ? $bgcolor : $self->option('fillcolor'); $index = 'white' unless defined $index; $self->factory->translate_color($index);}
| font | description | prev | next | Top |
my $self = shift; my $font = $self->option('font'); unless (UNIVERSAL::isa($font,'GD::Font')) { my $ref = { gdTinyFont => gdTinyFont, gdSmallFont => gdSmallFont, gdMediumBoldFont => gdMediumBoldFont, gdLargeFont => gdLargeFont, gdGiantFont => gdGiantFont}; my $gdfont = $ref->{$font} || $font; $self->configure(font=>$gdfont); return $gdfont; } return $font;}
| fontcolor | description | prev | next | Top |
my $self = shift; my $fontcolor = $self->color('fontcolor'); return defined $fontcolor ? $fontcolor : $self->fgcolor;}
| font2color | description | prev | next | Top |
my $self = shift; my $font2color = $self->color('font2color'); return defined $font2color ? $font2color : $self->fgcolor;}
| tkcolor | description | prev | next | Top |
# "track color" my $self = shift;}
$self->option('tkcolor') or return; return $self->color('tkcolor')
| connector_color | description | prev | next | Top |
my $self = shift; $self->color('connector_color') || $self->fgcolor;}
| layout_sort | description | prev | next | Top |
my $self = shift;
my $sortfunc;
my $opt = $self->option("sort_order");
if (!$opt) {
$sortfunc = eval 'sub { $a->left <=> $b->left }';
} elsif (ref $opt eq 'CODE') {
$sortfunc = $opt;
} elsif ($opt =~ /^sub\s+\{/o) {
$sortfunc = eval $opt;
} else {
# build $sortfunc for ourselves:
my @sortbys = split(/\s*\|\s*/o, $opt);
$sortfunc = 'sub { ';
my $sawleft = 0;
# not sure I can make this schwartzian transfored
for my $sortby (@sortbys) {
if ($sortby eq "left" || $sortby eq "default") {
$sortfunc .= '($a->left <=> $b->left) || ';
$sawleft++;
} elsif ($sortby eq "right") {
$sortfunc .= '($a->right <=> $b->right) || ';
} elsif ($sortby eq "low_score") {
$sortfunc .= '($a->score <=> $b->score) || ';
} elsif ($sortby eq "high_score") {
$sortfunc .= '($b->score <=> $a->score) || ';
} elsif ($sortby eq "longest") {
$sortfunc .= '(($b->length) <=> ($a->length)) || ';
} elsif ($sortby eq "shortest") {
$sortfunc .= '(($a->length) <=> ($b->length)) || ';
} elsif ($sortby eq "strand") {
$sortfunc .= '($b->strand <=> $a->strand) || ';
} elsif ($sortby eq "name") {
$sortfunc .= '($a->feature->display_name cmp $b->feature->display_name) || ';
}
}
unless ($sawleft) {
$sortfunc .= ' ($a->left <=> $b->left) ';
} else {
$sortfunc .= ' 0';
}
$sortfunc .= '}';
$sortfunc = eval $sortfunc;
}
# cache this
# $self->factory->set_option(sort_order => $sortfunc);
return sort $sortfunc @_;}| layout | description | prev | next | Top |
my $self = shift; return $self->{layout_height} if exists $self->{layout_height}; my @parts = $self->parts; return $self->{layout_height} = $self->height + $self->pad_top + $self->pad_bottom unless @parts; my $bump_direction = $self->bump; my $bump_limit = $self->option('bump_limit') || -1; $_->layout foreach @parts; # recursively lay out}
# no bumping requested, or only one part here
if (@parts == 1 || !$bump_direction) { my $highest = 0; foreach (@parts) { my $height = $_->layout_height; $highest = $height > $highest ? $height : $highest; } return $self->{layout_height} = $highest + $self->pad_top + $self->pad_bottom; } my (%bin1,%bin2); for my $g ($self->layout_sort(@parts)) { my $pos = 0; my $bumplevel = 0; my $left = $g->left; my $right = $g->right; my $height = $g->{layout_height}; while (1) { # stop bumping if we've gone too far down
if ($bump_limit > 0 && $bumplevel++ >= $bump_limit) { $g->{overbumped}++; # this flag can be used to suppress label and description
foreach ($g->parts) { $_->{overbumped}++; } last; } # look for collisions
my $bottom = $pos + $height; $self->collides(\%bin1,CM1,CM2,$left,$pos,$right,$bottom) or last; my $collision = $self->collides(\%bin2,CM3,CM4,$left,$pos,$right,$bottom) or last; if ($bump_direction > 0) { $pos += $collision->[3]-$collision->[1] + BUMP_SPACING; # collision, so bump
} else { $pos -= BUMP_SPACING; } } $g->move(0,$pos); $self->add_collision(\%bin1,CM1,CM2,$left,$g->top,$right,$g->bottom); $self->add_collision(\%bin2,CM3,CM4,$left,$g->top,$right,$g->bottom); } # If -1 bumping was allowed, then normalize so that the top glyph is at zero
if ($bump_direction < 0) { my $topmost; foreach (@parts) { my $top = $_->top; $topmost = $top if !defined($topmost) or $top < $topmost; } my $offset = - $topmost; $_->move(0,$offset) foreach @parts; } # find new height
my $bottom = 0; foreach (@parts) { $bottom = $_->bottom if $_->bottom > $bottom; } return $self->{layout_height} = $self->pad_bottom + $self->pad_top + $bottom - $self->top + 1;
| collides | description | prev | next | Top |
my $self = shift; my ($occupied,$cm1,$cm2,$left,$top,$right,$bottom) = @_; my @keys = $self->_collision_keys($cm1,$cm2,$left,$top,$right,$bottom); my $collides = 0; for my $k (@keys) { next unless exists $occupied->{$k}; for my $bounds (@{$occupied->{$k}}) { my ($l,$t,$r,$b) = @$bounds; next unless $right >= $l and $left <= $r and $bottom >= $t and $top <= $b; $collides = $bounds; last; } } $collides;}
| add_collision | description | prev | next | Top |
my $self = shift; my ($occupied,$cm1,$cm2,$left,$top,$right,$bottom) = @_; my $value = [$left,$top,$right+2,$bottom]; my @keys = $self->_collision_keys($cm1,$cm2,@$value); push @{$occupied->{$_}},$value foreach @keys;}
| _collision_keys | description | prev | next | Top |
my $self = shift; my ($binx,$biny,$left,$top,$right,$bottom) = @_; my @keys; my $bin_left = int($left/$binx);}
my $bin_right = int($right/$binx);
my $bin_top = int($top/$biny);
my $bin_bottom = int($bottom/$biny);
for (my $x=$bin_left;$x<=$bin_right; $x++) { for (my $y=$bin_top;$y<=$bin_bottom; $y++) { push @keys,join(',',$x,$y); } } @keys;
| draw | description | prev | next | Top |
my $self = shift; my $gd = shift; my ($left,$top,$partno,$total_parts) = @_; local($self->{partno},$self->{total_parts}); @{$self}{qw(partno total_parts)} = ($partno,$total_parts); my $connector = $self->connector; if (my @parts = $self->parts) { # invoke sorter if use wants to sort always and we haven't already sorted}
# during bumping.
@parts = $self->layout_sort(@parts) if !$self->bump && $self->option('always_sort'); my $x = $left; my $y = $top + $self->top + $self->pad_top; $self->draw_connectors($gd,$x,$y) if $connector && $connector ne 'none'; my $last_x; for (my $i=0; $i<@parts; $i++) { # lie just a little bit to avoid lines overlapping and
# make the picture prettier
my $fake_x = $x; $fake_x-- if defined $last_x && $parts[$i]->left - $last_x == 1; $parts[$i]->draw($gd,$fake_x,$y,$i,scalar(@parts)); $last_x = $parts[$i]->right; } } else { # no part
$self->draw_connectors($gd,$left,$top) if $connector && $connector ne 'none' && $self->{level} == 0; $self->draw_component($gd,$left,$top); }
| level | description | prev | next | Top |
shift->{level};}
| draw_connectors | description | prev | next | Top |
my $self = shift; return if $self->{overbumped}; my $gd = shift; my ($dx,$dy) = @_; my @parts = sort { $a->left <=> $b->left } $self->parts; for (my $i = 0; $i < @parts-1; $i++) { $self->_connector($gd,$dx,$dy,$parts[$i]->bounds,$parts[$i+1]->bounds); } # extra connectors going off ends}
if (@parts) { my($x1,$y1,$x2,$y2) = $self->bounds(0,0); my($xl,$xt,$xr,$xb) = $parts[0]->bounds; $self->_connector($gd,$dx,$dy,$x1,$xt,$x1,$xb,$xl,$xt,$xr,$xb) if $x1 < $xl; my ($xl2,$xt2,$xr2,$xb2) = $parts[-1]->bounds; $self->_connector($gd,$dx,$dy,$parts[-1]->bounds,$x2,$xt2,$x2,$xb2) if $x2 > $xr; }
| _connector | description | prev | next | Top |
my $self = shift; my ($gd, $dx,$dy, $xl,$xt,$xr,$xb, $yl,$yt,$yr,$yb) = @_; my $left = $dx + $xr; my $right = $dx + $yl; my $top1 = $dy + $xt; my $bottom1 = $dy + $xb; my $top2 = $dy + $yt; my $bottom2 = $dy + $yb; # restore this comment if you don't like the group dash working}
# its way backwards.
return if $right-$left < 1 && !$self->isa('Bio::Graphics::Glyph::group'); $self->draw_connector($gd, $top1,$bottom1,$left, $top2,$bottom2,$right, );
| draw_connector | description | prev | next | Top |
my $self = shift; my $gd = shift; my $color = $self->connector_color; my $connector_type = $self->connector or return; if ($connector_type eq 'hat') { $self->draw_hat_connector($gd,$color,@_); } elsif ($connector_type eq 'solid') { $self->draw_solid_connector($gd,$color,@_); } elsif ($connector_type eq 'dashed') { $self->draw_dashed_connector($gd,$color,@_); } elsif ($connector_type eq 'quill') { $self->draw_quill_connector($gd,$color,@_); } else { ; # draw nothing}
}
| draw_hat_connector | description | prev | next | Top |
my $self = shift; my $gd = shift; my $color = shift; my ($top1,$bottom1,$left,$top2,$bottom2,$right) = @_; my $center1 = ($top1 + $bottom1)/2;}
my $quarter1 = $top1 + ($bottom1-$top1)/4;
my $center2 = ($top2 + $bottom2)/2;
my $quarter2 = $top2 + ($bottom2-$top2)/4;
if ($center1 != $center2) { $self->draw_solid_connector($gd,$color,@_); return; } if ($right - $left > 4) { # room for the inverted "V"
my $middle = $left + int(($right - $left)/2);
$gd->line($left,$center1,$middle,$top1,$color); $gd->line($middle,$top1,$right-1,$center1,$color); } elsif ($right-$left > 1) { # no room, just connect
$gd->line($left,$quarter1,$right-1,$quarter1,$color); }
| draw_solid_connector | description | prev | next | Top |
my $self = shift; my $gd = shift; my $color = shift; my ($top1,$bottom1,$left,$top2,$bottom2,$right) = @_; my $center1 = ($top1 + $bottom1)/2;}
my $center2 = ($top2 + $bottom2)/2;
$gd->line($left,$center1,$right,$center2,$color);
| draw_dashed_connector | description | prev | next | Top |
my $self = shift; my $gd = shift; my $color = shift; my ($top1,$bottom1,$left,$top2,$bottom2,$right) = @_; my $center1 = ($top1 + $bottom1)/2;}
my $center2 = ($top2 + $bottom2)/2;
$gd->setStyle($color,$color,gdTransparent,gdTransparent,); $gd->line($left,$center1,$right,$center2,gdStyled);
| draw_quill_connector | description | prev | next | Top |
my $self = shift; my $gd = shift; my $color = shift; my ($top1,$bottom1,$left,$top2,$bottom2,$right) = @_; my $center1 = ($top1 + $bottom1)/2;}
my $center2 = ($top2 + $bottom2)/2;
$gd->line($left,$center1,$right,$center2,$color); my $direction = $self->feature->strand; return unless $direction; if ($direction > 0) { my $start = $left+4; my $end = $right-1; for (my $position=$start; $position <= $end; $position += QUILL_INTERVAL) { $gd->line($position,$center1,$position-2,$center1-2,$color); $gd->line($position,$center1,$position-2,$center1+2,$color); } } else { my $start = $left+1; my $end = $right-4; for (my $position=$start; $position <= $end; $position += QUILL_INTERVAL) { $gd->line($position,$center1,$position+2,$center1-2,$color); $gd->line($position,$center1,$position+2,$center1+2,$color); } }
| filled_box | description | prev | next | Top |
my $self = shift; my $gd = shift; my ($x1,$y1,$x2,$y2,$bg,$fg) = @_; $bg ||= $self->bgcolor; $fg ||= $self->fgcolor; my $linewidth = $self->option('linewidth') || 1; $gd->filledRectangle($x1,$y1,$x2,$y2,$bg); $fg = $self->set_pen($linewidth,$fg) if $linewidth > 1; # draw a box}
$gd->rectangle($x1,$y1,$x2,$y2,$fg); # if the left end is off the end, then cover over
# the leftmost line
my ($width) = $gd->getBounds; $bg = $self->set_pen($linewidth,$bg) if $linewidth > 1; $gd->line($x1,$y1+$linewidth,$x1,$y2-$linewidth,$bg) if $x1 < $self->panel->pad_left; $gd->line($x2,$y1+$linewidth,$x2,$y2-$linewidth,$bg) if $x2 > $width - $self->panel->pad_right;
| filled_oval | description | prev | next | Top |
my $self = shift; my $gd = shift; my ($x1,$y1,$x2,$y2,$bg,$fg) = @_; my $cx = ($x1+$x2)/2;
my $cy = ($y1+$y2)/2;
$fg ||= $self->fgcolor; $bg ||= $self->bgcolor; my $linewidth = $self->linewidth; $fg = $self->set_pen($linewidth) if $linewidth > 1; $gd->arc($cx,$cy,$x2-$x1,$y2-$y1,0,360,$fg); # and fill it