Rearranged the Mluvnice exercises to a roadmap as is Deutsch and other subjects

This commit is contained in:
dvorakmortonxd 2026-09-15 12:45:36 +02:00
commit 2e6bd75546
5 changed files with 43 additions and 100 deletions

2
main.c
View file

@ -238,7 +238,7 @@ void activate(GtkApplication *app, gpointer user_data) {
for (int n = 1; n <= 20; n++) { for (int n = 1; n <= 20; n++) {
char name[16]; char name[16];
g_snprintf(name, sizeof(name), "mluv%d", n); g_snprintf(name, sizeof(name), "mluve%d", n);
gtk_stack_add_named(main_stack, gtk_stack_add_named(main_stack,
build_mluvnice_exercise_page(n), name); build_mluvnice_exercise_page(n), name);
} }

View file

@ -136,6 +136,7 @@ typedef struct {
const char *page; /* roadmap-stack child name, e.g. "unit1" */ const char *page; /* roadmap-stack child name, e.g. "unit1" */
const char *ex_tag; /* exercise page prefix, e.g. "u1" */ const char *ex_tag; /* exercise page prefix, e.g. "u1" */
const char *sub_key; /* i18n key for the exercise-map subtitle */ const char *sub_key; /* i18n key for the exercise-map subtitle */
const char *back_target; /* page the exercise map returns to */
const char *progress_file; const char *progress_file;
gboolean unlocked; gboolean unlocked;
gboolean done[MAX_UNIT_EX + 1]; /* exercise state, 1..n_ex */ gboolean done[MAX_UNIT_EX + 1]; /* exercise state, 1..n_ex */
@ -803,6 +804,7 @@ GtkWidget *build_czechmap_page(void);
void mluvnice_init(void); void mluvnice_init(void);
GtkWidget *build_mluvnice_page(void); GtkWidget *build_mluvnice_page(void);
GtkWidget *build_mluvnice_exercise_page(int n); GtkWidget *build_mluvnice_exercise_page(int n);
void mluvnice_refresh_ui(void);
GtkWidget *build_readinglist_page(void); GtkWidget *build_readinglist_page(void);
GtkWidget *build_cetba1984_page(void); GtkWidget *build_cetba1984_page(void);
GtkWidget *build_cetba1984_quiz_page(void); GtkWidget *build_cetba1984_quiz_page(void);

View file

@ -49,13 +49,49 @@ typedef struct {
static UnitCtx mluv_unit; static UnitCtx mluv_unit;
static const char *mluv_names[MLUV_N_EX] = {
"i/y", "Velká písmena", "Slovní druhy", "Podst. jména", "Slovesa",
"Slovotvorba", "Větné členy", "Vedlejší věty", "Synonyma", "Antonyma",
"s/z", "Najdi chybu", "Tvary", "Test A–D", "Přímá řeč",
"Rozdíly", "Interpunkce", "Obrazná pojmen.", "Slohové útvary",
"Opakování",
};
void mluvnice_init(void) { void mluvnice_init(void) {
mluv_unit.title = "Mluvnice";
mluv_unit.page = "mluvnice"; mluv_unit.page = "mluvnice";
mluv_unit.ex_tag = "mluv";
mluv_unit.sub_key = "Cvičení z mluvnice – styl maturita / "
"přijímačky z ČJL";
mluv_unit.back_target = "czechmap";
mluv_unit.progress_file = "progress/mluvnice.conf"; mluv_unit.progress_file = "progress/mluvnice.conf";
mluv_unit.n_ex = MLUV_N_EX; mluv_unit.n_ex = MLUV_N_EX;
for (int i = 0; i < MLUV_N_EX; i++)
mluv_unit.ex_names[i + 1] = mluv_names[i];
unit_load_progress(&mluv_unit); unit_load_progress(&mluv_unit);
} }
void mluvnice_refresh_ui(void) {
for (int i = 0; i < mluv_unit.n_ex; i++) {
GtkWidget *btn = mluv_unit.ex_cells[i];
if (!btn)
continue;
if (mluv_unit.done[i + 1]) {
gtk_widget_add_css_class(btn, "done");
if (mluv_unit.ex_icons[i + 1])
gtk_widget_set_visible(mluv_unit.ex_icons[i + 1], TRUE);
} else {
gtk_widget_remove_css_class(btn, "done");
if (mluv_unit.ex_icons[i + 1])
gtk_widget_set_visible(mluv_unit.ex_icons[i + 1], FALSE);
}
}
if (mluv_unit.ex_rail)
gtk_widget_queue_draw(mluv_unit.ex_rail);
}
static void mluv_check(GtkButton *button, gpointer data) { static void mluv_check(GtkButton *button, gpointer data) {
MluvCtx *ctx = data; MluvCtx *ctx = data;
int total = 0; int total = 0;
@ -742,103 +778,6 @@ GtkWidget *build_mluvnice_exercise_page(int n) {
} }
} }
static const struct {
const char *title;
const char *sub;
} mluv_defs[MLUV_N_EX] = {
{"Pravopis – i/y po obojetných souhláskách", "Doplňte i/í nebo y/ý."},
{"Pravopis – velká/malá písmena", "Vyberte správnou variantu."},
{"Slovní druhy", "Určete slovní druh podtržených slov."},
{"Mluvnické kategorie – podstatná jména",
"Určete rod, číslo a pád."},
{"Mluvnické kategorie – slovesa",
"Určete osobu, číslo, čas a způsob."},
{"Slovotvorba", "Rozeberte slova na morfémy."},
{"Větné členy", "Určete větný člen podtržených výrazů."},
{"Druhy vedlejších vět", "Určete druh vedlejší věty."},
{"Synonyma", "Ke každému slovu napište synonymum."},
{"Antonyma", "Napište opak."},
{"Pravopis – s/z na začátku slova",
"Vyberte správnou předponu s-/z-."},
{"Skladba – najděte chybu", "Najděte a opravte chybu ve větě."},
{"Tvarosloví – správný tvar", "Dejte slovo do správného tvaru."},
{"Výběr ze čtyř možností", "Vyberte správnou odpověď."},
{"Přímá a nepřímá řeč", "Přepište přímou řeč na nepřímou."},
{"Slovní zásoba – rozdíly", "Vysvětlete rozdíl mezi dvojicemi slov."},
{"Interpunkce", "Doplňte čárky tam, kde patří."},
{"Obrazná pojmenování", "Určete druh obrazného pojmenování."},
{"Stylistika – slohové útvary", "Přiřaďte ukázku ke slohovému útvaru."},
{"Souhrnné opakování", "Vyberte správnou odpověď."},
};
static GtkWidget *mluv_card(int n) {
GtkWidget *btn = gtk_button_new();
GtkWidget *box = gtk_box_new(GTK_ORIENTATION_VERTICAL, 3);
GtkWidget *t = gtk_label_new(NULL);
GtkWidget *s = gtk_label_new(mluv_defs[n - 1].sub);
char *full = g_strdup_printf("%d. %s", n, mluv_defs[n - 1].title);
char target[16];
gtk_widget_add_css_class(btn, "lit-link");
gtk_widget_set_hexpand(btn, TRUE);
gtk_widget_set_halign(t, GTK_ALIGN_START);
gtk_label_set_xalign(GTK_LABEL(t), 0.0);
gtk_label_set_wrap(GTK_LABEL(t), TRUE);
gtk_label_set_max_width_chars(GTK_LABEL(t), 52);
gtk_widget_add_css_class(t, "lit-link-title");
gtk_label_set_text(GTK_LABEL(t), full);
g_free(full);
gtk_box_append(GTK_BOX(box), t);
gtk_widget_set_halign(s, GTK_ALIGN_START);
gtk_label_set_xalign(GTK_LABEL(s), 0.0);
gtk_label_set_wrap(GTK_LABEL(s), TRUE);
gtk_label_set_max_width_chars(GTK_LABEL(s), 58);
gtk_widget_add_css_class(s, "lit-link-sub");
gtk_box_append(GTK_BOX(box), s);
gtk_widget_set_margin_top(box, 4);
gtk_widget_set_margin_bottom(box, 4);
gtk_widget_set_margin_start(box, 6);
gtk_widget_set_margin_end(box, 6);
gtk_button_set_child(GTK_BUTTON(btn), box);
g_snprintf(target, sizeof(target), "mluv%d", n);
g_object_set_data_full(G_OBJECT(btn), "target", g_strdup(target), g_free);
g_signal_connect(btn, "clicked", G_CALLBACK(on_nav_clicked), NULL);
return btn;
}
GtkWidget *build_mluvnice_page(void) { GtkWidget *build_mluvnice_page(void) {
GtkWidget *page; return build_unit_page(&mluv_unit);
GtkWidget *scroll;
GtkWidget *box;
page = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);
gtk_widget_set_margin_start(page, 32);
gtk_widget_set_margin_end(page, 32);
gtk_widget_set_margin_top(page, 24);
gtk_widget_set_margin_bottom(page, 24);
gtk_box_append(GTK_BOX(page),
top_bar("czechmap", "Mluvnice",
"Cvičení z mluvnice – styl maturita / "
"přijímačky z ČJL"));
scroll = gtk_scrolled_window_new();
gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroll),
GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
gtk_widget_set_vexpand(scroll, TRUE);
gtk_widget_set_margin_top(scroll, 14);
gtk_widget_set_margin_bottom(scroll, 14);
gtk_box_append(GTK_BOX(page), scroll);
box = gtk_box_new(GTK_ORIENTATION_VERTICAL, 10);
gtk_scrolled_window_set_child(GTK_SCROLLED_WINDOW(scroll), box);
for (int i = 1; i <= MLUV_N_EX; i++)
gtk_box_append(GTK_BOX(box), mluv_card(i));
return page;
} }

View file

@ -126,6 +126,7 @@ void refresh_completion_ui(void) {
all_rails_redraw(); all_rails_redraw();
refresh_net_completion_ui(); refresh_net_completion_ui();
refresh_hw_completion_ui(); refresh_hw_completion_ui();
mluvnice_refresh_ui();
refresh_stats_ui(); refresh_stats_ui();
} }

View file

@ -337,7 +337,8 @@ GtkWidget *build_unit_page(UnitCtx *u) {
gtk_widget_set_margin_bottom(page, 24); gtk_widget_set_margin_bottom(page, 24);
gtk_box_append(GTK_BOX(page), gtk_box_append(GTK_BOX(page),
top_bar("roadmap", u->title, u->sub_key)); top_bar(u->back_target ? u->back_target : "roadmap",
u->title, u->sub_key));
scroll = gtk_scrolled_window_new(); scroll = gtk_scrolled_window_new();
gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroll), gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroll),