… | |
… | |
12 | return_type => undef, # void return |
12 | return_type => undef, # void return |
13 | param_types => [Glib::Scalar, Glib::Scalar], |
13 | param_types => [Glib::Scalar, Glib::Scalar], |
14 | }, |
14 | }, |
15 | }; |
15 | }; |
16 | |
16 | |
17 | my $tagtable = new Gtk2::TextTagTable; |
|
|
18 | |
|
|
19 | { |
|
|
20 | my %tags = ( |
|
|
21 | default => { foreground => "black" }, |
|
|
22 | node => { foreground => "#0000b0", event => 1 }, |
|
|
23 | move => { foreground => "#0000b0", event => 1 }, |
|
|
24 | user => { foreground => "#0000b0", event => 1 }, |
|
|
25 | coord => { foreground => "#0000b0", event => 1 }, |
|
|
26 | error => { foreground => "#ff0000", event => 1 }, |
|
|
27 | header => { weight => 800, pixels_above_lines => 6 }, |
|
|
28 | description => { weight => 800, foreground => "blue" }, |
|
|
29 | infoblock => { weight => 700, foreground => "blue" }, |
|
|
30 | ); |
|
|
31 | |
|
|
32 | while (my ($k, $v) = each %tags) { |
|
|
33 | my $tag = new Gtk2::TextTag $k; |
|
|
34 | if (delete $v->{event}) { |
|
|
35 | ### |
|
|
36 | } |
|
|
37 | $tag->set (%$v); |
|
|
38 | $tagtable->add ($tag); |
|
|
39 | } |
|
|
40 | } |
|
|
41 | |
|
|
42 | sub INIT_INSTANCE { |
17 | sub INIT_INSTANCE { |
43 | my $self = shift; |
18 | my $self = shift; |
|
|
19 | |
|
|
20 | my $tagtable = new Gtk2::TextTagTable; |
|
|
21 | |
|
|
22 | { |
|
|
23 | my @tags = ( |
|
|
24 | [default => { foreground => "black" }], |
|
|
25 | [node => { foreground => "#0000b0", event => 1 }], |
|
|
26 | [move => { foreground => "#0000b0", event => 1 }], |
|
|
27 | [user => { foreground => "#0000b0", event => 1 }], |
|
|
28 | [coord => { foreground => "#0000b0", event => 1 }], |
|
|
29 | [error => { foreground => "#ff0000", event => 1 }], |
|
|
30 | [header => { weight => 800, pixels_above_lines => 6 }], |
|
|
31 | [challenge => { weight => 800, pixels_above_lines => 6, background => "#ffffb0" }], |
|
|
32 | [description => { weight => 800, foreground => "blue" }], |
|
|
33 | [infoblock => { weight => 700, foreground => "blue" }], |
|
|
34 | ); |
|
|
35 | |
|
|
36 | for (@tags) { |
|
|
37 | my ($k, $v) = @$_; |
|
|
38 | my $tag = new Gtk2::TextTag $k; |
|
|
39 | if (delete $v->{event}) { |
|
|
40 | ### |
|
|
41 | } |
|
|
42 | $tag->set (%$v); |
|
|
43 | $tagtable->add ($tag); |
|
|
44 | } |
|
|
45 | } |
|
|
46 | |
|
|
47 | $self->{tagtable} = $tagtable; |
44 | |
48 | |
45 | $self->signal_connect (destroy => sub { |
49 | $self->signal_connect (destroy => sub { |
46 | remove Glib::Source delete $self->{idle} if $self->{idle}; |
50 | remove Glib::Source delete $self->{idle} if $self->{idle}; |
47 | %{$_[0]} = (); |
51 | %{$_[0]} = (); |
48 | }); |
52 | }); |
49 | |
53 | |
50 | $self->{buffer} = new Gtk2::TextBuffer $tagtable; |
54 | $self->{buffer} = new Gtk2::TextBuffer $self->{tagtable}; |
51 | |
55 | |
52 | $self->{widget} = new Gtk2::ScrolledWindow; |
56 | $self->{widget} = new Gtk2::ScrolledWindow; |
53 | $self->{widget}->set_policy("never", "always"); |
57 | $self->{widget}->set_policy("never", "always"); |
54 | $self->pack_start ($self->{widget}, 1, 1, 0); |
58 | $self->pack_start ($self->{widget}, 1, 1, 0); |
55 | |
59 | |
… | |
… | |
83 | 0; |
87 | 0; |
84 | }); |
88 | }); |
85 | |
89 | |
86 | $self->pack_start (($self->{entry} = new Gtk2::Entry), 0, 1, 0); |
90 | $self->pack_start (($self->{entry} = new Gtk2::Entry), 0, 1, 0); |
87 | |
91 | |
88 | $self->{entry}->signal_connect(activate => sub { |
92 | $self->{entry}->signal_connect (activate => sub { |
89 | my ($entry) = @_; |
93 | my ($entry) = @_; |
90 | my $text = $entry->get_text; |
94 | my $text = $entry->get_text; |
91 | $entry->set_text(""); |
95 | $entry->set_text(""); |
92 | |
96 | |
93 | my ($cmd, $arg); |
97 | my ($cmd, $arg); |
… | |
… | |
99 | } |
103 | } |
100 | |
104 | |
101 | $self->signal_emit (command => $cmd, $arg); |
105 | $self->signal_emit (command => $cmd, $arg); |
102 | }); |
106 | }); |
103 | |
107 | |
|
|
108 | $self->{end} = $self->{buffer}->create_mark (undef, $self->{buffer}->get_end_iter, 0); |
104 | |
109 | |
105 | $self->set_end; |
110 | $self->set_end; |
106 | } |
111 | } |
107 | |
112 | |
108 | sub do_command { |
113 | sub do_command { |
… | |
… | |
130 | |
135 | |
131 | sub append_text { |
136 | sub append_text { |
132 | my ($self, $text) = @_; |
137 | my ($self, $text) = @_; |
133 | |
138 | |
134 | my $at_end = $self->at_end; |
139 | my $at_end = $self->at_end; |
|
|
140 | $self->_append_text ($self->{end}, $text); |
|
|
141 | $self->set_end if $at_end; |
|
|
142 | } |
|
|
143 | |
|
|
144 | sub _append_text { |
|
|
145 | my ($self, $mark, $text) = @_; |
|
|
146 | |
|
|
147 | $text = "<default>$text</default>"; |
135 | |
148 | |
136 | my @tag; |
149 | my @tag; |
137 | $text = "<default>$text</default>"; |
|
|
138 | |
|
|
139 | # pseudo-simplistic-xml-parser |
150 | # pseudo-simplistic-xml-parser |
140 | for (;;) { |
151 | for (;;) { |
141 | $text =~ /\G<([^>]+)>/gc or last; |
152 | $text =~ /\G<([^>]+)>/gc or last; |
142 | my $tag = $1; |
153 | my $tag = $1; |
143 | if ($tag =~ s/^\///) { |
154 | if ($tag =~ s/^\///) { |
… | |
… | |
145 | } else { |
156 | } else { |
146 | push @tag, $tag; |
157 | push @tag, $tag; |
147 | } |
158 | } |
148 | |
159 | |
149 | $text =~ /\G([^<]*)/gc or last; |
160 | $text =~ /\G([^<]*)/gc or last; |
150 | $self->{buffer}->insert_with_tags_by_name ($self->{buffer}->get_end_iter, util::xmlto $1, $tag[-1]) |
161 | $self->{buffer}->insert_with_tags_by_name ($self->{buffer}->get_iter_at_mark ($mark), util::xmlto $1, @tag) |
151 | if length $1; |
162 | if length $1; |
152 | } |
163 | } |
153 | |
|
|
154 | $self->set_end if $at_end; |
|
|
155 | } |
164 | } |
156 | |
165 | |
157 | sub set_text { |
166 | sub set_text { |
158 | my ($self, $text) = @_; |
167 | my ($self, $text) = @_; |
159 | |
168 | |
… | |
… | |
163 | $self->append_text ($text); |
172 | $self->append_text ($text); |
164 | |
173 | |
165 | $self->set_end if $at_end; |
174 | $self->set_end if $at_end; |
166 | } |
175 | } |
167 | |
176 | |
|
|
177 | sub new_eventtag { |
|
|
178 | my ($self, $cb) = @_; |
|
|
179 | |
|
|
180 | my $tag = new Gtk2::TextTag; |
|
|
181 | $tag->signal_connect (event => $cb); |
|
|
182 | $self->{tagtable}->add ($tag); |
|
|
183 | |
|
|
184 | $tag |
|
|
185 | } |
|
|
186 | |
|
|
187 | # create a new "subbuffer" |
|
|
188 | sub new_inlay { |
|
|
189 | my ($self) = @_; |
|
|
190 | |
|
|
191 | my $end = $self->{buffer}->get_end_iter; |
|
|
192 | |
|
|
193 | my $self = bless { |
|
|
194 | buffer => $self->{buffer}, |
|
|
195 | parent => $self, |
|
|
196 | }, superchat::inlay; |
|
|
197 | |
|
|
198 | $self->{l} = $self->{buffer}->create_mark (undef, $end, 1); |
|
|
199 | $self->{buffer}->insert ($end, "\x{200d}"); |
|
|
200 | $self->{r} = $self->{buffer}->create_mark (undef, $self->{buffer}->get_iter_at_mark ($self->{l}), 0); |
|
|
201 | |
|
|
202 | Scalar::Util::weaken $self->{buffer}; |
|
|
203 | Scalar::Util::weaken $self->{parent}; |
|
|
204 | $self; |
|
|
205 | } |
|
|
206 | |
|
|
207 | sub new_switchable_inlay { |
|
|
208 | my ($self, $header, $cb, $visible) = @_; |
|
|
209 | |
|
|
210 | my $inlay; |
|
|
211 | |
|
|
212 | my $setvisible = sub { |
|
|
213 | if ($inlay->{visible}) { |
|
|
214 | $inlay->{cb}->($inlay); |
|
|
215 | } else { |
|
|
216 | $inlay->clear; |
|
|
217 | } |
|
|
218 | }; |
|
|
219 | |
|
|
220 | my $tag = $self->new_eventtag (sub { |
|
|
221 | my ($tag, $view, $event, $iter) = @_; |
|
|
222 | |
|
|
223 | if ($event->type eq "button-press") { |
|
|
224 | $inlay->{visible} = !$inlay->{visible}; |
|
|
225 | $setvisible->(); |
|
|
226 | } |
|
|
227 | |
|
|
228 | 1; |
|
|
229 | }); |
|
|
230 | |
|
|
231 | $tag->set (background => "#e0e0ff"); |
|
|
232 | |
|
|
233 | $self->{buffer}->insert ($self->{buffer}->get_end_iter, "\n"); |
|
|
234 | $self->{buffer}->insert_with_tags ($self->{buffer}->get_end_iter, util::xmlto "$header \x{21f3}", $tag); |
|
|
235 | |
|
|
236 | $inlay = $self->new_inlay; |
|
|
237 | |
|
|
238 | $inlay->{visible} = $visible; |
|
|
239 | $inlay->{tag} = $tag; |
|
|
240 | $inlay->{cb} = $cb; |
|
|
241 | |
|
|
242 | $setvisible->(); |
|
|
243 | |
|
|
244 | $inlay; |
|
|
245 | } |
|
|
246 | |
|
|
247 | package superchat::inlay; |
|
|
248 | |
|
|
249 | sub liter { $_[0]{buffer}->get_iter_at_mark ($_[0]{l}) } |
|
|
250 | sub riter { $_[0]{buffer}->get_iter_at_mark ($_[0]{r}) } |
|
|
251 | |
|
|
252 | sub clear { |
|
|
253 | my ($self) = @_; |
|
|
254 | $self->{buffer}->delete ($self->liter, $self->riter); |
|
|
255 | } |
|
|
256 | |
|
|
257 | sub append_text { |
|
|
258 | my ($self, $text) = @_; |
|
|
259 | |
|
|
260 | $self->{parent}->_append_text ($self->{r}, $text); |
|
|
261 | } |
|
|
262 | |
|
|
263 | sub DESTROY { |
|
|
264 | my ($self) = @_; |
|
|
265 | |
|
|
266 | $self->{parent}{tagtable}->remove (delete $self->{tag}) if $self->{tag}; |
|
|
267 | } |
|
|
268 | |
168 | 1; |
269 | 1; |
169 | |
270 | |