Logo Search packages:      
Sourcecode: leafpad version File versions

linenum.c

/*
 *  linenum.c
 *  This file is part of Leafpad
 *
 *  Copyright (C) 2004 Tarot Osuji
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

#include <gtk/gtk.h>

#define     DV(x)

static gint min_number_window_width;
static const gint margin = 5;

static gint calculate_min_number_window_width(GtkWidget *widget)
{
      PangoLayout *layout;
      gchar *str;
      gint width, col = 4;

      str = g_strnfill(col, 0x20);
      layout = gtk_widget_create_pango_layout(widget, str);
      g_free (str);

      pango_layout_get_pixel_size(layout, &width, NULL);
      g_object_unref(G_OBJECT(layout));

      return width;
}

/* taken from gedit and gtksourceview */
/* originated from gtk+/tests/testtext.c */

static void
get_lines (GtkTextView  *text_view,
           gint          y1,
           gint          y2,
           GArray       *buffer_coords,
           GArray       *numbers,
           gint         *countp)
{
      GtkTextIter iter;
      gint count;
      gint size;
            gint last_line_num;
      
      g_array_set_size (buffer_coords, 0);
      g_array_set_size (numbers, 0);
      
      /* Get iter at first y */
      gtk_text_view_get_line_at_y (text_view, &iter, y1, NULL);
      
      /* For each iter, get its location and add it to the arrays.
       * Stop when we pass y2
       */
      count = 0;
      size = 0;
      
      while (!gtk_text_iter_is_end (&iter))
      {
            gint y, height;
            
            gtk_text_view_get_line_yrange (text_view, &iter, &y, &height);
            
            g_array_append_val (buffer_coords, y);
            last_line_num = gtk_text_iter_get_line (&iter);
            g_array_append_val (numbers, last_line_num);
            
            ++count;
            
            if ((y + height) >= y2)
            break;
            
            gtk_text_iter_forward_line (&iter);
      }
      
      if (gtk_text_iter_is_end (&iter))
      {
            gint y, height;
            gint line_num;
            
            gtk_text_view_get_line_yrange (text_view, &iter, &y, &height);
            
            line_num = gtk_text_iter_get_line (&iter);
            
            if (line_num != last_line_num) {
                  g_array_append_val (buffer_coords, y);
                  g_array_append_val (numbers, line_num);
                  ++count;
            }
      }
      
      *countp = count;
}

static gint
line_numbers_expose (GtkWidget      *widget,
                     GdkEventExpose *event)
{
      GtkTextView *text_view;
      GdkWindow *win;
//    GtkStyle *style;
      PangoLayout *layout;
      PangoAttrList *alist;
      PangoAttribute *attr;
      GArray *numbers;
      GArray *pixels;
      gint y1, y2;
      gint count;
      gint layout_width;
      gint justify_width = 0;
      gint i;
//    gchar *str;
      gchar str [8];  /* we don't expect more than ten million lines */
      
      text_view = GTK_TEXT_VIEW (widget);
      
      /* See if this expose is on the line numbers window */
/*    left_win = gtk_text_view_get_window (text_view,
                                           GTK_TEXT_WINDOW_LEFT);
      right_win = gtk_text_view_get_window (text_view,
                                            GTK_TEXT_WINDOW_RIGHT);
      
      if (event->window == left_win)
      {
            type = GTK_TEXT_WINDOW_LEFT;
            target = event->window;
      }
      else if (event->window == right_win)
      {
            type = GTK_TEXT_WINDOW_RIGHT;
            target = right_win;
      }
      else
            return FALSE;
*/    
      win = gtk_text_view_get_window (text_view,
                                      GTK_TEXT_WINDOW_LEFT);
      if (event->window != win)
            return FALSE;
      
//    style = gtk_style_copy (widget->style);
//    style = gtk_style_copy (gtk_widget_get_default_style());
      
      y1 = event->area.y;
      y2 = y1 + event->area.height;
      
      gtk_text_view_window_to_buffer_coords (text_view,
                                             GTK_TEXT_WINDOW_LEFT,
                                             0,
                                             y1,
                                             NULL,
                                             &y1);
      
      gtk_text_view_window_to_buffer_coords (text_view,
                                             GTK_TEXT_WINDOW_LEFT,
                                             0,
                                             y2,
                                             NULL,
                                             &y2);
      
      numbers = g_array_new (FALSE, FALSE, sizeof (gint));
      pixels = g_array_new (FALSE, FALSE, sizeof (gint));
      
      get_lines (text_view,
                 y1,
                 y2,
                 pixels,
                 numbers,
                 &count);
      
      /* a zero-lined document should display a "1"; we don't need to worry about
      scrolling effects of the text widget in this special case */
      
      if (count == 0)
      {
            gint y = 0;
            gint n = 0;
            count = 1;
            g_array_append_val (pixels, y);
            g_array_append_val (numbers, n);
      }
      
DV({g_print("Painting line numbers %d - %d\n",
                  g_array_index(numbers, gint, 0),
                  g_array_index(numbers, gint, count - 1)); });
      
      layout = gtk_widget_create_pango_layout (widget, "");
      
//    str = g_strdup_printf ("%d", gtk_text_buffer_get_line_count(text_view->buffer));
      g_snprintf (str, sizeof (str),
                  "%d", MAX (99, gtk_text_buffer_get_line_count(text_view->buffer)));
      pango_layout_set_text (layout, str, -1);
//    g_free (str);
      
      pango_layout_get_pixel_size (layout, &layout_width, NULL);
      
      min_number_window_width = calculate_min_number_window_width(widget);
      if (layout_width > min_number_window_width)
            gtk_text_view_set_border_window_size (text_view,
                                                                    GTK_TEXT_WINDOW_LEFT,
                                                                    layout_width + margin);
      else {
//          if ((gtk_text_view_get_border_window_size (text_view, GTK_TEXT_WINDOW_LEFT) - 5) > layout_width) {
                  gtk_text_view_set_border_window_size (text_view,
                                                                          GTK_TEXT_WINDOW_LEFT,
                                                                          min_number_window_width + margin);
//          }
            justify_width = min_number_window_width - layout_width;
      }
      
      pango_layout_set_width (layout, layout_width);
      pango_layout_set_alignment (layout, PANGO_ALIGN_RIGHT);
      
      alist = pango_attr_list_new();
      attr = pango_attr_foreground_new(
            widget->style->text_aa->red,
            widget->style->text_aa->green,
            widget->style->text_aa->blue);
      attr->start_index = 0;
      attr->end_index = G_MAXUINT;
      pango_attr_list_insert(alist, attr);
      pango_layout_set_attributes(layout, alist);
      
      /* Draw fully internationalized numbers! */
      
      i = 0;
      while (i < count)
      {
            gint pos;
            
            gtk_text_view_buffer_to_window_coords (text_view,
                                                   GTK_TEXT_WINDOW_LEFT,
                                                   0,
                                                   g_array_index (pixels, gint, i),
                                                   NULL,
                                                   &pos);
            
//          str = g_strdup_printf ("%d", g_array_index (numbers, gint, i) + 1);
            g_snprintf (str, sizeof (str),
                        "%d", g_array_index (numbers, gint, i) + 1);
            
            pango_layout_set_text (layout, str, -1);
            
            gtk_paint_layout (widget->style,
                              win,
                              GTK_WIDGET_STATE (widget),
                              FALSE,
                              NULL,
                              widget,
                              NULL,
                              layout_width + justify_width + 1, pos,
                              layout);
//          g_free (str);
            
            ++i;
      }
      
      g_array_free (pixels, TRUE);
      g_array_free (numbers, TRUE);
      
      g_object_unref (G_OBJECT (layout));
//    g_object_ref (G_OBJECT (style));
      
      /* don't stop emission, need to draw children */
      return FALSE;
}

void show_line_numbers(GtkWidget *text_view, gboolean visible)
{
      if (visible) {
            min_number_window_width = calculate_min_number_window_width(text_view);
            gtk_text_view_set_border_window_size(
                  GTK_TEXT_VIEW(text_view),
                  GTK_TEXT_WINDOW_LEFT,
                  min_number_window_width + margin);
            g_signal_connect(
                  G_OBJECT(text_view),
                  "expose_event",
                  G_CALLBACK(line_numbers_expose),
                  NULL);
      } else {
            gtk_text_view_set_border_window_size(
                  GTK_TEXT_VIEW(text_view),
                  GTK_TEXT_WINDOW_LEFT,
                  0);
            g_signal_handlers_disconnect_by_func(
                  G_OBJECT(text_view),
                  G_CALLBACK(line_numbers_expose),
                  NULL);
      }
}

Generated by  Doxygen 1.6.0   Back to index