New text program styletest.so available to test some basic style/hyperlink functionality. Load with the plugin loader.
/* Timer capabilities present */
case gestalt_Timer:
return 1;
+
+ /* Hyperlink capabilities present */
+ case gestalt_Hyperlinks:
+ return 1;
+
+ /* Hyperlinks supported on textbuffers only at the moment */
+ case gestalt_HyperlinkInput:
+ return val == wintype_TextBuffer;
/* Unsupported capabilities */
case gestalt_MouseInput:
case gestalt_Sound:
case gestalt_SoundVolume:
case gestalt_SoundNotify:
- case gestalt_Hyperlinks:
- case gestalt_HyperlinkInput:
case gestalt_SoundMusic:
case gestalt_GraphicsTransparency:
/* Selector not supported */
}
/**
- * glk_set_hyperlink:
+ * glk_set_hyperlink_stream:
* @str: The stream to set the hyperlink mode on.
* @linkval: Set to nonzero to initiate hyperlink mode. Set to zero to disengage.
*
g_return_if_fail(str->window != NULL);
g_return_if_fail(str->window->type == wintype_TextBuffer);
- str->hyperlink_mode = (linkval != 0);
+ flush_window_buffer(str->window);
+
+ if(linkval == 0) {
+ /* Turn off hyperlink mode */
+ str->hyperlink_mode = FALSE;
+ str->window->current_hyperlink = NULL;
+ return;
+ }
+
+ /* Check whether a tag with the needed value already exists */
+ hyperlink_t *new_hyperlink = g_hash_table_lookup(str->window->hyperlinks, &linkval);
+ if(new_hyperlink == NULL) {
+ /* Create a new hyperlink with the requested value */
+ new_hyperlink = g_new0(struct hyperlink, 1);
+ new_hyperlink->value = linkval;
+ new_hyperlink->tag = gtk_text_tag_new(NULL);
+ new_hyperlink->event_handler = g_signal_connect( new_hyperlink->tag, "event", G_CALLBACK(on_hyperlink_clicked), new_hyperlink );
+ g_signal_handler_block(new_hyperlink->tag, new_hyperlink->event_handler);
+ new_hyperlink->window = str->window;
+
+ /* Add the new tag to the tag table of the textbuffer */
+ GtkTextBuffer *textbuffer = gtk_text_view_get_buffer( GTK_TEXT_VIEW(str->window->widget) );
+ GtkTextTagTable *tags = gtk_text_buffer_get_tag_table(textbuffer);
+ gtk_text_tag_table_add(tags, new_hyperlink->tag);
+
+ printf("inserting link %d\n", linkval);
+
+ gint *linkval_pointer = g_new0(gint, 1);
+ *linkval_pointer = linkval;
+ g_hash_table_insert(str->window->hyperlinks, linkval_pointer, new_hyperlink);
+ }
+
+ str->hyperlink_mode = TRUE;
+ str->window->current_hyperlink = new_hyperlink;
+}
+
+/* Internal function used to iterate over all the hyperlinks, unblocking the event handler */
+void
+hyperlink_unblock_event_handler(gpointer key, gpointer value, gpointer user_data)
+{
+ hyperlink_t *link = (hyperlink_t *) value;
+ g_signal_handler_unblock(link->tag, link->event_handler);
+ printf("unblocking link %d\n", link->value);
+}
+
+/* Internal function used to iterate over all the hyperlinks, blocking the event handler */
+void
+hyperlink_block_event_handler(gpointer key, gpointer value, gpointer user_data)
+{
+ hyperlink_t *link = (hyperlink_t *) value;
+ g_signal_handler_block(link->tag, link->event_handler);
}
void
{
VALID_WINDOW(win, return);
g_return_if_fail(win != NULL);
- g_return_if_fail(win->mouse_click_handler != 0);
g_return_if_fail(win->type != wintype_TextBuffer || win->type != wintype_TextGrid);
- g_signal_handler_unblock( G_OBJECT(win->widget), win->mouse_click_handler );
+ g_hash_table_foreach(win->hyperlinks, hyperlink_unblock_event_handler, NULL);
+
}
void
{
VALID_WINDOW(win, return);
g_return_if_fail(win != NULL);
- g_return_if_fail(win->mouse_click_handler != 0);
g_return_if_fail(win->type != wintype_TextBuffer || win->type != wintype_TextGrid);
-
- g_signal_handler_block( G_OBJECT(win->widget), win->mouse_click_handler );
+
+ g_hash_table_foreach(win->hyperlinks, hyperlink_block_event_handler, NULL);
}
-/* Internal function: General callback for signal button-release-event on a
- * text buffer or text grid window. Used for detecting clicks on hyperlinks.
- * Blocked when not in use.
- */
gboolean
-on_window_button_release_event(GtkWidget *widget, GdkEventButton *event, winid_t win)
+on_hyperlink_clicked(GtkTextTag *tag, GObject *object, GdkEvent *event, GtkTextIter *iter, hyperlink_t *link)
{
- printf("Click on (%f,%f)\n", event->x, event->y);
- return TRUE;
+ ChimaraGlk *glk = CHIMARA_GLK(gtk_widget_get_ancestor(link->window->widget, CHIMARA_TYPE_GLK));
+ g_assert(glk);
+
+ if(event->type == GDK_BUTTON_PRESS) {
+ event_throw(glk, evtype_Hyperlink, link->window, link->value, 0);
+ }
+
+ return FALSE;
}
#include "window.h"
#include "event.h"
-G_GNUC_INTERNAL gboolean on_window_button_release_event(GtkWidget *widget, GdkEventButton *event, winid_t win);
+struct hyperlink {
+ guint32 value;
+ GtkTextTag *tag;
+ gulong event_handler;
+ winid_t window;
+};
+typedef struct hyperlink hyperlink_t;
+
+G_GNUC_INTERNAL gboolean on_hyperlink_clicked(GtkTextTag *tag, GObject *object, GdkEvent *event, GtkTextIter *iter, hyperlink_t *link);
#endif
gchar *filename; /* Displayable filename in UTF-8 for error handling */
gchar *style; /* Name of the current style */
- gboolean hyperlink_mode; /* WHen turned on, text written to the stream will be a hyperlink */
+ gboolean hyperlink_mode; /* When turned on, text written to the stream will be a hyperlink */
};
G_GNUC_INTERNAL strid_t file_stream_new(frefid_t fileref, glui32 fmode, glui32 rock, gboolean unicode);
{
GtkTextIter iter;
gtk_text_buffer_get_end_iter(buffer, &iter);
- gtk_text_buffer_insert_with_tags_by_name(buffer, &iter, win->buffer->str, -1, win->window_stream->style, NULL);
+
+ GtkTextTagTable *tags = gtk_text_buffer_get_tag_table(buffer);
+ GtkTextTag *style_tag = gtk_text_tag_table_lookup(tags, win->window_stream->style);
+
+ if(win->window_stream->hyperlink_mode) {
+ GtkTextTag *link_style_tag = gtk_text_tag_table_lookup(tags, "hyperlink");
+ GtkTextTag *link_tag = win->current_hyperlink->tag;
+ gtk_text_buffer_insert_with_tags(buffer, &iter, win->buffer->str, -1, style_tag, link_style_tag, link_tag, NULL);
+ } else {
+ gtk_text_buffer_insert_with_tags(buffer, &iter, win->buffer->str, -1, style_tag, NULL);
+ }
ChimaraGlk *glk = CHIMARA_GLK(gtk_widget_get_ancestor(win->widget, CHIMARA_TYPE_GLK));
g_assert(glk);
GtkTextIter end = start;
gtk_text_iter_forward_to_line_end(&end);
gtk_text_buffer_delete(buffer, &start, &end);
- gtk_text_buffer_insert_with_tags_by_name(buffer, &start, win->buffer->str + (length - chars_left), available_space, win->window_stream->style, NULL);
+
+ GtkTextTagTable *tags = gtk_text_buffer_get_tag_table(buffer);
+ GtkTextTag *style_tag = gtk_text_tag_table_lookup(tags, win->window_stream->style);
+
+ if(win->window_stream->hyperlink_mode) {
+ GtkTextTag *link_style_tag = gtk_text_tag_table_lookup(tags, "hyperlink");
+ GtkTextTag *link_tag = win->current_hyperlink->tag;
+ gtk_text_buffer_insert_with_tags(buffer, &start, win->buffer->str + (length - chars_left), available_space, style_tag, link_style_tag, link_tag, NULL);
+ } else {
+ gtk_text_buffer_insert_with_tags(buffer, &start, win->buffer->str + (length - chars_left), available_space, style_tag, NULL);
+ }
+
chars_left -= available_space;
gtk_text_iter_forward_line(&start);
available_space = win->width;
GtkTextIter end = start;
gtk_text_iter_forward_chars(&end, chars_left);
gtk_text_buffer_delete(buffer, &start, &end);
- gtk_text_buffer_insert_with_tags_by_name(buffer, &start, win->buffer->str + (length - chars_left), -1, win->window_stream->style, NULL);
+
+ GtkTextTagTable *tags = gtk_text_buffer_get_tag_table(buffer);
+ GtkTextTag *style_tag = gtk_text_tag_table_lookup(tags, win->window_stream->style);
+
+ if(win->window_stream->hyperlink_mode) {
+ GtkTextTag *link_style_tag = gtk_text_tag_table_lookup(tags, "hyperlink");
+ GtkTextTag *link_tag = win->current_hyperlink->tag;
+ gtk_text_buffer_insert_with_tags(buffer, &start, win->buffer->str + (length - chars_left), -1, style_tag, link_style_tag, link_tag, NULL);
+ } else {
+ gtk_text_buffer_insert_with_tags(buffer, &start, win->buffer->str + (length - chars_left), -1, style_tag, NULL);
+ }
}
gtk_text_buffer_move_mark(buffer, cursor, &start);
static gboolean style_accept_style_hint(GScanner *scanner, GtkTextTag *current_tag);
static void style_add_tag_to_textbuffer(gpointer key, gpointer tag, gpointer tag_table);
static void style_table_copy(gpointer key, gpointer tag, gpointer target_table);
-static GtkTextTag* gtk_text_tag_copy(GtkTextTag *tag);
+GtkTextTag* gtk_text_tag_copy(GtkTextTag *tag);
/**
* glk_set_style:
}
/* Internal function that copies a text tag */
-static GtkTextTag*
+GtkTextTag*
gtk_text_tag_copy(GtkTextTag *tag)
{
GtkTextTag *copy;
_COPY_FLAG (language_set);
#undef _COPY_FLAG
- /* Copy the reverse_color attribute, that was added manually */
- g_object_set_data( G_OBJECT(copy), "reverse_color", g_object_get_data(G_OBJECT(tag), "reverse_color") );
+ /* Copy the data that was added manually */
+ gpointer reverse_color = g_object_get_data( G_OBJECT(tag), "reverse_color" );
+
+ if(reverse_color)
+ g_object_set_data( G_OBJECT(copy), "reverse_color", reverse_color );
return copy;
}
style_init()
{
ChimaraGlkPrivate *glk_data = g_private_get(glk_data_key);
- GHashTable *default_text_grid_styles = g_hash_table_new(g_str_hash, g_str_equal);
- GHashTable *default_text_buffer_styles = g_hash_table_new(g_str_hash, g_str_equal);
- GHashTable *current_text_grid_styles = g_hash_table_new(g_str_hash, g_str_equal);
- GHashTable *current_text_buffer_styles = g_hash_table_new(g_str_hash, g_str_equal);
+ GHashTable *default_text_grid_styles = g_hash_table_new_full(g_str_hash, g_str_equal, NULL, g_object_unref);
+ GHashTable *default_text_buffer_styles = g_hash_table_new_full(g_str_hash, g_str_equal, NULL, g_object_unref);
+ GHashTable *current_text_grid_styles = g_hash_table_new_full(g_str_hash, g_str_equal, NULL, g_object_unref);
+ GHashTable *current_text_buffer_styles = g_hash_table_new_full(g_str_hash, g_str_equal, NULL, g_object_unref);
GtkTextTag *tag;
/* Create the CSS file scanner */
g_hash_table_insert(default_text_grid_styles, "note", tag);
tag = gtk_text_tag_new("block-quote");
- g_object_set(tag, "style", PANGO_STYLE_ITALIC, NULL);
+ g_object_set(tag, "style", PANGO_STYLE_ITALIC, "style-set", TRUE, NULL);
g_hash_table_insert(default_text_grid_styles, "block-quote", tag);
g_hash_table_insert(default_text_grid_styles, "input", gtk_text_tag_new("input"));
g_hash_table_insert(default_text_grid_styles, "user1", gtk_text_tag_new("user1"));
g_hash_table_insert(default_text_grid_styles, "user2", gtk_text_tag_new("user2"));
+ tag = gtk_text_tag_new("hyperlink");
+ g_object_set(tag, "foreground", "#0000ff", "underline", PANGO_UNDERLINE_SINGLE, "underline-set", TRUE, NULL);
+ g_hash_table_insert(default_text_grid_styles, "hyperlink", tag);
+
/* Tags for the textbuffer */
tag = gtk_text_tag_new("normal");
g_object_set(tag, "font-desc", glk_data->default_font_desc, NULL);
g_hash_table_insert(default_text_buffer_styles, "note", tag);
tag = gtk_text_tag_new("block-quote");
- g_object_set(tag, "justification", GTK_JUSTIFY_CENTER, "style", PANGO_STYLE_ITALIC, NULL);
+ g_object_set(tag, "justification", GTK_JUSTIFY_CENTER, "style", PANGO_STYLE_ITALIC, "style-set", TRUE, NULL);
g_hash_table_insert(default_text_buffer_styles, "block-quote", tag);
g_hash_table_insert(default_text_buffer_styles, "input", gtk_text_tag_new("input"));
g_hash_table_insert(default_text_buffer_styles, "user1", gtk_text_tag_new("user1"));
g_hash_table_insert(default_text_buffer_styles, "user2", gtk_text_tag_new("user2"));
+ tag = gtk_text_tag_new("hyperlink");
+ g_object_set(tag, "foreground", "#0000ff", "underline", PANGO_UNDERLINE_SINGLE, "underline-set", TRUE, NULL);
+ g_hash_table_insert(default_text_buffer_styles, "hyperlink", tag);
+
+
glk_data->default_styles->text_grid = default_text_grid_styles;
glk_data->default_styles->text_buffer = default_text_buffer_styles;
G_GNUC_INTERNAL void style_init_textgrid(GtkTextBuffer *buffer);
G_GNUC_INTERNAL void style_init();
G_GNUC_INTERNAL PangoFontDescription* get_current_font(guint32 wintype);
+G_GNUC_INTERNAL GtkTextTag* gtk_text_tag_copy(GtkTextTag *tag);
typedef struct StyleSet {
GHashTable *text_grid;
/* Initialise the buffer */
win->buffer = g_string_sized_new(1024);
+ /* Initialise hyperlink table */
+ win->hyperlinks = g_hash_table_new_full(g_int_hash, g_direct_equal, g_free, g_object_unref);
+
return win;
}
g_list_free(win->history);
g_string_free(win->buffer, TRUE);
+ g_hash_table_destroy(win->hyperlinks);
+ g_free(win->current_hyperlink);
g_free(win);
}
g_signal_handler_block(textview, win->char_input_keypress_handler);
win->line_input_keypress_handler = g_signal_connect(textview, "key-press-event", G_CALLBACK(on_line_input_key_press_event), win);
g_signal_handler_block(textview, win->line_input_keypress_handler);
-
- gtk_widget_add_events( textview, GDK_BUTTON_RELEASE_MASK );
- win->mouse_click_handler = g_signal_connect_after( G_OBJECT(textview), "button-release-event", G_CALLBACK(on_window_button_release_event), win );
- g_signal_handler_block( textview, win->mouse_click_handler );
}
break;
win->line_input_keypress_handler = g_signal_connect( textview, "key-press-event", G_CALLBACK(on_line_input_key_press_event), win );
g_signal_handler_block(textview, win->line_input_keypress_handler);
- gtk_widget_add_events( GTK_WIDGET(textview), GDK_BUTTON_RELEASE_MASK );
- win->mouse_click_handler = g_signal_connect_after( textview, "button-release-event", G_CALLBACK(on_window_button_release_event), win );
- g_signal_handler_block( textview, win->mouse_click_handler );
-
win->insert_text_handler = g_signal_connect_after( textbuffer, "insert-text", G_CALLBACK(after_window_insert_text), win );
- g_signal_handler_block( textbuffer, win->insert_text_handler );
+ g_signal_handler_block(textbuffer, win->insert_text_handler);
+
/* Create an editable tag to indicate uneditable parts of the window
(for line input) */
gulong char_input_keypress_handler;
gulong line_input_keypress_handler;
gulong insert_text_handler;
- gulong mouse_click_handler;
- gulong mouse_move_handler;
+ gulong tag_event_handler;
/* Window buffer */
GString *buffer;
+ /* Hyperlinks */
+ GHashTable *hyperlinks;
+ struct hyperlink *current_hyperlink;
};
#endif
AM_CFLAGS = -Wall
AM_CPPFLAGS = -I$(top_srcdir)
-dist_data_DATA = chimara.ui chimara.menus glulxercise.ui
+PLUGIN_LIBTOOL_FLAGS=-module -avoid-version -export-symbols-regex "^glk_main$$"
+
+if TARGET_ILIAD
+
+iliad_SOURCES = iliad.c
+iliad_CFLAGS = @TEST_CFLAGS@ $(AM_CFLAGS)
+iliad_LDADD = @TEST_LIBS@ $(top_builddir)/libchimara/libchimara.la
+
+noinst_PROGRAMS = iliad
+else
+
+dist_data_DATA = chimara.ui chimara.menus glulxercise.ui
noinst_PROGRAMS = test-chimara test-multisession glulxercise plugin-loader
test_chimara_SOURCES = main.c callbacks.c error.c error.h
plugin_loader_CFLAGS = @TEST_CFLAGS@ $(AM_CFLAGS)
plugin_loader_LDADD = @TEST_LIBS@ $(top_builddir)/libchimara/libchimara.la
-pkglib_LTLIBRARIES = first.la model.la gridtest.la splittest.la multiwin.la
-PLUGIN_LIBTOOL_FLAGS=-module -avoid-version -export-symbols-regex "^glk_main$$"
+pkglib_LTLIBRARIES = first.la model.la gridtest.la splittest.la multiwin.la styletest.la
first_la_SOURCES = first.c
first_la_LDFLAGS = $(PLUGIN_LIBTOOL_FLAGS)
multiwin_la_SOURCES = multiwin.c
multiwin_la_LDFLAGS = $(PLUGIN_LIBTOOL_FLAGS)
+
+styletest_la_SOURCES = styletest.c
+styletest_la_LDFLAGS = $(PLUGIN_LIBTOOL_FLAGS)
+
+endif
}
glk = chimara_if_new();
+ //chimara_if_set_preferred_interpreter( CHIMARA_IF(glk), CHIMARA_IF_FORMAT_Z8, CHIMARA_IF_INTERPRETER_NITFOL);
+
g_object_set(glk,
"border-width", 6,
"spacing", 6,
error_dialog(GTK_WINDOW(window), error, "Error starting Glk library: ");
return 1;
}
+ //chimara_glk_run( CHIMARA_GLK(glk), ".libs/multiwin.so", argc, argv, NULL);
+
gdk_threads_enter();
gtk_main();
* text-align (left/right/center)
*/
grid.normal {
- font-size: 14;
+ font-size: 10;
}
grid.user1 {
}
buffer.normal {
- font-size: 14;
+ font-size: 10;
}
buffer.header {
- font-size: 18;
+ font-size: 14;
font-weight: bold;
text-align: center;
}
buffer.subheader {
- font-size: 16;
+ font-size: 12;
font-weight: bold;
}