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.305 by root, Sun Jun 18 17:13:12 2006 UTC vs.
Revision 1.328 by root, Sat Jul 22 13:43:05 2006 UTC

82} 82}
83 83
84sub feed_sdl_button_down_event { 84sub feed_sdl_button_down_event {
85 my ($ev) = @_; 85 my ($ev) = @_;
86 my ($x, $y) = ($ev->{x}, $ev->{y}); 86 my ($x, $y) = ($ev->{x}, $ev->{y});
87
88 warn "button down $ev->{button}\n";#d#
87 89
88 if (!$BUTTON_STATE) { 90 if (!$BUTTON_STATE) {
89 my $widget = $ROOT->find_widget ($x, $y); 91 my $widget = $ROOT->find_widget ($x, $y);
90 92
91 $GRAB = $widget; 93 $GRAB = $widget;
335sub size_request { 337sub size_request {
336 require Carp; 338 require Carp;
337 Carp::confess "size_request is abstract"; 339 Carp::confess "size_request is abstract";
338} 340}
339 341
342sub baseline_shift {
343 0
344}
345
340sub configure { 346sub configure {
341 my ($self, $x, $y, $w, $h) = @_; 347 my ($self, $x, $y, $w, $h) = @_;
342 348
343 if ($self->{aspect}) { 349 if ($self->{aspect}) {
344 my ($ow, $oh) = ($w, $h); 350 my ($ow, $oh) = ($w, $h);
419 my ($self) = @_; 425 my ($self) = @_;
420 426
421 return if $FOCUS == $self; 427 return if $FOCUS == $self;
422 return unless $self->{can_focus}; 428 return unless $self->{can_focus};
423 429
424 my $focus = $FOCUS; $FOCUS = $self; 430 $FOCUS = $self;
425 431
426 $focus->update if $focus; 432 $self->update;
427 $FOCUS->update;
428 433
429 0 434 0
430} 435}
431 436
432sub invoke_focus_out { 437sub invoke_focus_out {
433 my ($self) = @_; 438 my ($self) = @_;
434 439
435 return unless $FOCUS == $self; 440 return unless $FOCUS == $self;
436 441
437 my $focus = $FOCUS; undef $FOCUS; 442 undef $FOCUS;
438 443
439 $focus->update if $focus; #? 444 $self->update;
440 445
441 $::MAPWIDGET->grab_focus #d# focus mapwidget if no other widget has focus 446 $::MAPWIDGET->grab_focus #d# focus mapwidget if no other widget has focus
442 unless $FOCUS; 447 unless $FOCUS;
443 448
444 0 449 0
445} 450}
446 451
447sub grab_focus { 452sub grab_focus {
448 my ($self) = @_; 453 my ($self) = @_;
449 454
455 $FOCUS->emit ("focus_out") if $FOCUS;
450 $self->emit ("focus_in"); 456 $self->emit ("focus_in");
451} 457}
452 458
453sub invoke_mouse_motion { 1 } 459sub invoke_mouse_motion { 0 }
454sub invoke_button_up { 1 } 460sub invoke_button_up { 0 }
455sub invoke_key_down { 1 } 461sub invoke_key_down { 0 }
456sub invoke_key_up { 1 } 462sub invoke_key_up { 0 }
457 463
458sub invoke_button_down { 464sub invoke_button_down {
459 my ($self, $ev, $x, $y) = @_; 465 my ($self, $ev, $x, $y) = @_;
460 466
461 $self->grab_focus; 467 $self->grab_focus;
462 468
469 warn "button down $ev->{button} $x $y\n";#d#
470
463 1 471 0
464} 472}
465 473
466sub connect { 474sub connect {
467 my ($self, $signal, $cb) = @_; 475 my ($self, $signal, $cb) = @_;
468 476
470} 478}
471 479
472sub emit { 480sub emit {
473 my ($self, $signal, @args) = @_; 481 my ($self, $signal, @args) = @_;
474 482
483 #d##TODO# stop propagating at first true, do not use sum
475 (List::Util::sum +(map $_->($self, @args), @{$self->{signal_cb}{$signal} || []}), # before 484 (List::Util::sum map $_->($self, @args), @{$self->{signal_cb}{$signal} || []}) # before
476 ($self->can ("invoke_$signal") || sub { 1 })->($self, @args)) # closure 485 || ($self->can ("invoke_$signal") || sub { 1 })->($self, @args) # closure
477 || ($self->{parent} && $self->{parent}->emit ($signal, @args)) # parent 486 || ($self->{parent} && $self->{parent}->emit ($signal, @args)) # parent
478} 487}
479 488
480sub find_widget { 489sub find_widget {
481 my ($self, $x, $y) = @_; 490 my ($self, $x, $y) = @_;
482 491
534 return unless $self->{h} && $self->{w}; 543 return unless $self->{h} && $self->{w};
535 544
536 # update screen rectangle 545 # update screen rectangle
537 local $draw_x = $draw_x + $self->{x}; 546 local $draw_x = $draw_x + $self->{x};
538 local $draw_y = $draw_y + $self->{y}; 547 local $draw_y = $draw_y + $self->{y};
539 local $draw_w = $draw_x + $self->{w};
540 local $draw_h = $draw_y + $self->{h};
541 548
542 # skip widgets that are entirely outside the drawing area 549 # skip widgets that are entirely outside the drawing area
543 return if ($draw_x + $self->{w} < 0) || ($draw_x >= $draw_w) 550 return if ($draw_x + $self->{w} < 0) || ($draw_x >= $draw_w)
544 || ($draw_y + $self->{h} < 0) || ($draw_y >= $draw_h); 551 || ($draw_y + $self->{h} < 0) || ($draw_y >= $draw_h);
545 552
584} 591}
585 592
586sub DESTROY { 593sub DESTROY {
587 my ($self) = @_; 594 my ($self) = @_;
588 595
596 return if CFClient::in_destruct;
597
589 delete $WIDGET{$self+0}; 598 delete $WIDGET{$self+0};
590 599
591 eval { $self->destroy }; 600 eval { $self->destroy };
592 warn "exception during widget destruction: $@" if $@ & $@ != /during global destruction/; 601 warn "exception during widget destruction: $@" if $@ & $@ != /during global destruction/;
593} 602}
983 $self->add ($child) if $child; 992 $self->add ($child) if $child;
984 993
985 $self 994 $self
986} 995}
987 996
997#TODO# update range on size_allocate depending on child
998
988sub add { 999sub add {
989 my ($self, $widget) = @_; 1000 my ($self, $widget) = @_;
990 1001
991 $self->{vp}->add ($self->{child} = $widget); 1002 $self->{vp}->add ($self->{child} = $widget);
992} 1003}
993 1004
1005sub invoke_button_down {
1006 my ($self, $ev) = @_;
1007
1008 warn "button down $ev->{button}\n";#d#
1009
1010 0
1011}
1012
1013sub update_slider {
1014 my ($self) = @_;
1015
1016 $self->{slider}->set_range ([$self->{slider}{range}[0], 0, $self->{vp}->child->{h}, $self->{vp}{h}, 1]);
1017}
1018
994sub update { 1019sub update {
995 my ($self) = @_; 1020 my ($self) = @_;
996 1021
997 $self->SUPER::update; 1022 $self->SUPER::update;
998 1023
999 # todo: overwrite size_allocate of child 1024 $self->update_slider;
1000 my $child = $self->{vp}->child;
1001 $self->{slider}->set_range ([$self->{slider}{range}[0], 0, $child->{h}, $self->{vp}{h}, 1]);
1002} 1025}
1003 1026
1004sub invoke_size_allocate { 1027sub invoke_size_allocate {
1005 my ($self, $w, $h) = @_; 1028 my ($self, $w, $h) = @_;
1006 1029
1007 my $child = $self->{vp}->child; 1030 $self->update_slider;
1008 $self->{slider}->set_range ([$self->{slider}{range}[0], 0, $child->{h}, $self->{vp}{h}, 1]);
1009 1031
1010 $self->SUPER::invoke_size_allocate ($w, $h) 1032 $self->SUPER::invoke_size_allocate ($w, $h)
1011} 1033}
1012
1013#TODO# update range on size_allocate depending on child
1014# update viewport offset on scroll
1015 1034
1016############################################################################# 1035#############################################################################
1017 1036
1018package CFClient::UI::Frame; 1037package CFClient::UI::Frame;
1019 1038
1075 my $self = $class->SUPER::new ( 1094 my $self = $class->SUPER::new (
1076 bg => [1, 1, 1, 1], 1095 bg => [1, 1, 1, 1],
1077 border_bg => [1, 1, 1, 1], 1096 border_bg => [1, 1, 1, 1],
1078 border => 0.6, 1097 border => 0.6,
1079 can_events => 1, 1098 can_events => 1,
1080 min_w => 16, 1099 min_w => 64,
1081 min_h => 16, 1100 min_h => 32,
1082 %arg, 1101 %arg,
1083 ); 1102 );
1084 1103
1085 $self->{title_widget} = new CFClient::UI::Label 1104 $self->{title_widget} = new CFClient::UI::Label
1086 align => 0, 1105 align => 0,
1090 if exists $self->{title}; 1109 if exists $self->{title};
1091 1110
1092 if ($self->{has_close_button}) { 1111 if ($self->{has_close_button}) {
1093 $self->{close_button} = 1112 $self->{close_button} =
1094 new CFClient::UI::ImageButton 1113 new CFClient::UI::ImageButton
1095 image => 'x1_close.png', 1114 path => 'x1_close.png',
1096 on_activate => sub { $self->hide }; 1115 on_activate => sub { $self->emit ("delete") };
1097 1116
1098 $self->CFClient::UI::Container::add ($self->{close_button}); 1117 $self->CFClient::UI::Container::add ($self->{close_button});
1099 } 1118 }
1100 1119
1101 $self 1120 $self
1147 $self->child->configure ($border, $border, $w, $h); 1166 $self->child->configure ($border, $border, $w, $h);
1148 1167
1149 $self->{close_button}->configure ($self->{w} - $border, 0, $border, $border) 1168 $self->{close_button}->configure ($self->{w} - $border, 0, $border, $border)
1150 if $self->{close_button}; 1169 if $self->{close_button};
1151 1170
1171 1
1172}
1173
1174sub invoke_delete {
1175 my ($self) = @_;
1176
1177 $self->hide;
1178
1152 1 1179 1
1153} 1180}
1154 1181
1155sub invoke_button_down { 1182sub invoke_button_down {
1156 my ($self, $ev, $x, $y) = @_; 1183 my ($self, $ev, $x, $y) = @_;
1437 1464
1438sub invoke_size_allocate { 1465sub invoke_size_allocate {
1439 my ($self, $w, $h) = @_; 1466 my ($self, $w, $h) = @_;
1440 1467
1441 my $space = $self->{vertical} ? $h : $w; 1468 my $space = $self->{vertical} ? $h : $w;
1442 my $children = $self->{children}; 1469 my @children = $self->visible_children;
1443 1470
1444 my @req; 1471 my @req;
1445 1472
1446 if ($self->{homogeneous}) { 1473 if ($self->{homogeneous}) {
1447 @req = ($space / (@$children || 1)) x @$children; 1474 @req = ($space / (@children || 1)) x @children;
1448 } else { 1475 } else {
1449 @req = map $_->{$self->{vertical} ? "req_h" : "req_w"}, @$children; 1476 @req = map $_->{$self->{vertical} ? "req_h" : "req_w"}, @children;
1450 my $req = List::Util::sum @req; 1477 my $req = List::Util::sum @req;
1451 1478
1452 if ($req > $space) { 1479 if ($req > $space) {
1453 # ah well, not enough space 1480 # ah well, not enough space
1454 $_ *= $space / $req for @req; 1481 $_ *= $space / $req for @req;
1455 } else { 1482 } else {
1456 my $expand = (List::Util::sum map $_->{expand}, @$children) || 1; 1483 my $expand = (List::Util::sum map $_->{expand}, @children) || 1;
1457 1484
1458 $space = ($space - $req) / $expand; # remaining space to give away 1485 $space = ($space - $req) / $expand; # remaining space to give away
1459 1486
1460 $req[$_] += $space * $children->[$_]{expand} 1487 $req[$_] += $space * $children[$_]{expand}
1461 for 0 .. $#$children; 1488 for 0 .. $#children;
1462 } 1489 }
1463 } 1490 }
1464 1491
1465 CFClient::UI::harmonize \@req; 1492 CFClient::UI::harmonize \@req;
1466 1493
1467 my $pos = 0; 1494 my $pos = 0;
1468 for (0 .. $#$children) { 1495 for (0 .. $#children) {
1469 my $alloc = $req[$_]; 1496 my $alloc = $req[$_];
1470 $children->[$_]->configure ($self->{vertical} ? (0, $pos, $w, $alloc) : ($pos, 0, $alloc, $h)); 1497 $children[$_]->configure ($self->{vertical} ? (0, $pos, $w, $alloc) : ($pos, 0, $alloc, $h));
1471 1498
1472 $pos += $alloc; 1499 $pos += $alloc;
1473 } 1500 }
1474 1501
1475 1 1502 1
1578 my ($self, $text) = @_; 1605 my ($self, $text) = @_;
1579 1606
1580 return if $self->{text} eq "T$text"; 1607 return if $self->{text} eq "T$text";
1581 $self->{text} = "T$text"; 1608 $self->{text} = "T$text";
1582 1609
1583 $self->{layout} = new CFClient::Layout if $self->{layout}->is_rgba;
1584 $self->{layout}->set_text ($text); 1610 $self->{layout}->set_text ($text);
1585 1611
1586 delete $self->{size_req}; 1612 delete $self->{size_req};
1587 $self->realloc; 1613 $self->realloc;
1588 $self->update; 1614 $self->update;
1594 return if $self->{text} eq "M$markup"; 1620 return if $self->{text} eq "M$markup";
1595 $self->{text} = "M$markup"; 1621 $self->{text} = "M$markup";
1596 1622
1597 my $rgba = $markup =~ /span.*(?:foreground|background)/; 1623 my $rgba = $markup =~ /span.*(?:foreground|background)/;
1598 1624
1599 $self->{layout} = new CFClient::Layout $rgba if $self->{layout}->is_rgba != $rgba;
1600 $self->{layout}->set_markup ($markup); 1625 $self->{layout}->set_markup ($markup);
1601 1626
1602 delete $self->{size_req}; 1627 delete $self->{size_req};
1603 $self->realloc; 1628 $self->realloc;
1604 $self->update; 1629 $self->update;
1616 1641
1617 my ($w, $h) = $self->{layout}->size; 1642 my ($w, $h) = $self->{layout}->size;
1618 1643
1619 if (exists $self->{template}) { 1644 if (exists $self->{template}) {
1620 $self->{template}->set_font ($self->{font}) if $self->{font}; 1645 $self->{template}->set_font ($self->{font}) if $self->{font};
1646 $self->{template}->set_width ($self->{max_w} || -1);
1621 $self->{template}->set_height ($self->{fontsize} * $::FONTSIZE); 1647 $self->{template}->set_height ($self->{fontsize} * $::FONTSIZE);
1622 1648
1623 my ($w2, $h2) = $self->{template}->size; 1649 my ($w2, $h2) = $self->{template}->size;
1624 1650
1625 $w = List::Util::max $w, $w2; 1651 $w = List::Util::max $w, $w2;
1630 }; 1656 };
1631 1657
1632 @{ $self->{size_req} } 1658 @{ $self->{size_req} }
1633} 1659}
1634 1660
1661sub baseline_shift {
1662 $_[0]{layout}->descent
1663}
1664
1635sub invoke_size_allocate { 1665sub invoke_size_allocate {
1636 my ($self, $w, $h) = @_; 1666 my ($self, $w, $h) = @_;
1637 1667
1638 delete $self->{ox}; 1668 delete $self->{ox};
1639 1669
1645 1675
1646sub set_fontsize { 1676sub set_fontsize {
1647 my ($self, $fontsize) = @_; 1677 my ($self, $fontsize) = @_;
1648 1678
1649 $self->{fontsize} = $fontsize; 1679 $self->{fontsize} = $fontsize;
1680 delete $self->{size_req};
1650 delete $self->{texture}; 1681 delete $self->{texture};
1651 1682
1652 $self->realloc; 1683 $self->realloc;
1653} 1684}
1654 1685
1655sub reconfigure { 1686sub reconfigure {
1656 my ($self) = @_; 1687 my ($self) = @_;
1657 1688
1658 delete $self->{size_req}; 1689 delete $self->{size_req};
1690 delete $self->{texture};
1659 1691
1660 $self->SUPER::reconfigure; 1692 $self->SUPER::reconfigure;
1661} 1693}
1662 1694
1663sub _draw { 1695sub _draw {
1664 my ($self) = @_; 1696 my ($self) = @_;
1665 1697
1666 $self->SUPER::_draw; # draw background, if applicable 1698 $self->SUPER::_draw; # draw background, if applicable
1667 1699
1668 my $tex = $self->{texture} ||= do { 1700 my $size = $self->{texture} ||= do {
1669 $self->{layout}->set_foreground (@{$self->{fg}}); 1701 $self->{layout}->set_foreground (@{$self->{fg}});
1670 $self->{layout}->set_font ($self->{font}) if $self->{font}; 1702 $self->{layout}->set_font ($self->{font}) if $self->{font};
1671 $self->{layout}->set_width ($self->{w}); 1703 $self->{layout}->set_width ($self->{w});
1672 $self->{layout}->set_ellipsise ($self->{ellipsise}); 1704 $self->{layout}->set_ellipsise ($self->{ellipsise});
1673 $self->{layout}->set_single_paragraph_mode ($self->{ellipsise}); 1705 $self->{layout}->set_single_paragraph_mode ($self->{ellipsise});
1674 $self->{layout}->set_height ($self->{fontsize} * $::FONTSIZE); 1706 $self->{layout}->set_height ($self->{fontsize} * $::FONTSIZE);
1675 1707
1676 new_from_layout CFClient::Texture $self->{layout} 1708 [$self->{layout}->size]
1677 }; 1709 };
1678 1710
1679 unless (exists $self->{ox}) { 1711 unless (exists $self->{ox}) {
1680 $self->{ox} = int ($self->{align} < 0 ? $self->{padding_x} 1712 $self->{ox} = int ($self->{align} < 0 ? $self->{padding_x}
1681 : $self->{align} > 0 ? $self->{w} - $tex->{w} - $self->{padding_x} 1713 : $self->{align} > 0 ? $self->{w} - $size->[0] - $self->{padding_x}
1682 : ($self->{w} - $tex->{w}) * 0.5); 1714 : ($self->{w} - $size->[0]) * 0.5);
1683 1715
1684 $self->{oy} = int ($self->{valign} < 0 ? $self->{padding_y} 1716 $self->{oy} = int ($self->{valign} < 0 ? $self->{padding_y}
1685 : $self->{valign} > 0 ? $self->{h} - $tex->{h} - $self->{padding_y} 1717 : $self->{valign} > 0 ? $self->{h} - $size->[1] - $self->{padding_y}
1686 : ($self->{h} - $tex->{h}) * 0.5); 1718 : ($self->{h} - $size->[1]) * 0.5);
1687 }; 1719 };
1688 1720
1689 glEnable GL_TEXTURE_2D;
1690
1691 my $w = List::Util::min $self->{w} + 4, $tex->{w}; 1721 my $w = List::Util::min $self->{w} + 4, $size->[0];
1692 my $h = List::Util::min $self->{h} + 2, $tex->{h}; 1722 my $h = List::Util::min $self->{h} + 2, $size->[1];
1693 1723
1694 if ($tex->{format} == GL_ALPHA) { 1724 $self->{layout}->render ($self->{ox}, $self->{oy});
1695 glTexEnv GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE;
1696 glColor @{$self->{fg}};
1697 $tex->draw_quad_alpha ($self->{ox}, $self->{oy}, $w, $h);
1698 } else {
1699 glTexEnv GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE;
1700 $tex->draw_quad_alpha_premultiplied ($self->{ox}, $self->{oy}, $w, $h);
1701 }
1702
1703 glDisable GL_TEXTURE_2D;
1704} 1725}
1705 1726
1706############################################################################# 1727#############################################################################
1707 1728
1708package CFClient::UI::EntryBase; 1729package CFClient::UI::EntryBase;
1819 1840
1820 my $idx = $self->{layout}->xy_to_index ($x, $y); 1841 my $idx = $self->{layout}->xy_to_index ($x, $y);
1821 1842
1822 # byte-index to char-index 1843 # byte-index to char-index
1823 my $text = $self->{text}; 1844 my $text = $self->{text};
1824 utf8::encode $text; 1845 utf8::encode $text; $text = substr $text, 0, $idx; utf8::decode $text;
1825 $self->{cursor} = length substr $text, 0, $idx; 1846 $self->{cursor} = length $text;
1826 1847
1827 $self->_set_text ($self->{text}); 1848 $self->_set_text ($self->{text});
1828 $self->update; 1849 $self->update;
1829 1850
1830 1 1851 1
1891 my $sym = $ev->{sym}; 1912 my $sym = $ev->{sym};
1892 1913
1893 if ($sym == 13) { 1914 if ($sym == 13) {
1894 unshift @{$self->{history}}, 1915 unshift @{$self->{history}},
1895 my $txt = $self->get_text; 1916 my $txt = $self->get_text;
1917
1896 $self->{history_pointer} = -1; 1918 $self->{history_pointer} = -1;
1897 $self->{history_saveback} = ''; 1919 $self->{history_saveback} = '';
1898 $self->emit (activate => $txt); 1920 $self->emit (activate => $txt);
1899 $self->update; 1921 $self->update;
1900 1922
2049 my ($self) = @_; 2071 my ($self) = @_;
2050 2072
2051 (6) x 2 2073 (6) x 2
2052} 2074}
2053 2075
2076sub toggle {
2077 my ($self) = @_;
2078
2079 $self->{state} = !$self->{state};
2080 $self->emit (changed => $self->{state});
2081 $self->update;
2082}
2083
2054sub invoke_button_down { 2084sub invoke_button_down {
2055 my ($self, $ev, $x, $y) = @_; 2085 my ($self, $ev, $x, $y) = @_;
2056 2086
2057 if ($x >= $self->{padding_x} && $x < $self->{w} - $self->{padding_x} 2087 if ($x >= $self->{padding_x} && $x < $self->{w} - $self->{padding_x}
2058 && $y >= $self->{padding_y} && $y < $self->{h} - $self->{padding_y}) { 2088 && $y >= $self->{padding_y} && $y < $self->{h} - $self->{padding_y}) {
2059 $self->{state} = !$self->{state}; 2089 $self->toggle;
2060 $self->emit (changed => $self->{state});
2061 } else { 2090 } else {
2062 return 0 2091 return 0
2063 } 2092 }
2064 2093
2065 1 2094 1
2090package CFClient::UI::Image; 2119package CFClient::UI::Image;
2091 2120
2092our @ISA = CFClient::UI::Base::; 2121our @ISA = CFClient::UI::Base::;
2093 2122
2094use CFClient::OpenGL; 2123use CFClient::OpenGL;
2095use Carp qw/confess/;
2096 2124
2097our %loaded_images; 2125our %texture_cache;
2098 2126
2099sub new { 2127sub new {
2100 my $class = shift; 2128 my $class = shift;
2101 2129
2102 my $self = $class->SUPER::new (can_events => 0, @_); 2130 my $self = $class->SUPER::new (
2131 can_events => 0,
2132 @_,
2133 );
2103 2134
2104 $self->{image} or confess "Image has 'image' not set. This is a fatal error!"; 2135 $self->{path} || $self->{tex}
2136 or Carp::croak "'path' or 'tex' attributes required";
2105 2137
2106 $loaded_images{$self->{image}} ||= 2138 $self->{tex} ||= $texture_cache{$self->{path}} ||=
2107 new_from_file CFClient::Texture CFClient::find_rcfile $self->{image}, mipmap => 1; 2139 new_from_file CFClient::Texture CFClient::find_rcfile $self->{path}, mipmap => 1;
2108 2140
2109 my $tex = $self->{tex} = $loaded_images{$self->{image}}; 2141 Scalar::Util::weaken $texture_cache{$self->{path}};
2110 2142
2111 Scalar::Util::weaken $loaded_images{$self->{image}}; 2143 $self->{aspect} ||= $self->{tex}{w} / $self->{tex}{h};
2112
2113 $self->{aspect} = $tex->{w} / $tex->{h};
2114 2144
2115 $self 2145 $self
2116} 2146}
2117 2147
2118sub size_request { 2148sub size_request {
2119 my ($self) = @_; 2149 my ($self) = @_;
2120 2150
2121 ($self->{tex}->{w}, $self->{tex}->{h}) 2151 ($self->{tex}{w}, $self->{tex}{h})
2122} 2152}
2123 2153
2124sub _draw { 2154sub _draw {
2125 my ($self) = @_; 2155 my ($self) = @_;
2126 2156
2235 my $ycut1 = max 0, min 1, $ycut; 2265 my $ycut1 = max 0, min 1, $ycut;
2236 my $ycut2 = max 0, min 1, $ycut - 1; 2266 my $ycut2 = max 0, min 1, $ycut - 1;
2237 2267
2238 my $h1 = $self->{h} * (1 - $ycut1); 2268 my $h1 = $self->{h} * (1 - $ycut1);
2239 my $h2 = $self->{h} * (1 - $ycut2); 2269 my $h2 = $self->{h} * (1 - $ycut2);
2270 my $h3 = $self->{h};
2271
2272 $_ = $_ * (284-4)/288 + 4/288 for ($h1, $h2, $h3);
2240 2273
2241 glEnable GL_BLEND; 2274 glEnable GL_BLEND;
2242 glBlendFuncSeparate GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, 2275 glBlendFuncSeparate GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA,
2243 GL_ONE, GL_ONE_MINUS_SRC_ALPHA; 2276 GL_ONE, GL_ONE_MINUS_SRC_ALPHA;
2244 glEnable GL_TEXTURE_2D; 2277 glEnable GL_TEXTURE_2D;
2263 2296
2264 if ($t3) { 2297 if ($t3) {
2265 glBindTexture GL_TEXTURE_2D, $t3->{name}; 2298 glBindTexture GL_TEXTURE_2D, $t3->{name};
2266 glBegin GL_QUADS; 2299 glBegin GL_QUADS;
2267 glTexCoord 0 , $t3->{t} * (1 - $ycut2); glVertex 0 , $h2; 2300 glTexCoord 0 , $t3->{t} * (1 - $ycut2); glVertex 0 , $h2;
2268 glTexCoord 0 , $t3->{t}; glVertex 0 , $self->{h}; 2301 glTexCoord 0 , $t3->{t}; glVertex 0 , $h3;
2269 glTexCoord $t3->{s}, $t3->{t}; glVertex $w, $self->{h}; 2302 glTexCoord $t3->{s}, $t3->{t}; glVertex $w, $h3;
2270 glTexCoord $t3->{s}, $t3->{t} * (1 - $ycut2); glVertex $w, $h2; 2303 glTexCoord $t3->{s}, $t3->{t} * (1 - $ycut2); glVertex $w, $h2;
2271 glEnd; 2304 glEnd;
2272 } 2305 }
2273 2306
2274 glDisable GL_BLEND; 2307 glDisable GL_BLEND;
2409 2442
2410 $self->SUPER::invoke_button_down ($ev, $x, $y); 2443 $self->SUPER::invoke_button_down ($ev, $x, $y);
2411 2444
2412 $self->{click} = [$self->{range}[0], $self->{vertical} ? $y : $x]; 2445 $self->{click} = [$self->{range}[0], $self->{vertical} ? $y : $x];
2413 2446
2414 $self->mouse_motion ($ev, $x, $y) 2447 $self->invoke_mouse_motion ($ev, $x, $y)
2415} 2448}
2416 2449
2417sub invoke_mouse_motion { 2450sub invoke_mouse_motion {
2418 my ($self, $ev, $x, $y) = @_; 2451 my ($self, $ev, $x, $y) = @_;
2419 2452
2543 can_events => 0, 2576 can_events => 0,
2544 indent => 0, 2577 indent => 0,
2545 #font => default_font 2578 #font => default_font
2546 @_, 2579 @_,
2547 2580
2548 layout => (new CFClient::Layout 1), 2581 layout => (new CFClient::Layout),
2549 par => [], 2582 par => [],
2550 height => 0, 2583 height => 0,
2551 children => [ 2584 children => [
2552 (new CFClient::UI::Empty expand => 1), 2585 (new CFClient::UI::Empty expand => 1),
2553 (new CFClient::UI::Slider vertical => 1), 2586 (new CFClient::UI::Slider vertical => 1),
2564 2597
2565 $self->{fontsize} = $fontsize; 2598 $self->{fontsize} = $fontsize;
2566 $self->reflow; 2599 $self->reflow;
2567} 2600}
2568 2601
2602sub size_request {
2603 my ($self) = @_;
2604
2605 my ($empty, $slider) = @{ $self->{children} };
2606
2607 local $self->{children} = [$empty, $slider];
2608 $self->SUPER::size_request
2609}
2610
2569sub invoke_size_allocate { 2611sub invoke_size_allocate {
2570 my ($self, $w, $h) = @_; 2612 my ($self, $w, $h) = @_;
2571 2613
2614 my ($empty, $slider, @other) = @{ $self->{children} };
2615 $_->configure (@$_{qw(x y req_w req_h)}) for @other;
2616
2572 $self->{layout}->set_font ($self->{font}) if $self->{font}; 2617 $self->{layout}->set_font ($self->{font}) if $self->{font};
2573 $self->{layout}->set_height ($self->{fontsize} * $::FONTSIZE); 2618 $self->{layout}->set_height ($self->{fontsize} * $::FONTSIZE);
2574 $self->{layout}->set_width ($self->{children}[0]{w}); 2619 $self->{layout}->set_width ($empty->{w});
2575 $self->{layout}->set_indent ($self->{fontsize} * $::FONTSIZE * $self->{indent}); 2620 $self->{layout}->set_indent ($self->{fontsize} * $::FONTSIZE * $self->{indent});
2576 2621
2577 $self->reflow; 2622 $self->reflow;
2578 2623
2624 local $self->{children} = [$empty, $slider];
2579 $self->SUPER::invoke_size_allocate ($w, $h) 2625 $self->SUPER::invoke_size_allocate ($w, $h)
2580} 2626}
2581 2627
2582sub text_size { 2628sub get_layout {
2583 my ($self, $text, $indent) = @_; 2629 my ($self, $para) = @_;
2584 2630
2585 my $layout = $self->{layout}; 2631 my $layout = $self->{layout};
2586 2632
2633 $layout->set_font ($self->{font}) if $self->{font};
2634 $layout->set_foreground (@{$para->{fg}});
2587 $layout->set_height ($self->{fontsize} * $::FONTSIZE); 2635 $layout->set_height ($self->{fontsize} * $::FONTSIZE);
2588 $layout->set_width ($self->{children}[0]{w} - $indent); 2636 $layout->set_width ($self->{children}[0]{w} - $para->{indent});
2589 $layout->set_indent ($self->{fontsize} * $::FONTSIZE * $self->{indent}); 2637 $layout->set_indent ($self->{fontsize} * $::FONTSIZE * $self->{indent});
2590 $layout->set_markup ($text); 2638 $layout->set_markup ($para->{markup});
2639
2640 $layout->set_shapes (
2641 map
2642 +(0, $_->baseline_shift +$_->{padding_y} - $_->{h}, $_->{w}, $_->{h}),
2643 @{$para->{widget}}
2591 2644 );
2645
2592 $layout->size 2646 $layout
2593} 2647}
2594 2648
2595sub reflow { 2649sub reflow {
2596 my ($self) = @_; 2650 my ($self) = @_;
2597 2651
2606 $self->{children}[1]->set_value ($offset); 2660 $self->{children}[1]->set_value ($offset);
2607} 2661}
2608 2662
2609sub clear { 2663sub clear {
2610 my ($self) = @_; 2664 my ($self) = @_;
2665
2666 my (undef, undef, @other) = @{ $self->{children} };
2667 $self->remove ($_) for @other;
2611 2668
2612 $self->{par} = []; 2669 $self->{par} = [];
2613 $self->{height} = 0; 2670 $self->{height} = 0;
2614 $self->{children}[1]->set_range ([0, 0, 0, 1, 1]); 2671 $self->{children}[1]->set_range ([0, 0, 0, 1, 1]);
2615} 2672}
2616 2673
2617sub add_paragraph { 2674sub add_paragraph {
2618 my ($self, $color, $text, $indent) = @_; 2675 my ($self, $color, $para, $indent) = @_;
2619 2676
2620 for my $line (split /\n/, $text) { 2677 my ($text, @w) = ref $para ? @$para : $para;
2621 my ($w, $h) = $self->text_size ($line); 2678
2622 $self->{height} += $h; 2679 $para = {
2623 push @{$self->{par}}, [$w + $indent, $h, $color, $indent, $line]; 2680 w => 1e10,
2681 wrapped => 1,
2682 fg => $color,
2683 indent => $indent,
2684 markup => $text,
2685 widget => \@w,
2624 } 2686 };
2625 2687
2626 $self->{children}[1]->set_range ([$self->{height}, 0, $self->{height}, $self->{h}, 1]); 2688 $self->add (@w) if @w;
2689 push @{$self->{par}}, $para;
2690
2691 $self->{need_reflow}++;
2692 $self->update;
2693}
2694
2695sub scroll_to_bottom {
2696 my ($self) = @_;
2697
2698 $self->{scroll_to_bottom} = 1;
2699 $self->update;
2627} 2700}
2628 2701
2629sub update { 2702sub update {
2630 my ($self) = @_; 2703 my ($self) = @_;
2631 2704
2639 my ($W, $H) = @{$self->{children}[0]}{qw(w h)}; 2712 my ($W, $H) = @{$self->{children}[0]}{qw(w h)};
2640 2713
2641 if (delete $self->{need_reflow}) { 2714 if (delete $self->{need_reflow}) {
2642 my $height = 0; 2715 my $height = 0;
2643 2716
2644 my $layout = $self->{layout};
2645
2646 $layout->set_height ($self->{fontsize} * $::FONTSIZE);
2647
2648 for (@{$self->{par}}) { 2717 for my $para (@{$self->{par}}) {
2649 if (1 || $_->[0] >= $W) { # TODO: works,but needs reconfigure etc. support 2718 if ($para->{w} != $W && ($para->{wrapped} || $para->{w} > $W)) {
2650 $layout->set_width ($W - $_->[3]); 2719 my $layout = $self->get_layout ($para);
2651 $layout->set_indent ($self->{fontsize} * $::FONTSIZE * $self->{indent});
2652 $layout->set_markup ($_->[4]);
2653 my ($w, $h) = $layout->size; 2720 my ($w, $h) = $layout->size;
2654 $_->[0] = $w + $_->[3]; 2721
2655 $_->[1] = $h; 2722 $para->{w} = $w + $para->{indent};
2723 $para->{h} = $h;
2724 $para->{wrapped} = $layout->has_wrapped;
2656 } 2725 }
2657 2726
2658 $height += $_->[1]; 2727 $height += $para->{h};
2659 } 2728 }
2660 2729
2661 $self->{height} = $height; 2730 $self->{height} = $height;
2662 2731
2663 $self->{children}[1]->set_range ([$height, 0, $height, $H, 1]); 2732 $self->{children}[1]->set_range ([$self->{children}[1]{range}[0], 0, $height, $H, 1]);
2664 2733
2665 delete $self->{texture}; 2734 delete $self->{texture};
2735 }
2736
2737 if (delete $self->{scroll_to_bottom}) {
2738 $self->{children}[1]->set_value (1e10);
2666 } 2739 }
2667 2740
2668 $self->{texture} ||= new_from_opengl CFClient::Texture $W, $H, sub { 2741 $self->{texture} ||= new_from_opengl CFClient::Texture $W, $H, sub {
2669 glClearColor 0, 0, 0, 0; 2742 glClearColor 0, 0, 0, 0;
2670 glClear GL_COLOR_BUFFER_BIT; 2743 glClear GL_COLOR_BUFFER_BIT;
2674 my $y0 = $top; 2747 my $y0 = $top;
2675 my $y1 = $top + $H; 2748 my $y1 = $top + $H;
2676 2749
2677 my $y = 0; 2750 my $y = 0;
2678 2751
2679 my $layout = $self->{layout};
2680
2681 $layout->set_font ($self->{font}) if $self->{font};
2682
2683 glEnable GL_BLEND;
2684 #TODO# not correct in windows where rgba is forced off
2685 glBlendFunc GL_ONE, GL_ONE_MINUS_SRC_ALPHA;
2686
2687 for my $par (@{$self->{par}}) { 2752 for my $para (@{$self->{par}}) {
2688 my $h = $par->[1]; 2753 my $h = $para->{h};
2689 2754
2690 if ($y0 < $y + $h && $y < $y1) { 2755 if ($y0 < $y + $h && $y < $y1) {
2691 $layout->set_foreground (@{ $par->[2] });
2692 $layout->set_width ($W - $par->[3]);
2693 $layout->set_indent ($self->{fontsize} * $::FONTSIZE * $self->{indent});
2694 $layout->set_markup ($par->[4]);
2695 2756
2696 my ($w, $h, $data, $format, $internalformat) = $layout->render; 2757 my $layout = $self->get_layout ($para);
2697 2758
2698 glRasterPos $par->[3], $y - $y0; 2759 $layout->render ($para->{indent}, $y - $y0);
2699 glDrawPixels $w, $h, $format, GL_UNSIGNED_BYTE, $data; 2760
2761 if (my @w = @{ $para->{widget} }) {
2762 my @s = $layout->get_shapes;
2763
2764 for (@w) {
2765 my ($dx, $dy) = splice @s, 0, 2, ();
2766
2767 $_->{x} = $dx + $para->{indent};
2768 $_->{y} = $dy + $y - $y0;
2769
2770 $_->draw;
2771 }
2772 }
2700 } 2773 }
2701 2774
2702 $y += $h; 2775 $y += $h;
2703 } 2776 }
2704
2705 glDisable GL_BLEND;
2706 }; 2777 };
2707 }); 2778 });
2779}
2780
2781sub reconfigure {
2782 my ($self) = @_;
2783
2784 $self->SUPER::reconfigure;
2785
2786 $_->{w} = 1e10 for @{ $self->{par} };
2787 $self->reflow;
2708} 2788}
2709 2789
2710sub _draw { 2790sub _draw {
2711 my ($self) = @_; 2791 my ($self) = @_;
2712 2792
2715 glColor 0, 0, 0, 1; 2795 glColor 0, 0, 0, 1;
2716 $self->{texture}->draw_quad_alpha_premultiplied (0, 0, $self->{children}[0]{w}, $self->{children}[0]{h}); 2796 $self->{texture}->draw_quad_alpha_premultiplied (0, 0, $self->{children}[0]{w}, $self->{children}[0]{h});
2717 glDisable GL_TEXTURE_2D; 2797 glDisable GL_TEXTURE_2D;
2718 2798
2719 $self->{children}[1]->draw; 2799 $self->{children}[1]->draw;
2720
2721} 2800}
2722 2801
2723############################################################################# 2802#############################################################################
2724 2803
2725package CFClient::UI::Animator; 2804package CFClient::UI::Animator;
2998 for my $item (@{ $self->{items} }) { 3077 for my $item (@{ $self->{items} }) {
2999 my ($widget, $cb, $tooltip) = @$item; 3078 my ($widget, $cb, $tooltip) = @$item;
3000 3079
3001 # handle various types of items, only text for now 3080 # handle various types of items, only text for now
3002 if (!ref $widget) { 3081 if (!ref $widget) {
3082 if ($widget =~ /\t/) {
3083 my ($left, $right) = split /\t/, $widget, 2;
3084
3085 $widget = new CFClient::UI::HBox
3086 can_hover => 1,
3087 can_events => 1,
3088 tooltip => $tooltip,
3089 children => [
3090 (new CFClient::UI::Label markup => $left, expand => 1),
3091 (new CFClient::UI::Label markup => $right, align => +1),
3092 ],
3093 ;
3094
3095 } else {
3003 $widget = new CFClient::UI::Label 3096 $widget = new CFClient::UI::Label
3004 can_hover => 1, 3097 can_hover => 1,
3005 can_events => 1, 3098 can_events => 1,
3006 markup => $widget, 3099 markup => $widget,
3007 tooltip => $tooltip 3100 tooltip => $tooltip;
3101 }
3008 } 3102 }
3009 3103
3010 $self->{item}{$widget} = $item; 3104 $self->{item}{$widget} = $item;
3011 3105
3012 $self->{vbox}->add ($widget); 3106 $self->{vbox}->add ($widget);
3079 3173
3080 $self->SUPER::add (@widgets); 3174 $self->SUPER::add (@widgets);
3081 3175
3082 $self->{current} = $self->{children}[0] 3176 $self->{current} = $self->{children}[0]
3083 if @{ $self->{children} }; 3177 if @{ $self->{children} };
3178}
3179
3180sub get_current_page {
3181 my ($self) = @_;
3182
3183 $self->{current}
3084} 3184}
3085 3185
3086sub set_current_page { 3186sub set_current_page {
3087 my ($self, $page_or_widget) = @_; 3187 my ($self, $page_or_widget) = @_;
3088 3188
3154 tooltip => $tooltip, 3254 tooltip => $tooltip,
3155 on_activate => sub { $self->set_current_page ($widget) }, 3255 on_activate => sub { $self->set_current_page ($widget) },
3156 ); 3256 );
3157 3257
3158 $self->{multiplexer}->add ($widget); 3258 $self->{multiplexer}->add ($widget);
3259}
3260
3261sub get_current_page {
3262 my ($self) = @_;
3263
3264 $self->{multiplexer}->get_current_page
3159} 3265}
3160 3266
3161sub set_current_page { 3267sub set_current_page {
3162 my ($self, $page) = @_; 3268 my ($self, $page) = @_;
3163 3269
3341 count => 1, 3447 count => 1,
3342 %arg, 3448 %arg,
3343 }; 3449 };
3344 } 3450 }
3345 3451
3452 $ROOT->on_refresh (reorder => sub {
3346 $self->reorder; 3453 $self->reorder;
3454 });
3347} 3455}
3348 3456
3349sub reconfigure { 3457sub reconfigure {
3350 my ($self) = @_; 3458 my ($self) = @_;
3351 3459
3366 3474
3367############################################################################# 3475#############################################################################
3368 3476
3369package CFClient::UI::Inventory; 3477package CFClient::UI::Inventory;
3370 3478
3371our @ISA = CFClient::UI::ScrolledWindow::; 3479our @ISA = CFClient::UI::Table::;
3372 3480
3373sub new { 3481sub new {
3374 my $class = shift; 3482 my $class = shift;
3375 3483
3376 my $self = $class->SUPER::new ( 3484 my $self = $class->SUPER::new (
3377 child => (new CFClient::UI::Table col_expand => [0, 1, 0]), 3485 col_expand => [0, 1, 0],
3378 @_, 3486 @_,
3379 ); 3487 );
3380 3488
3381 $self 3489 $self
3382} 3490}
3383 3491
3384sub set_items { 3492sub set_items {
3385 my ($self, $items) = @_; 3493 my ($self, $items) = @_;
3386 3494
3387 $self->{child}->clear; 3495 $self->clear;
3388 return unless $items; 3496 return unless $items;
3389 3497
3390 my @items = sort { 3498 my @items = sort {
3391 ($a->{type} <=> $b->{type}) 3499 ($a->{type} <=> $b->{type})
3392 or ($a->{name} cmp $b->{name}) 3500 or ($a->{name} cmp $b->{name})
3393 } @$items; 3501 } values %$items;
3394 3502
3395 $self->{real_items} = \@items; 3503 $self->{real_items} = \@items;
3396 3504
3397 my $row = 0; 3505 my $row = 0;
3398 for my $item (@items) { 3506 for my $item (@items) {
3399 CFClient::Item::update_widgets $item; 3507 CFClient::Item::update_widgets $item;
3400 3508
3401 $self->{child}->add (0, $row, $item->{face_widget}); 3509 $self->add (0, $row, $item->{face_widget});
3402 $self->{child}->add (1, $row, $item->{desc_widget}); 3510 $self->add (1, $row, $item->{desc_widget});
3403 $self->{child}->add (2, $row, $item->{weight_widget}); 3511 $self->add (2, $row, $item->{weight_widget});
3404 3512
3405 $row++; 3513 $row++;
3406 }
3407}
3408
3409#############################################################################
3410
3411package CFClient::UI::BindEditor;
3412
3413our @ISA = CFClient::UI::FancyFrame::;
3414
3415sub new {
3416 my $class = shift;
3417
3418 my $self = $class->SUPER::new (binding => [], commands => [], @_);
3419
3420 $self->add (my $vb = new CFClient::UI::VBox);
3421
3422
3423 $vb->add ($self->{rec_btn} = new CFClient::UI::Button
3424 text => "start recording",
3425 tooltip => "Start/Stops recording of actions."
3426 ."All subsequent actions after the recording started will be captured."
3427 ."The actions are displayed after the record was stopped."
3428 ."To bind the action you have to click on the 'Bind' button",
3429 on_activate => sub {
3430 unless ($self->{recording}) {
3431 $self->start;
3432 } else {
3433 $self->stop;
3434 }
3435 });
3436
3437 $vb->add (new CFClient::UI::Label text => "Actions:");
3438 $vb->add ($self->{cmdbox} = new CFClient::UI::VBox);
3439
3440 $vb->add (new CFClient::UI::Label text => "Bound to: ");
3441 $vb->add (my $hb = new CFClient::UI::HBox);
3442 $hb->add ($self->{keylbl} = new CFClient::UI::Label expand => 1);
3443 $hb->add (new CFClient::UI::Button
3444 text => "bind",
3445 tooltip => "This opens a query where you have to press the key combination to bind the recorded actions",
3446 on_activate => sub {
3447 $self->ask_for_bind;
3448 });
3449
3450 $vb->add (my $hb = new CFClient::UI::HBox);
3451 $hb->add (new CFClient::UI::Button
3452 text => "ok",
3453 expand => 1,
3454 tooltip => "This closes the binding editor and saves the binding",
3455 on_activate => sub {
3456 $self->hide;
3457 $self->commit;
3458 });
3459
3460 $hb->add (new CFClient::UI::Button
3461 text => "cancel",
3462 expand => 1,
3463 tooltip => "This closes the binding editor without saving",
3464 on_activate => sub {
3465 $self->hide;
3466 $self->{binding_cancel}->()
3467 if $self->{binding_cancel};
3468 });
3469
3470 $self->update_binding_widgets;
3471
3472 $self
3473}
3474
3475sub commit {
3476 my ($self) = @_;
3477 my ($mod, $sym, $cmds) = $self->get_binding;
3478 if ($sym != 0 && @$cmds > 0) {
3479 $::STATUSBOX->add ("Bound actions to '".CFClient::Binder::keycombo_to_name ($mod, $sym)
3480 ."'. Don't forget 'Save Config'!");
3481 $self->{binding_change}->($mod, $sym, $cmds)
3482 if $self->{binding_change};
3483 } else {
3484 $::STATUSBOX->add ("No action bound, no key or action specified!");
3485 $self->{binding_cancel}->()
3486 if $self->{binding_cancel};
3487 }
3488}
3489
3490sub start {
3491 my ($self) = @_;
3492
3493 $self->{rec_btn}->set_text ("stop recording");
3494 $self->{recording} = 1;
3495 $self->clear_command_list;
3496 $::CONN->start_record if $::CONN;
3497}
3498
3499sub stop {
3500 my ($self) = @_;
3501
3502 $self->{rec_btn}->set_text ("start recording");
3503 $self->{recording} = 0;
3504
3505 my $rec;
3506 $rec = $::CONN->stop_record if $::CONN;
3507 return unless ref $rec eq 'ARRAY';
3508 $self->set_command_list ($rec);
3509}
3510
3511
3512sub ask_for_bind_and_commit {
3513 my ($self) = @_;
3514 $self->ask_for_bind (1);
3515}
3516
3517sub ask_for_bind {
3518 my ($self, $commit, $end_cb) = @_;
3519
3520 CFClient::Binder::open_binding_dialog (sub {
3521 my ($mod, $sym) = @_;
3522 $self->{binding} = [$mod, $sym]; # XXX: how to stop that memleak?
3523 $self->update_binding_widgets;
3524 $self->commit if $commit;
3525 $end_cb->() if $end_cb;
3526 });
3527}
3528
3529# $mod and $sym are the modifiers and key symbol
3530# $cmds is a array ref of strings (the commands)
3531# $cb is the callback that is executed on OK
3532# $ccb is the callback that is executed on CANCEL and
3533# when the binding was unsuccessful on OK
3534sub set_binding {
3535 my ($self, $mod, $sym, $cmds, $cb, $ccb) = @_;
3536
3537 $self->clear_command_list;
3538 $self->{recording} = 0;
3539 $self->{rec_btn}->set_text ("start recording");
3540
3541 $self->{binding} = [$mod, $sym];
3542 $self->{commands} = $cmds;
3543
3544 $self->{binding_change} = $cb;
3545 $self->{binding_cancel} = $ccb;
3546
3547 $self->update_binding_widgets;
3548}
3549
3550# this is a shortcut method that asks for a binding
3551# and then just binds it.
3552sub do_quick_binding {
3553 my ($self, $cmds, $end_cb) = @_;
3554 $self->set_binding (undef, undef, $cmds, sub {
3555 $::CFG->{bindings}->{$_[0]}->{$_[1]} = $_[2];
3556 });
3557 $self->ask_for_bind (1, $end_cb);
3558}
3559
3560sub update_binding_widgets {
3561 my ($self) = @_;
3562 my ($mod, $sym, $cmds) = $self->get_binding;
3563 $self->{keylbl}->set_text (CFClient::Binder::keycombo_to_name ($mod, $sym));
3564 $self->set_command_list ($cmds);
3565}
3566
3567sub get_binding {
3568 my ($self) = @_;
3569 return (
3570 $self->{binding}->[0],
3571 $self->{binding}->[1],
3572 [ grep { defined $_ } @{$self->{commands}} ]
3573 );
3574}
3575
3576sub clear_command_list {
3577 my ($self) = @_;
3578 $self->{cmdbox}->clear ();
3579}
3580
3581sub set_command_list {
3582 my ($self, $cmds) = @_;
3583
3584 $self->{cmdbox}->clear ();
3585 $self->{commands} = $cmds;
3586
3587 my $idx = 0;
3588
3589 for (@$cmds) {
3590 $self->{cmdbox}->add (my $hb = new CFClient::UI::HBox);
3591
3592 my $i = $idx;
3593 $hb->add (new CFClient::UI::Label text => $_);
3594 $hb->add (new CFClient::UI::Button
3595 text => "delete",
3596 tooltip => "Deletes the action from the record",
3597 on_activate => sub {
3598 $self->{cmdbox}->remove ($hb);
3599 $cmds->[$i] = undef;
3600 });
3601
3602
3603 $idx++
3604 } 3514 }
3605} 3515}
3606 3516
3607############################################################################# 3517#############################################################################
3608 3518
3662 } elsif ($ev->{button} == 2) { 3572 } elsif ($ev->{button} == 2) {
3663 $::CONN->user_send ("invoke $spell->{name}"); 3573 $::CONN->user_send ("invoke $spell->{name}");
3664 } elsif ($ev->{button} == 3) { 3574 } elsif ($ev->{button} == 3) {
3665 (new CFClient::UI::Menu 3575 (new CFClient::UI::Menu
3666 items => [ 3576 items => [
3667 ["bind <i>cast $spell->{name}</i> to a key" => sub { $::BIND_EDITOR->do_quick_binding (["cast $spell->{name}"]) }], 3577 ["bind <i>cast $spell->{name}</i> to a key" => sub { $::BIND_EDITOR->do_quick_binding (["cast $spell->{name}"]) }],
3668 ["bind <i>invoke $spell->{name}</i> to a key" => sub { $::BIND_EDITOR->do_quick_binding (["invoke $spell->{name}"]) }], 3578 ["bind <i>invoke $spell->{name}</i> to a key" => sub { $::BIND_EDITOR->do_quick_binding (["invoke $spell->{name}"]) }],
3669 ], 3579 ],
3670 )->popup ($ev); 3580 )->popup ($ev);
3671 } else { 3581 } else {
3672 return 0; 3582 return 0;
3918 my ($w, $h) = @$widget{qw(alloc_w alloc_h)}; 3828 my ($w, $h) = @$widget{qw(alloc_w alloc_h)};
3919 3829
3920 $w = 0 if $w < 0; 3830 $w = 0 if $w < 0;
3921 $h = 0 if $h < 0; 3831 $h = 0 if $h < 0;
3922 3832
3833 $w = max $widget->{min_w}, $w;
3834 $h = max $widget->{min_h}, $h;
3835
3836 $w = min $widget->{max_w}, $w if exists $widget->{max_w};
3837 $h = min $widget->{max_h}, $h if exists $widget->{max_h};
3838
3923 $w = int $w + 0.5; 3839 $w = int $w + 0.5;
3924 $h = int $h + 0.5; 3840 $h = int $h + 0.5;
3925 3841
3926 if ($widget->{w} != $w || $widget->{h} != $h || delete $widget->{force_size_alloc}) { 3842 if ($widget->{w} != $w || $widget->{h} != $h || delete $widget->{force_size_alloc}) {
3927 $widget->{old_w} = $widget->{w}; 3843 $widget->{old_w} = $widget->{w};

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines