ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/Net-IRC3/samples/CursesChatMainwindow.pm
Revision: 1.2
Committed: Mon Dec 25 19:39:41 2006 UTC (19 years, 8 months ago) by elmex
Branch: MAIN
Changes since 1.1: +12 -2 lines
Log Message:
further improvements on the json irc client

File Contents

# User Rev Content
1 elmex 1.1 package CursesChatMainwindow;
2     use strict;
3     use Curses;
4     use Term::ReadKey;
5     use Exporter;
6     our @ISA = qw/Exporter/;
7 elmex 1.2 our @EXPORT = qw/printline select_buffer current_buffer/;
8 elmex 1.1
9     our $HEIGHT;
10     our $WIDTH;
11     our $MAINWIN;
12     our $stdiowatcher;
13    
14     our $current_buffer_scroll = 0;
15     our $current_buffer = "status";
16     our $winbuffers = {};
17    
18     our $input_cb = sub {};
19    
20     our @history;
21     our $inputbuffer;
22     our $inputoffset = 0;
23     our $cursor = 0;
24     our $statusline;
25    
26     $SIG{WINCH} = sub {
27     my ($wc, $hc, $wpx, $hpx) = GetTerminalSize ();
28     resizeterm ($hc, $wc);
29     $MAINWIN->resize ($hc, $wc);
30     $HEIGHT = $hc;
31     $WIDTH = $wc;
32     $MAINWIN->erase;
33     refresh ();
34     };
35    
36     sub color2attr {
37     my $c = $_[0];
38     my $attr;
39     if ($c <= 63) {
40     $attr = COLOR_PAIR($c);
41     } elsif ($c <= 127) {
42     $c -= 64;
43     $attr = COLOR_PAIR($c) | A_BOLD;
44     } elsif ($c <= 191) {
45     $c -= 128;
46     $attr = COLOR_PAIR($c) | A_UNDERLINE;
47     } else {
48     $c -= 192;
49     $attr = COLOR_PAIR($c) | A_UNDERLINE | A_BOLD;
50     }
51     $attr
52     }
53    
54     sub register_input_cb {
55     my ($cb) = @_;
56     $input_cb = $cb;
57     }
58    
59     sub _draw_attr_line_at {
60     my ($line, $attrline) = @_;
61    
62     my @lcont = @$attrline;
63     my $li = 0;
64    
65     while (@lcont > 0) {
66     my ($color, $str) = (shift @lcont, shift @lcont);
67    
68     $MAINWIN->attron (color2attr ($color));
69    
70     my $sl = length $str;
71     if (($li + $sl) > $WIDTH) {
72     $sl = $WIDTH - $li;
73     last if $sl < 0;
74     }
75    
76     $MAINWIN->addnstr ($line, $li, (substr $str, 0, $sl), $sl);
77    
78     $li += $sl;
79    
80     $MAINWIN->attroff (color2attr ($color));
81     }
82     }
83    
84     sub clog {
85     open LOG, ">>/tmp/debuglog";
86     print LOG @_;
87     close LOG;
88     }
89    
90     sub wrap_attr_lines {
91     my ($width, @lines) = @_;
92    
93     my @outlines;
94    
95     for my $line (@lines) {
96     my $wrap_padding = 0;
97     my @cline = @$line;
98     my @oline;
99    
100     my $outc = 0;
101    
102     while (@cline) {
103     my ($color, $str) = (shift @cline, shift @cline);
104     if ($color =~ m/^p\s*(\d+)\s*$/) {
105     $wrap_padding = $1;
106     ($color, $str) = ($str, shift @cline);
107     }
108    
109     my $strlen = length $str;
110    
111     if (($outc + $strlen) > $width) {
112     my $thisl = $width - $outc;
113     push @oline, ($color, substr $str, 0, $thisl);
114     push @outlines, [@oline];
115     @oline = ();
116     unshift @cline, ($color, substr $str, $thisl);
117     if ($wrap_padding && $wrap_padding < $width) {
118     unshift @cline, (0, ' ' x $wrap_padding);
119     }
120     $outc = 0;
121     } else {
122     push @oline, ($color, $str);
123     $outc += $strlen;
124     }
125     }
126    
127     push @outlines, [@oline];
128     }
129    
130     # my $i = 0;
131     # for my $line (@outlines) {
132     # clog ("LINE$i: ".join ('|',@$line)."\n");
133     # $i++;
134     # }
135    
136     @outlines;
137     }
138    
139     sub refresh_lines {
140     $MAINWIN->erase;
141    
142     my @revwin = @{$winbuffers->{$current_buffer} || []};
143     if (scalar @revwin > ($HEIGHT + $current_buffer)) {
144     (@revwin) = splice @revwin, -$HEIGHT;
145     }
146    
147     my (@out_lines) = reverse wrap_attr_lines ($WIDTH, @revwin);
148    
149     if ($current_buffer_scroll > 0) {
150     if ($current_buffer_scroll > scalar (@out_lines)) {
151     $current_buffer_scroll = scalar (@out_lines);
152     }
153     @out_lines = splice @out_lines, $current_buffer_scroll;
154     clog ("SPLICE$current_buffer_scroll [".(scalar @out_lines)."]\n");
155     }
156    
157     _draw_attr_line_at ($HEIGHT - 2, $statusline || [0, 'nothing']);
158    
159     my $line = $HEIGHT - 3;
160     while ($line >= 0) {
161     my $l = shift @out_lines;
162     last unless defined $l;
163     _draw_attr_line_at ($line--, $l);
164     }
165     }
166    
167     sub refresh {
168     my ($onlyinput) = @_;
169    
170     refresh_lines unless $onlyinput;
171    
172     $MAINWIN->move ($HEIGHT - 1, 0);
173     $MAINWIN->clrtoeol ();
174    
175     my $padding = $WIDTH - int ($WIDTH / 1.2);
176    
177     if ($cursor >= ($WIDTH - $padding)) {
178     my $iobuf = $inputbuffer;
179     my $il = length $iobuf;
180     my $ncursor = $cursor;
181     my $lcursor = $cursor - int ($WIDTH / 1.2);
182     $ncursor -= $lcursor;
183     substr $iobuf, 0, $lcursor, '';
184     $MAINWIN->addstr ($HEIGHT - 1, 0, (substr $iobuf, 0, $WIDTH));
185     $MAINWIN->move ($HEIGHT - 1, $ncursor);
186     } else {
187     $MAINWIN->addstr ($HEIGHT - 1, 0, (substr $inputbuffer, 0, $WIDTH));
188     $MAINWIN->move ($HEIGHT - 1, $cursor);
189     }
190     $MAINWIN->refresh;
191     }
192    
193     sub select_buffer {
194     $current_buffer = $_[0];
195     $current_buffer_scroll = 0;
196     refresh ();
197     }
198    
199 elmex 1.2 sub current_buffer {
200     $current_buffer
201     }
202    
203 elmex 1.1 sub printline {
204     if ($_[0] eq 'statusline') {
205     $statusline = $_[1];
206     } else {
207     push @{$winbuffers->{(defined $_[0] ? $_[0] : "status")}}, $_[1];
208     }
209     refresh ();
210     }
211    
212     sub input {
213     my $c = $MAINWIN->getch;
214     if ($c == KEY_BACKSPACE) {
215     if ($cursor > 0) {
216     substr $inputbuffer, --$cursor, 1, '';
217     }
218     } elsif ($c == KEY_DC) {
219     substr $inputbuffer, $cursor, 1, '';
220     } elsif ($c == KEY_LEFT) {
221     $cursor-- if $cursor > 0;
222     } elsif ($c == KEY_RIGHT) {
223     $cursor++ if (($cursor + 1) <= (length $inputbuffer));
224     } elsif ($c == KEY_PPAGE) {
225     $current_buffer_scroll += int ($HEIGHT / 2);
226     } elsif ($c == KEY_NPAGE) {
227     $current_buffer_scroll -= int ($HEIGHT / 2);
228     $current_buffer_scroll = 0 if $current_buffer_scroll < 0;
229     } elsif ($c eq "\n") {
230     push @history, $inputbuffer;
231     $input_cb->($inputbuffer);
232     $inputbuffer = "";
233     $cursor = 0;
234     } else {
235     if ($c > 255) {
236     printline (status => [0, "SPECIAL[$c]"]);
237     } else {
238 elmex 1.2 if (ord ($c) == 27) {
239     my $nxt = $MAINWIN->getch;
240     $input_cb->(undef, $nxt);
241     return;
242     } else {
243     substr $inputbuffer, $cursor++, 0, $c;
244     }
245 elmex 1.1 }
246     }
247     refresh ();
248     }
249    
250     sub init {
251     my $win = $MAINWIN = Curses->new;
252     cbreak;
253     noecho;
254     clear;
255     $win->keypad (1);
256     ($HEIGHT, $WIDTH) = ($LINES, $COLS);
257     if (has_colors ()) {
258     start_color ();
259     use_default_colors ();
260     my $colors = "";
261     my (@ansi_tab) = qw/0 4 2 6 1 5 3 7/;
262     for (my $i = 1; $i < $COLOR_PAIRS; $i++) {
263     init_pair ($i, $ansi_tab[$i & 7], $i <= 7 ? -1 : $ansi_tab[$i >> 3]);
264     }
265     }
266     $win->attron (A_NORMAL);
267     $stdiowatcher = AnyEvent->io (fh => \*STDIN, poll => "r", cb => sub {
268     input;
269     });
270     }
271    
272     sub end {
273     endwin;
274     }
275    
276     sub print_colors {
277     my $l = [];
278     for (my $i = 0; $i <= 256; $i++) {
279     push @$l, $i, (sprintf "[%3d]", $i);
280     if (($i + 1) % 8 == 0) {
281     printline ($current_buffer => $l);
282     $l = [];
283     }
284     }
285     printline ($current_buffer => $l);
286     }
287     #printline ("TESTE!!!");
288    
289     1;