Add five hardware lessons on sampling and quantizing sound.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
pepaskopec-blip 2026-09-25 21:13:22 +02:00
commit 9860c56329
7 changed files with 420 additions and 5 deletions

View file

@ -65,7 +65,7 @@ Intel Mac, jiná architektura nebo úpravy kódu → [sestavení ze zdroje](#ses
Hause): cvičení, nápovědy, vokabeltraining Hause): cvičení, nápovědy, vokabeltraining
- **Správa počítačových sítí** — 1. ročník, 27 lekcí (VLSM + teorie a kvízy); - **Správa počítačových sítí** — 1. ročník, 27 lekcí (VLSM + teorie a kvízy);
ročníky 2–4 jsou zamčené ročníky 2–4 jsou zamčené
- **Technické vybavení** — 3 lekce (architektura, historie, bit/byte) - **Technické vybavení** — 9 lekcí (architektura, historie, data v počítači, digitalizace zvuku)
- **Český jazyk a literatura** — mluvnice (20 cvičení) a maturitní četba - **Český jazyk a literatura** — mluvnice (20 cvičení) a maturitní četba
(82 knih: zápisky, kvíz, sestavení děje); literární teorie je zatím zamčená (82 knih: zápisky, kvíz, sestavení děje); literární teorie je zatím zamčená
- statistiky, hledání (lupa nebo `Cmd/Ctrl+K`), 10 témat, tmavý/světlý režim, čeština/angličtina - statistiky, hledání (lupa nebo `Cmd/Ctrl+K`), 10 témat, tmavý/světlý režim, čeština/angličtina
@ -259,7 +259,7 @@ Intel Mac, another architecture, or hacking on the code →
exercises, hints, vocabulary training exercises, hints, vocabulary training
- **Computer networks** — year 1, 27 lessons (VLSM + theory/quizzes); - **Computer networks** — year 1, 27 lessons (VLSM + theory/quizzes);
years 2–4 are locked years 2–4 are locked
- **Computer hardware** — 3 lessons (architecture, history, bit/byte) - **Computer hardware** — 9 lessons (architecture, history, data representation, digitizing sound)
- **Czech language** — grammar (20 exercises) and required reading - **Czech language** — grammar (20 exercises) and required reading
(82 books: notes, quiz, plot ordering); literature theory is still locked (82 books: notes, quiz, plot ordering); literature theory is still locked
- statistics, search (magnifier or `Cmd/Ctrl+K`), 10 palettes, dark/light mode, Czech/English - statistics, search (magnifier or `Cmd/Ctrl+K`), 10 palettes, dark/light mode, Czech/English

View file

@ -6,6 +6,10 @@
# cs: bullet # cs: bullet
# en: bullet # en: bullet
--- 2026-09-25
cs: Technické vybavení: pět lekcí o digitalizaci zvuku (vzorkování, kvantování, PCM)
en: Hardware: five lessons on digitizing sound (sampling, quantization, PCM)
--- 2026-09-23 --- 2026-09-23
cs: Repozitář se jmenuje Graduately; instalátory a updater míří tam cs: Repozitář se jmenuje Graduately; instalátory a updater míří tam
cs: Balíčky a instalátory se jmenují graduately-* (už ne maturita-*) cs: Balíčky a instalátory se jmenují graduately-* (už ne maturita-*)

View file

@ -1085,7 +1085,7 @@ def main() -> int:
}) })
hw_lessons = [] hw_lessons = []
for i in range(1, 5): for i in range(1, 10):
hw_lessons.append({ hw_lessons.append({
"id": i, "id": i,
"titleKey": f"hw_unit{i}", "titleKey": f"hw_unit{i}",

351
src/hw.c
View file

@ -7,6 +7,11 @@ NetLesson hw_lessons[HW_LESSONS] = {
{ .n_slides = HW2_SLIDES, .unit_page = "hwunit2", .ex_page = "hwex2" }, { .n_slides = HW2_SLIDES, .unit_page = "hwunit2", .ex_page = "hwex2" },
{ .n_slides = HW3_SLIDES, .unit_page = "hwunit3", .ex_page = "hwex3" }, { .n_slides = HW3_SLIDES, .unit_page = "hwunit3", .ex_page = "hwex3" },
{ .n_slides = HW4_SLIDES, .unit_page = "hwunit4", .ex_page = "hwex4" }, { .n_slides = HW4_SLIDES, .unit_page = "hwunit4", .ex_page = "hwex4" },
{ .n_slides = HW5_SLIDES, .unit_page = "hwunit5", .ex_page = "hwex5" },
{ .n_slides = HW6_SLIDES, .unit_page = "hwunit6", .ex_page = "hwex6" },
{ .n_slides = HW7_SLIDES, .unit_page = "hwunit7", .ex_page = "hwex7" },
{ .n_slides = HW8_SLIDES, .unit_page = "hwunit8", .ex_page = "hwex8" },
{ .n_slides = HW9_SLIDES, .unit_page = "hwunit9", .ex_page = "hwex9" },
}; };
void hw_rail_theme_reset(void); void hw_rail_theme_reset(void);
@ -253,7 +258,8 @@ void hw_add_node(GtkFixed *fixed, int index) {
GtkWidget *name; GtkWidget *name;
char *text; char *text;
static const char *unit_keys[HW_LESSONS] = { static const char *unit_keys[HW_LESSONS] = {
"hw_unit1", "hw_unit2", "hw_unit3", "hw_unit4" "hw_unit1", "hw_unit2", "hw_unit3", "hw_unit4",
"hw_unit5", "hw_unit6", "hw_unit7", "hw_unit8", "hw_unit9"
}; };
card = gtk_button_new(); card = gtk_button_new();
@ -979,3 +985,346 @@ GtkWidget *build_hw_unit4_exercise_page(void) {
return build_hw_mcq_page(3, "hwunit4", "hw_ex4_title", "hw_quiz4_head", return build_hw_mcq_page(3, "hwunit4", "hw_ex4_title", "hw_quiz4_head",
qs, hints, 4); qs, hints, 4);
} }
GtkWidget *build_hw_unit5_page(void) {
static const NetSlide slides[HW5_SLIDES] = {
{
"1 / 2 • Signál", "Analogový a digitální zvuk",
"Tip: analog je spojitý, digitál je posloupnost čísel.",
{
"Analogový zvuk je spojitý signál – v každém okamžiku "
"má nějakou hodnotu.",
"Digitální zvuk je posloupnost čísel, která ten signál "
"popisují.",
"Z mikrofonu vychází analogové napětí, do reproduktoru "
"musí zase jít spojitý signál.",
"Počítač umí uložit jen čísla, proto se zvuk digitalizuje.",
NULL,
},
},
{
"2 / 2 • Převod", "A/D a D/A převodník",
"Tip: ADC dovnitř, DAC ven. Digitalizace = vzorkování + kvantování.",
{
"A/D převodník (ADC) převede analogový signál na čísla.",
"D/A převodník (DAC) z čísel znovu složí spojitý signál.",
"Digitalizace má dva kroky: vzorkování a kvantování.",
"Vzorkování určí, kdy se hodnota změří.",
"Kvantování určí, na kolik hladin se amplituda zaokrouhlí.",
NULL,
},
},
};
return build_hw_unit_page(&hw_lessons[4], "hw_unit5", "hw_unit5_sub",
slides, HW5_SLIDES);
}
GtkWidget *build_hw_unit5_exercise_page(void) {
static const ChoiceQ qs[] = {
{"Co je analogový zvuk?",
{"Posloupnost celých čísel",
"Spojitý signál s hodnotou v každém okamžiku",
"Jen název souboru WAV",
"Jen bit v paměti"},
4, 1},
{"Co dělá A/D převodník (ADC)?",
{"Převádí analogový signál na čísla",
"Zesiluje jen reproduktor",
"Maže vysoké tóny po uložení",
"Počítá jen velikost souboru"},
4, 0},
{"Jaké jsou dva hlavní kroky digitalizace zvuku?",
{"Komprese a tisk",
"Vzorkování a kvantování",
"Šifrování a záloha",
"Násobení a dělení"},
4, 1},
{"Co dělá D/A převodník (DAC)?",
{"Z čísel znovu skládá spojitý signál",
"Měří jen vzorkovací frekvenci",
"Ukládá zvuk jako text",
"Zvyšuje počet bitů v souboru"},
4, 0},
};
static const char *hints[] = {
"Analog = spojitý signál",
"ADC převádí analog na čísla",
"Digitalizace = vzorkování + kvantování",
"DAC skládá z čísel spojitý signál",
};
return build_hw_mcq_page(4, "hwunit5", "hw_ex5_title", "hw_quiz5_head",
qs, hints, 4);
}
GtkWidget *build_hw_unit6_page(void) {
static const NetSlide slides[HW6_SLIDES] = {
{
"1 / 2 • Vzorky", "Vzorkování",
"Tip: vzorkovací frekvence fs = počet vzorků za sekundu (Hz).",
{
"Vzorkování měří velikost signálu v pravidelných "
"okamžicích.",
"Mezi vzorky se hodnota neukládá.",
"Vzorkovací frekvence fs je počet vzorků za sekundu.",
"Jednotka je hertz (Hz). 1 kHz = 1000 vzorků za sekundu.",
"Vyšší fs zachytí rychlejší změny, tedy vyšší tóny.",
NULL,
},
},
{
"2 / 2 • Nyquist", "Nyquistův–Shannonův teorém",
"Tip: fs musí být vyšší než 2 × fmax. Nyquistova frekvence je fs / 2.",
{
"Pro věrnou rekonstrukci musí být fs vyšší než dvojnásobek "
"nejvyšší frekvence ve signálu.",
"Nyquistova frekvence je fs / 2 – vyšší tón už záznam neunese.",
"Člověk slyší zhruba do 20 kHz, dvojnásobek je 40 kHz.",
"CD proto používá 44,1 kHz: o něco víc než 40 kHz, "
"aby zbyl prostor pro filtr.",
NULL,
},
},
};
return build_hw_unit_page(&hw_lessons[5], "hw_unit6", "hw_unit6_sub",
slides, HW6_SLIDES);
}
GtkWidget *build_hw_unit6_exercise_page(void) {
static const ChoiceQ qs[] = {
{"Co je vzorkovací frekvence?",
{"Počet bitů v jednom vzorku",
"Počet vzorků za sekundu",
"Délka skladby v minutách",
"Počet kanálů (mono nebo stereo)"},
4, 1},
{"V jakých jednotkách se udává vzorkovací frekvence?",
{"V bytech", "V hertzech", "Ve voltech", "V pixelech"},
4, 1},
{"Co říká Nyquistův–Shannonův teorém?",
{"fs musí být vyšší než dvojnásobek nejvyšší frekvence",
"fs musí být vždy 8 kHz",
"Stačí jeden vzorek na celou skladbu",
"Bitová hloubka musí být 1"},
4, 0},
{"Proč má audio CD vzorkovací frekvenci 44,1 kHz?",
{"Protože byte má 8 bitů",
"Sluch sahá asi do 20 kHz a fs musí být vyšší než dvojnásobek",
"Protože stereo má dva kanály",
"Protože minutu tvoří 60 sekund"},
4, 1},
};
static const char *hints[] = {
"fs = počet vzorků za sekundu",
"Jednotka vzorkovací frekvence je hertz",
"fs > 2 × fmax",
"20 kHz × 2 = 40 kHz, CD má 44,1 kHz",
};
return build_hw_mcq_page(5, "hwunit6", "hw_ex6_title", "hw_quiz6_head",
qs, hints, 4);
}
GtkWidget *build_hw_unit7_page(void) {
static const NetSlide slides[HW7_SLIDES] = {
{
"1 / 2 • Hladiny", "Kvantování",
"Tip: n bitů → 2ⁿ hladin. 8 bitů = 256, 16 bitů = 65 536.",
{
"Kvantování zaokrouhlí amplitudu každého vzorku "
"na nejbližší z konečného počtu hladin.",
"Počet hladin je 2ⁿ, kde n je bitová hloubka "
"(počet bitů na vzorek).",
"8 bitů dává 256 hladin, 16 bitů dává 65 536 hladin.",
"Vzorkování říká jak často, kvantování jak přesně.",
NULL,
},
},
{
"2 / 2 • Chyba", "Kvantizační chyba",
"Tip: víc bitů = jemnější hladiny, menší šum a větší soubor.",
{
"Kvantizační chyba je rozdíl mezi skutečnou hodnotou "
"a zvolenou hladinou.",
"V záznamu se projeví jako kvantizační šum.",
"Větší bitová hloubka hladiny zjemní a šum zmenší.",
"Audio CD používá 16 bitů na vzorek, studio často 24 bitů.",
"Vyšší hloubka také zvětší datový tok.",
NULL,
},
},
};
return build_hw_unit_page(&hw_lessons[6], "hw_unit7", "hw_unit7_sub",
slides, HW7_SLIDES);
}
GtkWidget *build_hw_unit7_exercise_page(void) {
static const ChoiceQ qs[] = {
{"Co je kvantování?",
{"Měření signálu v pravidelných okamžicích",
"Zaokrouhlení amplitudy na konečný počet hladin",
"Převod čísel zpět na analog",
"Komprese souboru MP3"},
4, 1},
{"Kolik hladin má 8bitové kvantování?",
{"8", "16", "256", "65 536"},
4, 2},
{"Kolik hladin má 16bitové kvantování?",
{"16", "256", "1 024", "65 536"},
4, 3},
{"Co je kvantizační chyba?",
{"Rozdíl mezi skutečnou hodnotou a zvolenou hladinou",
"Příliš nízká vzorkovací frekvence",
"Počet kanálů ve stereu",
"Délka skladby v sekundách"},
4, 0},
};
static const char *hints[] = {
"Kvantování zaokrouhluje amplitudu na hladiny",
"8 bitů → 2⁸ = 256 hladin",
"16 bitů → 2¹⁶ = 65 536 hladin",
"Kvantizační chyba = rozdíl proti skutečné hodnotě",
};
return build_hw_mcq_page(6, "hwunit7", "hw_ex7_title", "hw_quiz7_head",
qs, hints, 4);
}
GtkWidget *build_hw_unit8_page(void) {
static const NetSlide slides[HW8_SLIDES] = {
{
"1 / 2 • PCM", "Pulzně kódová modulace",
"Tip: tok = fs × bity na vzorek × počet kanálů.",
{
"PCM uloží každý vzorek jako binární číslo.",
"Je to základní nekomprimovaný záznam (WAV, audio CD).",
"Datový tok = vzorkovací frekvence × bitová hloubka "
"× počet kanálů.",
"Mono má jeden kanál, stereo dva (levý a pravý).",
NULL,
},
},
{
"2 / 2 • Velikost", "Kolik dat zabere CD",
"Tip: komprese (MP3, AAC) soubor zmenší, ale část informace zahodí.",
{
"CD stereo: 44 100 Hz × 16 bit × 2 = 1 411 200 bit/s.",
"To je 176 400 B/s.",
"Za minutu je to 10 584 000 B, tedy přes 10 MB.",
"Delší záznam, vyšší fs, více bitů nebo více kanálů "
"soubor zvětší.",
"MP3 a AAC soubor zmenší za cenu ztráty části informace.",
NULL,
},
},
};
return build_hw_unit_page(&hw_lessons[7], "hw_unit8", "hw_unit8_sub",
slides, HW8_SLIDES);
}
GtkWidget *build_hw_unit8_exercise_page(void) {
static const ChoiceQ qs[] = {
{"Co je PCM?",
{"Každý vzorek uložený jako binární číslo",
"Jen komprimovaný formát MP3",
"Filtr před mikrofonem",
"Jednotka hlasitosti"},
4, 0},
{"Jak se spočítá datový tok nekomprimovaného zvuku?",
{"fs + bity + kanály",
"fs × bitová hloubka × počet kanálů",
"jen délka skladby v minutách",
"počet hladin děleno dvěma"},
4, 1},
{"Jaký je datový tok audio CD ve stereu?",
{"44 100 bit/s", "256 bit/s", "1 411 200 bit/s", "8 bit/s"},
4, 2},
{"Co udělá komprese MP3 se záznamem?",
{"Zvětší soubor a přidá vzorky",
"Zmenší soubor a část informace zahodí",
"Změní jen název souboru",
"Převede digitál zpět na analog"},
4, 1},
};
static const char *hints[] = {
"PCM = vzorek jako binární číslo",
"tok = fs × bity × kanály",
"44 100 × 16 × 2 = 1 411 200 bit/s",
"MP3 soubor zmenší a část informace zahodí",
};
return build_hw_mcq_page(7, "hwunit8", "hw_ex8_title", "hw_quiz8_head",
qs, hints, 4);
}
GtkWidget *build_hw_unit9_page(void) {
static const NetSlide slides[HW9_SLIDES] = {
{
"1 / 2 • Aliasing", "Když je vzorkování moc řídké",
"Tip: aliasing vznikne před uložením a z hotových vzorků "
"už nejde spolehlivě odstranit.",
{
"Aliasing vznikne, když je fs příliš nízká a poruší se "
"Nyquistovo pravidlo.",
"Vysoká frekvence se v záznamu jeví jako nižší tón.",
"Příklad: tón 6 kHz vzorkovaný 8 kHz se jeví jako 2 kHz.",
"Antialiasingový filtr před převodníkem vysoké frekvence "
"ořízne.",
NULL,
},
},
{
"2 / 2 • Formáty", "Běžné parametry záznamu",
"Tip: vyšší fs a víc bitů znamená věrnější záznam a větší tok.",
{
"Audio CD: 44,1 kHz, 16 bitů, stereo.",
"Klasický telefonní hovor: 8 kHz a 8 bitů – řeč se vejde "
"do pásma do 4 kHz.",
"Studio často používá 48 nebo 96 kHz a 24 bitů.",
"Parametry se volí podle toho, co má záznam unést "
"a jak velký smí být.",
NULL,
},
},
};
return build_hw_unit_page(&hw_lessons[8], "hw_unit9", "hw_unit9_sub",
slides, HW9_SLIDES);
}
GtkWidget *build_hw_unit9_exercise_page(void) {
static const ChoiceQ qs[] = {
{"Kdy vzniká aliasing?",
{"Když je vzorkovací frekvence příliš nízká",
"Když má záznam 24 bitů",
"Když je soubor ve stereu",
"Když se použije D/A převodník"},
4, 0},
{"K čemu je antialiasingový filtr?",
{"Zvětší bitovou hloubku po uložení",
"Před vzorkováním ořízne frekvence nad Nyquistovu",
"Spočítá datový tok",
"Převede mono na stereo"},
4, 1},
{"Jaké parametry má audio CD?",
{"8 kHz, 8 bitů, mono",
"44,1 kHz, 16 bitů, stereo",
"96 kHz, 8 bitů, mono",
"1 kHz, 1 bit, stereo"},
4, 1},
{"Proč telefonnímu hovoru stačí vzorkování 8 kHz?",
{"Řeč se vejde do pásma zhruba do 4 kHz",
"Telefon nahrává na audio CD",
"8 kHz je totéž co 44,1 kHz",
"Řeč nemá žádnou frekvenci"},
4, 0},
};
static const char *hints[] = {
"Aliasing = příliš nízká fs",
"Filtr ořízne frekvence nad fs / 2 ještě před vzorkováním",
"CD = 44,1 kHz, 16 bit, stereo",
"Pásmo řeči je do asi 4 kHz, proto stačí fs = 8 kHz",
};
return build_hw_mcq_page(8, "hwunit9", "hw_ex9_title", "hw_quiz9_head",
qs, hints, 4);
}

View file

@ -549,6 +549,41 @@ const TrEntry tr_ui[] = {
"Quiz: integer and real"}, "Quiz: integer and real"},
{"hw_quiz4_head", "Kvíz k celým a desetinným číslům", {"hw_quiz4_head", "Kvíz k celým a desetinným číslům",
"Quiz on integers and floating-point numbers"}, "Quiz on integers and floating-point numbers"},
{"hw_unit5", "Analogový a digitální zvuk", "Analog and digital sound"},
{"hw_unit5_sub", "2 snímky o převodu zvuku na čísla a pak kvíz.",
"2 slides about turning sound into numbers, then a quiz."},
{"hw_ex5_title", "Kvíz: analog a digitál",
"Quiz: analog and digital"},
{"hw_quiz5_head", "Kvíz k analogovému a digitálnímu zvuku",
"Quiz on analog and digital sound"},
{"hw_unit6", "Vzorkování", "Sampling"},
{"hw_unit6_sub", "2 snímky o vzorkovací frekvenci a Nyquistovi a pak kvíz.",
"2 slides about sample rate and Nyquist, then a quiz."},
{"hw_ex6_title", "Kvíz: vzorkování",
"Quiz: sampling"},
{"hw_quiz6_head", "Kvíz ke vzorkování zvuku",
"Quiz on sampling sound"},
{"hw_unit7", "Kvantování", "Quantization"},
{"hw_unit7_sub", "2 snímky o bitové hloubce a kvantizační chybě a pak kvíz.",
"2 slides about bit depth and quantization error, then a quiz."},
{"hw_ex7_title", "Kvíz: kvantování",
"Quiz: quantization"},
{"hw_quiz7_head", "Kvíz ke kvantování zvuku",
"Quiz on quantizing sound"},
{"hw_unit8", "PCM a datový tok", "PCM and data rate"},
{"hw_unit8_sub", "2 snímky o PCM a velikosti záznamu a pak kvíz.",
"2 slides about PCM and recording size, then a quiz."},
{"hw_ex8_title", "Kvíz: PCM a datový tok",
"Quiz: PCM and data rate"},
{"hw_quiz8_head", "Kvíz k PCM a datovému toku",
"Quiz on PCM and data rate"},
{"hw_unit9", "Aliasing a parametry", "Aliasing and formats"},
{"hw_unit9_sub", "2 snímky o aliasingu a běžných formátech a pak kvíz.",
"2 slides about aliasing and common formats, then a quiz."},
{"hw_ex9_title", "Kvíz: aliasing a parametry",
"Quiz: aliasing and formats"},
{"hw_quiz9_head", "Kvíz k aliasingu a parametrům záznamu",
"Quiz on aliasing and recording formats"},
{"czech_sub", "Vyberte oblast a začněte procvičovat.", {"czech_sub", "Vyberte oblast a začněte procvičovat.",
"Pick an area and start practicing."}, "Pick an area and start practicing."},
{"Literatura", "Literatura", "Literature"}, {"Literatura", "Literatura", "Literature"},

View file

@ -391,6 +391,8 @@ static gboolean run_smoke_test(gpointer data) {
"cetbaFuks", "cetbaFuksQuiz", "cetbaFuksDej", "cetbaFuks", "cetbaFuksQuiz", "cetbaFuksDej",
"hwunit1", "hwex1", "hwunit2", "hwex2", "hwunit3", "hwex3", "hwunit1", "hwex1", "hwunit2", "hwex2", "hwunit3", "hwex3",
"hwunit4", "hwex4", "hwunit4", "hwex4",
"hwunit5", "hwex5", "hwunit6", "hwex6", "hwunit7", "hwex7",
"hwunit8", "hwex8", "hwunit9", "hwex9",
"unit1", "unit2", "unit3", "unit1", "unit2", "unit3",
"u1e1", "u1e13", "u2e1", "u2e19", "u3e1", "u3e15", "u1e1", "u1e13", "u2e1", "u2e19", "u3e1", "u3e15",
"u1vocab", "u2vocab", "u3vocab", "u1vocab", "u2vocab", "u3vocab",
@ -533,6 +535,16 @@ void activate(GtkApplication *app, gpointer user_data) {
gtk_stack_add_named(main_stack, build_hw_unit3_exercise_page(), "hwex3"); gtk_stack_add_named(main_stack, build_hw_unit3_exercise_page(), "hwex3");
gtk_stack_add_named(main_stack, build_hw_unit4_page(), "hwunit4"); gtk_stack_add_named(main_stack, build_hw_unit4_page(), "hwunit4");
gtk_stack_add_named(main_stack, build_hw_unit4_exercise_page(), "hwex4"); gtk_stack_add_named(main_stack, build_hw_unit4_exercise_page(), "hwex4");
gtk_stack_add_named(main_stack, build_hw_unit5_page(), "hwunit5");
gtk_stack_add_named(main_stack, build_hw_unit5_exercise_page(), "hwex5");
gtk_stack_add_named(main_stack, build_hw_unit6_page(), "hwunit6");
gtk_stack_add_named(main_stack, build_hw_unit6_exercise_page(), "hwex6");
gtk_stack_add_named(main_stack, build_hw_unit7_page(), "hwunit7");
gtk_stack_add_named(main_stack, build_hw_unit7_exercise_page(), "hwex7");
gtk_stack_add_named(main_stack, build_hw_unit8_page(), "hwunit8");
gtk_stack_add_named(main_stack, build_hw_unit8_exercise_page(), "hwex8");
gtk_stack_add_named(main_stack, build_hw_unit9_page(), "hwunit9");
gtk_stack_add_named(main_stack, build_hw_unit9_exercise_page(), "hwex9");
{ {
typedef GtkWidget *(*NetBuilder)(void); typedef GtkWidget *(*NetBuilder)(void);
static const struct { static const struct {

View file

@ -113,11 +113,16 @@ extern char *app_progress_cetba;
#define NET27_SLIDES 8 #define NET27_SLIDES 8
#define NET_LESSONS 27 #define NET_LESSONS 27
#define HW_UNITS 10 #define HW_UNITS 10
#define HW_LESSONS 4 #define HW_LESSONS 9
#define HW_SLIDES 3 #define HW_SLIDES 3
#define HW2_SLIDES 6 #define HW2_SLIDES 6
#define HW3_SLIDES 2 #define HW3_SLIDES 2
#define HW4_SLIDES 2 #define HW4_SLIDES 2
#define HW5_SLIDES 2
#define HW6_SLIDES 2
#define HW7_SLIDES 2
#define HW8_SLIDES 2
#define HW9_SLIDES 2
typedef enum { typedef enum {
THEME_CATPPUCCIN = 0, THEME_CATPPUCCIN = 0,
@ -869,6 +874,16 @@ GtkWidget *build_hw_unit3_page(void);
GtkWidget *build_hw_unit3_exercise_page(void); GtkWidget *build_hw_unit3_exercise_page(void);
GtkWidget *build_hw_unit4_page(void); GtkWidget *build_hw_unit4_page(void);
GtkWidget *build_hw_unit4_exercise_page(void); GtkWidget *build_hw_unit4_exercise_page(void);
GtkWidget *build_hw_unit5_page(void);
GtkWidget *build_hw_unit5_exercise_page(void);
GtkWidget *build_hw_unit6_page(void);
GtkWidget *build_hw_unit6_exercise_page(void);
GtkWidget *build_hw_unit7_page(void);
GtkWidget *build_hw_unit7_exercise_page(void);
GtkWidget *build_hw_unit8_page(void);
GtkWidget *build_hw_unit8_exercise_page(void);
GtkWidget *build_hw_unit9_page(void);
GtkWidget *build_hw_unit9_exercise_page(void);
void draw_chip_icon(GtkDrawingArea *area, cairo_t *cr, void draw_chip_icon(GtkDrawingArea *area, cairo_t *cr,
int width, int height, gpointer data); int width, int height, gpointer data);
void draw_czech_flag(GtkDrawingArea *area, cairo_t *cr, void draw_czech_flag(GtkDrawingArea *area, cairo_t *cr,