| Prima documentation | Contained in the Prima distribution. |
Prima::ColorDialog - standard color selection facilities
use Prima qw(StdDlg Application); my $p = Prima::ColorDialog-> create( quality => 1, ); printf "color: %06x", $p-> value if $p-> execute == mb::OK;
The module contains two packages, Prima::ColorDialog and Prima::ColorComboBox,
used as standard tools for interactive color selection. Prima::ColorComboBox is
a modified combo widget, which provides selecting from predefined palette but also can
invoke Prima::ColorDialog window.
Used to increase visual quality of the dialog if run on paletted displays.
Default value: 0
Selects the color, represented by the color wheel and other dialog controls.
Default value: cl::White
Converts color from HSV to RGB format and returns three integer values, red, green, and blue components.
Converts color from RGB to HSV format and returns three numerical values, hue, saturation, and luminosity components.
Combines separate channels into single 24-bit RGB value and returns the result.
Splits 24-bit RGB value into three channels, red, green, and blue and returns three integer values.
Maps X and Y coordinate values onto a color wheel with RADIUS in pixels. The code uses RADIUS = 119 for mouse position coordinate mapping. Returns three values, - hue, saturation and error flag. If error flag is set, the conversion has failed.
Maps hue and saturation onto 256-pixel wide color wheel, and returns X and Y coordinates of the corresponding point.
Creates a color wheel with number of SHADES given,
drawn on a BACK_COLOR background, and returns a Prima::DeviceBitmap object.
Creates a circular 1-bit mask, with radius derived from SHAPES.
SHAPES must be same as passed to create_wheel.
Returns Prima::Image object.
Called when the user starts dragginh a color from the color wheel by with left
mouse button and combination of Alt, Ctrl, and Shift keys. $PROPERTY is one
of Prima::Widget color properties, and depends on combination of keys:
Alt backColor Ctrl color Alt+Shift hiliteBackColor Ctrl+Shift hiliteColor Ctrl+Alt disabledColor Ctrl+Alt+Shift disabledBackColor
Default action reflects the property to be changes in the dialog title
The notification is called when the value property is changed, either interactively or as a result of direct call.
Called when the user releases the mouse drag over a Prima widget.
Default action sets $WIDGET->$PROPERTY to the current color value.
Contains cached result of create_wheel call.
Contains cached result of create_wheel_shape call.
nt::Action callback, designed to map combo palette index into a RGB color.
INDEX is an integer from 0 to colors - 1, COLOR_PTR is a reference to a
result scalar, where the notification is expected to write the resulting color.
Defines amount of colors in the fixed palette of the combo box.
Contains the color selection as 24-bit integer value.
Prima, Prima::ComboBox, examples/cv.pl.
Dmitry Karasik, <dmitry@karasik.eu.org>.
| Prima documentation | Contained in the Prima distribution. |
# # Copyright (c) 1997-2002 The Protein Laboratory, University of Copenhagen # All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # 1. Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # 2. Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in the # documentation and/or other materials provided with the distribution. # # THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE # ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS # OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF # SUCH DAMAGE. # # Created by Dmitry Karasik <dk@plab.ku.dk> # # $Id$ # contains: # ColorDialog # ColorComboBox use strict; use Prima::Const; use Prima::Classes; use Prima::Sliders; use Prima::Label; use Prima::Buttons; use Prima::ComboBox; use Prima::ScrollBar; package Prima::ColorDialog; use vars qw( @ISA $colorWheel $colorWheelShape); @ISA = qw( Prima::Dialog); { my %RNT = ( %{Prima::Dialog-> notification_types()}, BeginDragColor => nt::Command, EndDragColor => nt::Command, ); sub notification_types { return \%RNT; } } my $shapext = Prima::Application-> get_system_value( sv::ShapeExtension); sub hsv2rgb { my ( $h, $s, $v) = @_; $v = 1 if $v > 1; $v = 0 if $v < 0; $s = 1 if $s > 1; $s = 0 if $s < 0; $v *= 255; return $v, $v, $v if $h == -1; my ( $r, $g, $b, $i, $f, $w, $q, $t); $h -= 360 if $h >= 360; $h /= 60; $i = int( $h); $f = $h - $i; $w = $v * (1 - $s); $q = $v * (1 - ($s * $f)); $t = $v * (1 - ($s * (1 - $f))); if ( $i == 0) { return $v, $t, $w; } elsif ( $i == 1) { return $q, $v, $w; } elsif ( $i == 2) { return $w, $v, $t; } elsif ( $i == 3) { return $w, $q, $v; } elsif ( $i == 4) { return $t, $w, $v; } else { return $v, $w, $q; } } sub rgb2hsv { my ( $r, $g, $b) = @_; my ( $h, $s, $v, $max, $min, $delta); $r /= 255; $g /= 255; $b /= 255; $max = $r; $max = $g if $g > $max; $max = $b if $b > $max; $min = $r; $min = $g if $g < $min; $min = $b if $b < $min; $v = $max; $s = $max ? ( $max - $min) / $max : 0; return -1, $s, $v unless $s; $delta = $max - $min; if ( $r == $max) { $h = ( $g - $b) / $delta; } elsif ( $g == $max) { $h = 2 + ( $b - $r) / $delta; } else { $h = 4 + ( $r - $g) / $delta; } $h *= 60; $h += 360 if $h < 0; return $h, $s, $v; } sub rgb2value { return $_[2]|($_[1] << 8)|($_[0] << 16); } sub value2rgb { my $c = $_[0]; return ( $c>>16) & 0xFF, ($c>>8) & 0xFF, $c & 0xFF; } sub xy2hs { my ( $x, $y, $c) = @_; my ( $d, $r, $rx, $ry, $h, $s); ( $rx, $ry) = ( $x - $c, $y - $c); my $c2 = $c * $c; $d = $c2 * ( $rx*$rx + $ry*$ry - $c2); $r = sqrt( $rx*$rx + $ry*$ry); $h = $r ? atan2( $rx/$r, $ry/$r) : 0; $s = $r / $c; $h = $h * 57.295779513 + 180; $s = 1 if $s > 1; return $h, $s, $d > 0; } sub hs2xy { my ( $h, $s) = @_; my ( $r, $a) = ( 128 * $s, ($h - 180) / 57.295779513); return 128 + $r * sin( $a), 128 + $r * cos( $a); } sub create_wheel { my ($id, $color) = @_; my $imul = 256 / $id; my $i = Prima::DeviceBitmap-> create( width => 256, height => 256, name => '', ); my ( $y1, $x1) = ($id,$id); my $d0 = $id / 2; $i-> begin_paint; $i-> color( cl::Black); $i-> bar( 0, 0, $i-> width, $i-> height); my ( $y, $x); for ( $y = 0; $y < $y1; $y++) { for ( $x = 0; $x < $x1; $x++) { my ( $h, $s, $ok) = xy2hs( $x, $y, $d0); next if $ok; my ( $r, $g, $b) = hsv2rgb( $h, $s, 1); $i-> color( $b | ($g << 8) | ($r << 16)); $i-> bar( $x * $imul, $y * $imul, ( $x + 1) * $imul - 1, ( $y + 1) * $imul - 1 ); } } $i-> end_paint; my $a = Prima::DeviceBitmap-> create( width => 256, height => 256, name => 'ColorWheel', ); $a-> begin_paint; $a-> color( $color); $a-> bar( 0, 0, $a-> size); $a-> rop( rop::XorPut); $a-> put_image( 0, 0, $i); $a-> rop( rop::CopyPut); $a-> color( cl::Black); $a-> fill_ellipse( 128, 128, 255 - $imul * 2, 255 - $imul * 2 ); $a-> rop( rop::XorPut); $a-> put_image( 0, 0, $i); $a-> end_paint; $i-> destroy; return $a; } sub create_wheel_shape { return unless $shapext; my $id = $_[0]; my $imul = 256 / $id; my $a = Prima::Image-> create( width => 256, height => 256, type => im::BW, ); $a-> begin_paint; $a-> color( cl::Black); $a-> bar( 0, 0, 255, 255); $a-> color( cl::White); $a-> fill_ellipse( 128, 128, 255 - $imul * 2, 255 - $imul * 2); $a-> end_paint; return $a; } sub profile_default { return { %{$_[ 0]-> SUPER::profile_default}, width => 348, height => 450, centered => 1, visible => 0, scaleChildren => 0, text => 'Select color', quality => 0, value => cl::White, } } sub init { my $self = shift; my %profile = $self-> SUPER::init(@_); $self-> {setTransaction} = undef; my $c = $self-> {value} = $profile{value}; $self-> {quality} = 0; my ( $r, $g, $b) = value2rgb( $c); my ( $h, $s, $v) = rgb2hsv( $r, $g, $b); $s *= 255; $v *= 255; $h = int($h); $s = int($s); $v = int($v); $colorWheel = create_wheel(32, $self-> backColor) unless $colorWheel; $colorWheelShape = create_wheel_shape(32) unless $colorWheelShape; $self-> {wheel} = $self-> insert( Widget => origin => [ 20, 172], width => 256, height => 256, name => 'Wheel', shape => $colorWheelShape, ownerBackColor => 1, syncPaint => 1, delegations => [qw(Paint MouseDown MouseUp MouseMove)], ); $self-> {roller} = $self-> insert( Widget => origin => [ 288, 164], width => 48, height => 272, buffered => 1, name => 'Roller', ownerBackColor => 1, delegations => [qw(Paint MouseDown MouseUp MouseMove)], ); # RGB my %rgbprf = ( width => 72, max => 255, onChange => sub { RGB_Change( $_[0]-> owner, $_[0]);}, ); $self-> {R} = $self-> insert( SpinEdit => origin => [40,120], value => $r, name => 'R', %rgbprf, ); my %labelprf = ( width => 20, height => $self-> {R}-> height, autoWidth => 0, autoHeight => 0, valignment => ta::Center, ); $self-> insert( Label => origin => [ 20, 120], focusLink => $self-> {R}, text => 'R:', %labelprf, ); $self-> {G} = $self-> insert( SpinEdit => origin => [148,120], value => $g, name => 'G', %rgbprf, ); $self-> insert( Label => origin => [ 126, 120], focusLink => $self-> {G}, text => 'G:', %labelprf, ); $self-> {B} = $self-> insert( SpinEdit => origin => [256,120], value => $b, name => 'B', %rgbprf, ); $self-> insert( Label => origin => [ 236, 120], focusLink => $self-> {B}, text => 'B:', %labelprf, ); $rgbprf{onChange} = sub { HSV_Change( $_[0]-> owner, $_[0])}; $self-> {H} = $self-> insert( SpinEdit => origin => [ 40,78], value => $h, name => 'H', %rgbprf, max => 360, ); $self-> insert( Label => origin => [ 20, 78], focusLink => $self-> {H}, text => 'H:', %labelprf, ); $self-> {S} = $self-> insert( SpinEdit => origin => [ 146,78], value => int($s), name => 'S', %rgbprf, ); $self-> insert( Label => origin => [ 126, 78], focusLink => $self-> {S}, text => 'S:', %labelprf, ); $self-> {V} = $self-> insert( SpinEdit => origin => [ 256,78], value => int($v), name => 'V', %rgbprf, ); $self-> insert( Label => origin => [ 236, 78], focusLink => $self-> {V}, text => 'V:', %labelprf, ); $self-> insert( Button => text => '~OK', origin => [ 20, 20], modalResult => mb::OK, default => 1, ); $self-> insert( Button => text => 'Cancel', origin => [ 126, 20], modalResult => mb::Cancel, ); $self-> {R}-> select; $self-> quality( $profile{quality}); $self-> Roller_Repaint if $self-> {quality}; return %profile; } sub on_destroy { $colorWheelShape = undef; } sub on_begindragcolor { my ( $self, $property) = @_; $self-> {old_text} = $self-> text; $self-> {wheel}-> pointer( cr::Invalid); $self-> text( "Apply $property..."); } sub on_enddragcolor { my ( $self, $property, $widget) = @_; $self-> {wheel}-> pointer( cr::Default); $self-> text( $self-> {old_text}); if ( $widget) { $property = $widget-> can( $property); $property-> ( $widget, $self-> value) if $property; } delete $self-> {old_text}; } use constant Hue => 1; use constant Sat => 2; use constant Lum => 4; use constant Roller => 8; use constant Wheel => 16; use constant All => 31; sub RGB_Change { my ($self, $pin) = @_; return if $self-> {setTransaction}; $self-> {setTransaction} = 1; $self-> {RGBPin} = $pin; my ( $r, $g, $b) = value2rgb( $self-> {value}); $r = $self-> {R}-> value if $pin == $self-> {R}; $g = $self-> {G}-> value if $pin == $self-> {G}; $b = $self-> {B}-> value if $pin == $self-> {B}; $self-> value( rgb2value( $r, $g, $b)); undef $self-> {RGBPin}; undef $self-> {setTransaction}; } sub HSV_Change { my ($self, $pin) = @_; return if $self-> {setTransaction}; $self-> {setTransaction} = 1; my ( $h, $s, $v); $self-> {HSVPin} = Hue | Lum | Sat | ( $pin == $self-> {V} ? (Wheel|Roller) : 0); $h = $self-> {H}-> value ; $s = $self-> {S}-> value / 255; $v = $self-> {V}-> value / 255; $self-> value( rgb2value( hsv2rgb( $h, $s, $v))); undef $self-> {HSVPin}; undef $self-> {setTransaction}; } sub Wheel_Paint { my ( $owner, $self, $canvas) = @_; $canvas-> put_image( 0, 0, $colorWheel); my ( $x, $y) = hs2xy( $owner-> {H}-> value, $owner-> {S}-> value/273); $canvas-> color( cl::White); $canvas-> rop( rop::XorPut); if ( $shapext) { my @sz = $canvas-> size; $canvas-> linePattern( lp::DotDot); $canvas-> line( $x, 0, $x, $sz[1]); $canvas-> line( 0, $y, $sz[0], $y); } else { $canvas-> lineWidth( 3); $canvas-> ellipse( $x, $y, 13, 13); } } sub Wheel_MouseDown { my ( $owner, $self, $btn, $mod, $x, $y) = @_; return if $self-> {mouseTransation}; return if $btn != mb::Left; my ( $h, $s, $ok) = xy2hs( $x-9, $y-9, 119); return if $ok; $self-> {mouseTransation} = $btn; $self-> capture(1); if ( $btn == mb::Left) { if ( $mod == ( km::Ctrl | km::Alt)) { $self-> {drag_color} = 'disabledColor'; } elsif ( $mod == ( km::Ctrl | km::Alt | km::Shift)) { $self-> {drag_color} = 'disabledBackColor'; } elsif ( $mod == ( km::Ctrl | km::Shift)) { $self-> {drag_color} = 'hiliteColor'; } elsif ( $mod == ( km::Alt | km::Shift)) { $self-> {drag_color} = 'hiliteBackColor'; } elsif ( $mod & km::Ctrl) { $self-> {drag_color} = 'color'; } elsif ( $mod & km::Alt) { $self-> {drag_color} = 'backColor'; } else { $self-> notify( "MouseMove", $mod, $x, $y); } $owner-> notify( 'BeginDragColor', $self-> {drag_color}) if $self-> {drag_color}; } } sub Wheel_MouseMove { my ( $owner, $self, $mod, $x, $y) = @_; return if !$self-> {mouseTransation} or $self-> {drag_color}; my ( $h, $s, $ok) = xy2hs( $x-9, $y-9, 119); $owner-> {setTransaction} = 1; $owner-> {HSVPin} = Lum|Hue|Sat; $owner-> {H}-> value( int( $h)); $owner-> {S}-> value( int( $s * 255)); $owner-> value( rgb2value( hsv2rgb( int($h), $s, $owner-> {V}-> value/255))); $owner-> {HSVPin} = undef; $owner-> {setTransaction} = undef; } sub Wheel_MouseUp { my ( $owner, $self, $btn, $mod, $x, $y) = @_; return unless $self-> {mouseTransation}; $self-> {mouseTransation} = undef; $self-> capture(0); if ( $self-> {drag_color}) { $owner-> notify('EndDragColor', $self-> {drag_color}, $::application-> get_widget_from_point( $self-> client_to_screen( $x, $y))); delete $self-> {drag_color}; } } sub Roller_Paint { my ( $owner, $self, $canvas) = @_; my @size = $self-> size; $canvas-> clear; my $i; my ( $h, $s, $v, $d) = ( $owner-> {H}-> value, $owner-> {S}-> value, $owner-> {V}-> value, ($size[1]-16) / 32); $s /= 255; $v /= 255; my ( $r, $g, $b); for $i (0..31) { ( $r, $g, $b) = hsv2rgb( $h, $s, $i / 31); $canvas-> color( rgb2value( $r, $g, $b)); $canvas-> bar( 8, 8 + $i * $d, $size[0] - 8, 8 + ($i + 1) * $d); } $canvas-> color( cl::Black); $canvas-> rectangle( 8, 8, $size[0] - 8, $size[1] - 8); $d = int( $v * ($size[1]-16)); $canvas-> rectangle( 0, $d, $size[0]-1, $d + 15); $canvas-> color( $owner-> {value}); $canvas-> bar( 1, $d + 1, $size[0]-2, $d + 14); $self-> {paintPoll} = 2 if exists $self-> {paintPoll}; } sub Roller_Repaint { my $owner = $_[0]; my $roller = $owner-> {roller}; if ( $owner-> {quality}) { my ( $h, $s, $v) = ( $owner-> {H}-> value, $owner-> {S}-> value, $owner-> {V}-> value); $s /= 255; $v /= 255; my ( $i, $r, $g, $b); my @pal; for ( $i = 0; $i < 32; $i++) { ( $r, $g, $b) = hsv2rgb( $h, $s, $i / 31); push ( @pal, $b, $g, $r); } ( $r, $g, $b) = value2rgb( $owner-> {value}); push ( @pal, $b, $g, $r); $roller-> {paintPoll} = 1; $roller-> palette([@pal]); $roller-> repaint if $roller-> {paintPoll} != 2; delete $roller-> {paintPoll}; } else { $roller-> repaint; } } sub Roller_MouseDown { my ( $owner, $self, $btn, $mod, $x, $y) = @_; return if $self-> {mouseTransation}; $self-> {mouseTransation} = 1; $self-> capture(1); $self-> notify( "MouseMove", $mod, $x, $y); } sub Roller_MouseMove { my ( $owner, $self, $mod, $x, $y) = @_; return unless $self-> {mouseTransation}; $owner-> {setTransaction} = 1; $owner-> {HSVPin} = Hue|Sat|Wheel|Roller; $owner-> value( rgb2value( hsv2rgb( $owner-> {H}-> value, $owner-> {S}-> value/255, ($y - 8) / ( $self-> height - 16)))); $owner-> {HSVPin} = undef; $owner-> {setTransaction} = undef; $self-> update_view; } sub Roller_MouseUp { my ( $owner, $self, $btn, $mod, $x, $y) = @_; return unless $self-> {mouseTransation}; $self-> {mouseTransation} = undef; $self-> capture(0); } sub set_quality { my ( $self, $quality) = @_; return if $quality == $self-> {quality}; $self-> {quality} = $quality; $self-> {roller}-> palette([]) unless $quality; $self-> Roller_Repaint; } sub set_value { my ( $self, $value) = @_; return if $value == $self-> {value} and ! $self-> {HSVPin}; $self-> {value} = $value; my $st = $self-> {setTransaction}; $self-> {setTransaction} = 1; my $rgb = $self-> {RGBPin} || 0; my $hsv = $self-> {HSVPin} || 0; my ( $r, $g, $b) = value2rgb( $value); my ( $h, $s, $v) = rgb2hsv( $r, $g, $b); $s = int( $s*255); $v = int( $v*255); $self-> {R}-> value( $r) if $self-> {R} != $rgb; $self-> {G}-> value( $g) if $self-> {G} != $rgb; $self-> {B}-> value( $b) if $self-> {B} != $rgb; $self-> {H}-> value( int($h)) unless $hsv & Hue; $self-> {S}-> value( int($s)) unless $hsv & Sat; $self-> {V}-> value( int($v)) unless $hsv & Lum; $self-> {wheel}-> repaint unless $hsv & Wheel; if ( $hsv & Roller) { $self-> {roller}-> repaint; } else { $self-> Roller_Repaint; } $self-> {setTransaction} = $st; $self-> notify(q(Change)); } sub value {($#_)?$_[0]-> set_value ($_[1]):return $_[0]-> {value};} sub quality {($#_)?$_[0]-> set_quality ($_[1]):return $_[0]-> {quality};} package Prima::ColorComboBox; use vars qw(@ISA); @ISA = qw(Prima::ComboBox); { my %RNT = ( %{Prima::Widget-> notification_types()}, Colorify => nt::Action, ); sub notification_types { return \%RNT; } } sub profile_default { my %sup = %{$_[ 0]-> SUPER::profile_default}; my @std = Prima::Application-> get_default_scrollbar_metrics; return { %sup, style => cs::DropDownList, height => $sup{ editHeight}, value => cl::White, width => 56, literal => 0, colors => 20 + 128, editClass => 'Prima::Widget', listClass => 'Prima::Widget', editProfile => { selectingButtons => 0, }, listProfile => { width => 78 + $std[0], height => 130, growMode => 0, }, }; } sub profile_check_in { my ( $self, $p, $default) = @_; $p-> { style} = cs::DropDownList; $self-> SUPER::profile_check_in( $p, $default); } sub init { my $self = shift; my %profile = @_; $self-> {value} = $profile{value}; $self-> {colors} = $profile{colors}; @{$profile{listDelegations}} = grep { $_ ne 'SelectItem' } @{$profile{listDelegations}}; push ( @{$profile{listDelegations}}, qw(Create Paint MouseDown)); push ( @{$profile{editDelegations}}, qw(Paint MouseDown Enter Leave Enable Disable KeyDown)); %profile = $self-> SUPER::init(%profile); $self-> colors( $profile{colors}); $self-> value( $profile{value}); return %profile; } sub InputLine_KeyDown { my ( $combo, $self, $code, $key) = @_; $combo-> listVisible(1), $self-> clear_event if $key == kb::Down; return if $key != kb::NoKey; $self-> clear_event; } sub InputLine_Paint { my ( $combo, $self, $canvas, $w, $h, $focused) = ($_[0],$_[1],$_[2],$_[1]-> size, $_[1]-> focused); my $back = $self-> enabled ? $self-> backColor : $self-> disabledBackColor; my $clr = $combo-> value; $clr = $back if $clr == cl::Invalid; $canvas-> rect3d( 0, 0, $w-1, $h-1, 1, $self-> light3DColor, $self-> dark3DColor); $canvas-> color( $back); $canvas-> rectangle( 1, 1, $w - 2, $h - 2); $canvas-> rectangle( 2, 2, $w - 3, $h - 3); $canvas-> color( $clr); $canvas-> fillPattern([(0xEE, 0xBB) x 4]) unless $self-> enabled; $canvas-> bar( 3, 3, $w - 4, $h - 4); $canvas-> rect_focus(2, 2, $w - 3, $h - 3) if $focused; } sub InputLine_MouseDown { # this code ( instead of listVisible(!listVisible)) is formed so because # ::InputLine is selectable, and unwilling focus() could easily hide # listBox automatically. Manual focus is also supported by # selectingButtons == 0. my ( $combo, $self) = @_; my $lv = $combo-> listVisible; $combo-> listVisible(!$lv); $self-> focus if $lv; $self-> clear_event; } sub InputLine_Enable { $_[1]-> repaint }; sub InputLine_Disable { $_[1]-> repaint }; sub InputLine_Enter { $_[1]-> repaint; } sub InputLine_Leave { $_[0]-> listVisible(0) if $Prima::ComboBox::capture_mode; $_[1]-> repaint; } sub InputLine_MouseWheel { my ( $self, $widget, $mod, $x, $y, $z) = @_; my $v = $self-> value; $z = $z / 120 * 16; my ( $r, $g, $b) = ( $v >> 16, ($v >> 8) & 0xff, $v & 0xff); if ( $mod & km::Shift) { $r += $z; } elsif ( $mod & km::Ctrl) { $g += $z; } elsif ( $mod & km::Alt) { $b += $z; } else { $r += $z; $g += $z; $b += $z; } for ( $r, $g, $b) { $_ = 0 if $_ < 0; $_ = 255 if $_ > 255; } $self-> value( $r * 65536 + $g * 256 + $b); $widget-> clear_event; } sub List_Create { my ($combo,$self) = @_; $combo-> {btn} = $self-> insert( Button => origin => [ 3, 3], width => $self-> width - 6, height => 28, text => '~More...', selectable => 0, name => 'MoreBtn', onClick => sub { $combo-> MoreBtn_Click( @_)}, ); my $c = $combo-> colors; $combo-> {scr} = $self-> insert( ScrollBar => origin => [ 75, $combo-> {btn}-> height + 8], top => $self-> height - 3, vertical => 1, name => 'Scroller', max => $c > 20 ? $c - 20 : 0, partial => 20, step => 4, pageStep => 20, whole => $c, delegations=> [ $combo, 'Change'], ); } sub List_Paint { my ( $combo, $self, $canvas) = @_; my ( $w, $h) = $self-> size; my @c3d = ( $self-> light3DColor, $self-> dark3DColor); $canvas-> rect3d( 0, 0, $w-1, $h-1, 1, @c3d, cl::Back) unless exists $self-> {inScroll}; my $i; my $pc = 18; my $dy = $combo-> {btn}-> height; my $maxc = $combo-> colors; my $shft = $combo-> {scr}-> value; for ( $i = 0; $i < 20; $i++) { next if $i >= $maxc; my ( $x, $y) = (($i % 4) * $pc + 3, ( 4 - int( $i / 4)) * $pc + 9 + $dy); my $clr = 0; $combo-> notify('Colorify', $i + $shft, \$clr); $canvas-> rect3d( $x, $y, $x + $pc - 2, $y + $pc - 2, 1, @c3d, $clr); } } sub List_MouseDown { my ( $combo, $self, $btn, $mod, $x, $y) = @_; $x -= 3; $y -= $combo-> {btn}-> height + 9; return if $x < 0 || $y < 0; $x = int($x / 18); $y = int($y / 18); return if $x > 3 || $y > 4; $y = 4 - $y; $combo-> listVisible(0); my $shft = $combo-> {scr}-> value; my $maxc = $combo-> colors; my $xcol = $shft + $x + $y * 4; return if $xcol >= $maxc; my $xval = 0; $combo-> notify('Colorify', $xcol, \$xval); $combo-> value( $xval); } sub MoreBtn_Click { my ($combo,$self) = @_; my $d; $combo-> listVisible(0); $d = Prima::ColorDialog-> create( text => 'Mixed color palette', value => $combo-> value, ); $combo-> value( $d-> value) if $d-> execute != mb::Cancel; $d-> destroy; } sub Scroller_Change { my ($combo,$self) = @_; $self = $combo-> List; $self-> {inScroll} = 1; $self-> invalidate_rect( 4, $combo-> {btn}-> top+6, $self-> width - $combo-> {scr}-> width, $self-> height - 3, ); delete $self-> {inScroll}; } sub set_style { $_[0]-> raise_ro('set_style')} sub set_value { my ( $self, $value) = @_; return if $value == $self-> {value}; $self-> {value} = $value; $self-> notify(q(Change)); $self-> {edit}-> repaint; } sub set_colors { my ( $self, $value) = @_; return if $value == $self-> {colors}; $self-> {colors} = $value; my $scr = $self-> {list}-> {scr}; $scr-> set( max => $value > 20 ? $value - 20 : 0, whole => $value, ) if $scr; $self-> {list}-> repaint; } my @palColors = ( 0xffffff,0x000000,0xc6c3c6,0x848284, 0xff0000,0x840000,0xffff00,0x848200, 0x00ff00,0x008200,0x00ffff,0x008284, 0x0000ff,0x000084,0xff00ff,0x840084, 0xc6dfc6,0xa5cbf7,0xfffbf7,0xa5a2a5, ); sub on_colorify { my ( $self, $index, $sref) = @_; if ( $index < 20) { $$sref = $palColors[ $index]; } else { my $i = $index - 20; my ( $r, $g, $b); if ( $i < 64) { ( $r, $g, $b) = Prima::ColorDialog::hsv2rgb( $i * 4, 0.25 + ($i % 4) * 0.25, 1 ); } else { ( $r, $g, $b) = Prima::ColorDialog::hsv2rgb( $i * 4, 1, 0.25 + ($i % 4) * 0.25 ); } $$sref = $b | $g << 8 | $r << 16; } $self-> clear_event; } sub value {($#_)?$_[0]-> set_value ($_[1]):return $_[0]-> {value}; } sub colors {($#_)?$_[0]-> set_colors ($_[1]):return $_[0]-> {colors}; } 1; __DATA__