#!/usr/bin/perl use strict; use Gtk2 '-init'; use Gtk2::Pango; my $w = Gtk2::Window->new; $w->set_size_request(805, 550); $w->add(my $text = Gtk2::TextView->new); $text->set_wrap_mode('word'); $w->show_all; _text_insert($text, [ titleFormat("Test title"), [ "test test\n", { 'weight' => Gtk2::Pango->PANGO_WEIGHT_BOLD } ], [ "blabla" . ": \x{200e}", { 'foreground' => 'royalblue3', 'weight' => 'bold' } ], ]); Gtk2->main; sub titleFormat { my ($title) = @_; [ $title . "\n", { 'weight' => Gtk2::Pango->PANGO_WEIGHT_BOLD, scale => Gtk2::Pango->PANGO_SCALE_LARGE } ]; } # _text_insert() can be used with any of choose one of theses styles: # - no tags: # _text_insert($textview, "My text.."); # - anonymous tags: # _text_insert($textview, [ [ 'first text', { 'foreground' => 'blue', 'background' => 'green', ... } ], # [ 'second text' ], # [ 'third', { 'font' => 'Serif 15', ... } ], # ... ]); # - named tags: # $textview->{tags} = { # 'blue_green' => { 'foreground' => 'blue', 'background' => 'green', ... }, # 'big_font' => { 'font' => 'Serif 35', ... }, # } # _text_insert($textview, [ [ 'first text', 'blue_green' ], # [ 'second', 'big_font' ], # ... ]); # - mixed anonymous and named tags: # $textview->{tags} = { # 'blue_green' => { 'foreground' => 'blue', 'background' => 'green', ... }, # 'big_font' => { 'font' => 'Serif 35', ... }, # } # _text_insert($textview, [ [ 'first text', 'blue_green' ], # [ 'second text' ], # [ 'third', 'big_font' ], # [ 'fourth', { 'font' => 'Serif 15', ... } ], # ... ]); sub _text_insert { my ($textview, $t, %opts) = @_; my $buffer = $textview->get_buffer; $buffer->{tags} ||= {}; $buffer->{gtk_tags} ||= {}; my $gtk_tags = $buffer->{gtk_tags}; my $tags = $buffer->{tags}; if (ref($t) eq 'ARRAY') { if (!$opts{append}) { $buffer->set_text(''); $textview->{anchors} = []; } foreach my $token (@$t) { my ($item, $tag) = @$token; my $iter1 = $buffer->get_end_iter; if (ref($item) =~ /^Gtk2::Gdk::Pixbuf/) { $buffer->insert_pixbuf($iter1, $item); next; } if (ref($item) =~ /^Gtk2::/) { my $anchor = $buffer->create_child_anchor($iter1); $textview->add_child_at_anchor($item, $anchor); $textview->{anchors} ||= []; push @{$textview->{anchors}}, $anchor; next; } if ($tag) { if (ref($tag)) { # use anonymous tags $buffer->insert_with_tags($iter1, $item, $buffer->create_tag(undef, %$tag)); } else { # fast text insertion: # since in some contexts (eg: localedrake, rpmdrake), we use quite a lot of identical tags, # it's much more efficient and less memory pressure to use named tags $gtk_tags->{$tag} ||= $buffer->create_tag($tag, %{$tags->{$token->[1]}}); $buffer->insert_with_tags($iter1, $item, $gtk_tags->{$tag}); } } else { $buffer->insert($iter1, $item); } } } else { $t ||= ''; if ($opts{append}) { $buffer->insert($buffer->get_end_iter, $t); } else { $textview->{anchors} = []; $buffer->set_text($t); } } $textview->{to_bottom}->() if $textview->{to_bottom}; #- the following line is needed to move the cursor to the beginning, so that if the #- textview has a scrollbar, it will not scroll to the bottom when focusing (#3633) $buffer->place_cursor($buffer->get_start_iter); $textview->set_wrap_mode($opts{wrap_mode} || 'word'); $textview->set_editable($opts{editable} || 0); $textview->set_cursor_visible($opts{visible} || 0); $textview; }