Beefy Boxes and Bandwidth Generously Provided by pair Networks
P is for Practical
 
PerlMonks  

comment on

( [id://3333]=superdoc: print w/replies, xml ) Need Help??
Hi, I recently posted Gtk2 Visual Grep, in which I have a hack to turn linenumbers on/off for copying-and-pasting. Well there is a better way to do line numbers with Gtk2, it's called Gtk2::SourceView, which has automatic line numbers and syntax highlighting.

However :-), being the amateur that I am, I wanted to make a way to do it, without needing to install additional modules. My first attempt was to scroll-link 2 textviews side-by-side, one showing line numbers, and the other showing the lines. This method was a bit bloated and had some scrolling problems.

But luckily for me, muppet(on the gtk2-perl maillist) did a quick conversion from the c Gtk2 code and made a line-numbered-textview class. Since this is such a choice gem of a snippet, and will almost certainly be asked for as monks learn Perl/Gtk2; I present it here. (muppet is so busy, he seldom posts here anymore.)

#!/usr/bin/perl -w # by muppet of the gtk2-perl maillist and perlmonks =doc This is a quick port of the line-number drawing code from gtksourcevie +w. I've removed the stuff about markers and the ability to turn off line numbers. =cut package LineNumberedTextView; use strict; use Gtk2; use Glib ':constants'; use Glib::Object::Subclass Gtk2::TextView::, signals => { expose_event => \&_expose_event, }, ; sub INIT_INSTANCE { my $self = shift; # just make up a size, it will be set properly later. $self->set_border_window_size (left => 10); # start with a monospace font; the user can set whatever else he l +ikes. $self->modify_font (Gtk2::Pango::FontDescription->from_string ('mo +nospace')); } # This function is taken from gtk+/tests/testtext.c sub _get_lines { my ($text_view, $first_y, $last_y, $buffer_coords, $numbers) = @_; my $last_line_num = -1; @$buffer_coords = (); @$numbers = (); # Get iter at first y (my $iter, undef) = $text_view->get_line_at_y ($first_y); # For each iter, get its location and add it to the arrays. # Stop when we pass last_y my $count = 0; my $size = 0; while (! $iter->is_end) { my ($y, $height) = $text_view->get_line_yrange ($iter); push @$buffer_coords, $y; push @$numbers, $iter->get_line; ++$count; last if (($y + $height) >= $last_y); $iter->forward_line; } if ($iter->is_end) { my ($y, $height) = $text_view->get_line_yrange ($iter); my $line_num = $iter->get_line; if ($line_num != $last_line_num) { push @$buffer_coords, $y; push @$numbers, $line_num; ++$count; } } return $count; } sub _paint_margin { my ($self, $event) = @_; my $win = $self->get_window ('left'); my $y1 = $event->area->y; my $y2 = $y1 + $event->area->height; # get the extents of the line printing (undef, $y1) = $self->window_to_buffer_coords ('left', 0, $y1); (undef, $y2) = $self->window_to_buffer_coords ('left', 0, $y2); my @numbers; my @pixels; # get the line numbers and y coordinates. my $count = $self->_get_lines ($y1, $y2, \@pixels, \@numbers); # A zero-lined document should display a "1"; we don't need to wor +ry about # scrolling effects of the text widget in this special case if ($count == 0) { $count = 1; push @pixels, 0; push @numbers, 0; } #warn ("Painting line numbers $numbers[0] - $numbers[$#numbers]\n" +); # set size. my $str = sprintf "%d", $self->get_buffer->get_line_count; my $layout = $self->create_pango_layout ($str); my ($text_width, undef) = $layout->get_pixel_size; $layout->set_width ($text_width); $layout->set_alignment ('right'); # determine the width of the left margin. my $margin_width = $text_width + 4; $self->set_border_window_size (left => $margin_width); my $i = 0; my $cur = $self->get_buffer->get_iter_at_mark ($self->get_buffer-> +get_insert); # Remember to account for zero-indexing my $cur_line = $cur->get_line + 1; while ($i < $count) { my $pos; (undef, $pos) = $self->buffer_to_window_coords ('left', 0, $pixels[$i] +); my $line_to_paint = $numbers[$i] + 1; if ($line_to_paint == $cur_line) { $layout->set_markup ("<b>$line_to_paint</b>"); } else { $layout->set_markup ("$line_to_paint"); } $self->style->paint_layout ($win, $self->state, FALSE, undef, $self, undef, $text_width + 2, $pos, $layout); ++$i; } } sub _expose_event { my ($self, $event) = @_; # if the event is actually on the left window, we need to repaint # our line numbers. if ($event->window == $self->get_window ('left')) { return $self->_paint_margin ($event); } else { # otherwise, we just let TextView do all the work. return $self->signal_chain_from_overridden ($event); } } ############## package main; use strict; use Gtk2 -init; my $window = Gtk2::Window->new; my $scroller = Gtk2::ScrolledWindow->new; my $textview = LineNumberedTextView->new; my $buffer = $textview->get_buffer; my @lines = (1..500); foreach my $line (@lines) { $buffer->insert ($buffer->get_end_iter, "$line\n"); } my $end_mark = $buffer->create_mark( 'end', $buffer->get_end_iter, 0 ) +; $textview->scroll_to_mark( $end_mark, 0.0,0, 0.0, 1.0 ); #while (<>) { # $buffer->insert ($buffer->get_end_iter, $_); #} $window->add ($scroller); $scroller->add ($textview); $window->set_default_size (500, 300); $window->show_all; $window->signal_connect (destroy => sub {Gtk2->main_quit}); Gtk2->main; # vim: set et sw=4 sts=4 :

In reply to Gtk2 TextView-w-linenumbers by zentara

Title:
Use:  <p> text here (a paragraph) </p>
and:  <code> code here </code>
to format your post; it's "PerlMonks-approved HTML":



  • Are you posting in the right place? Check out Where do I post X? to know for sure.
  • Posts may use any of the Perl Monks Approved HTML tags. Currently these include the following:
    <code> <a> <b> <big> <blockquote> <br /> <dd> <dl> <dt> <em> <font> <h1> <h2> <h3> <h4> <h5> <h6> <hr /> <i> <li> <nbsp> <ol> <p> <small> <strike> <strong> <sub> <sup> <table> <td> <th> <tr> <tt> <u> <ul>
  • Snippets of code should be wrapped in <code> tags not <pre> tags. In fact, <pre> tags should generally be avoided. If they must be used, extreme care should be taken to ensure that their contents do not have long lines (<70 chars), in order to prevent horizontal scrolling (and possible janitor intervention).
  • Want more info? How to link or How to display code and escape characters are good places to start.
Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others making s'mores by the fire in the courtyard of the Monastery: (4)
As of 2024-03-29 08:09 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found