Files

163 lines
7.4 KiB
C

// Copyright (c) 2026 Storm Dragon
// Authors: Storm Dragon, Angus Kola
// SPDX-License-Identifier: GPL-3.0-or-later
#include "native_internal.h"
static GtkListStore *reading_store;
static const struct { const char *id; const char *label; } reading_rows[] = {
{"only_speak_displayed_text", "Only speak displayed text"},
{"automatically_read_title_changes", "Automatically read title changes"},
{"automatically_read_clipboard_changes", "Automatically read clipboard changes"},
{"enable_pause_breaks", "Break speech into chunks between pauses"},
{"speak_numbers_as_digits", "Speak numbers as digits"},
{"speak_multicase_strings_as_words", "Speak multicase strings as words"},
{"enable_indentation", "Enable indentation presentation"},
{"speak_blank_lines", "Speak blank lines"},
{"enable_mnemonic_speaking", "Speak object mnemonics"},
{"enable_position_speaking", "Speak child position"},
{"enable_tutorial_messages", "Speak tutorial messages"},
{"speak_description", "Speak object descriptions"},
{"messages_are_detailed", "System messages are detailed"},
{"use_color_names", "Speak colors as names"},
{"speak_misspelled_indicator", "Speak misspelled-word indicator"},
{"speak_context_blockquote", "Announce block quotes during navigation"},
{"speak_context_list", "Announce lists during navigation"},
{"speak_context_table", "Announce tables during navigation"},
{"speak_context_panel", "Announce panels during navigation"},
{"speak_context_landmark", "Announce landmarks during navigation"},
{"speak_context_non_landmark_form", "Announce forms during navigation"},
{"read_full_row_in_gui_table", "Speak full row in GUI tables"},
{"read_full_row_in_document_table", "Speak full row in document tables"},
{"read_full_row_in_spreadsheet", "Speak full row in spreadsheets"},
{"present_tooltips", "Present tooltips"},
{"enable_mouse_review", "Speak object under mouse"},
{"say_all_context_blockquote", "Announce block quotes in Say All"},
{"say_all_context_list", "Announce lists in Say All"},
{"say_all_context_table", "Announce tables in Say All"},
{"say_all_context_panel", "Announce panels in Say All"},
{"say_all_context_non_landmark_form", "Announce forms in Say All"},
{"say_all_context_landmark", "Announce landmarks in Say All"},
};
enum {
READING_ID,
READING_LABEL,
READING_ENABLED,
READING_N_COLUMNS
};
static void name_reading_toggle_cells(void);
static void reading_toggled(GtkCellRendererToggle *renderer, gchar *path_string, gpointer data) {
(void)renderer; (void)data;
GtkTreeIter iter;
if (!gtk_tree_model_get_iter_from_string(GTK_TREE_MODEL(reading_store), &iter, path_string)) {
return;
}
gboolean active;
gtk_tree_model_get(GTK_TREE_MODEL(reading_store), &iter, READING_ENABLED, &active, -1);
gtk_list_store_set(reading_store, &iter, READING_ENABLED, !active, -1);
name_reading_toggle_cells();
}
static gboolean reading_key_press(GtkWidget *widget, GdkEventKey *event, gpointer data) {
(void)data;
if (event->keyval != GDK_KEY_space && event->keyval != GDK_KEY_KP_Space) return FALSE;
GtkTreePath *path = NULL;
gtk_tree_view_get_cursor(GTK_TREE_VIEW(widget), &path, NULL);
if (!path) return FALSE;
GtkTreeIter iter;
gboolean found = gtk_tree_model_get_iter(GTK_TREE_MODEL(reading_store), &iter, path);
gtk_tree_path_free(path);
if (!found) return FALSE;
gboolean active;
gtk_tree_model_get(GTK_TREE_MODEL(reading_store), &iter, READING_ENABLED, &active, -1);
gtk_list_store_set(reading_store, &iter, READING_ENABLED, !active, -1);
name_reading_toggle_cells();
return TRUE;
}
static void name_reading_toggle_cells(void) {
AtkObject *accessible = gtk_widget_get_accessible(prefs_widget("readingSettingsTreeview"));
if (!ATK_IS_TABLE(accessible)) return;
for (unsigned int i = 0; i < G_N_ELEMENTS(reading_rows); i++) {
AtkObject *cell = atk_table_ref_at(ATK_TABLE(accessible), i, 0);
if (!cell) continue;
GtkTreeIter iter;
gboolean active = FALSE;
if (gtk_tree_model_iter_nth_child(GTK_TREE_MODEL(reading_store), &iter, NULL, i))
gtk_tree_model_get(GTK_TREE_MODEL(reading_store), &iter, READING_ENABLED, &active, -1);
const char *name = active ? "checked" : "unchecked";
if (g_strcmp0(atk_object_get_name(cell), name) != 0) atk_object_set_name(cell, name);
g_object_unref(cell);
}
}
void prefs_init_reading_settings(void) {
reading_store = gtk_list_store_new(READING_N_COLUMNS, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_BOOLEAN);
for (unsigned int i = 0; i < G_N_ELEMENTS(reading_rows); i++) {
GtkTreeIter iter;
gtk_list_store_append(reading_store, &iter);
gtk_list_store_set(reading_store, &iter,
READING_ID, reading_rows[i].id,
READING_LABEL, reading_rows[i].label,
READING_ENABLED, FALSE,
-1);
}
GtkTreeView *view = GTK_TREE_VIEW(prefs_widget("readingSettingsTreeview"));
gtk_tree_view_set_model(view, GTK_TREE_MODEL(reading_store));
gtk_tree_view_set_headers_visible(view, TRUE);
GtkCellRenderer *text_renderer = gtk_cell_renderer_text_new();
GtkTreeViewColumn *setting_column = gtk_tree_view_column_new_with_attributes(
"Setting", text_renderer, "text", READING_LABEL, NULL);
GtkCellRenderer *toggle_renderer = gtk_cell_renderer_toggle_new();
g_object_set(toggle_renderer, "activatable", TRUE, NULL);
g_signal_connect(toggle_renderer, "toggled", G_CALLBACK(reading_toggled), NULL);
GtkTreeViewColumn *enabled_column = gtk_tree_view_column_new_with_attributes(
"Enabled", toggle_renderer, "active", READING_ENABLED, NULL);
gtk_tree_view_append_column(view, enabled_column);
gtk_tree_view_append_column(view, setting_column);
g_signal_connect(view, "key-press-event", G_CALLBACK(reading_key_press), NULL);
name_reading_toggle_cells();
}
void prefs_reading_set(const char *id, int value) {
GtkTreeIter iter;
gboolean valid = gtk_tree_model_get_iter_first(GTK_TREE_MODEL(reading_store), &iter);
while (valid) {
gchar *row_id;
gboolean active;
gtk_tree_model_get(GTK_TREE_MODEL(reading_store), &iter,
READING_ID, &row_id, READING_ENABLED, &active, -1);
if (g_strcmp0(row_id, id) == 0) {
if (active != (value != 0)) {
gtk_list_store_set(reading_store, &iter, READING_ENABLED, value != 0, -1);
name_reading_toggle_cells();
}
g_free(row_id);
return;
}
g_free(row_id);
valid = gtk_tree_model_iter_next(GTK_TREE_MODEL(reading_store), &iter);
}
}
int prefs_reading_get(const char *id) {
GtkTreeIter iter;
gboolean valid = gtk_tree_model_get_iter_first(GTK_TREE_MODEL(reading_store), &iter);
while (valid) {
gchar *row_id;
gtk_tree_model_get(GTK_TREE_MODEL(reading_store), &iter, READING_ID, &row_id, -1);
if (g_strcmp0(row_id, id) == 0) {
gboolean active;
gtk_tree_model_get(GTK_TREE_MODEL(reading_store), &iter, READING_ENABLED, &active, -1);
g_free(row_id);
return active ? 1 : 0;
}
g_free(row_id);
valid = gtk_tree_model_iter_next(GTK_TREE_MODEL(reading_store), &iter);
}
return 0;
}