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.261 by elmex, Tue May 30 14:45:56 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;
449 my ($self, $ev, $x, $y) = @_; 450 my ($self, $ev, $x, $y) = @_;
450 451
451 $self->focus_in; 452 $self->focus_in;
452} 453}
453 454
454sub w { $_[0]{w} = $_[1] if @_ > 1; $_[0]{w} }
455sub h { $_[0]{h} = $_[1] if @_ > 1; $_[0]{h} }
456sub x { $_[0]{x} = $_[1] if @_ > 1; $_[0]{x} }
457sub y { $_[0]{y} = $_[1] if @_ > 1; $_[0]{y} }
458sub z { $_[0]{z} = $_[1] if @_ > 1; $_[0]{z} }
459
460sub find_widget { 455sub find_widget {
461 my ($self, $x, $y) = @_; 456 my ($self, $x, $y) = @_;
462 457
463 return () unless $self->{can_events}; 458 return () unless $self->{can_events};
464 459
525 520
526 $self->realloc; 521 $self->realloc;
527 $self->update; 522 $self->update;
528} 523}
529 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
530sub draw { 529sub draw {
531 my ($self) = @_; 530 my ($self) = @_;
532 531
533 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);
534 543
535 glPushMatrix; 544 glPushMatrix;
536 glTranslate $self->{x}, $self->{y}, 0; 545 glTranslate $self->{x}, $self->{y}, 0;
537 $self->_draw; 546 $self->_draw;
538 glPopMatrix; 547 glPopMatrix;
803 $self->SUPER::size_allocate ($w, $h); 812 $self->SUPER::size_allocate ($w, $h);
804 $self->update; 813 $self->update;
805} 814}
806 815
807sub _render { 816sub _render {
817 my ($self) = @_;
818
808 $_[0]{children}[0]->draw; 819 $self->{children}[0]->draw;
809} 820}
810 821
811sub render_child { 822sub render_child {
812 my ($self) = @_; 823 my ($self) = @_;
813 824
814 $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 {
815 glClearColor 0, 0, 0, 0; 826 glClearColor 0, 0, 0, 0;
816 glClear GL_COLOR_BUFFER_BIT; 827 glClear GL_COLOR_BUFFER_BIT;
817 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
818 $self->_render; 836 $self->_render;
819 }; 837 };
820} 838}
821 839
822sub _draw { 840sub _draw {
823 my ($self) = @_; 841 my ($self) = @_;
824 842
825 my ($w, $h) = ($self->w, $self->h); 843 my ($w, $h) = @$self{qw(w h)};
826 844
827 my $tex = $self->{texture} 845 my $tex = $self->{texture}
828 or return; 846 or return;
829 847
830 glEnable GL_TEXTURE_2D; 848 glEnable GL_TEXTURE_2D;
912 } 930 }
913} 931}
914 932
915sub _render { 933sub _render {
916 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};
917 938
918 CFClient::OpenGL::glTranslate -$self->{view_x}, -$self->{view_y}; 939 CFClient::OpenGL::glTranslate -$self->{view_x}, -$self->{view_y};
919 940
920 $self->SUPER::_render; 941 $self->SUPER::_render;
921} 942}
1029my @border = 1050my @border =
1030 map { new_from_file CFClient::Texture CFClient::find_rcfile $_, mipmap => 1 } 1051 map { new_from_file CFClient::Texture CFClient::find_rcfile $_, mipmap => 1 }
1031 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);
1032 1053
1033sub new { 1054sub new {
1034 my $class = shift; 1055 my ($class, %arg) = @_;
1056
1057 my $title = delete $arg{title};
1035 1058
1036 my $self = $class->SUPER::new ( 1059 my $self = $class->SUPER::new (
1037 bg => [1, 1, 1, 1], 1060 bg => [1, 1, 1, 1],
1038 border_bg => [1, 1, 1, 1], 1061 border_bg => [1, 1, 1, 1],
1039 border => 0.6, 1062 border => 0.6,
1040 can_events => 1, 1063 can_events => 1,
1041 min_w => 16, 1064 min_w => 16,
1042 min_h => 16, 1065 min_h => 16,
1043 @_ 1066 %arg,
1044 ); 1067 );
1045 1068
1046 $self->{title} &&= new CFClient::UI::Label 1069 $self->{title} = new CFClient::UI::Label
1047 align => 0, 1070 align => 0,
1048 valign => 1, 1071 valign => 1,
1049 text => $self->{title}, 1072 text => $title,
1050 fontsize => $self->{border}; 1073 fontsize => $self->{border}
1074 if defined $title;
1051 1075
1052 $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};
1053} 1084}
1054 1085
1055sub border { 1086sub border {
1056 int $_[0]{border} * $::FONTSIZE 1087 int $_[0]{border} * $::FONTSIZE
1057} 1088}
1058 1089
1059sub size_request { 1090sub size_request {
1060 my ($self) = @_; 1091 my ($self) = @_;
1092
1093 $self->{title}->size_request
1094 if $self->{title};
1061 1095
1062 my ($w, $h) = $self->SUPER::size_request; 1096 my ($w, $h) = $self->SUPER::size_request;
1063 1097
1064 ( 1098 (
1065 $w + $self->border * 2, 1099 $w + $self->border * 2,
1068} 1102}
1069 1103
1070sub size_allocate { 1104sub size_allocate {
1071 my ($self, $w, $h) = @_; 1105 my ($self, $w, $h) = @_;
1072 1106
1107 if ($self->{title}) {
1108 $self->{title}{w} = $w;
1109 $self->{title}{h} = $h;
1110 $self->{title}->size_allocate ($w, $h);
1111 }
1112
1113 my $border = $self->border;
1114
1073 $h -= List::Util::max 0, $self->border * 2; 1115 $h -= List::Util::max 0, $border * 2;
1074 $w -= List::Util::max 0, $self->border * 2; 1116 $w -= List::Util::max 0, $border * 2;
1075 1117
1076 $self->{title}->configure ($self->border, int $self->border - $::FONTSIZE * 2, $w, int $::FONTSIZE * 2)
1077 if $self->{title};
1078
1079 $self->child->configure ($self->border, $self->border, $w, $h); 1118 $self->child->configure ($border, $border, $w, $h);
1080} 1119}
1081 1120
1082sub button_down { 1121sub button_down {
1083 my ($self, $ev, $x, $y) = @_; 1122 my ($self, $ev, $x, $y) = @_;
1084 1123
1136} 1175}
1137 1176
1138sub _draw { 1177sub _draw {
1139 my ($self) = @_; 1178 my ($self) = @_;
1140 1179
1180 my $child = $self->{children}[0];
1181
1141 my ($w, $h ) = ($self->{w}, $self->{h}); 1182 my ($w, $h ) = ($self->{w}, $self->{h});
1142 my ($cw, $ch) = ($self->child->{w}, $self->child->{h}); 1183 my ($cw, $ch) = ($child->{w}, $child->{h});
1143 1184
1144 glEnable GL_TEXTURE_2D; 1185 glEnable GL_TEXTURE_2D;
1145 glTexEnv GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE; 1186 glTexEnv GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE;
1146 1187
1147 my $border = $self->border; 1188 my $border = $self->border;
1162 $bg->draw_quad_alpha ($border, $border, $cw, $ch); 1203 $bg->draw_quad_alpha ($border, $border, $cw, $ch);
1163 } 1204 }
1164 1205
1165 glDisable GL_TEXTURE_2D; 1206 glDisable GL_TEXTURE_2D;
1166 1207
1167 $self->{title}->draw if $self->{title};
1168
1169 $self->child->draw; 1208 $child->draw;
1209
1210 if ($self->{title}) {
1211 glTranslate 0, $border - $self->{h};
1212 $self->{title}->_draw;
1213 }
1170} 1214}
1171 1215
1172############################################################################# 1216#############################################################################
1173 1217
1174package CFClient::UI::Table; 1218package CFClient::UI::Table;
1522} 1566}
1523 1567
1524sub size_allocate { 1568sub size_allocate {
1525 my ($self, $w, $h) = @_; 1569 my ($self, $w, $h) = @_;
1526 1570
1571 delete $self->{ox};
1572
1527 delete $self->{texture}; 1573 delete $self->{texture}
1574 unless $w >= $self->{req_w} && $self->{old_w} >= $self->{req_w};
1528} 1575}
1529 1576
1530sub set_fontsize { 1577sub set_fontsize {
1531 my ($self, $fontsize) = @_; 1578 my ($self, $fontsize) = @_;
1532 1579
1547 $self->{layout}->set_width ($self->{w}); 1594 $self->{layout}->set_width ($self->{w});
1548 $self->{layout}->set_ellipsise ($self->{ellipsise}); 1595 $self->{layout}->set_ellipsise ($self->{ellipsise});
1549 $self->{layout}->set_single_paragraph_mode ($self->{ellipsise}); 1596 $self->{layout}->set_single_paragraph_mode ($self->{ellipsise});
1550 $self->{layout}->set_height ($self->{fontsize} * $::FONTSIZE); 1597 $self->{layout}->set_height ($self->{fontsize} * $::FONTSIZE);
1551 1598
1552 my $tex = new_from_layout CFClient::Texture $self->{layout}; 1599 new_from_layout CFClient::Texture $self->{layout}
1600 };
1553 1601
1602 unless (exists $self->{ox}) {
1554 $self->{ox} = int ($self->{align} < 0 ? $self->{padding_x} 1603 $self->{ox} = int ($self->{align} < 0 ? $self->{padding_x}
1555 : $self->{align} > 0 ? $self->{w} - $tex->{w} - $self->{padding_x} 1604 : $self->{align} > 0 ? $self->{w} - $tex->{w} - $self->{padding_x}
1556 : ($self->{w} - $tex->{w}) * 0.5); 1605 : ($self->{w} - $tex->{w}) * 0.5);
1557 1606
1558 $self->{oy} = int ($self->{valign} < 0 ? $self->{padding_y} 1607 $self->{oy} = int ($self->{valign} < 0 ? $self->{padding_y}
1559 : $self->{valign} > 0 ? $self->{h} - $tex->{h} - $self->{padding_y} 1608 : $self->{valign} > 0 ? $self->{h} - $tex->{h} - $self->{padding_y}
1560 : ($self->{h} - $tex->{h}) * 0.5); 1609 : ($self->{h} - $tex->{h}) * 0.5);
1561
1562 $tex
1563 }; 1610 };
1564 1611
1565 glEnable GL_TEXTURE_2D; 1612 glEnable GL_TEXTURE_2D;
1566 glTexEnv GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE; 1613 glTexEnv GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE;
1567 1614
2776 2823
2777 $self->{timer}->cancel 2824 $self->{timer}->cancel
2778 if $self->{timer}; 2825 if $self->{timer};
2779 2826
2780 $self->SUPER::DESTROY; 2827 $self->SUPER::DESTROY;
2781}
2782
2783#############################################################################
2784
2785package CFClient::UI::Inventory;
2786
2787our @ISA = CFClient::UI::ScrolledWindow::;
2788
2789sub new {
2790 my $class = shift;
2791
2792 my $self = $class->SUPER::new (
2793 scrolled => (new CFClient::UI::Table col_expand => [0, 1, 0]),
2794 @_,
2795 );
2796
2797 $self
2798}
2799
2800sub set_items {
2801 my ($self, $items) = @_;
2802
2803 $self->{scrolled}->clear;
2804 return unless $items;
2805
2806 my @items = sort {
2807 ($a->{type} <=> $b->{type})
2808 or ($a->{name} cmp $b->{name})
2809 } @$items;
2810
2811 $self->{real_items} = \@items;
2812
2813 my $row = 0;
2814 for my $item (@items) {
2815 CFClient::Item::update_widgets $item;
2816
2817 $self->{scrolled}->add (0, $row, $item->{face_widget});
2818 $self->{scrolled}->add (1, $row, $item->{desc_widget});
2819 $self->{scrolled}->add (2, $row, $item->{weight_widget});
2820
2821 $row++;
2822 }
2823} 2828}
2824 2829
2825############################################################################# 2830#############################################################################
2826 2831
2827package CFClient::UI::Menu; 2832package CFClient::UI::Menu;
3004 $self->SUPER::reconfigure; 3009 $self->SUPER::reconfigure;
3005} 3010}
3006 3011
3007############################################################################# 3012#############################################################################
3008 3013
3009package CFClient::UI::Root; 3014package CFClient::UI::Inventory;
3010 3015
3011our @ISA = CFClient::UI::Container::; 3016our @ISA = CFClient::UI::ScrolledWindow::;
3012
3013use CFClient::OpenGL;
3014 3017
3015sub new { 3018sub new {
3016 my $class = shift; 3019 my $class = shift;
3017 3020
3018 my $self = $class->SUPER::new ( 3021 my $self = $class->SUPER::new (
3019 visible => 1, 3022 scrolled => (new CFClient::UI::Table col_expand => [0, 1, 0]),
3020 @_, 3023 @_,
3021 ); 3024 );
3022 3025
3023 Scalar::Util::weaken ($self->{root} = $self);
3024
3025 $self 3026 $self
3026} 3027}
3027 3028
3028sub size_request { 3029sub set_items {
3029 my ($self) = @_; 3030 my ($self, $items) = @_;
3030 3031
3031 ($self->{w}, $self->{h}) 3032 $self->{scrolled}->clear;
3032} 3033 return unless $items;
3033 3034
3034sub _to_pixel { 3035 my @items = sort {
3035 my ($coord, $size, $max) = @_; 3036 ($a->{type} <=> $b->{type})
3037 or ($a->{name} cmp $b->{name})
3038 } @$items;
3036 3039
3037 $coord = 3040 $self->{real_items} = \@items;
3038 $coord eq "center" ? ($max - $size) * 0.5
3039 : $coord eq "max" ? $max
3040 : $coord;
3041 3041
3042 $coord = 0 if $coord < 0; 3042 my $row = 0;
3043 $coord = $max - $size if $coord > $max - $size; 3043 for my $item (@items) {
3044 CFClient::Item::update_widgets $item;
3044 3045
3045 int $coord + 0.5 3046 $self->{scrolled}->add (0, $row, $item->{face_widget});
3046} 3047 $self->{scrolled}->add (1, $row, $item->{desc_widget});
3048 $self->{scrolled}->add (2, $row, $item->{weight_widget});
3047 3049
3048sub size_allocate { 3050 $row++;
3049 my ($self, $w, $h) = @_;
3050
3051 for my $child ($self->children) {
3052 my ($X, $Y, $W, $H) = @$child{qw(x y req_w req_h)};
3053
3054 $X = $child->{force_x} if exists $child->{force_x};
3055 $Y = $child->{force_y} if exists $child->{force_y};
3056
3057 $X = _to_pixel $X, $W, $self->{w};
3058 $Y = _to_pixel $Y, $H, $self->{h};
3059
3060 $child->configure ($X, $Y, $W, $H);
3061 } 3051 }
3062}
3063
3064sub coord2local {
3065 my ($self, $x, $y) = @_;
3066
3067 ($x, $y)
3068}
3069
3070sub coord2global {
3071 my ($self, $x, $y) = @_;
3072
3073 ($x, $y)
3074}
3075
3076sub update {
3077 my ($self) = @_;
3078
3079 $::WANT_REFRESH++;
3080}
3081
3082sub add {
3083 my ($self, @children) = @_;
3084
3085 $_->{is_toplevel} = 1
3086 for @children;
3087
3088 $self->SUPER::add (@children);
3089}
3090
3091sub remove {
3092 my ($self, @children) = @_;
3093
3094 $self->SUPER::remove (@children);
3095
3096 delete $self->{is_toplevel}
3097 for @children;
3098
3099 while (@children) {
3100 my $w = pop @children;
3101 push @children, $w->children;
3102 $w->set_invisible;
3103 }
3104}
3105
3106sub on_refresh {
3107 my ($self, $id, $cb) = @_;
3108
3109 $self->{refresh_hook}{$id} = $cb;
3110}
3111
3112sub on_post_alloc {
3113 my ($self, $id, $cb) = @_;
3114
3115 $self->{post_alloc_hook}{$id} = $cb;
3116}
3117
3118sub draw {
3119 my ($self) = @_;
3120
3121 while ($self->{refresh_hook}) {
3122 $_->()
3123 for values %{delete $self->{refresh_hook}};
3124 }
3125
3126 if ($self->{realloc}) {
3127 my @queue;
3128
3129 while () {
3130 if ($self->{realloc}) {
3131 #TODO use array-of-depth approach
3132
3133 use sort 'stable';
3134
3135 @queue = sort { $a->{visible} <=> $b->{visible} }
3136 @queue, values %{delete $self->{realloc}};
3137 }
3138
3139 my $widget = pop @queue || last;
3140
3141 $widget->{visible} or last; # do not resize invisible widgets
3142
3143 my ($w, $h) = $widget->size_request;
3144
3145 $w = List::Util::max $widget->{min_w}, $w + $widget->{padding_x} * 2;
3146 $h = List::Util::max $widget->{min_h}, $h + $widget->{padding_y} * 2;
3147
3148 $w = $widget->{force_w} if exists $widget->{force_w};
3149 $h = $widget->{force_h} if exists $widget->{force_h};
3150
3151 if ($widget->{req_w} != $w || $widget->{req_h} != $h
3152 || delete $widget->{force_realloc}) {
3153 $widget->{req_w} = $w;
3154 $widget->{req_h} = $h;
3155
3156 $self->{size_alloc}{$widget+0} = $widget;
3157
3158 if (my $parent = $widget->{parent}) {
3159 $self->{realloc}{$parent+0} = $parent;
3160 #unshift @queue, $parent;
3161 $parent->{force_size_alloc} = 1;
3162 $self->{size_alloc}{$parent+0} = $parent;
3163 }
3164 }
3165
3166 delete $self->{realloc}{$widget+0};
3167 }
3168 }
3169
3170 while (my $size_alloc = delete $self->{size_alloc}) {
3171 my @queue = sort { $b->{visible} <=> $a->{visible} }
3172 values %$size_alloc;
3173
3174 while () {
3175 my $widget = pop @queue || last;
3176
3177 my ($w, $h) = @$widget{qw(alloc_w alloc_h)};
3178
3179 $w = 0 if $w < 0;
3180 $h = 0 if $h < 0;
3181
3182 $w = int $w + 0.5;
3183 $h = int $h + 0.5;
3184
3185 if ($widget->{w} != $w || $widget->{h} != $h || delete $widget->{force_size_alloc}) {
3186 $widget->{w} = $w;
3187 $widget->{h} = $h;
3188
3189 $widget->emit (size_allocate => $w, $h);
3190 }
3191 }
3192 }
3193
3194 while ($self->{post_alloc_hook}) {
3195 $_->()
3196 for values %{delete $self->{post_alloc_hook}};
3197 }
3198
3199
3200 glViewport 0, 0, $::WIDTH, $::HEIGHT;
3201 glClearColor +($::CFG->{fow_intensity}) x 3, 1;
3202 glClear GL_COLOR_BUFFER_BIT;
3203
3204 glMatrixMode GL_PROJECTION;
3205 glLoadIdentity;
3206 glOrtho 0, $::WIDTH, $::HEIGHT, 0, -10000, 10000;
3207 glMatrixMode GL_MODELVIEW;
3208 glLoadIdentity;
3209
3210 $self->_draw;
3211} 3052}
3212 3053
3213############################################################################# 3054#############################################################################
3214 3055
3215package CFClient::UI::BindEditor; 3056package CFClient::UI::BindEditor;
3310 $rec = $::CONN->stop_record if $::CONN; 3151 $rec = $::CONN->stop_record if $::CONN;
3311 return unless ref $rec eq 'ARRAY'; 3152 return unless ref $rec eq 'ARRAY';
3312 $self->set_command_list ($rec); 3153 $self->set_command_list ($rec);
3313} 3154}
3314 3155
3156
3157sub ask_for_bind_and_commit {
3158 my ($self) = @_;
3159 $self->ask_for_bind (1);
3160}
3161
3315sub ask_for_bind { 3162sub ask_for_bind {
3316 my ($self, $commit) = @_; 3163 my ($self, $commit) = @_;
3317 3164
3318 CFClient::Binder::open_binding_dialog (sub { 3165 CFClient::Binder::open_binding_dialog (sub {
3319 my ($mod, $sym) = @_; 3166 my ($mod, $sym) = @_;
3321 $self->update_binding_widgets; 3168 $self->update_binding_widgets;
3322 $self->commit if $commit; 3169 $self->commit if $commit;
3323 }); 3170 });
3324} 3171}
3325 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
3326sub set_binding { 3178sub set_binding {
3327 my ($self, $mod, $sym, $cmds, $cb, $ccb) = @_; 3179 my ($self, $mod, $sym, $cmds, $cb, $ccb) = @_;
3328 3180
3329 $self->clear_command_list; 3181 $self->clear_command_list;
3330 $self->{recording} = 0; 3182 $self->{recording} = 0;
3335 3187
3336 $self->{binding_change} = $cb; 3188 $self->{binding_change} = $cb;
3337 $self->{binding_cancel} = $ccb; 3189 $self->{binding_cancel} = $ccb;
3338 3190
3339 $self->update_binding_widgets; 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);
3340} 3202}
3341 3203
3342sub update_binding_widgets { 3204sub update_binding_widgets {
3343 my ($self) = @_; 3205 my ($self) = @_;
3344 my ($mod, $sym, $cmds) = $self->get_binding; 3206 my ($mod, $sym, $cmds) = $self->get_binding;
3370 3232
3371 for (@$cmds) { 3233 for (@$cmds) {
3372 $self->{cmdbox}->add (my $hb = new CFClient::UI::HBox); 3234 $self->{cmdbox}->add (my $hb = new CFClient::UI::HBox);
3373 3235
3374 my $i = $idx; 3236 my $i = $idx;
3237 $hb->add (new CFClient::UI::Label text => $_);
3375 $hb->add (new CFClient::UI::Button 3238 $hb->add (new CFClient::UI::Button
3376 text => "delete", 3239 text => "delete",
3377 tooltip => "Deletes the action from the record", 3240 tooltip => "Deletes the action from the record",
3378 on_activate => sub { 3241 on_activate => sub {
3379 $self->{cmdbox}->remove ($hb); 3242 $self->{cmdbox}->remove ($hb);
3380 $cmds->[$i] = undef; 3243 $cmds->[$i] = undef;
3381 }); 3244 });
3382 3245
3383 $hb->add (new CFClient::UI::Label text => $_);
3384 3246
3385 $idx++ 3247 $idx++
3386 } 3248 }
3387} 3249}
3388 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
3310package CFClient::UI::Root;
3311
3312our @ISA = CFClient::UI::Container::;
3313
3314use CFClient::OpenGL;
3315
3316sub new {
3317 my $class = shift;
3318
3319 my $self = $class->SUPER::new (
3320 visible => 1,
3321 @_,
3322 );
3323
3324 Scalar::Util::weaken ($self->{root} = $self);
3325
3326 $self
3327}
3328
3329sub size_request {
3330 my ($self) = @_;
3331
3332 ($self->{w}, $self->{h})
3333}
3334
3335sub _to_pixel {
3336 my ($coord, $size, $max) = @_;
3337
3338 $coord =
3339 $coord eq "center" ? ($max - $size) * 0.5
3340 : $coord eq "max" ? $max
3341 : $coord;
3342
3343 $coord = 0 if $coord < 0;
3344 $coord = $max - $size if $coord > $max - $size;
3345
3346 int $coord + 0.5
3347}
3348
3349sub size_allocate {
3350 my ($self, $w, $h) = @_;
3351
3352 for my $child ($self->children) {
3353 my ($X, $Y, $W, $H) = @$child{qw(x y req_w req_h)};
3354
3355 $X = $child->{force_x} if exists $child->{force_x};
3356 $Y = $child->{force_y} if exists $child->{force_y};
3357
3358 $X = _to_pixel $X, $W, $self->{w};
3359 $Y = _to_pixel $Y, $H, $self->{h};
3360
3361 $child->configure ($X, $Y, $W, $H);
3362 }
3363}
3364
3365sub coord2local {
3366 my ($self, $x, $y) = @_;
3367
3368 ($x, $y)
3369}
3370
3371sub coord2global {
3372 my ($self, $x, $y) = @_;
3373
3374 ($x, $y)
3375}
3376
3377sub update {
3378 my ($self) = @_;
3379
3380 $::WANT_REFRESH++;
3381}
3382
3383sub add {
3384 my ($self, @children) = @_;
3385
3386 $_->{is_toplevel} = 1
3387 for @children;
3388
3389 $self->SUPER::add (@children);
3390}
3391
3392sub remove {
3393 my ($self, @children) = @_;
3394
3395 $self->SUPER::remove (@children);
3396
3397 delete $self->{is_toplevel}
3398 for @children;
3399
3400 while (@children) {
3401 my $w = pop @children;
3402 push @children, $w->children;
3403 $w->set_invisible;
3404 }
3405}
3406
3407sub on_refresh {
3408 my ($self, $id, $cb) = @_;
3409
3410 $self->{refresh_hook}{$id} = $cb;
3411}
3412
3413sub on_post_alloc {
3414 my ($self, $id, $cb) = @_;
3415
3416 $self->{post_alloc_hook}{$id} = $cb;
3417}
3418
3419sub draw {
3420 my ($self) = @_;
3421
3422 while ($self->{refresh_hook}) {
3423 $_->()
3424 for values %{delete $self->{refresh_hook}};
3425 }
3426
3427 if ($self->{realloc}) {
3428 my %queue;
3429 my @queue;
3430 my $widget;
3431
3432 outer:
3433 while () {
3434 if (my $realloc = delete $self->{realloc}) {
3435 for $widget (values %$realloc) {
3436 $widget->{visible} or next; # do not resize invisible widgets
3437
3438 $queue{$widget+0}++ and next; # duplicates are common
3439
3440 push @{ $queue[$widget->{visible}] }, $widget;
3441 }
3442 }
3443
3444 while () {
3445 @queue or last outer;
3446
3447 $widget = pop @{ $queue[-1] || [] }
3448 and last;
3449
3450 pop @queue;
3451 }
3452
3453 delete $queue{$widget+0};
3454
3455 my ($w, $h) = $widget->size_request;
3456
3457 $w = List::Util::max $widget->{min_w}, $w + $widget->{padding_x} * 2;
3458 $h = List::Util::max $widget->{min_h}, $h + $widget->{padding_y} * 2;
3459
3460 $w = $widget->{force_w} if exists $widget->{force_w};
3461 $h = $widget->{force_h} if exists $widget->{force_h};
3462
3463 if ($widget->{req_w} != $w || $widget->{req_h} != $h
3464 || delete $widget->{force_realloc}) {
3465 $widget->{req_w} = $w;
3466 $widget->{req_h} = $h;
3467
3468 $self->{size_alloc}{$widget+0} = $widget;
3469
3470 if (my $parent = $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};
3480 }
3481 }
3482
3483 while (my $size_alloc = delete $self->{size_alloc}) {
3484 my @queue = sort { $b->{visible} <=> $a->{visible} }
3485 values %$size_alloc;
3486
3487 while () {
3488 my $widget = pop @queue || last;
3489
3490 my ($w, $h) = @$widget{qw(alloc_w alloc_h)};
3491
3492 $w = 0 if $w < 0;
3493 $h = 0 if $h < 0;
3494
3495 $w = int $w + 0.5;
3496 $h = int $h + 0.5;
3497
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};
3501
3502 $widget->{w} = $w;
3503 $widget->{h} = $h;
3504
3505 $widget->emit (size_allocate => $w, $h);
3506 }
3507 }
3508 }
3509
3510 while ($self->{post_alloc_hook}) {
3511 $_->()
3512 for values %{delete $self->{post_alloc_hook}};
3513 }
3514
3515
3516 glViewport 0, 0, $::WIDTH, $::HEIGHT;
3517 glClearColor +($::CFG->{fow_intensity}) x 3, 1;
3518 glClear GL_COLOR_BUFFER_BIT;
3519
3520 glMatrixMode GL_PROJECTION;
3521 glLoadIdentity;
3522 glOrtho 0, $::WIDTH, $::HEIGHT, 0, -10000, 10000;
3523 glMatrixMode GL_MODELVIEW;
3524 glLoadIdentity;
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
3533 $self->_draw;
3534}
3389 3535
3390############################################################################# 3536#############################################################################
3391 3537
3392package CFClient::UI; 3538package CFClient::UI;
3393 3539

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines