ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/kgsueme/kgsueme/gtk.pl
Revision: 1.20
Committed: Tue Jun 3 15:08:41 2003 UTC (21 years ago) by pcg
Content type: text/plain
Branch: MAIN
Changes since 1.19: +1 -0 lines
Log Message:
*** empty log message ***

File Contents

# Content
1 package gtk;
2
3 use Carp;
4 use File::Temp;
5 use Gtk2;
6
7 our $text_renderer = new Gtk2::CellRendererText;
8 our $int_renderer = new Gtk2::CellRendererText;
9 $int_renderer->set (xalign => 1);
10
11 our $state = $util::state->{gtk} ||= {};
12
13 # shows the properties of a glib object
14 sub info {
15 my ($idx, $obj) = @_;
16 return if $seen{$idx}++;
17 print "\n$idx\n";
18 for ($obj->list_properties) {
19 printf "%-16s %-24s %-24s %s\n", $_->{name}, $_->{type}, (join ":", @{$_->{flags}}), $_->{descr};
20 }
21 }
22
23 my %get = (
24 window_size => sub { [ ($_[0]->allocation->values)[2,3] ] },
25 #window_pos => sub { die KGS::Listener::Debug::dumpval [ $_[0]->get_root_origin ] },
26 column_size => sub { $_[0]->get("width") || $_[0]->get("fixed_width") },
27 modelsortorder => sub { [ $_[0]->get_sort_column_id ] },
28 );
29
30 my %set = (
31 window_size => sub { $_[0]->set_default_size (@{$_[1]}) },
32 #window_pos => sub { $_[0]->set_uposition (@{$_[1]}) if @{$_[1]} },
33 column_size => sub { $_[0]->set (fixed_width => $_[1]) },
34 modelsortorder => sub { $_[0]->set_sort_column_id (@{$_[1]}) },
35 );
36
37 my %widget;
38
39 sub state {
40 my ($widget, $class, $instance, %attr) = @_;
41
42 while (my ($k, $v) = each %attr) {
43 my ($set, $get) = $k =~ /=/ ? split /=/, $k : ($k, $k);
44
45 $v = $state->{$class}{"*"}{$get}
46 if exists $state->{$class}{"*"} && exists $state->{$class}{"*"}{$get};
47
48 $v = $state->{$class}{$instance}{$get}
49 if defined $instance
50 && exists $state->{$class}{$instance} && exists $state->{$class}{$instance}{$get};
51
52 $set{$get} ? $set{$get}->($widget, $v) : $widget->set($set => $v);
53
54 my $vx = KGS::Listener::Debug::dumpval $v; $vx =~ s/\s+/ /g; warn "set $class ($instance) $set => $vx\n";#d#
55 }
56
57 #$widget->signal_connect(destroy => sub { delete $widget{$widget}; 0 });
58
59 $widget{$widget} = [$widget, $class, $instance, \%attr];
60 Scalar::Util::weaken $widget{$widget}[0];
61 }
62
63 sub save_state {
64 for (grep $_, values %widget) {
65 my ($widget, $class, $instance, $attr) = @$_;
66
67 next unless $widget; # no destroy => widget may be undef
68
69 $widget->realize if $widget->can("realize");
70
71 while (my ($k, $v) = each %$attr) {
72 my ($set, $get) = $k =~ /=/ ? split /=/, $k : ($k, $k);
73 $v = $get{$get} ? $get{$get}->($widget) : $widget->get($get);
74
75 $state->{$class}{"*"}{$get} = $v;
76 $state->{$class}{$instance}{$get} = $v if defined $instance;
77
78 my $vx = KGS::Listener::Debug::dumpval $v; $vx =~ s/\s+/ /g; warn "get $class ($instance) $get => $vx\n";#d#
79 }
80 }
81 }
82
83 # string => Gtk2::Image
84 sub image_from_data {
85 my ($data) = @_;
86 my $img;
87
88 if (defined $data) {
89 # need to write to file first :/
90 my ($fh, $filename) = File::Temp::tempfile ();
91 syswrite $fh, $data;
92 close $fh;
93 $img = new_from_file Gtk2::Image $filename;
94 unlink $filename;
95 } else {
96 $img = new_from_file Gtk2::Image "$::IMGDIR/default_userpic.png";
97 }
98
99 $img;
100 }
101
102 package gtk::widget;
103
104 # hacked gtk pseudo-widget
105
106 sub new {
107 my $class = shift;
108 bless { @_ }, $class;
109 }
110
111 sub widget { $_[0]{widget} }
112
113 sub AUTOLOAD {
114 $AUTOLOAD =~ /::([^:]+)$/ or Carp::confess "$AUTOLOAD: no such method (illegal name)";
115 ref $_[0]{widget} or Carp::confess "AUTOLOAD: non-method call $AUTOLOAD(@_)\n";
116 my $method = $_[0]{widget}->can($1)
117 or Carp::confess "$AUTOLOAD: no such method";
118 # do NOT cache.. we are fats enough this way
119 unshift @_, shift->{widget};
120 &$method;
121 }
122
123 sub destroy {
124 my ($self) = @_;
125 warn "destroy($self)";#d#
126
127 for (keys %$self) {
128 (delete $self->{$_})->destroy
129 if UNIVERSAL::can ($self->{$_}, "destroy");
130 # if (UNIVERSAL::isa ($self->{$_}, Glib::Object)
131 # && UNIVERSAL::isa ($self->{$_}, gtk::widget))
132 # && $self->{$_}->can("destroy");
133 }
134 }
135
136 sub DESTROY {
137 my ($self) = @_;
138 warn "DESTROY($self)";#d#
139 }
140
141 package gtk::text;
142
143 use base gtk::widget;
144
145 my $tagtable = new Gtk2::TextTagTable;
146
147 {
148 my %tags = (
149 default => { foreground => "black", background => "white" },
150 node => { foreground => "blue", event => 1 },
151 move => { foreground => "blue", event => 1 },
152 user => { foreground => "blue", event => 1 },
153 header => { weight => 800, pixels_above_lines => 4 },
154 description => { weight => 800, foreground => "blue" },
155 infoblock => { weight => 700, foreground => "#000080" },
156 );
157
158 while (my ($k, $v) = each %tags) {
159 my $tag = new Gtk2::TextTag $k;
160 if (delete $v->{event}) {
161 $tag->signal_connect (event => sub {
162 warn "TAG EVENT @_\n";
163 });
164 }
165 $tag->set (%$v);
166 $tagtable->add ($tag);
167 }
168 }
169
170 sub new {
171 my $class = shift;
172 my $self = $class->SUPER::new(@_);
173
174 $self->{buffer} = new Gtk2::TextBuffer $tagtable;
175
176 $self->{widget} = new Gtk2::ScrolledWindow;
177 $self->{widget}->set_policy("never", "always");
178
179 $self->{widget}->add ($self->{view} = new_with_buffer Gtk2::TextView $self->{buffer});
180 $self->{view}->set_wrap_mode ("word");
181 $self->{view}->set_cursor_visible (0);
182
183 $self->{view}->set_editable (0);
184
185 $self->set_end;
186
187 $self;
188 }
189
190 sub set_end {
191 my ($self) = @_;
192
193 # this is probably also a hack...
194 $self->{idle} ||= add Glib::Idle sub {
195 $self->{view}->scroll_to_iter ($self->{buffer}->get_end_iter, 0, 0, 0, 0)
196 if $self->{view};
197 delete $self->{idle};
198 };
199 }
200
201 sub at_end {
202 my ($self) = @_;
203
204 # this is, maybe, a bad hack :/
205 my $adj = $self->{widget}->get_vadjustment;
206 $adj->value + $adj->page_size >= $adj->upper - 0.5;
207 }
208
209 sub append_text {
210 my ($self, $text) = @_;
211
212 my $at_end = $self->at_end;
213
214 my @tag;
215 $text = "<default>$text</default>";
216
217 # pseudo-simplistic-xml-parser
218 for (;;) {
219 $text =~ /\G<([^>]+)>/gc or last;
220 my $tag = $1;
221 if ($tag =~ s/^\///) {
222 pop @tag;
223 } else {
224 push @tag, $tag;
225 }
226
227 $text =~ /\G([^<]*)/gc or last;
228 $self->{buffer}->insert_with_tags_by_name ($self->{buffer}->get_end_iter, util::xmlto $1, $tag[-1])
229 if length $1;
230 }
231
232 $self->set_end if $at_end;
233 }
234
235 sub set_text {
236 my ($self, $text) = @_;
237
238 my $at_end = $self->at_end;
239
240 $self->{buffer}->set_text ("");
241 $self->append_text ($text);
242
243 $self->set_end if $at_end;
244 }
245
246 1;
247