ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/kgsueme/kgsueme/gtk.pl
Revision: 1.26
Committed: Sat Jun 28 04:26:15 2003 UTC (20 years, 11 months ago) by pcg
Content type: text/plain
Branch: MAIN
Changes since 1.25: +3 -3 lines
Log Message:
*** empty log message ***

File Contents

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