Dies ist ein Template für den Skripte-Unterbereich FontSearchAndView.

Script zum Suchen und betrachten von Fonts

Name

Gtk2 Font View

Mein Problem war es, dass ich zu einem Font die Datei brauche, um sie in Image::Magick oder einer anderen Grafikbibliothek nutzen zu können. Ich habe auch weder die Zeit noch die Lust jede Datei zu suchen und einzeln zu öffnen. Zudem wollte ich eine Test Text eingeben und die Font-Größe Ändern können.

Heraus gekommen ist ein kleine Script, bei dem man auf der linken Seite eine liste mit Pfade hat, die nach Fonts durchsucht werden sollen. Daneben werden die gefunden Font-Familien ausgeben und auf der rechten Seite kann man Man des Style auswählen und bekommt einen gerenderten Text zu sehen und einige Informationen über den Font.

Noch ein paar Worte zur Struktur und was ich mir dabei gedacht habe.

Die GUI ist eine abgeleitete Klasse von Gtk2::Builder, zu dem ich einige Signalhandler hinzugefügt habe. Das erlaubt es die GUI sauber vom restlichen Programm zu trennen. Ähnliches habe ich mit der Fontverarbeitung gemacht. Sie besteht aus zwei Klassen FontList, das die Fonts sucht und sammelt und FontList::Font, das einen Font repräsentiert. Verknüpft Verknüpft ergeben die drei Klassen das Programm.

Wer geauer hinschaut wird feststellen, dass ich im Programm nur die Pfade zum Font vorhalte und jedes mal neu lade, wenn die Anzeige generiert wird. Das ist ineffizient, ist aber nötig da Font::FreeType ordentlich Speicher belegt und wenn viele Fonts geladen werden mit einem Speicherzugriffsfehler abstürzen kann ("out of memory"). Ich habe das Script wie es unten steht mit über 15.000 Fonts getestet und es lief zuverlässig.

Das Konvertieren von 8-Bit Graustufen zu 4*8Bit RGBA ist nötig, damit Gtk2 das Bild versteht, nebenbei setze ich den Alphakanal, damit das spätere Zusammenfügen ordentlich aussieht. Wer Freude daran hat kann ja die Möglichkeit hinzufügen die Glyphen ein zu färben.

Skript

#!/usr/bin/perl
use strict;
use warnings;
use utf8;
use Carp;

use Gtk2 -init;
use File::Spec;

my @font_dirs=(@ARGV,$ENV{HOME}.'/.fonts/','/usr/share/fonts/');

# get X-Config fontdirs
my $fpath='/etc/X11/fs/config';
if(open(my $fh, '<', $fpath))
{
  while(my $line=<$fh>)
  {
    chomp($line);
    if($line=~/^\s*catalogue\s*=\s*(.+?)\s*$/s)
    {
      for my $dir (split(/\s*,\s*/,$1))
      {
        $dir=File::Spec->rel2abs($dir);
        next unless(-d $dir);
        next if(grep{$dir=~/^\Q$_\E/}@font_dirs);
        push(@font_dirs,$dir);
      }
      last();
    }
  }
  close($fh);
}

#-----------------------------------------------------------------------
my $font_list=FontList->new(\@font_dirs);
my $gui=GUI->new();
$gui->signal_connect(do_exit => sub{ Gtk2->main_quit; });

$gui->signal_connect(do_search => sub{
    $font_list->search(sub{
        my($fl,$count,$dir,$name,$file)=@_;
        $gui->set_info_text("FOUND($count) $File::Find::name",'SEARCH');
        Gtk2->main_iteration while Gtk2->events_pending;
      });
    $gui->set_info_text('','SEARCH');

    my @lst=$font_list->get_family_list();
    $gui->set_family_list(\@lst);

    return 1;
  });

$gui->signal_connect( dir_added => sub{
    my $g=shift;
    my $path=shift;
    $font_list->add_path($path);
    my @lst=$font_list->get_path_list;
    $gui->set_dir_list(\@lst);
    return 1;
  });

$gui->signal_connect( dir_deleted => sub{
    my $g=shift;
    my $path=shift;
    $font_list->del_path($path);
    my @lst=$font_list->get_path_list();
    $gui->set_dir_list(\@lst);
    @lst=$font_list->get_family_list();
    $gui->set_family_list(\@lst);
    return 1;
  });

$gui->signal_connect( family_selected => sub{
    my $g=shift;
    my $name=shift;

    my @lst;
    for my $file ($font_list->get_file_list($name))
    {
      my $font=$font_list->get_font($name,$file);
      push(@lst,[$name,$file,$font->style()]);
    }
    $gui->set_style_list(\@lst);
    $gui->style_list()->select(0);
    return 1;
  });

$gui->signal_connect( font_selected => sub{
    my $g=shift;
    my $name=shift;
    my $file=shift;
    $gui->set_font($font_list->get_font($name,$file));
    return 1;
  });

$gui->signal_connect( text_changed => sub{
    my $g=shift;
    my $text=shift;

    my $slist=$gui->style_list();
    my ($pos)=$slist->get_selected_indices();
    unless(defined($pos))
    {
      $slist->select(0);
      return 1;
    }

    my ($name,$file)=@{$slist->{data}->[$pos]}[0,1];
    $gui->set_font($font_list->get_font($name,$file));

    return 1;
  });

$gui->signal_connect( size_changed => sub{
    my $g=shift;
    my $size=shift;


    my $slist=$gui->style_list();
    my ($pos)=$slist->get_selected_indices();

    unless(defined($pos))
    {
      $slist->select(0);
      return 1;
    }

    my ($name,$file)=@{$slist->{data}->[$pos]}[0,1];
    $gui->set_font($font_list->get_font($name,$file));

    return 1;
  });

my @lst=$font_list->get_path_list;
$gui->set_dir_list(\@lst);
$gui->show_all();

Gtk2->main();

exit();

########################################################################
########################################################################
########################################################################

package FontList;
use File::Find;
use Font::FreeType;
use File::Spec;
use Carp;

sub new
{
  my $class=shift();
  my $paths=shift();

  $class=ref($class) || $class;

  my $self={};
  $self->{path}={};
  if($paths && ref($paths) eq 'ARRAY')
  {
    for(@$paths)
    {
      my $path=File::Spec->rel2abs($_);
      next unless (-d $path);
      $self->{path}->{$path}={};
    }
  }
  $self->{fonts}={};

  bless($self,$class);
}


sub search
{
  my $self=shift;
  my $caller=shift;
  $caller=undef unless(ref($caller) eq 'CODE');

  my $count=0;
  my $freetype = Font::FreeType->new();

  for my $dir (keys(%{$self->{path}}))
  {
    my $dir_ref=$self->{path}->{$dir};
    find(sub{
        return unless(-f $File::Find::name);
        return if(exists($dir_ref->{$File::Find::name}));

        my $face = eval{ $freetype->face($File::Find::name) };
        return if($@ || !$face);


        my $name=$face->family_name() || '???';

        if($caller)
        {
          eval{ $caller->($self,$count,$dir,$name,$File::Find::name) };
          carp($@) if($@);
        }

        $dir_ref->{$File::Find::name}=$name;
        $self->{fonts}->{$name}->{$File::Find::name}=undef;

        $count++;
      },$dir);
  }

  return 1;
}

sub get_path_list
{ return sort{lc($a) cmp lc($b)}keys(%{$_[0]->{path}}); }

sub set_path_list
{
  my $self=shift;
  my $paths=shift;
  return 0 unless ($paths && ref($paths) eq 'ARRAY');

  my @lst=map{File::Spec->rel2abs($_)}@$paths;

  # delete old
  for my $dir (keys(%{$self->{path}}))
  {
    next if(grep{$dir eq $_}@lst);
    my @files=keys(%{$self->{path}->{$dir}});
    for my $file (@files)
    {
      my $name=$self->{path}->{$dir}->{$file};
      if($name && exists($self->{fonts}->{$name}))
      { delete($self->{fonts}->{$name}->{$file}); }
    }
  }

  # add new
  for my $path (@lst)
  {
    next unless (-d $path);
    unless($self->{path}->{$path})
    { $self->{path}->{$path}={}; }
  }

  # remove empty
  for my $name (keys(%{$self->{fonts}}))
  {
    unless(keys(%{$self->{fonts}->{$name}}))
    { delete($self->{fonts}->{$name}); }
  }

  return 1;
}

sub add_path
{
  my $self=shift;
  my $path=shift;
  return 0 unless($path);
  $path=File::Spec->rel2abs($path);
  return 0 unless(-d $path);

  return 1 if(exists($self->{path}->{$path}));

  $self->{path}->{$path}={};
  return 1;
}

sub del_path
{
  my $self=shift;
  my $path=shift;
  return 0 unless($path);
  $path=File::Spec->rel2abs($path);
  return 0 unless(exists($self->{path}->{$path}));

  my @files=keys(%{$self->{path}->{$path}});
  for my $file (@files)
  {
    my $name=$self->{path}->{$path}->{$file};
    if($name && exists($self->{fonts}->{$name}))
    { delete($self->{fonts}->{$name}->{$file}); }
  }

  for my $name (keys(%{$self->{fonts}}))
  {
    unless(keys(%{$self->{fonts}->{$name}}))
    { delete($self->{fonts}->{$name}); }
  }

  delete($self->{path}->{$path});
  return 1;
}

sub get_family_list
{ return sort{lc($a) cmp lc($b)}keys(%{$_[0]->{fonts}}); }

sub get_file_list
{
  my $self=shift;
  my $name=shift // '';
  return () unless(exists($self->{fonts}->{$name}));
  return sort{lc($a) cmp lc($b)}keys(%{$self->{fonts}->{$name}});
}

sub get_font
{
  my $self=shift;
  my $name=shift // '';
  my $file=shift // '';
  return undef unless(exists($self->{fonts}->{$name}));
  return undef unless(exists($self->{fonts}->{$name}->{$file}));
  unless($self->{fonts}->{$name}->{$file})
  { $self->{fonts}->{$name}->{$file}=FontList::Font->new($file); }
  return $self->{fonts}->{$name}->{$file};
}

1;

########################################################################
package FontList::Font;
use Font::FreeType;
use Gtk2;

sub new
{
  my $class=shift();
  $class=ref($class) || $class;

  my $self={};
  $self->{file}=shift() // '';

  $self->{name}='???';
  $self->{style}='???';
  $self->{type}='UNKNOWN';

  bless($self,$class);
  $self->_init() if(-f $self->{file});
  return $self;
}

sub _init
{
  my $self=shift;
  my $freetype = Font::FreeType->new();
  my $face=eval{ $freetype->face($self->file()) };
  return unless($face);
  $self->{name}  = $face->family_name() || '?NONE?';
  $self->{style} = $face->style_name() || '?NONE?';
  $self->{type}   = $face->is_scalable()? 'VECTOR': 'BITMAP';
}

sub name{ return $_[0]->{name}; }
sub file{ return $_[0]->{file}; }
sub style{ return $_[0]->{style}; }
sub type{ return $_[0]->{type}; }

sub image
{
  my $self=shift;
  my $str=shift || $self->name();
  my $height=shift || 12;

  my $freetype = Font::FreeType->new();
  my $face = eval{ $freetype->face($self->file()) };

  my $width=100;
  my $offset=10;
  my @glyphs;
  if($face)
  {
    my $scale=$face->is_scalable();
    unless($scale)
    {
      $height=0;
      for my $size (sort{$a->{height} <=> $b->{height}}$face->fixed_sizes())
      {
        if($size->{height}>=$height)
        {
          $height=$size->{height};
          last;
        }
      }
      unless($height)
      { $height=($face->fixed_sizes())[0]->{height}; }
    }
    $face->set_pixel_size(0, $height);

    $width=1;
    $offset=0;
    for(split('',$str))
    {
      my $glyph=$face->glyph_from_char($_);

      if($glyph)
      {
        my $w=$glyph->horizontal_advance();
        $width+=$w;
        $offset=$w if($offset<$w);
      }
      else
      { $width+=$height; }

      push(@glyphs, $glyph);
    }
  }



  my $iw=$width+2*$offset;
  my $ih=$height*2;

  my $pixbuf = Gtk2::Gdk::Pixbuf->new_from_data (pack('CCCC',255,255,255,255), 'GDK_COLORSPACE_RGB', 1, 8, 1, 1, 3);
  $pixbuf = $pixbuf->scale_simple( $iw, $ih, 'GDK_INTERP_NEAREST');


  if($face)
  {
    my $pos=$offset;
    for my $glyph (@glyphs)
    {
      if($glyph)
      {
        my ($pb,$left,$top)=__glyph_to_pixbuf($glyph);
        my $px=$pos+$left;
        my $py=$height-$top+int($height/2);
        my $gw=$glyph->width();
        my $gh=$glyph->height();
        if(
            $px>=0 && $py>=0 &&
            $gw>0  && $gh>0  &&
            $px+$gw <= $iw   &&
            $py+$gh <= $ih
          )
        {
          $pb->composite(
              $pixbuf,
              $px, $py,
              $gw, $gh,
              $px, $py,
              1, 1,
              'bilinear',
              255
            );
        }
        $pos+=$glyph->horizontal_advance();
      }
      else
      { $pos+=$height; }
    }
    return $pixbuf, $face->family_name(), $face->style_name(), $face->is_scalable();
  }


  $pixbuf = Gtk2::Gdk::Pixbuf->new_from_data (pack('CCC',0,0,255), 'GDK_COLORSPACE_RGB', 0, 8, 1, 1, 3);
  $pixbuf = $pixbuf->scale_simple( $width+2*$offset, $height*2, 'GDK_INTERP_NEAREST');
  return $pixbuf, '???', '???',0;

}

sub __glyph_to_pixbuf
{
  no utf8;
  my $glyph=shift;

  my ($bmp, $left, $top) = $glyph->bitmap(@_);

  my $width=$glyph->width() || 1;
  my $height=$glyph->height() || 1;

  # repack to rgb
  my $str=pack( 'C*', map{$_?(0,0,0,$_):(255,255,255,0)}unpack('C*',join('',@$bmp)) );
  my $pixbuf = eval{
      local $SIG{__DIE__}=sub{};
      local $SIG{__WARN__}=sub{};
      Gtk2::Gdk::Pixbuf->new_from_data ($str, 'GDK_COLORSPACE_RGB', 1, 8, $width, $height, $width*4);
    };

  unless($pixbuf)
  {
    # correct width/height
    my $str='';
    for my $y (0..$height-1)
    {
      my @l=unpack('C*',$bmp->[$y] // '');
      for my $x (0..$width-1)
      {
        my $val=$l[$x] // 0;
        if($val>0)
        { $str.=pack('C*',0,0,0,$val); }
        else
        { $str.=pack('C*',255,255,255,0); }
      }
    }
    $pixbuf = eval{
        local $SIG{__DIE__}=sub{};
        local $SIG{__WARN__}=sub{};
        Gtk2::Gdk::Pixbuf->new_from_data($str x $width*$height, 'GDK_COLORSPACE_RGB', 1, 8, $width, $height, $width*3);
      };
  }

  # give up..
  unless($pixbuf)
  {
    my $str=pack('C*',255,0,0,128);
    $pixbuf = Gtk2::Gdk::Pixbuf->new_from_data($str x $width*$height, 'GDK_COLORSPACE_RGB', 1, 8, $width, $height, $width*3);
  }

  return ($pixbuf, $left, $top);
}

1;

########################################################################
package GUI;
use strict;
use warnings;

use Gtk2;
use Gtk2::SimpleList;

use File::Spec;
use List::Util;

#______________________________________________________________________#
#__CREATION____________________________________________________________#

use Glib::Object::Subclass
  Gtk2::Builder::,
  signals => {
    do_exit  => {
      flags => [qw/run-last/],
      param_types => [],
    },
    do_search => {
      flags => [qw/run-last/],
      param_types => [],
    },
    dir_added => {
      flags => [qw/run-last/],
      param_types => [qw/Glib::String/],
    },
    dir_deleted => {
      flags => [qw/run-last/],
      param_types => [qw/Glib::String/],
    },
    font_selected => {
      flags => [qw/run-last/],
      param_types => [qw/Glib::String Glib::String/],
    },
    family_selected => {
      flags => [qw/run-last/],
      param_types => [qw/Glib::String/],
    },
    text_changed => {
      flags => [qw/run-last/],
      param_types => [qw/Glib::String/],
    },
    size_changed => {
      flags => [qw/run-last/],
      param_types => [qw/Glib::Int/],
    },
  },
  properties => [];

sub new
{
  my $class=shift;
  my $self=$class->SUPER::new();

  return undef unless($self->add_from_string(eval{local $/=undef; <DATA> }));

  $self->{dir_list} = Gtk2::SimpleList->new_from_treeview (
      $self->get_object('tv_dirs'),
      Directory => 'text',
    );

  $self->{font_list} = Gtk2::SimpleList->new_from_treeview (
      $self->get_object('tv_fonts'),
      Font => 'text',
    );

  $self->{style_list} = Gtk2::SimpleList->new_from_treeview (
      $self->get_object('tv_type'),
      name => 'hidden',
      file => 'hidden',
      Type => 'text',
    );

  my $adj=$self->font_size()->get_adjustment();
  $adj->lower(0);
  $adj->upper(100);
  $adj->step_increment(1);
  $adj->page_increment(10);
  $adj->value(40);

  $self->{font_list}->get_selection()->signal_connect(changed => sub{
      $self->on_font_select();
    });

  $self->{style_list}->get_selection()->signal_connect(changed => sub{
      $self->on_font_type_select();
    });

  $self->connect_signals($self);
  return $self;
}

#______________________________________________________________________#
#__GET_________________________________________________________________#

sub mainwin   { return $_[0]->get_object('mainwin'); }
sub status_bar{ return $_[0]->get_object('status'); }

sub font_image{ return $_[0]->get_object('img_font'); }
sub font_text { return $_[0]->get_object('entry_text'); }
sub font_name { return $_[0]->get_object('l_font_name'); }
sub font_style{ return $_[0]->get_object('l_font_type'); }
sub font_file { return $_[0]->get_object('l_font_file'); }
sub font_type { return $_[0]->get_object('l_font_vector'); }
sub font_size { return $_[0]->get_object('sb_size'); }

sub dir_list  { return $_[0]->{dir_list}; }
sub font_list { return $_[0]->{font_list}; }
sub style_list{ return $_[0]->{style_list}; }

sub get_dirs
{
  my $self=shift;
  return @{$self->dir_list()->{data}};
}

sub get_selected_font
{
  my $self=shift;
  my $slist=$self->style_list();
  my ($pos)=$slist->get_selected_indices();
  unless($pos)
  {
    $slist->select(0);
    $pos=0;
  }
  return @{$slist->{data}->[$pos]}[0,1];
}

#______________________________________________________________________#
#__SIGNALS_____________________________________________________________#

sub on_dir_del
{
  my $self=pop;
  my $slist=$self->dir_list();
  my ($pos)=$slist->get_selected_indices();
  my $dir=$slist->{data}->[$pos]->[0];
  $self->signal_emit('dir_deleted', $dir );
  return 1;
}

sub on_dir_add
{
  my $self=pop;

  my $dialog=Gtk2::FileChooserDialog->new (
      'Select Dir ...',
      undef,
      'select-folder',
      'gtk-cancel' => 'cancel',
      'gtk-open' => 'ok',
    );
  $dialog->set_select_multiple(0);
  $dialog->set_preview_widget_active(0);
  $dialog->set_local_only(1);
  $dialog->set_default_response ('ok');
  if ('ok' eq $dialog->run ())
  {
    my $dir=$dialog->get_filename();
    print "DIR: $dir\n";
    $self->signal_emit('dir_added', $dir );
  }

  $dialog->destroy();

  return 1;
}

sub on_update_fonts
{
  my $self=pop;
  $self->signal_emit('do_search');
  return 1;
}

sub on_exit
{
  my $self=pop;
  $self->mainwin()->destroy();
  $self->signal_emit('do_exit');
  return 1;
}

sub on_font_select
{
  my $self=pop;
  my $slist=$self->font_list();
  my ($pos)=$slist->get_selected_indices();
  return 0 unless(defined($pos));
  my $name=$slist->{data}->[$pos]->[0];
  $self->signal_emit('family_selected',$name);
  return 1;
}

sub on_font_type_select
{
  my $self=pop;
  my $slist=$self->style_list();
  my ($pos)=$slist->get_selected_indices();
  return 0 unless(defined($pos));
  my $name=$slist->{data}->[$pos]->[0];
  my $file=$slist->{data}->[$pos]->[1];
  $self->signal_emit('font_selected',$name,$file);
  return 1;
}

sub on_font_text_changed
{
  my $self=pop;
  my $entry=shift;
  $self->signal_emit('text_changed',$entry->get_text());
  return 1;
}

sub on_size_changed
{
  my $self=pop;
  my $sb=shift;
  $self->signal_emit('size_changed',$sb->get_value_as_int());
  return 1;
}
#______________________________________________________________________#
#__SET/PROCESS_________________________________________________________#

sub show
{
  my $self=shift;
  $self->mainwin()->show();
}

sub show_all
{
  my $self=shift;
  $self->mainwin()->show_all();
}

sub set_info_text
{
  my $self=shift;
  my $text=shift // '';
  my $context=shift // 'DEFAULT';

  my $s=$self->status_bar();
  my $id=$s->get_context_id($context);
  my $ret=$s->pop($id);
  $s->push($id, $text) if($text);
  return $ret;
}

sub set_dir_list
{
  my $self=shift;
  my $list=shift // [];
  return 0 if(ref($list) ne 'ARRAY');
  @{$self->dir_list()->{data}}=@$list;
  return 1;
}

sub set_family_list
{
  my $self=shift;
  my $list=shift // [];
  return 0 if(ref($list) ne 'ARRAY');
  @{$self->font_list()->{data}}=@$list;
  return 1;
}

sub set_style_list
{
  my $self=shift;
  my $list=shift // [];
  return 0 if(ref($list) ne 'ARRAY');
  @{$self->style_list()->{data}}=@$list;
  return 1;
}

sub set_font
{
  my $self=shift;
  my $font=shift;
  return 0 unless($font && ref($font) eq 'FontList::Font');

  $self->font_name() ->set_text($font->name());
  $self->font_style()->set_text($font->style());
  $self->font_file() ->set_text($font->file());
  $self->font_type() ->set_text($font->type());
  $self->set_font_image($font->image(
      $self->font_text()->get_text(),
      $self->font_size()->get_value_as_int()
    ));
  return 1;
}

sub set_font_image
{
  my $self=shift;
  my $pixbuf=shift;
  $self->font_image()->set_from_pixbuf($pixbuf);
  return 1;
}

#______________________________________________________________________#
#__PRIVATE_____________________________________________________________#

1;

#______________________________________________________________________#
#__GUI-XML_____________________________________________________________#
__DATA__
<?xml version="1.0"?>
<interface>
  <requires lib="gtk+" version="2.16"/>
  <!-- interface-naming-policy project-wide -->
  <object class="GtkWindow" id="mainwin">
    <child>
      <object class="GtkVBox" id="vbox1">
        <property name="visible">True</property>
        <property name="orientation">vertical</property>
        <property name="spacing">5</property>
        <child>
          <object class="GtkHPaned" id="hpaned1">
            <property name="visible">True</property>
            <property name="can_focus">True</property>
            <property name="position">170</property>
            <property name="position_set">True</property>
            <child>
              <object class="GtkVBox" id="vbox4">
                <property name="visible">True</property>
                <property name="border_width">5</property>
                <property name="orientation">vertical</property>
                <property name="spacing">5</property>
                <child>
                  <object class="GtkScrolledWindow" id="scrolledwindow4">
                    <property name="width_request">170</property>
                    <property name="visible">True</property>
                    <property name="can_focus">True</property>
                    <property name="hscrollbar_policy">automatic</property>
                    <child>
                      <object class="GtkTreeView" id="tv_dirs">
                        <property name="visible">True</property>
                        <property name="can_focus">True</property>
                        <property name="model">liststore3</property>
                      </object>
                    </child>
                  </object>
                  <packing>
                    <property name="position">0</property>
                  </packing>
                </child>
                <child>
                  <object class="GtkButton" id="b_del_dir">
                    <property name="label">gtk-delete</property>
                    <property name="visible">True</property>
                    <property name="can_focus">True</property>
                    <property name="receives_default">True</property>
                    <property name="use_stock">True</property>
                    <signal name="clicked" handler="on_dir_del"/>
                  </object>
                  <packing>
                    <property name="expand">False</property>
                    <property name="position">1</property>
                  </packing>
                </child>
                <child>
                  <object class="GtkButton" id="b_add_dir">
                    <property name="label" translatable="yes">Hinzuf&#xFC;gen</property>
                    <property name="visible">True</property>
                    <property name="can_focus">True</property>
                    <property name="receives_default">True</property>
                    <property name="image">image2</property>
                    <signal name="clicked" handler="on_dir_add"/>
                  </object>
                  <packing>
                    <property name="expand">False</property>
                    <property name="position">2</property>
                  </packing>
                </child>
              </object>
              <packing>
                <property name="resize">False</property>
                <property name="shrink">True</property>
              </packing>
            </child>
            <child>
              <object class="GtkHPaned" id="hpaned2">
                <property name="visible">True</property>
                <property name="can_focus">True</property>
                <property name="position">150</property>
                <property name="position_set">True</property>
                <child>
                  <object class="GtkVBox" id="vbox2">
                    <property name="visible">True</property>
                    <property name="border_width">5</property>
                    <property name="orientation">vertical</property>
                    <property name="spacing">5</property>
                    <child>
                      <object class="GtkScrolledWindow" id="scrolledwindow1">
                        <property name="width_request">170</property>
                        <property name="visible">True</property>
                        <property name="can_focus">True</property>
                        <property name="hscrollbar_policy">automatic</property>
                        <child>
                          <object class="GtkTreeView" id="tv_fonts">
                            <property name="visible">True</property>
                            <property name="can_focus">True</property>
                            <property name="model">liststore1</property>
                            <signal name="row_activated" handler="on_font_select"/>
                          </object>
                        </child>
                      </object>
                      <packing>
                        <property name="position">0</property>
                      </packing>
                    </child>
                    <child>
                      <object class="GtkButton" id="b_update">
                        <property name="label" translatable="yes">Aktualisieren</property>
                        <property name="visible">True</property>
                        <property name="can_focus">True</property>
                        <property name="receives_default">True</property>
                        <property name="image">image1</property>
                        <signal name="clicked" handler="on_update_fonts"/>
                      </object>
                      <packing>
                        <property name="expand">False</property>
                        <property name="position">1</property>
                      </packing>
                    </child>
                  </object>
                  <packing>
                    <property name="resize">False</property>
                    <property name="shrink">True</property>
                  </packing>
                </child>
                <child>
                  <object class="GtkHBox" id="hbox2">
                    <property name="visible">True</property>
                    <property name="border_width">5</property>
                    <property name="spacing">5</property>
                    <child>
                      <object class="GtkScrolledWindow" id="scrolledwindow2">
                        <property name="width_request">170</property>
                        <property name="visible">True</property>
                        <property name="can_focus">True</property>
                        <property name="hscrollbar_policy">never</property>
                        <child>
                          <object class="GtkTreeView" id="tv_type">
                            <property name="visible">True</property>
                            <property name="can_focus">True</property>
                            <property name="model">liststore2</property>
                            <property name="enable_search">False</property>
                            <signal name="row_activated" handler="on_font_type_select"/>
                          </object>
                        </child>
                      </object>
                      <packing>
                        <property name="expand">False</property>
                        <property name="position">0</property>
                      </packing>
                    </child>
                    <child>
                      <object class="GtkVBox" id="vbox3">
                        <property name="visible">True</property>
                        <property name="orientation">vertical</property>
                        <property name="spacing">5</property>
                        <child>
                          <object class="GtkImage" id="img_font">
                            <property name="height_request">200</property>
                            <property name="visible">True</property>
                            <property name="xalign">0</property>
                            <property name="yalign">0</property>
                            <property name="stock">gtk-missing-image</property>
                          </object>
                          <packing>
                            <property name="expand">False</property>
                            <property name="position">0</property>
                          </packing>
                        </child>
                        <child>
                          <object class="GtkTable" id="table2">
                            <property name="visible">True</property>
                            <property name="n_rows">2</property>
                            <property name="n_columns">2</property>
                            <property name="column_spacing">5</property>
                            <property name="row_spacing">5</property>
                            <child>
                              <object class="GtkSpinButton" id="sb_size">
                                <property name="visible">True</property>
                                <property name="can_focus">True</property>
                                <property name="max_length">5</property>
                                <property name="climb_rate">1</property>
                                <property name="numeric">True</property>
                                <signal name="value_changed" handler="on_size_changed"/>
                              </object>
                              <packing>
                                <property name="left_attach">1</property>
                                <property name="right_attach">2</property>
                                <property name="top_attach">1</property>
                                <property name="bottom_attach">2</property>
                                <property name="y_options">GTK_FILL</property>
                              </packing>
                            </child>
                            <child>
                              <object class="GtkLabel" id="label6">
                                <property name="visible">True</property>
                                <property name="xalign">1</property>
                                <property name="yalign">0</property>
                                <property name="label" translatable="yes">Font Size:</property>
                              </object>
                              <packing>
                                <property name="top_attach">1</property>
                                <property name="bottom_attach">2</property>
                                <property name="x_options">GTK_FILL</property>
                                <property name="y_options">GTK_FILL</property>
                              </packing>
                            </child>
                            <child>
                              <object class="GtkEntry" id="entry_text">
                                <property name="visible">True</property>
                                <property name="can_focus">True</property>
                                <signal name="changed" handler="on_font_text_changed"/>
                              </object>
                              <packing>
                                <property name="left_attach">1</property>
                                <property name="right_attach">2</property>
                              </packing>
                            </child>
                            <child>
                              <object class="GtkLabel" id="label7">
                                <property name="visible">True</property>
                                <property name="xalign">1</property>
                                <property name="yalign">0</property>
                                <property name="label" translatable="yes">Font Text:</property>
                              </object>
                              <packing>
                                <property name="x_options">GTK_FILL</property>
                                <property name="y_options">GTK_FILL</property>
                              </packing>
                            </child>
                          </object>
                          <packing>
                            <property name="expand">False</property>
                            <property name="position">1</property>
                          </packing>
                        </child>
                        <child>
                          <object class="GtkLabel" id="label5">
                            <property name="visible">True</property>
                          </object>
                          <packing>
                            <property name="position">2</property>
                          </packing>
                        </child>
                        <child>
                          <object class="GtkTable" id="table1">
                            <property name="visible">True</property>
                            <property name="border_width">5</property>
                            <property name="n_rows">4</property>
                            <property name="n_columns">2</property>
                            <property name="column_spacing">5</property>
                            <property name="row_spacing">5</property>
                            <child>
                              <object class="GtkLabel" id="label1">
                                <property name="visible">True</property>
                                <property name="sensitive">False</property>
                                <property name="xalign">1</property>
                                <property name="yalign">0</property>
                                <property name="label" translatable="yes">Name:</property>
                              </object>
                              <packing>
                                <property name="x_options">GTK_FILL</property>
                                <property name="y_options">GTK_FILL</property>
                              </packing>
                            </child>
                            <child>
                              <object class="GtkLabel" id="label2">
                                <property name="visible">True</property>
                                <property name="sensitive">False</property>
                                <property name="xalign">1</property>
                                <property name="yalign">0</property>
                                <property name="label" translatable="yes">Typ:</property>
                              </object>
                              <packing>
                                <property name="top_attach">1</property>
                                <property name="bottom_attach">2</property>
                                <property name="x_options">GTK_FILL</property>
                                <property name="y_options">GTK_FILL</property>
                              </packing>
                            </child>
                            <child>
                              <object class="GtkLabel" id="label3">
                                <property name="visible">True</property>
                                <property name="sensitive">False</property>
                                <property name="xalign">1</property>
                                <property name="yalign">0</property>
                                <property name="label" translatable="yes">Datei:</property>
                              </object>
                              <packing>
                                <property name="top_attach">2</property>
                                <property name="bottom_attach">3</property>
                                <property name="x_options">GTK_FILL</property>
                                <property name="y_options">GTK_FILL</property>
                              </packing>
                            </child>
                            <child>
                              <object class="GtkLabel" id="l_font_name">
                                <property name="visible">True</property>
                                <property name="xalign">0</property>
                                <property name="yalign">0</property>
                                <property name="label" translatable="yes">???</property>
                                <property name="selectable">True</property>
                              </object>
                              <packing>
                                <property name="left_attach">1</property>
                                <property name="right_attach">2</property>
                              </packing>
                            </child>
                            <child>
                              <object class="GtkLabel" id="l_font_type">
                                <property name="visible">True</property>
                                <property name="xalign">0</property>
                                <property name="yalign">0</property>
                                <property name="label" translatable="yes">???</property>
                              </object>
                              <packing>
                                <property name="left_attach">1</property>
                                <property name="right_attach">2</property>
                                <property name="top_attach">1</property>
                                <property name="bottom_attach">2</property>
                              </packing>
                            </child>
                            <child>
                              <object class="GtkLabel" id="l_font_file">
                                <property name="visible">True</property>
                                <property name="xalign">0</property>
                                <property name="yalign">0</property>
                                <property name="label" translatable="yes">???</property>
                                <property name="selectable">True</property>
                              </object>
                              <packing>
                                <property name="left_attach">1</property>
                                <property name="right_attach">2</property>
                                <property name="top_attach">2</property>
                                <property name="bottom_attach">3</property>
                              </packing>
                            </child>
                            <child>
                              <object class="GtkLabel" id="label4">
                                <property name="visible">True</property>
                                <property name="sensitive">False</property>
                                <property name="xalign">1</property>
                                <property name="yalign">0</property>
                                <property name="label" translatable="yes">Art:</property>
                              </object>
                              <packing>
                                <property name="top_attach">3</property>
                                <property name="bottom_attach">4</property>
                                <property name="x_options">GTK_FILL</property>
                                <property name="y_options">GTK_FILL</property>
                              </packing>
                            </child>
                            <child>
                              <object class="GtkLabel" id="l_font_vector">
                                <property name="visible">True</property>
                                <property name="xalign">0</property>
                                <property name="yalign">0</property>
                                <property name="label" translatable="yes">???</property>
                              </object>
                              <packing>
                                <property name="left_attach">1</property>
                                <property name="right_attach">2</property>
                                <property name="top_attach">3</property>
                                <property name="bottom_attach">4</property>
                              </packing>
                            </child>
                          </object>
                          <packing>
                            <property name="expand">False</property>
                            <property name="position">3</property>
                          </packing>
                        </child>
                      </object>
                      <packing>
                        <property name="position">1</property>
                      </packing>
                    </child>
                  </object>
                  <packing>
                    <property name="resize">True</property>
                    <property name="shrink">True</property>
                  </packing>
                </child>
              </object>
              <packing>
                <property name="resize">True</property>
                <property name="shrink">True</property>
              </packing>
            </child>
          </object>
          <packing>
            <property name="position">0</property>
          </packing>
        </child>
        <child>
          <object class="GtkButton" id="b_exit">
            <property name="label">gtk-close</property>
            <property name="visible">True</property>
            <property name="can_focus">True</property>
            <property name="receives_default">True</property>
            <property name="border_width">5</property>
            <property name="use_stock">True</property>
            <signal name="clicked" handler="on_exit"/>
          </object>
          <packing>
            <property name="expand">False</property>
            <property name="position">1</property>
          </packing>
        </child>
        <child>
          <object class="GtkStatusbar" id="status">
            <property name="visible">True</property>
            <property name="spacing">2</property>
          </object>
          <packing>
            <property name="expand">False</property>
            <property name="position">2</property>
          </packing>
        </child>
      </object>
    </child>
  </object>
  <object class="GtkListStore" id="liststore1"/>
  <object class="GtkListStore" id="liststore2"/>
  <object class="GtkListStore" id="liststore3"/>
  <object class="GtkImage" id="image1">
    <property name="visible">True</property>
    <property name="stock">gtk-file</property>
  </object>
  <object class="GtkImage" id="image2">
    <property name="visible">True</property>
    <property name="stock">gtk-open</property>
  </object>
</interface>

Ergänzungen, Kommentare

Kommentare werden am besten in folgender Form vorgenommen, damit sie im Inhaltsverzeichnis angezeigt werden (natürlich ohne das <verbatim>):
<small>
---### Main.??? - 14 Jul 2003 - Betreff
</small>

UtilPerlSkripteSubForm edit

Titel Script zum Suchen und betrachten von Fonts
Autor
Bereich Gtk2Scripte
Topic revision: 2011-08-13, ToPeGroe
 
Bitte die NutzungsBedingungen beachten.
Bei Vorschlägen, Anfragen oder Problemen mit dem PerlCommunityWiki bitten wir um WebBottomBarExample">Rückmeldung.