ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/kgsueme/kgsueme/chat.pl
(Generate patch)

Comparing kgsueme/kgsueme/chat.pl (file contents):
Revision 1.3 by pcg, Thu May 20 22:59:55 2004 UTC vs.
Revision 1.4 by root, Wed Jun 2 04:39:07 2004 UTC

1use utf8;
2
1package chat; 3package chat;
4
5# waaay cool widget. well... maybe at one point in the future
2 6
3use Gtk2; 7use Gtk2;
4 8
5use Glib::Object::Subclass 9use Glib::Object::Subclass
6 Gtk2::VBox, 10 Gtk2::VBox,
10 return_type => undef, # void return 14 return_type => undef, # void return
11 param_types => [Glib::Scalar, Glib::Scalar], 15 param_types => [Glib::Scalar, Glib::Scalar],
12 }, 16 },
13 }; 17 };
14 18
15my $tagtable = new Gtk2::TextTagTable;
16
17{
18 my %tags = (
19 default => { foreground => "black" },
20 node => { foreground => "#0000b0", event => 1 },
21 move => { foreground => "#0000b0", event => 1 },
22 user => { foreground => "#0000b0", event => 1 },
23 coord => { foreground => "#0000b0", event => 1 },
24 error => { foreground => "#ff0000", event => 1 },
25 header => { weight => 800, pixels_above_lines => 6 },
26 description => { weight => 800, foreground => "blue" },
27 infoblock => { weight => 700, foreground => "blue" },
28 );
29
30 while (my ($k, $v) = each %tags) {
31 my $tag = new Gtk2::TextTag $k;
32 if (delete $v->{event}) {
33 ###
34 }
35 $tag->set (%$v);
36 $tagtable->add ($tag);
37 }
38}
39
40sub INIT_INSTANCE { 19sub INIT_INSTANCE {
41 my $self = shift; 20 my $self = shift;
21
22 my $tagtable = new Gtk2::TextTagTable;
23
24 {
25 my @tags = (
26 [default => { foreground => "black" }],
27 [node => { foreground => "#0000b0", event => 1 }],
28 [move => { foreground => "#0000b0", event => 1 }],
29 [user => { foreground => "#0000b0", event => 1 }],
30 [coord => { foreground => "#0000b0", event => 1 }],
31 [score => { foreground => "#0000b0", event => 1 }],
32 [error => { foreground => "#ff0000", event => 1 }],
33 [header => { weight => 800, pixels_above_lines => 6 }],
34 [undo => { foreground => "#ffff00", background => "#ff0000", weight => 800, pixels_above_lines => 6 }],
35 [challenge => { weight => 800, pixels_above_lines => 6, background => "#ffffb0" }],
36 [description => { weight => 800, foreground => "blue" }],
37 [infoblock => { weight => 700, foreground => "blue" }],
38 );
39
40 for (@tags) {
41 my ($k, $v) = @$_;
42 my $tag = new Gtk2::TextTag $k;
43 if (delete $v->{event}) {
44 ###
45 }
46 $tag->set (%$v);
47 $tagtable->add ($tag);
48 }
49 }
50
51 $self->{tagtable} = $tagtable;
42 52
43 $self->signal_connect (destroy => sub { 53 $self->signal_connect (destroy => sub {
44 remove Glib::Source delete $self->{idle} if $self->{idle}; 54 remove Glib::Source delete $self->{idle} if $self->{idle};
45 %{$_[0]} = (); 55 %{$_[0]} = ();
46 }); 56 });
47 57
48 $self->{buffer} = new Gtk2::TextBuffer $tagtable; 58 $self->{buffer} = new Gtk2::TextBuffer $self->{tagtable};
49 59
50 $self->{widget} = new Gtk2::ScrolledWindow; 60 $self->{widget} = new Gtk2::ScrolledWindow;
51 $self->{widget}->set_policy("never", "always"); 61 $self->{widget}->set_policy("never", "always");
52 $self->pack_start ($self->{widget}, 1, 1, 0); 62 $self->pack_start ($self->{widget}, 1, 1, 0);
53 63
81 0; 91 0;
82 }); 92 });
83 93
84 $self->pack_start (($self->{entry} = new Gtk2::Entry), 0, 1, 0); 94 $self->pack_start (($self->{entry} = new Gtk2::Entry), 0, 1, 0);
85 95
86 $self->{entry}->signal_connect(activate => sub { 96 $self->{entry}->signal_connect (activate => sub {
87 my ($entry) = @_; 97 my ($entry) = @_;
88 my $text = $entry->get_text; 98 my $text = $entry->get_text;
89 $entry->set_text(""); 99 $entry->set_text("");
90 100
91 my ($cmd, $arg); 101 my ($cmd, $arg);
97 } 107 }
98 108
99 $self->signal_emit (command => $cmd, $arg); 109 $self->signal_emit (command => $cmd, $arg);
100 }); 110 });
101 111
112 #$self->{end} = $self->{buffer}->create_mark (undef, $self->{buffer}->get_end_iter, 0);#d##todo# use this one for gtk-1.050+
113 $self->{end} = $self->{buffer}->create_mark (++$USELESSNAME, $self->{buffer}->get_end_iter, 0); # workaround for gtk-perl bug
102 114
103 $self->set_end; 115 $self->set_end;
104} 116}
105 117
106sub do_command { 118sub do_command {
127} 139}
128 140
129sub append_text { 141sub append_text {
130 my ($self, $text) = @_; 142 my ($self, $text) = @_;
131 143
144 $self->_append_text ($self->{end}, $text);
145}
146
147sub _append_text {
148 my ($self, $mark, $text) = @_;
149
132 my $at_end = $self->at_end; 150 my $at_end = $self->at_end;
133 151
152 $text = "<default>$text</default>";
153
134 my @tag; 154 my @tag;
135 $text = "<default>$text</default>";
136
137 # pseudo-simplistic-xml-parser 155 # pseudo-simplistic-xml-parser
138 for (;;) { 156 for (;;) {
139 $text =~ /\G<([^>]+)>/gc or last; 157 $text =~ /\G<([^>]+)>/gc or last;
140 my $tag = $1; 158 my $tag = $1;
141 if ($tag =~ s/^\///) { 159 if ($tag =~ s/^\///) {
143 } else { 161 } else {
144 push @tag, $tag; 162 push @tag, $tag;
145 } 163 }
146 164
147 $text =~ /\G([^<]*)/gc or last; 165 $text =~ /\G([^<]*)/gc or last;
148 $self->{buffer}->insert_with_tags_by_name ($self->{buffer}->get_end_iter, util::xmlto $1, $tag[-1]) 166 $self->{buffer}->insert_with_tags_by_name ($self->{buffer}->get_iter_at_mark ($mark), util::xmlto $1, @tag)
149 if length $1; 167 if length $1;
150 } 168 }
151 169
152 $self->set_end if $at_end; 170 $self->set_end if $at_end;
153} 171}
161 $self->append_text ($text); 179 $self->append_text ($text);
162 180
163 $self->set_end if $at_end; 181 $self->set_end if $at_end;
164} 182}
165 183
184sub new_eventtag {
185 my ($self, $cb) = @_;
186
187 my $tag = new Gtk2::TextTag;
188 $tag->signal_connect (event => $cb);
189 $self->{tagtable}->add ($tag);
190
191 $tag
192}
193
194# create a new "subbuffer"
195sub new_inlay {
196 my ($self) = @_;
197
198 my $end = $self->{buffer}->get_end_iter;
199
200 my $self = bless {
201 buffer => $self->{buffer},
202 parent => $self,
203 }, superchat::inlay;
204
205 # $USELESSNAME is a Gtk-perl < 1.042 workaround
206 $self->{l} = $self->{buffer}->create_mark (++$USELESSNAME, $end, 1);
207 $self->{buffer}->insert ($end, "\x{200d}");
208 $self->{r} = $self->{buffer}->create_mark (++$USELESSNAME, $self->{buffer}->get_iter_at_mark ($self->{l}), 0);
209
210 Scalar::Util::weaken $self->{buffer};
211 Scalar::Util::weaken $self->{parent};
212 $self;
213}
214
215sub new_switchable_inlay {
216 my ($self, $header, $cb, $visible) = @_;
217
218 my $inlay;
219
220 my $tag = $self->new_eventtag (sub {
221 my ($tag, $view, $event, $iter) = @_;
222
223 if ($event->type eq "button-press") {
224 $inlay->set_visible (!$inlay->{visible});
225 return 1;
226 }
227
228 0;
229 });
230
231 $tag->set (background => "#e0e0ff");
232
233 $inlay = $self->new_inlay;
234
235 $inlay->{visible} = $visible;
236 $inlay->{header} = $header;
237 $inlay->{tag} = $tag;
238 $inlay->{cb} = $cb;
239
240 Scalar::Util::weaken $inlay->{tag};
241
242 $inlay->refresh;
243
244 $inlay;
245}
246
247package superchat::inlay;
248
249sub liter { $_[0]{buffer}->get_iter_at_mark ($_[0]{l}) }
250sub riter { $_[0]{buffer}->get_iter_at_mark ($_[0]{r}) }
251
252sub clear {
253 my ($self) = @_;
254 $self->{buffer}->delete ($self->liter, $self->riter);
255}
256
257sub append_text {
258 my ($self, $text) = @_;
259
260 $self->{parent}->_append_text ($self->{r}, $text);
261}
262
263sub append_widget {
264 my ($self, $widget) = @_;
265
266 $widget->show_all;
267
268 my $anchor = $self->{buffer}->create_child_anchor ($self->riter);
269 $self->{parent}{view}->add_child_at_anchor ($widget, $anchor);
270}
271
272sub append_optionmenu {
273 my ($self, $ref, @entry) = @_;
274
275 my @vals;
276
277 my $widget = new Gtk2::OptionMenu;
278 $widget->set (menu => my $menu = new Gtk2::Menu);
279
280 my $idx = 0;
281
282 while (@entry >= 2) {
283 my $value = shift @entry;
284 my $label = shift @entry;
285
286 $menu->append (new Gtk2::MenuItem $label);
287 push @vals, $value;
288
289 if ($value eq $$ref && $idx >= 0) {
290 $widget->set_history ($idx);
291 $idx = -1e6;
292 }
293 $idx++;
294 }
295
296 my $cb = shift @entry;
297
298 $widget->signal_connect (changed => sub {
299 my $new = $vals[$_[0]->get_history];
300
301 if ($new ne $$ref) {
302 $$ref = $new;
303 $cb->($new) if $cb;
304 }
305 });
306
307 $self->append_widget ($widget);
308
309 $widget;
310}
311
312sub append_entry {
313 my ($self, $ref, $width, $cb) = @_;
314
315 my $widget = new Gtk2::Entry;
316 $widget->set (text => $$ref, width_chars => $width);
317 eval { $widget->set (xalign => 1) }; # workaround für 2.2
318 $widget->signal_connect (changed => sub {
319 $$ref = $_[0]->get_text;
320 $cb->($$ref) if $cb;
321 });
322
323 $self->append_widget ($widget);
324 $widget;
325}
326
327sub append_button {
328 my ($self, $label, $cb) = @_;
329
330 my $widget = new_with_label Gtk2::Button $label;
331 $widget->signal_connect (clicked => sub { $cb->() if $cb });
332
333 $self->append_widget ($widget);
334 $widget;
335}
336
337sub visible { $_[0]{visible} }
338
339sub set_visible {
340 my ($self, $visible) = @_;
341
342 return if $self->{visible} == $visible;
343 $self->{visible} = $visible;
344
345 $self->refresh;
346}
347
348sub refresh {
349 my ($self) = @_;
350
351 $self->clear;
352
353 my $arrow = $self->{visible} ? "⊟" : "⊞";
354
355 $self->{buffer}->insert ($self->riter, "\n");
356 $self->{buffer}->insert_with_tags ($self->riter, util::xmlto "$arrow $self->{header}", $self->{tag});
357
358 return unless $self->{visible};
359
360 $self->{cb}->($self);
361}
362
363sub destroy {
364 my ($self) = @_;
365
366 return if !$self->{l} || !$self->{buffer} || $self->{l}->get_deleted;
367
368 $self->clear if $self->{buffer};
369
370 delete $self->{parent};
371 delete $self->{buffer};
372 delete $self->{l};
373 delete $self->{r};
374}
375
376sub DESTROY {
377 my $self = shift;
378
379 $self->{parent}{tagtable}->remove (delete $self->{tag}) if $self->{tag} && $self->{parent};
380 #&destroy;
381}
382
1661; 3831;
167 384

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines