1# combo styles 2package 3 cs; 4use constant Simple => 0; 5use constant DropDown => 1; 6use constant DropDownList => 2; 7 8use strict; 9use warnings; 10 11package Prima::ComboBox; 12 13use vars qw(@ISA %listProps %editProps %listDynas $capture_mode); 14use Prima qw( InputLine Lists Utils StdBitmap); 15@ISA = qw(Prima::Widget); 16 17use constant DefButtonX => 17; 18 19# these are properties, methods and dynas of encapsulated widgets, edit and list 20 21%editProps = map { $_ => 1 } qw( 22 alignment autoScroll text select_all 23 charOffset maxLen insertMode firstChar 24 selection selStart selEnd writeOnly 25 copy cut delete paste 26 wordDelimiters readOnly passwordChar focus 27); 28 29%listProps = map { $_ => 1 } qw( 30 focusedItem hScroll 31 integralHeight items itemHeight 32 topItem vScroll gridColor 33 multiColumn offset autoHScroll 34 autoVScroll 35); 36 37%listDynas = map { $_ => 1} qw(onDrawItem onSelectItem); 38 39for ( keys %editProps) { 40 eval <<GENPROC; 41sub $_ { return shift-> {edit}-> $_(\@_); } 42sub Prima::ComboBox::DummyEdit::$_ {} 43GENPROC 44} 45 46for (keys %listProps) { 47 eval <<GENPROC; 48sub $_ { return shift-> {list}-> $_(\@_); } 49sub Prima::ComboBox::DummyList::$_ {} 50GENPROC 51} 52 53$capture_mode = (Prima::Application-> get_system_info-> {apc} == apc::Unix); 54 55sub profile_default 56{ 57 my $f = $_[ 0]-> get_default_font; 58 return { 59 %{Prima::InputLine-> profile_default}, 60 %{Prima::ListBox-> profile_default}, 61 %{$_[ 0]-> SUPER::profile_default}, 62 style => cs::Simple, 63 caseSensitive => 0, 64 autoHeight => 1, 65 66 autoHScroll => 0, 67 autoVScroll => 1, 68 listVisible => 0, 69 editHeight => $f-> {height} + 2, 70 listHeight => $::application-> uiScaling * 100, 71 ownerBackColor => 1, 72 selectable => 0, 73 literal => 1, 74 scaleChildren => 0, 75 autoEnableChildren => 1, 76 77 editClass => 'Prima::InputLine', 78 listClass => 'Prima::ListBox', 79 buttonClass => 'Prima::Widget', 80 scrollBarClass => 'Prima::ScrollBar', 81 editProfile => {}, 82 listProfile => {}, 83 buttonProfile => {}, 84 hScrollBarProfile => {}, 85 vScrollBarProfile => {}, 86 listDelegations => [qw(Leave SelectItem MouseUp Click KeyDown)], 87 editDelegations => [qw(FontChanged Create Setup KeyDown KeyUp Change Leave MouseWheel)], 88 buttonDelegations => [qw(ColorChanged FontChanged MouseDown MouseClick 89 MouseUp MouseMove MouseEnter MouseLeave Paint Enable Disable)], 90 } 91} 92 93sub profile_check_in 94{ 95 my ( $self, $p, $default) = @_; 96 $self-> SUPER::profile_check_in( $p, $default); 97 my $style = exists $p-> {style} ? $p-> {style} : $default-> {style}; 98 $p-> {autoHeight} = 0 99 if exists $p-> {height} || exists $p-> {size} || exists $p-> {rect} || ( exists $p-> {top} && exists $p-> {bottom}); 100 if ( $style != cs::Simple) { 101 $p-> { editHeight } = exists $p-> {height} ? $p-> {height} : $default-> {height} 102 unless exists $p-> { editHeight }; 103 } else { 104 my $fh = exists $p-> {font}-> {height} ? 105 $p-> {font}-> {height} : 106 $default-> {font}-> {height}; 107 $p-> { editHeight } = $fh + 2 108 unless exists $p-> {editHeight }; 109 } 110 $p-> {autoHScroll} = 0 if exists $p-> {hScroll}; 111 $p-> {autoVScroll} = 0 if exists $p-> {vScroll}; 112} 113 114sub init 115{ 116 my $self = shift; 117 my %profile = @_; 118 my $visible = $profile{visible}; 119 $profile{visible} = 0; 120 $self-> {edit} = bless [], q\Prima::ComboBox::DummyEdit\; 121 $self-> {list} = bless [], q\Prima::ComboBox::DummyList\; 122 %profile = $self-> SUPER::init(%profile); 123 my ( $w, $h) = ( $self-> size); 124 $self-> {style} = $profile{style}; 125 $self-> {listVisible} = $profile{style} != cs::Simple; 126 $self-> {caseSensitive}= $profile{caseSensitive}; 127 $self-> {literal} = $profile{literal}; 128 my $eh = $self-> {editHeight } = $profile{editHeight }; 129 $self-> {listHeight} = $profile{listHeight}; 130 $self-> {autoHeight} = $profile{autoHeight}; 131 132 $self-> {edit} = $self-> insert( $profile{editClass} => 133 name => 'InputLine', 134 origin => [ 0, $h - $eh], 135 size => [ $w - (( $self-> {style} == cs::Simple) ? 0 : ( $::application-> uiScaling * DefButtonX)), $eh], 136 growMode => gm::GrowHiX | gm::GrowLoY, 137 selectable => 1, 138 tabStop => 1, 139 current => 1, 140 dndAware => (( $self->{style} == cs::DropDown) ? 'Text' : 0 ), 141 delegations => $profile{editDelegations}, 142 (map { $_ => $profile{$_}} keys %editProps), 143 %{$profile{editProfile}}, 144 ); 145 146 if ( $self->{autoHeight} && $self->{style} != cs::Simple) { 147 $self->check_auto_size; 148 ( $w, $h) = ( $self-> size); 149 $eh = $self-> geomHeight; 150 $self->{edit}->set( height => $eh, bottom => $h - $eh ); 151 } 152 153 my %lp = (%listProps, scrollBarClass => 1, hScrollBarProfile => 1, vScrollBarProfile => 1); 154 delete $lp{hScroll} if $profile{autoHScroll}; 155 delete $lp{vScroll} if $profile{autoVScroll}; 156 $self-> {list} = $self-> insert( $profile{listClass} => 157 name => 'List', 158 origin => [ 0, 0], 159 selectable => $capture_mode ? ($self->{style} == cs::Simple) : 1, 160 width => $w, 161 height => ( $self-> {style} == cs::Simple) ? ( $h - $eh) : $self-> {listHeight}, 162 growMode => gm::Client, 163 tabStop => 0, 164 multiSelect => 0, 165 clipOwner => $self-> {style} == cs::Simple, 166 visible => $self-> {style} == cs::Simple, 167 delegations => $profile{listDelegations}, 168 (map { $_ => $profile{$_}} grep { exists $profile{$_} ? 1 : 0} keys %listDynas), 169 (map { $_ => $profile{$_}} keys %lp), 170 %{$profile{listProfile}}, 171 ); 172 173 $self-> {button} = $self-> insert( $profile{buttonClass} => 174 ownerBackColor => 1, 175 name => 'Button', 176 origin => [ $w - $::application-> uiScaling * DefButtonX, $h - $eh], 177 size => [ $::application-> uiScaling * DefButtonX, $eh], 178 visible => $self-> {style} != cs::Simple, 179 growMode => gm::GrowLoX | gm::GrowLoY, 180 tabStop => 0, 181 ownerFont => 0, 182 selectable => 0, 183 delegations => $profile{buttonDelegations}, 184 %{$profile{buttonProfile}}, 185 ); 186 187 $self-> visible( $visible); 188 return %profile; 189} 190 191sub check_auto_size 192{ 193 my $self = $_[0]; 194 $self-> geomHeight( $self-> {edit}-> default_geom_height ) 195 if $self-> {autoHeight} && $self->{style} != cs::Simple && $self->{edit}->can('default_geom_height'); 196} 197 198sub on_create 199{ 200 my $self = $_[0]; 201 $self-> InputLine_Change( $self-> {edit}) 202 if $self-> {style} == cs::DropDownList; 203} 204 205sub on_size { $_[0]-> listVisible(0); } 206sub on_move { $_[0]-> listVisible(0); } 207sub on_hide { $_[0]-> listVisible(0); } 208 209sub List_Leave 210{ 211 $_[0]-> listVisible( 0) if $_[0]-> {style} != cs::Simple; 212} 213 214sub List_SelectItem 215{ 216 return if defined $_[1]-> {interaction}; 217 $_[0]-> {edit}-> {interaction} = 1; 218 $_[0]-> {edit}-> text($_[1]-> get_item_text( $_[1]-> focusedItem)); 219 $_[0]-> {edit}-> {interaction} = undef; 220 $_[0]-> notify( q(Change)) if $_[0]-> {style} == cs::Simple; 221} 222 223sub List_MouseUp 224{ 225 return unless $_[2] == mb::Left || $_[1]-> capture; 226 $_[0]-> listVisible(0) if $_[0]-> {style} != cs::Simple; 227 $_[0]-> notify( q(Change)) if $_[0]-> {style} != cs::Simple; 228} 229 230sub List_Click 231{ 232 my ( $self, $list) = @_; 233 $self-> {edit}-> {interaction} = 1; 234 $self-> {edit}-> text( $list-> get_item_text( $list-> focusedItem)); 235 $self-> {edit}-> {interaction} = undef; 236 $self-> listVisible(0); 237 $self-> notify( q(Change)); 238} 239 240sub List_KeyDown 241{ 242 my ( $self, $list, $code, $key, $mod) = @_; 243 if ( $key == kb::Esc) { 244 $self-> listVisible(0); 245 $list-> clear_event; 246 } elsif ( $key == kb::Enter) { 247 $list-> notify(q(Click)); 248 $list-> clear_event; 249 } 250} 251 252sub Button_ColorChanged 253{ 254 my $self = shift; 255 if ( $self-> {style} != cs::Simple) { 256 $self-> {list}-> color( $self-> {button}-> color); 257 $self-> {list}-> backColor( $self-> {button}-> backColor); 258 } 259} 260 261sub Button_FontChanged 262{ 263 my $self = shift; 264 if ( $self-> {style} != cs::Simple) { 265 my $f = $self-> {button}-> font; 266 $self-> {list}-> font($f); 267 } 268} 269 270sub Button_MouseDown 271{ 272 $_[0]-> listVisible( !$_[0]-> {list}-> visible); 273 $_[1]-> clear_event; 274 return if !$_[0]-> {list}-> visible; 275 $_[1]-> capture(1); 276} 277 278sub Button_MouseClick 279{ 280 return unless $_[-1]; 281 $_[0]-> listVisible( !$_[0]-> {list}-> visible); 282 $_[1]-> clear_event; 283 return if !$_[0]-> {list}-> visible; 284 $_[1]-> capture(1); 285} 286 287 288sub Button_MouseMove 289{ 290 $_[1]-> clear_event; 291 if ($_[1]-> capture) { 292 my ($x,$y,$W,$H) = ($_[3],$_[4],$_[1]-> size); 293 return unless ($x < 0) || ($y < 0) || ($x >= $W) || ($y >= $H); 294 $_[1]-> capture(0); 295 $_[0]-> {list}-> mouse_down( mb::Left, 0, 5, $_[0]-> {list}-> height - 5, 1) 296 if ($_[0]-> {list}-> visible); 297 } 298} 299 300sub Button_MouseEnter 301{ 302 my ( $self, $button ) = @_; 303 if ( !$button->capture && $self->enabled) { 304 $button->{prelight} = 1; 305 $button->repaint; 306 } 307} 308 309sub Button_MouseLeave 310{ 311 my ( $self, $button ) = @_; 312 if ( !$button->capture && $button->{prelight}) { 313 delete $button->{prelight}; 314 $button->repaint; 315 } 316 317} 318 319sub Button_MouseUp { $_[1]-> capture(0); } 320 321sub fix_triangle 322{ 323 my @spot = map { int($_ + .5) } @_; 324 my $dx = $spot[4] - $spot[0]; 325 my $dy = $spot[1] - $spot[3]; 326 if ($dx % 2) { 327 $spot[2] = $spot[0] + ($dx - 1) / 2; 328 $spot[4]--; 329 $dx--; 330 } 331 if ( $dx == 2 ) { 332 $spot[4]++; 333 $spot[0]--; 334 $dx += 2; 335 } 336 $spot[3]-- if $dy < $dx / 2; 337 return @spot; 338} 339 340sub Button_Paint 341{ 342 my ( $owner, $self, $canvas) = @_; 343 my ( $w, $h) = $canvas-> size; 344 my $ena = $self-> enabled; 345 my @clr = $ena ? 346 ( $self-> color, $self-> backColor) : 347 ( $self-> disabledColor, $self-> disabledBackColor); 348 $clr[1] = $self->prelight_color($clr[1]) if $self->{prelight}; 349 my $lv = $owner-> listVisible; 350 my ( $rc, $lc) = ( $self-> light3DColor, $self-> dark3DColor); 351 ( $rc, $lc) = ( $lc, $rc) if $lv; 352 $self-> rect_bevel( 353 $canvas, 0, 0, $w-1, $h-1, 354 fill => $self-> new_gradient( 355 palette => [ $self-> dark3DColor, $clr[1], $self-> light3DColor ], 356 spline => [0,0.5,1,0.5], 357 vertical => 0, 358 ), 359 width => 2 360 ); 361 my @triangle = fix_triangle( 4, $h * 0.6, $w/2, $h * 0.4, $w - 4, $h * 0.6 ); 362 if ( $ena) { 363 $canvas-> color( $rc); 364 $canvas-> translate(1,-1); 365 $canvas-> fillpoly(\@triangle); 366 $canvas-> translate(0,0); 367 } 368 $canvas-> color( $clr[0]); 369 $canvas-> fillpoly(\@triangle); 370} 371 372sub Button_Enable { $_[1]-> repaint } 373sub Button_Disable { $_[1]-> repaint } 374 375sub InputLine_Leave 376{ 377 $_[0]-> listVisible( 0) if $capture_mode and $_[0]-> {style} != cs::Simple; 378} 379 380sub InputLine_FontChanged 381{ 382 $_[0]-> editHeight ( $_[1]-> default_geom_height ); 383 $_[0]-> check_auto_size; 384} 385 386sub InputLine_Create 387{ 388 $_[1]-> {incline} = ''; 389} 390 391sub InputLine_KeyDown 392{ 393 my ( $self, $edit, $code, $key, $mod, $repeat) = @_; 394 395 if ( $self-> listVisible) { 396 $self-> {list}-> notify(q(KeyDown), $code, $key, $mod, $repeat); 397 $edit-> clear_event; 398 return; 399 } 400 401 return if $mod & km::DeadKey; 402 if ( 403 ( $key & 0xFF00) && 404 ( $key != kb::NoKey) && 405 ( $key != kb::Space) && 406 ( $key != kb::Backspace) 407 ) { 408 return if $key == kb::Tab || $key == kb::BackTab || $key == kb::NoKey; 409 $edit-> {incline} = ''; 410 $self-> listVisible(1), $edit-> clear_event 411 if $key == kb::Down && $_[0]-> {style} != cs::Simple; 412 $_[0]-> notify( q(Change)), $edit-> clear_event 413 if $key == kb::Enter && $_[0]-> {style} == cs::DropDownList; 414 return; 415 } else { 416 return unless $code; 417 return unless $_[0]-> {literal}; 418 return if $_[0]-> {style} != cs::DropDownList; 419 return if $mod & ( km::Alt|km::Ctrl); 420 $edit-> {keyDown} = 1; 421 if ( $key == kb::Backspace) { 422 chop $edit-> {incline}; 423 } else { 424 $code = chr ( $code); 425 $code = uc $code unless $self-> caseSensitive; 426 $edit-> {incline} .= $code; 427 } 428 my ($ftc,$i,$txt,$t); 429 $ftc = quotemeta $edit-> {incline}; 430 for ( $i = 0; $i < $_[0]-> {list}-> count; $i++) { 431 $txt = $_[0]-> {list}-> get_item_text($i); 432 $t = $txt; 433 $t = uc $t unless $self-> caseSensitive; 434 last if $t =~ /^$ftc/; 435 } 436 if ( $i < $_[0]-> {list}-> count) { 437 $edit-> text( $txt); 438 } else { 439 chop $edit-> {incline}; 440 } 441 $edit-> selection( 0, length $edit-> {incline}); 442 } 443 $edit-> clear_event if $_[0]-> {style} == cs::DropDownList; 444} 445 446 447sub InputLine_KeyUp 448{ 449 $_[1]-> {keyDown} = undef; 450} 451 452sub InputLine_Setup 453{ 454 my $self = shift; 455 $self-> InputLine_Change(@_) if $self-> {style} == cs::DropDownList; 456} 457 458sub InputLine_Change 459{ 460 return if defined $_[0]-> {edit}-> {interaction}; 461 return unless $_[0]-> {literal}; 462 463 $_[0]-> notify(q(Change)) if $_[0]-> {style} != cs::DropDownList; 464 465 $_[0]-> {list}-> {interaction} = 1; 466 my ( $self, $style, $list, $edit) = ($_[0], $_[0]-> {style}, $_[0]-> {list}, $_[1]); 467 my $i; 468 my $found = 0; 469 my $cap = $edit-> text; 470 $cap = uc $cap unless $self-> caseSensitive; 471 my @matchArray; 472 my @texts; 473 my $maxMatch = 0; 474 my $matchId = -1; 475 # filling list 476 for ( $i = 0; $i < $list-> count; $i++) { 477 my $t = $list-> get_item_text($i); 478 $t = uc $t unless $self-> caseSensitive; 479 push ( @texts, $t); 480 } 481 # trying to find exact match 482 for ( $i = 0; $i < scalar @texts; $i++) { 483 if ( $texts[$i] eq $cap) { 484 $matchId = $i; 485 last; 486 } 487 } 488 if ( 489 ( $style == cs::DropDown) && 490 ( $matchId < 0) && 491 defined $edit-> {keyDown} 492 ) { 493 my ($t,$txt); 494 for ( $i = 0; $i < scalar @texts; $i++) { 495 $txt = $t = $list-> get_item_text($i); 496 $t = uc $t unless $self-> caseSensitive; 497 last if $t =~ /^\Q$cap\E/; 498 } 499 # netscape 4 combo behavior 500 if ( $i < scalar @texts) { 501 $edit-> {interaction} = 1; 502 $edit-> text( $txt); 503 $edit-> {interaction} = undef; 504 $t =~ /^\Q$cap\E/; 505 $edit-> selection( length $cap, length $t); 506 $list-> focusedItem( $i); 507 return; 508 } 509 } 510 # or unexact match 511 if ( $matchId < 0) { 512 for ( $i = 0; $i < scalar @texts; $i++) { 513 my $l = 0; 514 $l++ while 515 $l < length($texts[$i]) && $l < length($cap) 516 && substr( $texts[$i], $l, 1) eq substr( $cap, $l, 1); 517 if ( $l >= $maxMatch) { 518 @matchArray = () if $l > $maxMatch; 519 $maxMatch = $l; 520 push @matchArray, $i; 521 } 522 } 523 $matchId = $matchArray[0] if $matchId < 0; 524 } 525 $matchId = 0 unless defined $matchId; 526 $list-> focusedItem( $matchId); 527 528 if ( $style == cs::DropDownList) { 529 $edit-> {interaction} = 1; 530 $edit-> text( $list-> get_item_text( $matchId) // ''); 531 $edit-> {interaction} = undef; 532 } 533 $list-> {interaction} = undef; 534} 535 536sub InputLine_MouseWheel 537{ 538 my ( $self, $edit, $mod, $x, $y, $z) = @_; 539 540 my $f = $self-> {list}-> focusedItem; 541 $f += (($z > 0) ? -1 : 1); 542 return if $f < 0; 543 $self-> {list}-> focusedItem($f); 544 $self-> notify(q(Change)); 545 $edit-> clear_event; 546} 547 548sub set_style 549{ 550 my ( $self, $style) = @_; 551 return if $self-> {style} == $style; 552 my $decr = (( $self-> {style} == cs::Simple) || ( $style == cs::Simple)) ? 1 : 0; 553 $self-> {style} = $style; 554 if ( $style == cs::Simple) { 555 $self-> set( 556 height=> $self-> height + $self-> listHeight, 557 bottom=> $self-> bottom - $self-> listHeight, 558 ); 559 $self-> {list}-> set( 560 visible => 1, 561 origin => [ 0, 0], 562 width => $self-> width, 563 height => $self-> height - $self-> editHeight , 564 clipOwner => 1, 565 selectable => 1, 566 ); 567 } elsif ( $decr) { 568 $self-> set( 569 height => $self-> height - $self-> listHeight, 570 bottom => $self-> bottom + $self-> listHeight, 571 ); 572 $self-> { list}-> set( 573 visible => 0, 574 height => $self-> {listHeight}, 575 clipOwner => 0, 576 selectable => $capture_mode ? 0 : 1, 577 ); 578 $self-> listVisible( 0); 579 } 580 $self-> {edit}-> set( 581 bottom => $self-> height - $self-> editHeight , 582 width => $self-> { edit}-> width + $::application-> uiScaling * DefButtonX * $decr * 583 (( $style == cs::Simple) ? 1 : -1), 584 height => $self-> editHeight , 585 dndAware => (( $style == cs::DropDown) ? 'Text' : 0 ), 586 ); 587 $self-> {button}-> set( 588 bottom => $self-> height - $self-> editHeight , 589 height => $self-> editHeight , 590 visible=> $style != cs::Simple, 591 ); 592 if ( $style == cs::DropDownList) { 593 $self-> {edit}-> insertMode(1); 594 $self-> {edit}-> text( $self-> {edit}-> text); 595 } 596} 597 598sub set_list_visible 599{ 600 my ( $self, $nlv) = @_; 601 return if ( $self-> {list}-> visible == $nlv) || 602 ( $self-> {style} == cs::Simple) || 603 ( !$self-> visible && $nlv); 604 my ( $list, $edit) = ( $self-> {list}, $self-> {edit}); 605 if ( $nlv) { 606 my @gp = $edit-> client_to_screen( 0, -$list-> height); 607 $gp[1] += $edit-> height + $list-> height if $gp[1] < 0; 608 $gp[0] = $::application->width - $list->width if $gp[0] + $list->width > $::application->width; 609 $list-> origin( @gp); 610 } 611 $list-> bring_to_front if $nlv; 612 $list-> visible( $nlv); 613 $self-> {button}-> repaint; 614 if ( $capture_mode) { 615 $list-> capture( $nlv ? 1 : 0); 616 $edit-> focus; 617 } else { 618 $nlv ? $list-> focus : $edit-> focus; 619 } 620} 621 622sub set_edit_height 623{ 624 my ( $self, $edit, $list, $btn, $h, $new) = 625 ($_[0], $_[0]-> {edit}, $_[0]-> {list}, $_[0]-> {button}, $_[0]-> height, $_[1]); 626 if ( $self-> style != cs::Simple) { 627 $self-> height( $new); 628 $edit-> set( 629 bottom => 0, 630 height => $new 631 ); 632 $btn-> set( 633 bottom => 0, 634 height => $new 635 ); 636 $list-> height( $self-> {listHeight}); 637 } else { 638 $edit-> set( 639 bottom => $h - $new, 640 height => $new 641 ); 642 $btn-> set( 643 bottom => $h - $new, 644 height => $new 645 ); 646 $list-> height( $h - $new); 647 } 648 $self-> {editHeight} = $new; 649} 650 651sub set_list_height 652{ 653 my ( $self, $hei) = @_; 654 if ( $self-> style == cs::Simple) { 655 $self-> height( $self-> height + $hei - $self-> {listHeight}); 656 } else { 657 $self-> {list}-> height($hei); 658 } 659 $self-> {listHeight} = $hei; 660} 661 662sub get_style { return $_[0]-> {style}} 663sub get_list_visible{ return $_[0]-> {list} ? $_[0]-> {list}-> visible : 0} 664sub get_edit_height { return $_[0]-> {edit} ? $_[0]-> {edit}-> height : 0} 665sub get_list_height { return $_[0]-> {list} ? $_[0]-> {list}-> height : 0} 666 667sub caseSensitive{($#_)?$_[0]-> {caseSensitive}=$_[1]:return $_[0]-> {caseSensitive};} 668sub listVisible {($#_)?$_[0]-> set_list_visible($_[1]):return $_[0]-> get_list_visible;} 669sub style {($#_)?$_[0]-> set_style ($_[1]):return $_[0]-> get_style; } 670sub editHeight {($#_)?$_[0]-> set_edit_height($_[1]):return $_[0]-> get_edit_height;} 671sub listHeight {($#_)?$_[0]-> set_list_height ($_[1]):return $_[0]-> get_list_height;} 672sub literal {($#_)?$_[0]-> {literal} = $_[1] :return $_[0]-> {literal} } 673 6741; 675 676=pod 677 678=head1 NAME 679 680Prima::ComboBox - standard combo box widget 681 682=head1 SYNOPSIS 683 684 use Prima qw(Application ComboBox); 685 686 my $combo = Prima::ComboBox-> new( style => cs::DropDown, items => [ 1 .. 10 ]); 687 $combo-> style( cs::DropDownList ); 688 print $combo-> text; 689 690 run Prima; 691 692=for podview <img src="combo.gif"> 693 694=for html <p><img src="https://raw.githubusercontent.com/dk/Prima/master/pod/Prima/combo.gif"> 695 696=head1 DESCRIPTION 697 698Provides a combo box widget which consists of an input line, list box of possible 699selections and eventual drop-down button. The combo box can be either in form 700with a drop-down selection list, that is shown by the command of the user, 701or in form when the selection list is always visible. 702 703The combo box is a grouping widget, and contains neither painting nor user-input 704code. All such functionality is delegated into the children widgets: input line, list 705box and button. C<Prima::ComboBox> exports a fixed list of methods and properties from 706namespaces of L<Prima::InputLine> and L<Prima::ListBox>. Since, however, it is 707possible to tweak the C<Prima::ComboBox> ( using its L<editClass> and L<listClass> 708create-only properties ) so the input line and list box would be other classes, 709it is not necessarily that all default functionality would work. 710The list of exported names is stored in package variables %listProps, %editProps 711and %listDynas. These also described in L<Exported names> section. 712 713The module defines C<cs::> package for the constants used by L<style> property. 714 715=head1 API 716 717=head2 Properties 718 719=over 720 721=item autoHeight BOOLEAN 722 723If 1, adjusts the height of the widget automatically when its font changes. 724Only when style is not C<cs::Simple>. 725 726Default value: 1 727 728=item buttonClass STRING 729 730Assigns a drop-down button class. 731 732Create-only property. 733 734Default value: C<Prima::Widget> 735 736=item buttonDelegations ARRAY 737 738Assigns a drop-down button list of delegated notifications. 739 740Create-only property. 741 742=item buttonProfile HASH 743 744Assigns hash of properties, passed to the drop-down button during the creation. 745 746Create-only property. 747 748=item caseSensitive BOOLEAN 749 750Selects whether the user input is case-sensitive or not, when a value 751is picked from the selection list. 752 753Default value: 0 754 755=item editClass STRING 756 757Assigns an input line class. 758 759Create-only property. 760 761Default value: C<Prima::InputLine> 762 763=item editProfile HASH 764 765Assigns hash of properties, passed to the input line during the creation. 766 767Create-only property. 768 769=item editDelegations ARRAY 770 771Assigns an input line list of delegated notifications. 772 773Create-only property. 774 775=item editHeight INTEGER 776 777Selects height of an input line. 778 779=item items ARRAY 780 781Mapped onto the list widget's C<items> property. See L<Prima::Lists> for details. 782 783=item listClass STRING 784 785Assigns a listbox class. 786 787Create-only property. 788 789Default value: C<Prima::ListBox> 790 791=item listHeight INTEGER 792 793Selects height of the listbox widget. 794 795Default value: 100 796 797=item listVisible BOOLEAN 798 799Sets whether the listbox is visible or not. Not writable 800when L<style> is C<cs::Simple>. 801 802=item listProfile HASH 803 804Assigns hash of properties, passed to the listbox during the creation. 805 806Create-only property. 807 808=item listDelegations ARRAY 809 810Assigns a selection listbox list of delegated notifications. 811 812Create-only property. 813 814=item literal BOOLEAN 815 816Selects whether the combo box user input routine assume that 817the listbox contains literal strings, that can be fetched via 818C<get_item_text> ( see L<Prima::Lists> ). As an example when 819this property is set to 0 is C<Prima::ColorComboBox> from L<Prima::ComboBox> package. 820 821Default value: 1 822 823=item style INTEGER 824 825Selected one of three styles: 826 827=over 828 829=item cs::Simple 830 831The listbox is always visible, and the drop-down button is not. 832 833=item cs::DropDown 834 835The listbox is not visible, but the drop-down button is. When the 836use presses the drop-down button, the listbox is shown; when the list-box 837is defocused, it gets hidden. 838 839=item cs::DropDownList 840 841Same as C<cs::DropDown>, but the user is restricted in the selection: 842the input line can only accept user input that is contained in listbox. 843If L<literal> set to 1, the auto completion feature is provided. 844 845=back 846 847=item text STRING 848 849Mapped onto the edit widget's C<text> property. 850 851=back 852 853=head2 Events 854 855=over 856 857=item Change 858 859Triggered with ComboBox value is changed. 860 861=item List events 862 863ComboBox forwards C<SelectItem> and C<DrawItem> events from the list box, and 864these are executed in the List's context (therefore $self there is not 865ComboBox, but the ComboBox->List). If you use C<SelectItem> you probably need 866C<Change> instead. 867 868See more in L<Prima::Lists>. 869 870=back 871 872=head2 Exported names 873 874=over 875 876=item %editProps 877 878 alignment autoScroll text text 879 charOffset maxLen insertMode firstChar 880 selection selStart selEnd writeOnly 881 copy cut delete paste 882 wordDelimiters readOnly passwordChar focus 883 select_all 884 885=item %listProps 886 887 focusedItem hScroll 888 integralHeight items itemHeight 889 topItem vScroll gridColor 890 multiColumn offset 891 892=item %listDynas 893 894 onDrawItem 895 onSelectItem 896 897=back 898 899=head1 AUTHOR 900 901Dmitry Karasik, E<lt>dmitry@karasik.eu.orgE<gt>. 902 903=head1 SEE ALSO 904 905L<Prima>, L<Prima::InputLine>, L<Prima::Lists>, L<Prima::Dialog::ColorDialog>, L<Prima::Dialog::FileDialog>, 906F<examples/listbox.pl>. 907 908=cut 909