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.258 by root, Tue May 30 02:55:45 2006 UTC vs.
Revision 1.270 by elmex, Fri Jun 2 09:02:49 2006 UTC

40 40
41 $LAYOUT = $layout; 41 $LAYOUT = $layout;
42} 42}
43 43
44sub check_tooltip { 44sub check_tooltip {
45 return if $ENV{CFPLUS_DEBUG} & 8;
46
45 if (!$GRAB) { 47 if (!$GRAB) {
46 for (my $widget = $HOVER; $widget; $widget = $widget->{parent}) { 48 for (my $widget = $HOVER; $widget; $widget = $widget->{parent}) {
47 if (length $widget->{tooltip}) { 49 if (length $widget->{tooltip}) {
48
49 if ($TOOLTIP->{owner} != $widget) { 50 if ($TOOLTIP->{owner} != $widget) {
50 $TOOLTIP->hide; 51 $TOOLTIP->hide;
51 52
52 $TOOLTIP->{owner} = $widget; 53 $TOOLTIP->{owner} = $widget;
53 54
170sub rescale_widgets { 171sub rescale_widgets {
171 my ($sx, $sy) = @_; 172 my ($sx, $sy) = @_;
172 173
173 for my $widget (values %WIDGET) { 174 for my $widget (values %WIDGET) {
174 if ($widget->{is_toplevel}) { 175 if ($widget->{is_toplevel}) {
175 $widget->{x} += $widget->{w} * 0.5 if $widget->{x} =~ /^[0-9.]+$/; 176 $widget->{x} += int $widget->{w} * 0.5 if $widget->{x} =~ /^[0-9.]+$/;
176 $widget->{y} += $widget->{h} * 0.5 if $widget->{y} =~ /^[0-9.]+$/; 177 $widget->{y} += int $widget->{h} * 0.5 if $widget->{y} =~ /^[0-9.]+$/;
177 178
178 $widget->{x} = int 0.5 + $widget->{x} * $sx if $widget->{x} =~ /^[0-9.]+$/; 179 $widget->{x} = int 0.5 + $widget->{x} * $sx if $widget->{x} =~ /^[0-9.]+$/;
179 $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};
180 $widget->{force_w} = int 0.5 + $widget->{force_w} * $sx if exists $widget->{force_w}; 181 $widget->{force_w} = int 0.5 + $widget->{force_w} * $sx if exists $widget->{force_w};
181 $widget->{y} = int 0.5 + $widget->{y} * $sy if $widget->{y} =~ /^[0-9.]+$/; 182 $widget->{y} = int 0.5 + $widget->{y} * $sy if $widget->{y} =~ /^[0-9.]+$/;
182 $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};
183 $widget->{force_h} = int 0.5 + $widget->{force_h} * $sy if exists $widget->{force_h}; 184 $widget->{force_h} = int 0.5 + $widget->{force_h} * $sy if exists $widget->{force_h};
184 185
185 $widget->{x} -= $widget->{w} * 0.5 if $widget->{x} =~ /^[0-9.]+$/; 186 $widget->{x} -= int $widget->{w} * 0.5 if $widget->{x} =~ /^[0-9.]+$/;
186 $widget->{y} -= $widget->{h} * 0.5 if $widget->{y} =~ /^[0-9.]+$/; 187 $widget->{y} -= int $widget->{h} * 0.5 if $widget->{y} =~ /^[0-9.]+$/;
187 188
188 } 189 }
189 } 190 }
190 191
191 reconfigure_widgets; 192 reconfigure_widgets;
219 $self->connect ($1 => delete $self->{$_}); 220 $self->connect ($1 => delete $self->{$_});
220 } 221 }
221 } 222 }
222 223
223 if (my $layout = $CFClient::UI::LAYOUT->{$self->{name}}) { 224 if (my $layout = $CFClient::UI::LAYOUT->{$self->{name}}) {
224 $self->{x} = $layout->{x} * $CFClient::UI::ROOT->{w} if exists $layout->{x}; 225 $self->{x} = $layout->{x} * $CFClient::UI::ROOT->{alloc_w} if exists $layout->{x};
225 $self->{y} = $layout->{y} * $CFClient::UI::ROOT->{h} if exists $layout->{y}; 226 $self->{y} = $layout->{y} * $CFClient::UI::ROOT->{alloc_h} if exists $layout->{y};
226 $self->{force_w} = $layout->{w} * $CFClient::UI::ROOT->{w} if exists $layout->{w}; 227 $self->{force_w} = $layout->{w} * $CFClient::UI::ROOT->{alloc_w} if exists $layout->{w};
227 $self->{force_h} = $layout->{h} * $CFClient::UI::ROOT->{h} if exists $layout->{h}; 228 $self->{force_h} = $layout->{h} * $CFClient::UI::ROOT->{alloc_h} if exists $layout->{h};
228 229
229 $self->{x} -= $self->{force_w} * 0.5 if exists $layout->{x}; 230 $self->{x} -= $self->{force_w} * 0.5 if exists $layout->{x};
230 $self->{y} -= $self->{force_h} * 0.5 if exists $layout->{y}; 231 $self->{y} -= $self->{force_h} * 0.5 if exists $layout->{y};
231 232
232 $self->show if $layout->{show}; 233 $self->show if $layout->{show};
355 $self->{x} = $x; 356 $self->{x} = $x;
356 $self->{y} = $y; 357 $self->{y} = $y;
357 $self->update; 358 $self->update;
358 } 359 }
359 360
360 if ($self->{w} != $w || $self->{h} != $h) { 361 if ($self->{alloc_w} != $w || $self->{alloc_h} != $h) {
361 return unless $self->{visible}; 362 return unless $self->{visible};
362 363
364 $self->{alloc_w} = $w;
365 $self->{alloc_h} = $h;
366
363 $self->{root}->{size_alloc}{$self+0} = [$self, $w, $h]; 367 $self->{root}{size_alloc}{$self+0} = $self;
364 } 368 }
365} 369}
366 370
367sub size_allocate { 371sub size_allocate {
368 # nothing to be done 372 # nothing to be done
446 my ($self, $ev, $x, $y) = @_; 450 my ($self, $ev, $x, $y) = @_;
447 451
448 $self->focus_in; 452 $self->focus_in;
449} 453}
450 454
451sub w { $_[0]{w} = $_[1] if @_ > 1; $_[0]{w} }
452sub h { $_[0]{h} = $_[1] if @_ > 1; $_[0]{h} }
453sub x { $_[0]{x} = $_[1] if @_ > 1; $_[0]{x} }
454sub y { $_[0]{y} = $_[1] if @_ > 1; $_[0]{y} }
455sub z { $_[0]{z} = $_[1] if @_ > 1; $_[0]{z} }
456
457sub find_widget { 455sub find_widget {
458 my ($self, $x, $y) = @_; 456 my ($self, $x, $y) = @_;
459 457
460 return () unless $self->{can_events}; 458 return () unless $self->{can_events};
461 459
498 496
499sub realloc { 497sub realloc {
500 my ($self) = @_; 498 my ($self) = @_;
501 499
502 if ($self->{visible}) { 500 if ($self->{visible}) {
503 return if $self->{root}{realloc}{$self}; 501 return if $self->{root}{realloc}{$self+0};
504 502
505 $self->{root}{realloc}{$self} = $self; 503 $self->{root}{realloc}{$self+0} = $self;
506 $self->{root}->update; 504 $self->{root}->update;
507 } else { 505 } else {
508 delete $self->{req_w}; 506 delete $self->{req_w};
507 delete $self->{req_h};
509 } 508 }
510} 509}
511 510
512sub update { 511sub update {
513 my ($self) = @_; 512 my ($self) = @_;
521 520
522 $self->realloc; 521 $self->realloc;
523 $self->update; 522 $self->update;
524} 523}
525 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
526sub draw { 529sub draw {
527 my ($self) = @_; 530 my ($self) = @_;
528 531
529 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);
530 543
531 glPushMatrix; 544 glPushMatrix;
532 glTranslate $self->{x}, $self->{y}, 0; 545 glTranslate $self->{x}, $self->{y}, 0;
533 $self->_draw; 546 $self->_draw;
534 glPopMatrix; 547 glPopMatrix;
546 glVertex $x , $y + $self->{h}; 559 glVertex $x , $y + $self->{h};
547 glEnd; 560 glEnd;
548 glDisable GL_BLEND; 561 glDisable GL_BLEND;
549 } 562 }
550 563
551 if ($ENV{CFPLUS_DEBUG}) { 564 if ($ENV{CFPLUS_DEBUG} & 1) {
552 glPushMatrix; 565 glPushMatrix;
553 glColor 1, 1, 0, 1; 566 glColor 1, 1, 0, 1;
554 glTranslate $self->{x} + 0.375, $self->{y} + 0.375; 567 glTranslate $self->{x} + 0.375, $self->{y} + 0.375;
555 glBegin GL_LINE_LOOP; 568 glBegin GL_LINE_LOOP;
556 glVertex 0 , 0; 569 glVertex 0 , 0;
765sub size_request { 778sub size_request {
766 $_[0]{children}[0]->size_request 779 $_[0]{children}[0]->size_request
767} 780}
768 781
769sub size_allocate { 782sub size_allocate {
770 my ($self, $w, $h, $changed) = @_; 783 my ($self, $w, $h) = @_;
771 784
772 $self->{children}[0]->configure (0, 0, $w, $h); 785 $self->{children}[0]->configure (0, 0, $w, $h);
773} 786}
774 787
775############################################################################# 788#############################################################################
792 $ROOT->on_post_alloc ($self => sub { $self->render_child }); 805 $ROOT->on_post_alloc ($self => sub { $self->render_child });
793 $self->SUPER::update; 806 $self->SUPER::update;
794} 807}
795 808
796sub size_allocate { 809sub size_allocate {
797 my ($self, $w, $h, $changed) = @_; 810 my ($self, $w, $h) = @_;
798 811
799 $self->SUPER::size_allocate ($w, $h, $changed); 812 $self->SUPER::size_allocate ($w, $h);
800 $self->update 813 $self->update;
801 if $changed;
802} 814}
803 815
804sub _render { 816sub _render {
817 my ($self) = @_;
818
805 $_[0]{children}[0]->draw; 819 $self->{children}[0]->draw;
806} 820}
807 821
808sub render_child { 822sub render_child {
809 my ($self) = @_; 823 my ($self) = @_;
810 824
811 $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 {
812 glClearColor 0, 0, 0, 0; 826 glClearColor 0, 0, 0, 0;
813 glClear GL_COLOR_BUFFER_BIT; 827 glClear GL_COLOR_BUFFER_BIT;
814 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
815 $self->_render; 836 $self->_render;
816 }; 837 };
817} 838}
818 839
819sub _draw { 840sub _draw {
820 my ($self) = @_; 841 my ($self) = @_;
821 842
822 my ($w, $h) = ($self->w, $self->h); 843 my ($w, $h) = @$self{qw(w h)};
823 844
824 my $tex = $self->{texture} 845 my $tex = $self->{texture}
825 or return; 846 or return;
826 847
827 glEnable GL_TEXTURE_2D; 848 glEnable GL_TEXTURE_2D;
850} 871}
851 872
852sub size_request { 873sub size_request {
853 my ($self) = @_; 874 my ($self) = @_;
854 875
855 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)};
856 877
857 $w = 10 if $self->{scroll_x}; 878 $w = 10 if $self->{scroll_x};
858 $h = 10 if $self->{scroll_y}; 879 $h = 10 if $self->{scroll_y};
859 880
860 ($w, $h) 881 ($w, $h)
861} 882}
862 883
863sub size_allocate { 884sub size_allocate {
864 my ($self, $w, $h, $changed) = @_; 885 my ($self, $w, $h) = @_;
865 886
887 my $child = $self->child;
888
866 $w = $self->{child_w} if $self->{scroll_x} && $self->{child_w}; 889 $w = $child->{req_w} if $self->{scroll_x} && $child->{req_w};
867 $h = $self->{child_h} if $self->{scroll_y} && $self->{child_h}; 890 $h = $child->{req_h} if $self->{scroll_y} && $child->{req_h};
868 891
869 $self->child->configure (0, 0, $w, $h); 892 $self->child->configure (0, 0, $w, $h);
870 $self->update; 893 $self->update;
871} 894}
872 895
907 } 930 }
908} 931}
909 932
910sub _render { 933sub _render {
911 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};
912 938
913 CFClient::OpenGL::glTranslate -$self->{view_x}, -$self->{view_y}; 939 CFClient::OpenGL::glTranslate -$self->{view_x}, -$self->{view_y};
914 940
915 $self->SUPER::_render; 941 $self->SUPER::_render;
916} 942}
956 my $child = $self->{vp}->child; 982 my $child = $self->{vp}->child;
957 $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]);
958} 984}
959 985
960sub size_allocate { 986sub size_allocate {
961 my ($self, $w, $h, $changed) = @_; 987 my ($self, $w, $h) = @_;
962 988
963 $self->SUPER::size_allocate ($w, $h, $changed); 989 $self->SUPER::size_allocate ($w, $h);
964 990
965 my $child = $self->{vp}->child; 991 my $child = $self->{vp}->child;
966 $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]);
967} 993}
968 994
1024my @border = 1050my @border =
1025 map { new_from_file CFClient::Texture CFClient::find_rcfile $_, mipmap => 1 } 1051 map { new_from_file CFClient::Texture CFClient::find_rcfile $_, mipmap => 1 }
1026 qw(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);
1027 1053
1028sub new { 1054sub new {
1029 my $class = shift; 1055 my ($class, %arg) = @_;
1056
1057 my $title = delete $arg{title};
1030 1058
1031 my $self = $class->SUPER::new ( 1059 my $self = $class->SUPER::new (
1032 bg => [1, 1, 1, 1], 1060 bg => [1, 1, 1, 1],
1033 border_bg => [1, 1, 1, 1], 1061 border_bg => [1, 1, 1, 1],
1034 border => 0.6, 1062 border => 0.6,
1035 can_events => 1, 1063 can_events => 1,
1036 min_w => 16, 1064 min_w => 16,
1037 min_h => 16, 1065 min_h => 16,
1038 @_ 1066 %arg,
1039 ); 1067 );
1040 1068
1041 $self->{title} &&= new CFClient::UI::Label 1069 $self->{title} = new CFClient::UI::Label
1042 align => 0, 1070 align => 0,
1043 valign => 1, 1071 valign => 1,
1044 text => $self->{title}, 1072 text => $title,
1045 fontsize => $self->{border}; 1073 fontsize => $self->{border}
1074 if defined $title;
1046 1075
1047 $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};
1048} 1084}
1049 1085
1050sub border { 1086sub border {
1051 int $_[0]{border} * $::FONTSIZE 1087 int $_[0]{border} * $::FONTSIZE
1052} 1088}
1053 1089
1054sub size_request { 1090sub size_request {
1055 my ($self) = @_; 1091 my ($self) = @_;
1092
1093 $self->{title}->size_request
1094 if $self->{title};
1056 1095
1057 my ($w, $h) = $self->SUPER::size_request; 1096 my ($w, $h) = $self->SUPER::size_request;
1058 1097
1059 ( 1098 (
1060 $w + $self->border * 2, 1099 $w + $self->border * 2,
1061 $h + $self->border * 2, 1100 $h + $self->border * 2,
1062 ) 1101 )
1063} 1102}
1064 1103
1065sub size_allocate { 1104sub size_allocate {
1066 my ($self, $w, $h, $changed) = @_; 1105 my ($self, $w, $h) = @_;
1067 1106
1068 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 }
1069 1112
1113 my $border = $self->border;
1114
1070 $h -= List::Util::max 0, $self->border * 2; 1115 $h -= List::Util::max 0, $border * 2;
1071 $w -= List::Util::max 0, $self->border * 2; 1116 $w -= List::Util::max 0, $border * 2;
1072 1117
1073 $self->{title}->configure ($self->border, int $self->border - $::FONTSIZE * 2, $w, int $::FONTSIZE * 2)
1074 if $self->{title};
1075
1076 $self->child->configure ($self->border, $self->border, $w, $h); 1118 $self->child->configure ($border, $border, $w, $h);
1077} 1119}
1078 1120
1079sub button_down { 1121sub button_down {
1080 my ($self, $ev, $x, $y) = @_; 1122 my ($self, $ev, $x, $y) = @_;
1081 1123
1133} 1175}
1134 1176
1135sub _draw { 1177sub _draw {
1136 my ($self) = @_; 1178 my ($self) = @_;
1137 1179
1180 my $child = $self->{children}[0];
1181
1138 my ($w, $h ) = ($self->{w}, $self->{h}); 1182 my ($w, $h ) = ($self->{w}, $self->{h});
1139 my ($cw, $ch) = ($self->child->{w}, $self->child->{h}); 1183 my ($cw, $ch) = ($child->{w}, $child->{h});
1140 1184
1141 glEnable GL_TEXTURE_2D; 1185 glEnable GL_TEXTURE_2D;
1142 glTexEnv GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE; 1186 glTexEnv GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE;
1143 1187
1144 my $border = $self->border; 1188 my $border = $self->border;
1159 $bg->draw_quad_alpha ($border, $border, $cw, $ch); 1203 $bg->draw_quad_alpha ($border, $border, $cw, $ch);
1160 } 1204 }
1161 1205
1162 glDisable GL_TEXTURE_2D; 1206 glDisable GL_TEXTURE_2D;
1163 1207
1164 $self->{title}->draw if $self->{title};
1165
1166 $self->child->draw; 1208 $child->draw;
1209
1210 if ($self->{title}) {
1211 glTranslate 0, $border - $self->{h};
1212 $self->{title}->_draw;
1213 }
1167} 1214}
1168 1215
1169############################################################################# 1216#############################################################################
1170 1217
1171package CFClient::UI::Table; 1218package CFClient::UI::Table;
1245 (sum @$hs), 1292 (sum @$hs),
1246 ) 1293 )
1247} 1294}
1248 1295
1249sub size_allocate { 1296sub size_allocate {
1250 my ($self, $w, $h, $changed) = @_; 1297 my ($self, $w, $h) = @_;
1251 1298
1252 my ($ws, $hs) = $self->get_wh; 1299 my ($ws, $hs) = $self->get_wh;
1253 1300
1254 my $req_w = (sum @$ws) || 1; 1301 my $req_w = (sum @$ws) || 1;
1255 my $req_h = (sum @$hs) || 1; 1302 my $req_h = (sum @$hs) || 1;
1333 (List::Util::max map $_->{req_h}, @{$self->{children}}), 1380 (List::Util::max map $_->{req_h}, @{$self->{children}}),
1334 ) 1381 )
1335} 1382}
1336 1383
1337sub size_allocate { 1384sub size_allocate {
1338 my ($self, $w, $h, $changed) = @_; 1385 my ($self, $w, $h) = @_;
1339 1386
1340 my $space = $self->{vertical} ? $h : $w; 1387 my $space = $self->{vertical} ? $h : $w;
1341 my $children = $self->{children}; 1388 my $children = $self->{children};
1342 1389
1343 my @req; 1390 my @req;
1517 1564
1518 ($w, $h) 1565 ($w, $h)
1519} 1566}
1520 1567
1521sub size_allocate { 1568sub size_allocate {
1522 my ($self, $w, $h, $changed) = @_; 1569 my ($self, $w, $h) = @_;
1570
1571 delete $self->{ox};
1523 1572
1524 delete $self->{texture} 1573 delete $self->{texture}
1525 if $changed; 1574 unless $w >= $self->{req_w} && $self->{old_w} >= $self->{req_w};
1526} 1575}
1527 1576
1528sub set_fontsize { 1577sub set_fontsize {
1529 my ($self, $fontsize) = @_; 1578 my ($self, $fontsize) = @_;
1530 1579
1545 $self->{layout}->set_width ($self->{w}); 1594 $self->{layout}->set_width ($self->{w});
1546 $self->{layout}->set_ellipsise ($self->{ellipsise}); 1595 $self->{layout}->set_ellipsise ($self->{ellipsise});
1547 $self->{layout}->set_single_paragraph_mode ($self->{ellipsise}); 1596 $self->{layout}->set_single_paragraph_mode ($self->{ellipsise});
1548 $self->{layout}->set_height ($self->{fontsize} * $::FONTSIZE); 1597 $self->{layout}->set_height ($self->{fontsize} * $::FONTSIZE);
1549 1598
1550 my $tex = new_from_layout CFClient::Texture $self->{layout}; 1599 new_from_layout CFClient::Texture $self->{layout}
1600 };
1551 1601
1602 unless (exists $self->{ox}) {
1552 $self->{ox} = int ($self->{align} < 0 ? $self->{padding_x} 1603 $self->{ox} = int ($self->{align} < 0 ? $self->{padding_x}
1553 : $self->{align} > 0 ? $self->{w} - $tex->{w} - $self->{padding_x} 1604 : $self->{align} > 0 ? $self->{w} - $tex->{w} - $self->{padding_x}
1554 : ($self->{w} - $tex->{w}) * 0.5); 1605 : ($self->{w} - $tex->{w}) * 0.5);
1555 1606
1556 $self->{oy} = int ($self->{valign} < 0 ? $self->{padding_y} 1607 $self->{oy} = int ($self->{valign} < 0 ? $self->{padding_y}
1557 : $self->{valign} > 0 ? $self->{h} - $tex->{h} - $self->{padding_y} 1608 : $self->{valign} > 0 ? $self->{h} - $tex->{h} - $self->{padding_y}
1558 : ($self->{h} - $tex->{h}) * 0.5); 1609 : ($self->{h} - $tex->{h}) * 0.5);
1559
1560 $tex
1561 }; 1610 };
1562 1611
1563 glEnable GL_TEXTURE_2D; 1612 glEnable GL_TEXTURE_2D;
1564 glTexEnv GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE; 1613 glTexEnv GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE;
1565 1614
2382 $self->{fontsize} = $fontsize; 2431 $self->{fontsize} = $fontsize;
2383 $self->reflow; 2432 $self->reflow;
2384} 2433}
2385 2434
2386sub size_allocate { 2435sub size_allocate {
2387 my ($self, $w, $h, $changed) = @_; 2436 my ($self, $w, $h) = @_;
2388 2437
2389 $self->SUPER::size_allocate ($w, $h, $changed); 2438 $self->SUPER::size_allocate ($w, $h);
2390
2391 return unless $changed;
2392 2439
2393 $self->{layout}->set_font ($self->{font}) if $self->{font}; 2440 $self->{layout}->set_font ($self->{font}) if $self->{font};
2394 $self->{layout}->set_height ($self->{fontsize} * $::FONTSIZE); 2441 $self->{layout}->set_height ($self->{fontsize} * $::FONTSIZE);
2395 $self->{layout}->set_width ($self->{children}[0]{w}); 2442 $self->{layout}->set_width ($self->{children}[0]{w});
2396 2443
2619} 2666}
2620 2667
2621sub set_tooltip_from { 2668sub set_tooltip_from {
2622 my ($self, $widget) = @_; 2669 my ($self, $widget) = @_;
2623 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
2624 $self->add (new CFClient::UI::Label 2680 $self->add (new CFClient::UI::Label
2625 markup => $widget->{tooltip}, 2681 markup => $tooltip,
2626 max_w => ($widget->{tooltip_width} || 0.25) * $::WIDTH, 2682 max_w => ($widget->{tooltip_width} || 0.25) * $::WIDTH,
2627 fontsize => 0.8, 2683 fontsize => 0.8,
2628 fg => [0, 0, 0, 1], 2684 fg => [0, 0, 0, 1],
2629 ellipsise => 0, 2685 ellipsise => 0,
2630 font => ($widget->{tooltip_font} || $::FONT_PROP), 2686 font => ($widget->{tooltip_font} || $::FONT_PROP),
2638 2694
2639 ($w + 4, $h + 4) 2695 ($w + 4, $h + 4)
2640} 2696}
2641 2697
2642sub size_allocate { 2698sub size_allocate {
2643 my ($self, $w, $h, $changed) = @_; 2699 my ($self, $w, $h) = @_;
2644 2700
2645 return unless $changed;
2646
2647 $self->SUPER::size_allocate ($w - 4, $h - 4, $changed); 2701 $self->SUPER::size_allocate ($w - 4, $h - 4);
2648} 2702}
2649 2703
2650sub visibility_change { 2704sub visibility_change {
2651 my ($self, $visible) = @_; 2705 my ($self, $visible) = @_;
2652 2706
2769 2823
2770 $self->{timer}->cancel 2824 $self->{timer}->cancel
2771 if $self->{timer}; 2825 if $self->{timer};
2772 2826
2773 $self->SUPER::DESTROY; 2827 $self->SUPER::DESTROY;
2774}
2775
2776#############################################################################
2777
2778package CFClient::UI::Inventory;
2779
2780our @ISA = CFClient::UI::ScrolledWindow::;
2781
2782sub new {
2783 my $class = shift;
2784
2785 my $self = $class->SUPER::new (
2786 scrolled => (new CFClient::UI::Table col_expand => [0, 1, 0]),
2787 @_,
2788 );
2789
2790 $self
2791}
2792
2793sub set_items {
2794 my ($self, $items) = @_;
2795
2796 $self->{scrolled}->clear;
2797 return unless $items;
2798
2799 my @items = sort {
2800 ($a->{type} <=> $b->{type})
2801 or ($a->{name} cmp $b->{name})
2802 } @$items;
2803
2804 $self->{real_items} = \@items;
2805
2806 my $row = 0;
2807 for my $item (@items) {
2808 CFClient::Item::update_widgets $item;
2809
2810 $self->{scrolled}->add (0, $row, $item->{face_widget});
2811 $self->{scrolled}->add (1, $row, $item->{desc_widget});
2812 $self->{scrolled}->add (2, $row, $item->{weight_widget});
2813
2814 $row++;
2815 }
2816} 2828}
2817 2829
2818############################################################################# 2830#############################################################################
2819 2831
2820package CFClient::UI::Menu; 2832package CFClient::UI::Menu;
2997 $self->SUPER::reconfigure; 3009 $self->SUPER::reconfigure;
2998} 3010}
2999 3011
3000############################################################################# 3012#############################################################################
3001 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
3157sub ask_for_bind_and_commit {
3158 my ($self) = @_;
3159 $self->ask_for_bind (1);
3160}
3161
3162sub ask_for_bind {
3163 my ($self, $commit) = @_;
3164
3165 CFClient::Binder::open_binding_dialog (sub {
3166 my ($mod, $sym) = @_;
3167 $self->{binding} = [$mod, $sym]; # XXX: how to stop that memleak?
3168 $self->update_binding_widgets;
3169 $self->commit if $commit;
3170 });
3171}
3172
3173# $mod and $sym are the modifiers and key symbol
3174# $cmds is a array ref of strings (the commands)
3175# $cb is the callback that is executed on OK
3176# $ccb is the callback that is executed on CANCEL and
3177# when the binding was unsuccessful on OK
3178sub set_binding {
3179 my ($self, $mod, $sym, $cmds, $cb, $ccb) = @_;
3180
3181 $self->clear_command_list;
3182 $self->{recording} = 0;
3183 $self->{rec_btn}->set_text ("start recording");
3184
3185 $self->{binding} = [$mod, $sym];
3186 $self->{commands} = $cmds;
3187
3188 $self->{binding_change} = $cb;
3189 $self->{binding_cancel} = $ccb;
3190
3191 $self->update_binding_widgets;
3192}
3193
3194# this is a shortcut method that asks for a binding
3195# and then just binds it.
3196sub do_quick_binding {
3197 my ($self, $cmds) = @_;
3198 $self->set_binding (undef, undef, $cmds, sub {
3199 $::CFG->{bindings}->{$_[0]}->{$_[1]} = $_[2];
3200 });
3201 $self->ask_for_bind (1);
3202}
3203
3204sub update_binding_widgets {
3205 my ($self) = @_;
3206 my ($mod, $sym, $cmds) = $self->get_binding;
3207 $self->{keylbl}->set_text (CFClient::Binder::keycombo_to_name ($mod, $sym));
3208 $self->set_command_list ($cmds);
3209}
3210
3211sub get_binding {
3212 my ($self) = @_;
3213 return (
3214 $self->{binding}->[0],
3215 $self->{binding}->[1],
3216 [ grep { defined $_ } @{$self->{commands}} ]
3217 );
3218}
3219
3220sub clear_command_list {
3221 my ($self) = @_;
3222 $self->{cmdbox}->clear ();
3223}
3224
3225sub set_command_list {
3226 my ($self, $cmds) = @_;
3227
3228 $self->{cmdbox}->clear ();
3229 $self->{commands} = $cmds;
3230
3231 my $idx = 0;
3232
3233 for (@$cmds) {
3234 $self->{cmdbox}->add (my $hb = new CFClient::UI::HBox);
3235
3236 my $i = $idx;
3237 $hb->add (new CFClient::UI::Label text => $_);
3238 $hb->add (new CFClient::UI::Button
3239 text => "delete",
3240 tooltip => "Deletes the action from the record",
3241 on_activate => sub {
3242 $self->{cmdbox}->remove ($hb);
3243 $cmds->[$i] = undef;
3244 });
3245
3246
3247 $idx++
3248 }
3249}
3250
3251#############################################################################
3252
3253package CFClient::UI::SpellList;
3254
3255our @ISA = CFClient::UI::FancyFrame::;
3256
3257sub new {
3258 my $class = shift;
3259
3260 my $self = $class->SUPER::new (binding => [], commands => [], @_);
3261
3262 $self->add (new CFClient::UI::ScrolledWindow
3263 scrolled => $self->{spellbox} = new CFClient::UI::Table);
3264
3265 $self;
3266}
3267
3268# XXX: Do sorting? Argl...
3269sub add_spell {
3270 my ($self, $spell) = @_;
3271 $self->{spells}->{$spell->{name}} = $spell;
3272
3273 $self->{spellbox}->add (0, $self->{tbl_idx}, new CFClient::UI::Face
3274 face => $spell->{face},
3275 can_hover => 1,
3276 can_events => 1,
3277 tooltip => $spell->{message});
3278
3279 $self->{spellbox}->add (1, $self->{tbl_idx}, new CFClient::UI::Label
3280 text => $spell->{name},
3281 can_hover => 1,
3282 can_events => 1,
3283 tooltip => $spell->{message},
3284 expand => 1);
3285
3286 $self->{spellbox}->add (2, $self->{tbl_idx}, new CFClient::UI::Label
3287 text => (sprintf "lvl: %2d sp: %2d dmg: %2d",
3288 $spell->{level}, ($spell->{mana} || $spell->{grace}), $spell->{damage}),
3289 expand => 1);
3290
3291 $self->{spellbox}->add (3, $self->{tbl_idx}++, new CFClient::UI::Button
3292 text => "bind to key",
3293 on_activate => sub { $::BIND_EDITOR->do_quick_binding (["cast $spell->{name}"]) });
3294}
3295
3296sub rebuild_spell_list {
3297 my ($self) = @_;
3298 $self->{tbl_idx} = 0;
3299 $self->add_spell ($_) for values %{$self->{spells}};
3300}
3301
3302sub remove_spell {
3303 my ($self, $spell) = @_;
3304 delete $self->{spells}->{$spell->{name}};
3305 $self->rebuild_spell_list;
3306}
3307
3308#############################################################################
3309
3002package CFClient::UI::Root; 3310package CFClient::UI::Root;
3003 3311
3004our @ISA = CFClient::UI::Container::; 3312our @ISA = CFClient::UI::Container::;
3005 3313
3006use CFClient::OpenGL; 3314use CFClient::OpenGL;
3016 Scalar::Util::weaken ($self->{root} = $self); 3324 Scalar::Util::weaken ($self->{root} = $self);
3017 3325
3018 $self 3326 $self
3019} 3327}
3020 3328
3021sub configure {
3022 my ($self, $x, $y, $w, $h) = @_;
3023
3024 $self->{w} = $w;
3025 $self->{h} = $h;
3026}
3027
3028sub reconfigure {
3029 my ($self) = @_;
3030
3031 $self->SUPER::reconfigure;
3032
3033 $self->size_allocate ($self->{w}, $self->{h}, 1)
3034 if $self->{w};
3035}
3036
3037sub size_request { 3329sub size_request {
3038 my ($self) = @_; 3330 my ($self) = @_;
3039 3331
3040 ($self->{w}, $self->{h}) 3332 ($self->{w}, $self->{h})
3041} 3333}
3053 3345
3054 int $coord + 0.5 3346 int $coord + 0.5
3055} 3347}
3056 3348
3057sub size_allocate { 3349sub size_allocate {
3058 my ($self, $w, $h, $changed) = @_; 3350 my ($self, $w, $h) = @_;
3059 3351
3060 for my $child ($self->children) { 3352 for my $child ($self->children) {
3061 my ($X, $Y, $W, $H) = @$child{qw(x y req_w req_h)}; 3353 my ($X, $Y, $W, $H) = @$child{qw(x y req_w req_h)};
3062 3354
3063 $X = $child->{force_x} if exists $child->{force_x}; 3355 $X = $child->{force_x} if exists $child->{force_x};
3131 $_->() 3423 $_->()
3132 for values %{delete $self->{refresh_hook}}; 3424 for values %{delete $self->{refresh_hook}};
3133 } 3425 }
3134 3426
3135 if ($self->{realloc}) { 3427 if ($self->{realloc}) {
3428 my %queue;
3136 my @queue; 3429 my @queue;
3430 my $widget;
3137 3431
3432 outer:
3138 while () { 3433 while () {
3139 if ($self->{realloc}) { 3434 if (my $realloc = delete $self->{realloc}) {
3140 #TODO use array-of-depth approach 3435 for $widget (values %$realloc) {
3436 $widget->{visible} or next; # do not resize invisible widgets
3141 3437
3142 @queue = sort { $a->{visible} <=> $b->{visible} } 3438 $queue{$widget+0}++ and next; # duplicates are common
3143 @queue, values %{delete $self->{realloc}}; 3439
3440 push @{ $queue[$widget->{visible}] }, $widget;
3441 }
3144 } 3442 }
3145 3443
3444 while () {
3445 @queue or last outer;
3446
3146 my $widget = pop @queue || last; 3447 $widget = pop @{ $queue[-1] || [] }
3448 and last;
3449
3450 pop @queue;
3451 }
3147 3452
3148 $widget->{visible} or last; # do not resize invisible widgets 3453 delete $queue{$widget+0};
3149 3454
3150 my ($w, $h) = $widget->size_request; 3455 my ($w, $h) = $widget->size_request;
3151 3456
3152 $w = List::Util::max $widget->{min_w}, $w + $widget->{padding_x} * 2; 3457 $w = List::Util::max $widget->{min_w}, $w + $widget->{padding_x} * 2;
3153 $h = List::Util::max $widget->{min_h}, $h + $widget->{padding_y} * 2; 3458 $h = List::Util::max $widget->{min_h}, $h + $widget->{padding_y} * 2;
3154 3459
3155 $w = $widget->{force_w} if exists $widget->{force_w}; 3460 $w = $widget->{force_w} if exists $widget->{force_w};
3156 $h = $widget->{force_h} if exists $widget->{force_h}; 3461 $h = $widget->{force_h} if exists $widget->{force_h};
3157 3462
3463 if ($widget->{req_w} != $w || $widget->{req_h} != $h
3464 || delete $widget->{force_realloc}) {
3158 $widget->{req_w} = $w; 3465 $widget->{req_w} = $w;
3159 $widget->{req_h} = $h; 3466 $widget->{req_h} = $h;
3160 3467
3161 $self->{size_alloc}{$widget} = [$widget, undef, undef]; 3468 $self->{size_alloc}{$widget+0} = $widget;
3162 3469
3163 push @queue, $widget->{parent} 3470 if (my $parent = $widget->{parent}) {
3164 if ($self->{w} != $w || $self->{h} != $h) && $widget->{parent}; 3471 $self->{realloc}{$parent+0} = $parent
3472 unless $queue{$parent+0};
3473
3474 $parent->{force_size_alloc} = 1;
3475 $self->{size_alloc}{$parent+0} = $parent;
3476 }
3477 }
3478
3479 delete $self->{realloc}{$widget+0};
3165 } 3480 }
3166 } 3481 }
3167 3482
3168 while (my $size_alloc = delete $self->{size_alloc}) { 3483 while (my $size_alloc = delete $self->{size_alloc}) {
3169 my @queue = sort $b->[0]{visible} <=> $a->[0]{visible}, 3484 my @queue = sort { $b->{visible} <=> $a->{visible} }
3170 values %$size_alloc; 3485 values %$size_alloc;
3171 3486
3172 while () { 3487 while () {
3173 my ($widget, $w, $h) = @{ pop @queue or last }; 3488 my $widget = pop @queue || last;
3174 3489
3175 $w = $widget->{w} || $widget->{req_w} unless defined $w; 3490 my ($w, $h) = @$widget{qw(alloc_w alloc_h)};
3176 $h = $widget->{h} || $widget->{req_h} unless defined $h;
3177 3491
3178 $w = 0 if $w < 0; 3492 $w = 0 if $w < 0;
3179 $h = 0 if $h < 0; 3493 $h = 0 if $h < 0;
3180 3494
3181 $w = int $w + 0.5; 3495 $w = int $w + 0.5;
3182 $h = int $h + 0.5; 3496 $h = int $h + 0.5;
3183 3497
3184 my $changed = $widget->{w} != $w || $widget->{h} != $h; 3498 if ($widget->{w} != $w || $widget->{h} != $h || delete $widget->{force_size_alloc}) {
3499 $widget->{old_w} = $widget->{w};
3500 $widget->{old_h} = $widget->{h};
3185 3501
3186 $widget->{w} = $w; 3502 $widget->{w} = $w;
3187 $widget->{h} = $h; 3503 $widget->{h} = $h;
3188 3504
3189 $widget->emit (size_allocate => $w, $h, $changed); 3505 $widget->emit (size_allocate => $w, $h);
3506 }
3190 } 3507 }
3191 } 3508 }
3192 3509
3193 while ($self->{post_alloc_hook}) { 3510 while ($self->{post_alloc_hook}) {
3194 $_->() 3511 $_->()
3195 for values %{delete $self->{post_alloc_hook}}; 3512 for values %{delete $self->{post_alloc_hook}};
3196 } 3513 }
3514
3197 3515
3198 glViewport 0, 0, $::WIDTH, $::HEIGHT; 3516 glViewport 0, 0, $::WIDTH, $::HEIGHT;
3199 glClearColor +($::CFG->{fow_intensity}) x 3, 1; 3517 glClearColor +($::CFG->{fow_intensity}) x 3, 1;
3200 glClear GL_COLOR_BUFFER_BIT; 3518 glClear GL_COLOR_BUFFER_BIT;
3201 3519
3203 glLoadIdentity; 3521 glLoadIdentity;
3204 glOrtho 0, $::WIDTH, $::HEIGHT, 0, -10000, 10000; 3522 glOrtho 0, $::WIDTH, $::HEIGHT, 0, -10000, 10000;
3205 glMatrixMode GL_MODELVIEW; 3523 glMatrixMode GL_MODELVIEW;
3206 glLoadIdentity; 3524 glLoadIdentity;
3207 3525
3526 {
3527 package CFClient::UI::Base;
3528
3529 ($draw_x, $draw_y, $draw_w, $draw_h) =
3530 (0, 0, $self->{w}, $self->{h});
3531 }
3532
3208 $self->_draw; 3533 $self->_draw;
3209} 3534}
3210 3535
3211############################################################################# 3536#############################################################################
3212 3537

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines