mirror of
https://github.com/pepaskopec-blip/Graduately.git
synced 2026-10-27 23:24:34 +00:00
new exercise in unit 1, vocabulary training
This commit is contained in:
parent
56fe5ae6fc
commit
2782446b89
7 changed files with 539 additions and 5 deletions
274
exercise_u1.c
274
exercise_u1.c
|
|
@ -977,3 +977,277 @@ GtkWidget *build_assign(UnitCtx *unit, const char *title,
|
||||||
g_signal_connect(check, "clicked", G_CALLBACK(assign_check), ac);
|
g_signal_connect(check, "clicked", G_CALLBACK(assign_check), ac);
|
||||||
return page;
|
return page;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------------ */
|
||||||
|
/* Exercise 14: Wörter übersetzen */
|
||||||
|
/* ------------------------------------------------------------------ */
|
||||||
|
|
||||||
|
const TypedQ trans_p10[] = {
|
||||||
|
{"der Abend, -e", "večer|evening", "večer"},
|
||||||
|
{"Guten Abend!", "dobrý večer|good evening", "Dobrý večer!"},
|
||||||
|
{"du", "ty|you", "ty"},
|
||||||
|
{"(Es) freut mich.", "těší mě|nice to meet you", "Těší mě."},
|
||||||
|
{"gut", "dobrý|good", "dobrý"},
|
||||||
|
{"Hallo!", "ahoj|hello", "Ahoj!"},
|
||||||
|
{"heißen, er heißt", "jmenovat se|to be called|to be named", "jmenovat se"},
|
||||||
|
{"Ich heiße Jens.", "jmenuji se jens|my name is jens", "Jmenuji se Jens."},
|
||||||
|
{"Hi!", "ahoj|hi", "Ahoj! (neformálně)"},
|
||||||
|
{"ich", "já|i", "já"},
|
||||||
|
{"ihr", "vy|you", "vy"},
|
||||||
|
{"ja", "ano|yes", "ano"},
|
||||||
|
{"der Morgen", "ráno|morning", "ráno"},
|
||||||
|
{"Guten Morgen!", "dobré ráno|good morning", "Dobré ráno!"},
|
||||||
|
{"der Name, -n", "jméno|name", "jméno"},
|
||||||
|
{"nein", "ne|no", "ne"},
|
||||||
|
{"(er/sie/es) ist", "je|is", "je"},
|
||||||
|
{"der Tag, -e", "den|day", "den"},
|
||||||
|
{"Guten Tag!", "dobrý den|good day", "Dobrý den!"},
|
||||||
|
{"und", "a|and", "a"},
|
||||||
|
{"wer", "kdo|who", "kdo"},
|
||||||
|
{"Wer bist du?", "kdo jsi|who are you", "Kdo jsi?"},
|
||||||
|
{"wie", "jak|how", "jak"},
|
||||||
|
{"Wie heißt du?", "jak se jmenuješ|what is your name", "Jak se jmenuješ?"},
|
||||||
|
{"wir", "my|we", "my"},
|
||||||
|
};
|
||||||
|
|
||||||
|
const TypedQ trans_p11[] = {
|
||||||
|
{"in", "v|in", "v"},
|
||||||
|
{"in der Nähe (von)", "poblíž|v blízkosti|near|nearby", "poblíž, v blízkosti"},
|
||||||
|
{"das Spiel, -e", "hra|game", "hra"},
|
||||||
|
{"wo", "kde|where", "kde"},
|
||||||
|
{"wohnen, er wohnt", "bydlet|to live", "bydlet"},
|
||||||
|
{"Wo wohnst du?", "kde bydlíš|where do you live", "Kde bydlíš?"},
|
||||||
|
{"Ich wohne in Prag.", "bydlím v praze|i live in prague", "Bydlím v Praze."},
|
||||||
|
{"null", "nula|zero", "nula"},
|
||||||
|
{"eins", "jedna|one", "jedna"},
|
||||||
|
{"zwei", "dvě|two", "dvě"},
|
||||||
|
{"drei", "tři|three", "tři"},
|
||||||
|
{"vier", "čtyři|four", "čtyři"},
|
||||||
|
{"fünf", "pět|five", "pět"},
|
||||||
|
{"sechs", "šest|six", "šest"},
|
||||||
|
{"sieben", "sedm|seven", "sedm"},
|
||||||
|
{"acht", "osm|eight", "osm"},
|
||||||
|
{"neun", "devět|nine", "devět"},
|
||||||
|
{"zehn", "deset|ten", "deset"},
|
||||||
|
{"elf", "jedenáct|eleven", "jedenáct"},
|
||||||
|
{"zwölf", "dvanáct|twelve", "dvanáct"},
|
||||||
|
{"dreizehn", "třináct|thirteen", "třináct"},
|
||||||
|
{"vierzehn", "čtrnáct|fourteen", "čtrnáct"},
|
||||||
|
{"fünfzehn", "patnáct|fifteen", "patnáct"},
|
||||||
|
{"sechzehn", "šestnáct|sixteen", "šestnáct"},
|
||||||
|
{"siebzehn", "sedmnáct|seventeen", "sedmnáct"},
|
||||||
|
{"achtzehn", "osmnáct|eighteen", "osmnáct"},
|
||||||
|
{"neunzehn", "devatenáct|nineteen", "devatenáct"},
|
||||||
|
{"zwanzig", "dvacet|twenty", "dvacet"},
|
||||||
|
};
|
||||||
|
|
||||||
|
const TypedQ trans_p12[] = {
|
||||||
|
{"alt", "starý|old", "starý"},
|
||||||
|
{"er", "on|he", "on"},
|
||||||
|
{"der Monat, -e", "měsíc|month", "měsíc"},
|
||||||
|
{"sie", "ona|she", "ona"},
|
||||||
|
{"sie", "oni|they", "oni"},
|
||||||
|
};
|
||||||
|
|
||||||
|
const TypedQ trans_p13[] = {
|
||||||
|
{"aber", "ale|but", "ale"},
|
||||||
|
{"das Alter", "věk|age", "věk"},
|
||||||
|
{"auch", "také|also|too", "také"},
|
||||||
|
{"aus", "z|from", "z"},
|
||||||
|
{"die Band, -s", "skupina|band", "(hudební) skupina"},
|
||||||
|
{"chatten, er chattet", "chatovat|to chat", "chatovat"},
|
||||||
|
{"das Computerspiel, -e", "počítačová hra|computer game", "počítačová hra"},
|
||||||
|
{"die/das E-Mail, -s", "e-mail|email", "e-mail"},
|
||||||
|
{"das Englisch", "angličtina|anglicky|english", "angličtina, anglicky"},
|
||||||
|
{"der Fan, -s", "fanoušek|fan", "fanoušek"},
|
||||||
|
{"das Französisch", "francouzština|francouzsky|french",
|
||||||
|
"francouzština, francouzsky"},
|
||||||
|
{"der Freund, -e", "kamarád|friend", "kamarád"},
|
||||||
|
{"die Freundin, -nen", "kamarádka|friend", "kamarádka"},
|
||||||
|
{"beste Freundin", "nejlepší kamarádka|best friend", "nejlepší kamarádka"},
|
||||||
|
{"der Fußball", "fotbal|football", "fotbal"},
|
||||||
|
{"Er ist Fußballfanatiker.", "je fotbalový fanatik|he is a football fanatic",
|
||||||
|
"Je fotbalový fanatik."},
|
||||||
|
{"gehen, er geht", "jít|to go", "jít"},
|
||||||
|
{"Ich gehe gern auf Konzerte.",
|
||||||
|
"rád chodím na koncerty|ráda chodím na koncerty|i like going to concerts",
|
||||||
|
"Rád(a) chodím na koncerty."},
|
||||||
|
{"gern", "rád|ráda|gladly", "rád/a"},
|
||||||
|
{"die Gitarre, -n", "kytara|guitar", "kytara"},
|
||||||
|
{"das Handy, -s", "mobil|mobile phone", "mobil"},
|
||||||
|
{"das Hobby, -s", "koníček|hobby", "koníček"},
|
||||||
|
{"hören, er hört", "poslouchat|to listen", "poslouchat"},
|
||||||
|
{"Er hört gern Musik.", "rád poslouchá hudbu|he likes listening to music",
|
||||||
|
"Rád poslouchá hudbu."},
|
||||||
|
{"im Internet surfen, er surft im Internet",
|
||||||
|
"surfovat na internetu|to surf the internet", "surfovat na internetu"},
|
||||||
|
{"immer", "pořád|neustále|always", "pořád, neustále"},
|
||||||
|
{"das Jahr, -e", "rok|year", "rok"},
|
||||||
|
{"kein/keine/kein", "žádný|žádná|žádné|no|none", "žádný/žádná/žádné"},
|
||||||
|
{"das Klavier, -e", "klavír|piano", "klavír"},
|
||||||
|
{"kommen (aus), er kommt", "přicházet|pocházet|to come|to come from",
|
||||||
|
"přicházet, pocházet (z)"},
|
||||||
|
{"Er kommt aus Wien.", "pochází z vídně|he comes from vienna",
|
||||||
|
"Pochází z Vídně."},
|
||||||
|
{"das Konzert, -e", "koncert|concert", "koncert"},
|
||||||
|
{"lernen, er lernt", "učit se|to learn", "učit se"},
|
||||||
|
{"liegen, er liegt", "ležet|to lie", "ležet"},
|
||||||
|
{"der Nachname, -n", "příjmení|surname|last name", "příjmení"},
|
||||||
|
{"nicht weit von", "nedaleko od|not far from", "nedaleko od"},
|
||||||
|
{"reisen, er reist", "cestovat|to travel", "cestovat"},
|
||||||
|
{"schreiben, er schreibt", "psát|to write", "psát"},
|
||||||
|
{"die Schule, -n", "škola|school", "škola"},
|
||||||
|
{"spielen, er spielt", "hrát|to play", "hrát"},
|
||||||
|
{"Sie spielt Gitarre.", "hraje na kytaru|she plays the guitar",
|
||||||
|
"Hraje na kytaru."},
|
||||||
|
{"tanzen, er tanzt", "tancovat|to dance", "tancovat"},
|
||||||
|
{"der Vorname, -n", "křestní jméno|first name", "křestní jméno"},
|
||||||
|
{"der Wohnort, -e", "bydliště|place of residence", "bydliště"},
|
||||||
|
};
|
||||||
|
|
||||||
|
const TypedQ trans_p14[] = {
|
||||||
|
{"falsch", "nesprávně|chybně|wrong|incorrect", "nesprávně, chybně"},
|
||||||
|
{"die Flöte, -n", "flétna|flute", "flétna"},
|
||||||
|
{"haben, er hat", "mít|to have", "mít"},
|
||||||
|
{"das Instrument, -e", "nástroj|instrument", "(hudební) nástroj"},
|
||||||
|
{"jetzt", "teď|now", "teď"},
|
||||||
|
{"machen, er macht", "dělat|to do|to make", "dělat"},
|
||||||
|
{"richtig", "správně|correct|right", "správně"},
|
||||||
|
{"der Sport", "sport", "sport"},
|
||||||
|
{"Sport treiben, er treibt Sport", "sportovat|to do sport", "sportovat"},
|
||||||
|
{"das Squash", "squash", "squash"},
|
||||||
|
{"das/der Yoga", "jóga|yoga", "jóga"},
|
||||||
|
};
|
||||||
|
|
||||||
|
const TypedQ trans_p15[] = {
|
||||||
|
{"bald", "brzy|soon", "brzy"},
|
||||||
|
{"Bis bald!", "brzy na shledanou|see you soon", "Brzy na shledanou!"},
|
||||||
|
{"bis", "do|until", "do"},
|
||||||
|
{"Bis zum nächsten Mal!", "do příštího setkání|until next time",
|
||||||
|
"Do příštího setkání!"},
|
||||||
|
{"die Frau, -en", "paní|woman|mrs", "paní"},
|
||||||
|
{"der Herr, -en", "pan|man|mr", "pan"},
|
||||||
|
{"Mach's gut!", "měj se hezky|take care", "Měj se hezky!"},
|
||||||
|
{"das Museum, Museen", "muzeum|museum", "muzeum"},
|
||||||
|
{"Sie gehen ins Museum.", "jdou do muzea|they are going to the museum",
|
||||||
|
"Jdou do muzea."},
|
||||||
|
{"schön", "hezký|beautiful|nice", "hezký"},
|
||||||
|
{"Einen schönen Tag noch!", "hezký zbytek dne|have a nice day",
|
||||||
|
"Hezký zbytek dne!"},
|
||||||
|
{"Servus!", "ahoj|hi", "Ahoj! (servus)"},
|
||||||
|
{"Tschüs!", "ahoj|bye", "Ahoj! (při loučení)"},
|
||||||
|
{"das Wiedersehen", "shledání|reunion", "shledání"},
|
||||||
|
{"Auf Wiedersehen!", "na shledanou|goodbye", "Na shledanou!"},
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
const char *header; /* i18n key, e.g. "Strana 10" */
|
||||||
|
const TypedQ *rows;
|
||||||
|
int n;
|
||||||
|
} TransSection;
|
||||||
|
|
||||||
|
static const TransSection trans_sections[] = {
|
||||||
|
{"Strana 10", trans_p10, (int)G_N_ELEMENTS(trans_p10)},
|
||||||
|
{"Strana 11", trans_p11, (int)G_N_ELEMENTS(trans_p11)},
|
||||||
|
{"Strana 12", trans_p12, (int)G_N_ELEMENTS(trans_p12)},
|
||||||
|
{"Strana 13", trans_p13, (int)G_N_ELEMENTS(trans_p13)},
|
||||||
|
{"Strana 14", trans_p14, (int)G_N_ELEMENTS(trans_p14)},
|
||||||
|
{"Strana 15", trans_p15, (int)G_N_ELEMENTS(trans_p15)},
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
UnitCtx *unit;
|
||||||
|
int ex_num;
|
||||||
|
GtkWidget *feedback;
|
||||||
|
GtkWidget **entries;
|
||||||
|
GtkWidget **trans;
|
||||||
|
int total;
|
||||||
|
} TransCtx;
|
||||||
|
|
||||||
|
static void translate_check(GtkButton *button, gpointer data) {
|
||||||
|
TransCtx *ctx = data;
|
||||||
|
int ok = 0;
|
||||||
|
int idx = 0;
|
||||||
|
|
||||||
|
(void)button;
|
||||||
|
|
||||||
|
for (guint s = 0; s < G_N_ELEMENTS(trans_sections); s++) {
|
||||||
|
const TransSection *sec = &trans_sections[s];
|
||||||
|
for (int i = 0; i < sec->n; i++, idx++) {
|
||||||
|
const gchar *txt =
|
||||||
|
gtk_editable_get_text(GTK_EDITABLE(ctx->entries[idx]));
|
||||||
|
gchar *norm = normalize_answer(txt);
|
||||||
|
gboolean good =
|
||||||
|
txt && txt[0] && answer_accepts(norm, sec->rows[i].answers);
|
||||||
|
|
||||||
|
g_free(norm);
|
||||||
|
answer_mark(ctx->entries[idx], good);
|
||||||
|
if (good)
|
||||||
|
ok++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < ctx->total; i++)
|
||||||
|
if (ctx->trans[i])
|
||||||
|
gtk_widget_set_visible(ctx->trans[i], TRUE);
|
||||||
|
|
||||||
|
if (ok == ctx->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 *build_translate(UnitCtx *unit) {
|
||||||
|
GtkWidget *body, *feedback, *check;
|
||||||
|
GtkWidget *page = ex_page_shell(unit->page, "Vokabeltraining",
|
||||||
|
"sub_translate", "check",
|
||||||
|
&body, &feedback, &check);
|
||||||
|
TransCtx *ctx = g_new0(TransCtx, 1);
|
||||||
|
int total = 0;
|
||||||
|
int idx = 0;
|
||||||
|
|
||||||
|
for (guint s = 0; s < G_N_ELEMENTS(trans_sections); s++)
|
||||||
|
total += trans_sections[s].n;
|
||||||
|
|
||||||
|
ctx->unit = unit;
|
||||||
|
ctx->ex_num = unit->branch_ex;
|
||||||
|
ctx->feedback = feedback;
|
||||||
|
ctx->total = total;
|
||||||
|
ctx->entries = g_new0(GtkWidget *, total);
|
||||||
|
ctx->trans = g_new0(GtkWidget *, total);
|
||||||
|
|
||||||
|
for (guint s = 0; s < G_N_ELEMENTS(trans_sections); s++) {
|
||||||
|
const TransSection *sec = &trans_sections[s];
|
||||||
|
GtkWidget *hdr = gtk_label_new(NULL);
|
||||||
|
|
||||||
|
i18n_bind(hdr, sec->header, 0);
|
||||||
|
gtk_widget_set_halign(hdr, GTK_ALIGN_START);
|
||||||
|
gtk_widget_add_css_class(hdr, "ex-sub");
|
||||||
|
gtk_widget_set_margin_top(hdr, s > 0 ? 12 : 0);
|
||||||
|
gtk_box_append(GTK_BOX(body), hdr);
|
||||||
|
|
||||||
|
for (int i = 0; i < sec->n; i++, idx++) {
|
||||||
|
GtkWidget *prompt = gtk_label_new(sec->rows[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[idx] = entry;
|
||||||
|
|
||||||
|
if (sec->rows[i].meaning)
|
||||||
|
ctx->trans[idx] = meaning_add(body, sec->rows[i].meaning);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
g_signal_connect(check, "clicked", G_CALLBACK(translate_check), ctx);
|
||||||
|
return page;
|
||||||
|
}
|
||||||
|
|
|
||||||
127
i18n.c
127
i18n.c
|
|
@ -75,6 +75,9 @@ const TrEntry tr_ui[] = {
|
||||||
"Sort the phrases into greetings and farewells."},
|
"Sort the phrases into greetings and farewells."},
|
||||||
{"sub_land", "Přiřaďte symboly ke správné zemi.",
|
{"sub_land", "Přiřaďte symboly ke správné zemi.",
|
||||||
"Match the symbols to the correct country."},
|
"Match the symbols to the correct country."},
|
||||||
|
{"Vokabeltraining", NULL, "Vocabulary training"},
|
||||||
|
{"sub_translate", "Přeložte tato slova – česky nebo anglicky.",
|
||||||
|
"Translate these words – in Czech or English."},
|
||||||
{"assign_hint",
|
{"assign_hint",
|
||||||
"Vyberte skupinu a klikněte na kartu. Kliknutím na kartu ve skupině "
|
"Vyberte skupinu a klikněte na kartu. Kliknutím na kartu ve skupině "
|
||||||
"ji vrátíte zpět.",
|
"ji vrátíte zpět.",
|
||||||
|
|
@ -592,6 +595,130 @@ const TrEntry tr_content[] = {
|
||||||
"My brother is driving to a lake."},
|
"My brother is driving to a lake."},
|
||||||
{"A já? Navštívím obchodní centrum.", NULL,
|
{"A já? Navštívím obchodní centrum.", NULL,
|
||||||
"And me? I am going to a shopping centre."},
|
"And me? I am going to a shopping centre."},
|
||||||
|
/* ---- unit 1: Wörter übersetzen (page headers) ---- */
|
||||||
|
{"Strana 10", NULL, "Page 10"},
|
||||||
|
{"Strana 11", NULL, "Page 11"},
|
||||||
|
{"Strana 12", NULL, "Page 12"},
|
||||||
|
{"Strana 13", NULL, "Page 13"},
|
||||||
|
{"Strana 14", NULL, "Page 14"},
|
||||||
|
{"Strana 15", NULL, "Page 15"},
|
||||||
|
/* ---- unit 1: Wörter übersetzen (word meanings) ---- */
|
||||||
|
{"večer", NULL, "evening"},
|
||||||
|
{"Dobrý večer!", NULL, "Good evening!"},
|
||||||
|
{"ty", NULL, "you"},
|
||||||
|
{"Těší mě.", NULL, "Nice to meet you."},
|
||||||
|
{"dobrý", NULL, "good"},
|
||||||
|
{"Ahoj!", NULL, "Hello!"},
|
||||||
|
{"jmenovat se", NULL, "to be called"},
|
||||||
|
{"Jmenuji se Jens.", NULL, "My name is Jens."},
|
||||||
|
{"Ahoj! (neformálně)", NULL, "Hi! (informal)"},
|
||||||
|
{"já", NULL, "I"},
|
||||||
|
{"vy", NULL, "you (plural)"},
|
||||||
|
{"ano", NULL, "yes"},
|
||||||
|
{"ráno", NULL, "morning"},
|
||||||
|
{"jméno", NULL, "name"},
|
||||||
|
{"ne", NULL, "no"},
|
||||||
|
{"je", NULL, "is"},
|
||||||
|
{"den", NULL, "day"},
|
||||||
|
{"Dobrý den!", NULL, "Good day!"},
|
||||||
|
{"a", NULL, "and"},
|
||||||
|
{"kdo", NULL, "who"},
|
||||||
|
{"Kdo jsi?", NULL, "Who are you?"},
|
||||||
|
{"jak", NULL, "how"},
|
||||||
|
{"my", NULL, "we"},
|
||||||
|
{"v", NULL, "in"},
|
||||||
|
{"poblíž, v blízkosti", NULL, "near, in the vicinity"},
|
||||||
|
{"hra", NULL, "game"},
|
||||||
|
{"kde", NULL, "where"},
|
||||||
|
{"bydlet", NULL, "to live"},
|
||||||
|
{"Kde bydlíš?", NULL, "Where do you live?"},
|
||||||
|
{"nula", NULL, "zero"},
|
||||||
|
{"jedna", NULL, "one"},
|
||||||
|
{"dvě", NULL, "two"},
|
||||||
|
{"tři", NULL, "three"},
|
||||||
|
{"čtyři", NULL, "four"},
|
||||||
|
{"pět", NULL, "five"},
|
||||||
|
{"sedm", NULL, "seven"},
|
||||||
|
{"osm", NULL, "eight"},
|
||||||
|
{"devět", NULL, "nine"},
|
||||||
|
{"deset", NULL, "ten"},
|
||||||
|
{"jedenáct", NULL, "eleven"},
|
||||||
|
{"dvanáct", NULL, "twelve"},
|
||||||
|
{"patnáct", NULL, "fifteen"},
|
||||||
|
{"šestnáct", NULL, "sixteen"},
|
||||||
|
{"osmnáct", NULL, "eighteen"},
|
||||||
|
{"devatenáct", NULL, "nineteen"},
|
||||||
|
{"starý", NULL, "old"},
|
||||||
|
{"on", NULL, "he"},
|
||||||
|
{"měsíc", NULL, "month"},
|
||||||
|
{"ona", NULL, "she"},
|
||||||
|
{"oni", NULL, "they"},
|
||||||
|
{"ale", NULL, "but"},
|
||||||
|
{"věk", NULL, "age"},
|
||||||
|
{"také", NULL, "also"},
|
||||||
|
{"(hudební) skupina", NULL, "(music) band"},
|
||||||
|
{"chatovat", NULL, "to chat"},
|
||||||
|
{"počítačová hra", NULL, "computer game"},
|
||||||
|
{"e-mail", NULL, "email"},
|
||||||
|
{"angličtina, anglicky", NULL, "English"},
|
||||||
|
{"fanoušek", NULL, "fan"},
|
||||||
|
{"francouzština, francouzsky", NULL, "French"},
|
||||||
|
{"kamarádka", NULL, "friend (f.)"},
|
||||||
|
{"nejlepší kamarádka", NULL, "best friend (f.)"},
|
||||||
|
{"fotbal", NULL, "football"},
|
||||||
|
{"Je fotbalový fanatik.", NULL, "He is a football fanatic."},
|
||||||
|
{"jít", NULL, "to go"},
|
||||||
|
{"Rád(a) chodím na koncerty.", NULL, "I like going to concerts."},
|
||||||
|
{"rád/a", NULL, "gladly"},
|
||||||
|
{"kytara", NULL, "guitar"},
|
||||||
|
{"mobil", NULL, "mobile phone"},
|
||||||
|
{"koníček", NULL, "hobby"},
|
||||||
|
{"poslouchat", NULL, "to listen"},
|
||||||
|
{"Rád poslouchá hudbu.", NULL, "He likes listening to music."},
|
||||||
|
{"surfovat na internetu", NULL, "to surf the internet"},
|
||||||
|
{"pořád, neustále", NULL, "always"},
|
||||||
|
{"rok", NULL, "year"},
|
||||||
|
{"žádný/žádná/žádné", NULL, "no / none"},
|
||||||
|
{"klavír", NULL, "piano"},
|
||||||
|
{"přicházet, pocházet (z)", NULL, "to come (from)"},
|
||||||
|
{"Pochází z Vídně.", NULL, "He comes from Vienna."},
|
||||||
|
{"koncert", NULL, "concert"},
|
||||||
|
{"ležet", NULL, "to lie"},
|
||||||
|
{"příjmení", NULL, "surname"},
|
||||||
|
{"nedaleko od", NULL, "not far from"},
|
||||||
|
{"cestovat", NULL, "to travel"},
|
||||||
|
{"psát", NULL, "to write"},
|
||||||
|
{"škola", NULL, "school"},
|
||||||
|
{"hrát", NULL, "to play"},
|
||||||
|
{"Hraje na kytaru.", NULL, "She plays the guitar."},
|
||||||
|
{"tancovat", NULL, "to dance"},
|
||||||
|
{"křestní jméno", NULL, "first name"},
|
||||||
|
{"bydliště", NULL, "place of residence"},
|
||||||
|
{"nesprávně, chybně", NULL, "wrong, incorrectly"},
|
||||||
|
{"flétna", NULL, "flute"},
|
||||||
|
{"(hudební) nástroj", NULL, "(musical) instrument"},
|
||||||
|
{"teď", NULL, "now"},
|
||||||
|
{"dělat", NULL, "to do"},
|
||||||
|
{"správně", NULL, "correctly"},
|
||||||
|
{"sport", NULL, "sport"},
|
||||||
|
{"sportovat", NULL, "to do sport"},
|
||||||
|
{"squash", NULL, "squash"},
|
||||||
|
{"jóga", NULL, "yoga"},
|
||||||
|
{"brzy", NULL, "soon"},
|
||||||
|
{"Brzy na shledanou!", NULL, "See you soon!"},
|
||||||
|
{"do", NULL, "until"},
|
||||||
|
{"Do příštího setkání!", NULL, "Until next time!"},
|
||||||
|
{"paní", NULL, "woman / Mrs."},
|
||||||
|
{"pan", NULL, "man / Mr."},
|
||||||
|
{"Měj se hezky!", NULL, "Take care!"},
|
||||||
|
{"muzeum", NULL, "museum"},
|
||||||
|
{"Jdou do muzea.", NULL, "They are going to the museum."},
|
||||||
|
{"hezký", NULL, "beautiful"},
|
||||||
|
{"Hezký zbytek dne!", NULL, "Have a nice rest of the day!"},
|
||||||
|
{"Ahoj! (servus)", NULL, "Hi! (Servus)"},
|
||||||
|
{"Ahoj! (při loučení)", NULL, "Bye!"},
|
||||||
|
{"shledání", NULL, "reunion"},
|
||||||
|
{"Na shledanou!", NULL, "Goodbye!"},
|
||||||
{NULL, NULL, NULL}
|
{NULL, NULL, NULL}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
12
main.c
12
main.c
|
|
@ -31,6 +31,12 @@ void unit_meta_init(void) {
|
||||||
units[1].progress_file = PROGRESS_U2;
|
units[1].progress_file = PROGRESS_U2;
|
||||||
units[2].sub_key = "unit3_sub";
|
units[2].sub_key = "unit3_sub";
|
||||||
units[2].progress_file = PROGRESS_U3;
|
units[2].progress_file = PROGRESS_U3;
|
||||||
|
|
||||||
|
/* Off-path branch hanging above exercise 2 of unit 1. */
|
||||||
|
units[0].has_branch = TRUE;
|
||||||
|
units[0].branch_name = "Vokabeltraining";
|
||||||
|
units[0].branch_target = "u1vocab";
|
||||||
|
units[0].branch_ex = MAX_UNIT_EX;
|
||||||
}
|
}
|
||||||
|
|
||||||
void unit_configure(int idx, const char *const *names, int n) {
|
void unit_configure(int idx, const char *const *names, int n) {
|
||||||
|
|
@ -183,6 +189,12 @@ void activate(GtkApplication *app, gpointer user_data) {
|
||||||
g_snprintf(name, sizeof(name), "%se%d", u->ex_tag, n);
|
g_snprintf(name, sizeof(name), "%se%d", u->ex_tag, n);
|
||||||
gtk_stack_add_named(main_stack, page, name);
|
gtk_stack_add_named(main_stack, page, name);
|
||||||
}
|
}
|
||||||
|
if (u->has_branch && u->branch_target) {
|
||||||
|
GtkWidget *branch = build_translate(u);
|
||||||
|
|
||||||
|
if (branch)
|
||||||
|
gtk_stack_add_named(main_stack, branch, u->branch_target);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
gtk_stack_set_visible_child_name(main_stack, "welcome");
|
gtk_stack_set_visible_child_name(main_stack, "welcome");
|
||||||
|
|
|
||||||
12
maturita.h
12
maturita.h
|
|
@ -36,6 +36,7 @@
|
||||||
#define EX_SPAC 150.0 /* horizontal distance between bubbles */
|
#define EX_SPAC 150.0 /* horizontal distance between bubbles */
|
||||||
#define EX_GAP 200.0 /* vertical space between folded rows */
|
#define EX_GAP 200.0 /* vertical space between folded rows */
|
||||||
#define EX_WAVE 26.0 /* wavy vertical offset of the bubbles */
|
#define EX_WAVE 26.0 /* wavy vertical offset of the bubbles */
|
||||||
|
#define EX_BRANCH_LIFT 150.0 /* extra top space for an off-path branch */
|
||||||
#define HM_WORDS 5
|
#define HM_WORDS 5
|
||||||
#define HM_MAX_MISSES 6
|
#define HM_MAX_MISSES 6
|
||||||
#define HM_N_LETTERS 29 /* QWERTY rows + Ä/Ö/Ü (see hm_letters[]) */
|
#define HM_N_LETTERS 29 /* QWERTY rows + Ä/Ö/Ü (see hm_letters[]) */
|
||||||
|
|
@ -116,6 +117,16 @@ typedef struct {
|
||||||
double ex_cy[MAX_UNIT_EX];
|
double ex_cy[MAX_UNIT_EX];
|
||||||
int ex_rows, ex_cols, ex_cw, ex_ch;
|
int ex_rows, ex_cols, ex_cw, ex_ch;
|
||||||
guint ex_idle;
|
guint ex_idle;
|
||||||
|
/* optional off-path branch exercise (e.g. vocabulary training) */
|
||||||
|
gboolean has_branch;
|
||||||
|
const char *branch_name; /* label under the branch bubble */
|
||||||
|
const char *branch_target; /* stack page name */
|
||||||
|
int branch_ex; /* done[] slot used by the branch */
|
||||||
|
GtkWidget *branch_cell;
|
||||||
|
GtkWidget *branch_label;
|
||||||
|
GtkWidget *branch_icon;
|
||||||
|
double branch_cx;
|
||||||
|
double branch_cy;
|
||||||
} UnitCtx;
|
} UnitCtx;
|
||||||
typedef struct { double r, g, b; } Rgb;
|
typedef struct { double r, g, b; } Rgb;
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
|
@ -816,6 +827,7 @@ char *verbq_german(const char *before, const char *answer,
|
||||||
const char *after);
|
const char *after);
|
||||||
GtkWidget *build_ex8(UnitCtx *unit);
|
GtkWidget *build_ex8(UnitCtx *unit);
|
||||||
GtkWidget *build_ex12(UnitCtx *unit);
|
GtkWidget *build_ex12(UnitCtx *unit);
|
||||||
|
GtkWidget *build_translate(UnitCtx *unit);
|
||||||
void assign_rebuild(AssignCtx *ac);
|
void assign_rebuild(AssignCtx *ac);
|
||||||
void assign_chip_clicked(GtkButton *button, gpointer data);
|
void assign_chip_clicked(GtkButton *button, gpointer data);
|
||||||
void assign_group_toggled(GtkToggleButton *button, gpointer data);
|
void assign_group_toggled(GtkToggleButton *button, gpointer data);
|
||||||
|
|
|
||||||
19
progress.c
19
progress.c
|
|
@ -6,7 +6,7 @@
|
||||||
|
|
||||||
void unit_save_progress(UnitCtx *u) {
|
void unit_save_progress(UnitCtx *u) {
|
||||||
GKeyFile *kf = g_key_file_new();
|
GKeyFile *kf = g_key_file_new();
|
||||||
for (int i = 1; i <= u->n_ex; i++) {
|
for (int i = 1; i <= MAX_UNIT_EX; i++) {
|
||||||
gchar key[8];
|
gchar key[8];
|
||||||
g_snprintf(key, sizeof(key), "%d", i);
|
g_snprintf(key, sizeof(key), "%d", i);
|
||||||
g_key_file_set_boolean(kf, "done", key, u->done[i]);
|
g_key_file_set_boolean(kf, "done", key, u->done[i]);
|
||||||
|
|
@ -40,7 +40,7 @@ void unit_load_progress(UnitCtx *u) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 1; i <= u->n_ex; i++) {
|
for (int i = 1; i <= MAX_UNIT_EX; i++) {
|
||||||
gchar key[8];
|
gchar key[8];
|
||||||
g_snprintf(key, sizeof(key), "%d", i);
|
g_snprintf(key, sizeof(key), "%d", i);
|
||||||
u->done[i] = g_key_file_get_boolean(kf, "done", key, NULL);
|
u->done[i] = g_key_file_get_boolean(kf, "done", key, NULL);
|
||||||
|
|
@ -92,6 +92,19 @@ void refresh_completion_ui(void) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* off-path branch marker */
|
||||||
|
if (u->has_branch && u->branch_cell) {
|
||||||
|
if (u->done[u->branch_ex]) {
|
||||||
|
gtk_widget_add_css_class(u->branch_cell, "done");
|
||||||
|
if (u->branch_icon)
|
||||||
|
gtk_widget_set_visible(u->branch_icon, TRUE);
|
||||||
|
} else {
|
||||||
|
gtk_widget_remove_css_class(u->branch_cell, "done");
|
||||||
|
if (u->branch_icon)
|
||||||
|
gtk_widget_set_visible(u->branch_icon, FALSE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* roadmap node marker */
|
/* roadmap node marker */
|
||||||
if (u->node) {
|
if (u->node) {
|
||||||
if (all && u->n_ex > 0) {
|
if (all && u->n_ex > 0) {
|
||||||
|
|
@ -113,7 +126,7 @@ void refresh_completion_ui(void) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void mark_done(UnitCtx *u, int n) {
|
void mark_done(UnitCtx *u, int n) {
|
||||||
if (!u || n < 1 || n > u->n_ex)
|
if (!u || n < 1 || n > MAX_UNIT_EX)
|
||||||
return;
|
return;
|
||||||
u->done[n] = TRUE;
|
u->done[n] = TRUE;
|
||||||
refresh_completion_ui();
|
refresh_completion_ui();
|
||||||
|
|
|
||||||
|
|
@ -344,6 +344,13 @@ windowcontrols button:not(:hover) image {
|
||||||
.ex-bubble:focus-visible {
|
.ex-bubble:focus-visible {
|
||||||
outline: none;
|
outline: none;
|
||||||
}
|
}
|
||||||
|
.ex-branch {
|
||||||
|
border-style: dashed;
|
||||||
|
border-color: @accent;
|
||||||
|
}
|
||||||
|
.ex-branch:hover {
|
||||||
|
border-style: solid;
|
||||||
|
}
|
||||||
.bubble-number {
|
.bubble-number {
|
||||||
font-size: 22px;
|
font-size: 22px;
|
||||||
font-weight: 800;
|
font-weight: 800;
|
||||||
|
|
|
||||||
93
unitmap.c
93
unitmap.c
|
|
@ -9,6 +9,7 @@
|
||||||
void ex_layout_geometry(UnitCtx *u, double avail) {
|
void ex_layout_geometry(UnitCtx *u, double avail) {
|
||||||
const int n = u->n_ex;
|
const int n = u->n_ex;
|
||||||
const double phase = 2.0 * G_PI * 1.7 / (double)(n > 1 ? n - 1 : 1);
|
const double phase = 2.0 * G_PI * 1.7 / (double)(n > 1 ? n - 1 : 1);
|
||||||
|
const double lift = u->has_branch ? EX_BRANCH_LIFT : 0.0;
|
||||||
int rows;
|
int rows;
|
||||||
int r, c, i;
|
int r, c, i;
|
||||||
|
|
||||||
|
|
@ -26,7 +27,7 @@ void ex_layout_geometry(UnitCtx *u, double avail) {
|
||||||
if (u->ex_cols < 1)
|
if (u->ex_cols < 1)
|
||||||
u->ex_cols = 1;
|
u->ex_cols = 1;
|
||||||
u->ex_cw = (int)(2.0 * EX_MX + (u->ex_cols - 1) * EX_SPAC);
|
u->ex_cw = (int)(2.0 * EX_MX + (u->ex_cols - 1) * EX_SPAC);
|
||||||
u->ex_ch = (int)(2.0 * EX_MY + (rows - 1) * EX_GAP);
|
u->ex_ch = (int)(2.0 * EX_MY + (rows - 1) * EX_GAP + lift);
|
||||||
|
|
||||||
for (r = 0; r < rows; r++) {
|
for (r = 0; r < rows; r++) {
|
||||||
int base = r * u->ex_cols;
|
int base = r * u->ex_cols;
|
||||||
|
|
@ -36,10 +37,16 @@ void ex_layout_geometry(UnitCtx *u, double avail) {
|
||||||
i = base + c;
|
i = base + c;
|
||||||
int cc = fwd ? c : (u->ex_cols - 1 - c);
|
int cc = fwd ? c : (u->ex_cols - 1 - c);
|
||||||
u->ex_cx[i] = EX_MX + cc * EX_SPAC;
|
u->ex_cx[i] = EX_MX + cc * EX_SPAC;
|
||||||
u->ex_cy[i] = EX_MY + r * EX_GAP
|
u->ex_cy[i] = EX_MY + lift + r * EX_GAP
|
||||||
+ EX_WAVE * sin((double)i * phase);
|
+ EX_WAVE * sin((double)i * phase);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* The branch hangs straight above exercise 2 (index 1). */
|
||||||
|
if (u->has_branch && n > 1) {
|
||||||
|
u->branch_cx = u->ex_cx[1];
|
||||||
|
u->branch_cy = u->ex_cy[1] - EX_BRANCH_LIFT;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ex_point(UnitCtx *u, double t, double *ox, double *oy) {
|
void ex_point(UnitCtx *u, double t, double *ox, double *oy) {
|
||||||
|
|
@ -125,6 +132,28 @@ void draw_ex_rail(GtkDrawingArea *area, cairo_t *cr,
|
||||||
cairo_set_line_width(cr, 9);
|
cairo_set_line_width(cr, 9);
|
||||||
cairo_stroke(cr);
|
cairo_stroke(cr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Off-path branch connector up from exercise 2. */
|
||||||
|
if (u->has_branch && u->n_ex > 1) {
|
||||||
|
gboolean bdone = u->done[u->branch_ex];
|
||||||
|
|
||||||
|
cairo_new_path(cr);
|
||||||
|
cairo_move_to(cr, u->ex_cx[1], u->ex_cy[1]);
|
||||||
|
cairo_line_to(cr, u->branch_cx, u->branch_cy);
|
||||||
|
cairo_set_line_width(cr, 14);
|
||||||
|
cairo_set_source_rgb(cr, rail.r, rail.g, rail.b);
|
||||||
|
cairo_stroke(cr);
|
||||||
|
|
||||||
|
cairo_new_path(cr);
|
||||||
|
cairo_move_to(cr, u->ex_cx[1], u->ex_cy[1]);
|
||||||
|
cairo_line_to(cr, u->branch_cx, u->branch_cy);
|
||||||
|
cairo_set_line_width(cr, 9);
|
||||||
|
if (bdone)
|
||||||
|
cairo_set_source_rgba(cr, green.r, green.g, green.b, 0.85);
|
||||||
|
else
|
||||||
|
cairo_set_source_rgb(cr, slate.r, slate.g, slate.b);
|
||||||
|
cairo_stroke(cr);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ex_apply_layout(UnitCtx *u) {
|
void ex_apply_layout(UnitCtx *u) {
|
||||||
|
|
@ -144,6 +173,16 @@ void ex_apply_layout(UnitCtx *u) {
|
||||||
(int)(u->ex_cy[i] + EX_BUBBLE / 2.0 + 8.0));
|
(int)(u->ex_cy[i] + EX_BUBBLE / 2.0 + 8.0));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (u->has_branch && u->branch_cell) {
|
||||||
|
gtk_fixed_move(GTK_FIXED(u->ex_fixed), u->branch_cell,
|
||||||
|
(int)(u->branch_cx - EX_BUBBLE / 2.0),
|
||||||
|
(int)(u->branch_cy - EX_BUBBLE / 2.0));
|
||||||
|
if (u->branch_label)
|
||||||
|
gtk_fixed_move(GTK_FIXED(u->ex_fixed), u->branch_label,
|
||||||
|
(int)(u->branch_cx + EX_BUBBLE / 2.0 + 10.0),
|
||||||
|
(int)(u->branch_cy - 14.0));
|
||||||
|
}
|
||||||
|
|
||||||
gtk_widget_set_size_request(u->ex_fixed, u->ex_cw, u->ex_ch);
|
gtk_widget_set_size_request(u->ex_fixed, u->ex_cw, u->ex_ch);
|
||||||
gtk_widget_set_size_request(u->ex_rail, u->ex_cw, u->ex_ch);
|
gtk_widget_set_size_request(u->ex_rail, u->ex_cw, u->ex_ch);
|
||||||
gtk_fixed_move(GTK_FIXED(u->ex_fixed), u->ex_rail, 0, 0);
|
gtk_fixed_move(GTK_FIXED(u->ex_fixed), u->ex_rail, 0, 0);
|
||||||
|
|
@ -225,6 +264,43 @@ GtkWidget *make_bubble(UnitCtx *u, int n) {
|
||||||
return btn;
|
return btn;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static GtkWidget *make_branch_bubble(UnitCtx *u) {
|
||||||
|
GtkWidget *btn;
|
||||||
|
GtkWidget *vbox;
|
||||||
|
GtkWidget *star;
|
||||||
|
GtkWidget *icon;
|
||||||
|
|
||||||
|
btn = gtk_button_new();
|
||||||
|
gtk_widget_add_css_class(btn, "ex-bubble");
|
||||||
|
gtk_widget_add_css_class(btn, "ex-branch");
|
||||||
|
gtk_widget_set_size_request(btn, (int)EX_BUBBLE, (int)EX_BUBBLE);
|
||||||
|
gtk_widget_set_can_focus(btn, FALSE);
|
||||||
|
if (u->done[u->branch_ex])
|
||||||
|
gtk_widget_add_css_class(btn, "done");
|
||||||
|
|
||||||
|
vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 2);
|
||||||
|
gtk_widget_set_halign(vbox, GTK_ALIGN_CENTER);
|
||||||
|
gtk_widget_set_valign(vbox, GTK_ALIGN_CENTER);
|
||||||
|
gtk_button_set_child(GTK_BUTTON(btn), vbox);
|
||||||
|
|
||||||
|
star = gtk_label_new("★");
|
||||||
|
gtk_widget_set_halign(star, GTK_ALIGN_CENTER);
|
||||||
|
gtk_widget_add_css_class(star, "bubble-number");
|
||||||
|
gtk_box_append(GTK_BOX(vbox), star);
|
||||||
|
|
||||||
|
icon = icon_area_new(draw_check_icon, 0.1176, 0.1176, 0.1804, 16);
|
||||||
|
gtk_widget_set_visible(icon, u->done[u->branch_ex]);
|
||||||
|
gtk_box_append(GTK_BOX(vbox), icon);
|
||||||
|
|
||||||
|
u->branch_cell = btn;
|
||||||
|
u->branch_icon = icon;
|
||||||
|
|
||||||
|
g_object_set_data_full(G_OBJECT(btn), "target",
|
||||||
|
g_strdup(u->branch_target), g_free);
|
||||||
|
g_signal_connect(btn, "clicked", G_CALLBACK(on_nav_clicked), NULL);
|
||||||
|
return btn;
|
||||||
|
}
|
||||||
|
|
||||||
GtkWidget *build_unit_page(UnitCtx *u) {
|
GtkWidget *build_unit_page(UnitCtx *u) {
|
||||||
GtkWidget *page;
|
GtkWidget *page;
|
||||||
GtkWidget *scroll;
|
GtkWidget *scroll;
|
||||||
|
|
@ -293,6 +369,19 @@ GtkWidget *build_unit_page(UnitCtx *u) {
|
||||||
gtk_fixed_put(GTK_FIXED(fixed), lbl, 0, 0);
|
gtk_fixed_put(GTK_FIXED(fixed), lbl, 0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (u->has_branch && u->branch_target) {
|
||||||
|
GtkWidget *btn = make_branch_bubble(u);
|
||||||
|
GtkWidget *lbl = gtk_label_new(u->branch_name);
|
||||||
|
|
||||||
|
u->branch_label = lbl;
|
||||||
|
gtk_widget_set_halign(lbl, GTK_ALIGN_START);
|
||||||
|
gtk_widget_add_css_class(lbl, "ex-label");
|
||||||
|
gtk_widget_set_visible(lbl, TRUE);
|
||||||
|
|
||||||
|
gtk_fixed_put(GTK_FIXED(fixed), btn, 0, 0);
|
||||||
|
gtk_fixed_put(GTK_FIXED(fixed), lbl, 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
ha = gtk_scrolled_window_get_hadjustment(GTK_SCROLLED_WINDOW(scroll));
|
ha = gtk_scrolled_window_get_hadjustment(GTK_SCROLLED_WINDOW(scroll));
|
||||||
va = gtk_scrolled_window_get_vadjustment(GTK_SCROLLED_WINDOW(scroll));
|
va = gtk_scrolled_window_get_vadjustment(GTK_SCROLLED_WINDOW(scroll));
|
||||||
g_signal_connect(ha, "notify::page-size",
|
g_signal_connect(ha, "notify::page-size",
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue