<?xml version="1.0" encoding="windows-1252"?>
<node id="464906" title="thundergnat's scratchpad" created="2005-06-08 20:17:41" updated="2005-08-11 04:59:38">
<type id="182711">
scratchpad</type>
<author id="449608">
thundergnat</author>
<data>
<field name="doctext">
&lt;code&gt;
#!/usr/bin/perl

require 5.008;
use strict;
use warnings;
use Tk;
use Tk::Pane;
use Tk::Text;
use Tk::BrowseEntry;
use Tk::Balloon;
use charnames();

use constant OS_Win =&gt; $^O =~ /Win/;

die "You need to upgrade to a later version of Perl/Tk.\n"
  unless ( $Tk::version ge 8.4 );

my ( $fontname, $fontsize ) = ( 'Times', 16 );
my $font        = "{$fontname} $fontsize";
my $activecolor = '#abcdef';
my ( $globalx, $globaly );
my $utftop;

my $top = MainWindow-&gt;new;

my $dragimg = $top-&gt;Photo(
    -format =&gt; 'gif',
    -data   =&gt;
'R0lGODlhDAAMALMAAISChNTSzPz+/AAAAOAAyukAwRIA4wAAd8oA0MEAe+MTYHcAANAGgnsAAGAA
AAAAACH5BAAAAAAALAAAAAAMAAwAAwQfMMg5BaDYXiw178AlcJ6VhYFXoSoosm7KvrR8zfXHRQA7'
);

my $text = $top-&gt;Scrolled(
    'Text',
    -exportselection =&gt; 'true',
    -scrollbars      =&gt; 'se',
    -background      =&gt; 'white',
    -font            =&gt; "{$fontname} 14"
  )-&gt;pack(
    -expand =&gt; 1,
    -fill   =&gt; 'both',
  );

my $menu = $text-&gt;Menu( -type =&gt; 'menubar' );

$top-&gt;configure( -menu =&gt; $menu );

$menu-&gt;Button( -label =&gt; 'Unicode-Character-Search', -command =&gt; \&amp;uchar );

drag($text);

MainLoop;

sub uchar {
    if ( defined $utftop ) {
        $utftop-&gt;deiconify;
        $utftop-&gt;raise;
    }
    else {
        require q(unicore/Blocks.pl);
		require q(unicore/Name.pl);
        my $utftop = $top-&gt;Toplevel;
        $utftop-&gt;title('Find A Unicode Character');
        $utftop-&gt;geometry('550x400');

        my ( %blocks, $sizelabel, @textchars, @textlabels );

        for ( split /\n/, do 'unicore/Blocks.pl' ) {
            my @array = split /\t/, $_;
            $blocks{ $array[2] } = [ @array[ 0, 1 ] ];
        }

        my $button_frame = $utftop-&gt;Frame-&gt;pack;
        my $search_frame = $utftop-&gt;Frame-&gt;pack(
            -side   =&gt; 'top',
            -anchor =&gt; 'n',
            -pady   =&gt; 4
        );

        my $pane = $utftop-&gt;Scrolled(
            'Pane',
            -background =&gt; 'white',
            -scrollbars =&gt; 'se',
            -sticky     =&gt; 'wne',
          )-&gt;pack(
            -expand =&gt; 'y',
            -fill   =&gt; 'both',
            -anchor =&gt; 'nw'
          );

        drag($pane);

        my $fontlist = $button_frame-&gt;BrowseEntry(
            -label     =&gt; 'Font',
            -browsecmd =&gt; sub { font_propagate( \@textchars ) },
            -variable  =&gt; \$fontname,
          )-&gt;grid(
            -row    =&gt; 1,
            -column =&gt; 1,
            -padx   =&gt; 8,
            -pady   =&gt; 2
          );

        $fontlist-&gt;insert( 'end', sort( $top-&gt;fontFamilies ) );

        my $bigger = $button_frame-&gt;Button(
            -activebackground =&gt; $activecolor,
            -text             =&gt; 'Bigger',
            -command          =&gt; sub {
                $fontsize++;
                font_propagate( \@textchars );
                $sizelabel-&gt;configure( -text =&gt; $fontsize );
            },
          )-&gt;grid(
            -row    =&gt; 1,
            -column =&gt; 2,
            -padx   =&gt; 2,
            -pady   =&gt; 2
          );

        $sizelabel = $button_frame-&gt;Label( -textvariable =&gt; \$fontsize )-&gt;grid(
            -row    =&gt; 1,
            -column =&gt; 3,
            -padx   =&gt; 2,
            -pady   =&gt; 2
        );
        my $smaller = $button_frame-&gt;Button(
            -activebackground =&gt; $activecolor,
            -text             =&gt; 'Smaller',
            -command          =&gt; sub {
                $fontsize--;
                font_propagate( \@textchars );
                $sizelabel-&gt;configure( -text =&gt; $fontsize );
            },
          )-&gt;grid(
            -row    =&gt; 1,
            -column =&gt; 4,
            -padx   =&gt; 2,
            -pady   =&gt; 2
          );

        $search_frame-&gt;Label( -text =&gt; 'Search Characteristics ', )-&gt;grid(
            -row    =&gt; 1,
            -column =&gt; 1
        );

        my $characteristics = $search_frame-&gt;Entry(
            -width      =&gt; 40,
            -background =&gt; 'white'
          )-&gt;grid(
            -row    =&gt; 1,
            -column =&gt; 2
          );

        my $doit = $search_frame-&gt;Button(
            -text    =&gt; 'Search',
            -command =&gt; sub {
                for ( @textchars, @textlabels ) {
                    $_-&gt;destroy;
                }
                my $row = 0;
                @textlabels = @textchars = ();
                my @searches = split /\s+/, uc( $characteristics-&gt;get );
                my @lines    = split /\n/,  do 'unicore/Name.pl';
                while (@lines) {
                    my @char_info = split /\t+/, shift @lines;
                    my ( $ord, $name ) = ( $char_info[0], $char_info[-1] );
                    last if ( hex $ord &gt; 65535 );
                    my $count = 0;
                    for my $search (@searches) {
                        $count++;
                        last unless $name =~ /\b$search\b/;
                        if ( @searches == $count ) {
                            my $block = '';
                            for ( keys %blocks ) {
                                if (   hex( $blocks{$_}[0] ) &lt;= hex($ord)
                                    &amp;&amp; hex( $blocks{$_}[1] ) &gt;= hex($ord) )
                                {
                                    $block = $_;
                                    last;
                                }
                            }
                            $textchars[$row] = $pane-&gt;Label(
                                -text       =&gt; chr( hex $ord ),
                                -font       =&gt; $font,
                                -background =&gt; 'white',
                              )-&gt;grid(
                                -row    =&gt; $row,
                                -column =&gt; 0,
                                -padx   =&gt; 4,
                              );

                            $textlabels[$row] = $pane-&gt;Label(
                                -text =&gt; "$name  -  Ordinal $ord  -  $block",
                                -background =&gt; 'white',
                              )-&gt;grid(
                                -row    =&gt; $row,
                                -column =&gt; 1,
                                -sticky =&gt; 'w'
                              );

                            utfchar_bind( $textchars[$row] );
                            utflabel_bind(
                                $textlabels[$row],  $block,
                                $blocks{$block}[0], $blocks{$block}[1]
                            );
                            $row++;
                            $utftop-&gt;update;
                        }
                    }
                }
            },
          )-&gt;grid(
            -row    =&gt; 1,
            -column =&gt; 3
          );

        $characteristics-&gt;bind( '&lt;Return&gt;' =&gt; sub { $doit-&gt;invoke } );
    }
}

sub utflabel_bind {
    my ( $widget, $block, $start, $end ) = @_;
    $widget-&gt;bind( '&lt;Enter&gt;',
        sub { $widget-&gt;configure( -background =&gt; $activecolor ); } );
    $widget-&gt;bind( '&lt;Leave&gt;',
        sub { $widget-&gt;configure( -background =&gt; 'white' ); } );
    $widget-&gt;bind(
        '&lt;ButtonPress-1&gt;',
        sub {
            $widget-&gt;toplevel-&gt;Busy( -recurse =&gt; 1 );
            utfpopup( $block, $start, $end );
            $widget-&gt;toplevel-&gt;Unbusy( -recurse =&gt; 1 );
        }
    );
}

sub utfchar_bind {
    my $widget = shift;
    $widget-&gt;bind( '&lt;Enter&gt;',
        sub { $widget-&gt;configure( -background =&gt; $activecolor ); } );
    $widget-&gt;bind( '&lt;Leave&gt;',
        sub { $widget-&gt;configure( -background =&gt; 'white' ) } );
    $widget-&gt;bind(
        '&lt;ButtonPress-3&gt;',
        sub {
            $widget-&gt;clipboardClear;
            $widget-&gt;clipboardAppend( $widget-&gt;cget('-text') );
            $widget-&gt;configure( -relief =&gt; 'sunken' );
        }
    );
    $widget-&gt;bind(
        '&lt;ButtonRelease-3&gt;',
        sub {
            $widget-&gt;configure( -relief =&gt; 'flat' );
        }
    );
    $widget-&gt;bind(
        '&lt;ButtonPress-1&gt;',
        sub {
            $widget-&gt;configure( -relief =&gt; 'sunken' );
            $text-&gt;insert( 'insert', $widget-&gt;cget('-text') );
        }
    );
    $widget-&gt;bind(
        '&lt;ButtonRelease-1&gt;',
        sub {
            $widget-&gt;configure( -relief =&gt; 'flat' );
        }
    );
}

sub utfpopup {
    my ( $block, $start, $end ) = @_;

    my ( $sizelabel, @buttons );
    my $rows = ( ( hex $end ) - ( hex $start ) + 1 ) / 16 - 1;

    my $utfpop = $top-&gt;Toplevel();
    $utfpop-&gt;geometry('600x300+10+10');
    $utfpop-&gt;title( $block . ': ' . $start . ' - ' . $end );

    my $balloon = $utfpop-&gt;Balloon( -initwait =&gt; 750 );

    my $top_frame = $utfpop-&gt;Frame-&gt;pack;
    my $fontlist  = $top_frame-&gt;BrowseEntry(
        -label     =&gt; 'Font',
        -browsecmd =&gt; sub { font_propagate( \@buttons ) },
        -variable  =&gt; \$fontname,
      )-&gt;grid(
        -row    =&gt; 1,
        -column =&gt; 1,
        -padx   =&gt; 8,
        -pady   =&gt; 2
      );

    my $bigger = $top_frame-&gt;Button(
        -activebackground =&gt; $activecolor,
        -text             =&gt; 'Bigger',
        -command          =&gt; sub {
            $fontsize++;
            font_propagate( \@buttons );
            $sizelabel-&gt;configure( -text =&gt; $fontsize );
        },
      )-&gt;grid(
        -row    =&gt; 1,
        -column =&gt; 2,
        -padx   =&gt; 2,
        -pady   =&gt; 2
      );

    $sizelabel = $top_frame-&gt;Label( -textvariable =&gt; \$fontsize )-&gt;grid(
        -row    =&gt; 1,
        -column =&gt; 3,
        -padx   =&gt; 2,
        -pady   =&gt; 2
    );

    my $smaller = $top_frame-&gt;Button(
        -activebackground =&gt; $activecolor,
        -text             =&gt; 'Smaller',
        -command          =&gt; sub {
            $fontsize--;
            font_propagate( \@buttons );
            $sizelabel-&gt;configure( -text =&gt; $fontsize );
        },
      )-&gt;grid(
        -row    =&gt; 1,
        -column =&gt; 4,
        -padx   =&gt; 2,
        -pady   =&gt; 2
      );

    $fontlist-&gt;insert( 'end', sort( $top-&gt;fontFamilies ) );

    my $pane = $utfpop-&gt;Scrolled(
        'Pane',
        -background =&gt; 'white',
        -scrollbars =&gt; 'se',
        -sticky     =&gt; 'nswe'
      )-&gt;pack(
        -expand =&gt; 'y',
        -fill   =&gt; 'both'
      );

    drag($pane);

    for my $y ( 0 .. $rows ) {
        for my $x ( 0 .. 15 ) {
            my $name = hex($start) + ( $y * 16 ) + $x;
            my $hex   = uc sprintf "%04x", $name;
            my $msg   = "Dec. $name, Hex. $hex";
            my $cname = charnames::viacode($name);
            $msg .= ", $cname" if $cname;
            $name = 0 unless $cname;
            $buttons[ ( $y * 16 ) + $x ] = $pane-&gt;Button(
                -activebackground   =&gt; $activecolor,
                -text               =&gt; chr($name),
                -font               =&gt; $font,
                -relief             =&gt; 'flat',
                -borderwidth        =&gt; 0,
                -background         =&gt; 'white',
                -command            =&gt; [ \&amp;pututf, $utfpop ],
                -highlightthickness =&gt; 0,
              )-&gt;grid(
                -row    =&gt; $y,
                -column =&gt; $x
              );
            $buttons[ ( $y * 16 ) + $x ]-&gt;bind(
                '&lt;ButtonPress-3&gt;',
                sub {
                    $text-&gt;clipboardClear;
                    $text-&gt;clipboardAppend(
                        $buttons[ ( $y * 16 ) + $x ]-&gt;cget('-text') );
                }
            );
            $balloon-&gt;attach( $buttons[ ( $y * 16 ) + $x ],
                -balloonmsg =&gt; $msg, );
            $utfpop-&gt;update;
        }
    }
    $utfpop-&gt;protocol(
        'WM_DELETE_WINDOW' =&gt; sub { $balloon-&gt;destroy; $utfpop-&gt;destroy; } );
}

sub pututf {
    my $container = shift;
    my @xy        = $container-&gt;pointerxy;
    my $widget    = $container-&gt;containing(@xy);
    my $letter    = $widget-&gt;cget( -text );
    return unless $letter;
    my @ranges = $text-&gt;tagRanges('sel');
    $text-&gt;delete(@ranges) if @ranges;
    $text-&gt;insert( 'insert', $letter );
    $text-&gt;focus;
}

sub font_propagate {
    my $array = shift;
    $font = "{$fontname} $fontsize";
    for (@$array) {
        $_-&gt;configure( -font =&gt; $font );
    }
}

sub drag {
    my $widget = shift;
    my $corner;
    if ( defined $widget-&gt;Subwidget('corner') ) {
        $corner = $widget-&gt;Subwidget('corner');
    }
    else {
        $corner = $widget-&gt;Frame-&gt;pack( -side =&gt; 'bottom', -anchor =&gt; 'se' );
    }
    my $corner_label =
      $corner-&gt;Label( -image =&gt; $dragimg )
      -&gt;pack( -side =&gt; 'right', -anchor =&gt; 'se' );
    $corner_label-&gt;bind(
        '&lt;Enter&gt;',
        sub {
            if (OS_Win) {
                $corner-&gt;configure( -cursor =&gt; 'size_nw_se' );
            }
            else {
                $corner-&gt;configure( -cursor =&gt; 'sizing' );
            }
        }
    );
    $corner_label-&gt;bind( '&lt;Leave&gt;',
        sub { $corner-&gt;configure( -cursor =&gt; 'arrow' ) } );
    $corner_label-&gt;bind(
        '&lt;1&gt;',
        sub {
            ( $globalx, $globaly ) =
              ( $widget-&gt;toplevel-&gt;pointerx, $widget-&gt;toplevel-&gt;pointery );
        }
    );
    $corner_label-&gt;bind(
        '&lt;B1-Motion&gt;',
        sub {
            my $x =
              $widget-&gt;toplevel-&gt;width - $globalx + $widget-&gt;toplevel-&gt;pointerx;
            my $y = $widget-&gt;toplevel-&gt;height - $globaly +
              $widget-&gt;toplevel-&gt;pointery;
            ( $globalx, $globaly ) =
              ( $widget-&gt;toplevel-&gt;pointerx, $widget-&gt;toplevel-&gt;pointery );
            $widget-&gt;toplevel-&gt;geometry( $x . 'x' . $y );
        }
    );
}

&lt;/code&gt;</field>
</data>
</node>
