ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/Deliantra-Client/DC/UI.pm
(Generate patch)

Comparing deliantra/Deliantra-Client/DC/UI.pm (file contents):
Revision 1.251 by root, Sun May 28 22:24:24 2006 UTC vs.
Revision 1.269 by root, Fri Jun 2 06:22:55 2006 UTC

17our $BUTTON_STATE; 17our $BUTTON_STATE;
18 18
19our %WIDGET; # all widgets, weak-referenced 19our %WIDGET; # all widgets, weak-referenced
20 20
21sub get_layout { 21sub get_layout {
22 my $layout;
23
22 for (grep { $_->{name} } values %WIDGET) { 24 for (grep { $_->{name} } values %WIDGET) {
23 $LAYOUT->{$_->{name}} = { 25 my $win = $layout->{$_->{name}} = { };
24 x => $_->{x} / $::WIDTH,
25 y => $_->{y} / $::HEIGHT,
26 w => $_->{w} / $::WIDTH,
27 h => $_->{h} / $::HEIGHT
28 }; 26
29 } 27 $win->{x} = ($_->{x} + $_->{w} * 0.5) / $::WIDTH if $_->{x} =~ /^[0-9.]+$/;
28 $win->{y} = ($_->{y} + $_->{h} * 0.5) / $::HEIGHT if $_->{y} =~ /^[0-9.]+$/;
29 $win->{w} = $_->{w} / $::WIDTH if defined $_->{w};
30 $win->{h} = $_->{h} / $::HEIGHT if defined $_->{h};
30 31
31 return $LAYOUT; 32 $win->{show} = $_->{visible} && $_->{is_toplevel};
33 }
34
35 $layout
32} 36}
33 37
34sub set_layout { 38sub set_layout {
35 my ($layout) = @_; 39 my ($layout) = @_;
40
36 $LAYOUT = $layout; 41 $LAYOUT = $layout;
37} 42}
38 43
39sub check_tooltip { 44sub check_tooltip {
45 return if $ENV{CFPLUS_DEBUG} & 8;
46
40 if (!$GRAB) { 47 if (!$GRAB) {
41 for (my $widget = $HOVER; $widget; $widget = $widget->{parent}) { 48 for (my $widget = $HOVER; $widget; $widget = $widget->{parent}) {
42 if (length $widget->{tooltip}) { 49 if (length $widget->{tooltip}) {
43
44 if ($TOOLTIP->{owner} != $widget) { 50 if ($TOOLTIP->{owner} != $widget) {
51 $TOOLTIP->hide;
52
45 $TOOLTIP->{owner} = $widget; 53 $TOOLTIP->{owner} = $widget;
46 54
47 my $tip = $widget->{tooltip}; 55 my $tip = $widget->{tooltip};
48 56
49 $tip = $tip->($widget) if CODE:: eq ref $tip; 57 $tip = $tip->($widget) if CODE:: eq ref $tip;
50 58
51 $TOOLTIP->set_tooltip_from ($widget); 59 $TOOLTIP->set_tooltip_from ($widget);
52 $TOOLTIP->show; 60 $TOOLTIP->show;
53
54 my ($x, $y) = $widget->coord2global ($widget->{w}, 0);
55
56 ($x, $y) = $widget->coord2global (-$TOOLTIP->{w}, 0)
57 if $x + $TOOLTIP->{w} > $::WIDTH;
58
59 $TOOLTIP->move ($x, $y);
60 $TOOLTIP->realloc;
61 } 61 }
62 62
63 return; 63 return;
64 } 64 }
65 } 65 }
171sub rescale_widgets { 171sub rescale_widgets {
172 my ($sx, $sy) = @_; 172 my ($sx, $sy) = @_;
173 173
174 for my $widget (values %WIDGET) { 174 for my $widget (values %WIDGET) {
175 if ($widget->{is_toplevel}) { 175 if ($widget->{is_toplevel}) {
176 $widget->{x} += int $widget->{w} * 0.5 if $widget->{x} =~ /^[0-9.]+$/;
177 $widget->{y} += int $widget->{h} * 0.5 if $widget->{y} =~ /^[0-9.]+$/;
178
176 $widget->{x} = int 0.5 + $widget->{x} * $sx if exists $widget->{x}; 179 $widget->{x} = int 0.5 + $widget->{x} * $sx if $widget->{x} =~ /^[0-9.]+$/;
177 $widget->{w} = int 0.5 + $widget->{w} * $sx if exists $widget->{w}; 180 $widget->{w} = int 0.5 + $widget->{w} * $sx if exists $widget->{w};
178 $widget->{req_w} = int 0.5 + $widget->{req_w} * $sx if exists $widget->{req_w}; 181 $widget->{force_w} = int 0.5 + $widget->{force_w} * $sx if exists $widget->{force_w};
179 $widget->{y} = int 0.5 + $widget->{y} * $sy if exists $widget->{y}; 182 $widget->{y} = int 0.5 + $widget->{y} * $sy if $widget->{y} =~ /^[0-9.]+$/;
180 $widget->{h} = int 0.5 + $widget->{h} * $sy if exists $widget->{h}; 183 $widget->{h} = int 0.5 + $widget->{h} * $sy if exists $widget->{h};
181 $widget->{req_h} = int 0.5 + $widget->{req_h} * $sy if exists $widget->{req_h}; 184 $widget->{force_h} = int 0.5 + $widget->{force_h} * $sy if exists $widget->{force_h};
185
186 $widget->{x} -= int $widget->{w} * 0.5 if $widget->{x} =~ /^[0-9.]+$/;
187 $widget->{y} -= int $widget->{h} * 0.5 if $widget->{y} =~ /^[0-9.]+$/;
188
182 } 189 }
183 } 190 }
184 191
185 reconfigure_widgets; 192 reconfigure_widgets;
186} 193}
195 202
196sub new { 203sub new {
197 my $class = shift; 204 my $class = shift;
198 205
199 my $self = bless { 206 my $self = bless {
200 x => 0, 207 x => "center",
201 y => 0, 208 y => "center",
202 z => 0, 209 z => 0,
210 w => undef,
211 h => undef,
203 can_events => 1, 212 can_events => 1,
204 @_ 213 @_
205 }, $class; 214 }, $class;
215
216 Scalar::Util::weaken ($CFClient::UI::WIDGET{$self+0} = $self);
206 217
207 for (keys %$self) { 218 for (keys %$self) {
208 if (/^on_(.*)$/) { 219 if (/^on_(.*)$/) {
209 $self->connect ($1 => delete $self->{$_}); 220 $self->connect ($1 => delete $self->{$_});
210 } 221 }
211 } 222 }
212 223
213 Scalar::Util::weaken ($CFClient::UI::WIDGET{$self+0} = $self);
214
215 if (my $layout = $CFClient::UI::LAYOUT->{$self->{name}}) { 224 if (my $layout = $CFClient::UI::LAYOUT->{$self->{name}}) {
216 $self->{req_x} = $layout->{x} * $::WIDTH; 225 $self->{x} = $layout->{x} * $CFClient::UI::ROOT->{alloc_w} if exists $layout->{x};
217 $self->{req_y} = $layout->{y} * $::HEIGHT; 226 $self->{y} = $layout->{y} * $CFClient::UI::ROOT->{alloc_h} if exists $layout->{y};
218 $self->{def_w} = ($layout->{w} != 0 ? $layout->{w} : 1) * $::WIDTH; 227 $self->{force_w} = $layout->{w} * $CFClient::UI::ROOT->{alloc_w} if exists $layout->{w};
219 $self->{def_h} = ($layout->{h} != 0 ? $layout->{h} : 1) * $::HEIGHT; 228 $self->{force_h} = $layout->{h} * $CFClient::UI::ROOT->{alloc_h} if exists $layout->{h};
229
230 $self->{x} -= $self->{force_w} * 0.5 if exists $layout->{x};
231 $self->{y} -= $self->{force_h} * 0.5 if exists $layout->{y};
232
233 $self->show if $layout->{show};
220 } 234 }
221 235
222 $self 236 $self
223} 237}
224 238
235 return if $self->{parent}; 249 return if $self->{parent};
236 250
237 $CFClient::UI::ROOT->add ($self); 251 $CFClient::UI::ROOT->add ($self);
238} 252}
239 253
240sub center {
241 my ($self) = @_;
242
243 $CFClient::UI::ROOT->on_post_alloc (
244 "center_$self" => sub {
245 $self->move (($self->{parent}{w} - $self->{w}) * 0.5, ($self->{parent}{h} - $self->{h}) * 0.5);
246 },
247 );
248
249 $self->update;
250}
251
252sub set_visible { 254sub set_visible {
253 my ($self) = @_; 255 my ($self) = @_;
254 256
255 return if $self->{visible}; 257 return if $self->{visible};
256 258
257 $self->{root} = $self->{parent}{root}; 259 $self->{root} = $self->{parent}{root};
258 $self->{visible} = $self->{parent}{visible} + 1; 260 $self->{visible} = $self->{parent}{visible} + 1;
259 261
260 $self->emit (visibility_change => 1); 262 $self->emit (visibility_change => 1);
261 263
262 $self->realloc unless exists $self->{req_w}; 264 $self->realloc if !exists $self->{req_w};
263 265
264 $_->set_visible for $self->children; 266 $_->set_visible for $self->children;
265} 267}
266 268
267sub set_invisible { 269sub set_invisible {
309 311
310 $self->{parent}->remove ($self) 312 $self->{parent}->remove ($self)
311 if $self->{parent}; 313 if $self->{parent};
312} 314}
313 315
314sub move { 316sub move_abs {
315 my ($self, $x, $y, $z) = @_; 317 my ($self, $x, $y, $z) = @_;
316 318
317 $self->{x} = int $x; 319 $self->{x} = List::Util::max 0, int $x;
318 $self->{y} = int $y; 320 $self->{y} = List::Util::max 0, int $y;
319 $self->{z} = $z if defined $z; 321 $self->{z} = $z if defined $z;
320 322
321 $self->update; 323 $self->update;
322} 324}
323 325
324sub set_size { 326sub set_size {
325 my ($self, $w, $h) = @_; 327 my ($self, $w, $h) = @_;
326 328
327 $self->{def_w} = $w; 329 $self->{force_w} = $w;
328 $self->{def_h} = $h; 330 $self->{force_h} = $h;
329 331
330 $self->realloc; 332 $self->realloc;
331} 333}
332 334
333sub size_request { 335sub size_request {
337 339
338sub configure { 340sub configure {
339 my ($self, $x, $y, $w, $h) = @_; 341 my ($self, $x, $y, $w, $h) = @_;
340 342
341 if ($self->{aspect}) { 343 if ($self->{aspect}) {
344 my ($ow, $oh) = ($w, $h);
345
342 my $w2 = List::Util::min $w, int $h * $self->{aspect}; 346 $w = List::Util::min $w, int $h * $self->{aspect};
343 my $h2 = List::Util::min $h, int $w / $self->{aspect}; 347 $h = List::Util::min $h, int $w / $self->{aspect};
344 348
345 # use alignment to adjust x, y 349 # use alignment to adjust x, y
346 350
347 $x += int +($w - $w2) * 0.5; 351 $x += int 0.5 * ($ow - $w);
348 $y += int +($h - $h2) * 0.5; 352 $y += int 0.5 * ($oh - $h);
349
350 ($w, $h) = ($w2, $h2);
351 } 353 }
352 354
353 if ($self->{x} != $x || $self->{y} != $y) { 355 if ($self->{x} ne $x || $self->{y} ne $y) {
354 $self->{x} = $x; 356 $self->{x} = $x;
355 $self->{y} = $y; 357 $self->{y} = $y;
356 $self->update; 358 $self->update;
357 } 359 }
358 360
359 if ($self->{w} != $w || $self->{h} != $h) { 361 if ($self->{alloc_w} != $w || $self->{alloc_h} != $h) {
360 return unless $self->{visible}; 362 return unless $self->{visible};
361 363
364 $self->{alloc_w} = $w;
365 $self->{alloc_h} = $h;
366
362 $self->{root}->{size_alloc}{$self+0} = [$self, $w, $h]; 367 $self->{root}{size_alloc}{$self+0} = $self;
363 } 368 }
364} 369}
365 370
366sub size_allocate { 371sub size_allocate {
367 # nothing to be done 372 # nothing to be done
445 my ($self, $ev, $x, $y) = @_; 450 my ($self, $ev, $x, $y) = @_;
446 451
447 $self->focus_in; 452 $self->focus_in;
448} 453}
449 454
450sub w { $_[0]{w} = $_[1] if @_ > 1; $_[0]{w} }
451sub h { $_[0]{h} = $_[1] if @_ > 1; $_[0]{h} }
452sub x { $_[0]{x} = $_[1] if @_ > 1; $_[0]{x} }
453sub y { $_[0]{y} = $_[1] if @_ > 1; $_[0]{y} }
454sub z { $_[0]{z} = $_[1] if @_ > 1; $_[0]{z} }
455
456sub find_widget { 455sub find_widget {
457 my ($self, $x, $y) = @_; 456 my ($self, $x, $y) = @_;
458 457
459 return () unless $self->{can_events}; 458 return () unless $self->{can_events};
460 459
467 466
468sub set_parent { 467sub set_parent {
469 my ($self, $parent) = @_; 468 my ($self, $parent) = @_;
470 469
471 Scalar::Util::weaken ($self->{parent} = $parent); 470 Scalar::Util::weaken ($self->{parent} = $parent);
472
473 $self->set_visible if $parent->{visible}; 471 $self->set_visible if $parent->{visible};
474
475 $self->realloc;
476} 472}
477 473
478sub connect { 474sub connect {
479 my ($self, $signal, $cb) = @_; 475 my ($self, $signal, $cb) = @_;
480 476
499} 495}
500 496
501sub realloc { 497sub realloc {
502 my ($self) = @_; 498 my ($self) = @_;
503 499
504 return unless $self->{visible}; 500 if ($self->{visible}) {
505
506 return if $self->{root}{realloc}{$self}; 501 return if $self->{root}{realloc}{$self+0};
507 502
508 $self->{root}{realloc}{$self} = $self; 503 $self->{root}{realloc}{$self+0} = $self;
509 $self->{root}->update; 504 $self->{root}->update;
505 } else {
506 delete $self->{req_w};
507 delete $self->{req_h};
508 }
510} 509}
511 510
512sub update { 511sub update {
513 my ($self) = @_; 512 my ($self) = @_;
514 513
515 $self->{parent}->update 514 $self->{parent}->update
516 if $self->{parent}; 515 if $self->{parent};
517} 516}
518 517
518sub reconfigure {
519 my ($self) = @_;
520
521 $self->realloc;
522 $self->update;
523}
524
525# using global variables seems a bit hacky, but passing through all drawing
526# functions seems pointless.
527our ($draw_x, $draw_y, $draw_w, $draw_h); # screen rectangle being drawn
528
519sub draw { 529sub draw {
520 my ($self) = @_; 530 my ($self) = @_;
521 531
522 return unless $self->{h} && $self->{w}; 532 return unless $self->{h} && $self->{w};
533
534 # update screen rectangle
535 local $draw_x = $draw_x + $self->{x};
536 local $draw_y = $draw_y + $self->{y};
537 local $draw_w = $draw_x + $self->{w};
538 local $draw_h = $draw_y + $self->{h};
539
540 # skip widgets that are entirely outside the drawing area
541 return if ($draw_x + $self->{w} < 0) || ($draw_x >= $draw_w)
542 || ($draw_y + $self->{h} < 0) || ($draw_y >= $draw_h);
523 543
524 glPushMatrix; 544 glPushMatrix;
525 glTranslate $self->{x}, $self->{y}, 0; 545 glTranslate $self->{x}, $self->{y}, 0;
526 $self->_draw; 546 $self->_draw;
527 glPopMatrix; 547 glPopMatrix;
539 glVertex $x , $y + $self->{h}; 559 glVertex $x , $y + $self->{h};
540 glEnd; 560 glEnd;
541 glDisable GL_BLEND; 561 glDisable GL_BLEND;
542 } 562 }
543 563
544 if ($ENV{PCLIENT_DEBUG}) { 564 if ($ENV{CFPLUS_DEBUG} & 1) {
545 glPushMatrix; 565 glPushMatrix;
546 glColor 1, 1, 0, 1; 566 glColor 1, 1, 0, 1;
547 glTranslate $self->{x} + 0.375, $self->{y} + 0.375; 567 glTranslate $self->{x} + 0.375, $self->{y} + 0.375;
548 glBegin GL_LINE_LOOP; 568 glBegin GL_LINE_LOOP;
549 glVertex 0 , 0; 569 glVertex 0 , 0;
625 my ($class, %arg) = @_; 645 my ($class, %arg) = @_;
626 $class->SUPER::new (can_events => 0, %arg); 646 $class->SUPER::new (can_events => 0, %arg);
627} 647}
628 648
629sub size_request { 649sub size_request {
630 (0, 0) 650 my ($self) = @_;
651
652 ($self->{w} + 0, $self->{h} + 0)
631} 653}
632 654
633sub draw { } 655sub draw { }
634 656
635############################################################################# 657#############################################################################
756sub size_request { 778sub size_request {
757 $_[0]{children}[0]->size_request 779 $_[0]{children}[0]->size_request
758} 780}
759 781
760sub size_allocate { 782sub size_allocate {
761 my ($self, $w, $h, $changed) = @_; 783 my ($self, $w, $h) = @_;
762 784
763 $self->{children}[0]->configure (0, 0, $w, $h); 785 $self->{children}[0]->configure (0, 0, $w, $h);
764} 786}
765 787
766############################################################################# 788#############################################################################
783 $ROOT->on_post_alloc ($self => sub { $self->render_child }); 805 $ROOT->on_post_alloc ($self => sub { $self->render_child });
784 $self->SUPER::update; 806 $self->SUPER::update;
785} 807}
786 808
787sub size_allocate { 809sub size_allocate {
788 my ($self, $w, $h, $changed) = @_; 810 my ($self, $w, $h) = @_;
789 811
790 $self->SUPER::size_allocate ($w, $h, $changed); 812 $self->SUPER::size_allocate ($w, $h);
791 $self->update 813 $self->update;
792 if $changed;
793} 814}
794 815
795sub _render { 816sub _render {
817 my ($self) = @_;
818
796 $_[0]{children}[0]->draw; 819 $self->{children}[0]->draw;
797} 820}
798 821
799sub render_child { 822sub render_child {
800 my ($self) = @_; 823 my ($self) = @_;
801 824
802 $self->{texture} = new_from_opengl CFClient::Texture $self->{w}, $self->{h}, sub { 825 $self->{texture} = new_from_opengl CFClient::Texture $self->{w}, $self->{h}, sub {
803 glClearColor 0, 0, 0, 0; 826 glClearColor 0, 0, 0, 0;
804 glClear GL_COLOR_BUFFER_BIT; 827 glClear GL_COLOR_BUFFER_BIT;
805 828
829 {
830 package CFClient::UI::Base;
831
832 ($draw_x, $draw_y, $draw_w, $draw_h) =
833 (0, 0, $self->{w}, $self->{h});
834 }
835
806 $self->_render; 836 $self->_render;
807 }; 837 };
808} 838}
809 839
810sub _draw { 840sub _draw {
811 my ($self) = @_; 841 my ($self) = @_;
812 842
813 my ($w, $h) = ($self->w, $self->h); 843 my ($w, $h) = @$self{qw(w h)};
814 844
815 my $tex = $self->{texture} 845 my $tex = $self->{texture}
816 or return; 846 or return;
817 847
818 glEnable GL_TEXTURE_2D; 848 glEnable GL_TEXTURE_2D;
841} 871}
842 872
843sub size_request { 873sub size_request {
844 my ($self) = @_; 874 my ($self) = @_;
845 875
846 my ($w, $h) = @$self{qw(child_w child_h)} = @{$self->child}{qw(req_w req_h)}; 876 my ($w, $h) = @{$self->child}{qw(req_w req_h)};
847 877
848 $w = 10 if $self->{scroll_x}; 878 $w = 10 if $self->{scroll_x};
849 $h = 10 if $self->{scroll_y}; 879 $h = 10 if $self->{scroll_y};
850 880
851 ($w, $h) 881 ($w, $h)
852} 882}
853 883
854sub size_allocate { 884sub size_allocate {
855 my ($self, $w, $h, $changed) = @_; 885 my ($self, $w, $h) = @_;
856 886
887 my $child = $self->child;
888
857 $w = $self->{child_w} if $self->{scroll_x} && $self->{child_w}; 889 $w = $child->{req_w} if $self->{scroll_x} && $child->{req_w};
858 $h = $self->{child_h} if $self->{scroll_y} && $self->{child_h}; 890 $h = $child->{req_h} if $self->{scroll_y} && $child->{req_h};
859 891
860 $self->child->configure (0, 0, $w, $h); 892 $self->child->configure (0, 0, $w, $h);
861 $self->update; 893 $self->update;
862} 894}
863 895
898 } 930 }
899} 931}
900 932
901sub _render { 933sub _render {
902 my ($self) = @_; 934 my ($self) = @_;
935
936 local $CFClient::UI::Base::draw_x = $CFClient::UI::Base::draw_x - $self->{view_x};
937 local $CFClient::UI::Base::draw_y = $CFClient::UI::Base::draw_y - $self->{view_y};
903 938
904 CFClient::OpenGL::glTranslate -$self->{view_x}, -$self->{view_y}; 939 CFClient::OpenGL::glTranslate -$self->{view_x}, -$self->{view_y};
905 940
906 $self->SUPER::_render; 941 $self->SUPER::_render;
907} 942}
947 my $child = $self->{vp}->child; 982 my $child = $self->{vp}->child;
948 $self->{slider}->set_range ([$self->{slider}{range}[0], 0, $child->{h}, $self->{vp}{h}, 1]); 983 $self->{slider}->set_range ([$self->{slider}{range}[0], 0, $child->{h}, $self->{vp}{h}, 1]);
949} 984}
950 985
951sub size_allocate { 986sub size_allocate {
952 my ($self, $w, $h, $changed) = @_; 987 my ($self, $w, $h) = @_;
953 988
954 $self->SUPER::size_allocate ($w, $h, $changed); 989 $self->SUPER::size_allocate ($w, $h);
955 990
956 my $child = $self->{vp}->child; 991 my $child = $self->{vp}->child;
957 $self->{slider}->set_range ([$self->{slider}{range}[0], 0, $child->{h}, $self->{vp}{h}, 1]); 992 $self->{slider}->set_range ([$self->{slider}{range}[0], 0, $child->{h}, $self->{vp}{h}, 1]);
958} 993}
959 994
1006 1041
1007our @ISA = CFClient::UI::Bin::; 1042our @ISA = CFClient::UI::Bin::;
1008 1043
1009use CFClient::OpenGL; 1044use CFClient::OpenGL;
1010 1045
1011my @tex = 1046my $bg =
1047 new_from_file CFClient::Texture CFClient::find_rcfile "d1_bg.png",
1048 mipmap => 1, wrap => 1;
1049
1050my @border =
1012 map { new_from_file CFClient::Texture CFClient::find_rcfile $_, mipmap => 1 } 1051 map { new_from_file CFClient::Texture CFClient::find_rcfile $_, mipmap => 1 }
1013 qw(d1_bg.png d1_border_top.png d1_border_right.png d1_border_left.png d1_border_bottom.png); 1052 qw(d1_border_top.png d1_border_right.png d1_border_left.png d1_border_bottom.png);
1014 1053
1015sub new { 1054sub new {
1016 my $class = shift; 1055 my ($class, %arg) = @_;
1056
1057 my $title = delete $arg{title};
1017 1058
1018 my $self = $class->SUPER::new ( 1059 my $self = $class->SUPER::new (
1019 bg => [1, 1, 1, 1], 1060 bg => [1, 1, 1, 1],
1020 border_bg => [1, 1, 1, 1], 1061 border_bg => [1, 1, 1, 1],
1021 border => 0.6, 1062 border => 0.6,
1022 is_toplevel => 1,
1023 can_events => 1, 1063 can_events => 1,
1024 @_ 1064 min_w => 16,
1065 min_h => 16,
1066 %arg,
1025 ); 1067 );
1026 1068
1027 $self->{title} &&= new CFClient::UI::Label 1069 $self->{title} = new CFClient::UI::Label
1028 align => 0, 1070 align => 0,
1029 valign => 1, 1071 valign => 1,
1030 text => $self->{title}, 1072 text => $title,
1031 fontsize => $self->{border}; 1073 fontsize => $self->{border}
1074 if defined $title;
1032 1075
1033 $self 1076 $self
1077}
1078
1079sub add {
1080 my ($self, @widgets) = @_;
1081
1082 $self->SUPER::add (@widgets);
1083 $self->CFClient::UI::Container::add ($self->{title}) if $self->{title};
1034} 1084}
1035 1085
1036sub border { 1086sub border {
1037 int $_[0]{border} * $::FONTSIZE 1087 int $_[0]{border} * $::FONTSIZE
1038} 1088}
1039 1089
1040sub size_request { 1090sub size_request {
1041 my ($self) = @_; 1091 my ($self) = @_;
1092
1093 $self->{title}->size_request
1094 if $self->{title};
1042 1095
1043 my ($w, $h) = $self->SUPER::size_request; 1096 my ($w, $h) = $self->SUPER::size_request;
1044 1097
1045 ( 1098 (
1046 $w + $self->border * 2, 1099 $w + $self->border * 2,
1047 $h + $self->border * 2, 1100 $h + $self->border * 2,
1048 ) 1101 )
1049} 1102}
1050 1103
1051sub size_allocate { 1104sub size_allocate {
1052 my ($self, $w, $h, $changed) = @_; 1105 my ($self, $w, $h) = @_;
1053 1106
1054 return unless $changed; 1107 if ($self->{title}) {
1108 $self->{title}{w} = $w;
1109 $self->{title}{h} = $h;
1110 $self->{title}->size_allocate ($w, $h);
1111 }
1055 1112
1113 my $border = $self->border;
1114
1056 $h -= List::Util::max 0, $self->border * 2; 1115 $h -= List::Util::max 0, $border * 2;
1057 $w -= List::Util::max 0, $self->border * 2; 1116 $w -= List::Util::max 0, $border * 2;
1058 1117
1059 $self->{title}->configure ($self->border, int $self->border - $::FONTSIZE * 2, $w, int $::FONTSIZE * 2)
1060 if $self->{title};
1061
1062 $self->child->configure ($self->border, $self->border, $w, $h); 1118 $self->child->configure ($border, $border, $w, $h);
1063} 1119}
1064 1120
1065sub button_down { 1121sub button_down {
1066 my ($self, $ev, $x, $y) = @_; 1122 my ($self, $ev, $x, $y) = @_;
1067 1123
1083 my ($ev, $x, $y) = @_; 1139 my ($ev, $x, $y) = @_;
1084 1140
1085 my $dx = $ev->{x} - $ox; 1141 my $dx = $ev->{x} - $ox;
1086 my $dy = $ev->{y} - $oy; 1142 my $dy = $ev->{y} - $oy;
1087 1143
1088 $self->{user_x} = $wx + $dx * $mx;
1089 $self->{user_y} = $wy + $dy * $my;
1090 $self->{def_w} = $bw + $dx * ($mx ? -1 : 1); 1144 $self->{force_w} = $bw + $dx * ($mx ? -1 : 1);
1091 $self->{def_h} = $bh + $dy * ($my ? -1 : 1); 1145 $self->{force_h} = $bh + $dy * ($my ? -1 : 1);
1092 $self->move ($self->{user_x}, $self->{user_y}); 1146
1093 $self->realloc; 1147 $self->realloc;
1148 $self->move_abs ($wx + $dx * $mx, $wy + $dy * $my);
1094 }; 1149 };
1095 1150
1096 } elsif ($lr ^ $td) { 1151 } elsif ($lr ^ $td) {
1097 my ($ox, $oy) = ($ev->{x}, $ev->{y}); 1152 my ($ox, $oy) = ($ev->{x}, $ev->{y});
1098 my ($bx, $by) = ($self->{x}, $self->{y}); 1153 my ($bx, $by) = ($self->{x}, $self->{y});
1100 $self->{motion} = sub { 1155 $self->{motion} = sub {
1101 my ($ev, $x, $y) = @_; 1156 my ($ev, $x, $y) = @_;
1102 1157
1103 ($x, $y) = ($ev->{x}, $ev->{y}); 1158 ($x, $y) = ($ev->{x}, $ev->{y});
1104 1159
1105 $self->{user_x} = $bx + $x - $ox; 1160 $self->move_abs ($bx + $x - $ox, $by + $y - $oy);
1106 $self->{user_y} = $by + $y - $oy;
1107
1108 $self->move ($self->{user_x}, $self->{user_y});
1109 $self->realloc;
1110 }; 1161 };
1111 } 1162 }
1112} 1163}
1113 1164
1114sub button_up { 1165sub button_up {
1124} 1175}
1125 1176
1126sub _draw { 1177sub _draw {
1127 my ($self) = @_; 1178 my ($self) = @_;
1128 1179
1180 my $child = $self->{children}[0];
1181
1129 my ($w, $h ) = ($self->{w}, $self->{h}); 1182 my ($w, $h ) = ($self->{w}, $self->{h});
1130 my ($cw, $ch) = ($self->child->{w}, $self->child->{h}); 1183 my ($cw, $ch) = ($child->{w}, $child->{h});
1131 1184
1132 glEnable GL_TEXTURE_2D; 1185 glEnable GL_TEXTURE_2D;
1133 glTexEnv GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE; 1186 glTexEnv GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE;
1134 1187
1135 my $border = $self->border; 1188 my $border = $self->border;
1136 1189
1137 glColor @{ $self->{border_bg} }; 1190 glColor @{ $self->{border_bg} };
1138 $tex[1]->draw_quad_alpha (0, 0, $w, $border); 1191 $border[0]->draw_quad_alpha (0, 0, $w, $border);
1139 $tex[3]->draw_quad_alpha (0, $border, $border, $ch); 1192 $border[1]->draw_quad_alpha (0, $border, $border, $ch);
1140 $tex[2]->draw_quad_alpha ($w - $border, $border, $border, $ch); 1193 $border[2]->draw_quad_alpha ($w - $border, $border, $border, $ch);
1141 $tex[4]->draw_quad_alpha (0, $h - $border, $w, $border); 1194 $border[3]->draw_quad_alpha (0, $h - $border, $w, $border);
1142 1195
1143 if (@{$self->{bg}} < 4 || $self->{bg}[3]) { 1196 if (@{$self->{bg}} < 4 || $self->{bg}[3]) {
1144 my $bg = $tex[0]; 1197 glColor @{ $self->{bg} };
1145 1198
1146 # TODO: repeat texture not scale 1199 # TODO: repeat texture not scale
1200 # solve this better(?)
1147 my $rep_x = $cw / $bg->{w}; 1201 $bg->{s} = $cw / $bg->{w};
1148 my $rep_y = $ch / $bg->{h}; 1202 $bg->{t} = $ch / $bg->{h};
1149
1150 glColor @{ $self->{bg} };
1151
1152 $bg->{s} = $rep_x;
1153 $bg->{t} = $rep_y;
1154 $bg->{wrap_mode} = 1;
1155 $bg->draw_quad_alpha ($border, $border, $cw, $ch); 1203 $bg->draw_quad_alpha ($border, $border, $cw, $ch);
1156 } 1204 }
1157 1205
1158 glDisable GL_TEXTURE_2D; 1206 glDisable GL_TEXTURE_2D;
1159 1207
1160 $self->{title}->draw if $self->{title};
1161
1162 $self->child->draw; 1208 $child->draw;
1209
1210 if ($self->{title}) {
1211 glTranslate 0, $border - $self->{h};
1212 $self->{title}->_draw;
1213 }
1163} 1214}
1164 1215
1165############################################################################# 1216#############################################################################
1166 1217
1167package CFClient::UI::Table; 1218package CFClient::UI::Table;
1241 (sum @$hs), 1292 (sum @$hs),
1242 ) 1293 )
1243} 1294}
1244 1295
1245sub size_allocate { 1296sub size_allocate {
1246 my ($self, $w, $h, $changed) = @_; 1297 my ($self, $w, $h) = @_;
1247 1298
1248 my ($ws, $hs) = $self->get_wh; 1299 my ($ws, $hs) = $self->get_wh;
1249 1300
1250 my $req_w = (sum @$ws) || 1; 1301 my $req_w = (sum @$ws) || 1;
1251 my $req_h = (sum @$hs) || 1; 1302 my $req_h = (sum @$hs) || 1;
1329 (List::Util::max map $_->{req_h}, @{$self->{children}}), 1380 (List::Util::max map $_->{req_h}, @{$self->{children}}),
1330 ) 1381 )
1331} 1382}
1332 1383
1333sub size_allocate { 1384sub size_allocate {
1334 my ($self, $w, $h, $changed) = @_; 1385 my ($self, $w, $h) = @_;
1335 1386
1336 my $space = $self->{vertical} ? $h : $w; 1387 my $space = $self->{vertical} ? $h : $w;
1337 my $children = $self->{children}; 1388 my $children = $self->{children};
1338 1389
1339 my @req; 1390 my @req;
1422 ellipsise => 3, # end 1473 ellipsise => 3, # end
1423 layout => (new CFClient::Layout), 1474 layout => (new CFClient::Layout),
1424 fontsize => 1, 1475 fontsize => 1,
1425 align => -1, 1476 align => -1,
1426 valign => -1, 1477 valign => -1,
1427 padding => 2, 1478 padding_x => 2,
1479 padding_y => 2,
1428 can_events => 0, 1480 can_events => 0,
1429 %arg 1481 %arg
1430 ); 1482 );
1431 1483
1432 if (exists $self->{template}) { 1484 if (exists $self->{template}) {
1469 1521
1470 $self->{layout} = new CFClient::Layout if $self->{layout}->is_rgba; 1522 $self->{layout} = new CFClient::Layout if $self->{layout}->is_rgba;
1471 $self->{layout}->set_text ($text); 1523 $self->{layout}->set_text ($text);
1472 1524
1473 $self->realloc; 1525 $self->realloc;
1526 $self->update;
1474} 1527}
1475 1528
1476sub set_markup { 1529sub set_markup {
1477 my ($self, $markup) = @_; 1530 my ($self, $markup) = @_;
1478 1531
1483 1536
1484 $self->{layout} = new CFClient::Layout $rgba if $self->{layout}->is_rgba != $rgba; 1537 $self->{layout} = new CFClient::Layout $rgba if $self->{layout}->is_rgba != $rgba;
1485 $self->{layout}->set_markup ($markup); 1538 $self->{layout}->set_markup ($markup);
1486 1539
1487 $self->realloc; 1540 $self->realloc;
1541 $self->update;
1488} 1542}
1489 1543
1490sub size_request { 1544sub size_request {
1491 my ($self) = @_; 1545 my ($self) = @_;
1492 1546
1506 1560
1507 $w = List::Util::max $w, $w2; 1561 $w = List::Util::max $w, $w2;
1508 $h = List::Util::max $h, $h2; 1562 $h = List::Util::max $h, $h2;
1509 } 1563 }
1510 1564
1511 ( 1565 ($w, $h)
1512 $w + $self->{padding} * 2,
1513 $h + $self->{padding} * 2,
1514 )
1515} 1566}
1516 1567
1517sub size_allocate { 1568sub size_allocate {
1518 my ($self, $w, $h, $changed) = @_; 1569 my ($self, $w, $h) = @_;
1570
1571 delete $self->{ox};
1519 1572
1520 delete $self->{texture} 1573 delete $self->{texture}
1521 if $changed; 1574 unless $w >= $self->{req_w} && $self->{old_w} >= $self->{req_w};
1522} 1575}
1523 1576
1524sub set_fontsize { 1577sub set_fontsize {
1525 my ($self, $fontsize) = @_; 1578 my ($self, $fontsize) = @_;
1526 1579
1541 $self->{layout}->set_width ($self->{w}); 1594 $self->{layout}->set_width ($self->{w});
1542 $self->{layout}->set_ellipsise ($self->{ellipsise}); 1595 $self->{layout}->set_ellipsise ($self->{ellipsise});
1543 $self->{layout}->set_single_paragraph_mode ($self->{ellipsise}); 1596 $self->{layout}->set_single_paragraph_mode ($self->{ellipsise});
1544 $self->{layout}->set_height ($self->{fontsize} * $::FONTSIZE); 1597 $self->{layout}->set_height ($self->{fontsize} * $::FONTSIZE);
1545 1598
1546 my $tex = new_from_layout CFClient::Texture $self->{layout}; 1599 new_from_layout CFClient::Texture $self->{layout}
1600 };
1547 1601
1602 unless (exists $self->{ox}) {
1548 $self->{ox} = int ($self->{align} < 0 ? $self->{padding} 1603 $self->{ox} = int ($self->{align} < 0 ? $self->{padding_x}
1549 : $self->{align} > 0 ? $self->{w} - $tex->{w} - $self->{padding} 1604 : $self->{align} > 0 ? $self->{w} - $tex->{w} - $self->{padding_x}
1550 : ($self->{w} - $tex->{w}) * 0.5); 1605 : ($self->{w} - $tex->{w}) * 0.5);
1551 1606
1552 $self->{oy} = int ($self->{valign} < 0 ? $self->{padding} 1607 $self->{oy} = int ($self->{valign} < 0 ? $self->{padding_y}
1553 : $self->{valign} > 0 ? $self->{h} - $tex->{h} - $self->{padding} 1608 : $self->{valign} > 0 ? $self->{h} - $tex->{h} - $self->{padding_y}
1554 : ($self->{h} - $tex->{h}) * 0.5); 1609 : ($self->{h} - $tex->{h}) * 0.5);
1555
1556 $tex
1557 }; 1610 };
1558 1611
1559 glEnable GL_TEXTURE_2D; 1612 glEnable GL_TEXTURE_2D;
1560 glTexEnv GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE; 1613 glTexEnv GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE;
1561 1614
1797 1850
1798sub new { 1851sub new {
1799 my $class = shift; 1852 my $class = shift;
1800 1853
1801 $class->SUPER::new ( 1854 $class->SUPER::new (
1802 padding => 4, 1855 padding_x => 4,
1856 padding_y => 4,
1803 fg => [1, 1, 1], 1857 fg => [1, 1, 1],
1804 active_fg => [0, 0, 1], 1858 active_fg => [0, 0, 1],
1805 can_hover => 1, 1859 can_hover => 1,
1806 align => 0, 1860 align => 0,
1807 valign => 0, 1861 valign => 0,
1854 1908
1855sub new { 1909sub new {
1856 my $class = shift; 1910 my $class = shift;
1857 1911
1858 $class->SUPER::new ( 1912 $class->SUPER::new (
1859 padding => 2, 1913 padding_x => 2,
1914 padding_y => 2,
1860 fg => [1, 1, 1], 1915 fg => [1, 1, 1],
1861 active_fg => [1, 1, 0], 1916 active_fg => [1, 1, 0],
1862 bg => [0, 0, 0, 0.2], 1917 bg => [0, 0, 0, 0.2],
1863 active_bg => [1, 1, 1, 0.5], 1918 active_bg => [1, 1, 1, 0.5],
1864 state => 0, 1919 state => 0,
1868} 1923}
1869 1924
1870sub size_request { 1925sub size_request {
1871 my ($self) = @_; 1926 my ($self) = @_;
1872 1927
1873 ($self->{padding} * 2 + 6) x 2 1928 (6) x 2
1874} 1929}
1875 1930
1876sub button_down { 1931sub button_down {
1877 my ($self, $ev, $x, $y) = @_; 1932 my ($self, $ev, $x, $y) = @_;
1878 1933
1879 if ($x >= $self->{padding} && $x < $self->{w} - $self->{padding} 1934 if ($x >= $self->{padding_x} && $x < $self->{w} - $self->{padding_x}
1880 && $y >= $self->{padding} && $y < $self->{h} - $self->{padding}) { 1935 && $y >= $self->{padding_y} && $y < $self->{h} - $self->{padding_y}) {
1881 $self->{state} = !$self->{state}; 1936 $self->{state} = !$self->{state};
1882 $self->_emit (changed => $self->{state}); 1937 $self->_emit (changed => $self->{state});
1883 } 1938 }
1884} 1939}
1885 1940
1886sub _draw { 1941sub _draw {
1887 my ($self) = @_; 1942 my ($self) = @_;
1888 1943
1889 $self->SUPER::_draw; 1944 $self->SUPER::_draw;
1890 1945
1891 glTranslate $self->{padding} + 0.375, $self->{padding} + 0.375, 0; 1946 glTranslate $self->{padding_x} + 0.375, $self->{padding_y} + 0.375, 0;
1892 1947
1893 my $s = (List::Util::min @$self{qw(w h)}) - $self->{padding} * 2; 1948 my ($w, $h) = @$self{qw(w h)};
1949
1950 my $s = List::Util::min $w - $self->{padding_x} * 2, $h - $self->{padding_y} * 2;
1894 1951
1895 glColor @{ $FOCUS == $self ? $self->{active_fg} : $self->{fg} }; 1952 glColor @{ $FOCUS == $self ? $self->{active_fg} : $self->{fg} };
1896 1953
1897 my $tex = $self->{state} ? $tex[1] : $tex[0]; 1954 my $tex = $self->{state} ? $tex[1] : $tex[0];
1898 1955
2163 fg => [1, 1, 1], 2220 fg => [1, 1, 1],
2164 active_fg => [0, 0, 0], 2221 active_fg => [0, 0, 0],
2165 bg => [0, 0, 0, 0.2], 2222 bg => [0, 0, 0, 0.2],
2166 active_bg => [1, 1, 1, 0.5], 2223 active_bg => [1, 1, 1, 0.5],
2167 range => [0, 0, 100, 10, 0], 2224 range => [0, 0, 100, 10, 0],
2168 req_w => $::WIDTH / 80, 2225 min_w => $::WIDTH / 80,
2169 req_h => $::WIDTH / 80, 2226 min_h => $::WIDTH / 80,
2170 vertical => 0, 2227 vertical => 0,
2171 can_hover => 1, 2228 can_hover => 1,
2172 inner_pad => 0.02, 2229 inner_pad => 0.02,
2173 @_ 2230 @_
2174 ); 2231 );
2214} 2271}
2215 2272
2216sub size_request { 2273sub size_request {
2217 my ($self) = @_; 2274 my ($self) = @_;
2218 2275
2219 my $w = $self->{req_w}; 2276 ($self->{req_w}, $self->{req_h})
2220 my $h = $self->{req_h};
2221
2222 $self->{vertical} ? ($h, $w) : ($w, $h)
2223} 2277}
2224 2278
2225sub button_down { 2279sub button_down {
2226 my ($self, $ev, $x, $y) = @_; 2280 my ($self, $ev, $x, $y) = @_;
2227 2281
2377 $self->{fontsize} = $fontsize; 2431 $self->{fontsize} = $fontsize;
2378 $self->reflow; 2432 $self->reflow;
2379} 2433}
2380 2434
2381sub size_allocate { 2435sub size_allocate {
2382 my ($self, $w, $h, $changed) = @_; 2436 my ($self, $w, $h) = @_;
2383 2437
2384 $self->SUPER::size_allocate ($w, $h, $changed); 2438 $self->SUPER::size_allocate ($w, $h);
2385
2386 return unless $changed;
2387 2439
2388 $self->{layout}->set_font ($self->{font}) if $self->{font}; 2440 $self->{layout}->set_font ($self->{font}) if $self->{font};
2389 $self->{layout}->set_height ($self->{fontsize} * $::FONTSIZE); 2441 $self->{layout}->set_height ($self->{fontsize} * $::FONTSIZE);
2390 $self->{layout}->set_width ($self->{children}[0]{w}); 2442 $self->{layout}->set_width ($self->{children}[0]{w});
2391 2443
2614} 2666}
2615 2667
2616sub set_tooltip_from { 2668sub set_tooltip_from {
2617 my ($self, $widget) = @_; 2669 my ($self, $widget) = @_;
2618 2670
2671 my $tooltip = $widget->{tooltip};
2672
2673 if ($ENV{CFPLUS_DEBUG} & 2) {
2674 $tooltip .= "\n\n" . (ref $widget) . "\n"
2675 . "$widget->{x} $widget->{y} $widget->{w} $widget->{h}\n"
2676 . "req $widget->{req_w} $widget->{req_h}\n"
2677 . "visible $widget->{visible}";
2678 }
2679
2619 $self->add (new CFClient::UI::Label 2680 $self->add (new CFClient::UI::Label
2620 markup => $widget->{tooltip}, 2681 markup => $tooltip,
2621 max_w => ($widget->{tooltip_width} || 0.25) * $::WIDTH, 2682 max_w => ($widget->{tooltip_width} || 0.25) * $::WIDTH,
2622 fontsize => 0.8, 2683 fontsize => 0.8,
2623 fg => [0, 0, 0, 1], 2684 fg => [0, 0, 0, 1],
2624 ellipsise => 0, 2685 ellipsise => 0,
2625 font => ($widget->{tooltip_font} || $::FONT_PROP), 2686 font => ($widget->{tooltip_font} || $::FONT_PROP),
2633 2694
2634 ($w + 4, $h + 4) 2695 ($w + 4, $h + 4)
2635} 2696}
2636 2697
2637sub size_allocate { 2698sub size_allocate {
2638 my ($self, $w, $h, $changed) = @_; 2699 my ($self, $w, $h) = @_;
2639 2700
2640 return unless $changed;
2641
2642 $self->SUPER::size_allocate ($w - 4, $h - 4, $changed); 2701 $self->SUPER::size_allocate ($w - 4, $h - 4);
2702}
2703
2704sub visibility_change {
2705 my ($self, $visible) = @_;
2706
2707 return unless $visible;
2708
2709 $self->{root}->on_post_alloc ("move_$self" => sub {
2710 my $widget = $self->{owner}
2711 or return;
2712
2713 my ($x, $y) = $widget->coord2global ($widget->{w}, 0);
2714
2715 ($x, $y) = $widget->coord2global (-$self->{w}, 0)
2716 if $x + $self->{w} > $::WIDTH;
2717
2718 $self->move_abs ($x, $y);
2719 });
2643} 2720}
2644 2721
2645sub _draw { 2722sub _draw {
2646 my ($self) = @_; 2723 my ($self) = @_;
2647 2724
2664 glVertex $w, $h; 2741 glVertex $w, $h;
2665 glVertex $w, 0; 2742 glVertex $w, 0;
2666 glEnd; 2743 glEnd;
2667 2744
2668 glTranslate 2 - 0.375, 2 - 0.375; 2745 glTranslate 2 - 0.375, 2 - 0.375;
2746
2669 $self->SUPER::_draw; 2747 $self->SUPER::_draw;
2670} 2748}
2671 2749
2672############################################################################# 2750#############################################################################
2673 2751
2749 $self->SUPER::DESTROY; 2827 $self->SUPER::DESTROY;
2750} 2828}
2751 2829
2752############################################################################# 2830#############################################################################
2753 2831
2754package CFClient::UI::Inventory;
2755
2756our @ISA = CFClient::UI::ScrolledWindow::;
2757
2758sub new {
2759 my $class = shift;
2760
2761 my $self = $class->SUPER::new (
2762 scrolled => (new CFClient::UI::Table col_expand => [0, 1, 0]),
2763 @_,
2764 );
2765
2766 $self
2767}
2768
2769sub set_items {
2770 my ($self, $items) = @_;
2771
2772 $self->{scrolled}->clear;
2773 return unless $items;
2774
2775 my @items = sort {
2776 ($a->{type} <=> $b->{type})
2777 or ($a->{name} cmp $b->{name})
2778 } @$items;
2779
2780 $self->{real_items} = \@items;
2781
2782 my $row = 0;
2783 for my $item (@items) {
2784 CFClient::Item::update_widgets $item;
2785
2786 $self->{scrolled}->add (0, $row, $item->{face_widget});
2787 $self->{scrolled}->add (1, $row, $item->{desc_widget});
2788 $self->{scrolled}->add (2, $row, $item->{weight_widget});
2789
2790 $row++;
2791 }
2792}
2793
2794#############################################################################
2795
2796package CFClient::UI::Menu; 2832package CFClient::UI::Menu;
2797 2833
2798our @ISA = CFClient::UI::FancyFrame::; 2834our @ISA = CFClient::UI::FancyFrame::;
2799 2835
2800use CFClient::OpenGL; 2836use CFClient::OpenGL;
2838 # maybe save $GRAB? must be careful about events... 2874 # maybe save $GRAB? must be careful about events...
2839 $GRAB = $self; 2875 $GRAB = $self;
2840 $self->{button} = $ev->{button}; 2876 $self->{button} = $ev->{button};
2841 2877
2842 $self->show; 2878 $self->show;
2843 $self->move ($ev->{x} - $self->{w} * 0.5, $ev->{y} - $self->{h} * 0.5); 2879 $self->move_abs ($ev->{x} - $self->{w} * 0.5, $ev->{y} - $self->{h} * 0.5);
2844} 2880}
2845 2881
2846sub mouse_motion { 2882sub mouse_motion {
2847 my ($self, $ev, $x, $y) = @_; 2883 my ($self, $ev, $x, $y) = @_;
2848 2884
2973 $self->SUPER::reconfigure; 3009 $self->SUPER::reconfigure;
2974} 3010}
2975 3011
2976############################################################################# 3012#############################################################################
2977 3013
3014package CFClient::UI::Inventory;
3015
3016our @ISA = CFClient::UI::ScrolledWindow::;
3017
3018sub new {
3019 my $class = shift;
3020
3021 my $self = $class->SUPER::new (
3022 scrolled => (new CFClient::UI::Table col_expand => [0, 1, 0]),
3023 @_,
3024 );
3025
3026 $self
3027}
3028
3029sub set_items {
3030 my ($self, $items) = @_;
3031
3032 $self->{scrolled}->clear;
3033 return unless $items;
3034
3035 my @items = sort {
3036 ($a->{type} <=> $b->{type})
3037 or ($a->{name} cmp $b->{name})
3038 } @$items;
3039
3040 $self->{real_items} = \@items;
3041
3042 my $row = 0;
3043 for my $item (@items) {
3044 CFClient::Item::update_widgets $item;
3045
3046 $self->{scrolled}->add (0, $row, $item->{face_widget});
3047 $self->{scrolled}->add (1, $row, $item->{desc_widget});
3048 $self->{scrolled}->add (2, $row, $item->{weight_widget});
3049
3050 $row++;
3051 }
3052}
3053
3054#############################################################################
3055
3056package CFClient::UI::BindEditor;
3057
3058our @ISA = CFClient::UI::FancyFrame::;
3059
3060sub new {
3061 my $class = shift;
3062
3063 my $self = $class->SUPER::new (binding => [], commands => [], @_);
3064
3065 $self->add (my $vb = new CFClient::UI::VBox);
3066
3067
3068 $vb->add ($self->{rec_btn} = new CFClient::UI::Button
3069 text => "start recording",
3070 tooltip => "Start/Stops recording of actions."
3071 ."All subsequent actions after the recording started will be captured."
3072 ."The actions are displayed after the record was stopped."
3073 ."To bind the action you have to click on the 'Bind' button",
3074 on_activate => sub {
3075 unless ($self->{recording}) {
3076 $self->start;
3077 } else {
3078 $self->stop;
3079 }
3080 });
3081
3082 $vb->add (new CFClient::UI::Label text => "Actions:");
3083 $vb->add ($self->{cmdbox} = new CFClient::UI::VBox);
3084
3085 $vb->add (new CFClient::UI::Label text => "Bound to: ");
3086 $vb->add (my $hb = new CFClient::UI::HBox);
3087 $hb->add ($self->{keylbl} = new CFClient::UI::Label expand => 1);
3088 $hb->add (new CFClient::UI::Button
3089 text => "bind",
3090 tooltip => "This opens a query where you have to press the key combination to bind the recorded actions",
3091 on_activate => sub {
3092 $self->ask_for_bind;
3093 });
3094
3095 $vb->add (my $hb = new CFClient::UI::HBox);
3096 $hb->add (new CFClient::UI::Button
3097 text => "ok",
3098 expand => 1,
3099 tooltip => "This closes the binding editor and saves the binding",
3100 on_activate => sub {
3101 $self->hide;
3102 $self->commit;
3103 });
3104
3105 $hb->add (new CFClient::UI::Button
3106 text => "cancel",
3107 expand => 1,
3108 tooltip => "This closes the binding editor without saving",
3109 on_activate => sub {
3110 $self->hide;
3111 $self->{binding_cancel}->()
3112 if $self->{binding_cancel};
3113 });
3114
3115 $self->update_binding_widgets;
3116
3117 $self
3118}
3119
3120sub commit {
3121 my ($self) = @_;
3122 my ($mod, $sym, $cmds) = $self->get_binding;
3123 if ($sym != 0 && @$cmds > 0) {
3124 $::STATUSBOX->add ("Bound actions to '".CFClient::Binder::keycombo_to_name ($mod, $sym)
3125 ."'. Don't forget 'Save Config'!");
3126 $self->{binding_change}->($mod, $sym, $cmds)
3127 if $self->{binding_change};
3128 } else {
3129 $::STATUSBOX->add ("No action bound, no key or action specified!");
3130 $self->{binding_cancel}->()
3131 if $self->{binding_cancel};
3132 }
3133}
3134
3135sub start {
3136 my ($self) = @_;
3137
3138 $self->{rec_btn}->set_text ("stop recording");
3139 $self->{recording} = 1;
3140 $self->clear_command_list;
3141 $::CONN->start_record if $::CONN;
3142}
3143
3144sub stop {
3145 my ($self) = @_;
3146
3147 $self->{rec_btn}->set_text ("start recording");
3148 $self->{recording} = 0;
3149
3150 my $rec;
3151 $rec = $::CONN->stop_record if $::CONN;
3152 return unless ref $rec eq 'ARRAY';
3153 $self->set_command_list ($rec);
3154}
3155
3156# if $commit is true, the binding will be set after the user entered a key combo
3157sub ask_for_bind {
3158 my ($self, $commit) = @_;
3159
3160 CFClient::Binder::open_binding_dialog (sub {
3161 my ($mod, $sym) = @_;
3162 $self->{binding} = [$mod, $sym]; # XXX: how to stop that memleak?
3163 $self->update_binding_widgets;
3164 $self->commit if $commit;
3165 });
3166}
3167
3168# $mod and $sym are the modifiers and key symbol
3169# $cmds is a array ref of strings (the commands)
3170# $cb is the callback that is executed on OK
3171# $ccb is the callback that is executed on CANCEL and
3172# when the binding was unsuccessful on OK
3173sub set_binding {
3174 my ($self, $mod, $sym, $cmds, $cb, $ccb) = @_;
3175
3176 $self->clear_command_list;
3177 $self->{recording} = 0;
3178 $self->{rec_btn}->set_text ("start recording");
3179
3180 $self->{binding} = [$mod, $sym];
3181 $self->{commands} = $cmds;
3182
3183 $self->{binding_change} = $cb;
3184 $self->{binding_cancel} = $ccb;
3185
3186 $self->update_binding_widgets;
3187}
3188
3189# this is a shortcut method that asks for a binding
3190# and then just binds it.
3191sub do_quick_binding {
3192 my ($self, $cmds) = @_;
3193 $self->set_binding (undef, undef, $cmds, sub {
3194 $::CFG->{bindings}->{$_[0]}->{$_[1]} = $_[2];
3195 });
3196 $self->ask_for_bind (1);
3197}
3198
3199sub update_binding_widgets {
3200 my ($self) = @_;
3201 my ($mod, $sym, $cmds) = $self->get_binding;
3202 $self->{keylbl}->set_text (CFClient::Binder::keycombo_to_name ($mod, $sym));
3203 $self->set_command_list ($cmds);
3204}
3205
3206sub get_binding {
3207 my ($self) = @_;
3208 return (
3209 $self->{binding}->[0],
3210 $self->{binding}->[1],
3211 [ grep { defined $_ } @{$self->{commands}} ]
3212 );
3213}
3214
3215sub clear_command_list {
3216 my ($self) = @_;
3217 $self->{cmdbox}->clear ();
3218}
3219
3220sub set_command_list {
3221 my ($self, $cmds) = @_;
3222
3223 $self->{cmdbox}->clear ();
3224 $self->{commands} = $cmds;
3225
3226 my $idx = 0;
3227
3228 for (@$cmds) {
3229 $self->{cmdbox}->add (my $hb = new CFClient::UI::HBox);
3230
3231 my $i = $idx;
3232 $hb->add (new CFClient::UI::Label text => $_);
3233 $hb->add (new CFClient::UI::Button
3234 text => "delete",
3235 tooltip => "Deletes the action from the record",
3236 on_activate => sub {
3237 $self->{cmdbox}->remove ($hb);
3238 $cmds->[$i] = undef;
3239 });
3240
3241
3242 $idx++
3243 }
3244}
3245
3246#############################################################################
3247
3248package CFClient::UI::SpellList;
3249
3250our @ISA = CFClient::UI::FancyFrame::;
3251
3252sub new {
3253 my $class = shift;
3254
3255 my $self = $class->SUPER::new (binding => [], commands => [], @_);
3256
3257 $self->add (new CFClient::UI::ScrolledWindow
3258 scrolled => $self->{spellbox} = new CFClient::UI::Table);
3259
3260 $self;
3261}
3262
3263# XXX: Do sorting? Argl...
3264sub add_spell {
3265 my ($self, $spell) = @_;
3266 $self->{spells}->{$spell->{name}} = $spell;
3267
3268 $self->{spellbox}->add (0, $self->{tbl_idx}, new CFClient::UI::Face
3269 face => $spell->{face},
3270 can_hover => 1,
3271 can_events => 1,
3272 tooltip => $spell->{message});
3273
3274 $self->{spellbox}->add (1, $self->{tbl_idx}, new CFClient::UI::Label
3275 text => $spell->{name},
3276 can_hover => 1,
3277 can_events => 1,
3278 tooltip => $spell->{message},
3279 expand => 1);
3280
3281 $self->{spellbox}->add (2, $self->{tbl_idx}, new CFClient::UI::Label
3282 text => (sprintf "lvl: %2d sp: %2d dmg: %2d",
3283 $spell->{level}, ($spell->{mana} || $spell->{grace}), $spell->{damage}),
3284 expand => 1);
3285
3286 $self->{spellbox}->add (3, $self->{tbl_idx}++, new CFClient::UI::Button
3287 text => "bind to key",
3288 on_activate => sub { $::BIND_EDITOR->do_quick_binding (["cast $spell->{name}"]) });
3289}
3290
3291sub rebuild_spell_list {
3292 my ($self) = @_;
3293 $self->{tbl_idx} = 0;
3294 $self->add_spell ($_) for values %{$self->{spells}};
3295}
3296
3297sub remove_spell {
3298 my ($self, $spell) = @_;
3299 delete $self->{spells}->{$spell->{name}};
3300 $self->rebuild_spell_list;
3301}
3302
3303#############################################################################
3304
2978package CFClient::UI::Root; 3305package CFClient::UI::Root;
2979 3306
2980our @ISA = CFClient::UI::Container::; 3307our @ISA = CFClient::UI::Container::;
2981 3308
2982use CFClient::OpenGL; 3309use CFClient::OpenGL;
2992 Scalar::Util::weaken ($self->{root} = $self); 3319 Scalar::Util::weaken ($self->{root} = $self);
2993 3320
2994 $self 3321 $self
2995} 3322}
2996 3323
2997sub configure {
2998 my ($self, $x, $y, $w, $h) = @_;
2999
3000 $self->{w} = $w;
3001 $self->{h} = $h;
3002}
3003
3004sub reconfigure {
3005 my ($self) = @_;
3006
3007 $self->SUPER::reconfigure;
3008
3009 $self->size_allocate ($self->{w}, $self->{h}, 1)
3010 if $self->{w};
3011}
3012
3013sub size_request { 3324sub size_request {
3014 my ($self) = @_; 3325 my ($self) = @_;
3015 3326
3016 ($self->{w}, $self->{h}) 3327 ($self->{w}, $self->{h})
3017} 3328}
3018 3329
3330sub _to_pixel {
3331 my ($coord, $size, $max) = @_;
3332
3333 $coord =
3334 $coord eq "center" ? ($max - $size) * 0.5
3335 : $coord eq "max" ? $max
3336 : $coord;
3337
3338 $coord = 0 if $coord < 0;
3339 $coord = $max - $size if $coord > $max - $size;
3340
3341 int $coord + 0.5
3342}
3343
3019sub size_allocate { 3344sub size_allocate {
3020 my ($self, $w, $h, $changed) = @_; 3345 my ($self, $w, $h) = @_;
3021 3346
3022 for my $child ($self->children) { 3347 for my $child ($self->children) {
3023 my ($X, $Y, $W, $H) = @$child{qw(x y req_w req_h)}; 3348 my ($X, $Y, $W, $H) = @$child{qw(x y req_w req_h)};
3024 3349
3025 $X = $child->{req_x} > 0 ? $child->{req_x} : $w - $W - $child->{req_x} + 1 3350 $X = $child->{force_x} if exists $child->{force_x};
3026 if exists $child->{req_x}; 3351 $Y = $child->{force_y} if exists $child->{force_y};
3027 3352
3028 $Y = $child->{req_y} > 0 ? $child->{req_y} : $h - $H - $child->{req_y} + 1 3353 $X = _to_pixel $X, $W, $self->{w};
3029 if exists $child->{req_y}; 3354 $Y = _to_pixel $Y, $H, $self->{h};
3030
3031 #delete @$child{qw(req_x req_y)};#d# def_x, def_y
3032
3033 $X = List::Util::max 0, List::Util::min $w - $W, int $X + 0.5;
3034 $Y = List::Util::max 0, List::Util::min $h - $H, int $Y + 0.5;
3035 3355
3036 $child->configure ($X, $Y, $W, $H); 3356 $child->configure ($X, $Y, $W, $H);
3037 } 3357 }
3038} 3358}
3039 3359
3056} 3376}
3057 3377
3058sub add { 3378sub add {
3059 my ($self, @children) = @_; 3379 my ($self, @children) = @_;
3060 3380
3061 for my $child (@children) {
3062 $child->{is_toplevel} = 1; 3381 $_->{is_toplevel} = 1
3063 3382 for @children;
3064 # integerise window positions
3065 $child->{x} = int $child->{x};
3066 $child->{y} = int $child->{y};
3067 }
3068 3383
3069 $self->SUPER::add (@children); 3384 $self->SUPER::add (@children);
3070} 3385}
3071 3386
3072sub remove { 3387sub remove {
3073 my ($self, @children) = @_; 3388 my ($self, @children) = @_;
3074 3389
3075 $self->SUPER::remove (@children); 3390 $self->SUPER::remove (@children);
3391
3392 delete $self->{is_toplevel}
3393 for @children;
3076 3394
3077 while (@children) { 3395 while (@children) {
3078 my $w = pop @children; 3396 my $w = pop @children;
3079 push @children, $w->children; 3397 push @children, $w->children;
3080 $w->set_invisible; 3398 $w->set_invisible;
3100 $_->() 3418 $_->()
3101 for values %{delete $self->{refresh_hook}}; 3419 for values %{delete $self->{refresh_hook}};
3102 } 3420 }
3103 3421
3104 if ($self->{realloc}) { 3422 if ($self->{realloc}) {
3423 my %queue;
3105 my @queue; 3424 my @queue;
3425 my $widget;
3106 3426
3427 outer:
3107 while () { 3428 while () {
3108 if ($self->{realloc}) { 3429 if (my $realloc = delete $self->{realloc}) {
3109 #TODO use array-of-depth approach 3430 for $widget (values %$realloc) {
3431 $widget->{visible} or next; # do not resize invisible widgets
3110 3432
3111 @queue = sort { $a->{visible} <=> $b->{visible} } 3433 $queue{$widget+0}++ and next; # duplicates are common
3112 @queue, values %{delete $self->{realloc}}; 3434
3435 push @{ $queue[$widget->{visible}] }, $widget;
3436 }
3113 } 3437 }
3114 3438
3439 while () {
3440 @queue or last outer;
3441
3442 $widget = pop @{ $queue[-1] || [] }
3443 and last;
3444
3445 pop @queue;
3446 }
3447
3448 delete $queue{$widget+0};
3449
3450 my ($w, $h) = $widget->size_request;
3451
3452 $w = List::Util::max $widget->{min_w}, $w + $widget->{padding_x} * 2;
3453 $h = List::Util::max $widget->{min_h}, $h + $widget->{padding_y} * 2;
3454
3455 $w = $widget->{force_w} if exists $widget->{force_w};
3456 $h = $widget->{force_h} if exists $widget->{force_h};
3457
3458 if ($widget->{req_w} != $w || $widget->{req_h} != $h
3459 || delete $widget->{force_realloc}) {
3460 $widget->{req_w} = $w;
3461 $widget->{req_h} = $h;
3462
3463 $self->{size_alloc}{$widget+0} = $widget;
3464
3465 if (my $parent = $widget->{parent}) {
3466 $self->{realloc}{$parent+0} = $parent
3467 unless $queue{$parent+0};
3468
3469 $parent->{force_size_alloc} = 1;
3470 $self->{size_alloc}{$parent+0} = $parent;
3471 }
3472 }
3473
3474 delete $self->{realloc}{$widget+0};
3475 }
3476 }
3477
3478 while (my $size_alloc = delete $self->{size_alloc}) {
3479 my @queue = sort { $b->{visible} <=> $a->{visible} }
3480 values %$size_alloc;
3481
3482 while () {
3115 my $widget = pop @queue || last; 3483 my $widget = pop @queue || last;
3116 3484
3117 $widget->{visible} or last; # do not resize invisible widgets 3485 my ($w, $h) = @$widget{qw(alloc_w alloc_h)};
3118
3119 my ($w, $h) = $widget->{def_w} && $widget->{def_h}
3120 ? @$widget{qw(def_w def_h)}
3121 : $widget->size_request;
3122
3123 Carp::confess "$widget: size_request is negative" if $w < 0 || $h < 0;#d#
3124
3125 $widget->{req_w} = $w;
3126 $widget->{req_h} = $h;
3127
3128 $self->{size_alloc}{$widget} = [$widget, $widget->{w}, $widget->{h}];
3129
3130 push @queue, $widget->{parent}
3131 if $widget->{parent};
3132 }
3133 }
3134
3135 while (my $size_alloc = delete $self->{size_alloc}) {
3136 my @queue = sort $b->[0]{visible} <=> $a->[0]{visible},
3137 values %$size_alloc;
3138
3139 while () {
3140 my ($widget, $w, $h) = @{ pop @queue or last };
3141 3486
3142 $w = 0 if $w < 0; 3487 $w = 0 if $w < 0;
3143 $h = 0 if $h < 0; 3488 $h = 0 if $h < 0;
3144 3489
3490 $w = int $w + 0.5;
3491 $h = int $h + 0.5;
3492
3493 if ($widget->{w} != $w || $widget->{h} != $h || delete $widget->{force_size_alloc}) {
3494 $widget->{old_w} = $widget->{w};
3495 $widget->{old_h} = $widget->{h};
3496
3145 $widget->{w} = $w; 3497 $widget->{w} = $w;
3146 $widget->{h} = $h; 3498 $widget->{h} = $h;
3499
3147 $widget->emit (size_allocate => $w, $h, 1); 3500 $widget->emit (size_allocate => $w, $h);
3501 }
3148 } 3502 }
3149 } 3503 }
3150 3504
3151 while ($self->{post_alloc_hook}) { 3505 while ($self->{post_alloc_hook}) {
3152 $_->() 3506 $_->()
3153 for values %{delete $self->{post_alloc_hook}}; 3507 for values %{delete $self->{post_alloc_hook}};
3154 } 3508 }
3509
3155 3510
3156 glViewport 0, 0, $::WIDTH, $::HEIGHT; 3511 glViewport 0, 0, $::WIDTH, $::HEIGHT;
3157 glClearColor +($::CFG->{fow_intensity}) x 3, 1; 3512 glClearColor +($::CFG->{fow_intensity}) x 3, 1;
3158 glClear GL_COLOR_BUFFER_BIT; 3513 glClear GL_COLOR_BUFFER_BIT;
3159 3514
3161 glLoadIdentity; 3516 glLoadIdentity;
3162 glOrtho 0, $::WIDTH, $::HEIGHT, 0, -10000, 10000; 3517 glOrtho 0, $::WIDTH, $::HEIGHT, 0, -10000, 10000;
3163 glMatrixMode GL_MODELVIEW; 3518 glMatrixMode GL_MODELVIEW;
3164 glLoadIdentity; 3519 glLoadIdentity;
3165 3520
3521 {
3522 package CFClient::UI::Base;
3523
3524 ($draw_x, $draw_y, $draw_w, $draw_h) =
3525 (0, 0, $self->{w}, $self->{h});
3526 }
3527
3166 $self->_draw; 3528 $self->_draw;
3167} 3529}
3168 3530
3169############################################################################# 3531#############################################################################
3170 3532

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines