[GTK3] Make use of GB_debugger_complete_substring
This commit is contained in:
parent
5049f400f0
commit
07f6da4c9e
@ -2,6 +2,11 @@
|
|||||||
#include "util.h"
|
#include "util.h"
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
struct Selection {
|
||||||
|
gint start;
|
||||||
|
gint end;
|
||||||
|
};
|
||||||
|
|
||||||
struct _ConsoleWindow {
|
struct _ConsoleWindow {
|
||||||
GtkWindowClass parent_class;
|
GtkWindowClass parent_class;
|
||||||
|
|
||||||
@ -20,16 +25,49 @@ struct _ConsoleWindow {
|
|||||||
GtkEntryCompletion *command_completion;
|
GtkEntryCompletion *command_completion;
|
||||||
guint command_history_len;
|
guint command_history_len;
|
||||||
gint command_history_index;
|
gint command_history_index;
|
||||||
|
|
||||||
|
struct Selection auto_complete_range;
|
||||||
|
uintptr_t auto_complete_context;
|
||||||
|
bool ignore_auto_complete_context_reset;
|
||||||
|
|
||||||
|
GB_gameboy_t *gb;
|
||||||
};
|
};
|
||||||
|
|
||||||
G_DEFINE_TYPE(ConsoleWindow, console_window, GTK_TYPE_WINDOW);
|
G_DEFINE_TYPE(ConsoleWindow, console_window, GTK_TYPE_WINDOW);
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
PROP_GB_PTR = 1,
|
||||||
|
|
||||||
|
N_PROPERTIES
|
||||||
|
} ConsoleWindowProperty;
|
||||||
|
|
||||||
|
static GParamSpec *obj_properties[N_PROPERTIES] = { NULL, };
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
const char *message;
|
const char *message;
|
||||||
GB_log_attributes attributes;
|
GB_log_attributes attributes;
|
||||||
bool sidebar;
|
bool sidebar;
|
||||||
} AttributedMessage;
|
} AttributedMessage;
|
||||||
|
|
||||||
|
static void console_window_set_property(GObject *object, guint property_id, const GValue *value, GParamSpec *pspec) {
|
||||||
|
ConsoleWindow *self = (ConsoleWindow *) object;
|
||||||
|
|
||||||
|
switch ((ConsoleWindowProperty) property_id) {
|
||||||
|
case PROP_GB_PTR: self->gb = g_value_get_pointer(value); break;
|
||||||
|
default: G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void console_window_get_property(GObject *object, guint property_id, GValue *value, GParamSpec *pspec) {
|
||||||
|
ConsoleWindow *self = (ConsoleWindow *) object;
|
||||||
|
|
||||||
|
switch ((ConsoleWindowProperty) property_id) {
|
||||||
|
case PROP_GB_PTR: g_value_set_pointer(value, self->gb); break;
|
||||||
|
default: G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static gboolean on_input_key_press(GtkEntry *input, GdkEventKey *event, ConsoleWindow *self) {
|
static gboolean on_input_key_press(GtkEntry *input, GdkEventKey *event, ConsoleWindow *self) {
|
||||||
switch (event->keyval) {
|
switch (event->keyval) {
|
||||||
case GDK_KEY_Up:
|
case GDK_KEY_Up:
|
||||||
@ -88,7 +126,48 @@ static gboolean on_input_key_press(GtkEntry *input, GdkEventKey *event, ConsoleW
|
|||||||
|
|
||||||
case GDK_KEY_Tab:
|
case GDK_KEY_Tab:
|
||||||
if (event->type == GDK_KEY_PRESS) {
|
if (event->type == GDK_KEY_PRESS) {
|
||||||
gtk_editable_set_position(GTK_EDITABLE(input), -1);
|
if (self->auto_complete_context == 0) {
|
||||||
|
gint start_pos;
|
||||||
|
gint end_pos;
|
||||||
|
gtk_editable_get_selection_bounds(GTK_EDITABLE(input), &start_pos, &end_pos);
|
||||||
|
|
||||||
|
if (start_pos != end_pos) {
|
||||||
|
self->ignore_auto_complete_context_reset = true;
|
||||||
|
gtk_editable_delete_text(GTK_EDITABLE(input), start_pos, end_pos);
|
||||||
|
self->ignore_auto_complete_context_reset = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
self->auto_complete_range = (struct Selection){
|
||||||
|
.start = start_pos,
|
||||||
|
.end = start_pos
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
gchar *substring = gtk_editable_get_chars(GTK_EDITABLE(input), 0, self->auto_complete_range.start);
|
||||||
|
|
||||||
|
uintptr_t context = self->auto_complete_context;
|
||||||
|
char *completion = GB_debugger_complete_substring(self->gb, substring, &context);
|
||||||
|
g_free(substring);
|
||||||
|
|
||||||
|
if (completion) {
|
||||||
|
self->ignore_auto_complete_context_reset = true;
|
||||||
|
|
||||||
|
gtk_editable_select_region(GTK_EDITABLE(input), self->auto_complete_range.start, self->auto_complete_range.end);
|
||||||
|
gint new_end = self->auto_complete_range.start;
|
||||||
|
gtk_editable_delete_text(GTK_EDITABLE(input), self->auto_complete_range.start, self->auto_complete_range.end);
|
||||||
|
gtk_editable_insert_text(GTK_EDITABLE(input), completion, -1, &new_end);
|
||||||
|
self->auto_complete_range.end = new_end;
|
||||||
|
|
||||||
|
gtk_editable_set_position(GTK_EDITABLE(input), self->auto_complete_range.end);
|
||||||
|
|
||||||
|
self->ignore_auto_complete_context_reset = false;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
g_debug("BEEP (no completion found)");
|
||||||
|
gdk_display_beep(gdk_display_get_default());
|
||||||
|
}
|
||||||
|
|
||||||
|
self->auto_complete_context = context;
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@ -98,6 +177,26 @@ static gboolean on_input_key_press(GtkEntry *input, GdkEventKey *event, ConsoleW
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void reset_auto_completion_context(GtkEntry *input, ConsoleWindow *self) {
|
||||||
|
if (self->ignore_auto_complete_context_reset) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
self->auto_complete_context = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void on_delete_text(GtkEditable *editable, int start_pos, int end_pos, ConsoleWindow *self) {
|
||||||
|
reset_auto_completion_context(GTK_ENTRY(editable), self);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void on_insert_text(GtkEditable *editable, char*new_text, int new_text_length, gpointer position, ConsoleWindow *self) {
|
||||||
|
reset_auto_completion_context(GTK_ENTRY(editable), self);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void on_move_cursor(GtkEntry *input, GtkMovementStep step, int count, gboolean extend_selection, ConsoleWindow *self) {
|
||||||
|
reset_auto_completion_context(input, self);
|
||||||
|
}
|
||||||
|
|
||||||
static void console_window_init(ConsoleWindow *self) {
|
static void console_window_init(ConsoleWindow *self) {
|
||||||
gtk_widget_init_template(GTK_WIDGET(self));
|
gtk_widget_init_template(GTK_WIDGET(self));
|
||||||
|
|
||||||
@ -127,7 +226,7 @@ static void console_window_init(ConsoleWindow *self) {
|
|||||||
gtk_entry_completion_set_model(self->command_completion, GTK_TREE_MODEL(command_list_store));
|
gtk_entry_completion_set_model(self->command_completion, GTK_TREE_MODEL(command_list_store));
|
||||||
gtk_entry_completion_set_text_column(self->command_completion, 0);
|
gtk_entry_completion_set_text_column(self->command_completion, 0);
|
||||||
gtk_entry_completion_set_popup_completion(self->command_completion, false);
|
gtk_entry_completion_set_popup_completion(self->command_completion, false);
|
||||||
gtk_entry_completion_set_inline_completion(self->command_completion, true);
|
gtk_entry_completion_set_inline_completion(self->command_completion, false);
|
||||||
gtk_entry_set_completion(self->input, self->command_completion);
|
gtk_entry_set_completion(self->input, self->command_completion);
|
||||||
gtk_entry_set_input_hints(self->input, GTK_INPUT_HINT_NO_SPELLCHECK | GTK_INPUT_HINT_NO_EMOJI);
|
gtk_entry_set_input_hints(self->input, GTK_INPUT_HINT_NO_SPELLCHECK | GTK_INPUT_HINT_NO_EMOJI);
|
||||||
|
|
||||||
@ -135,6 +234,9 @@ static void console_window_init(ConsoleWindow *self) {
|
|||||||
|
|
||||||
g_signal_connect(self->input, "key-press-event", G_CALLBACK(on_input_key_press), self);
|
g_signal_connect(self->input, "key-press-event", G_CALLBACK(on_input_key_press), self);
|
||||||
g_signal_connect(self->input, "key-release-event", G_CALLBACK(on_input_key_press), self);
|
g_signal_connect(self->input, "key-release-event", G_CALLBACK(on_input_key_press), self);
|
||||||
|
g_signal_connect(self->input, "delete-text", G_CALLBACK(on_delete_text), self);
|
||||||
|
g_signal_connect(self->input, "insert-text", G_CALLBACK(on_insert_text), self);
|
||||||
|
g_signal_connect(self->input, "move-cursor", G_CALLBACK(on_move_cursor), self);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void console_window_realize(GtkWidget *widget) {
|
static void console_window_realize(GtkWidget *widget) {
|
||||||
@ -330,10 +432,20 @@ static void console_window_class_init(ConsoleWindowClass *class) {
|
|||||||
|
|
||||||
GTK_WIDGET_CLASS(class)->realize = console_window_realize;
|
GTK_WIDGET_CLASS(class)->realize = console_window_realize;
|
||||||
GTK_WIDGET_CLASS(class)->draw = console_window_draw;
|
GTK_WIDGET_CLASS(class)->draw = console_window_draw;
|
||||||
|
|
||||||
|
obj_properties[PROP_GB_PTR] = g_param_spec_pointer(
|
||||||
|
"gb", "SameBoy core pointer", "SameBoy Core pointer (GB_gameboy_t)",
|
||||||
|
G_PARAM_CONSTRUCT | G_PARAM_READWRITE
|
||||||
|
);
|
||||||
|
|
||||||
|
G_OBJECT_CLASS(class)->set_property = console_window_set_property;
|
||||||
|
G_OBJECT_CLASS(class)->get_property = console_window_get_property;
|
||||||
|
|
||||||
|
g_object_class_install_properties(G_OBJECT_CLASS(class), N_PROPERTIES, obj_properties);
|
||||||
}
|
}
|
||||||
|
|
||||||
ConsoleWindow *console_window_new(void) {
|
ConsoleWindow *console_window_new(GB_gameboy_t *gb) {
|
||||||
return g_object_new(CONSOLE_WINDOW_TYPE, NULL);
|
return g_object_new(CONSOLE_WINDOW_TYPE, "gb", gb, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
// This function gets called every VBlank while the emulation is running.
|
// This function gets called every VBlank while the emulation is running.
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
#define CONSOLE_WINDOW_TYPE (console_window_get_type())
|
#define CONSOLE_WINDOW_TYPE (console_window_get_type())
|
||||||
G_DECLARE_FINAL_TYPE(ConsoleWindow, console_window, SAMEBOY, CONSOLE_WINDOW, GtkWindow)
|
G_DECLARE_FINAL_TYPE(ConsoleWindow, console_window, SAMEBOY, CONSOLE_WINDOW, GtkWindow)
|
||||||
|
|
||||||
ConsoleWindow *console_window_new(void);
|
ConsoleWindow *console_window_new(GB_gameboy_t *gb);
|
||||||
char *console_get_async_input(ConsoleWindow *self, GB_gameboy_t *gb);
|
char *console_get_async_input(ConsoleWindow *self, GB_gameboy_t *gb);
|
||||||
char *console_get_sync_input(ConsoleWindow *self, GB_gameboy_t *gb);
|
char *console_get_sync_input(ConsoleWindow *self, GB_gameboy_t *gb);
|
||||||
void console_log(ConsoleWindow *self, const char *message, GB_log_attributes attributes);
|
void console_log(ConsoleWindow *self, const char *message, GB_log_attributes attributes);
|
||||||
|
@ -992,7 +992,7 @@ static void startup(GApplication *app, gpointer null_ptr) {
|
|||||||
init_config(app, gui_data.cli_options.config_path, &gui_data.config_modification_date);
|
init_config(app, gui_data.cli_options.config_path, &gui_data.config_modification_date);
|
||||||
|
|
||||||
gui_data.screen = gb_screen_new(gui_data.cli_options.force_software_renderer);
|
gui_data.screen = gb_screen_new(gui_data.cli_options.force_software_renderer);
|
||||||
gui_data.console = console_window_new();
|
gui_data.console = console_window_new(&gb);
|
||||||
gui_data.preferences = preferences_window_new(&gb);
|
gui_data.preferences = preferences_window_new(&gb);
|
||||||
gui_data.vram_viewer = vram_viewer_window_new();
|
gui_data.vram_viewer = vram_viewer_window_new();
|
||||||
gui_data.memory_viewer = GTK_WINDOW(get_object("memory_viewer"));
|
gui_data.memory_viewer = GTK_WINDOW(get_object("memory_viewer"));
|
||||||
|
Loading…
Reference in New Issue
Block a user