package Hexed::Util; use strict; use warnings; use include; use Exporter; our @ISA = ("Exporter"); our @EXPORT = (qw( &strip &wrap ¢er &paint )); use Curses; use Inline C => "DATA"; use Memoize; # Strip the formatting tags out of a string. sub strip { my $orig = shift; $orig =~ s/<[^>]+>//g; return $orig; } # Turns a string into a list of strings by word wrapping to the specified # number of fixed-width columns. Any embedded formatting tags (denoted by # ) are preserved, but do not count towards a line's width. sub wrap { my ($width, $in) = @_; $width = length($in) if $width == -1; my @msgs; my ($real, $line) = ("", ""); # Leading whitespace SHOULD be preserved!!! my $lead; if ($in =~ s/^(\s+)//) { $real = $line = $1; $lead = length($line); } else { $lead = 0; } # Formatting and wrapping... mmm, text bondage. $in =~ s/\n/ /g; # Collapse editor-inserted newlines $in =~ s/\s+/ /g; # Crunch extra whitespace # My homegrown word wrap disregards tags! foreach my $realword (split(/\s/, $in)) { # Strip the word first. my $word = strip $realword; if (length($line) + length($word) + 1 <= $width) { # We have enough room on this line. unless (length($line) == 0 or $lead) { # If we're at the start of the line (including leading whitespace), # don't add another space. $word = " $word"; $realword = " $realword"; } $line .= $word; $real .= $realword; } elsif (length($line) == $lead) { # If we're at the beginning of a line (including leading whitespace) and # the next word is just too big for one line, put as much of it as we can # on this line and the rest on the next. # TODO: WARNING. If we encounter a huge line like this and there are # formatting tags, just give up. # First get as much of $word as we can handle for this line. # TODO: On second thought... die "Word wrap exploded. Too big. Ugh.\n"; } else { # We've hit the edge and have to wrap. push @msgs, $real; # Start a new line with this current word. $line = $word; $real = $realword; } $lead = 0; } push @msgs, $real; # Leftovers? return @msgs; } # Tells where a string of the specified length should start on a line segment # of the specified length so that the string is centered. May be one space off # due to the fixed-width nature of terminal fonts. sub center { my ($strlen, $total) = @_; return int($total / 2) - int($strlen / 2); } # Caching color codes is highly useful in big maps. Believe me. memoize("paint"); # Returns the attribute for the specified color. sub paint { my ($fg, $bg); if (@_ == 1) { ($fg, $bg) = ($_[0] eq "/") ? ("grey", "black") : (split("/", shift)); } else { ($fg, $bg) = @_; } # If the foreground and background color are the same, something screws up. # So prevent that. # Used to be "if (!$fg)"... but that'd be something! $bg ||= "black"; $fg = "black" if $bg =~ m/(grey|grey|white)/i; #debug [$fg, $bg]; return trans_color($fg, $bg); } 42; __DATA__ __C__ #include // Return the attribute for the specified foreground and background color. int trans_color (char *fg, char *bg) { // Uppercase first letter denotes bright, lowercase denotes normal int attrib; if (islower(fg[0])) { attrib = A_NORMAL; } else { attrib = A_BOLD; } int fgcolor = color_attrib(fg); // Some foreground colors require brightness or something. if ( strcasecmp(fg, "orange") == 0) { attrib = A_NORMAL; } else if ( strcasecmp(fg, "yellow") == 0) { attrib = A_BOLD; } else if ( strcasecmp(fg, "grey") == 0) { attrib = A_NORMAL; } else if ( strcasecmp(fg, "gray") == 0) { attrib = A_NORMAL; } else if ( strcasecmp(fg, "white") == 0) { attrib = A_BOLD; } int bgcolor = color_attrib(bg); int color = fgcolor + (8 * (bgcolor - 1)); return attrib | COLOR_PAIR(color); } // Return the attribute for just one color. int color_attrib (char *color) { int attrib; if ( strcasecmp(color, "black") == 0) { attrib = 1; } else if ( strcasecmp(color, "red") == 0) { attrib = 2; } else if ( strcasecmp(color, "green") == 0) { attrib = 3; } else if ( strcasecmp(color, "yellow") == 0) { attrib = 4; } else if ( strcasecmp(color, "orange") == 0) { attrib = 4; } else if ( strcasecmp(color, "blue") == 0) { attrib = 5; } else if ( strcasecmp(color, "purple") == 0) { attrib = 6; } else if ( strcasecmp(color, "aqua") == 0) { attrib = 7; } else if ( strcasecmp(color, "cyan") == 0) { attrib = 7; } else if ( strcasecmp(color, "grey") == 0) { attrib = 8; } else if ( strcasecmp(color, "gray") == 0) { attrib = 8; } else if ( strcasecmp(color, "white") == 0) { attrib = 8; } else { fprintf(stderr, "Error! Don't recognize color %s!\n", color); } return attrib; }