File Coverage

blib/lib/Games/Roguelike/Console.pm
Criterion Covered Total %
statement 51 90 56.6
branch 16 54 29.6
condition 0 3 0.0
subroutine 11 15 73.3
pod 4 8 50.0
total 82 170 48.2


line stmt bran cond sub pod time code
1             package Games::Roguelike::Console;
2            
3 5     5   31 use strict;
  5         19  
  5         362  
4            
5 5     5   29 use Exporter;
  5         9  
  5         1195  
6             our @ISA=qw(Exporter);
7 5     5   34 use Carp qw(croak);
  5         7  
  5         351  
8 5     5   57 use warnings::register;
  5         10  
  5         2366  
9            
10             our $VERSION = '0.4.' . [qw$Revision: 256 $]->[1];
11            
12             =head1 NAME
13            
14             Games::Roguelike::Console - Platform-neutral console handling
15            
16             =head1 SYNOPSIS
17            
18             use Games::Roguelike::Console;
19            
20             $con = Games::Roguelike::Console->new();
21             $con->attron('bold yellow');
22             $con->addstr('test');
23             $con->attroff();
24             $con->refresh();
25            
26             =head1 DESCRIPTION
27            
28             Attempts to figure out which Games::Roguelike::Console subclass to instantiate in order to provide console support.
29            
30             =head2 METHODS
31            
32             =over 4
33            
34             =item new ([type=>$stype], [noinit=>1])
35            
36             Create a new console, optionally specifying the subtype (win32, ansi, curses or dump:file[:keys]), and the noinit flag (which suppresses terminal initialization.)
37            
38             If a type is not specified, a suitable default will be chosen.
39            
40             =item addch ([$y, $x], $str);
41            
42             =item addstr ([$y, $x], $str);
43            
44             =item attrstr ($color, [$y, $x], $str);
45            
46             Prints a string at the y, x positions or at the current cursor position (also positions the cursor at y, x+length(str))
47            
48             =item attron ($color)
49            
50             Turns on color attributes ie: bold blue, white, white on black, black on bold blue
51            
52             =item attroff ()
53            
54             Turns off color attributes
55            
56             =item refresh ()
57            
58             Draws the current screen
59            
60             =item redraw ()
61            
62             Redraws entire screen (if out of sync)
63            
64             =item move ($y, $x)
65            
66             Moves the cursor to y, x
67            
68             =item getch ()
69            
70             Reads a character from input
71            
72             =item nbgetch ()
73            
74             Reads a character from input, non-blocking
75            
76             =item parsecolor ()
77            
78             Helper function for subclass, parses an attribute then calls "nativecolor($fg, $bg, $bold)", caching the results.
79            
80             Subclass can define this instead of nativecolor, if desired.
81            
82             =item tagstr ([$y, $x,] $str)
83            
84             Moves the cursor to y, x and writes the string $str, which can contain tags
85            
86             =item cursor([bool])
87            
88             Changes the state of whether the cursor is shown, or returns the current state.
89            
90             =item rect(x, y, w, h)
91            
92             Sets the left margin (x) for things that parse out carraige returns, and is the
93             rectangle used for scrolling.
94            
95             =back
96            
97             =head1 SEE ALSO
98            
99             L, L, L
100            
101             =head1 AUTHOR
102            
103             Erik Aronesty C
104            
105             =head1 LICENSE
106            
107             This program is free software; you can redistribute it and/or
108             modify it under the same terms as Perl itself.
109            
110             See L or the included LICENSE file.
111            
112             =cut
113            
114            
115             # platform independent
116 5     5   7436 use Games::Roguelike::Console::ANSI;
  5         17  
  5         203  
117 5     5   5689 use Games::Roguelike::Console::Dump;
  5         41  
  5         6705  
118            
119             our ($OK_WIN32, $OK_CURSES, $DUMPFILE, $DUMPKEYS);
120            
121             my %CONDATA;
122            
123             eval{require Games::Roguelike::Console::Win32};
124             $OK_WIN32 = !$@;
125            
126             eval{require Games::Roguelike::Console::Curses};
127             $OK_CURSES = !$@;
128            
129             # guess best package, and return "new of that package"
130            
131             sub new {
132 4     4 1 355 my $pkg = shift;
133 4         25 my %opt = @_;
134            
135 4 100       15 if ($DUMPFILE) {
136             # override params and just create a dump console
137 3 50       55 return new Games::Roguelike::Console::Dump @_, file=>($DUMPFILE?$DUMPFILE:'>/dev/null'), keys=>$DUMPKEYS;
138             }
139            
140 1 50       6 $opt{type} = '' if !defined $opt{type};
141            
142 1 50       7 if ($opt{type} eq '') {
143 1 50       4 $opt{type} = 'win32' if $OK_WIN32;
144 1 50       5 $opt{type} = 'curses' if $OK_CURSES;
145             }
146            
147 1 50       6 $opt{type} = 'ansi' if $opt{type} eq '';
148            
149 1 50       5 if ($opt{type} eq 'ansi') {
150 1         19 return new Games::Roguelike::Console::ANSI @_;
151             }
152 0 0       0 if ($opt{type} =~ /dump:?(.*):?(.*)/) {
153 0         0 return new Games::Roguelike::Console::Dump @_, file=>$1, keys=>$2;
154             }
155 0 0       0 if ($opt{type} eq 'win32') {
156 0         0 return new Games::Roguelike::Console::Win32 @_;
157             }
158 0 0       0 if ($opt{type} eq 'curses') {
159 0         0 return new Games::Roguelike::Console::Curses @_;
160             }
161             }
162            
163             # this should be called by sublcass, unless they supply their own defcolor, rect defaults
164             sub init {
165 2     2 0 5 my $self = shift;
166 2         6 my %opts = @_;
167 2         26 $self->defcolor($opts{defcolor});
168 2         25 $self->rect($opts{x}, $opts{y}, $opts{w}, $opts{h});
169             }
170            
171             sub DESTROY {
172 0     0   0 croak "hey, this should never be called, override it!";
173             }
174            
175             my %COLORMAP;
176             sub parsecolor {
177 0     0 1 0 my $self = shift;
178 0         0 my $pkg = ref($self);
179 0         0 my ($attr, $parsedef) = @_;
180            
181 0 0       0 $attr = '' if ! defined $attr;
182 0 0 0     0 if ($parsedef || !$COLORMAP{$pkg}{$attr}) {
183 0         0 my $bg = $CONDATA{$self}->{bg};
184 0         0 my $fg = $CONDATA{$self}->{fg};
185 0 0       0 $bg = $1 if $attr=~ s/on[\s_]+(.*)$//;
186 0         0 $fg = $attr;
187 0         0 my $bold = 0;
188 0 0       0 $bold = 1 if $fg =~ s/\s*bold\s*//;
189 0 0       0 $fg = 'white' if !$fg;
190             # trim spaces in color names
191 0         0 $fg =~ s/ //g;
192 0         0 $bg =~ s/ //g;
193 0 0       0 ($fg, $bold) = ('black', 1) if $fg =~ /gray|grey/;
194 0 0       0 ($bg, $bold) = ('black', 1) if $bg =~ /gray|grey/;
195 0         0 $COLORMAP{$pkg}{$attr} = $self->nativecolor($fg, $bg, $bold);
196 0 0       0 return ($COLORMAP{$pkg}{$attr}, $fg, $bg) if $parsedef;
197             }
198 0         0 return $COLORMAP{$pkg}{$attr};
199             }
200            
201             sub nativecolor {
202 0     0 0 0 my $self = shift;
203 0         0 my ($fg, $bg, $bold) = @_;
204 0         0 croak "nativecolor must be overridden in " . ref($self);
205             }
206            
207             sub attrch {
208 189     189 0 293 my $self = shift;
209 189         705 my ($color, @args) = @_;
210            
211 189 50       1016 if ($color) {
212 0         0 $self->attron($color);
213 0         0 $self->addch(@args);
214 0         0 $self->attroff($color);
215             } else {
216 189         2470 $self->addch(@args);
217             }
218             }
219            
220             sub attrstr {
221 0     0 1 0 my $self = shift;
222 0         0 my ($color, @args) = @_;
223            
224 0 0       0 if ($color) {
225 0         0 $self->attron($color);
226 0         0 $self->addstr(@args);
227 0         0 $self->attroff($color);
228             } else {
229 0         0 $self->addch(@args);
230             }
231             }
232            
233             sub rect {
234 2     2 1 4 my $self = shift;
235 2         8 my ($x, $y, $w, $h) = @_;
236 2 50       7 $CONDATA{$self}->{rx} = $x+0 if defined $x;
237 2 50       6 $CONDATA{$self}->{ry} = $y+0 if defined $y;
238 2 50       7 $CONDATA{$self}->{rw} = $w+0 if defined $w;
239 2 50       7 $CONDATA{$self}->{rh} = $h+0 if defined $h;
240 2         148 return ($CONDATA{$self}->{rx}, $CONDATA{$self}->{ry}, $CONDATA{$self}->{rw}, $CONDATA{$self}->{rh});
241             }
242            
243             sub defcolor {
244 2     2 0 5 my $self = shift;
245 2 50       16 if (@_) {
246 2 50       19 my ($color, $fg, $bg) = $self->parsecolor(($_[0] ? $_[0] : 'white on black'), 1);
247 2         66 $CONDATA{$self}->{defcolor}= $color;
248 2         14 $CONDATA{$self}->{fg}= $fg;
249 2         8 $CONDATA{$self}->{bg}= $bg;
250             }
251 2         8 return $CONDATA{$self}->{defcolor};
252             }
253            
254             1;