#!/usr/bin/perl
#
# -*- perl -*- (this line is for emacs)
#
# Pikture
# Xterm/Ascii art drawing program
# Written by X-3mE'89 - http://exxtreme.altervista.org
# Released under GNU GPL terms
#
# Big thanks to Alessandro Rubini, author of GPM,
# that inspired this code
#
use strict;
use warnings;
use Term::ReadKey;
use Term::Size;
use Term::ReadLine;
#
# Escape sequences for Xterm mouse handling
# (DEC private mode set/reset)
#
my $Dec_Pvt_Mode_Set = "h"; # DEC private mode set
my $Dec_Pvt_Mode_Reset = "l"; # DEC private mode unset
my $VT200_Mouse = "1000"; # DEC pvt mode for VT200 mouse
my $VT200_HighLight_Mouse = "1001"; # DEC pvt mode for VT200 hilite mo
+use
my $Btn_Event_Mouse = "1002"; # DEC pvt mode: detect button even
+ts
my $Any_Event_Mouse = "1003"; # DEC pvt mode: detect any mouse e
+vent
my %MouseState;
$MouseState{'x'} = 0; # mouse X
$MouseState{'y'} = 0; # mouse Y
$MouseState{'mod'} = 0; # mode (pressed/released)
$MouseState{'btn'} = 0; # button
$MouseState{'wheel'} = 0; # was wheel moved?
$MouseState{'moving'} = 0; # detect mouse motion
my $PenChar = '+';
my $Columns = 0;
my $Lines = 0;
my @Screen = undef;
# Raw mode. I chose to put this in a variable for debugging.
my $Read_Mode = 4;
#
# DecSet
# Accepts a list of modes and prints escape sequences that set the
# associate DEC private mode
#
sub DecSet
{
my $what = shift;
print "\e[?".$what.$Dec_Pvt_Mode_Set;
}
#
# DecUnset
# Accepts a list of modes and prints escape sequences that reset the
# associate DEC private mode
#
sub DecUnset
{
my $what = shift;
print "\e[?".$what.$Dec_Pvt_Mode_Reset;
}
sub InitScr
{
print "\ec";
ReadMode $Read_Mode;
DecSet $VT200_Mouse;
#DecSet $VT200_HighLight_Mouse;
DecSet $Btn_Event_Mouse;
DecSet $Any_Event_Mouse;
($Columns, $Lines) = Term::Size::chars *STDOUT{IO};
}
sub EndScr
{
print "\n";
DecUnset $VT200_Mouse;
#DecUnset $VT200_HighLight_Mouse;
DecUnset $Btn_Event_Mouse;
DecUnset $Any_Event_Mouse;
print "\ec";
ReadMode 0;
}
sub BeginMouse
{
DecSet $VT200_Mouse;
DecSet $Btn_Event_Mouse;
DecSet $Any_Event_Mouse;
}
sub EndMouse
{
DecUnset $VT200_Mouse;
DecUnset $Btn_Event_Mouse;
DecUnset $Any_Event_Mouse;
}
#
# Paint
# Paints on the screen.
#
sub Paint
{
if($MouseState{'btn'} == 0)
{
print "\e[".$MouseState{'y'}.";".$MouseState{'x'}."H".
$PenChar;
print "\e[0;0H";
$Screen[$MouseState{'y'}][$MouseState{'x'}-1] = $PenChar;
}
}
#
# HandleChars
# Handle input chars != mouse events
#
sub HandleChars
{
my $char = chr shift;
if(($char eq 'p') or ($char eq 'P'))
{
ReadMode 0;
EndMouse;
print "\e[";
print $Lines-2;
print ";0HPen char: ";
$PenChar = ReadKey;
ReadMode $Read_Mode;
BeginMouse;
print "\e[".($Lines-2).";0H";
for(my $i = 0; $i < $Columns; $i++)
{
print " ";
}
print "\e[".($Lines-2).";0H";
}
if(($char eq 'c') or ($char eq 'C'))
{
InitScr;
my ($i,$j);
for($i = 0; $i < $Lines; $i++)
{
for($j = 0; $j < $Columns; $j++)
{
$Screen[$i][$j] = " ";
}
}
}
if(($char eq 'r') or ($char eq 'R'))
{
InitScr;
my ($i, $j);
for($i = 0; $i < $Lines; $i++)
{
for($j = 0; $j < $Columns; $j++)
{
print $Screen[$i][$j];
}
my $real = $i + 1;
print "\e[$real;0H";
}
}
if(($char eq 's') or ($char eq 'S'))
{
ReadMode 0;
EndMouse;
print "\e[";
print $Lines-2;
print ";0HFile name: ";
my $Fname = ReadLine;
ReadMode $Read_Mode;
BeginMouse;
print "\e[".($Lines-2).";0H";
for(my $i = 0; $i < $Columns; $i++)
{
print " ";
}
print "\e[";
print $Lines-1;
print "0H";
open(FILE, ">$Fname") or die "Couldn't open $Fname: $!\n";
my ($i, $j);
for($i = 0; $i < $Lines; $i++)
{
for($j = 0; $j < $Columns; $j++)
{
print FILE $Screen[$i][$j];
}
print FILE "\n";
}
close FILE;
ReadMode $Read_Mode;
BeginMouse;
}
}
#
# MouseEvents
# Handle mouse events, and put the result in %MouseEvents.
#
sub MouseEvents
{
my $btn = ord(ReadKey) - 32;
my $mod = $btn & 28; # get other 3 bits (mask = 00011100)
$mod >>= 3; # shift 3 bits right
my $wheel = 0;
my $moving = 0;
if($mod != 0)
{
$btn &= ~28; # remove modifier info
}
if($btn >= 64) # ... then wheel has been rolled
{
$wheel = 1;
$btn -= 64;
}
elsif($btn >= 32) # ... then mouse has been moved
{
$moving = 1;
$btn -= 32;
}
my $x = ord(ReadKey) - 32;
my $y = ord(ReadKey) - 32;
#
# Fill %MouseState's fields
#
$MouseState{'x'} = $x;
$MouseState{'y'} = $y;
$MouseState{'mod'} = $mod;
$MouseState{'btn'} = $btn;
$MouseState{'wheel'} = $wheel;
$MouseState{'moving'} = $moving;
printf "\e[0;0H[P]en - [C]lear - [R]efresh - [Q]uit\n".
"\e[".($Lines-1).";0HBtn=%3d; X=%3d; Y=%3d; Mod=%3d; ".
"Wheel=%3d; Moving=%3d",
$btn, $x, $y, $mod, $wheel, $moving;
Paint;
}
################## ### ## #
#
# Main loop
#
################## ### ## #
#
# Clear screen and set read mode to $Read_Mode
#
InitScr;
my ($i,$j);
for($i = 0; $i < $Lines; $i++)
{
for($j = 0; $j < $Columns; $j++)
{
$Screen[$i][$j] = " ";
}
}
my $key = "";
$| = 1; # autoflush
while(($key = ReadKey) ne 'q')
{
my $code = ord $key;
if($code == 0x1b) # got an escape seq ("\e")
{
# is it 0x5b ([) ?
$key = ReadKey;
$code = ord($key);
next if($code != 0x5b); # 0x5b = '['
my $what = ord(ReadKey);
if($what == 0x4d) # 0x4d = 'M'
{
MouseEvents;
}
}
else
{
HandleChars($code)
}
}
EndScr;
ReadMode 0;
|