Graduately/exercise_u3.c

1279 lines
46 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include "maturita.h"
/* ------------------------------------------------------------------ */
/* Unit 3 exercises ("Bei uns zu Hause") */
/* ------------------------------------------------------------------ */
/* Sentence fill-ins: a row is made of literal text segments that
* alternate with one or more blank widgets (dropdowns). `num` is the
* optional item number shown at the start of the line. */
/* Build the complete German sentence of a fill row (segments spliced
* with the correct answers) – used as the model shown after Check. */
char *u3_fill_sentence(const U3Fill *f) {
const char *segs[4];
const char *ans[3];
GString *s;
int i, g;
segs[0] = f->s0;
segs[1] = f->s1;
segs[2] = f->s2;
segs[3] = f->s3;
ans[0] = f->a0;
ans[1] = f->a1;
ans[2] = f->a2;
g = 0;
while (g < 3 && ans[g])
g++;
s = g_string_new(NULL);
for (i = 0; i <= g; i++) {
if (segs[i] && segs[i][0])
g_string_append(s, segs[i]);
if (i < g && ans[i])
g_string_append(s, ans[i]);
}
if (s->len == 0) {
g_string_free(s, TRUE);
return NULL;
}
return g_string_free(s, FALSE);
}
/* Append one horizontal fill row to `body`. The answer of blank i sits
* between text segments s[i] and s[i+1]; empty segments are skipped.
* `gloss` (may be NULL) is an i18n key for a small grey note shown at
* the end of the line, e.g. the meaning of the expected possessive. */
void u3_fill_row(ComboListCtx *ctx, GtkWidget *body, const U3Fill *f,
const char **pool, int pool_n, const char *gloss) {
const char *segs[4];
const char *ans[3];
int i, g;
GtkWidget *line;
segs[0] = f->s0;
segs[1] = f->s1;
segs[2] = f->s2;
segs[3] = f->s3;
ans[0] = f->a0;
ans[1] = f->a1;
ans[2] = f->a2;
g = 0;
while (g < 3 && ans[g])
g++;
line = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 6);
gtk_widget_set_halign(line, GTK_ALIGN_START);
gtk_box_append(GTK_BOX(body), line);
if (f->num && f->num[0]) {
GtkWidget *nl = gtk_label_new(f->num);
gtk_widget_set_valign(nl, GTK_ALIGN_CENTER);
gtk_widget_add_css_class(nl, "ex-prompt");
gtk_box_append(GTK_BOX(line), nl);
}
for (i = 0; i <= g; i++) {
if (segs[i] && segs[i][0]) {
GtkWidget *lb = gtk_label_new(segs[i]);
gtk_widget_set_valign(lb, GTK_ALIGN_CENTER);
gtk_widget_add_css_class(lb, "ex-prompt");
gtk_box_append(GTK_BOX(line), lb);
}
if (i < g) {
GtkWidget *combo = make_word_combo(pool, pool_n);
gtk_widget_set_size_request(combo, 96, -1);
gtk_widget_set_valign(combo, GTK_ALIGN_CENTER);
gtk_box_append(GTK_BOX(line), combo);
combo_list_add(ctx, combo, ans[i]);
}
}
if (gloss && gloss[0]) {
GtkWidget *gl = gtk_label_new(NULL);
i18n_bind(gl, gloss, 0);
gtk_widget_set_valign(gl, GTK_ALIGN_CENTER);
gtk_widget_set_margin_start(gl, 8);
gtk_widget_add_css_class(gl, "meaning");
gtk_box_append(GTK_BOX(line), gl);
}
if (f->mean && f->mean[0]) {
GtkWidget *m = meaning_add(body, f->mean);
combo_list_add_trans(ctx, m);
if (ctx->trans_upfront)
gtk_widget_set_visible(m, TRUE);
}
if (ctx->reveal_german) {
char *sentence = u3_fill_sentence(f);
if (sentence && sentence[0]) {
GtkWidget *w = model_answer_add(body, sentence);
g_array_append_val(ctx->models, w);
}
g_free(sentence);
}
}
void u3_sample_line(GtkWidget *body, const char *text) {
GtkWidget *sl = gtk_label_new(text);
gtk_widget_set_halign(sl, GTK_ALIGN_START);
gtk_widget_set_margin_top(sl, 2);
gtk_widget_set_margin_bottom(sl, 4);
gtk_widget_add_css_class(sl, "hint");
gtk_label_set_wrap(GTK_LABEL(sl), TRUE);
gtk_box_append(GTK_BOX(body), sl);
}
GtkWidget *u3_build_drop(UnitCtx *unit, int ex_num, const char *title,
const char *sub, const char *sample,
const U3Fill *rows, int n,
const char **pool, int pool_n,
const char **glosses, gboolean show_german) {
GtkWidget *body, *feedback, *check;
GtkWidget *page = ex_page_shell(unit->page, title, sub, "check",
&body, &feedback, &check);
ComboListCtx *ctx = combo_list_ctx_new(unit, ex_num, feedback);
ctx->trans_upfront = show_german;
ctx->reveal_german = show_german;
if (sample && sample[0])
u3_sample_line(body, sample);
for (int i = 0; i < n; i++)
u3_fill_row(ctx, body, &rows[i], pool, pool_n,
glosses ? glosses[i] : NULL);
g_signal_connect(check, "clicked", G_CALLBACK(combo_list_check), ctx);
return page;
}
/* ---- ex1: Familienpaare (match the pair) ---------------------------- */
const char *ex1_u3_pool[] = {
"die Cousine", "die Tante", "die Oma", "der Bruder",
"die Freundin", "der Sohn",
};
const U3Fill ex1_u3_rows[] = {
{"1.", "der Cousin", "die Cousine", NULL, NULL, NULL, NULL, NULL,
"bratranec / sestřenice"},
{"2.", "der Onkel", "die Tante", NULL, NULL, NULL, NULL, NULL,
"strýc / teta"},
{"3.", "der Opa", "die Oma", NULL, NULL, NULL, NULL, NULL,
"dědeček / babička"},
{"4.", "die Schwester", "der Bruder", NULL, NULL, NULL, NULL, NULL,
"sestra / bratr"},
{"5.", "der Freund", "die Freundin", NULL, NULL, NULL, NULL, NULL,
"kamarád / kamarádka"},
{"6.", "die Tochter", "der Sohn", NULL, NULL, NULL, NULL, NULL,
"dcera / syn"},
};
GtkWidget *u3ex1(UnitCtx *unit) {
return u3_build_drop(unit, 1, "Familienpaare", "sub3_pair",
"Beispiel: der Vater ↔ die Mutter",
ex1_u3_rows, G_N_ELEMENTS(ex1_u3_rows),
ex1_u3_pool, G_N_ELEMENTS(ex1_u3_pool), NULL, FALSE);
}
/* ---- ex2: Possessivpronomen im Nominativ ----------------------------- */
const char *ex2_u3_pool[] = {
"dein", "deine", "mein", "meine", "sein", "seine",
};
/* The Czech sentence is shown straight away, and pressing "Check" only
* adds the translations of the words the student picked in the blanks. */
const Ex2Row ex2_u3_rows2[] = {
{"2.", {"Ist das ", " Mutter? – Nein, das ist nicht ", " Mutter.", NULL},
{"deine", "meine", NULL}, 2},
{NULL, {"Das ist ", " Tante.", NULL, NULL}, {"seine", NULL, NULL}, 1},
};
const Ex2Row ex2_u3_rows3[] = {
{"3.", {"Ist das ", " Bruder? – Nein, das ist nicht ", " Bruder.", NULL},
{"dein", "mein", NULL}, 2},
{NULL, {"Das ist ", " Cousin.", NULL, NULL}, {"sein", NULL, NULL}, 1},
};
const Ex2Row ex2_u3_rows4[] = {
{"4.",
{"Sind das ", " Eltern? – Nein, das sind nicht ",
" Eltern. Das sind die Eltern von Markus.", NULL},
{"deine", "meine", NULL}, 2},
};
const Ex2Item ex2_u3_items[] = {
{"Je to tvoje matka? – Ne, to není moje matka. To je jeho teta.",
ex2_u3_rows2, G_N_ELEMENTS(ex2_u3_rows2)},
{"Je to tvůj bratr? – Ne, to není můj bratr. To je jeho bratranec.",
ex2_u3_rows3, G_N_ELEMENTS(ex2_u3_rows3)},
{"Jsou to tvoji rodiče? – Ne, to nejsou moji rodiče. To jsou rodiče "
"Markuse.",
ex2_u3_rows4, G_N_ELEMENTS(ex2_u3_rows4)},
};
const char *ex2_word_cs(const char *w) {
if (!w)
return NULL;
if (g_strcmp0(w, "dein") == 0) return "tvůj";
if (g_strcmp0(w, "deine") == 0) return "tvoje";
if (g_strcmp0(w, "mein") == 0) return "můj";
if (g_strcmp0(w, "meine") == 0) return "moje";
if (g_strcmp0(w, "sein") == 0) return "jeho";
if (g_strcmp0(w, "seine") == 0) return "jeho";
return NULL;
}
void ex2_check(GtkButton *button, gpointer data) {
Ex2Ctx *ctx = data;
guint total = ctx->combos->len;
guint ok = 0;
(void)button;
for (guint i = 0; i < total; i++) {
GtkComboBox *combo = g_array_index(ctx->combos, GtkComboBox *, i);
const char *ans = g_array_index(ctx->answers, const char *, i);
gchar *sel = gtk_combo_box_text_get_active_text(
GTK_COMBO_BOX_TEXT(combo));
gboolean good = FALSE;
if (sel) {
gchar *t = normalize_answer(sel);
good = answer_accepts(t, ans);
g_free(t);
g_free(sel);
}
answer_mark(GTK_WIDGET(combo), good);
if (good)
ok++;
}
for (int it = 0; it < ctx->n_items; it++) {
GArray *item = ctx->item_combos[it];
GtkWidget *note = ctx->notes[it];
GString *s = g_string_new(NULL);
for (guint k = 0; k < item->len; k++) {
GtkComboBox *combo = g_array_index(item, GtkComboBox *, k);
gchar *sel = gtk_combo_box_text_get_active_text(
GTK_COMBO_BOX_TEXT(combo));
const char *cs;
if (sel) {
cs = ex2_word_cs(sel);
if (cs) {
if (s->len > 0)
g_string_append(s, " · ");
g_string_append_printf(s, "%s = %s", sel, tr(cs));
}
g_free(sel);
}
}
gtk_label_set_text(GTK_LABEL(note), s->str);
g_string_free(s, TRUE);
gtk_widget_set_visible(note, TRUE);
}
if (ok == total) {
set_feedback(ctx->feedback, TRUE, tr("feedback_ok"));
mark_done(ctx->unit, ctx->ex_num);
} else {
set_feedback(ctx->feedback, FALSE, tr("feedback_retry"));
}
}
GtkWidget *u3ex2(UnitCtx *unit) {
GtkWidget *body, *feedback, *check;
GtkWidget *page = ex_page_shell(unit->page, "mein oder dein", "sub3_poss",
"check", &body, &feedback, &check);
Ex2Ctx *ctx = g_new0(Ex2Ctx, 1);
ctx->combos = g_array_new(FALSE, FALSE, sizeof(GtkComboBox *));
ctx->answers = g_array_new(FALSE, FALSE, sizeof(const char *));
ctx->n_items = G_N_ELEMENTS(ex2_u3_items);
ctx->notes = g_new0(GtkWidget *, ctx->n_items);
ctx->item_combos = g_new0(GArray *, ctx->n_items);
ctx->unit = unit;
ctx->ex_num = 2;
ctx->feedback = feedback;
u3_sample_line(body, "Beispiel: Ist das dein Vater? – Nein, das ist "
"nicht mein Vater. Das ist sein Onkel.");
for (int it = 0; it < ctx->n_items; it++) {
const Ex2Item *item = &ex2_u3_items[it];
GtkWidget *mean;
GtkWidget *note;
GArray *item_combos = g_array_new(FALSE, FALSE,
sizeof(GtkComboBox *));
ctx->item_combos[it] = item_combos;
for (int r = 0; r < item->nrows; r++) {
const Ex2Row *row = &item->rows[r];
GtkWidget *line = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 6);
gtk_widget_set_halign(line, GTK_ALIGN_START);
if (row->num && row->num[0]) {
GtkWidget *nl = gtk_label_new(row->num);
gtk_widget_set_valign(nl, GTK_ALIGN_CENTER);
gtk_widget_add_css_class(nl, "ex-prompt");
gtk_box_append(GTK_BOX(line), nl);
}
for (int i = 0; i <= row->gaps; i++) {
if (row->seg[i] && row->seg[i][0]) {
GtkWidget *lb = gtk_label_new(row->seg[i]);
gtk_widget_set_valign(lb, GTK_ALIGN_CENTER);
gtk_widget_add_css_class(lb, "ex-prompt");
gtk_box_append(GTK_BOX(line), lb);
}
if (i < row->gaps) {
GtkWidget *combo = make_word_combo(ex2_u3_pool,
G_N_ELEMENTS(ex2_u3_pool));
gtk_widget_set_size_request(combo, 96, -1);
gtk_widget_set_valign(combo, GTK_ALIGN_CENTER);
gtk_box_append(GTK_BOX(line), combo);
g_array_append_val(ctx->combos, combo);
g_array_append_val(item_combos, combo);
g_array_append_val(ctx->answers, row->ans[i]);
}
}
gtk_box_append(GTK_BOX(body), line);
}
/* Czech sentence is available before checking. */
mean = meaning_add(body, item->czech);
gtk_widget_set_visible(mean, TRUE);
/* word translations appear only after pressing "Check". */
note = gtk_label_new(NULL);
gtk_widget_set_halign(note, GTK_ALIGN_START);
gtk_widget_set_margin_bottom(note, 2);
gtk_widget_add_css_class(note, "meaning");
gtk_label_set_wrap(GTK_LABEL(note), TRUE);
gtk_widget_set_visible(note, FALSE);
gtk_box_append(GTK_BOX(body), note);
ctx->notes[it] = note;
}
g_signal_connect(check, "clicked", G_CALLBACK(ex2_check), ctx);
return page;
}
/* ---- ex3: Haustiere – ein/kein --------------------------------------- */
const char *ex3_u3_pool[] = {
"ein", "eine", "einen", "kein", "keine", "keinen",
};
const U3Fill ex3_u3_rows[] = {
{"2.", "Hast du ", "einen",
" Hamster? – Nein, ich habe ", "keinen", " Hamster.", NULL, NULL,
NULL},
{NULL, "Ich habe ", "eine", " Schildkröte.", NULL, NULL, NULL, NULL,
"Máš křečka? – Ne, nemám křečka. Mám želvu."},
{"3.", "Hast du ", "ein",
" Pferd? – Nein, ich habe ", "kein", " Pferd.", NULL, NULL, NULL},
{NULL, "Ich habe ", "ein", " Kaninchen.", NULL, NULL, NULL, NULL,
"Máš koně? – Ne, nemám koně. Mám králíka."},
{"4.", "Hast du ", "einen",
" Fisch? – Nein, ich habe ", "keinen", " Fisch.", NULL, NULL, NULL},
{NULL, "Ich habe ", "einen", " Vogel.", NULL, NULL, NULL, NULL,
"Máš rybu? – Ne, nemám rybu. Mám ptáka."},
{"5.", "Hast du ", "ein",
" Meerschweinchen? – Nein, ich habe ", "kein",
" Meerschweinchen.", NULL, NULL, NULL},
{NULL, "Ich habe ", "einen", " Wellensittich.", NULL, NULL, NULL, NULL,
"Máš morče? – Ne, nemám morče. Mám andulku."},
};
GtkWidget *u3ex3(UnitCtx *unit) {
return u3_build_drop(unit, 3, "ein / kein", "sub3_haustier",
"Beispiel: Hast du eine Katze? – Nein, ich habe "
"keine Katze. Ich habe einen Hund.",
ex3_u3_rows, G_N_ELEMENTS(ex3_u3_rows),
ex3_u3_pool, G_N_ELEMENTS(ex3_u3_pool), NULL, TRUE);
}
/* ---- inline letter-gap rows (ex15) ----------------------------------- */
/* One sentence row whose text is split into segments with up to four
* small text entries (one per missing-letter group) inserted. */
U3LetCtx *u3_let_ctx_new(UnitCtx *unit, int ex_num,
GtkWidget *feedback) {
U3LetCtx *ctx = g_new0(U3LetCtx, 1);
ctx->entries = g_array_new(FALSE, FALSE, sizeof(GtkWidget *));
ctx->answers = g_array_new(FALSE, FALSE, sizeof(const char *));
ctx->trans = g_array_new(FALSE, FALSE, sizeof(GtkWidget *));
ctx->models = g_array_new(FALSE, FALSE, sizeof(GtkWidget *));
ctx->unit = unit;
ctx->ex_num = ex_num;
ctx->feedback = feedback;
return ctx;
}
/* Rebuild the full German sentence (letter gaps filled in). */
char *u3_let_sentence(const U3Let *row) {
const char *segs[5];
const char *ans[4];
GString *s;
int i, g;
segs[0] = row->s0;
segs[1] = row->s1;
segs[2] = row->s2;
segs[3] = row->s3;
segs[4] = row->s4;
ans[0] = row->a0;
ans[1] = row->a1;
ans[2] = row->a2;
ans[3] = row->a3;
g = 0;
while (g < 4 && ans[g])
g++;
s = g_string_new(NULL);
for (i = 0; i <= g; i++) {
if (segs[i] && segs[i][0])
g_string_append(s, segs[i]);
if (i < g && ans[i])
g_string_append(s, ans[i]);
}
if (s->len == 0) {
g_string_free(s, TRUE);
return NULL;
}
return g_string_free(s, FALSE);
}
void u3_let_check(GtkButton *button, gpointer data) {
U3LetCtx *ctx = data;
guint total = ctx->entries->len;
guint ok = 0;
(void)button;
for (guint i = 0; i < total; i++) {
GtkWidget *e = g_array_index(ctx->entries, GtkWidget *, i);
const char *ans = g_array_index(ctx->answers, const char *, i);
const gchar *txt = gtk_editable_get_text(GTK_EDITABLE(e));
gchar *norm = normalize_answer(txt);
gboolean good = txt && txt[0] && answer_accepts(norm, ans);
g_free(norm);
answer_mark(e, good);
if (good)
ok++;
}
for (guint i = 0; i < ctx->trans->len; i++) {
GtkWidget *lbl = g_array_index(ctx->trans, GtkWidget *, i);
if (lbl)
gtk_widget_set_visible(lbl, TRUE);
}
for (guint i = 0; i < ctx->models->len; i++) {
GtkWidget *lbl = g_array_index(ctx->models, GtkWidget *, i);
if (lbl)
gtk_widget_set_visible(lbl, TRUE);
}
if (ok == total) {
set_feedback(ctx->feedback, TRUE, tr("feedback_ok"));
mark_done(ctx->unit, ctx->ex_num);
} else {
set_feedback(ctx->feedback, FALSE, tr("feedback_retry"));
}
}
void u3_let_row(U3LetCtx *ctx, GtkWidget *body, const U3Let *row) {
const char *segs[5];
const char *ans[4];
int i, g;
GtkWidget *line;
segs[0] = row->s0;
segs[1] = row->s1;
segs[2] = row->s2;
segs[3] = row->s3;
segs[4] = row->s4;
ans[0] = row->a0;
ans[1] = row->a1;
ans[2] = row->a2;
ans[3] = row->a3;
g = 0;
while (g < 4 && ans[g])
g++;
line = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 4);
gtk_widget_set_halign(line, GTK_ALIGN_START);
gtk_box_append(GTK_BOX(body), line);
if (row->num && row->num[0]) {
GtkWidget *nl = gtk_label_new(row->num);
gtk_widget_set_valign(nl, GTK_ALIGN_CENTER);
gtk_widget_add_css_class(nl, "ex-prompt");
gtk_box_append(GTK_BOX(line), nl);
}
for (i = 0; i <= g; i++) {
if (segs[i] && segs[i][0]) {
GtkWidget *lb = gtk_label_new(segs[i]);
gtk_widget_set_valign(lb, GTK_ALIGN_CENTER);
gtk_widget_add_css_class(lb, "ex-prompt");
gtk_box_append(GTK_BOX(line), lb);
}
if (i < g) {
GtkWidget *e = gtk_entry_new();
gtk_editable_set_width_chars(GTK_EDITABLE(e), 4);
gtk_widget_set_valign(e, GTK_ALIGN_CENTER);
gtk_box_append(GTK_BOX(line), e);
g_array_append_val(ctx->entries, e);
g_array_append_val(ctx->answers, ans[i]);
}
}
if (row->mean && row->mean[0]) {
GtkWidget *m = meaning_add(body, row->mean);
gtk_widget_set_visible(m, TRUE);
g_array_append_val(ctx->trans, m);
}
{
char *sentence = u3_let_sentence(row);
if (sentence && sentence[0]) {
GtkWidget *w = model_answer_add(body, sentence);
g_array_append_val(ctx->models, w);
}
g_free(sentence);
}
}
GtkWidget *u3_build_letters(UnitCtx *unit, int ex_num,
const char *title, const char *sub,
const U3Let *rows, int n) {
GtkWidget *body, *feedback, *check;
GtkWidget *page = ex_page_shell(unit->page, title, sub, "check",
&body, &feedback, &check);
U3LetCtx *ctx = u3_let_ctx_new(unit, ex_num, feedback);
{
gboolean need = FALSE;
for (int i = 0; i < n && !need; i++) {
const U3Let *r = &rows[i];
need = text_has_german_umlaut(r->s0) ||
text_has_german_umlaut(r->s1) ||
text_has_german_umlaut(r->s2) ||
text_has_german_umlaut(r->s3) ||
text_has_german_umlaut(r->s4) ||
text_has_german_umlaut(r->a0) ||
text_has_german_umlaut(r->a1) ||
text_has_german_umlaut(r->a2) ||
text_has_german_umlaut(r->a3);
}
if (need)
add_umlaut_note(body);
}
for (int i = 0; i < n; i++)
u3_let_row(ctx, body, &rows[i]);
g_signal_connect(check, "clicked", G_CALLBACK(u3_let_check), ctx);
return page;
}
/* ---- ex4: missing letters in a paragraph ----------------------------- */
/* The Czech sentence is shown straight away; pressing "Check" only adds
* the translations of the words the student had to complete. */
const Ex4Row ex4_u3_rows[] = {
{{"Wir hab", "n Fre", "nde in Öster", "ich. Sie wo", "nen in Wien."},
{"e", "u", "re", "h"},
"Máme přátele v Rakousku. Bydlí ve Vídni.",
{"haben", "Freunde", "Österreich", "wohnen"},
{"mít", "přátelé", "Rakousko", "bydlet"}, 4},
{{"Sie hei", "en Elfriede und Jiri. Sie haben auch ", "inder.", NULL,
NULL},
{"ß", "K", NULL, NULL},
"Jmenují se Elfriede a Jiří. Mají také děti.",
{"heißen", "Kinder", NULL, NULL},
{"jmenovat se", "děti", NULL, NULL}, 2},
{{"Ihr S", "hn heißt Philipp und ihr", " Tochter heißt Sabine.", NULL,
NULL},
{"o", "e", NULL, NULL},
"Jejich syn se jmenuje Philipp a jejich dcera Sabine.",
{"Sohn", "ihre", NULL, NULL},
{"syn", "jejich", NULL, NULL}, 2},
{{"Die Famili", " re", "st gern.", NULL, NULL},
{"e", "i", NULL, NULL},
"Rodina ráda cestuje.",
{"Familie", "reist", NULL, NULL},
{"rodina", "cestuje", NULL, NULL}, 2},
{{"Sie ist o", "t bei uns zu Bes", "ch in Tsche", "ien.", NULL},
{"f", "u", "ch", NULL},
"Často je u nás na návštěvě v Česku.",
{"oft", "Besuch", "Tschechien", NULL},
{"často", "návštěva", "Česko", NULL}, 3},
{{"Die Kinder ler", "en auch Tsche", "isch.", NULL, NULL},
{"n", "ch", NULL, NULL},
"Děti se učí také česky.",
{"lernen", "Tschechisch", NULL, NULL},
{"učit se", "čeština", NULL, NULL}, 2},
};
void ex4_check(GtkButton *button, gpointer data) {
Ex4LetterCtx *ctx = data;
guint total = ctx->entries->len;
guint ok = 0;
(void)button;
for (guint i = 0; i < total; i++) {
GtkWidget *e = g_array_index(ctx->entries, GtkWidget *, i);
const char *ans = g_array_index(ctx->answers, const char *, i);
const gchar *txt = gtk_editable_get_text(GTK_EDITABLE(e));
gchar *norm = normalize_answer(txt);
gboolean good = txt && txt[0] && answer_accepts(norm, ans);
g_free(norm);
answer_mark(e, good);
if (good)
ok++;
}
for (int r = 0; r < ctx->n_rows; r++) {
const Ex4Row *row = &ctx->rows[r];
GtkWidget *note = ctx->notes[r];
GString *s = g_string_new(NULL);
for (int k = 0; k < row->gaps; k++) {
if (k > 0)
g_string_append(s, " · ");
if (row->word[k])
g_string_append_printf(s, "%s = %s", row->word[k],
tr(row->gmean[k]));
}
gtk_label_set_text(GTK_LABEL(note), s->str);
g_string_free(s, TRUE);
gtk_widget_set_visible(note, TRUE);
}
if (ok == total) {
set_feedback(ctx->feedback, TRUE, tr("feedback_ok"));
mark_done(ctx->unit, ctx->ex_num);
} else {
set_feedback(ctx->feedback, FALSE, tr("feedback_retry"));
}
}
GtkWidget *u3ex4(UnitCtx *unit) {
GtkWidget *body, *feedback, *check;
GtkWidget *page = ex_page_shell(unit->page, "Lückentext", "sub3_buchst",
"check", &body, &feedback, &check);
Ex4LetterCtx *ctx = g_new0(Ex4LetterCtx, 1);
ctx->entries = g_array_new(FALSE, FALSE, sizeof(GtkWidget *));
ctx->answers = g_array_new(FALSE, FALSE, sizeof(const char *));
ctx->rows = ex4_u3_rows;
ctx->n_rows = G_N_ELEMENTS(ex4_u3_rows);
ctx->notes = g_new0(GtkWidget *, ctx->n_rows);
ctx->unit = unit;
ctx->ex_num = 4;
ctx->feedback = feedback;
{
gboolean need = FALSE;
for (int r = 0; r < ctx->n_rows && !need; r++) {
for (int i = 0; i < ctx->rows[r].gaps; i++) {
if (text_has_german_umlaut(ctx->rows[r].ans[i]) ||
text_has_german_umlaut(ctx->rows[r].word[i])) {
need = TRUE;
break;
}
}
}
if (need)
add_umlaut_note(body);
}
for (int r = 0; r < ctx->n_rows; r++) {
const Ex4Row *row = &ctx->rows[r];
GtkWidget *line = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 4);
GtkWidget *mean;
GtkWidget *note;
gtk_widget_set_halign(line, GTK_ALIGN_START);
for (int i = 0; i <= row->gaps; i++) {
if (row->seg[i] && row->seg[i][0]) {
GtkWidget *lb = gtk_label_new(row->seg[i]);
gtk_widget_set_valign(lb, GTK_ALIGN_CENTER);
gtk_widget_add_css_class(lb, "ex-prompt");
gtk_box_append(GTK_BOX(line), lb);
}
if (i < row->gaps) {
GtkWidget *e = gtk_entry_new();
gtk_editable_set_width_chars(GTK_EDITABLE(e), 4);
gtk_widget_set_valign(e, GTK_ALIGN_CENTER);
gtk_box_append(GTK_BOX(line), e);
g_array_append_val(ctx->entries, e);
g_array_append_val(ctx->answers, row->ans[i]);
}
}
gtk_box_append(GTK_BOX(body), line);
/* the Czech sentence is available before checking */
mean = meaning_add(body, row->czech);
gtk_widget_set_visible(mean, TRUE);
/* gapped-word translations appear only after "Check" */
note = gtk_label_new(NULL);
gtk_widget_set_halign(note, GTK_ALIGN_START);
gtk_widget_set_margin_bottom(note, 2);
gtk_widget_add_css_class(note, "meaning");
gtk_label_set_wrap(GTK_LABEL(note), TRUE);
gtk_widget_set_visible(note, FALSE);
gtk_box_append(GTK_BOX(body), note);
ctx->notes[r] = note;
}
g_signal_connect(check, "clicked", G_CALLBACK(ex4_check), ctx);
return page;
}
/* ---- ex5: Marcos Familie (word-bank typing) -------------------------- */
const char *ex5_u3_bank =
"Tanten | Job | Vater | Ferien | Zwillinge | Eltern | Kroatien";
const TypedQ ex5_u3_rows[] = {
{"Wir haben eine Männer-Wohngemeinschaft: Mein ________ Johann (50), "
"Ivo (16) und ich.",
"vater", "Máme mužskou domácnost: Můj otec Johann (50), Ivo (16) a já."},
{"Ivo und ich sind gleich alt – wir sind nämlich ________.",
"zwillinge", "Ivo a já jsme stejně staří – jsme totiž dvojčata."},
{"Jetzt wohnen wir in Hannover, unser Vater hat hier einen neuen "
"________.",
"job", "Náš otec tu má novou práci."},
{"Unsere ________ sind geschieden.",
"eltern", "Naši rodiče jsou rozvedení."},
{"Unsere Mutter Maja (50) lebt in Wien, aber sie kommt aus ________.",
"kroatien", "Naše matka Maja (50) žije ve Vídni, ale pochází z "
"Chorvatska."},
{"Wir haben viele Onkel, ________, Cousinen und Cousins in Kroatien.",
"tanten", "Máme v Chorvatsku hodně strýců, tet, sestřenic a bratranců."},
{"Wir sehen sie manchmal in den ________.",
"ferien", "Vídáme je někdy o prázdninách."},
};
GtkWidget *u3ex5(UnitCtx *unit) {
return build_typed(unit, 5, "Marcos Familie", "sub3_marco",
ex5_u3_rows, G_N_ELEMENTS(ex5_u3_rows),
ex5_u3_bank, FALSE);
}
/* ---- ex6: Wortschatz sortieren --------------------------------------- */
const AssignItem ex6_u3_items[] = {
{NULL, "die Oma", 0},
{NULL, "der Bruder", 0},
{NULL, "der Opa", 0},
{NULL, "die Tochter", 0},
{NULL, "die Tante", 0},
{NULL, "der Hamster", 1},
{NULL, "das Pferd", 1},
{NULL, "die Katze", 1},
{NULL, "der Hund", 1},
{NULL, "der Wellensittich", 1},
};
const char *ex6_u3_groups[] = {"Familienmitglieder", "Haustiere"};
const char *ex6_u3_meaning[] = {
"babička", "bratr", "dědeček", "dcera", "teta",
"křeček", "kůň", "kočka", "pes", "andulka",
};
GtkWidget *u3ex6(UnitCtx *unit) {
return build_assign(unit, "Sortieren", "sub3_sort", 6,
ex6_u3_items, G_N_ELEMENTS(ex6_u3_items),
ex6_u3_groups, G_N_ELEMENTS(ex6_u3_groups),
ex6_u3_meaning);
}
/* ---- ex7: Possessivpronomen-Tabelle ---------------------------------- */
void u3_table_check(GtkButton *button, gpointer data) {
U3TableCtx *ctx = data;
int ok = 0;
(void)button;
for (int i = 0; i < ctx->n; i++) {
const gchar *txt = gtk_editable_get_text(
GTK_EDITABLE(ctx->entries[i]));
gchar *norm = normalize_answer(txt);
gboolean good = txt && txt[0] &&
g_strcmp0(norm, ctx->answers[i]) == 0;
g_free(norm);
answer_mark(ctx->entries[i], good);
if (good)
ok++;
}
if (ok == ctx->n) {
set_feedback(ctx->feedback, TRUE, tr("feedback_ok"));
mark_done(ctx->unit, ctx->ex_num);
} else {
set_feedback(ctx->feedback, FALSE, tr("feedback_retry"));
}
}
GtkWidget *u3ex7(UnitCtx *unit) {
static const char *persons[] = {
"ich", "du", "er", "sie", "es", "wir", "ihr", "sie / Sie",
};
static const char *nouns[] = {
"der Garten", "die Idee", "das Fest", "die Geschwister",
};
static const char *ans[4][8] = {
{"mein", "dein", "sein", "ihr", "sein", "unser", "euer",
"ihr"},
{"meine", "deine", "seine", "ihre", "seine", "unsere", "eure",
"ihre"},
{"mein", "dein", "sein", "ihr", "sein", "unser", "euer",
"ihr"},
{"meine", "deine", "seine", "ihre", "seine", "unsere", "eure",
"ihre"},
};
const int np = G_N_ELEMENTS(persons);
const int nn = G_N_ELEMENTS(nouns);
GtkWidget *body, *feedback, *check;
GtkWidget *page = ex_page_shell(unit->page, "Possessivtabelle",
"sub3_tabelle", "check",
&body, &feedback, &check);
GtkWidget *grid;
GtkWidget *sample_note;
GtkWidget *bank_row;
GtkWidget *bank_hdr;
GtkWidget *bank1;
GtkWidget *bank2;
U3TableCtx *ctx = g_new0(U3TableCtx, 1);
ctx->n = nn * np;
ctx->entries = g_new0(GtkWidget *, ctx->n);
ctx->answers = g_new0(const char *, ctx->n);
ctx->unit = unit;
ctx->ex_num = 7;
ctx->feedback = feedback;
sample_note = gtk_label_new("Beispiel: mein (ich × der Garten)");
gtk_widget_set_halign(sample_note, GTK_ALIGN_START);
gtk_widget_set_margin_top(sample_note, 2);
gtk_widget_set_margin_bottom(sample_note, 4);
gtk_widget_add_css_class(sample_note, "hint");
gtk_box_append(GTK_BOX(body), sample_note);
bank_row = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 6);
gtk_widget_set_halign(bank_row, GTK_ALIGN_START);
gtk_box_append(GTK_BOX(body), bank_row);
bank_hdr = gtk_label_new(NULL);
i18n_bind(bank_hdr, "wordbank", 0);
gtk_widget_add_css_class(bank_hdr, "hint");
gtk_box_append(GTK_BOX(bank_row), bank_hdr);
bank1 = gtk_label_new("(der Garten / das Fest) "
"mein · dein · sein · ihr · unser · euer");
gtk_widget_add_css_class(bank1, "hint");
gtk_box_append(GTK_BOX(bank_row), bank1);
bank_row = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 6);
gtk_widget_set_halign(bank_row, GTK_ALIGN_START);
gtk_box_append(GTK_BOX(body), bank_row);
bank2 = gtk_label_new("(die Idee / die Geschwister) "
"meine · deine · seine · ihre · unsere · eure");
gtk_widget_add_css_class(bank2, "hint");
gtk_box_append(GTK_BOX(bank_row), bank2);
grid = gtk_grid_new();
gtk_grid_set_column_spacing(GTK_GRID(grid), 8);
gtk_grid_set_row_spacing(GTK_GRID(grid), 8);
gtk_widget_set_halign(grid, GTK_ALIGN_START);
gtk_box_append(GTK_BOX(body), grid);
for (int c = 0; c < np; c++) {
GtkWidget *h = gtk_label_new(persons[c]);
gtk_widget_set_halign(h, GTK_ALIGN_CENTER);
gtk_widget_add_css_class(h, "ex-sub");
gtk_grid_attach(GTK_GRID(grid), h, c + 1, 0, 1, 1);
}
for (int r = 0; r < nn; r++) {
GtkWidget *h = gtk_label_new(nouns[r]);
gtk_widget_set_halign(h, GTK_ALIGN_START);
gtk_widget_add_css_class(h, "ex-sub");
gtk_grid_attach(GTK_GRID(grid), h, 0, r + 1, 1, 1);
}
for (int r = 0; r < nn; r++) {
for (int c = 0; c < np; c++) {
GtkWidget *e = gtk_entry_new();
gtk_editable_set_width_chars(GTK_EDITABLE(e), 6);
gtk_widget_set_halign(e, GTK_ALIGN_CENTER);
gtk_grid_attach(GTK_GRID(grid), e, c + 1, r + 1, 1, 1);
ctx->entries[r * np + c] = e;
ctx->answers[r * np + c] = ans[r][c];
}
}
/* pre-filled sample cell (ich × der Garten) */
gtk_editable_set_text(GTK_EDITABLE(ctx->entries[0]), "mein");
gtk_widget_set_sensitive(ctx->entries[0], FALSE);
g_signal_connect(check, "clicked", G_CALLBACK(u3_table_check), ctx);
return page;
}
/* ---- ex8: Possessivpronomen im Akkusativ ------------------------------ */
const char *ex8_u3_pool[] = {
"mein", "meine", "meinen", "dein", "deine", "deinen",
"sein", "seine", "seinen", "ihr", "ihre", "ihren",
"unser", "unsere", "unseren", "euer", "eure", "euren",
};
const U3Fill ex8_u3_rows[] = {
{"2.", "das Handy → Du brauchst ", "dein", " Handy.", NULL, NULL, NULL,
NULL, "Potřebuješ svůj mobil."},
{"3.", "das Pferd → Er hat ", "sein", " Pferd.", NULL, NULL, NULL, NULL,
"Má svého koně."},
{"4.", "die Party → Sie macht ", "ihre", " Party.", NULL, NULL, NULL,
NULL, "Dělá svou párty."},
{"5.", "der Lehrer → Es fragt ", "seinen", " Lehrer.", NULL, NULL, NULL,
NULL, "Ptá se svého učitele."},
{"6.", "das Wochenendhaus → Wir besuchen ", "unser", " Wochenendhaus.",
NULL, NULL, NULL, NULL, "Navštěvujeme náš víkendový dům."},
{"7.", "der Hund → Ihr seht ", "euren", " Hund.", NULL, NULL, NULL, NULL,
"Vy vidíte svého psa."},
{"8.", "die Instrumente → Sie haben ", "ihre", " Instrumente.", NULL,
NULL, NULL, NULL, "Mají své nástroje."},
};
const char *ex8_u3_gloss[] = {
"u3g_dein", "u3g_sein", "u3g_ihr_sie", "u3g_sein_es",
"u3g_unser", "u3g_euer", "u3g_ihr_sie_pl",
};
GtkWidget *u3ex8(UnitCtx *unit) {
return u3_build_drop(unit, 8, "Akkusativ", "sub3_akk",
"Beispiel: die Inliner (ich) → Ich brauche meine "
"Inliner.",
ex8_u3_rows, G_N_ELEMENTS(ex8_u3_rows),
ex8_u3_pool, G_N_ELEMENTS(ex8_u3_pool),
ex8_u3_gloss, TRUE);
}
/* ---- ex9: kein / keine / keinen / nicht ------------------------------ */
const char *ex9_u3_pool[] = {
"kein", "keine", "keinen", "nicht",
};
const U3Fill ex9_u3_rows[] = {
{"1.", "● Sprichst du Spanisch? ○ Nein, ich spreche ", "kein",
" Spanisch.", NULL, NULL, NULL, NULL,
"Mluvíš španělsky? – Ne, nemluvím španělsky."},
{"2.", "● Hast du einen Bruder? ○ Nein, ich habe ", "keinen",
" Bruder.", NULL, NULL, NULL, NULL, "Máš bratra? – Ne, nemám bratra."},
{"3.", "● Gibt es in Opava einen Zoo? ○ Nein, in Opava gibt es ",
"keinen", " Zoo.", NULL, NULL, NULL, NULL,
"Je v Opavě zoo? – Ne, v Opavě žádná zoo není."},
{"4.", "● Gehst du ins Schwimmbad? ○ Nein, ich gehe ", "nicht",
" ins Schwimmbad.", NULL, NULL, NULL, NULL,
"Jdeš do bazénu? – Ne, do bazénu nejdu."},
{"5.", "● Wandert er gern? ○ Nein, er wandert ", "nicht", " gern.",
NULL, NULL, NULL, NULL, "Rád chodí na túry? – Ne, nerad chodí na túry."},
{"6.", "● Besuchst du heute ein Schloss? ○ Nein, heute besuche ich ",
"kein", " Schloss.", NULL, NULL, NULL, NULL,
"Navštívíš dnes zámek? – Ne, dnes nenavštívím žádný zámek."},
};
GtkWidget *u3ex9(UnitCtx *unit) {
return u3_build_drop(unit, 9, "kein / nicht", "sub3_nicht", NULL,
ex9_u3_rows, G_N_ELEMENTS(ex9_u3_rows),
ex9_u3_pool, G_N_ELEMENTS(ex9_u3_pool), NULL, TRUE);
}
/* ---- ex10: Sätze bauen ------------------------------------------------ */
const AssemblyItem ex10_u3_items[] = {
{NULL, {"Sie", "haben", "eine", "Schildkröte", "."}, 5},
{NULL, {"Was", "macht", "deine", "Freundin", "am", "Wochenende?"}, 6},
{NULL, {"Mein", "Vater", "ist", "Lehrer", "von", "Beruf."}, 6},
{NULL, {"Seid", "ihr", "viele", "zu", "Hause?"}, 5},
{NULL, {"Julia", "stellt", "ihren", "Hund", "Trixi", "vor."}, 6},
};
const char *ex10_u3_meaning[] = {
"Mají želvu.",
"Co dělá tvoje kamarádka o víkendu?",
"Můj otec je povoláním učitel.",
"Je vás doma hodně?",
"Julie představuje svého psa Trixiho.",
};
GtkWidget *u3ex10(UnitCtx *unit) {
return build_assembly(unit, "Sätze bauen", "sub3_satz", 10,
ex10_u3_items, ex10_u3_meaning,
G_N_ELEMENTS(ex10_u3_items));
}
/* ---- keyword-typed builder (ex11 + ex14) ----------------------------- */
void u3_kw_check(GtkButton *button, gpointer data) {
U3KwCtx *ctx = data;
int ok = 0;
(void)button;
for (int i = 0; i < ctx->n; i++) {
const gchar *txt = gtk_editable_get_text(GTK_EDITABLE(ctx->entries[i]));
gchar *norm = normalize_answer(txt);
gboolean good = txt && txt[0];
if (good) {
gchar **parts = g_strsplit(ctx->qs[i].answers, "|", -1);
good = FALSE;
for (int j = 0; parts[j]; j++) {
gchar *a = normalize_answer(parts[j]);
if (a[0] && g_strrstr(norm, a)) {
good = TRUE;
g_free(a);
break;
}
g_free(a);
}
g_strfreev(parts);
}
g_free(norm);
answer_mark(ctx->entries[i], good);
if (good)
ok++;
}
for (int i = 0; i < ctx->n; i++)
if (ctx->models[i])
gtk_widget_set_visible(ctx->models[i], TRUE);
if (ok == ctx->n) {
set_feedback(ctx->feedback, TRUE, tr("feedback_ok"));
mark_done(ctx->unit, ctx->ex_num);
} else {
set_feedback(ctx->feedback, FALSE, tr("feedback_retry"));
}
}
GtkWidget *u3_build_kw(UnitCtx *unit, int ex_num, const char *title,
const char *sub, const char *sample,
const U3Kw *qs, int n) {
GtkWidget *body, *feedback, *check;
GtkWidget *page = ex_page_shell(unit->page, title, sub, "check",
&body, &feedback, &check);
U3KwCtx *ctx = g_new0(U3KwCtx, 1);
ctx->qs = qs;
ctx->n = n;
ctx->unit = unit;
ctx->ex_num = ex_num;
ctx->feedback = feedback;
ctx->entries = g_new0(GtkWidget *, n);
ctx->trans = g_new0(GtkWidget *, n);
ctx->models = g_new0(GtkWidget *, n);
{
gboolean need = FALSE;
for (int i = 0; i < n && !need; i++) {
need = text_has_german_umlaut(qs[i].prompt) ||
text_has_german_umlaut(qs[i].answers) ||
text_has_german_umlaut(qs[i].german);
}
if (need)
add_umlaut_note(body);
}
if (sample && sample[0])
u3_sample_line(body, sample);
for (int i = 0; i < n; i++) {
GtkWidget *prompt = gtk_label_new(qs[i].prompt);
GtkWidget *entry;
gtk_widget_set_halign(prompt, GTK_ALIGN_START);
gtk_widget_add_css_class(prompt, "ex-prompt");
gtk_label_set_wrap(GTK_LABEL(prompt), TRUE);
gtk_box_append(GTK_BOX(body), prompt);
entry = gtk_entry_new();
gtk_widget_set_hexpand(entry, FALSE);
gtk_widget_set_halign(entry, GTK_ALIGN_START);
gtk_box_append(GTK_BOX(body), entry);
ctx->entries[i] = entry;
if (qs[i].mean)
ctx->trans[i] = meaning_add(body, qs[i].mean);
/* Czech meaning acts as a hint and stays visible. */
if (ctx->trans[i])
gtk_widget_set_visible(ctx->trans[i], TRUE);
/* The model German sentence is only shown after clicking Check. */
if (qs[i].german && qs[i].german[0]) {
GtkWidget *model = gtk_label_new(qs[i].german);
gtk_widget_set_halign(model, GTK_ALIGN_START);
gtk_label_set_xalign(GTK_LABEL(model), 0.0);
gtk_label_set_wrap(GTK_LABEL(model), TRUE);
gtk_widget_set_margin_top(model, 2);
gtk_widget_set_margin_bottom(model, 2);
gtk_widget_set_margin_start(model, 8);
gtk_widget_add_css_class(model, "u3-answer");
gtk_widget_set_visible(model, FALSE);
gtk_box_append(GTK_BOX(body), model);
ctx->models[i] = model;
}
}
g_signal_connect(check, "clicked", G_CALLBACK(u3_kw_check), ctx);
return page;
}
/* ---- ex11: Was siehst du? -------------------------------------------- */
const U3Kw ex11_u3_qs[] = {
{"Ein altes Gebäude aus dem Mittelalter. Es steht auf einem Berg.",
"burg|schloss", "Vidím hrad / zámek.",
"Ich sehe eine Burg. / Ich sehe ein Schloss."},
{"Wasser, Bäume und Berge. Es ist sehr ruhig.",
"see", "Vidím jezero.", "Ich sehe einen See."},
{"Eine Frau, ein Mann und zwei Kinder essen zusammen.",
"familie", "Vidím rodinu.", "Ich sehe eine Familie."},
};
GtkWidget *u3ex11(UnitCtx *unit) {
return u3_build_kw(unit, 11, "Was siehst du?", "sub3_sehen",
"Beispiel: Ich sehe eine Burg. / Ich sehe ein Schloss.",
ex11_u3_qs, G_N_ELEMENTS(ex11_u3_qs));
}
/* ---- ex12: Wem gehört das? ------------------------------------------- */
const char *ex12_u3_pool[] = {
"mein", "meine", "dein", "deine", "sein", "seine",
"ihr", "ihre", "unser", "unsere", "euer", "eure",
};
const U3Fill ex12_u3_rows[] = {
{"1.", "Das ist Tom. → Das ist ", "sein", " Handy.", NULL, NULL, NULL,
NULL, "To je jeho mobil."},
{"2.", "Das ist Maria. → Das ist ", "ihr", " Kaninchen.", NULL, NULL,
NULL, NULL, "To je její králík."},
{"3.", "Das sind Max und Lisa. → Das sind ", "ihre", " Inliner.", NULL,
NULL, NULL, NULL, "To jsou jejich brusle."},
{"4.", "Das ist Frau Berger. → Das ist ", "ihr", " Kuchen.", NULL, NULL,
NULL, NULL, "To je její dort."},
{"5.", "Das ist Herr Müller. → Das ist ", "sein", " Haus.", NULL, NULL,
NULL, NULL, "To je jeho dům."},
{"6.", "Das sind die Schmidts. → Das sind ", "ihre", " Kinder.", NULL,
NULL, NULL, NULL, "To jsou jejich děti."},
};
GtkWidget *u3ex12(UnitCtx *unit) {
return u3_build_drop(unit, 12, "Wem gehört das?", "sub3_wem", NULL,
ex12_u3_rows, G_N_ELEMENTS(ex12_u3_rows),
ex12_u3_pool, G_N_ELEMENTS(ex12_u3_pool), NULL, TRUE);
}
/* ---- ex13: Es gibt + unbestimmter Artikel ---------------------------- */
const char *ex13_u3_pool[] = {"ein", "eine", "einen"};
const U3Fill ex13_u3_rows[] = {
{"1.", "(das Konzert) → Es gibt ", "ein", " Konzert.", NULL, NULL, NULL,
NULL, "Je tu koncert."},
{"2.", "(die Ausstellung) → Es gibt ", "eine", " Ausstellung.", NULL,
NULL, NULL, NULL, "Je tu výstava."},
{"3.", "(das Sportfest) → Es gibt ", "ein", " Sportfest.", NULL, NULL,
NULL, NULL, "Je tu sportovní slavnost."},
{"4.", "(das Familientreffen) → Es gibt ", "ein", " Familientreffen.",
NULL, NULL, NULL, NULL, "Je tu rodinné setkání."},
{"5.", "(die Theatervorstellung) → Es gibt ", "eine",
" Theatervorstellung.", NULL, NULL, NULL, NULL,
"Je tu divadelní představení."},
{"6.", "(der Flohmarkt) → Es gibt ", "einen", " Flohmarkt.", NULL, NULL,
NULL, NULL, "Je tu bleší trh."},
};
GtkWidget *u3ex13(UnitCtx *unit) {
return u3_build_drop(unit, 13, "Es gibt …", "sub3_gibt", NULL,
ex13_u3_rows, G_N_ELEMENTS(ex13_u3_rows),
ex13_u3_pool, G_N_ELEMENTS(ex13_u3_pool), NULL, TRUE);
}
/* ---- ex14: Beschreiben (sentence pairs) ------------------------------ */
const U3Kw ex14_u3_qs[] = {
{"Eine Frau fährt Fahrrad. → Ich sehe ________.",
"eine frau|frau", "Vidím ženu.", "Ich sehe eine Frau."},
{"→ Sie ________.",
"sie fährt fahrrad|sie fährt|fährt fahrrad|fährt", "Jezdí na kole.",
"Sie fährt Fahrrad."},
{"Ein Mann wandert im Wald. → Ich sehe ________.",
"einen mann|mann", "Vidím muže.", "Ich sehe einen Mann."},
{"→ Er ________.",
"er wandert im wald|er wandert|wandert im wald|wandert",
"Chodí po lese.", "Er wandert im Wald."},
{"Zwei Kinder spielen Fußball. → Ich sehe ________.",
"zwei kinder|kinder", "Vidím dvě děti.", "Ich sehe zwei Kinder."},
{"→ Sie ________.",
"sie spielen fußball|sie spielen fussball|spielen fußball|spielen "
"fussball|spielen", "Hrají fotbal.", "Sie spielen Fußball."},
};
GtkWidget *u3ex14(UnitCtx *unit) {
return u3_build_kw(unit, 14, "Beschreiben", "sub3_saetze",
"Beispiel: Ich sehe einen Jungen. Er liest ein Buch.",
ex14_u3_qs, G_N_ELEMENTS(ex14_u3_qs));
}
/* ---- ex15: missing letters (Wochenende) ------------------------------ */
const U3Let ex15_u3_rows[] = {
{"1.", "Meine Gr", "oß", "eltern fahr", "en", " ins Wochen", "end",
"haus.", NULL, NULL,
"Moji prarodiče jedou o víkendu do víkendového domu."},
{"2.", "Mein ", "Va", "ter und mein", "e", " Mutter besuch", "en",
" ein Konz", "er", "t.",
"Můj otec a moje matka navštíví koncert."},
{"3.", "Mein", "e", " Sch", "w", "ester geh", "t", " ins K", "in", "o.",
"Moje sestra jde do kina."},
{"4.", "Mein Bru", "d", "er f", "äh", "rt an ", "ei", "nen S", "ee",
".",
"Můj bratr jede k jezeru."},
{"5.", "Und ich? Ich besuch", "e", " ein Einka", "ufs", "zentrum.",
NULL, NULL, NULL, NULL,
"A já? Navštívím obchodní centrum."},
};
GtkWidget *u3ex15(UnitCtx *unit) {
return u3_build_letters(unit, 15, "Wochenende", "sub3_wochen",
ex15_u3_rows, G_N_ELEMENTS(ex15_u3_rows));
}