ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/kgsueme/kgsueme/superchat.pl
Revision: 1.9
Committed: Wed May 26 03:28:37 2004 UTC (20 years ago) by pcg
Content type: text/plain
Branch: MAIN
Changes since 1.8: +1 -1 lines
Log Message:
*** empty log message ***

File Contents

# User Rev Content
1 pcg 1.6 use utf8;
2    
3 pcg 1.1 package superchat;
4    
5     # waaay cool widget. well... maybe at one point in the future
6    
7     use Gtk2;
8    
9     use Glib::Object::Subclass
10     Gtk2::VBox,
11     signals => {
12     command => {
13     flags => [qw/run-first/],
14     return_type => undef, # void return
15     param_types => [Glib::Scalar, Glib::Scalar],
16     },
17     };
18    
19 pcg 1.2 sub INIT_INSTANCE {
20     my $self = shift;
21 pcg 1.1
22 pcg 1.2 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     [error => { foreground => "#ff0000", event => 1 }],
32     [header => { weight => 800, pixels_above_lines => 6 }],
33     [challenge => { weight => 800, pixels_above_lines => 6, background => "#ffffb0" }],
34     [description => { weight => 800, foreground => "blue" }],
35     [infoblock => { weight => 700, foreground => "blue" }],
36     );
37    
38     for (@tags) {
39     my ($k, $v) = @$_;
40     my $tag = new Gtk2::TextTag $k;
41     if (delete $v->{event}) {
42     ###
43     }
44     $tag->set (%$v);
45     $tagtable->add ($tag);
46 pcg 1.1 }
47     }
48    
49 pcg 1.2 $self->{tagtable} = $tagtable;
50 pcg 1.1
51     $self->signal_connect (destroy => sub {
52     remove Glib::Source delete $self->{idle} if $self->{idle};
53     %{$_[0]} = ();
54     });
55    
56 pcg 1.2 $self->{buffer} = new Gtk2::TextBuffer $self->{tagtable};
57 pcg 1.1
58     $self->{widget} = new Gtk2::ScrolledWindow;
59     $self->{widget}->set_policy("never", "always");
60     $self->pack_start ($self->{widget}, 1, 1, 0);
61    
62     $self->{widget}->add ($self->{view} = new_with_buffer Gtk2::TextView $self->{buffer});
63     $self->{view}->set_wrap_mode ("word");
64     $self->{view}->set_cursor_visible (0);
65    
66     $self->{view}->set_editable (0);
67    
68     $self->{view}->signal_connect (motion_notify_event => sub {
69     my ($widget, $event) = @_;
70    
71     my $window = $widget->get_window ("text");
72     if ($event->window == $window) {
73     my ($win, $x, $y, $mask) = $window->get_pointer;
74     # warn "TAG EVENT @_ ($window, $win, $x, $y, $mask)\n";
75     #gtk_text_view_window_to_buffer_coords (text_view,
76     # GTK_TEXT_WINDOW_TEXT,
77     # text_view->drag_start_x,
78     # text_view->drag_start_y,
79     # &buffer_x,
80     # &buffer_y);
81     #
82     # gtk_text_layout_get_iter_at_pixel (text_view->layout,
83     # &iter,
84     # buffer_x, buffer_y);
85     #
86     # gtk_text_view_start_selection_dnd (text_view, &iter, event);
87     # return TRUE;
88     }
89     0;
90     });
91    
92     $self->pack_start (($self->{entry} = new Gtk2::Entry), 0, 1, 0);
93    
94 pcg 1.2 $self->{entry}->signal_connect (activate => sub {
95 pcg 1.1 my ($entry) = @_;
96     my $text = $entry->get_text;
97     $entry->set_text("");
98    
99     my ($cmd, $arg);
100    
101     if ($text =~ /^\/(\S+)\s*(.*)$/) {
102     ($cmd, $arg) = ($1, $2);
103     } else {
104     ($cmd, $arg) = ("say", $text);
105     }
106    
107     $self->signal_emit (command => $cmd, $arg);
108     });
109    
110 pcg 1.9 #$self->{end} = $self->{buffer}->create_mark (undef, $self->{buffer}->get_end_iter, 0);#d##todo# use this one for gtk-1.050+
111 pcg 1.8 $self->{end} = $self->{buffer}->create_mark (++$USELESSNAME, $self->{buffer}->get_end_iter, 0); # workaround for gtk-perl bug
112 pcg 1.1
113     $self->set_end;
114     }
115    
116     sub do_command {
117     my ($self, $cmd, $arg, %arg) = @_;
118     }
119    
120     sub set_end {
121     my ($self) = @_;
122    
123     # this is probably also a hack...
124     $self->{idle} ||= add Glib::Idle sub {
125     $self->{view}->scroll_to_iter ($self->{buffer}->get_end_iter, 0, 0, 0, 0)
126     if $self->{view};
127     delete $self->{idle};
128     };
129     }
130    
131     sub at_end {
132     my ($self) = @_;
133    
134     # this is, maybe, a bad hack :/
135     my $adj = $self->{widget}->get_vadjustment;
136     $adj->value + $adj->page_size >= $adj->upper - 0.5;
137     }
138    
139     sub append_text {
140     my ($self, $text) = @_;
141    
142 pcg 1.2 $self->_append_text ($self->{end}, $text);
143     }
144    
145     sub _append_text {
146     my ($self, $mark, $text) = @_;
147 pcg 1.1
148 pcg 1.5 my $at_end = $self->at_end;
149    
150 pcg 1.1 $text = "<default>$text</default>";
151    
152 pcg 1.2 my @tag;
153 pcg 1.1 # pseudo-simplistic-xml-parser
154     for (;;) {
155     $text =~ /\G<([^>]+)>/gc or last;
156     my $tag = $1;
157     if ($tag =~ s/^\///) {
158     pop @tag;
159     } else {
160     push @tag, $tag;
161     }
162    
163     $text =~ /\G([^<]*)/gc or last;
164 pcg 1.2 $self->{buffer}->insert_with_tags_by_name ($self->{buffer}->get_iter_at_mark ($mark), util::xmlto $1, @tag)
165 pcg 1.1 if length $1;
166     }
167 pcg 1.5
168     $self->set_end if $at_end;
169 pcg 1.1 }
170    
171     sub set_text {
172     my ($self, $text) = @_;
173    
174     my $at_end = $self->at_end;
175    
176     $self->{buffer}->set_text ("");
177     $self->append_text ($text);
178    
179     $self->set_end if $at_end;
180     }
181    
182 pcg 1.2 sub new_eventtag {
183     my ($self, $cb) = @_;
184    
185     my $tag = new Gtk2::TextTag;
186     $tag->signal_connect (event => $cb);
187     $self->{tagtable}->add ($tag);
188    
189     $tag
190     }
191    
192     # create a new "subbuffer"
193     sub new_inlay {
194     my ($self) = @_;
195    
196     my $end = $self->{buffer}->get_end_iter;
197    
198     my $self = bless {
199     buffer => $self->{buffer},
200     parent => $self,
201     }, superchat::inlay;
202    
203     $self->{l} = $self->{buffer}->create_mark (undef, $end, 1);
204     $self->{buffer}->insert ($end, "\x{200d}");
205     $self->{r} = $self->{buffer}->create_mark (undef, $self->{buffer}->get_iter_at_mark ($self->{l}), 0);
206    
207     Scalar::Util::weaken $self->{buffer};
208     Scalar::Util::weaken $self->{parent};
209     $self;
210     }
211    
212     sub new_switchable_inlay {
213     my ($self, $header, $cb, $visible) = @_;
214    
215     my $inlay;
216    
217     my $tag = $self->new_eventtag (sub {
218     my ($tag, $view, $event, $iter) = @_;
219    
220     if ($event->type eq "button-press") {
221 pcg 1.4 $inlay->set_visible (!$inlay->{visible});
222 pcg 1.2 }
223    
224     1;
225     });
226    
227     $tag->set (background => "#e0e0ff");
228    
229     $inlay = $self->new_inlay;
230    
231 pcg 1.4 $inlay->{visible} = 0;
232 pcg 1.6 $inlay->{header} = $header;
233 pcg 1.2 $inlay->{tag} = $tag;
234     $inlay->{cb} = $cb;
235    
236 pcg 1.3 Scalar::Util::weaken $inlay->{tag};
237    
238 pcg 1.4 $inlay->set_visible ($visible);
239 pcg 1.2
240     $inlay;
241     }
242    
243     package superchat::inlay;
244    
245     sub liter { $_[0]{buffer}->get_iter_at_mark ($_[0]{l}) }
246     sub riter { $_[0]{buffer}->get_iter_at_mark ($_[0]{r}) }
247    
248     sub clear {
249     my ($self) = @_;
250     $self->{buffer}->delete ($self->liter, $self->riter);
251     }
252    
253     sub append_text {
254     my ($self, $text) = @_;
255    
256     $self->{parent}->_append_text ($self->{r}, $text);
257     }
258    
259 pcg 1.4 sub visible { $_[0]{visible} }
260     sub set_visible {
261     my ($self, $visible) = @_;
262    
263     return if $self->{visible} == $visible;
264     $self->{visible} = $visible;
265    
266     $self->refresh;
267     }
268    
269     sub refresh {
270     my ($self) = @_;
271    
272     $self->clear;
273 pcg 1.6
274 pcg 1.7 my $arrow = $self->{visible} ? "⊟" : "⊞";
275 pcg 1.6
276     $self->{buffer}->insert ($self->riter, "\n");
277     $self->{buffer}->insert_with_tags ($self->riter, util::xmlto "$arrow $self->{header}", $self->{tag});
278    
279 pcg 1.4 return unless $self->{visible};
280    
281     $self->{cb}->($self);
282     }
283    
284 pcg 1.2 sub DESTROY {
285     my ($self) = @_;
286    
287     $self->{parent}{tagtable}->remove (delete $self->{tag}) if $self->{tag};
288     }
289    
290 pcg 1.1 1;
291