ChimaraGlkPrivate *glk_data = g_private_get(glk_data_key);
win->input_request_type = unicode? INPUT_REQUEST_CHARACTER_UNICODE : INPUT_REQUEST_CHARACTER;
- g_signal_handler_unblock( G_OBJECT(win->widget), win->keypress_handler );
+ g_signal_handler_unblock( win->widget, win->char_input_keypress_handler );
gdk_threads_enter();
if(win->input_request_type == INPUT_REQUEST_CHARACTER || win->input_request_type == INPUT_REQUEST_CHARACTER_UNICODE)
{
win->input_request_type = INPUT_REQUEST_NONE;
- g_signal_handler_block( G_OBJECT(win->widget), win->keypress_handler );
+ g_signal_handler_block( win->widget, win->char_input_keypress_handler );
}
}
gtk_widget_modify_base(win->input_entry, GTK_STATE_NORMAL, &background);
g_signal_connect(win->input_entry, "activate", G_CALLBACK(on_input_entry_activate), win);
+ g_signal_connect(win->input_entry, "key-press-event", G_CALLBACK(on_input_entry_key_press_event), win);
+ win->line_input_entry_changed = g_signal_connect(win->input_entry, "changed", G_CALLBACK(on_input_entry_changed), win);
gtk_widget_show(win->input_entry);
gtk_text_view_add_child_at_anchor(GTK_TEXT_VIEW(win->widget), win->input_entry, win->input_anchor);
-
- g_signal_handler_unblock( G_OBJECT(win->widget), win->keypress_handler );
gtk_widget_grab_focus(win->input_entry);
gtk_text_buffer_apply_tag_by_name(buffer, "uneditable", &start_iter, &end_iter);
/* Insert pre-entered text if needed */
- if(insert)
+ if(insert) {
gtk_text_buffer_insert(buffer, &end_iter, inserttext, -1);
+ gtk_text_buffer_get_end_iter(buffer, &end_iter); /* update after text insertion */
+ }
/* Scroll to input point */
gtk_text_view_scroll_mark_onscreen(GTK_TEXT_VIEW(win->widget), input_position);
+
+ /* Apply the correct style to the input prompt */
+ GtkTextIter input_iter;
+ gtk_text_buffer_get_iter_at_mark(buffer, &input_iter, input_position);
+ gtk_text_buffer_apply_tag_by_name(buffer, "input", &input_iter, &end_iter);
gtk_text_view_set_editable(GTK_TEXT_VIEW(win->widget), TRUE);
- g_signal_handler_unblock(buffer, win->insert_text_handler);
+ g_signal_handler_unblock(buffer, win->insert_text_handler);
gtk_widget_grab_focus(win->widget);
gdk_threads_leave();
break;
}
g_free(inserttext);
+ g_signal_handler_unblock(win->widget, win->line_input_keypress_handler);
/* Emit the "waiting" signal to let listeners know we are ready for input */
g_signal_emit_by_name(glk_data->self, "waiting");
case wintype_TextGrid:
text_grid_request_line_event_common(win, maxlen, (initlen > 0), utf8);
break;
- }
+ }
+ g_signal_handler_unblock(win->widget, win->line_input_keypress_handler);
g_free(utf8);
/* Emit the "waiting" signal to let listeners know we are ready for input */
if(win->input_request_type != INPUT_REQUEST_LINE && win->input_request_type != INPUT_REQUEST_LINE_UNICODE)
return;
- g_signal_handler_block( G_OBJECT(win->widget), win->keypress_handler );
+ g_signal_handler_block( win->widget, win->line_input_keypress_handler );
int chars_written = 0;
if(win->type == wintype_TextGrid) {
- g_signal_handler_block( G_OBJECT(win->widget), win->keypress_handler );
chars_written = finish_text_grid_line_input(win, FALSE);
} else if(win->type == wintype_TextBuffer) {
GtkTextBuffer *window_buffer = gtk_text_view_get_buffer( GTK_TEXT_VIEW(win->widget) );
}
}
-/* Internal function: General callback for signal key-press-event on a text buffer or text grid window. Used in character input on both text buffers and grids, and also in line input on grids, to redirect keystrokes to the line input field. Blocked when not in use. */
+/* Internal function: General callback for signal key-press-event on a text buffer or text grid window. Used in character input on both text buffers and grids. Blocked when not in use. */
gboolean
on_char_input_key_press_event(GtkWidget *widget, GdkEventKey *event, winid_t win)
{
/* Only one keypress will be handled */
win->input_request_type = INPUT_REQUEST_NONE;
- g_signal_handler_block( G_OBJECT(win->widget), win->keypress_handler );
+ g_signal_handler_block( win->widget, win->char_input_keypress_handler );
return TRUE;
}
switch(win->type)
{
case wintype_TextBuffer:
- if(event->keyval == GDK_Up || event->keyval == GDK_KP_Up)
- {
-
- }
- else if(event->keyval == GDK_Down || event->keyval == GDK_KP_Down)
+ if(event->keyval == GDK_Up || event->keyval == GDK_KP_Up
+ || event->keyval == GDK_Down || event->keyval == GDK_KP_Down)
{
+ /* Prevent falling off the end of the history list */
+ if( (event->keyval == GDK_Up || event->keyval == GDK_KP_Up)
+ && win->history_pos && win->history_pos->next == NULL)
+ return TRUE;
+ if( (event->keyval == GDK_Down || event->keyval == GDK_KP_Down)
+ && (win->history_pos == NULL || win->history_pos->prev == NULL) )
+ return TRUE;
+ GtkTextBuffer *buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(win->widget));
+ GtkTextIter start, end;
+ /* Erase any text that was already typed */
+ GtkTextMark *input_position = gtk_text_buffer_get_mark(buffer, "input_position");
+ gtk_text_buffer_get_iter_at_mark(buffer, &start, input_position);
+ gtk_text_buffer_get_end_iter(buffer, &end);
+
+ if(win->history_pos == NULL) {
+ gchar *current_input = gtk_text_buffer_get_text(buffer, &start, &end, FALSE);
+ win->history = g_list_prepend(win->history, current_input);
+ win->history_pos = win->history;
+ }
+
+ gtk_text_buffer_delete(buffer, &start, &end);
+
+ if(event->keyval == GDK_Up || event->keyval == GDK_KP_Up)
+ {
+ if(win->history_pos)
+ win->history_pos = g_list_next(win->history_pos);
+ else
+ win->history_pos = win->history;
+ }
+ else /* down */
+ win->history_pos = g_list_previous(win->history_pos);
+
+ /* Insert the history item into the window */
+ gtk_text_buffer_get_end_iter(buffer, &end);
+
+ g_signal_handler_block(buffer, win->insert_text_handler);
+ gtk_text_buffer_insert_with_tags_by_name(buffer, &end, win->history_pos->data, -1, "input", NULL);
+ g_signal_handler_unblock(buffer, win->insert_text_handler);
+ return TRUE;
}
- break;
+ return FALSE;
/* If this is a text grid window, then redirect the key press to the line input GtkEntry */
case wintype_TextGrid:
return retval; /* Block this key event if the entry handled it */
}
}
+ return FALSE;
}
/* Internal function: finish handling a line input request, for both text grid and text buffer windows. */
}
/* Add the text to the window input history */
- win->history = g_list_prepend(win->history, g_strdup(inserted_text));
- win->history_pos = win->history;
+ if(win->history_pos != NULL)
+ {
+ g_free(win->history->data);
+ win->history = g_list_delete_link(win->history, win->history);
+ }
+ if(*inserted_text != 0)
+ win->history = g_list_prepend(win->history, g_strdup(inserted_text));
+
+ win->history_pos = NULL;
g_free(inserted_text);
g_assert(glk);
g_signal_emit_by_name(glk, "line-input", win->rock, text);
}
+
+ /* Add the text to the window input history */
+ if(win->history_pos != NULL)
+ {
+ g_free(win->history->data);
+ win->history = g_list_delete_link(win->history, win->history);
+ }
+ if(*text != 0)
+ win->history = g_list_prepend(win->history, g_strdup(text));
+ win->history_pos = NULL;
+
g_free(text);
-
return chars_written;
}
void
after_window_insert_text(GtkTextBuffer *textbuffer, GtkTextIter *location, gchar *text, gint len, winid_t win)
{
+ GtkTextBuffer *window_buffer = gtk_text_view_get_buffer( GTK_TEXT_VIEW(win->widget) );
+
+ /* Set the history position to NULL and erase the text we were already editing */
+ if(win->history_pos != NULL)
+ {
+ g_free(win->history->data);
+ win->history = g_list_delete_link(win->history, win->history);
+ win->history_pos = NULL;
+ }
if( strchr(text, '\n') != NULL )
{
/* Remove signal handlers */
- GtkTextBuffer *window_buffer = gtk_text_view_get_buffer( GTK_TEXT_VIEW(win->widget) );
g_signal_handler_block(window_buffer, win->insert_text_handler);
+ g_signal_handler_block(win->widget, win->line_input_keypress_handler);
/* Make the window uneditable again and retrieve the text that was input */
gtk_text_view_set_editable(GTK_TEXT_VIEW(win->widget), FALSE);
ChimaraGlk *glk = CHIMARA_GLK(gtk_widget_get_ancestor(win->widget, CHIMARA_TYPE_GLK));
event_throw(glk, evtype_LineInput, win, chars_written, 0);
}
+
+ /* Apply the 'input' style to the text that was entered */
+ GtkTextIter end_iter;
+ gtk_text_buffer_get_end_iter(window_buffer, &end_iter);
+ GtkTextIter input_iter;
+ GtkTextMark *input_position = gtk_text_buffer_get_mark(window_buffer, "input_position");
+ gtk_text_buffer_get_iter_at_mark(window_buffer, &input_iter, input_position);
+ gtk_text_buffer_apply_tag_by_name(window_buffer, "input", &input_iter, &end_iter);
}
/* Internal function: Callback for signal activate on the line input GtkEntry
void
on_input_entry_activate(GtkEntry *input_entry, winid_t win)
{
- g_signal_handler_block(win->widget, win->keypress_handler);
+ g_signal_handler_block(win->widget, win->line_input_keypress_handler);
int chars_written = finish_text_grid_line_input(win, TRUE);
ChimaraGlk *glk = CHIMARA_GLK(gtk_widget_get_ancestor(win->widget, CHIMARA_TYPE_GLK));
event_throw(glk, evtype_LineInput, win, chars_written, 0);
}
+/* Internal function: Callback for signal key-press-event on the line input
+GtkEntry in a text grid window. */
+gboolean
+on_input_entry_key_press_event(GtkEntry *input_entry, GdkEventKey *event, winid_t win)
+{
+ if(event->keyval == GDK_Up || event->keyval == GDK_KP_Up
+ || event->keyval == GDK_Down || event->keyval == GDK_KP_Down)
+ {
+ /* Prevent falling off the end of the history list */
+ if( (event->keyval == GDK_Up || event->keyval == GDK_KP_Up)
+ && win->history_pos && win->history_pos->next == NULL)
+ return TRUE;
+ if( (event->keyval == GDK_Down || event->keyval == GDK_KP_Down)
+ && (win->history_pos == NULL || win->history_pos->prev == NULL) )
+ return TRUE;
+
+ if(win->history_pos == NULL)
+ {
+ const gchar *current_input = gtk_entry_get_text(input_entry);
+ win->history = g_list_prepend(win->history, g_strdup(current_input));
+ win->history_pos = win->history;
+ }
+
+ if(event->keyval == GDK_Up || event->keyval == GDK_KP_Up)
+ {
+ if(win->history_pos)
+ win->history_pos = g_list_next(win->history_pos);
+ else
+ win->history_pos = win->history;
+ }
+ else /* down */
+ win->history_pos = g_list_previous(win->history_pos);
+
+ /* Insert the history item into the window */
+ g_signal_handler_block(input_entry, win->line_input_entry_changed);
+ gtk_entry_set_text(input_entry, win->history_pos->data);
+ g_signal_handler_unblock(input_entry, win->line_input_entry_changed);
+ return TRUE;
+ }
+ return FALSE;
+}
+
+void
+on_input_entry_changed(GtkEditable *editable, winid_t win)
+{
+ /* Set the history position to NULL and erase the text we were already editing */
+ if(win->history_pos != NULL)
+ {
+ g_free(win->history->data);
+ win->history = g_list_delete_link(win->history, win->history);
+ win->history_pos = NULL;
+ }
+}
+
glui32
keyval_to_glk_keycode(guint keyval, gboolean unicode)
{
/* Remove signal handlers so the line input doesn't get picked up again */
g_signal_handler_block(buffer, win->insert_text_handler);
+ g_signal_handler_block(win->widget, win->line_input_keypress_handler);
/* Erase any text that was already typed */
GtkTextMark *input_position = gtk_text_buffer_get_mark(buffer, "input_position");
else if(win->type == wintype_TextGrid)
{
/* Remove signal handlers so the line input doesn't get picked up again */
- g_signal_handler_block(win->widget, win->keypress_handler);
+ g_signal_handler_block(win->widget, win->char_input_keypress_handler);
/* Insert the forced input into the window */
gtk_entry_set_text(GTK_ENTRY(win->input_entry), text);