[Xfce4-commits] <mousepad:master> * mousepad/mousepad-view.c: Cleanup the line number code. This version is a bit faster and removed a bunch of code. * mousepad/mousepad-view.c: Cleanup the indentation code. You can also increase the (vertical) selected text with Shift + Space and decrease with Shift + Backspace. I though this might be useful for developers. * mousepad/mousepad-view.c: Vertical selection using the mouse and Ctrl + Shift. Keyboard vertical selection is not possible because that adds too much code for (hardly) nothing. You can (un-)indent the block with Tab, Shift + Tab and the 2 new space (in/de)crease commands above. * mousepad/mousepad-view.c: Draw a vertical line to separate the line numbers from the text, this looks beter with light themes (IMHO). * mousepad/mousepad-window.c: Add 'paste column' option to paste the clipboard text in a column under the cursor. * mousepad/mousepad-window.c: Set stock menu names to NULL so G tk fills the default (translated) name, makes your binary smaller and translators happy. * mousepad/mousepad-{search-bar, document}.c: Fix segfault with empty string in the search bar and highlighting enabled. * TODO: Add items.
Nick Schermer
noreply at xfce.org
Sat May 5 21:30:35 CEST 2012
Updating branch refs/heads/master
to 924ec4cfdac8ef8ad541d643f9789836bb3bd86c (commit)
from 4abd78f00bd8306fd7a8028875cb9050b62df53e (commit)
commit 924ec4cfdac8ef8ad541d643f9789836bb3bd86c
Author: Nick Schermer <nick at xfce.org>
Date: Thu May 17 20:00:53 2007 +0000
* mousepad/mousepad-view.c: Cleanup the line number code.
This version is a bit faster and removed a bunch of code.
* mousepad/mousepad-view.c: Cleanup the indentation code. You
can also increase the (vertical) selected text with Shift +
Space and decrease with Shift + Backspace. I though this
might be useful for developers.
* mousepad/mousepad-view.c: Vertical selection using the mouse
and Ctrl + Shift. Keyboard vertical selection is not possible
because that adds too much code for (hardly) nothing. You can
(un-)indent the block with Tab, Shift + Tab and the 2 new
space (in/de)crease commands above.
* mousepad/mousepad-view.c: Draw a vertical line to separate
the line numbers from the text, this looks beter with light
themes (IMHO).
* mousepad/mousepad-window.c: Add 'paste column' option to
paste the clipboard text in a column under the cursor.
* mousepad/mousepad-window.c: Set stock menu names to NULL so
Gtk fills the default (translated) name, makes your binary
smaller and translators happy.
* mousepad/mousepad-{search-bar,document}.c: Fix segfault with
empty string in the search bar and highlighting enabled.
* TODO: Add items.
(Old svn revision: 25720)
ChangeLog | 25 +
TODO | 9 +-
mousepad/mousepad-document.c | 41 ++-
mousepad/mousepad-document.h | 2 +
mousepad/mousepad-private.h | 4 +-
mousepad/mousepad-search-bar.c | 11 +-
mousepad/mousepad-view.c | 1156 +++++++++++++++++++++++++++------------
mousepad/mousepad-view.h | 13 +
mousepad/mousepad-window-ui.xml | 1 +
mousepad/mousepad-window.c | 60 ++-
10 files changed, 945 insertions(+), 377 deletions(-)
diff --git a/ChangeLog b/ChangeLog
index c5c1855..326ead6 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,28 @@
+2007-05-xx Nick Schermer <nick at xfce.org>
+ * mousepad/mousepad-view.c: Cleanup the line number code.
+ This version is a bit faster and removed a bunch of code.
+ * mousepad/mousepad-view.c: Cleanup the indentation code. You
+ can also increase the (vertical) selected text with Shift +
+ Space and decrease with Shift + Backspace. I though this
+ might be useful for developers.
+ * mousepad/mousepad-view.c: Vertical selection using the mouse
+ and Ctrl + Shift. Keyboard vertical selection is not possible
+ because that adds too much code for (hardly) nothing. You can
+ (un-)indent the block with Tab, Shift + Tab and the 2 new
+ space (in/de)crease commands above.
+ * mousepad/mousepad-view.c: Draw a vertical line to separate
+ the line numbers from the text, this looks beter with light
+ themes (IMHO).
+ * mousepad/mousepad-window.c: Add 'paste column' option to
+ paste the clipboard text in a column under the cursor.
+ * mousepad/mousepad-window.c: Set stock menu names to NULL so
+ Gtk fills the default (translated) name, makes your binary
+ smaller and translators happy.
+ * mousepad/mousepad-{search-bar,document}.c: Fix segfault with
+ empty string in the search bar and highlighting enabled.
+ * TODO: Add items.
+
+
2007-05-12 Nick Schermer <nick at xfce.org>
* mousepad/mousepad-window.c: Add extra tests if the file
really exists, because Gtk file dialogs hang if the
diff --git a/TODO b/TODO
index 8f30a10..b475bf5 100644
--- a/TODO
+++ b/TODO
@@ -19,6 +19,9 @@ Interface
- You can't use the Ctrl - v/c/x buttons in the type-ahead bar
because they are 'registered' by the textview/ui.
- When hitting the enter button in the jump dialog, we should jump.
+- Replace dialog. This dialog should also provide a find button so
+ there is an alternative for the type-ahead feature.
+- Maybe a match whole word option.
Code
@@ -30,9 +33,7 @@ Code
Text View
=========
-- Replace dialog. This dialog should also provide a find button so
- there is an alternative for the type-ahead feature.
-- Maybe a match whole word option.
+- Tabs as spaces option.
Undo Manager
@@ -42,6 +43,8 @@ Undo Manager
- We erase the GString in the undo manager, but this buffer will be
(very) large when a large bunch of text is deleted. Maybe not a big
problem, but we could shrink it after erasing.
+- Let the undo manager handle multiple steps (mostly for vertical
+ selection cut/delete).
Saving and loading
diff --git a/mousepad/mousepad-document.c b/mousepad/mousepad-document.c
index de38641..6c92296 100644
--- a/mousepad/mousepad-document.c
+++ b/mousepad/mousepad-document.c
@@ -907,7 +907,7 @@ mousepad_document_highlight_all (MousepadDocument *document,
gtk_text_buffer_remove_tag (document->buffer, document->tag, &doc_start, &doc_end);
/* highlight the new string */
- if (G_LIKELY (string != NULL))
+ if (G_LIKELY (string != NULL && *string != '\0'))
{
/* set the iter to the beginning of the document */
iter = doc_start;
@@ -937,12 +937,16 @@ void
mousepad_document_cut_selection (MousepadDocument *document)
{
GtkClipboard *clipboard;
+ MousepadView *view = MOUSEPAD_VIEW (document->textview);
/* get the clipboard */
clipboard = gtk_widget_get_clipboard (GTK_WIDGET (document->textview), GDK_SELECTION_CLIPBOARD);
/* cut the text */
- gtk_text_buffer_cut_clipboard (document->buffer, clipboard, gtk_text_view_get_editable (document->textview));
+ if (mousepad_view_get_vertical_selection (view))
+ mousepad_view_cut_clipboard (view, clipboard);
+ else
+ gtk_text_buffer_cut_clipboard (document->buffer, clipboard, gtk_text_view_get_editable (document->textview));
/* make sure the cursor is in the visible area */
mousepad_document_scroll_to_visible_area (document);
@@ -950,18 +954,20 @@ mousepad_document_cut_selection (MousepadDocument *document)
-
-
void
mousepad_document_copy_selection (MousepadDocument *document)
{
GtkClipboard *clipboard;
+ MousepadView *view = MOUSEPAD_VIEW (document->textview);
/* get the clipboard */
clipboard = gtk_widget_get_clipboard (GTK_WIDGET (document->textview), GDK_SELECTION_CLIPBOARD);
/* copy the selected text */
- gtk_text_buffer_copy_clipboard (document->buffer, clipboard);
+ if (mousepad_view_get_vertical_selection (view))
+ mousepad_view_copy_clipboard (view, clipboard);
+ else
+ gtk_text_buffer_copy_clipboard (document->buffer, clipboard);
}
@@ -984,10 +990,33 @@ mousepad_document_paste_clipboard (MousepadDocument *document)
void
+mousepad_document_paste_column_clipboard (MousepadDocument *document)
+{
+ GtkClipboard *clipboard;
+ MousepadView *view = MOUSEPAD_VIEW (document->textview);
+
+ /* get the clipboard */
+ clipboard = gtk_widget_get_clipboard (GTK_WIDGET (document->textview), GDK_SELECTION_CLIPBOARD);
+
+ /* past the clipboard text in a column */
+ mousepad_view_paste_column_clipboard (view, clipboard);
+
+ /* make sure the cursor is in the visible area */
+ mousepad_document_scroll_to_visible_area (document);
+}
+
+
+
+void
mousepad_document_delete_selection (MousepadDocument *document)
{
+ MousepadView *view = MOUSEPAD_VIEW (document->textview);
+
/* delete the selected text */
- gtk_text_buffer_delete_selection (document->buffer, TRUE, gtk_text_view_get_editable (document->textview));
+ if (mousepad_view_get_vertical_selection (view))
+ mousepad_view_delete_selection (view);
+ else
+ gtk_text_buffer_delete_selection (document->buffer, TRUE, gtk_text_view_get_editable (document->textview));
/* make sure the cursor is in the visible area */
mousepad_document_scroll_to_visible_area (document);
diff --git a/mousepad/mousepad-document.h b/mousepad/mousepad-document.h
index 28e01fa..019471e 100644
--- a/mousepad/mousepad-document.h
+++ b/mousepad/mousepad-document.h
@@ -85,6 +85,8 @@ void mousepad_document_copy_selection (MousepadDocument
void mousepad_document_paste_clipboard (MousepadDocument *document);
+void mousepad_document_paste_column_clipboard (MousepadDocument *document);
+
void mousepad_document_delete_selection (MousepadDocument *document);
void mousepad_document_select_all (MousepadDocument *document);
diff --git a/mousepad/mousepad-private.h b/mousepad/mousepad-private.h
index ce7fafe..3bb9a96 100644
--- a/mousepad/mousepad-private.h
+++ b/mousepad/mousepad-private.h
@@ -33,10 +33,10 @@ G_BEGIN_DECLS
GTimer *__FUNCTION__timer = g_timer_new();
#define TIMER_SPLIT \
- g_print ("%s (%d): %f\n", __FUNCTION__, __LINE__, g_timer_elapsed (__FUNCTION__timer, NULL));
+ g_print ("%s (%s:%d): %.2f ms\n", __FUNCTION__, __FILE__, __LINE__, g_timer_elapsed (__FUNCTION__timer, NULL) * 1000);
#define TIMER_STOP \
- g_print ("%s (%d): %f\n", __FUNCTION__, __LINE__, g_timer_elapsed (__FUNCTION__timer, NULL)); \
+ TIMER_SPLIT \
g_timer_destroy (__FUNCTION__timer);
#define PRINT_LINE g_print ("%d\n", __LINE__);
diff --git a/mousepad/mousepad-search-bar.c b/mousepad/mousepad-search-bar.c
index f9c3e05..2804684 100644
--- a/mousepad/mousepad-search-bar.c
+++ b/mousepad/mousepad-search-bar.c
@@ -518,14 +518,11 @@ mousepad_search_bar_highlight_timeout (gpointer user_data)
if (!search_bar->match_case)
flags |= MOUSEPAD_SEARCH_CASE_INSENSITIVE;
- /* get the string if highlighting is enabled */
+ /* set the entry string or a 0 string to remove the highlight */
if (search_bar->highlight_all)
- {
- /* get the entry string */
- string = gtk_entry_get_text (GTK_ENTRY (search_bar->entry));
- if (string == NULL || *string == '\0')
- string = NULL;
- }
+ string = gtk_entry_get_text (GTK_ENTRY (search_bar->entry));
+ else
+ string = "\0";
/* send the signal and wait for the result */
g_signal_emit (G_OBJECT (search_bar), search_bar_signals[HIGHLIGHT_ALL], 0,
diff --git a/mousepad/mousepad-view.c b/mousepad/mousepad-view.c
index 3ca086e..a00d8e6 100644
--- a/mousepad/mousepad-view.c
+++ b/mousepad/mousepad-view.c
@@ -32,24 +32,47 @@
-static void mousepad_view_class_init (MousepadViewClass *klass);
-static void mousepad_view_finalize (GObject *object);
-static gboolean mousepad_view_key_press_event (GtkWidget *widget,
- GdkEventKey *event);
-static void mousepad_view_indent_lines (MousepadView *view,
- GtkTextIter *start,
- GtkTextIter *end,
- gboolean indent);
-static gchar *mousepad_view_compute_indentation (MousepadView *view,
- GtkTextIter *iter);
-static gint mousepad_view_expose (GtkWidget *widget,
- GdkEventExpose *event);
-static void mousepad_view_get_lines (GtkTextView *text_view,
- gint first_y,
- gint last_y,
- GArray **pixels,
- GArray **numbers,
- gint *countp);
+/* we can assume there is a buffer for this view */
+#define mousepad_view_get_buffer(view) (GTK_TEXT_VIEW(view)->buffer)
+
+
+
+/* class functions */
+static void mousepad_view_class_init (MousepadViewClass *klass);
+static void mousepad_view_init (MousepadView *view);
+static void mousepad_view_finalize (GObject *object);
+static void mousepad_view_style_set (GtkWidget *widget,
+ GtkStyle *previous_style);
+static gint mousepad_view_expose (GtkWidget *widget,
+ GdkEventExpose *event);
+static gboolean mousepad_view_key_press_event (GtkWidget *widget,
+ GdkEventKey *event);
+static gboolean mousepad_view_button_press_event (GtkWidget *widget,
+ GdkEventButton *event);
+static gboolean mousepad_view_button_release_event (GtkWidget *widget,
+ GdkEventButton *event);
+
+/* vertical selection functions */
+static GArray *mousepad_view_vertical_selection_array (MousepadView *view,
+ gboolean forced);
+static gboolean mousepad_view_vertical_selection_timeout (gpointer user_data);
+static void mousepad_view_vertical_selection_reset (MousepadView *view);
+
+/* indentation functions */
+static void mousepad_view_indent_line (GtkTextBuffer *buffer,
+ GtkTextIter *iter,
+ gboolean increase,
+ gboolean tab);
+static gboolean mousepad_view_indent_lines (MousepadView *view,
+ gboolean indent,
+ gboolean tab);
+static gchar *mousepad_view_compute_indentation (GtkTextBuffer *buffer,
+ const GtkTextIter *iter);
+
+/* vertical selection edit handler */
+static void mousepad_view_handle_clipboard (MousepadView *view,
+ GtkClipboard *clipboard,
+ gboolean remove);
@@ -62,6 +85,19 @@ struct _MousepadView
{
GtkTextView __parent__;
+ /* coordinates for the vertical selection */
+ gint vertical_start_x, vertical_start_y;
+ gint vertical_end_x, vertical_end_y;
+
+ /* pointer array with all the vertical selection marks */
+ GPtrArray *marks;
+
+ /* vertical selection timeout id */
+ guint vertical_selection_id;
+
+ /* the selection tag */
+ GtkTextTag *tag;
+
/* settings */
guint auto_indent : 1;
guint line_numbers : 1;
@@ -85,7 +121,7 @@ mousepad_view_get_type (void)
sizeof (MousepadViewClass),
(GClassInitFunc) mousepad_view_class_init,
sizeof (MousepadView),
- NULL,
+ (GInstanceInitFunc) mousepad_view_init,
0);
}
@@ -106,8 +142,29 @@ mousepad_view_class_init (MousepadViewClass *klass)
gobject_class->finalize = mousepad_view_finalize;
widget_class = GTK_WIDGET_CLASS (klass);
- widget_class->key_press_event = mousepad_view_key_press_event;
- widget_class->expose_event = mousepad_view_expose;
+ widget_class->expose_event = mousepad_view_expose;
+ widget_class->style_set = mousepad_view_style_set;
+ widget_class->key_press_event = mousepad_view_key_press_event;
+ widget_class->button_press_event = mousepad_view_button_press_event;
+ widget_class->button_release_event = mousepad_view_button_release_event;
+}
+
+
+
+static void
+mousepad_view_init (MousepadView *view)
+{
+ /* initialize */
+ view->auto_indent = view->line_numbers = FALSE;
+
+ /* initialize */
+ view->marks = NULL;
+ view->tag = NULL;
+
+ /* initialize */
+ view->vertical_start_x = view->vertical_start_y =
+ view->vertical_end_x = view->vertical_end_y = -1;
+ view->vertical_selection_id = 0;
}
@@ -115,240 +172,668 @@ mousepad_view_class_init (MousepadViewClass *klass)
static void
mousepad_view_finalize (GObject *object)
{
+ MousepadView *view = MOUSEPAD_VIEW (object);
+
+ /* stop a pending vertical selection timeout */
+ if (G_UNLIKELY (view->vertical_selection_id != 0))
+ g_source_remove (view->vertical_selection_id);
+
+ /* free the marks array (we're not owning a ref on the marks) */
+ if (G_UNLIKELY (view->marks != NULL))
+ g_ptr_array_free (view->marks, TRUE);
+
(*G_OBJECT_CLASS (mousepad_view_parent_class)->finalize) (object);
}
-/**
- * mousepad_view_key_press_event:
- * @widget : A #GtkWidget.
- * @event : A #GdkEventKey
- *
- * This function is triggered when the user pressed a key in the
- * #MousepadView. It checks if we need to auto indent the new line
- * or when multiple lines are selected we (un)indent all of them.
- *
- * Return value: %TRUE if we handled the event, else we trigger the
- * parent class so Gtk can handle the event.
- **/
+static gboolean
+mousepad_view_expose (GtkWidget *widget,
+ GdkEventExpose *event)
+{
+ GdkWindow *window;
+ GtkTextView *text_view = GTK_TEXT_VIEW (widget);
+ gint y_top, y_offset, y_bottom;
+ gint y, height;
+ gint line_number = 0, line_count;
+ GtkTextIter iter;
+ gint width;
+ PangoLayout *layout;
+ gchar str[8]; /* maximum of 10e6 lines */
+
+ /* get the left window */
+ window = gtk_text_view_get_window (text_view, GTK_TEXT_WINDOW_LEFT);
+
+ /* check if the event if for the left window */
+ if (event->window == window)
+ {
+ /* get the real start position */
+ gtk_text_view_window_to_buffer_coords (text_view, GTK_TEXT_WINDOW_LEFT,
+ 0, event->area.y, NULL, &y_top);
+
+ /* get the bottom position */
+ y_bottom = y_top + event->area.height;
+
+ /* get the buffer offset (negative value or 0) */
+ y_offset = event->area.y - y_top;
+
+ /* get the start iter */
+ gtk_text_view_get_line_at_y (text_view, &iter, y_top, NULL);
+
+ /* get the number of lines in the buffer */
+ line_count = gtk_text_buffer_get_line_count (text_view->buffer);
+
+ /* string with the 'last' line number */
+ g_snprintf (str, sizeof (str), "%d", MAX (99, line_count));
+
+ /* create the pango layout */
+ layout = gtk_widget_create_pango_layout (widget, str);
+ pango_layout_get_pixel_size (layout, &width, NULL);
+ pango_layout_set_width (layout, width);
+ pango_layout_set_alignment (layout, PANGO_ALIGN_RIGHT);
+
+ /* set the width of the left window border */
+ gtk_text_view_set_border_window_size (text_view, GTK_TEXT_WINDOW_LEFT, width + 8);
+
+ /* draw a vertical line to separate the numbers and text */
+ gtk_paint_vline (widget->style, window,
+ GTK_WIDGET_STATE (widget),
+ NULL, widget, NULL,
+ event->area.y,
+ event->area.y + event->area.height,
+ width + 6);
+
+ /* walk through the lines until we hit the last line */
+ while (line_number < line_count)
+ {
+ /* get the y position and the height of the iter */
+ gtk_text_view_get_line_yrange (text_view, &iter, &y, &height);
+
+ /* include the buffer offset */
+ y += y_offset;
+
+ /* get the number of the line */
+ line_number = gtk_text_iter_get_line (&iter) + 1;
+
+ /* create the number */
+ g_snprintf (str, sizeof (str), "%d", line_number);
+
+ /* create the pange layout */
+ pango_layout_set_text (layout, str, strlen (str));
+
+ /* draw the layout on the left window */
+ gtk_paint_layout (widget->style, window,
+ GTK_WIDGET_STATE (widget),
+ FALSE, NULL, widget, NULL,
+ width + 2, y, layout);
+
+ /* stop when we reached the end of the expose area */
+ if ((y + height) >= y_bottom)
+ break;
+
+ /* jump to the next line */
+ gtk_text_iter_forward_line (&iter);
+ }
+
+ /* release the pango layout */
+ g_object_unref (G_OBJECT (layout));
+ }
+
+ /* Gtk can draw the text now */
+ return (*GTK_WIDGET_CLASS (mousepad_view_parent_class)->expose_event) (widget, event);
+}
+
+
+
+static void
+mousepad_view_style_set (GtkWidget *widget,
+ GtkStyle *previous_style)
+{
+ GtkStyle *style;
+ MousepadView *view = MOUSEPAD_VIEW (widget);
+
+ /* only set the style once, because we don't care to restart
+ * after a theme change */
+ if (view->tag == NULL && GTK_WIDGET_VISIBLE (widget))
+ {
+ /* get the textview style */
+ style = gtk_widget_get_style (widget);
+
+ /* create the selection tag */
+ view->tag = gtk_text_buffer_create_tag (mousepad_view_get_buffer (view), NULL,
+ "background-gdk", &style->base[GTK_STATE_SELECTED],
+ "foreground-gdk", &style->text[GTK_STATE_SELECTED],
+ NULL);
+ }
+
+ (*GTK_WIDGET_CLASS (mousepad_view_parent_class)->style_set) (widget, previous_style);
+}
+
+
+
static gboolean
mousepad_view_key_press_event (GtkWidget *widget,
GdkEventKey *event)
{
MousepadView *view = MOUSEPAD_VIEW (widget);
GtkTextBuffer *buffer;
- GtkTextIter start, end;
+ GtkTextIter start;
GtkTextMark *mark;
guint modifiers;
- guint key = event->keyval;
gchar *string;
- gboolean has_selection;
+ gboolean key_is_tab = FALSE;
- /* get the textview buffer */
- buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (widget));
+ /* get the modifiers state */
+ modifiers = event->state & gtk_accelerator_get_default_mod_mask ();
- /* check if we have to indent when the user pressed enter */
- if ((key == GDK_Return || key == GDK_KP_Enter)
- && !(event->state & GDK_SHIFT_MASK) && view->auto_indent)
+ /* handle the key event */
+ switch (event->keyval)
{
- /* get the iter */
- mark = gtk_text_buffer_get_insert (buffer);
- gtk_text_buffer_get_iter_at_mark (buffer, &start, mark);
+ case GDK_Return:
+ case GDK_KP_Enter:
+ if (!(event->state & GDK_SHIFT_MASK) && view->auto_indent)
+ {
+ /* get the textview buffer */
+ buffer = mousepad_view_get_buffer (view);
+
+ /* get the iter position of the cursor */
+ mark = gtk_text_buffer_get_insert (buffer);
+ gtk_text_buffer_get_iter_at_mark (buffer, &start, mark);
+
+ /* get the string of tabs and spaces we're going to indent */
+ string = mousepad_view_compute_indentation (buffer, &start);
+
+ if (string != NULL)
+ {
+ /* insert the indent characters */
+ gtk_text_buffer_insert (buffer, &start, "\n", 1);
+ gtk_text_buffer_insert (buffer, &start, string, strlen (string));
+
+ /* cleanup */
+ g_free (string);
+
+ /* make sure the new string is visible for the user */
+ gtk_text_view_scroll_mark_onscreen (GTK_TEXT_VIEW (widget), mark);
+
+ /* we inserted the new line, nothing to do for gtk */
+ return TRUE;
+ }
+ }
+ break;
- /* get the string of tabs and spaces we're going to indent */
- string = mousepad_view_compute_indentation (view, &start);
+ case GDK_Tab:
+ case GDK_KP_Tab:
+ case GDK_ISO_Left_Tab:
+ /* indent a tab when no modifiers are pressed, else fall-through */
+ if (modifiers == 0 &&
+ mousepad_view_indent_lines (view, TRUE, TRUE))
+ return TRUE;
- if (string != NULL)
- {
- /* tell others we're going to change the buffer */
- gtk_text_buffer_begin_user_action (buffer);
+ /* a tab was pressed */
+ key_is_tab = TRUE;
- /* insert the indent characters */
- gtk_text_buffer_insert (buffer, &start, "\n", 1);
- gtk_text_buffer_insert (buffer, &start, string, strlen (string));
- g_free (string);
+ case GDK_BackSpace:
+ case GDK_space:
+ /* indent on Space unindent on Backspace or Tab */
+ if (modifiers == GDK_SHIFT_MASK &&
+ mousepad_view_indent_lines (view, (event->keyval == GDK_space), key_is_tab))
+ return TRUE;
+ break;
+ }
- /* we're finished */
- gtk_text_buffer_end_user_action (buffer);
+ /* reset the vertical selection */
+ if (G_UNLIKELY (view->marks != NULL && !event->is_modifier))
+ mousepad_view_vertical_selection_reset (view);
- /* make sure the new string is visible for the user */
- gtk_text_view_scroll_mark_onscreen (GTK_TEXT_VIEW (widget), mark);
+ return (*GTK_WIDGET_CLASS (mousepad_view_parent_class)->key_press_event) (widget, event);
+}
- return TRUE;
- }
+
+
+static gboolean
+mousepad_view_button_press_event (GtkWidget *widget,
+ GdkEventButton *event)
+{
+ MousepadView *view = MOUSEPAD_VIEW (widget);
+ GtkTextView *text_view;
+
+ /* cleanup the marks if needed */
+ if (G_UNLIKELY (view->marks != NULL))
+ {
+ /* reset the vertical selection */
+ mousepad_view_vertical_selection_reset (view);
}
- /* get the modifiers state */
- modifiers = gtk_accelerator_get_default_mod_mask ();
+ /* Shift + Ctrl + Button 1 are pressed */
+ if (G_UNLIKELY (event->type == GDK_BUTTON_PRESS
+ && event->button == 1
+ && (event->state & GDK_CONTROL_MASK)
+ && (event->state & GDK_SHIFT_MASK)
+ && event->x >= 0
+ && event->y >= 0))
+ {
+ /* get the textview */
+ text_view = GTK_TEXT_VIEW (widget);
+
+ /* set the vertical selection start position, inclusing textview offset */
+ view->vertical_start_x = event->x + text_view->xoffset;
+ view->vertical_start_y = event->y + text_view->yoffset;
+
+ /* start a vertical selection timeout */
+ view->vertical_selection_id = g_timeout_add (75, mousepad_view_vertical_selection_timeout, view);
+
+ return TRUE;
+ }
+
+ return (*GTK_WIDGET_CLASS (mousepad_view_parent_class)->button_press_event) (widget, event);
+}
+
+
- /* check if the user pressed the tab button for indenting lines */
- if ((key == GDK_Tab || key == GDK_KP_Tab || key == GDK_ISO_Left_Tab)
- && ((event->state & modifiers) == 0 || (event->state & modifiers) == GDK_SHIFT_MASK))
+static gboolean
+mousepad_view_button_release_event (GtkWidget *widget,
+ GdkEventButton *event)
+{
+ MousepadView *view = MOUSEPAD_VIEW (widget);
+ GArray *array;
+ gint i;
+ GtkTextBuffer *buffer;
+ GtkTextIter iter;
+ GtkTextMark *mark;
+
+ _mousepad_return_val_if_fail (view->marks == NULL, TRUE);
+
+ /* end of a vertical selection */
+ if (G_UNLIKELY (view->vertical_start_x != -1
+ && event->button == 1))
+ {
+ /* stop the timeout */
+ g_source_remove (view->vertical_selection_id);
+ view->vertical_selection_id = 0;
+
+ /* get the array */
+ array = mousepad_view_vertical_selection_array (view, TRUE);
+
+ if (G_LIKELY (array != NULL))
{
- /* get the selected text */
- has_selection = gtk_text_buffer_get_selection_bounds (buffer, &start, &end);
+ /* get the buffer */
+ buffer = mousepad_view_get_buffer (view);
+
+ /* allocate the array */
+ view->marks = g_ptr_array_sized_new (array->len);
- /* shift + tab */
- if (event->state & GDK_SHIFT_MASK)
+ /* walk though the iters in the array */
+ for (i = 0; i < array->len; i++)
{
- /* unindent */
- mousepad_view_indent_lines (view, &start, &end, FALSE);
+ /* get the iter from the array */
+ iter = g_array_index (array, GtkTextIter, i);
- return TRUE;
+ /* create the mark */
+ mark = gtk_text_buffer_create_mark (buffer, NULL, &iter, FALSE);
+
+ /* append the mark to the array */
+ g_ptr_array_add (view->marks, mark);
}
- if (has_selection &&
- ((gtk_text_iter_starts_line (&start) && gtk_text_iter_ends_line (&end)) ||
- (gtk_text_iter_get_line (&start) != gtk_text_iter_get_line (&end))))
- {
- /* indent */
- mousepad_view_indent_lines (view, &start, &end, TRUE);
+ /* free the array */
+ g_array_free (array, TRUE);
- return TRUE;
- }
+ /* notify the has-selection signal */
+ buffer->has_selection = TRUE;
+ g_object_notify (G_OBJECT (buffer), "has-selection");
}
- return (*GTK_WIDGET_CLASS (mousepad_view_parent_class)->key_press_event) (widget, event);
+ return TRUE;
+ }
+
+ return (*GTK_WIDGET_CLASS (mousepad_view_parent_class)->button_release_event) (widget, event);
}
/**
- * mousepad_view_indent_lines:
- * @view : A #MousepadView
- * @start : The start #GtkTextIter of the selection.
- * @end : The end #GtkTextIter of the selection
- * @indent : Whether we need to indent or unindent the
- * selected lines.
- *
- * This function (un)indents the selected lines. It simply walks
- * from the start line number to the end line number and prepends
- * or removed a tab (or the tab width in spaces).
+ * Vertical Selection Functions
**/
+static GArray *
+mousepad_view_vertical_selection_array (MousepadView *view,
+ gboolean forced)
+{
+ gint x, y, i;
+ gint start_y, end_y, height;
+ GArray *array = NULL;
+ GtkTextIter start, end;
+ GtkTextView *text_view = GTK_TEXT_VIEW (view);
+
+ /* leave when there is no start coordinate */
+ if (G_UNLIKELY (view->vertical_start_x == -1))
+ return NULL;
+
+ /* get the cursor position */
+ gdk_window_get_pointer (gtk_text_view_get_window (text_view, GTK_TEXT_WINDOW_TEXT),
+ &x, &y, NULL);
+
+ /* no negative values, that sucks */
+ if (G_LIKELY (x >= 0 && y >= 0))
+ {
+ /* get the buffer coordinates */
+ x += text_view->xoffset;
+ y += text_view->yoffset;
+
+ /* quick check if we need to update the selection */
+ if (G_LIKELY (forced || view->vertical_end_x != x || view->vertical_end_y != y))
+ {
+ /* update the end coordinates */
+ view->vertical_end_x = x;
+ view->vertical_end_y = y;
+
+ /* get the start and end iter */
+ gtk_text_view_get_iter_at_location (text_view, &start, 0, view->vertical_start_y);
+ gtk_text_view_get_iter_at_location (text_view, &end, 0, view->vertical_end_y);
+
+ /* make sure the start iter is before the end iter */
+ gtk_text_iter_order (&start, &end);
+
+ /* get the start and end location in pixels */
+ gtk_text_view_get_line_yrange (text_view, &start, &start_y, &height);
+ gtk_text_view_get_line_yrange (text_view, &end, &end_y, NULL);
+
+ /* allocate a sized array to avoid reallocation (array might be too big if there are equal iters) */
+ array = g_array_sized_new (FALSE, FALSE, sizeof (GtkTextIter), (end_y - start_y) / height * 2);
+
+ /* make sure atleast one line is selected */
+ end_y += height;
+
+ /* walk through the selected lines */
+ for (i = start_y; i < end_y; i += height)
+ {
+ /* get the begin and end iter */
+ gtk_text_view_get_iter_at_location (text_view, &start, view->vertical_start_x, i);
+ gtk_text_view_get_iter_at_location (text_view, &end, view->vertical_end_x, i);
+
+ /* continue when the iters are the same */
+ if (gtk_text_iter_equal (&start, &end))
+ continue;
+
+ /* make sure the iters are in the correct order */
+ gtk_text_iter_order (&start, &end);
+
+ /* append the iters to the array */
+ g_array_append_val (array, start);
+ g_array_append_val (array, end);
+ }
+ }
+ }
+
+ return array;
+}
+
+
+static gboolean
+mousepad_view_vertical_selection_timeout (gpointer user_data)
+{
+ gint i;
+ GArray *array;
+ GtkTextIter start, end;
+ GtkTextBuffer *buffer;
+ MousepadView *view = MOUSEPAD_VIEW (user_data);
+
+ GDK_THREADS_ENTER ();
+
+ /* get the iters array */
+ array = mousepad_view_vertical_selection_array (view, FALSE);
+
+ /* update the selection highlight */
+ if (array != NULL)
+ {
+ /* get the buffer */
+ buffer = mousepad_view_get_buffer (user_data);
+
+ /* remove the old highlight */
+ gtk_text_buffer_get_bounds (buffer, &start, &end);
+ gtk_text_buffer_remove_tag (buffer, view->tag, &start, &end);
+
+ /* walk though the iters in the array */
+ for (i = 0; i < array->len; i += 2)
+ {
+ /* get the iters from the array */
+ start = g_array_index (array, GtkTextIter, i);
+ end = g_array_index (array, GtkTextIter, i + 1);
+
+ /* highlight the text between the iters */
+ gtk_text_buffer_apply_tag (buffer, view->tag, &start, &end);
+ }
+
+ /* free the array */
+ g_array_free (array, TRUE);
+
+ /* set the cursor below the pointer */
+ gtk_text_view_get_iter_at_location (GTK_TEXT_VIEW (view), &end, view->vertical_end_x, view->vertical_end_y);
+ gtk_text_buffer_place_cursor (buffer, &end);
+ }
+
+ GDK_THREADS_LEAVE ();
+
+ /* keep the timeout running */
+ return TRUE;
+}
+
+
+
static void
-mousepad_view_indent_lines (MousepadView *view,
- GtkTextIter *start,
- GtkTextIter *end,
- gboolean indent)
+mousepad_view_vertical_selection_reset (MousepadView *view)
{
+ GtkTextIter start, end;
GtkTextBuffer *buffer;
- GtkTextIter iter, iter2;
- gint start_line, end_line;
- gint i, spaces, tabs;
+ gint i;
- /* get the textview buffer */
- buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (view));
+ _mousepad_return_if_fail (view->marks != NULL);
- /* get the line numbers for the start and end iter */
- start_line = gtk_text_iter_get_line (start);
- end_line = gtk_text_iter_get_line (end);
+ /* get the buffer */
+ buffer = mousepad_view_get_buffer (view);
- /* check if the last line does not exist of 'invisible' characters */
- if ((gtk_text_iter_get_visible_line_offset (end) == 0) && (end_line > start_line))
- end_line--;
+ buffer->has_selection = FALSE;
+ g_object_notify (G_OBJECT (buffer), "has-selection");
- /* tell everybody we're going to change the buffer */
- gtk_text_buffer_begin_user_action (buffer);
+ /* remove the selections */
+ gtk_text_buffer_get_bounds (buffer, &start, &end);
+ gtk_text_buffer_remove_tag (buffer, view->tag, &start, &end);
- /* insert a tab in front of each line */
- for (i = start_line; i <= end_line; i++)
- {
- /* get the iter of the line we're going to indent */
- gtk_text_buffer_get_iter_at_line (buffer, &iter, i);
+ /* reset the coordinates */
+ view->vertical_start_x = view->vertical_start_y =
+ view->vertical_end_x = view->vertical_end_y = -1;
+
+ /* delete all the marks in the buffer */
+ for (i = 0; i < view->marks->len; i++)
+ gtk_text_buffer_delete_mark (buffer, g_ptr_array_index (view->marks, i));
+
+ /* cleanup */
+ g_ptr_array_free (view->marks, TRUE);
+ view->marks = NULL;
+}
+
+
+/**
+ * Indentation Functions
+ **/
+static void
+mousepad_view_indent_line (GtkTextBuffer *buffer,
+ GtkTextIter *iter,
+ gboolean increase,
+ gboolean tab)
+{
+ GtkTextIter end;
+ gint spaces;
- /* don't (un)indent empty lines */
- if (gtk_text_iter_ends_line (&iter))
- continue;
+ /* increase the indentation */
+ if (increase)
+ {
+ /* insert the tab or a space */
+ gtk_text_buffer_insert (buffer, iter, tab ? "\t" : " ", -1);
+ }
+ else /* decrease the indentation */
+ {
+ /* set the end iter */
+ end = *iter;
- if (indent)
+ /* remove a tab */
+ if (tab && gtk_text_iter_get_char (iter) == '\t')
{
- /* insert the tab */
- gtk_text_buffer_insert (buffer, &iter, "\t", -1);
+ /* get the iter after the tab */
+ gtk_text_iter_forward_char (&end);
+
+ /* remove the tab */
+ gtk_text_buffer_delete (buffer, iter, &end);
}
- else /* unindent */
+ /* remove a space */
+ else if (gtk_text_iter_get_char (iter) == ' ')
{
- if (gtk_text_iter_get_char (&iter) == '\t')
+ /* (re)set the number of spaces */
+ spaces = tab ? 0 : 1;
+
+ /* count the number of spaces before the text (when unindenting tabs) */
+ while (tab && !gtk_text_iter_ends_line (&end))
{
- /* remove the tab */
- iter2 = iter;
- gtk_text_iter_forward_char (&iter2);
- gtk_text_buffer_delete (buffer, &iter, &iter2);
+ if (gtk_text_iter_get_char (&end) == ' ')
+ spaces++;
+ else
+ break;
+
+ gtk_text_iter_forward_char (&end);
}
- else if (gtk_text_iter_get_char (&iter) == ' ')
- {
- spaces = 0;
- iter2 = iter;
+ /* delete the spaces */
+ if (spaces > 0)
+ {
+ /* reset the end iter */
+ end = *iter;
- /* count the number of spaces before the text */
- while (!gtk_text_iter_ends_line (&iter2))
+ /* correct the number of spaces for matching tabs */
+ if (tab)
{
- if (gtk_text_iter_get_char (&iter2) == ' ')
- spaces++;
- else
- break;
+ /* the number of spaces we need to remove to be inlign with the tabs */
+ spaces = spaces - (spaces / 8) * 8;
- gtk_text_iter_forward_char (&iter2);
+ /* we're inlign with the tabs, remove 8 spaces */
+ if (spaces == 0)
+ spaces = 8;
}
- if (spaces > 0)
- {
- /* the number of tabs in the spaces */
- tabs = spaces / 8;
+ /* delete the spaces */
+ gtk_text_iter_forward_chars (&end, spaces);
+ gtk_text_buffer_delete (buffer, iter, &end);
+ }
+ }
+ }
+}
- /* the number of spaces after the 'tabs' */
- spaces = spaces - (tabs * 8);
- /* we're going to remove the number of spaces after the 'tabs'
- * or 1 'tab' */
- if (spaces == 0)
- spaces = 8;
- iter2 = iter;
+static gboolean
+mousepad_view_indent_lines (MousepadView *view,
+ gboolean increase,
+ gboolean tab)
+{
+ GtkTextBuffer *buffer;
+ gint start_line, end_line;
+ gint i;
+ GtkTextIter start, end, needle;
+ GtkTextMark *mark;
+ gboolean succeed = FALSE;
+
+ /* get the textview buffer */
+ buffer = mousepad_view_get_buffer (view);
- /* delete the spaces */
- gtk_text_iter_forward_chars (&iter2, spaces);
- gtk_text_buffer_delete (buffer, &iter, &iter2);
+ /* if we have a vertical selection, we're not handling that here */
+ if (view->vertical_start_x != -1)
+ {
+ /* walk through the start marks (hence the +2) */
+ for (i = 0; i < view->marks->len; i += 2)
+ {
+ /* get the mark */
+ mark = g_ptr_array_index (view->marks, i);
+
+ /* get the iter at this mark */
+ gtk_text_buffer_get_iter_at_mark (buffer, &start, mark);
+
+ /* first move the iter when we're going to indent */
+ if (!increase)
+ {
+ /* sync the iters */
+ needle = end = start;
+
+ /* walk backwards till we hit text */
+ while (gtk_text_iter_backward_char (&needle)
+ && !gtk_text_iter_starts_line (&needle))
+ {
+ if ((gtk_text_iter_get_char (&needle) == ' ' && !tab)
+ || (gtk_text_iter_get_char (&needle) == '\t' && tab))
+ end = needle;
+ else
+ break;
}
+
+ /* continue if the old and new iter are the same, this makes sure
+ * we don't indent spaces in the block */
+ if (gtk_text_iter_equal (&start, &end))
+ continue;
+
+ /* set the new start iter */
+ start = end;
}
+
+ /* (de/in)crease the line the line with a tab or a space */
+ mousepad_view_indent_line (buffer, &start, increase, tab);
}
+
+ succeed = TRUE;
}
- /* we're done */
- gtk_text_buffer_end_user_action (buffer);
+ if (gtk_text_buffer_get_selection_bounds (buffer, &start, &end))
+ {
+ /* only indent when the entire line or multiple lines are selected */
+ if (increase
+ && !(gtk_text_iter_starts_line (&start) && gtk_text_iter_ends_line (&end))
+ && (gtk_text_iter_get_line (&start) == gtk_text_iter_get_line (&end)))
+ goto failed;
+
+ /* get the line numbers for the start and end iter */
+ start_line = gtk_text_iter_get_line (&start);
+ end_line = gtk_text_iter_get_line (&end);
+
+ /* insert a tab in front of each line */
+ for (i = start_line; i <= end_line; i++)
+ {
+ /* get the iter of the line we're going to indent */
+ gtk_text_buffer_get_iter_at_line (buffer, &start, i);
+
+ /* don't (un)indent empty lines */
+ if (gtk_text_iter_ends_line (&start))
+ continue;
+
+ /* change the indentation of this line */
+ mousepad_view_indent_line (buffer, &start, increase, tab);
+ }
+
+ succeed = TRUE;
+ }
+failed:
/* scroll */
gtk_text_view_scroll_mark_onscreen (GTK_TEXT_VIEW (view),
gtk_text_buffer_get_insert (buffer));
+
+ return succeed;
}
-/**
- * mousepad_view_compute_indentation:
- * @view : A #MousepadView.
- * @iter : The #GtkTextIter of the previous line.
- *
- * This function is used to get the tabs and spaces we need to
- * append when auto indentation is enabled. If scans the line of
- * @iter and returns a slice of the tabs and spaces before the
- * first character or line end.
- *
- * Return value: A string of tabs and spaces or %NULL when the
- * previous line has no tabs or spaces before the text.
- **/
static gchar *
-mousepad_view_compute_indentation (MousepadView *view,
- GtkTextIter *iter)
+mousepad_view_compute_indentation (GtkTextBuffer *buffer,
+ const GtkTextIter *iter)
{
- GtkTextBuffer *buffer;
- GtkTextIter start, end;
- gint line;
- gunichar ch;
-
- /* get the buffer */
- buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (view));
+ GtkTextIter start, end;
+ gint line;
+ gunichar ch;
/* get the line of the iter */
line = gtk_text_iter_get_line (iter);
@@ -356,16 +841,17 @@ mousepad_view_compute_indentation (MousepadView *view,
/* get the iter of the beginning of this line */
gtk_text_buffer_get_iter_at_line (buffer, &start, line);
- /* clone baby */
+ /* set the end iter */
end = start;
/* get the first character */
ch = gtk_text_iter_get_char (&end);
/* keep walking till we hit text or a new line */
- while (g_unichar_isspace (ch) &&
- (ch != '\n') && (ch != '\r') &&
- (gtk_text_iter_compare (&end, iter) < 0))
+ while (g_unichar_isspace (ch)
+ && ch != '\n'
+ && ch != '\r'
+ && gtk_text_iter_compare (&end, iter) < 0)
{
/* break if we can't step forward */
if (!gtk_text_iter_forward_char (&end))
@@ -385,204 +871,202 @@ mousepad_view_compute_indentation (MousepadView *view,
-/**
- * mousepad_view_get_lines:
- * @text_view : A #GtkTextView
- * @first_y : The first y location of the visible #GtkTextView window.
- * @last_y : The last y location of the visible #GtkTextView window.
- * @pixels : Return location for the #GArray with the y location
- * in pixels we need to draw line numbers.
- * @numbers : Return location for the #GArray with all the visible
- * line numbers.
- * @countp : Return location for the number of lines visible between
- * @first_y and @last_y.
- *
- * This function returns two arrays with the lines number and there draw
- * location of the visible text view window.
- **/
static void
-mousepad_view_get_lines (GtkTextView *text_view,
- gint first_y,
- gint last_y,
- GArray **pixels,
- GArray **numbers,
- gint *countp)
+mousepad_view_handle_clipboard (MousepadView *view,
+ GtkClipboard *clipboard,
+ gboolean remove)
{
- GtkTextIter iter;
- gint count = 0;
- gint y, height;
- gint line_number = 0, last_line_number;
+ GString *string;
+ gint i;
+ gint ln, previous_ln;
+ gchar *slice;
+ GtkTextBuffer *buffer;
+ GtkTextMark *mark_start, *mark_end;
+ GtkTextIter iter_start, iter_end;
- g_array_set_size (*pixels, 0);
- g_array_set_size (*numbers, 0);
+ /* get the buffer */
+ buffer = mousepad_view_get_buffer (view);
- /* get iter at first y */
- gtk_text_view_get_line_at_y (text_view, &iter, first_y, NULL);
+ /* create a new string */
+ if (G_LIKELY (clipboard))
+ string = g_string_new (NULL);
- /* for each iter, get its location and add it to the arrays.
- * stop when we pass last_y */
- while (!gtk_text_iter_is_end (&iter))
+ /* walk through the marks */
+ for (i = 0; i < view->marks->len; i += 2)
{
- /* get the y position of the iter */
- gtk_text_view_get_line_yrange (text_view, &iter, &y, &height);
+ /* get the marks */
+ mark_start = g_ptr_array_index (view->marks, i);
+ mark_end = g_ptr_array_index (view->marks, i + 1);
- /* get the number of the line */
- line_number = gtk_text_iter_get_line (&iter);
+ /* and their iter positions */
+ gtk_text_buffer_get_iter_at_mark (buffer, &iter_start, mark_start);
+ gtk_text_buffer_get_iter_at_mark (buffer, &iter_end, mark_end);
- /* append both values to the array */
- g_array_append_val (*pixels, y);
- g_array_append_val (*numbers, line_number);
+ /* only handle the selection when there is clipbaord */
+ if (G_LIKELY (clipboard))
+ {
+ /* the line number of the iter */
+ ln = gtk_text_iter_get_line (&iter_start);
- ++count;
+ /* fix the number of new lines between the parts */
+ if (i == 0)
+ previous_ln = ln;
+ else
+ for (; previous_ln < ln; previous_ln++)
+ string = g_string_append_c (string, '\n');
- /* stop when we reached last_y */
- if ((y + height) >= last_y)
- break;
+ /* get the text slice */
+ slice = gtk_text_buffer_get_slice (buffer, &iter_start, &iter_end, TRUE);
- /* jump to the next line */
- gtk_text_iter_forward_line (&iter);
- }
+ /* append the slice to the string */
+ string = g_string_append (string, slice);
- if (gtk_text_iter_is_end (&iter))
- {
- gtk_text_view_get_line_yrange (text_view, &iter, &y, &height);
-
- last_line_number = gtk_text_iter_get_line (&iter);
-
- if (last_line_number != line_number)
- {
- g_array_append_val (*pixels, y);
- g_array_append_val (*numbers, last_line_number);
- ++count;
+ /* cleanup */
+ g_free (slice);
}
+
+ /* delete the text between the iters if requested */
+ if (remove)
+ gtk_text_buffer_delete (buffer, &iter_start, &iter_end);
}
- /* not lines in the buffer? weird, there is atleast one... */
- if (G_UNLIKELY (count == 0))
+ /* set the clipboard text */
+ if (G_LIKELY (clipboard))
{
- y = 0;
- g_array_append_val (*pixels, y);
- g_array_append_val (*numbers, y);
+ /* set the clipboard text */
+ gtk_clipboard_set_text (clipboard, string->str, string->len);
- ++count;
+ /* free the string */
+ g_string_free (string, TRUE);
}
+}
- *countp = count;
+
+
+gboolean
+mousepad_view_get_vertical_selection (MousepadView *view)
+{
+ _mousepad_return_val_if_fail (MOUSEPAD_IS_VIEW (view), FALSE);
+
+ return (view->marks != NULL);
}
-/**
- * mousepad_view_expose:
- * @widget : A textview widget.
- * @event : A #GdkEventExpose event.
- *
- * This function draws the line numbers in the GTK_TEXT_WINDOW_LEFT window
- * when it receives an expose event. At the end of the function we always
- * return the expose_event of the parent class so Gtk can draw the text.
- *
- * Return value: The return value of the parent_class.
- **/
-static gboolean
-mousepad_view_expose (GtkWidget *widget,
- GdkEventExpose *event)
+void
+mousepad_view_cut_clipboard (MousepadView *view,
+ GtkClipboard *clipboard)
{
- GdkWindow *window;
- GtkTextView *view = GTK_TEXT_VIEW (widget);
- gint y1, y2;
- GArray *numbers, *pixels;
- gint count, i;
- PangoLayout *layout;
- gchar str[8]; /* maximum of 10e6 lines */
- gint width;
- gint position;
- gint line_number;
+ _mousepad_return_if_fail (MOUSEPAD_IS_VIEW (view));
+ _mousepad_return_if_fail (view->marks != NULL);
+ _mousepad_return_if_fail (GTK_IS_CLIPBOARD (clipboard));
- /* get the left window */
- window = gtk_text_view_get_window (view, GTK_TEXT_WINDOW_LEFT);
+ /* call the clipboard function with remove bool */
+ mousepad_view_handle_clipboard (view, clipboard, TRUE);
- /* check if the event if for the left window */
- if (event->window == window)
+ /* cleanup the vertical selection */
+ mousepad_view_vertical_selection_reset (view);
+}
+
+
+
+void
+mousepad_view_copy_clipboard (MousepadView *view,
+ GtkClipboard *clipboard)
+{
+ _mousepad_return_if_fail (MOUSEPAD_IS_VIEW (view));
+ _mousepad_return_if_fail (view->marks != NULL);
+ _mousepad_return_if_fail (GTK_IS_CLIPBOARD (clipboard));
+
+ /* call the clipboard function without remove bool */
+ mousepad_view_handle_clipboard (view, clipboard, FALSE);
+}
+
+
+
+void
+mousepad_view_paste_column_clipboard (MousepadView *view,
+ GtkClipboard *clipboard)
+{
+ _mousepad_return_if_fail (MOUSEPAD_IS_VIEW (view));
+ _mousepad_return_if_fail (GTK_IS_CLIPBOARD (clipboard));
+
+ GtkTextMark *mark;
+ GtkTextIter iter;
+ GtkTextBuffer *buffer;
+ GtkTextView *text_view;
+ gchar *string, **pieces;
+ gint i, y;
+ GdkRectangle rect;
+
+ /* get the text buffer */
+ buffer = mousepad_view_get_buffer (view);
+ text_view = GTK_TEXT_VIEW (view);
+
+ /* get the clipboard text */
+ string = gtk_clipboard_wait_for_text (clipboard);
+
+ if (G_LIKELY (string != NULL))
{
- /* get the expose event area */
- y1 = event->area.y;
- y2 = y1 + event->area.height;
-
- /* correct then to the size of the textview window */
- gtk_text_view_window_to_buffer_coords (view, GTK_TEXT_WINDOW_LEFT,
- 0, y1, NULL, &y1);
- gtk_text_view_window_to_buffer_coords (view, GTK_TEXT_WINDOW_LEFT,
- 0, y2, NULL, &y2);
-
- /* create new arrays */
- pixels = g_array_new (FALSE, FALSE, sizeof (gint));
- numbers = g_array_new (FALSE, FALSE, sizeof (gint));
-
- /* get the line numbers and y coordinates. */
- mousepad_view_get_lines (view,
- y1, y2,
- &pixels,
- &numbers,
- &count);
+ /* chop the string into pieces */
+ pieces = g_strsplit (string, "\n", -1);
- /* create the pango layout */
- g_snprintf (str, sizeof (str), "%d",
- MAX (99, gtk_text_buffer_get_line_count (view->buffer)));
- layout = gtk_widget_create_pango_layout (widget, str);
- pango_layout_get_pixel_size (layout, &width, NULL);
- pango_layout_set_width (layout, width);
- pango_layout_set_alignment (layout, PANGO_ALIGN_RIGHT);
+ /* cleanup */
+ g_free (string);
- /* set the width of the left window border */
- gtk_text_view_set_border_window_size (view, GTK_TEXT_WINDOW_LEFT,
- width + 6);
+ /* get the iter are the cursor position */
+ mark = gtk_text_buffer_get_insert (buffer);
+ gtk_text_buffer_get_iter_at_mark (buffer, &iter, mark);
- for (i = 0; i < count; i++)
+ /* get the buffer location */
+ gtk_text_view_get_iter_location (text_view, &iter, &rect);
+
+ /* insert the pieces in the buffer */
+ for (i = 0; pieces[i] != NULL; i++)
{
- gtk_text_view_buffer_to_window_coords (view,
- GTK_TEXT_WINDOW_LEFT, 0,
- g_array_index (pixels, gint, i),
- NULL,
- &position);
+ /* insert the text in the buffer */
+ gtk_text_buffer_insert (buffer, &iter, pieces[i], -1);
- /* get the line number */
- line_number = g_array_index (numbers, gint, i) + 1;
+ /* don't try to add a new line if we reached the end of the array */
+ if (G_UNLIKELY (pieces[i+1] == NULL))
+ break;
- /* create the pango layout */
- g_snprintf (str, sizeof (str), "%d", line_number);
- pango_layout_set_markup (layout, str, strlen (str));
+ /* move the iter to the next line and add a new line if needed */
+ if (!gtk_text_iter_forward_line (&iter))
+ gtk_text_buffer_insert (buffer, &iter, "\n", 1);
- /* time to draw the layout in the window */
- gtk_paint_layout (widget->style, window,
- GTK_WIDGET_STATE (widget),
- FALSE, NULL,
- widget, NULL,
- width + 2,
- position,
- layout);
+ /* get the y coordinate for this line */
+ gtk_text_view_get_line_yrange (text_view, &iter, &y, NULL);
+
+ /* get the iter at the y location of this line and the same x as the cursor */
+ gtk_text_view_get_iter_at_location (text_view, &iter, rect.x, y);
}
/* cleanup */
- g_array_free (pixels, TRUE);
- g_array_free (numbers, TRUE);
+ g_strfreev (pieces);
- g_object_unref (G_OBJECT (layout));
+ /* set the cursor at the last iter position */
+ gtk_text_buffer_place_cursor (buffer, &iter);
}
+}
- /* Gtk can draw the text now */
- return (*GTK_WIDGET_CLASS (mousepad_view_parent_class)->expose_event) (widget, event);
+
+
+void
+mousepad_view_delete_selection (MousepadView *view)
+{
+ _mousepad_return_if_fail (MOUSEPAD_IS_VIEW (view));
+ _mousepad_return_if_fail (view->marks != NULL);
+
+ /* set the clipbaord to NULL to remove the selection */
+ mousepad_view_handle_clipboard (view, NULL, TRUE);
+
+ /* cleanup the vertical selection */
+ mousepad_view_vertical_selection_reset (view);
}
-/**
- * mousepad_view_set_show_line_numbers:
- * @view : A #MousepadView
- * @visible : Boolean whether we show or hide the line
- * numbers.
- *
- * Whether line numbers are visible in the @view.
- **/
void
mousepad_view_set_show_line_numbers (MousepadView *view,
gboolean visible)
@@ -606,14 +1090,6 @@ mousepad_view_set_show_line_numbers (MousepadView *view,
-/**
- * mousepad_view_set_auto_indent:
- * @view : A #MousepadView
- * @visible : Boolean whether we enable or disable
- * auto indentation.
- *
- * Whether we enable auto indentation.
- **/
void
mousepad_view_set_auto_indent (MousepadView *view,
gboolean enable)
diff --git a/mousepad/mousepad-view.h b/mousepad/mousepad-view.h
index f18da6e..3eb1406 100644
--- a/mousepad/mousepad-view.h
+++ b/mousepad/mousepad-view.h
@@ -34,6 +34,19 @@ typedef struct _MousepadView MousepadView;
GType mousepad_view_get_type (void) G_GNUC_CONST;
+gboolean mousepad_view_get_vertical_selection (MousepadView *view);
+
+void mousepad_view_cut_clipboard (MousepadView *view,
+ GtkClipboard *clipboard);
+
+void mousepad_view_copy_clipboard (MousepadView *view,
+ GtkClipboard *clipboard);
+
+void mousepad_view_paste_column_clipboard (MousepadView *view,
+ GtkClipboard *clipboard);
+
+void mousepad_view_delete_selection (MousepadView *view);
+
void mousepad_view_set_show_line_numbers (MousepadView *view,
gboolean visible);
diff --git a/mousepad/mousepad-window-ui.xml b/mousepad/mousepad-window-ui.xml
index e69829f..a3d6483 100644
--- a/mousepad/mousepad-window-ui.xml
+++ b/mousepad/mousepad-window-ui.xml
@@ -40,6 +40,7 @@
<menuitem action="cut" />
<menuitem action="copy" />
<menuitem action="paste" />
+ <menuitem action="paste-column" />
<menuitem action="delete" />
<separator />
<menuitem action="select-all" />
diff --git a/mousepad/mousepad-window.c b/mousepad/mousepad-window.c
index 5b21c0a..76e6b1b 100644
--- a/mousepad/mousepad-window.c
+++ b/mousepad/mousepad-window.c
@@ -213,6 +213,8 @@ static void mousepad_window_action_copy (GtkAction
MousepadWindow *window);
static void mousepad_window_action_paste (GtkAction *action,
MousepadWindow *window);
+static void mousepad_window_action_paste_column (GtkAction *action,
+ MousepadWindow *window);
static void mousepad_window_action_delete (GtkAction *action,
MousepadWindow *window);
static void mousepad_window_action_select_all (GtkAction *action,
@@ -313,41 +315,42 @@ static const GtkActionEntry action_entries[] =
{ "recent-menu", NULL, N_("Open _Recent"), NULL, NULL, NULL, },
{ "no-recent-items", NULL, N_("No items found"), NULL, NULL, NULL, },
{ "clear-recent", GTK_STOCK_CLEAR, N_("Clear _History"), NULL, N_("Clear the recently used files history"), G_CALLBACK (mousepad_window_action_clear_recent), },
- { "save-file", GTK_STOCK_SAVE, N_("_Save"), NULL, N_("Save the current file"), G_CALLBACK (mousepad_window_action_save_file), },
- { "save-file-as", GTK_STOCK_SAVE_AS, N_("Save _As"), NULL, N_("Save current document as another file"), G_CALLBACK (mousepad_window_action_save_file_as), },
+ { "save-file", GTK_STOCK_SAVE, NULL, NULL, N_("Save the current file"), G_CALLBACK (mousepad_window_action_save_file), },
+ { "save-file-as", GTK_STOCK_SAVE_AS, NULL, NULL, N_("Save current document as another file"), G_CALLBACK (mousepad_window_action_save_file_as), },
{ "reload", GTK_STOCK_REFRESH, N_("Re_load"), NULL, N_("Reload this document."), G_CALLBACK (mousepad_window_action_reload), },
- { "print-document", GTK_STOCK_PRINT, N_("_Print"), "<control>P", N_("Prin the current page"), G_CALLBACK (mousepad_window_action_print), },
+ { "print-document", GTK_STOCK_PRINT, NULL, "<control>P", N_("Prin the current page"), G_CALLBACK (mousepad_window_action_print), },
{ "detach-tab", NULL, N_("_Detach Tab"), "<control>D", N_("Move the current document to a new window"), G_CALLBACK (mousepad_window_action_detach), },
{ "close-tab", GTK_STOCK_CLOSE, N_("C_lose Tab"), "<control>W", N_("Close the current file"), G_CALLBACK (mousepad_window_action_close_tab), },
{ "close-window", GTK_STOCK_QUIT, N_("_Close Window"), "<control>Q", N_("Quit the program"), G_CALLBACK (mousepad_window_action_close), },
{ "edit-menu", NULL, N_("_Edit"), NULL, NULL, NULL, },
- { "undo", GTK_STOCK_UNDO, N_("_Undo"), "<control>Z", N_("Undo the last action"), G_CALLBACK (mousepad_window_action_undo), },
- { "redo", GTK_STOCK_REDO, N_("_Redo"), "<control>Y", N_("Redo the last undone action"), G_CALLBACK (mousepad_window_action_redo), },
- { "cut", GTK_STOCK_CUT, N_("Cu_t"), NULL, N_("Cut the selection"), G_CALLBACK (mousepad_window_action_cut), },
- { "copy", GTK_STOCK_COPY, N_("_Copy"), NULL, N_("Copy the selection"), G_CALLBACK (mousepad_window_action_copy), },
- { "paste", GTK_STOCK_PASTE, N_("_Paste"), NULL, N_("Paste the clipboard"), G_CALLBACK (mousepad_window_action_paste), },
- { "delete", GTK_STOCK_DELETE, N_("_Delete"), NULL, N_("Delete the selected text"), G_CALLBACK (mousepad_window_action_delete), },
- { "select-all", GTK_STOCK_SELECT_ALL, N_("Select _All"), NULL, N_("Select the entire document"), G_CALLBACK (mousepad_window_action_select_all), },
+ { "undo", GTK_STOCK_UNDO, NULL, "<control>Z", N_("Undo the last action"), G_CALLBACK (mousepad_window_action_undo), },
+ { "redo", GTK_STOCK_REDO, NULL, "<control>Y", N_("Redo the last undone action"), G_CALLBACK (mousepad_window_action_redo), },
+ { "cut", GTK_STOCK_CUT, NULL, NULL, N_("Cut the selection"), G_CALLBACK (mousepad_window_action_cut), },
+ { "copy", GTK_STOCK_COPY, NULL, NULL, N_("Copy the selection"), G_CALLBACK (mousepad_window_action_copy), },
+ { "paste", GTK_STOCK_PASTE, NULL, NULL, N_("Paste the clipboard"), G_CALLBACK (mousepad_window_action_paste), },
+ { "paste-column", NULL, N_("Paste _Column"), NULL, N_("Paste the clipboard text in a clumn"), G_CALLBACK (mousepad_window_action_paste_column), },
+ { "delete", GTK_STOCK_DELETE, NULL, NULL, N_("Delete the selected text"), G_CALLBACK (mousepad_window_action_delete), },
+ { "select-all", GTK_STOCK_SELECT_ALL, NULL, NULL, N_("Select the entire document"), G_CALLBACK (mousepad_window_action_select_all), },
{ "search-menu", NULL, N_("_Search"), NULL, NULL, NULL, },
- { "find", GTK_STOCK_FIND, N_("_Find"), NULL, N_("Search for text"), G_CALLBACK (mousepad_window_action_find), },
+ { "find", GTK_STOCK_FIND, NULL, NULL, N_("Search for text"), G_CALLBACK (mousepad_window_action_find), },
{ "find-next", NULL, N_("Find _Next"), NULL, N_("Search forwards for the same text"), G_CALLBACK (mousepad_window_action_find_next), },
{ "find-previous", NULL, N_("Find _Previous"), NULL, N_("Search backwards for the same text"), G_CALLBACK (mousepad_window_action_find_previous), },
- { "replace", GTK_STOCK_FIND_AND_REPLACE, N_("_Replace"), NULL, N_("Search for and replace text"), G_CALLBACK (mousepad_window_action_replace), },
- { "jump-to", GTK_STOCK_JUMP_TO, N_("_Jump To"), NULL, N_("Go to a specific line"), G_CALLBACK (mousepad_window_action_jump_to), },
+ { "replace", GTK_STOCK_FIND_AND_REPLACE, NULL, NULL, N_("Search for and replace text"), G_CALLBACK (mousepad_window_action_replace), },
+ { "jump-to", GTK_STOCK_JUMP_TO, NULL, NULL, N_("Go to a specific line"), G_CALLBACK (mousepad_window_action_jump_to), },
{ "view-menu", NULL, N_("_View"), NULL, NULL, NULL, },
- { "font", GTK_STOCK_SELECT_FONT, N_("_Font"), NULL, N_("Change the editor font"), G_CALLBACK (mousepad_window_action_select_font), },
+ { "font", GTK_STOCK_SELECT_FONT, NULL, NULL, N_("Change the editor font"), G_CALLBACK (mousepad_window_action_select_font), },
{ "document-menu", NULL, N_("_Document"), NULL, NULL, NULL, },
{ "go-menu", NULL, N_("_Go"), NULL, },
- { "back", GTK_STOCK_GO_BACK, N_("Back"), NULL, N_("Select the previous tab"), G_CALLBACK (mousepad_window_action_prev_tab), },
- { "forward", GTK_STOCK_GO_FORWARD, N_("Forward"), NULL, N_("Select the next tab"), G_CALLBACK (mousepad_window_action_next_tab), },
+ { "back", GTK_STOCK_GO_BACK, NULL, NULL, N_("Select the previous tab"), G_CALLBACK (mousepad_window_action_prev_tab), },
+ { "forward", GTK_STOCK_GO_FORWARD, NULL, NULL, N_("Select the next tab"), G_CALLBACK (mousepad_window_action_next_tab), },
{ "help-menu", NULL, N_("_Help"), NULL, },
- { "about", GTK_STOCK_ABOUT, N_("_About"), NULL, N_("About this application"), G_CALLBACK (mousepad_window_action_about), },
+ { "about", GTK_STOCK_ABOUT, NULL, NULL, N_("About this application"), G_CALLBACK (mousepad_window_action_about), },
};
static const GtkToggleActionEntry toggle_action_entries[] =
@@ -929,7 +932,7 @@ mousepad_window_save (MousepadWindow *window,
/* get the current filename */
filename = mousepad_document_get_filename (document);
-
+
/* check if the file really exists */
if (g_file_test (filename, G_FILE_TEST_EXISTS) == FALSE)
filename = NULL;
@@ -1612,7 +1615,7 @@ static gboolean
mousepad_window_update_gomenu_idle (gpointer user_data)
{
GtkWidget *document;
- MousepadWindow *window = MOUSEPAD_WINDOW (user_data);
+ MousepadWindow *window;
gint npages;
gint n;
gchar name[15];
@@ -1623,8 +1626,13 @@ mousepad_window_update_gomenu_idle (gpointer user_data)
GSList *group = NULL;
GList *actions, *li;
+ _mousepad_return_val_if_fail (MOUSEPAD_IS_WINDOW (user_data), FALSE);
+
GDK_THREADS_ENTER ();
+ /* get the window */
+ window = MOUSEPAD_WINDOW (user_data);
+
/* prevent menu updates */
lock_menu_updates++;
@@ -1704,6 +1712,8 @@ mousepad_window_update_gomenu_idle (gpointer user_data)
static void
mousepad_window_update_gomenu_idle_destroy (gpointer user_data)
{
+ _mousepad_return_if_fail (MOUSEPAD_IS_WINDOW (user_data));
+
MOUSEPAD_WINDOW (user_data)->update_go_menu_id = 0;
}
@@ -1712,6 +1722,8 @@ mousepad_window_update_gomenu_idle_destroy (gpointer user_data)
static void
mousepad_window_update_gomenu (MousepadWindow *window)
{
+ _mousepad_return_if_fail (MOUSEPAD_IS_WINDOW (window));
+
/* leave when we're updating multiple files or there is this an idle function pending */
if (lock_menu_updates && window->update_go_menu_id != 0)
return;
@@ -2518,6 +2530,16 @@ mousepad_window_action_paste (GtkAction *action,
static void
+mousepad_window_action_paste_column (GtkAction *action,
+ MousepadWindow *window)
+{
+ if (G_LIKELY (window->active != NULL))
+ mousepad_document_paste_column_clipboard (window->active);
+}
+
+
+
+static void
mousepad_window_action_delete (GtkAction *action,
MousepadWindow *window)
{
More information about the Xfce4-commits
mailing list