mirror of
https://github.com/pepaskopec-blip/Graduately.git
synced 2026-10-27 07:04:35 +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);
|
||||
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."},
|
||||
{"sub_land", "Přiřaďte symboly ke správné zemi.",
|
||||
"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",
|
||||
"Vyberte skupinu a klikněte na kartu. Kliknutím na kartu ve skupině "
|
||||
"ji vrátíte zpět.",
|
||||
|
|
@ -592,6 +595,130 @@ const TrEntry tr_content[] = {
|
|||
"My brother is driving to a lake."},
|
||||
{"A já? Navštívím obchodní centrum.", NULL,
|
||||
"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}
|
||||
};
|
||||
|
||||
|
|
|
|||
12
main.c
12
main.c
|
|
@ -31,6 +31,12 @@ void unit_meta_init(void) {
|
|||
units[1].progress_file = PROGRESS_U2;
|
||||
units[2].sub_key = "unit3_sub";
|
||||
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) {
|
||||
|
|
@ -183,6 +189,12 @@ void activate(GtkApplication *app, gpointer user_data) {
|
|||
g_snprintf(name, sizeof(name), "%se%d", u->ex_tag, n);
|
||||
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");
|
||||
|
|
|
|||
12
maturita.h
12
maturita.h
|
|
@ -36,6 +36,7 @@
|
|||
#define EX_SPAC 150.0 /* horizontal distance between bubbles */
|
||||
#define EX_GAP 200.0 /* vertical space between folded rows */
|
||||
#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_MAX_MISSES 6
|
||||
#define HM_N_LETTERS 29 /* QWERTY rows + Ä/Ö/Ü (see hm_letters[]) */
|
||||
|
|
@ -116,6 +117,16 @@ typedef struct {
|
|||
double ex_cy[MAX_UNIT_EX];
|
||||
int ex_rows, ex_cols, ex_cw, ex_ch;
|
||||
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;
|
||||
typedef struct { double r, g, b; } Rgb;
|
||||
typedef struct {
|
||||
|
|
@ -816,6 +827,7 @@ char *verbq_german(const char *before, const char *answer,
|
|||
const char *after);
|
||||
GtkWidget *build_ex8(UnitCtx *unit);
|
||||
GtkWidget *build_ex12(UnitCtx *unit);
|
||||
GtkWidget *build_translate(UnitCtx *unit);
|
||||
void assign_rebuild(AssignCtx *ac);
|
||||
void assign_chip_clicked(GtkButton *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) {
|
||||
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];
|
||||
g_snprintf(key, sizeof(key), "%d", i);
|
||||
g_key_file_set_boolean(kf, "done", key, u->done[i]);
|
||||
|
|
@ -40,7 +40,7 @@ void unit_load_progress(UnitCtx *u) {
|
|||
return;
|
||||
}
|
||||
|
||||
for (int i = 1; i <= u->n_ex; i++) {
|
||||
for (int i = 1; i <= MAX_UNIT_EX; i++) {
|
||||
gchar key[8];
|
||||
g_snprintf(key, sizeof(key), "%d", i);
|
||||
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 */
|
||||
if (u->node) {
|
||||
if (all && u->n_ex > 0) {
|
||||
|
|
@ -113,7 +126,7 @@ void refresh_completion_ui(void) {
|
|||
}
|
||||
|
||||
void mark_done(UnitCtx *u, int n) {
|
||||
if (!u || n < 1 || n > u->n_ex)
|
||||
if (!u || n < 1 || n > MAX_UNIT_EX)
|
||||
return;
|
||||
u->done[n] = TRUE;
|
||||
refresh_completion_ui();
|
||||
|
|
|
|||
|
|
@ -344,6 +344,13 @@ windowcontrols button:not(:hover) image {
|
|||
.ex-bubble:focus-visible {
|
||||
outline: none;
|
||||
}
|
||||
.ex-branch {
|
||||
border-style: dashed;
|
||||
border-color: @accent;
|
||||
}
|
||||
.ex-branch:hover {
|
||||
border-style: solid;
|
||||
}
|
||||
.bubble-number {
|
||||
font-size: 22px;
|
||||
font-weight: 800;
|
||||
|
|
|
|||
93
unitmap.c
93
unitmap.c
|
|
@ -9,6 +9,7 @@
|
|||
void ex_layout_geometry(UnitCtx *u, double avail) {
|
||||
const int n = u->n_ex;
|
||||
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 r, c, i;
|
||||
|
||||
|
|
@ -26,7 +27,7 @@ void ex_layout_geometry(UnitCtx *u, double avail) {
|
|||
if (u->ex_cols < 1)
|
||||
u->ex_cols = 1;
|
||||
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++) {
|
||||
int base = r * u->ex_cols;
|
||||
|
|
@ -36,10 +37,16 @@ void ex_layout_geometry(UnitCtx *u, double avail) {
|
|||
i = base + c;
|
||||
int cc = fwd ? c : (u->ex_cols - 1 - c);
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
/* 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) {
|
||||
|
|
@ -125,6 +132,28 @@ void draw_ex_rail(GtkDrawingArea *area, cairo_t *cr,
|
|||
cairo_set_line_width(cr, 9);
|
||||
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) {
|
||||
|
|
@ -144,6 +173,16 @@ void ex_apply_layout(UnitCtx *u) {
|
|||
(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_rail, u->ex_cw, u->ex_ch);
|
||||
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;
|
||||
}
|
||||
|
||||
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 *page;
|
||||
GtkWidget *scroll;
|
||||
|
|
@ -293,6 +369,19 @@ GtkWidget *build_unit_page(UnitCtx *u) {
|
|||
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));
|
||||
va = gtk_scrolled_window_get_vadjustment(GTK_SCROLLED_WINDOW(scroll));
|
||||
g_signal_connect(ha, "notify::page-size",
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue