1# contains 2# DockManager 3# DockManager::LaunchPad 4# DockManager::Toolbar 5# DockManager::ToolbarDocker 6# DockManager::Panelbar 7# DockManager::S::SpeedButton; 8# 9 10use strict; 11use warnings; 12use Prima; 13use Prima::Utils; 14use Prima::Docks; 15use Prima::Notebooks; 16use Prima::Lists; 17use Prima::StdBitmap; 18 19package Prima::DockManager::LaunchPad; 20use vars qw(@ISA); 21@ISA = qw(Prima::Notebook Prima::SimpleWidgetDocker); 22 23sub profile_default 24{ 25 my $def = $_[0]-> SUPER::profile_default; 26 my %prf = ( 27 fingerprint => 0x0000FFFF, 28 dockup => undef, 29 ); 30 @$def{keys %prf} = values %prf; 31 return $def; 32} 33 34sub init 35{ 36 my $self = shift; 37 my %profile = $self-> SUPER::init( @_); 38 $self-> $_( $profile{$_}) for ( qw(fingerprint dockup)); 39 return %profile; 40} 41 42# inner part of toolbar tandem 43 44package Prima::DockManager::ToolbarDocker; 45use vars qw(@ISA); 46@ISA = qw(Prima::SingleLinearWidgetDocker); 47 48sub profile_default 49{ 50 my $def = $_[0]-> SUPER::profile_default; 51 my %prf = ( 52 parentDocker => undef, 53 instance => undef, 54 x_sizeable => 0, 55 y_sizeable => 0, 56 ); 57 @$def{keys %prf} = values %prf; 58 return $def; 59} 60 61sub init 62{ 63 my ($self, %profile) = @_; 64 %profile = $self-> SUPER::init( %profile); 65 $self-> $_($profile{$_}) for qw( parentDocker instance); 66 return %profile; 67} 68 69sub get_extent 70{ 71 my $self = $_[0]; 72 my @ext = (0,0); 73 for ($self-> docklings) { 74 my @z = $_-> rect; 75 for (0,1) { 76 $ext[$_] = $z[$_+2] if $ext[$_] < $z[$_+2] 77 } 78 } 79 return @ext; 80} 81 82sub update_size 83{ 84 my ( $self, @sz) = @_; 85 my $o = $self-> parentDocker; 86 return unless $o; 87 @sz = $self-> size unless scalar @sz; 88 my @r = $o-> client2frame( 0, 0, @sz); 89 $o-> size( $r[2] - $r[0], $r[3] - $r[1]); 90 $self-> size( @sz); 91 if ( $o-> dock) { 92 $o-> redock; 93 } else { 94 @r = $o-> externalDocker-> client2frame( 0,0, @sz); 95 $o-> externalDocker-> size($r[2] - $r[0], $r[3] - $r[1]); 96 $self-> rect( 0,0,@sz); # respect growMode 97 } 98} 99 100# this part is responsible for changing toolbar's size when new tools are docked in 101sub dock 102{ 103 return $_[0]-> {dock} unless $#_; 104 my $self = shift; 105 my @sz = $self-> size; 106 $self-> SUPER::dock(@_); 107 my @sz1 = $self-> size; 108 my $resize = 0; 109 my @ext = $self-> get_extent; 110 for ( 0, 1) { 111 $resize = 1, $sz1[$_] = $ext[$_] if $sz1[$_] > $ext[$_]; 112 } 113 return if !$resize && ($sz[0] == $sz1[0] && $sz[1] == $sz1[1]); 114 $self-> size( @sz1); 115 $self-> update_size( @sz1); 116} 117 118sub rearrange 119{ 120 my $self = $_[0]; 121# fast version of rearrange, without real redocking 122 my $v = $self-> vertical; 123 my @ext = (0,0); 124 my ( $xid, $yid) = ( $v ? 0 : 1, $v ? 1 : 0); 125 my $a; 126 for ( $self-> docklings) { 127 $a = $_ unless $a; # 128 my @sz = $_-> size; 129 $_-> origin( $v ? ( 0, $ext[1]) : ( $ext[0], 0)); 130 $ext[$xid] = $sz[$xid] if $ext[$xid] < $sz[$xid]; 131 $ext[$yid] += $sz[$yid]; 132 } 133 if ( $a) { 134 $self-> size( @ext); 135 #innvoke dock-undock, just to be sure, but for only one widget 136 $self-> redock_widget( $a); 137 } 138} 139 140sub parentDocker 141{ 142 return $_[0]-> {parentDocker} unless $#_; 143 $_[0]-> {parentDocker} = $_[1]; 144} 145 146sub instance 147{ 148 return $_[0]-> {instance} unless $#_; 149 $_[0]-> {instance} = $_[1]; 150} 151 152sub on_dockerror 153{ 154 my ( $self, $urchin) = @_; 155 $self-> redock_widget( $urchin); 156} 157 158sub on_undock 159{ 160 my $self = $_[0]; 161 return if scalar(@{$self->{docklings}}); 162 my $i = $self-> instance; 163 $i-> post( sub { 164 return if scalar(@{$self->{docklings}}); 165 if ( $self-> parentDocker-> autoClose) { 166 $self-> parentDocker-> destroy; 167 } else { 168 $i-> toolbar_visible( $self-> parentDocker, 0); 169 $i-> notify(q(ToolbarChange)); 170 } 171 }); 172} 173 174package Prima::DockManager::Toolbar; 175use vars qw(@ISA); 176@ISA = qw(Prima::LinearDockerShuttle); 177 178sub profile_default 179{ 180 my $def = $_[0]-> SUPER::profile_default; 181 my %prf = ( 182 instance => undef, 183 childDocker => undef, 184 autoClose => 1, 185 ); 186 @$def{keys %prf} = values %prf; 187 return $def; 188} 189 190sub init 191{ 192 my $self = shift; 193 my %profile = $self-> SUPER::init( @_); 194 $self-> $_( $profile{$_}) for ( qw(instance childDocker autoClose)); 195 return %profile; 196} 197 198sub autoClose 199{ 200 return $_[0]-> {autoClose} unless $#_; 201 $_[0]-> {autoClose} = $_[1]; 202} 203 204sub childDocker 205{ 206 return $_[0]-> {childDocker} unless $#_; 207 $_[0]-> {childDocker} = $_[1]; 208} 209 210sub instance 211{ 212 return $_[0]-> {instance} unless $#_; 213 $_[0]-> {instance} = $_[1]; 214} 215 216sub on_getcaps 217{ 218 my ( $self, $docker, $prf) = @_; 219 $self-> SUPER::on_getcaps( $docker, $prf); 220 my @cd = $self-> {childDocker}-> size; 221 my @i = @{$self-> {indents}}; 222 my @sz = ($i[2] + $i[0] + $cd[0], $i[3] + $i[1] + $cd[1]); 223 $prf-> {sizeMin} = [ @sz]; 224 my $vs = $docker-> can('vertical') ? $docker-> vertical : 0; 225 my $v = $self-> {vertical}; 226 $prf-> {sizes} = ( $v == $vs) ? [[@sz]] : [[@sz[1,0]]]; 227} 228 229sub on_dock 230{ 231 my $self = $_[0]; 232 my $nv = $self-> dock-> can('vertical') ? $self-> dock-> vertical : 0; 233 return if $nv == $self-> {vertical}; 234 $self-> vertical( $nv); 235 my $c = $self-> {childDocker}; 236 $c-> vertical( $nv); 237 $c-> rect( $self-> frame2client( 0, 0, $self-> size)); 238 $c-> rearrange; 239} 240 241package Prima::DockManager::Panelbar; 242use vars qw(@ISA); 243@ISA = qw(Prima::LinearDockerShuttle); 244 245sub profile_default 246{ 247 my $def = $_[0]-> SUPER::profile_default; 248 my %prf = ( 249 vertical => 1, 250 instance => undef, 251 externalDockerProfile => { borderStyle => bs::Sizeable }, 252 x_sizeable => 1, 253 y_sizeable => 1, 254 ); 255 @$def{keys %prf} = values %prf; 256 return $def; 257} 258 259sub init 260{ 261 my $self = shift; 262 my %profile = $self-> SUPER::init( @_); 263 $self-> $_( $profile{$_}) for ( qw(instance)); 264 return %profile; 265} 266 267sub instance 268{ 269 return $_[0]-> {instance} unless $#_; 270 $_[0]-> {instance} = $_[1]; 271} 272 273 274# flags for fingerprints - for different dockers and stages. 275package 276 dmfp; 277 278use constant Tools => 0x0F000; # those who want tools, must set this 279use constant Toolbar => 0x10000; # those who want toolbars, must set this 280use constant LaunchPad => 0x20000; # tools that want to be disposable, set this 281 282package Prima::DockManager; 283use vars qw(@ISA); 284@ISA = qw(Prima::Component Prima::AbstractDocker::Interface); 285 286{ 287my %RNT = ( 288 %{Prima::Component->notification_types()}, 289 CommandChange => nt::Notification, 290 ToolbarChange => nt::Notification, 291 PanelChange => nt::Notification, 292 Command => nt::Command, 293); 294 295sub notification_types { return \%RNT; } 296} 297 298sub profile_default 299{ 300 my $def = $_[0]-> SUPER::profile_default; 301 my %prf = ( 302 interactiveDrag => 0, 303 commands => {}, 304 ); 305 @$def{keys %prf} = values %prf; 306 return $def; 307} 308 309sub init 310{ 311 my $self = shift; 312 $self-> {commands} = {}; 313 $self-> {interactiveDrag} = 0; 314 my %profile = $self-> SUPER::init( @_); 315 $self-> {classes} = []; 316 $self-> {hiddenToolbars} = []; 317 $self-> {toolbars} = []; 318 $self-> {panels} = []; 319 $self-> $_( $profile{$_}) for ( qw( commands interactiveDrag)); 320 return %profile; 321} 322 323sub interactiveDrag 324{ 325 return $_[0]-> {interactiveDrag} unless $#_; 326 my ( $self, $id) = @_; 327 return if $id == $self-> {interactiveDrag}; 328 $self-> {interactiveDrag} = $id; 329 if ( $id) { 330 for ( $self-> toolbars) { 331 $_-> enabled(1) for $_-> childDocker-> docklings; 332 } 333 } else { 334 my $c = $self-> {commands}; 335 for ( $self-> toolbars) { 336 for ( $_-> childDocker-> docklings) { 337 next if !defined $_->{CLSID} || !exists($c-> {$_->{CLSID}}) || $c-> {$_->{CLSID}}; 338 $_-> enabled(0); 339 } 340 } 341 } 342} 343 344sub toolbars { return @{$_[0]->{toolbars}}} 345sub panels { return @{$_[0]->{panels}}} 346 347sub fingerprint { return 0xFFFFFFFF } 348 349sub register_tool 350{ 351 my ( $self, $CLSID, $hash) = @_; 352 $hash-> {tool} = 1; 353 push @{$self-> {classes}}, $CLSID, $hash; 354} 355 356sub register_panel 357{ 358 my ( $self, $CLSID, $hash) = @_; 359 $hash-> {tool} = 0; 360 push @{$self-> {classes}}, $CLSID, $hash; 361} 362 363sub get_class 364{ 365 my ( $self, $CLSID) = @_; 366 my $i; 367 my $c = $self-> {classes}; 368 my $x = scalar @$c; 369 for ( $i = 0; $i < $x; $i+=2) { 370 return $$c[$i+1] if $CLSID eq $$c[$i]; 371 } 372} 373 374sub panel_by_id 375{ 376 my ( $self, $name) = @_; 377 for ( @{$self-> {panels}}) { 378 return $_ if $_-> {CLSID} eq $name; 379 } 380} 381 382sub toolbar_by_name 383{ 384 my ( $self, $name) = @_; 385 for ( @{$self-> {toolbars}}) { 386 return $_ if $_-> name eq $name; 387 } 388} 389 390sub post 391{ 392 my ( $self, $sub, @parms) = @_; 393 $self-> post_message( 'sub', [ $sub, @parms]); 394} 395 396sub on_postmessage 397{ 398 my ( $self, $id, $val) = @_; 399 return unless $id eq 'sub'; 400 my $sub = shift @$val; 401 $sub->( $self, @$val); 402} 403 404sub create_manager 405{ 406 my ( $self, $where, %profile) = @_; 407 my @o = exists($profile{origin}) ? @{$profile{origin}} : (0,0); 408 my @sz = exists($profile{size}) ? @{$profile{size}} : ($where-> size); 409 my ( @items, %items); 410 my @lclasses; 411 my $i = 0; 412 my $cls = $self-> {classes}; 413 my $xcls = scalar @$cls; 414 for ( $i = 0; $i < $xcls; $i += 2) { 415 my ( $CLSID, $hash) = @$cls[$i, $i+1]; 416 next unless $hash->{tool}; 417 push ( @lclasses, $CLSID); 418 $CLSID =~ m/^([^\:]+)(?:\:|$)/; 419 next if !$1 || exists($items{$1}); 420 $items{$1} = 1; 421 push( @items, $1); 422 } 423 $i = 0; 424 my $nb; 425 my $lb = $where-> insert( ListBox => 426 origin => [@o], 427 size => [ int($sz[0] / 3), $sz[1]], 428 name => 'GroupSelector', 429 vScroll => 1, 430 items => \@items, 431 growMode=> gm::Client, 432 focusedItem => 0, 433 onSelectItem => sub { 434 my ($self,$lst,$state) = @_; 435 return unless $state; 436 $nb-> pageIndex( $self-> focusedItem); 437 }, 438 exists($profile{listboxProfile}) ? %{$profile{listboxProfile}} : (), 439 ); 440 $nb = $where-> insert( 'Prima::DockManager::LaunchPad' => 441 exists($profile{dockerProfile}) ? %{$profile{dockerProfile}} : (), 442 origin => [ $o[0] + int($sz[0] / 3), 0], 443 size => [ $sz[0] - int($sz[0] / 3), $sz[1]], 444 name => 'PageFlipper', 445 pageCount => scalar(@items), 446 growMode => gm::GrowHiY|gm::GrowLoX, 447 fingerprint => dmfp::LaunchPad, 448 dockup => $self, 449 ); 450 $nb-> {dockingRoot} = $self; 451 $i = 0; 452 my %x = @$cls; 453 my @szn = $nb-> size; 454 455 for ( @items) { 456 my $iid = $_; 457 my @d = grep { m/^([^\:]+)(?:\:|$)/; my $j = $1 || ''; $j eq $iid; } @lclasses; 458 my @org = (5,5); 459 my $maxy = 0; 460 my @ctrls; 461 my $ix = 0; 462 for ( @d) { 463 my %acp = exists($x{$_}-> {profile}) ? %{$x{$_}-> {profile}} : (); 464 my $ctrl = $nb-> insert_to_page( $i, $x{$_}->{class} => 465 growMode => gm::GrowLoY, 466 %acp, 467 onMouseDown => \&Control_MouseDown_FirstStage, 468 onKeyDown => \&Control_KeyDown, 469 origin => [ @org], 470 ); 471 $ctrl-> {CLSID} = $_; 472 $ctrl-> {DOCKMAN} = $self; 473 push ( @ctrls, $ctrl); 474 my @s = $ctrl-> size; 475 if (( $s[0] + $org[0] > $szn[0] - 5) && ( $ix > 0)) { 476 $ctrl-> origin( $org[0] = 5, $org[1] += $maxy + 3); 477 $maxy = 0; 478 } else { 479 $org[0] += $s[0] + 1; 480 $maxy = $s[1] if $maxy < $s[1]; 481 } 482 $ix++; 483 } 484 if ( $org[1] + $maxy < $szn[1] - 5) { 485 my $d = $sz[1] - 5 - $org[1] - $maxy; 486 for ( @ctrls) { 487 my @o = $_-> origin; 488 $_-> origin( $o[0], $o[1] + $d); 489 } 490 } 491 $i++; 492 } 493 return $lb, $nb; 494} 495 496sub create_tool 497{ 498 my ( $self, $where, $CLSID, @rect) = @_; 499 my $x = $self-> get_class( $CLSID); 500 return unless $x; 501 my %acp = exists($x-> {profile}) ? %{$x-> {profile}} : (); 502 %acp = ( %acp, 503 onMouseDown => \&Control_MouseDown, 504 onKeyDown => \&Control_KeyDown, 505 onDestroy => \&Control_Destroy, 506 ); 507 $acp{rect} = \@rect if 4 == scalar @rect; 508 my $ctrl = $where-> insert( $x->{class} => %acp); 509 $ctrl-> {CLSID} = $CLSID; 510 $ctrl-> {DOCKMAN} = $self; 511 $ctrl-> enabled(0) if !$self-> {interactiveDrag} && exists( $self-> {commands}->{$CLSID}) 512 && !$self-> {commands}->{$CLSID}; 513 return $ctrl; 514} 515 516sub create_toolbar 517{ 518 my ( $self, %profile) = @_; 519 my $v = $profile{vertical} || 0; 520 my $dock = $profile{dock}; 521 my $auto = exists( $profile{autoClose}) ? $profile{autoClose} : ( exists($profile{name}) ? 1 : 0); 522 my $name = $profile{name} || $self-> auto_toolbar_name; 523 my $visible = exists($profile{visible}) ? $profile{visible} : 1; 524 my @r = $profile{rect} ? @{$profile{rect}} : ( 0, 0, 10, 10); 525 my $acd = $profile{dockerProfile} || {}; 526 my $aci = $profile{toolbarProfile} || {}; 527 528 my $x = Prima::DockManager::Toolbar-> create( 529 dockingRoot => $self, 530 name => $name, 531 text => $name, 532 visible => $visible, 533 vertical => $v, 534 instance => $self, 535 autoClose => $auto, 536 onEDSClose => \&Toolbar_EDSClose, 537 %$acd, 538 ); 539 540 my @i = @{$x-> indents}; 541 $x-> rect( $r[0] - $i[0], $r[1] - $i[1], $r[2] + $i[2], $r[3] + $i[3]); 542 @r = $x-> frame2client( $x-> rect); 543 544 my $xcl = $x-> insert( 'Prima::DockManager::ToolbarDocker' => 545 %$aci, 546 origin => [ @i[0,1]], 547 size => [ $r[2] - $r[0], $r[3] - $r[1]], 548 vertical => $v, 549 growMode => gm::Client, 550 fingerprint => dmfp::Toolbar, 551 parentDocker => $x, 552 name => $name, 553 instance => $self, 554 onDestroy => \&Toolbar_Destroy, 555 ); 556 $x-> client( $xcl); 557 $x-> childDocker( $xcl); 558 $self-> add_subdocker( $xcl); 559 if ( $profile{dock}) { 560 $x-> dock( $dock, $dock-> client_to_screen( $x-> rect)); 561 } else { 562 $x-> externalDocker-> rect( $x-> externalDocker-> client2frame( @r)); 563 } 564 push ( @{$self-> {toolbars}}, $x); 565 $self-> toolbar_visible( $x, 0) unless $visible; 566 $self-> notify(q(ToolbarChange)); 567 return $x, $xcl; 568} 569 570sub create_panel 571{ 572 my ( $self, $CLSID, %profile) = @_; 573 my $prf = $self-> get_class( $CLSID); 574 return unless $prf; 575 my %prf = ( 576 dockingRoot => $self, 577 x_sizeable => 1, 578 y_sizeable => 1, 579 instance => $self, 580 ); 581 $prf{text} = $prf-> {text} if exists $prf-> {text}; 582 my $x = Prima::DockManager::Panelbar-> create( %prf, 583 $prf-> {dockerProfile} ? %{$prf-> {dockerProfile}} : (), 584 $profile{dockerProfile} ? %{$profile{dockerProfile}} : (), 585 dock => undef, 586 ); 587 $x-> onEDSClose( \&Panel_EDSClose); 588 $prf-> {text} = $x-> text unless exists $prf-> {text}; 589 my @rrc = $x-> frame2client( 0, 0, $x-> size); 590 my $xcl = $x-> insert( $prf->{class} => 591 growMode => gm::Client, 592 $prf-> {profile} ? %{$prf-> {profile}} : (), 593 $profile{profile} ? %{$profile{profile}} : (), 594 rect => [@rrc], 595 ); 596 $xcl-> add_notification( 'Destroy', \&Panelbar_Destroy, $x); 597 $x-> client( $xcl); 598 push( @{$self-> {panels}}, $x); 599 $x-> {CLSID} = $CLSID; 600 if ( $prf-> {dockerProfile}-> {dock} || $profile{dockerProfile}-> {dock}) { 601 my $dock = $prf-> {dockerProfile}-> {dock} || $profile{dockerProfile}-> {dock}; 602 $x-> dock( $dock, $dock-> client_to_screen( $x-> rect)); 603 } 604 $self-> notify(q(PanelChange)); 605 return ( $x, $xcl); 606} 607 608sub auto_toolbar_name 609{ 610 my $name; 611 my $self = $_[0]; 612 my @ids; 613 for ( @{$self->{toolbars}}) { 614 my $x = $_-> name; 615 next unless $x =~ m/^ToolBar(\d+)$/; 616 $ids[$1] = 1; 617 } 618 my $i = 0; 619 for ( @ids) { 620 $i++, next unless $i; # skip ToolBar0 621 $name = $i, last unless $_; 622 $i++; 623 } 624 $name = scalar(@ids) unless defined $name; 625 $name++ unless $name; 626 return "ToolBar$name"; 627} 628 629sub toolbar_menuitems 630{ 631 my ( $self, $sub) = @_; 632 my @items; 633 for ( @{$self->{toolbars}}) { 634 my $vis = $_-> dock() ? $_-> visible : $_-> externalDocker-> visible; 635 $vis = ( $vis ? '*' : '') . $_-> name; 636 push ( @items, [ $vis => $_-> name => $sub ]); 637 } 638 return \@items; 639} 640 641sub panel_menuitems 642{ 643 my ( $self, $sub) = @_; 644 my @items; 645 my %h = map { $_->{CLSID} => 1} @{$self-> {panels}}; 646 my $i; 647 my $c = $self-> {classes}; 648 for ( $i = 0; $i < @$c; $i += 2) { 649 my ( $CLSID, $hash) = @$c[$i,$i+1]; 650 next if $hash->{tool}; 651 my $vis = ( $h{$CLSID} ? '*' : '') . $CLSID; 652 push ( @items, [ $vis => $hash-> {text} => $sub ]); 653 } 654 return \@items; 655} 656 657sub toolbar_visible 658{ 659 my ( $self, $d, $visible) = @_; 660 return unless $d; 661 if ( $d-> dock) { 662 return if $visible == $d-> visible; 663 if ( $visible) { 664 $d-> dock_back; 665 } else { 666 $d-> dock( undef); 667 $d-> externalDocker-> visible( $visible); 668 } 669 } else { 670 return if $visible == $d-> externalDocker-> visible; 671 $d-> externalDocker-> visible( $visible); 672 } 673} 674 675sub panel_visible 676{ 677 my ( $self, $panelbarCLSID, $visible) = @_; 678 my $d = $self-> panel_by_id( $panelbarCLSID); 679 my $hash = $self-> get_class( $panelbarCLSID); 680 if ( $visible) { 681 return if $d; 682 my %pf; 683 if ( $hash-> {lastUsedDock} && Prima::Object::alive($hash-> {lastUsedDock})) { 684 $pf{dockerProfile}->{dock} = $hash-> {lastUsedDock}; 685 } 686 if ( $hash-> {lastUsedRect}) { 687 $pf{dockerProfile}->{rect} = $hash-> {lastUsedRect}; 688 } 689 my ( $x, $xcl) = $self-> create_panel( $panelbarCLSID, %pf); 690 $x-> bring_to_front; 691 } else { 692 return unless $d; 693 $hash-> {lastUsedDock} = $d-> dock; 694 $hash-> {lastUsedRect} = [$d-> dock ? $d-> rect : $d-> externalDocker-> rect], 695 $d-> close; 696 } 697} 698 699sub predefined_toolbars 700{ 701 my $self = shift; 702 my %toolbars = map { $_-> name => $_ } @{$self-> {toolbars}}; 703 my %c = @{$self-> {classes}}; 704 my @o = ( 10, $::application-> height - 100); 705 my @as = $::application-> size; 706 for ( @_) { 707 my $rec = $_; 708 next if $toolbars{$_-> {name}}; 709 my @org = (0,0); 710 my $maxy = 0; 711 my @ctrls; 712 my @list = $rec->{list} ? @{$rec->{list}} : (); 713 for ( @list) { 714 my $ctrl = $self-> create_tool( $::application, $_); 715 next unless $ctrl; 716 $ctrl-> origin( @org); 717 my @sz = $ctrl-> size; 718 $org[0] += $sz[0]; 719 $maxy = $sz[1] if $maxy < $sz[1]; 720 push ( @ctrls, $ctrl); 721 } 722 my @oz = $rec->{origin} ? @{$rec->{origin}} : ( $rec->{dock} ? (0,0) : @o); 723 my ( $x, $xcl) = $self-> create_toolbar( 724 name => $_->{name}, 725 rect => [ @oz, $oz[0]+$org[0], $oz[1]+$maxy], 726 visible => 1, 727 dock => $rec->{dock}, 728 ); 729 for ( @ctrls) { 730 $_-> owner( $xcl); 731 $xcl-> dock( $_); 732 } 733 $xcl-> rearrange; 734 $o[0] += 25; 735 $o[1] -= 25; 736 } 737} 738 739sub predefined_panels 740{ 741 my ( $self, @rec) = @_; 742 my $i; 743 my %pan = map { $_-> {CLSID} => 1 } @{$self-> {panels}}; 744 for ( $i = 0; $i < scalar @rec; $i += 2) { 745 my ( $CLSID, $dock) = @rec[$i, $i+1]; 746 next if $pan{$CLSID}; 747 my ( $a, $b) = $self-> create_panel( $CLSID, dockerProfile => {dock => $dock}); 748 } 749} 750 751sub activate 752{ 753 my $self = $_[0]; 754 for ( @{$self->{panels}}, @{$self-> {toolbars}}) { 755 next if $_-> dock; 756 $_-> externalDocker-> bring_to_front if $_-> externalDocker; 757 } 758} 759 760sub windowState 761{ 762 my ( $self, $ws) = @_; 763 if ( $ws == ws::Minimized) { 764 for ( @{$self->{panels}}, @{$self-> {toolbars}}) { 765 next if $_-> dock; 766 my $e = $_-> externalDocker; 767 next unless $e; 768 $e-> hide; 769 push ( @{$self->{hiddenToolbars}}, $e); 770 } 771 } else { 772 $_-> show for @{$self->{hiddenToolbars}}; 773 @{$self->{hiddenToolbars}} = (); 774 } 775} 776 777sub commands_enable 778{ 779 my ( $self, $enable) = ( shift, shift); 780 my %cmds = map { $_ => 1 } @_; 781 unless ( $self-> interactiveDrag) { 782 for ( $self-> toolbars) { 783 for ( $_-> childDocker-> docklings) { 784 next if !defined $_->{CLSID} || !$cmds{$_->{CLSID}} || $enable == $self-> {commands}->{$_->{CLSID}}; 785 $_-> enabled( $enable); 786 } 787 } 788 } 789 for ( keys %{$self->{commands}}) { 790 next unless $cmds{$_}; 791 $self-> {commands}-> {$_} = $enable; 792 } 793 $self-> notify(q(CommandChange)); 794} 795 796sub commands 797{ 798 return $_[0]-> {commands} unless $#_; 799 my ( $self, $cmds) = @_; 800 $self-> {commands} = $cmds; 801 unless ( $self-> interactiveDrag) { 802 for ( $self-> toolbars) { 803 for ( $_-> childDocker-> docklings) { 804 next if !defined $_->{CLSID} || !$cmds-> {$_->{CLSID}}; 805 $_-> enabled( $cmds-> {$_-> {CLSID}}); 806 } 807 } 808 } 809 $self-> notify(q(CommandChange)); 810} 811 812# internals 813 814sub autodock 815{ 816 my ( $self, $ctrl) = @_; 817 my $dock = $ctrl-> owner; 818 $dock-> undock( $ctrl); 819 820 my ( $x, $xcl) = $self-> create_toolbar( 821 vertical => $dock-> can('vertical') ? $dock-> vertical : 0, 822 dock => $dock, 823 rect => [$ctrl-> rect], 824 autoClose => 1, 825 ); 826 $ctrl-> owner( $xcl); 827 $ctrl-> origin( 0,0); 828 $xcl-> dock( $ctrl); 829 return $x; 830} 831 832 833sub Control_KeyDown 834{ 835 return unless $_[0]-> {DOCKMAN}-> interactiveDrag; 836 $_[0]-> clear_event; 837} 838 839sub Control_MouseDown_FirstStage 840{ 841 my ($self,$btn, $mod, $x,$y) = @_; 842 return unless $btn == mb::Left; 843 my $man = $self-> {DOCKMAN}; 844 my $c = Prima::InternalDockerShuttle-> create( 845 owner => $self-> owner, 846 rect => [$self-> rect], 847 dockingRoot => $man, 848 fingerprint => dmfp::LaunchPad | dmfp::Toolbar | dmfp::Tools, # allow all docks 849 backColor => cl::Yellow, 850 onLanding => \&InternalDockerShuttle_Landing, 851 name => 'FirstStage', 852 onDock => sub { 853 my $me = $_[0]; 854 if ( $me-> owner-> isa(q(Prima::DockManager::LaunchPad))) { 855 $man-> post( sub { $me-> destroy; }); 856 return; 857 } 858 my $ctrl = $man-> create_tool( $me-> owner, $self-> {CLSID}, $me-> rect); 859 return unless $ctrl; 860 $me-> {dock} = undef; 861 $me-> owner-> replace( $me, $ctrl); 862 $man-> post( sub { $me-> destroy; }); 863 $man-> autodock( $ctrl) 864 unless $me-> owner-> isa(q(Prima::DockManager::ToolbarDocker)); 865 }, 866 onFailDock => sub { 867 my ( $me, $ax, $ay) = @_; 868 my ( $x, $xcl) = $man-> create_toolbar( rect => [$me-> rect], autoClose => 1); 869 $xcl-> dock( $man-> create_tool( $xcl, $self-> {CLSID})); 870 $x-> externalDocker-> origin( $ax, $ay); 871 $man-> post( sub { $me-> destroy; }); 872 }, 873 ); 874 $c-> externalDocker-> hide; 875 $::application-> yield; 876 $c-> drag( 1, [ $self-> client_to_screen(0,0,$self-> size)], $c-> screen_to_client( $self-> client_to_screen($x, $y))); 877 $self-> clear_event; 878} 879 880sub Control_Destroy 881{ 882 $_[0]-> owner-> undock( $_[0]); 883} 884 885sub Control_MouseDown 886{ 887 my ( $self, $btn, $mod, $x, $y) = @_; 888 my $man = $self-> {DOCKMAN}; 889 return unless $man-> interactiveDrag; 890 $self-> clear_event; 891 return unless $btn == mb::Left; 892 893 my $c; 894 $c = Prima::InternalDockerShuttle-> create( 895 owner => $self-> owner, 896 rect => [$self-> rect], 897 dockingRoot => $man, 898 fingerprint => dmfp::LaunchPad | dmfp::Toolbar | dmfp::Tools, # allow all docks 899 backColor => cl::White, 900 onLanding => \&InternalDockerShuttle_Landing, 901 name => 'SecondStage', 902 onDock => sub { 903 my $me = $_[0]; 904 $me-> {dock} = undef; 905 $me-> owner-> replace( $me, $self); 906 $man-> post( sub { $me-> destroy; }); 907 if ( $me-> owner-> isa(q(Prima::DockManager::LaunchPad))) { 908 $man-> post( sub { $self-> destroy; }); 909 return; 910 } 911 $man-> autodock( $self) unless $me-> owner-> isa(q(Prima::DockManager::ToolbarDocker)); 912 }, 913 onFailDock => sub { 914 $self-> owner-> replace( $c, $self); 915 $c-> {dock} = undef; 916 $man-> post( sub { $c-> destroy; }); 917 }, 918 ); 919 $c-> {dock} = $self-> owner; 920 $self-> owner-> replace( $self, $c); 921 $c-> externalDocker-> hide; 922 $c-> hide; 923 $::application-> yield; 924 $c-> drag( 1, [ $self-> client_to_screen(0,0,$self-> size)], $c-> screen_to_client( $self-> client_to_screen($x, $y))); 925} 926 927sub Panelbar_Destroy 928{ 929 my $self = $_[0]; 930 my $i = $self-> instance; 931 return unless $i; 932 @{$i-> {panels}} = grep { $_ != $self } @{$i->{panels}}; 933 @{$i-> {hiddenToolbars}} = grep { $_ != $self } @{$i->{hiddenToolbars}}; 934 $i-> notify(q(PanelChange)); 935} 936 937sub Toolbar_Destroy 938{ 939 my $self = $_[0]-> parentDocker; 940 my $i = $self-> instance; 941 return unless $i; 942 @{$i-> {toolbars}} = grep { $_ != $self } @{$i->{toolbars}}; 943 @{$i-> {hiddenToolbars}} = grep { $_ != $self } @{$i->{hiddenToolbars}}; 944 $i-> notify(q(ToolbarChange)); 945} 946 947sub Toolbar_EDSClose 948{ 949 my $e = $_[0]-> externalDocker; 950 $e-> hide; 951 $_[0]-> clear_event; 952 $_[0]-> instance-> notify(q(ToolbarChange)); 953} 954 955sub Panel_EDSClose 956{ 957 my $hash = $_[0]-> instance-> get_class($_[0]-> {CLSID}); 958 return unless $hash; 959 $hash-> {lastUsedDock} = undef; 960 $hash-> {lastUsedRect} = [ $_[0]-> externalDocker-> rect ]; 961 $_[0]-> instance-> notify(q(PanelChange)); 962} 963 964sub InternalDockerShuttle_Landing 965{ 966 my ( $self, $dm, @rc) = @_; 967 return unless $self-> {drag}; # only for interactive 968 my $wi = $::application-> get_widget_from_point($::application-> pointerPos); 969 return if !$wi || $wi == $dm; 970 unless ( $wi-> can('dock')) { 971 $wi = $wi-> owner; 972 return if $wi == $dm; 973 } 974 return unless $wi-> can('dock') && $wi-> isa('Prima::DockManager::ToolbarDocker'); 975 $self-> clear_event; 976} 977 978package Prima::DockManager::S::SpeedButton; 979 980sub class 981{ 982 my ( $image, $action, %profile) = @_; 983 $image =~ s/\:(\d+)$//; 984 my $index = $1 || 0; 985 my $i = Prima::Icon-> create; 986 undef($i) unless $i-> load(Prima::Utils::find_image($image), index => $index); 987 my $s = $::application ? $::application->uiScaling : 1; 988 $i->ui_scale if $i; 989 return $action, { 990 class => 'Prima::SpeedButton', 991 profile => { 992 size => [ 24 * $s, 24 * $s], 993 image => $i, 994 borderWidth => 1, 995 onClick => \&on_click, 996 %profile, 997 }, 998 }, 999} 1000 1001sub on_click 1002{ 1003 $_[0]-> owner-> instance-> notify(q(Command), $_[0]-> {CLSID}); 1004} 1005 10061; 1007 1008=pod 1009 1010=head1 NAME 1011 1012Prima::DockManager - advanced dockable widgets 1013 1014=head1 DESCRIPTION 1015 1016C<Prima::DockManager> contains classes that implement additional 1017functionality within the dockable widgets paradigm. 1018 1019The module introduces two new dockable widget classes: 1020C<Prima::DockManager::Panelbar>, a general purpose 1021dockable container for variable-sized widgets; and C<Prima::DockManager::Toolbar>, 1022a dockable container for fixed-size command widgets, mostly push buttons. 1023The command widgets, nested in a toolbar, can also be docked. 1024 1025C<Prima::DockManager> class is an application-oriented class in a way 1026that ( mostly ) the only instance of it is needed in the program. It 1027is derived from C<Prima::Component> and therefore is never visualized. 1028The class instance is stored in C<instance> property of all module classes 1029to serve as a docking hierarchy root. Through the document, I<instance> 1030term is referred to C<Prima::DockManager> class instance. 1031 1032The module by itself is not enough to make a docking-aware application work 1033effectively. The reader is urged to look at F<examples/dock.pl> 1034example code, which demonstrates the usage and capabilities of 1035the module. 1036 1037=head1 Prima::DockManager::Toolbar 1038 1039A toolbar widget class. The toolbar has a dual nature; it can dock 1040and accept docking widgets simultaneously. In the scope of C<Prima::DockManager>, 1041the toolbar hosts command widget, mostly push buttons. 1042 1043The toolbar consists of two widgets. The external dockable widget is 1044implemented in C<Prima::DockManager::Toolbar>, and the internal dock 1045in C<Prima::DockManager::ToolbarDocker> classes. 1046 1047=head2 Properties 1048 1049=over 1050 1051=item autoClose BOOLEAN 1052 1053Selects the behavior of a toolbar when all of its command widgets are 1054undocked. If 1, the toolbar is automatically destroyed. If 0 1055it calls C<visible(0)>. 1056 1057=item childDocker WIDGET 1058 1059Pointer to C<Prima::DockManager::ToolbarDocker> instance. 1060 1061See also C<Prima::DockManager::ToolbarDocker::parentDocker>. 1062 1063=item instance INSTANCE 1064 1065C<Prima::DockManager> instance, the docking hierarchy root. 1066 1067=back 1068 1069=head1 Prima::DockManager::ToolbarDocker 1070 1071Internal class, implements a dock widget for command widgets, 1072while serves as a client in a dockable toolbar, which is 1073a C<Prima::LinearDockerShuttle> descendant. When its size is 1074changed due an eventual rearrange of its docked widgets, also resizes 1075the toolbar. 1076 1077=head2 Properties 1078 1079=over 1080 1081=item instance INSTANCE 1082 1083C<Prima::DockManager> instance, the docking hierarchy root. 1084 1085=item parentDocker WIDGET 1086 1087Pointer to C<Prima::DockManager::Toolbar> instance. When in 1088the docked state, C<parentDocker> value is always equals to C<owner>. 1089 1090See also C<Prima::DockManager::Toolbar::childDocker>. 1091 1092=back 1093 1094=head2 Methods 1095 1096=over 1097 1098=item get_extent 1099 1100Calculates the minimal rectangle that encloses all docked widgets 1101and returns its extensions. 1102 1103=item update_size 1104 1105Called when size is changed to resizes the owner widget. If it is in the docked 1106state, the size change might result in change of position or docking state. 1107 1108=back 1109 1110=head1 Prima::DockManager::Panelbar 1111 1112The class is derived from C<Prima::LinearDockerShuttle>, and 1113is different only in that C<instance> property is introduced, 1114and the external shuttle can be resized interactively. 1115 1116The class is to be used as a simple host to sizeable widgets. 1117The user can dispose of the panel bar by clicking close button 1118on the external shuttle. 1119 1120=head2 Properties 1121 1122=over 1123 1124=item instance INSTANCE 1125 1126C<Prima::DockManager> instance, the docking hierarchy root. 1127 1128=back 1129 1130=head1 Prima::DockManager 1131 1132A binder class, contains set of functions that groups 1133toolbars, panels, and command widgets together under the docking 1134hierarchy. 1135 1136The manager servers several purposes. 1137First, it is a command state holder: the command 1138widgets, mostly buttons, usually are in enabled or disabled state in different 1139life stages of a program. The manager maintains the enabled/disabled state 1140by assigning each command an unique scalar value ( farther and in the 1141code referred as I<CLSID> ). The toolbars can be created with set of 1142command widgets, referred via these CLSIDs. The same is valid for 1143the panels - although they do not host command widgets, the widgets that 1144they do host can also be created indirectly via CLSID identifier. 1145In addition to CLSID, the commands can be grouped by sections. 1146Both CLSID and group descriptor scalars are defined by the programmer. 1147 1148Second, C<create_manager> method presents a standard configuration 1149widget, that allows rearranging of normally non-dockable command widgets, 1150by presenting a full set of available commands to the user as icons. 1151Dragging the icons to toolbars, dock widgets or merely outside the 1152configuration widget automatically creates the corresponding command widget. 1153The notable moment here is that the command widgets are not required 1154to know anything about dragging and docking; any C<Prima::Widget> 1155descendant can be used as a command widget. 1156 1157Third, it helps maintaining the toolbars and panels visibility 1158when the main window is hidden or restored. C<windowState> method 1159hides or shows the toolbars and panels effectively. 1160 1161Fourth, it serves as a docking hierarchy root. All docking sessions 1162begin from C<Prima::DockManager> object, which although does not provide 1163docking capabilities itself ( it is C<Prima::Component> descendant ), 1164redirects the docking requests to the lower-level dock widgets. 1165 1166Fifth, it provides number of helper methods and notifications, 1167and enforces use or C<fingerprint> property by all dockable widgets. 1168This property has default value of C<0xFFFF> ( defined in C<Prima::Docks> ). 1169The module contains the fingerprint C<dmfp::XXX> constants with value greater than this, 1170so the toolbars and panels are not docked to a dock widget with the default 1171configuration. The base constant set is: 1172 1173 fdmp::Tools ( 0x0F000) - dock the command widgets 1174 fdmp::Toolbar ( 0x10000) - dock the toolbars 1175 fdmp::LaunchPad ( 0x20000) - allows widgets recycling 1176 1177All this functionality is demonstrated in F<examples/dock.pl> 1178example. 1179 1180=head2 Properties 1181 1182=over 1183 1184=item commands HASH 1185 1186A hash of boolean values, with keys of CLSID scalars. 1187If value is 1, the command is available. If 0, the command 1188is disabled. Changes to this property are reflected in the 1189visible command widgets, which are enabled or disabled 1190immediately. Also, C<CommandChange> notification is triggered. 1191 1192=item fingerprint INTEGER 1193 1194The property is read-only, and always returns C<0xFFFFFFFF>, 1195to allow landing for all dockable widgets. In case when a finer 1196granulation is needed, the default C<fingerprint> values of 1197toolbars and panels can be reset. 1198 1199=item interactiveDrag BOOLEAN 1200 1201If 1, the command widgets can be interactively dragged, 1202created and destroyed. This property is usually operated together 1203with C<create_manager> widget. If 0, the command widgets 1204cannot be dragged. 1205 1206Default value: 0 1207 1208=back 1209 1210=head2 Methods 1211 1212=over 1213 1214=item activate 1215 1216Brings to front all toolbars and panels. To be 1217used inside a callback code of a main window, that has 1218the toolbars and panels attached to: 1219 1220 onActivate => sub { $dock_manager-> activate } 1221 1222=item auto_toolbar_name 1223 1224Returns an unique name for an automatically created 1225toolbar, like C<Toolbar1>, C<Toolbar2> etc. 1226 1227=item commands_enable BOOLEAN, @CLSIDs 1228 1229Enabled or disables commands from CLSIDs array. 1230The changes are reflected in the visible command widgets, which 1231are enabled or disabled immediately. 1232Also, C<CommandChange> notification is triggered. 1233 1234=item create_manager OWNER, %PROFILE 1235 1236Inserts two widgets into OWNER with PROFILE parameters: 1237a listbox with command section groups, displayed as items, that usually correspond to 1238the predefined toolbar names, and a notebook that displays the 1239command icons. The notebook pages are interactively selected by the listbox 1240navigation. 1241 1242The icons, dragged from the notebook, behave as dockable widgets: 1243they can be landed upon a toolbar, or any other dock widget, given 1244it matches the C<fingerprint> ( by default C<dmfp::LaunchPad|dmfp::Toolbar|dmfp::Tools>). 1245C<dmfp::LaunchPad> constant allows the recycling; if a widget is dragged 1246back onto the notebook, it is destroyed. 1247 1248Returns two widgets, the listbox and the notebook. 1249 1250PROFILE recognizes the following keys: 1251 1252=over 1253 1254=item origin X, Y 1255 1256Position where the widgets are to be inserted. 1257Default value is 0,0. 1258 1259=item size X, Y 1260 1261Size of the widget insertion area. By default 1262the widgets occupy all OWNER interior. 1263 1264=item listboxProfile PROFILE 1265 1266Custom parameters, passed to the listbox. 1267 1268=item dockerProfile PROFILE 1269 1270Custom parameteres, passed to the notebook. 1271 1272=back 1273 1274=item create_panel CLSID, %PROFILE 1275 1276Creates a dockable panel of a previously registered CLSID 1277by C<register_panel>. PROFILE recognizes the following keys: 1278 1279=over 1280 1281=item profile HASH 1282 1283Hash of parameters, passed to C<create()> of the panel widget class. 1284Before passing it is merged with the set of parameters, registered 1285by C<register_panel>. The C<profile> hash takes the precedence. 1286 1287=item dockerProfile HASH 1288 1289Constains extra options, passed to C<Prima::DockManager::Panelbar> 1290widget. Before the usage it is merged with the set of parameters, 1291registered by C<register_panel>. 1292 1293NB: The C<dock> key here contains a reference to a desired dock widget. 1294If C<dock> set to C<undef>, the panel is created in the non-docked state. 1295 1296=back 1297 1298Example: 1299 1300 $dock_manager-> create_panel( $CLSID, 1301 dockerProfile => { dock => $main_window }}, 1302 profile => { backColor => cl::Green }); 1303 1304 1305=item create_tool OWNER, CLSID, X1, Y1, X2, Y2 1306 1307Inserts a command widget, previously registered with CLSID by C<register_tool>, into 1308OWNER widget with X1 - Y2 coordinates. For automatic maintenance of 1309enable/disable state of command widgets OWNER is expected to be a 1310toolbar. If it is not, the maintenance must be performed separately, 1311for example, by C<CommandChange> event. 1312 1313=item create_toolbar %PROFILE 1314 1315Creates a new toolbar of C<Prima::DockManager::Toolbar> class. 1316The following PROFILE options are recognized: 1317 1318=over 1319 1320=item autoClose BOOLEAN 1321 1322Sets C<autoClose> property of the toolbar. 1323 1324Default value is 1 if C<name> options is set, 0 otherwise. 1325 1326=item dock DOCK 1327 1328Contain a reference to a desired DOCK widget. If C<undef>, 1329the toolbar is created in the non-docked state. 1330 1331=item dockerProfile HASH 1332 1333Parameters passed to C<Prima::DockManager::Toolbar> as 1334creation properties. 1335 1336NB: The C<dock> key here contains a reference to a desired dock widget. 1337If C<dock> set to C<undef>, the panel is created in the non-docked state. 1338 1339=item rect X1, Y1, X2, Y2 1340 1341Selects rectangle of the C<Prima::DockManager::ToolbarDocker> instance 1342in the dock widget ( if docked ) or the screen ( if non-docked ) coordinates. 1343 1344=item toolbarProfile HASH 1345 1346Parameters passed to C<Prima::DockManager::ToolbarDocker> as 1347creation properties. 1348 1349=item vertical BOOLEAN 1350 1351Sets C<vertical> property of the toolbar. 1352 1353=item visible BOOLEAN 1354 1355Selects visibility state of the toolbar. 1356 1357=back 1358 1359=item get_class CLSID 1360 1361Returns class record hash, registered under CLSID, or C<undef> 1362if the class is not registered. The hash format contains 1363the following keys: 1364 1365=over 1366 1367=item class STRING 1368 1369Widget class 1370 1371=item profile HASH 1372 1373Creation parameters passed to C<create> when the widget is created. 1374 1375=item tool BOOLEAN 1376 1377If 1, the class belongs to a control widget. If 0, 1378the class represents a panel client widget. 1379 1380=item lastUsedDock DOCK 1381 1382Saved value of the last used dock widget 1383 1384=item lastUsedRect X1, Y1, X2, Y2 1385 1386Saved coordinates of the widget 1387 1388=back 1389 1390=item panel_by_id CLSID 1391 1392Return reference to a panel widget represented by CLSID scalar, 1393or C<undef> if none found. 1394 1395=item panel_menuitems CALLBACK 1396 1397A helper function; maps all panel names into a structure, ready to 1398feed into C<Prima::AbstractMenu::items> property ( see L<Prima::Menu> ). 1399The action member of the menu item record is set to CALLBACK scalar. 1400 1401=item panel_visible CLSID, BOOLEAN 1402 1403Sets the visibility of a panel, referred by CLSID scalar. 1404If VISIBLE is 0, a panel is destroyed; if 1, new panel instance 1405is created. 1406 1407=item panels 1408 1409Returns all visible panel widgets in an array. 1410 1411=item predefined_panels CLSID, DOCK, [ CLSID, DOCK, ... ] 1412 1413Accepts pairs of scalars, where each first item is a panel CLSID 1414and second is the default dock widget. Checks for panel visibility, 1415and creates the panels that are not visible. 1416 1417The method is useful in program startup, when some panels 1418have to be visible from the beginning. 1419 1420=item predefined_toolbars @PROFILES 1421 1422Accepts array of hashes, where each array item describes a toolbar and 1423a default set of command widgets. Checks for toolbar visibility, 1424and creates the toolbars that are not visible. 1425 1426The method recognizes the following PROFILES options: 1427 1428=over 1429 1430=item dock DOCK 1431 1432The default dock widget. 1433 1434=item list ARRAY 1435 1436Array of CLSIDs corresponding to the command widgets to be inserted 1437into the toolbar. 1438 1439=item name STRING 1440 1441Selects toolbar name. 1442 1443=item origin X, Y 1444 1445Selects the toolbar position relative to the dock ( if C<dock> is specified ) 1446or to the screen ( if C<dock> is not specified ). 1447 1448=back 1449 1450The method is useful in program startup, when some panels 1451have to be visible from the beginning. 1452 1453=item register_panel CLSID, PROFILE 1454 1455Registers a panel client class and set of parameters to be associated with 1456CLSID scalar. PROFILE must contain the following keys: 1457 1458=over 1459 1460=item class STRING 1461 1462Client widget class 1463 1464=item text STRING 1465 1466String, displayed in the panel title bar 1467 1468=item dockerProfile HASH 1469 1470Hash of parameters, passed to C<Prima::DockManager::Panelbar>. 1471 1472=item profile 1473 1474Hash of parameters, passed to the client widget. 1475 1476=back 1477 1478=item register_tool CLSID, PROFILE 1479 1480Registers a control widget class and set of parameters to be associated with 1481CLSID scalar. PROFILE must be set the following keys: 1482 1483=over 1484 1485=item class STRING 1486 1487Client widget class 1488 1489=item profile HASH 1490 1491Hash of parameters, passed to the control widget. 1492 1493=back 1494 1495=item toolbar_by_name NAME 1496 1497Returns a pointer to a toolbar of NAME, or C<undef> if none found. 1498 1499=item toolbar_menuitems CALLBACK 1500 1501A helper function; maps all toolbar names into a structure, ready to 1502feed into C<Prima::AbstractMenu::items> property ( see L<Prima::Menu> ). 1503The action member of the menu item record is set to CALLBACK scalar. 1504 1505=item toolbar_visible TOOLBAR, BOOLEAN 1506 1507Sets the visibility of a TOOLBAR. 1508If VISIBLE is 0, the toolbar is hidden; if 1, it is shown. 1509 1510=item toolbars 1511 1512Returns all toolbar widgets in an array. 1513 1514=item windowState INTEGER 1515 1516Mimics interface of C<Prima::Window::windowState>, and maintains 1517visibility of toolbars and panels. If the parameter is C<ws::Minimized>, 1518the toolbars and panels are hidden. On any other parameter these are shown. 1519 1520To be used inside a callback code of a main window, that has the toolbars 1521and panels attached to: 1522 1523 onWindowState => sub { $dock_manager-> windowState( $_[1] ) } 1524 1525=back 1526 1527=head2 Events 1528 1529=over 1530 1531=item Command CLSID 1532 1533A generic event, triggered by a command widget when the user activates 1534it. It can also be called by other means. 1535 1536CLSID is the widget identifier. 1537 1538=item CommandChange 1539 1540Called when C<commands> property changes or C<commands_enable> method is invoked. 1541 1542=item PanelChange 1543 1544Triggered when a panel is created or destroyed by the user. 1545 1546=item ToolbarChange 1547 1548Triggered when a toolbar is created, shown, hidden, or destroyed by the user. 1549 1550=back 1551 1552=head1 Prima::DockManager::S::SpeedButton 1553 1554The package simplifies creation of C<Prima::SpeedButton> command widgets. 1555 1556=head2 Methods 1557 1558=over 1559 1560=item class IMAGE, CLSID, %PROFILE 1561 1562Builds a hash with parameters, ready to feed C<Prima::DockManager::register_tool> 1563for registering a C<Prima::SpeedButton> class instance with PROFILE parameters. 1564 1565IMAGE is a path to a image file, loaded and stored in the registration hash. 1566IMAGE provides an extended syntax for indicating a frame index, if the image file is multiframed: the frame index is appended to the path name 1567with C<:> character prefix. 1568 1569CLSID scalar is not used; it is returned so the method result can 1570directly be passed into C<register_tool> method. 1571 1572Returns two scalars: CLSID and the registration hash. 1573 1574Example: 1575 1576 $dock_manager-> register_tool( 1577 Prima::DockManager::S::SpeedButton::class( "myicon.gif:2", 1578 q(CLSID::Logo), hint => 'Logo image' )); 1579 1580=back 1581 1582=head1 AUTHOR 1583 1584Dmitry Karasik, E<lt>dmitry@karasik.eu.orgE<gt>. 1585 1586=head1 SEE ALSO 1587 1588L<Prima>, L<Prima::Widget>, L<Prima::Docks>, F<examples/dock.pl> 1589 1590=cut 1591