l3afpad/src/view.c

386 lines
11 KiB
C

/*
* L3afpad - GTK+ based simple text editor
* Copyright (C) 2004-2005 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.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include "l3afpad.h"
#include <gdk/gdkkeysyms.h>
#include <string.h>
static gint keyval;
static gboolean view_scroll_flag = FALSE;
extern GtkClipboard *selection_primary;
gchar *selection_primary_str = NULL;
gint get_current_keyval(void)
{
return keyval;
}
void clear_current_keyval(void)
{
keyval = 0;
}
/*
gboolean scroll_to_cursor(GtkTextBuffer *buffer, gdouble within_margin)
{
GtkTextIter iter;
// gtk_text_buffer_get_start_iter(buffer, &iter);
gtk_text_buffer_get_iter_at_mark(buffer, &iter,
gtk_text_buffer_get_insert(buffer));
return gtk_text_view_scroll_to_iter(GTK_TEXT_VIEW(pub->mw->view),
&iter, within_margin, FALSE, 0.5, 0.5);
}
*/
void scroll_to_cursor(GtkTextBuffer *buffer, gdouble within_margin)
{
gtk_text_view_scroll_to_mark(GTK_TEXT_VIEW(pub->mw->view),
gtk_text_buffer_get_insert(buffer),
within_margin, FALSE, 0, 0);
}
gint check_text_modification(void)
{
gchar *basename, *str;
gint res;
if (gtk_text_buffer_get_modified(pub->mw->buffer)) {
basename = get_file_basename(pub->fi->filename, FALSE);
str = g_strdup_printf(_("Save changes to '%s'?"), basename);
g_free(basename);
res = run_dialog_message_question(pub->mw->window, str);
g_free(str);
switch (res) {
case GTK_RESPONSE_NO:
return 0;
case GTK_RESPONSE_YES:
if (!on_file_save())
return 0;
}
return -1;
}
return 0;
}
#if 0
static gint check_preedit(GtkWidget *view)
{
gint cursor_pos;
gtk_im_context_get_preedit_string(
GTK_TEXT_VIEW(view)->im_context, NULL, NULL, &cursor_pos);
return cursor_pos;
}
#endif
static gboolean check_selection_bound(GtkTextBuffer *buffer)
{
GtkTextIter start, end;
gchar *str, *p;
if (gtk_text_buffer_get_selection_bounds(buffer, &start, &end)) {
str = gtk_text_iter_get_text(&start, &end);
p = strchr(str, '\n');
g_free(str);
if (p)
return TRUE;
}
return FALSE;
}
static gboolean cb_key_press_event(GtkWidget *view, GdkEventKey *event)
{
GtkTextBuffer *buffer;
GtkTextMark *mark;
GtkTextIter iter;
GdkRectangle prev_rect;
#if 0
if (check_preedit(view))
return FALSE;
#endif
buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(view));
mark = gtk_text_buffer_get_insert(buffer);
gtk_text_buffer_get_iter_at_mark(buffer, &iter, mark);
gtk_text_view_get_iter_location(GTK_TEXT_VIEW(view), &iter, &prev_rect);
keyval = 0;
//g_print("key-press-event: 0x%X\n", event->keyval);
switch (event->keyval) {
case GDK_Up: // Try [Shift]+[Down]. it works bad.
case GDK_Down:
if (gtk_text_view_move_mark_onscreen(GTK_TEXT_VIEW(view), mark)) {
GdkRectangle iter_rect;
gtk_text_buffer_get_iter_at_mark(buffer, &iter, mark);
gtk_text_view_get_iter_location(GTK_TEXT_VIEW(view), &iter, &iter_rect);
if (iter_rect.y < prev_rect.y) {
gtk_text_view_get_line_at_y(GTK_TEXT_VIEW(view), &iter,
iter_rect.y - iter_rect.height, NULL);
gtk_text_buffer_move_mark(buffer, mark, &iter);
}
if (!(event->state & GDK_SHIFT_MASK)) {
gtk_text_buffer_get_iter_at_mark(buffer, &iter, mark);
gtk_text_buffer_place_cursor(buffer, &iter);
}
return TRUE;
}
break;
case GDK_Page_Up:
case GDK_Page_Down:
if (gtk_text_view_move_mark_onscreen(GTK_TEXT_VIEW(view), mark)) {
GdkRectangle visible_rect, iter_rect;
gint pos = 0;
gtk_text_view_get_visible_rect(GTK_TEXT_VIEW(view), &visible_rect);
gtk_text_buffer_get_iter_at_mark(buffer, &iter, mark);
gtk_text_view_get_iter_location(GTK_TEXT_VIEW(view), &iter, &iter_rect);
if (iter_rect.y < prev_rect.y)
pos = 1;
if (event->keyval == GDK_Page_Up)
gtk_text_view_get_line_at_y(GTK_TEXT_VIEW(view), &iter,
iter_rect.y - visible_rect.height + iter_rect.height, NULL);
else
gtk_text_view_get_line_at_y(GTK_TEXT_VIEW(view), &iter,
iter_rect.y + visible_rect.height - iter_rect.height, NULL);
gtk_text_buffer_move_mark(buffer, mark, &iter);
gtk_text_view_scroll_to_mark(GTK_TEXT_VIEW(view),
mark, 0, TRUE, 0, pos);
if (!(event->state & GDK_SHIFT_MASK)) {
gtk_text_buffer_get_iter_at_mark(buffer, &iter, mark);
gtk_text_buffer_place_cursor(gtk_text_view_get_buffer(GTK_TEXT_VIEW(view)), &iter);
}
return TRUE;
}
break;
case GDK_Return:
if (indent_get_state()) {
indent_real(view);
return TRUE;
}
break;
case GDK_Tab:
if (event->state & GDK_CONTROL_MASK) {
indent_toggle_tab_width(view);
return TRUE;
}
case GDK_ISO_Left_Tab:
if (event->state & GDK_SHIFT_MASK)
indent_multi_line_unindent(gtk_text_view_get_buffer(GTK_TEXT_VIEW(view)));
else if (!check_selection_bound(gtk_text_view_get_buffer(GTK_TEXT_VIEW(view))))
break;
else
indent_multi_line_indent(gtk_text_view_get_buffer(GTK_TEXT_VIEW(view)));
return TRUE;
}
keyval = event->keyval;
if ((event->state & GDK_CONTROL_MASK)
|| (event->keyval == GDK_Control_L)
|| (event->keyval == GDK_Control_R)) {
keyval = keyval + 0x10000;
//g_print("=================================================\n");
}
return FALSE;
}
static gboolean cb_button_press_event(GtkWidget *view, GdkEventButton *event)
{
GtkTextIter iter, start, end;
gint x, y;
GtkTextBuffer *buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(view));
if ((event->button) == 3 && (event->type == GDK_BUTTON_PRESS)) {
gtk_text_view_window_to_buffer_coords(GTK_TEXT_VIEW(view),
gtk_text_view_get_window_type(GTK_TEXT_VIEW(view), event->window),
(gint)event->x, (gint)event->y, &x, &y);
gtk_text_view_get_iter_at_location(GTK_TEXT_VIEW(view), &iter, x, y);
gtk_text_buffer_get_selection_bounds(buffer, &start, &end);
if (!gtk_text_iter_in_range(&iter, &start, &end))
gtk_text_buffer_place_cursor(buffer, &iter);
}
// backup and restore the clipboard
gchar *current_clipboard_str = gtk_clipboard_wait_for_text(selection_primary);
if (((current_clipboard_str == NULL) || (current_clipboard_str[0]=='\0')) &&
selection_primary_str && selection_primary_str[0]) {
gtk_clipboard_set_text(selection_primary, selection_primary_str, -1);
}
else {
g_free(selection_primary_str);
selection_primary_str = g_strdup(current_clipboard_str);
}
return FALSE;
}
static void cb_modified_changed(GtkTextBuffer *buffer, GtkWidget *view)
{
gboolean modified_flag, exist_flag = FALSE;
gchar *filename, *title;
modified_flag = gtk_text_buffer_get_modified(buffer);
filename = get_file_basename(pub->fi->filename, TRUE);
if (modified_flag)
title = g_strconcat("*", filename, NULL);
else {
title = g_strdup(filename);
undo_reset_modified_step(buffer);
}
g_free(filename);
gtk_window_set_title(GTK_WINDOW(gtk_widget_get_toplevel(view)), title);
g_free(title);
if (pub->fi->filename)
exist_flag = g_file_test(
g_filename_to_utf8(pub->fi->filename, -1, NULL, NULL, NULL),
G_FILE_TEST_EXISTS);
menu_sensitivity_from_modified_flag(modified_flag || !exist_flag);
}
void force_call_cb_modified_changed(GtkWidget *view)
{
cb_modified_changed(gtk_text_view_get_buffer(GTK_TEXT_VIEW(view)), view);
}
void force_block_cb_modified_changed(GtkWidget *view)
{
g_signal_handlers_block_by_func(G_OBJECT(gtk_text_view_get_buffer(GTK_TEXT_VIEW(view))),
G_CALLBACK(cb_modified_changed), view);
}
void force_unblock_cb_modified_changed(GtkWidget *view)
{
g_signal_handlers_unblock_by_func(G_OBJECT(gtk_text_view_get_buffer(GTK_TEXT_VIEW(view))),
G_CALLBACK(cb_modified_changed), view);
}
/*
static void cb_mark_set(GtkTextBuffer *buffer, GtkTextIter *iter, GtkTextMark *mark)
{
if (gtk_text_mark_get_name(mark))
{g_print(gtk_text_mark_get_name(mark));
}else g_print("|");
menu_sensitivity_from_selection_bound(
gtk_text_buffer_get_selection_bounds(buffer, NULL, NULL));
}
*/
static void cb_mark_changed(GtkTextBuffer *buffer)
{
menu_sensitivity_from_selection_bound(
gtk_text_buffer_get_selection_bounds(buffer, NULL, NULL));
}
static void cb_focus_event(GtkWidget *view, GdkEventFocus *event)
{
if (!gtk_text_buffer_get_selection_bounds(gtk_text_view_get_buffer(GTK_TEXT_VIEW(view)), NULL, NULL))
gtk_text_mark_set_visible(
gtk_text_buffer_get_selection_bound(
gtk_text_view_get_buffer(GTK_TEXT_VIEW(view))), !event->in);
if (event->in)
menu_sensitivity_from_clipboard();
}
/*
static void cb_begin_user_action(GtkTextBuffer *buffer, GtkWidget *view)
{
g_signal_handlers_unblock_by_func(G_OBJECT(buffer),
G_CALLBACK(cb_modified_changed), view);
// g_print("begin-user-action\n");
}
static void cb_end_user_action(GtkTextBuffer *buffer, GtkWidget *view)
{
g_signal_handlers_block_by_func(G_OBJECT(buffer),
G_CALLBACK(cb_modified_changed), view);
gtk_text_view_scroll_mark_onscreen( // TODO: require?
GTK_TEXT_VIEW(view),
gtk_text_buffer_get_insert(buffer));
// g_print("end-user-action\n");
}
*//*
static void cb_something(GtkTextBuffer *buffer, gchar *data)
{
g_print("%s\n", data);
}
*/
void set_view_scroll(void)
{
view_scroll_flag = TRUE;
}
static void cb_end_user_action(GtkTextBuffer *buffer, GtkWidget *view)
{
if (view_scroll_flag) {
gtk_text_view_scroll_mark_onscreen( // TODO: require?
GTK_TEXT_VIEW(view),
gtk_text_buffer_get_insert(buffer));
view_scroll_flag = FALSE;
}
}
GtkWidget *create_text_view(void)
{
GtkWidget *view;
GtkTextBuffer *buffer;
view = gtk_text_view_new();
buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(view));
// gtk_text_view_set_left_margin(GTK_TEXT_VIEW(view), 1);
// gtk_text_view_set_right_margin(GTK_TEXT_VIEW(view), 1);
g_signal_connect(G_OBJECT(view), "key-press-event",
G_CALLBACK(cb_key_press_event), NULL);
g_signal_connect(G_OBJECT(view), "button-press-event",
G_CALLBACK(cb_button_press_event), NULL);
g_signal_connect_after(G_OBJECT(view), "cut-clipboard",
G_CALLBACK(menu_sensitivity_from_clipboard), NULL);
g_signal_connect_after(G_OBJECT(view), "copy-clipboard",
G_CALLBACK(menu_sensitivity_from_clipboard), NULL);
g_signal_connect_after(G_OBJECT(view), "paste-clipboard",
G_CALLBACK(set_view_scroll),
gtk_text_buffer_get_insert(buffer));
/* g_signal_connect_after(G_OBJECT(view), "paste-clipboard",
G_CALLBACK(gtk_text_view_scroll_mark_onscreen),
gtk_text_buffer_get_insert(buffer));*/
g_signal_connect_after(G_OBJECT(view), "focus-in-event",
G_CALLBACK(cb_focus_event), NULL);
g_signal_connect_after(G_OBJECT(view), "focus-out-event",
G_CALLBACK(cb_focus_event), NULL);
g_signal_connect(G_OBJECT(buffer), "mark-set",
G_CALLBACK(cb_mark_changed), NULL);
g_signal_connect(G_OBJECT(buffer), "mark-deleted",
G_CALLBACK(cb_mark_changed), NULL);
g_signal_connect(G_OBJECT(buffer), "modified-changed",
G_CALLBACK(cb_modified_changed), view);
g_signal_connect_after(G_OBJECT(buffer), "end-user-action",
G_CALLBACK(cb_end_user_action), view);
/* g_signal_connect(G_OBJECT(buffer), "begin-user-action",
G_CALLBACK(cb_begin_user_action), view);
g_signal_connect_after(G_OBJECT(buffer), "end-user-action",
G_CALLBACK(cb_end_user_action), view);
cb_end_user_action(buffer, view);
*/
linenum_init(view);
return view;
}