Add networks unit 2: basic concepts slides and MCQ quiz.
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
parent
2782446b89
commit
f3347e7dc3
4 changed files with 429 additions and 121 deletions
24
i18n.c
24
i18n.c
|
|
@ -199,6 +199,12 @@ const TrEntry tr_ui[] = {
|
|||
"4 slides with the method, then an exercise."},
|
||||
{"net_ex_title", "Cvičení: výpočet IP adres",
|
||||
"Exercise: IP address calculation"},
|
||||
{"net_unit2", "Základní pojmy a rozdělení sítí",
|
||||
"Basic concepts and network types"},
|
||||
{"net_unit2_sub", "5 snímků s pojmy a pak kvíz.",
|
||||
"5 slides with the concepts, then a quiz."},
|
||||
{"net_ex2_title", "Kvíz: základní pojmy sítí",
|
||||
"Quiz: basic networking concepts"},
|
||||
{"net_slide_next", "Další", "Next"},
|
||||
{"net_slide_prev", "Zpět", "Back"},
|
||||
{"net_slide_start", "Přejít na cvičení", "Go to the exercise"},
|
||||
|
|
@ -237,6 +243,20 @@ const TrEntry tr_content[] = {
|
|||
{"„siebzehn“ = sedmnáct (17)", NULL, "“siebzehn” = seventeen (17)"},
|
||||
{"„zwanzig“ = dvacet (20)", NULL, "“zwanzig” = twenty (20)"},
|
||||
{"„sechs“ = šest (6)", NULL, "“sechs” = six (6)"},
|
||||
{"1 B = 8 b", NULL, "1 B = 8 b"},
|
||||
{"2⁸ = 256 hodnot (0–255)", NULL, "2⁸ = 256 values (0–255)"},
|
||||
{"Kabely – síť zůstává připojená i po přenosu", NULL,
|
||||
"Cables – the network stays connected after transfer"},
|
||||
{"WAN = Wide Area Network, např. internet", NULL,
|
||||
"WAN = Wide Area Network, e.g. the internet"},
|
||||
{"Např. hvězda, kruh, sběrnice", NULL,
|
||||
"E.g. star, ring, bus"},
|
||||
{"Architektura = topologie + standard", NULL,
|
||||
"Architecture = topology + standard"},
|
||||
{"Bez centrálního serveru – stanice si sdílejí data a tiskárny", NULL,
|
||||
"No central server – stations share data and printers"},
|
||||
{"Server řídí a poskytuje služby, má vyšší výkon", NULL,
|
||||
"A server controls and provides services; higher performance"},
|
||||
{"čtrnáct", NULL, "fourteen"},
|
||||
{"sedmnáct", NULL, "seventeen"},
|
||||
{"dvacet", NULL, "twenty"},
|
||||
|
|
@ -807,7 +827,7 @@ void refresh_welcome_heading(void) {
|
|||
}
|
||||
|
||||
void refresh_stats_ui(void);
|
||||
void net_slide_apply(void);
|
||||
void net_lessons_apply_lang(void);
|
||||
void net_rail_theme_reset(void);
|
||||
|
||||
void apply_language(void) {
|
||||
|
|
@ -818,5 +838,5 @@ void apply_language(void) {
|
|||
i18n_apply_one(&g_array_index(i18n_binds, I18nBind, i));
|
||||
refresh_welcome_heading();
|
||||
refresh_stats_ui();
|
||||
net_slide_apply();
|
||||
net_lessons_apply_lang();
|
||||
}
|
||||
|
|
|
|||
2
main.c
2
main.c
|
|
@ -173,6 +173,8 @@ void activate(GtkApplication *app, gpointer user_data) {
|
|||
gtk_stack_add_named(main_stack, build_netmap_page(), "netmap");
|
||||
gtk_stack_add_named(main_stack, build_net_unit1_page(), "netunit1");
|
||||
gtk_stack_add_named(main_stack, build_net_exercise_page(), "netex");
|
||||
gtk_stack_add_named(main_stack, build_net_unit2_page(), "netunit2");
|
||||
gtk_stack_add_named(main_stack, build_net_unit2_exercise_page(), "netex2");
|
||||
|
||||
for (int i = 0; i < NUM_UNLOCKED; i++) {
|
||||
UnitCtx *u = &units[i];
|
||||
|
|
|
|||
40
maturita.h
40
maturita.h
|
|
@ -46,6 +46,8 @@
|
|||
#define NET_UNITS 30
|
||||
#define NET_GRID_COLS 6
|
||||
#define NET_SLIDES 4
|
||||
#define NET2_SLIDES 5
|
||||
#define NET_LESSONS 2
|
||||
|
||||
typedef enum {
|
||||
THEME_CATPPUCCIN = 0,
|
||||
|
|
@ -469,6 +471,29 @@ typedef struct {
|
|||
int id;
|
||||
gboolean infeasible;
|
||||
} NetQz;
|
||||
typedef struct {
|
||||
GtkWidget *stack;
|
||||
GtkWidget *prev_btn;
|
||||
GtkWidget *next_btn;
|
||||
guint idx;
|
||||
guint n_slides;
|
||||
const char *unit_page;
|
||||
const char *ex_page;
|
||||
} NetLesson;
|
||||
typedef struct {
|
||||
const char *kicker;
|
||||
const char *title;
|
||||
const char *tip;
|
||||
const char *line[8];
|
||||
} NetSlide;
|
||||
typedef struct {
|
||||
const ChoiceQ *qs;
|
||||
int n;
|
||||
int n_opts;
|
||||
GtkWidget *feedback;
|
||||
GtkToggleButton **toggles;
|
||||
GtkWidget **hints;
|
||||
} NetMcqCtx;
|
||||
|
||||
extern GtkStack *main_stack;
|
||||
extern GtkWindow *main_window;
|
||||
|
|
@ -628,10 +653,7 @@ extern const char *ex13_u3_pool[];
|
|||
extern const U3Fill ex13_u3_rows[];
|
||||
extern const U3Kw ex14_u3_qs[];
|
||||
extern const U3Let ex15_u3_rows[];
|
||||
extern GtkWidget *net_slide_stack;
|
||||
extern GtkWidget *net_prev_btn;
|
||||
extern GtkWidget *net_next_btn;
|
||||
extern guint net_slide_idx;
|
||||
extern NetLesson net_lessons[NET_LESSONS];
|
||||
extern GtkWidget *net_note_host;
|
||||
extern GArray *net_note_kicks;
|
||||
extern GArray *net_note_titles;
|
||||
|
|
@ -670,7 +692,7 @@ void i18n_apply_one(const I18nBind *b);
|
|||
void i18n_bind(GtkWidget *widget, const char *key, int kind);
|
||||
void refresh_welcome_heading(void);
|
||||
void refresh_stats_ui(void);
|
||||
void net_slide_apply(void);
|
||||
void net_lessons_apply_lang(void);
|
||||
void net_rail_theme_reset(void);
|
||||
void apply_language(void);
|
||||
char *read_css_file(void);
|
||||
|
|
@ -961,7 +983,8 @@ GtkWidget *net_slide_card(const char *cls);
|
|||
void net_note_kicker(GtkWidget *box, const char *text);
|
||||
void net_note_title(GtkWidget *box, const char *text);
|
||||
void net_note_line(GtkWidget *box, const char *text, gboolean tip);
|
||||
void net_slide_apply(void);
|
||||
void net_slide_apply(NetLesson *L);
|
||||
void net_lessons_apply_lang(void);
|
||||
void net_open_unit(GtkButton *button, gpointer data);
|
||||
void net_slide_prev(GtkButton *button, gpointer data);
|
||||
void net_slide_next(GtkButton *button, gpointer data);
|
||||
|
|
@ -980,7 +1003,10 @@ void net_draw_rail(GtkDrawingArea *area, cairo_t *cr,
|
|||
void net_rail_theme_reset(void);
|
||||
void net_add_node(GtkFixed *fixed, int index);
|
||||
GtkWidget *build_netmap_page(void);
|
||||
GtkWidget *build_net_unit_page(NetLesson *L, const char *title_key,
|
||||
const NetSlide *slides, guint n_slides);
|
||||
GtkWidget *build_net_unit1_page(void);
|
||||
GtkWidget *build_net_unit2_page(void);
|
||||
GtkWidget *net_qz_combo(void);
|
||||
void net_qz_set_prefix(GtkComboBoxText *c, int pfx);
|
||||
int net_qz_prefix(GtkComboBoxText *c);
|
||||
|
|
@ -991,6 +1017,8 @@ void net_qz_fill(GtkButton *button, gpointer data);
|
|||
void net_qz_header(GtkWidget *box, const char *text);
|
||||
GtkWidget *net_qz_make_entry(void);
|
||||
GtkWidget *build_net_exercise_page(void);
|
||||
void net_mcq_check(GtkButton *button, gpointer data);
|
||||
GtkWidget *build_net_unit2_exercise_page(void);
|
||||
void activate(GtkApplication *app, gpointer user_data);
|
||||
int main(int argc, char **argv);
|
||||
|
||||
|
|
|
|||
484
net.c
484
net.c
|
|
@ -3,10 +3,10 @@
|
|||
/* ---- Computer networks: subject path, lesson & exercise ------------ */
|
||||
|
||||
|
||||
GtkWidget *net_slide_stack;
|
||||
GtkWidget *net_prev_btn;
|
||||
GtkWidget *net_next_btn;
|
||||
guint net_slide_idx;
|
||||
NetLesson net_lessons[NET_LESSONS] = {
|
||||
{ .n_slides = NET_SLIDES, .unit_page = "netunit1", .ex_page = "netex" },
|
||||
{ .n_slides = NET2_SLIDES, .unit_page = "netunit2", .ex_page = "netex2" },
|
||||
};
|
||||
|
||||
void net_paragraph(GtkWidget *box, const char *text) {
|
||||
GtkWidget *l = gtk_label_new(text);
|
||||
|
|
@ -34,6 +34,14 @@ GArray *net_note_titles;
|
|||
GArray *net_note_bodies;
|
||||
int net_note_last_w = -1;
|
||||
|
||||
void net_notes_ensure(void) {
|
||||
if (net_note_kicks)
|
||||
return;
|
||||
net_note_kicks = g_array_new(FALSE, FALSE, sizeof(GtkWidget *));
|
||||
net_note_titles = g_array_new(FALSE, FALSE, sizeof(GtkWidget *));
|
||||
net_note_bodies = g_array_new(FALSE, FALSE, sizeof(GtkWidget *));
|
||||
}
|
||||
|
||||
void net_note_font(GtkWidget *l, int px) {
|
||||
PangoAttrList *attrs = pango_attr_list_new();
|
||||
|
||||
|
|
@ -46,6 +54,8 @@ void net_rescale_notes(void) {
|
|||
int w = net_note_host ? gtk_widget_get_allocated_width(net_note_host) : 0;
|
||||
int body, head, kick;
|
||||
|
||||
if (!net_note_kicks)
|
||||
return;
|
||||
if (w < 160)
|
||||
w = 160;
|
||||
body = w / 46;
|
||||
|
|
@ -112,52 +122,66 @@ void net_note_line(GtkWidget *box, const char *text, gboolean tip) {
|
|||
g_array_append_val(net_note_bodies, l);
|
||||
}
|
||||
|
||||
void net_slide_apply(void) {
|
||||
void net_slide_apply(NetLesson *L) {
|
||||
char name[16];
|
||||
|
||||
if (!net_slide_stack)
|
||||
if (!L || !L->stack)
|
||||
return;
|
||||
|
||||
g_snprintf(name, sizeof(name), "net_slide%u", net_slide_idx);
|
||||
gtk_stack_set_visible_child_name(GTK_STACK(net_slide_stack), name);
|
||||
g_snprintf(name, sizeof(name), "net_slide%u", L->idx);
|
||||
gtk_stack_set_visible_child_name(GTK_STACK(L->stack), name);
|
||||
|
||||
if (net_prev_btn) {
|
||||
gtk_button_set_label(GTK_BUTTON(net_prev_btn), tr("net_slide_prev"));
|
||||
gtk_widget_set_sensitive(net_prev_btn, net_slide_idx > 0);
|
||||
if (L->prev_btn) {
|
||||
gtk_button_set_label(GTK_BUTTON(L->prev_btn), tr("net_slide_prev"));
|
||||
gtk_widget_set_sensitive(L->prev_btn, L->idx > 0);
|
||||
}
|
||||
if (net_next_btn) {
|
||||
if (L->next_btn) {
|
||||
gtk_button_set_label(
|
||||
GTK_BUTTON(net_next_btn),
|
||||
net_slide_idx + 1 >= NET_SLIDES ? tr("net_slide_start")
|
||||
: tr("net_slide_next"));
|
||||
GTK_BUTTON(L->next_btn),
|
||||
L->idx + 1 >= L->n_slides ? tr("net_slide_start")
|
||||
: tr("net_slide_next"));
|
||||
}
|
||||
}
|
||||
|
||||
void net_lessons_apply_lang(void) {
|
||||
for (int i = 0; i < NET_LESSONS; i++)
|
||||
net_slide_apply(&net_lessons[i]);
|
||||
}
|
||||
|
||||
void net_open_unit(GtkButton *button, gpointer data) {
|
||||
NetLesson *L = data;
|
||||
|
||||
(void)button;
|
||||
(void)data;
|
||||
net_slide_idx = 0;
|
||||
net_slide_apply();
|
||||
gtk_stack_set_visible_child_name(main_stack, "netunit1");
|
||||
if (!L)
|
||||
return;
|
||||
L->idx = 0;
|
||||
net_slide_apply(L);
|
||||
gtk_stack_set_visible_child_name(main_stack, L->unit_page);
|
||||
}
|
||||
|
||||
void net_slide_prev(GtkButton *button, gpointer data) {
|
||||
NetLesson *L = data;
|
||||
|
||||
(void)button;
|
||||
(void)data;
|
||||
if (net_slide_idx > 0) {
|
||||
net_slide_idx--;
|
||||
net_slide_apply();
|
||||
if (!L)
|
||||
return;
|
||||
if (L->idx > 0) {
|
||||
L->idx--;
|
||||
net_slide_apply(L);
|
||||
}
|
||||
}
|
||||
|
||||
void net_slide_next(GtkButton *button, gpointer data) {
|
||||
NetLesson *L = data;
|
||||
|
||||
(void)button;
|
||||
(void)data;
|
||||
if (net_slide_idx + 1 < NET_SLIDES) {
|
||||
net_slide_idx++;
|
||||
net_slide_apply();
|
||||
if (!L)
|
||||
return;
|
||||
if (L->idx + 1 < L->n_slides) {
|
||||
L->idx++;
|
||||
net_slide_apply(L);
|
||||
} else {
|
||||
gtk_stack_set_visible_child_name(main_stack, "netex");
|
||||
gtk_stack_set_visible_child_name(main_stack, L->ex_page);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -400,13 +424,14 @@ void net_rail_theme_reset(void) {
|
|||
|
||||
void net_add_node(GtkFixed *fixed, int index) {
|
||||
int num = index + 1;
|
||||
gboolean locked = index != 0;
|
||||
gboolean locked = index >= NET_LESSONS;
|
||||
GtkWidget *card;
|
||||
GtkWidget *vbox;
|
||||
GtkWidget *number;
|
||||
GtkWidget *icon;
|
||||
GtkWidget *name;
|
||||
char *text;
|
||||
static const char *unit_keys[NET_LESSONS] = { "net_unit1", "net_unit2" };
|
||||
|
||||
card = gtk_button_new();
|
||||
gtk_widget_add_css_class(card, "unit-node");
|
||||
|
|
@ -437,7 +462,8 @@ void net_add_node(GtkFixed *fixed, int index) {
|
|||
icon = icon_area_new(draw_check_icon, 0.1176, 0.1176, 0.1804, 18);
|
||||
gtk_widget_set_visible(icon, FALSE);
|
||||
gtk_box_append(GTK_BOX(vbox), icon);
|
||||
g_signal_connect(card, "clicked", G_CALLBACK(net_open_unit), NULL);
|
||||
g_signal_connect(card, "clicked", G_CALLBACK(net_open_unit),
|
||||
&net_lessons[index]);
|
||||
}
|
||||
|
||||
net_nodes[index] = card;
|
||||
|
|
@ -449,8 +475,8 @@ void net_add_node(GtkFixed *fixed, int index) {
|
|||
gtk_label_set_justify(GTK_LABEL(name), GTK_JUSTIFY_CENTER);
|
||||
gtk_label_set_wrap(GTK_LABEL(name), TRUE);
|
||||
gtk_widget_add_css_class(name, "unit-name");
|
||||
if (index == 0) {
|
||||
i18n_bind(name, "net_unit1", 0);
|
||||
if (index < NET_LESSONS) {
|
||||
i18n_bind(name, unit_keys[index], 0);
|
||||
} else {
|
||||
gtk_widget_add_css_class(name, "unit-name-locked");
|
||||
}
|
||||
|
|
@ -522,13 +548,86 @@ GtkWidget *build_netmap_page(void) {
|
|||
return page;
|
||||
}
|
||||
|
||||
GtkWidget *build_net_unit_page(NetLesson *L, const char *title_key,
|
||||
const NetSlide *slides, guint n_slides) {
|
||||
GtkWidget *page;
|
||||
GtkWidget *scroll;
|
||||
GtkWidget *nav;
|
||||
|
||||
net_notes_ensure();
|
||||
L->n_slides = n_slides;
|
||||
|
||||
page = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);
|
||||
gtk_widget_set_margin_start(page, 28);
|
||||
gtk_widget_set_margin_end(page, 28);
|
||||
gtk_widget_set_margin_top(page, 20);
|
||||
gtk_widget_set_margin_bottom(page, 20);
|
||||
|
||||
gtk_box_append(GTK_BOX(page), top_bar("netmap", title_key, NULL));
|
||||
|
||||
scroll = gtk_scrolled_window_new();
|
||||
gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroll),
|
||||
GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
|
||||
gtk_widget_set_vexpand(scroll, TRUE);
|
||||
gtk_widget_set_margin_top(scroll, 10);
|
||||
gtk_box_append(GTK_BOX(page), scroll);
|
||||
|
||||
L->stack = gtk_stack_new();
|
||||
gtk_stack_set_transition_type(GTK_STACK(L->stack),
|
||||
GTK_STACK_TRANSITION_TYPE_SLIDE_LEFT_RIGHT);
|
||||
gtk_scrolled_window_set_child(GTK_SCROLLED_WINDOW(scroll), L->stack);
|
||||
net_note_host = L->stack;
|
||||
|
||||
for (guint s = 0; s < n_slides; s++) {
|
||||
GtkWidget *stage = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);
|
||||
GtkWidget *card;
|
||||
char name[16];
|
||||
|
||||
gtk_widget_set_vexpand(stage, TRUE);
|
||||
g_snprintf(name, sizeof(name), "net_slide%u", s);
|
||||
gtk_stack_add_named(GTK_STACK(L->stack), stage, name);
|
||||
|
||||
card = gtk_box_new(GTK_ORIENTATION_VERTICAL, 16);
|
||||
gtk_widget_add_css_class(card, "notes-card");
|
||||
gtk_widget_set_valign(card, GTK_ALIGN_CENTER);
|
||||
gtk_box_append(GTK_BOX(stage), card);
|
||||
|
||||
net_note_kicker(card, slides[s].kicker);
|
||||
net_note_title(card, slides[s].title);
|
||||
|
||||
for (int i = 0; i < 8 && slides[s].line[i]; i++)
|
||||
net_note_line(card, slides[s].line[i], FALSE);
|
||||
|
||||
if (slides[s].tip)
|
||||
net_note_line(card, slides[s].tip, TRUE);
|
||||
}
|
||||
|
||||
gtk_widget_add_tick_callback(L->stack, net_note_tick, NULL, NULL);
|
||||
net_note_last_w = -1;
|
||||
net_rescale_notes();
|
||||
|
||||
nav = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 10);
|
||||
gtk_box_set_homogeneous(GTK_BOX(nav), TRUE);
|
||||
gtk_widget_set_margin_top(nav, 10);
|
||||
gtk_box_append(GTK_BOX(page), nav);
|
||||
|
||||
L->prev_btn = gtk_button_new_with_label(tr("net_slide_prev"));
|
||||
gtk_widget_add_css_class(L->prev_btn, "btn-primary");
|
||||
g_signal_connect(L->prev_btn, "clicked", G_CALLBACK(net_slide_prev), L);
|
||||
gtk_box_append(GTK_BOX(nav), L->prev_btn);
|
||||
|
||||
L->next_btn = gtk_button_new_with_label(tr("net_slide_next"));
|
||||
gtk_widget_add_css_class(L->next_btn, "btn-primary");
|
||||
g_signal_connect(L->next_btn, "clicked", G_CALLBACK(net_slide_next), L);
|
||||
gtk_box_append(GTK_BOX(nav), L->next_btn);
|
||||
|
||||
L->idx = 0;
|
||||
net_slide_apply(L);
|
||||
|
||||
return page;
|
||||
}
|
||||
|
||||
GtkWidget *build_net_unit1_page(void) {
|
||||
typedef struct {
|
||||
const char *kicker;
|
||||
const char *title;
|
||||
const char *tip;
|
||||
const char *line[7];
|
||||
} NetSlide;
|
||||
static const NetSlide slides[NET_SLIDES] = {
|
||||
{
|
||||
"1 / 4 • VLSM", "Podsíťování sítí",
|
||||
|
|
@ -586,84 +685,74 @@ GtkWidget *build_net_unit1_page(void) {
|
|||
},
|
||||
},
|
||||
};
|
||||
GtkWidget *page;
|
||||
GtkWidget *scroll;
|
||||
GtkWidget *nav;
|
||||
|
||||
net_note_kicks = g_array_new(FALSE, FALSE, sizeof(GtkWidget *));
|
||||
net_note_titles = g_array_new(FALSE, FALSE, sizeof(GtkWidget *));
|
||||
net_note_bodies = g_array_new(FALSE, FALSE, sizeof(GtkWidget *));
|
||||
return build_net_unit_page(&net_lessons[0], "net_unit1", slides, NET_SLIDES);
|
||||
}
|
||||
|
||||
page = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);
|
||||
gtk_widget_set_margin_start(page, 28);
|
||||
gtk_widget_set_margin_end(page, 28);
|
||||
gtk_widget_set_margin_top(page, 20);
|
||||
gtk_widget_set_margin_bottom(page, 20);
|
||||
GtkWidget *build_net_unit2_page(void) {
|
||||
static const NetSlide slides[NET2_SLIDES] = {
|
||||
{
|
||||
"1 / 5 • Jednotky", "Bit, byte a počítačová síť",
|
||||
"Tip: 1 B = 8 b → 2⁸ = 256 možných hodnot",
|
||||
{
|
||||
"Bit (1 b): základní jednotka informace – 0 nebo 1.",
|
||||
"0 = nevede proud, 1 = vede proud.",
|
||||
"Byte (1 B): 1 B = 8 b, nabývá 256 hodnot.",
|
||||
"Počítačová síť: propojení uzlů (PC a dalších prvků).",
|
||||
"Vyžaduje hardwarové i softwarové prostředky.",
|
||||
NULL,
|
||||
},
|
||||
},
|
||||
{
|
||||
"2 / 5 • Propojení", "Trvalé, dočasné a důvody zapojení",
|
||||
NULL,
|
||||
{
|
||||
"Trvalé propojení: kabely – síť zůstává připojená i po přenosu.",
|
||||
"Dočasné propojení: modem, Wi‑Fi – po přenosu se odpojuje.",
|
||||
"Důvody zapojení do sítě:",
|
||||
"sdílení dat (nutná podpora aplikací)",
|
||||
"sdílení HW (tiskárny, disky) a SW (databáze)",
|
||||
"vyšší spolehlivost, bezpečnost (přístupová práva)",
|
||||
"komunikace (e‑mail, hlas)",
|
||||
NULL,
|
||||
},
|
||||
},
|
||||
{
|
||||
"3 / 5 • Pojmy", "Terminologie sítí",
|
||||
"Architektura = topologie + standard",
|
||||
{
|
||||
"Uzel: jakékoli zařízení (stanice, server, aktivní prvek).",
|
||||
"Topologie: způsob propojení (hvězda, kruh, sběrnice).",
|
||||
"Standard: normy pro zpracování dat.",
|
||||
"Architektura: topologie + standard.",
|
||||
NULL,
|
||||
},
|
||||
},
|
||||
{
|
||||
"4 / 5 • Rozlehlost", "WAN, MAN a LAN",
|
||||
NULL,
|
||||
{
|
||||
"WAN: rozsáhlé sítě (státy, kontinenty), např. internet.",
|
||||
"MAN: městské sítě – propojují lokální sítě.",
|
||||
"LAN: lokální sítě (budova), kabeláž v řádu km,",
|
||||
"jednotná architektura.",
|
||||
NULL,
|
||||
},
|
||||
},
|
||||
{
|
||||
"5 / 5 • Uzly", "Server, stanice a peer‑to‑peer",
|
||||
NULL,
|
||||
{
|
||||
"Server: nadřazený, řídící, poskytuje služby, vyšší výkon.",
|
||||
"Pracovní stanice: pro uživatele, jednodušší konfigurace.",
|
||||
"Peer‑to‑peer: síť bez serverů – jen stanice,",
|
||||
"které sdílejí data a tiskárny.",
|
||||
NULL,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
gtk_box_append(GTK_BOX(page),
|
||||
top_bar("netmap", "net_unit1", NULL));
|
||||
|
||||
scroll = gtk_scrolled_window_new();
|
||||
gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroll),
|
||||
GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
|
||||
gtk_widget_set_vexpand(scroll, TRUE);
|
||||
gtk_widget_set_margin_top(scroll, 10);
|
||||
gtk_box_append(GTK_BOX(page), scroll);
|
||||
|
||||
net_slide_stack = gtk_stack_new();
|
||||
gtk_stack_set_transition_type(GTK_STACK(net_slide_stack),
|
||||
GTK_STACK_TRANSITION_TYPE_SLIDE_LEFT_RIGHT);
|
||||
gtk_scrolled_window_set_child(GTK_SCROLLED_WINDOW(scroll),
|
||||
net_slide_stack);
|
||||
net_note_host = net_slide_stack;
|
||||
|
||||
for (int s = 0; s < NET_SLIDES; s++) {
|
||||
GtkWidget *stage = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);
|
||||
GtkWidget *card;
|
||||
char name[16];
|
||||
|
||||
gtk_widget_set_vexpand(stage, TRUE);
|
||||
g_snprintf(name, sizeof(name), "net_slide%d", s);
|
||||
gtk_stack_add_named(GTK_STACK(net_slide_stack), stage, name);
|
||||
|
||||
card = gtk_box_new(GTK_ORIENTATION_VERTICAL, 16);
|
||||
gtk_widget_add_css_class(card, "notes-card");
|
||||
gtk_widget_set_valign(card, GTK_ALIGN_CENTER);
|
||||
gtk_box_append(GTK_BOX(stage), card);
|
||||
|
||||
net_note_kicker(card, slides[s].kicker);
|
||||
net_note_title(card, slides[s].title);
|
||||
|
||||
for (int i = 0; i < 7 && slides[s].line[i]; i++)
|
||||
net_note_line(card, slides[s].line[i], FALSE);
|
||||
|
||||
if (slides[s].tip)
|
||||
net_note_line(card, slides[s].tip, TRUE);
|
||||
}
|
||||
|
||||
gtk_widget_add_tick_callback(net_slide_stack, net_note_tick, NULL, NULL);
|
||||
net_note_last_w = -1;
|
||||
net_rescale_notes();
|
||||
|
||||
nav = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 10);
|
||||
gtk_box_set_homogeneous(GTK_BOX(nav), TRUE);
|
||||
gtk_widget_set_margin_top(nav, 10);
|
||||
gtk_box_append(GTK_BOX(page), nav);
|
||||
|
||||
net_prev_btn = gtk_button_new_with_label(tr("net_slide_prev"));
|
||||
gtk_widget_add_css_class(net_prev_btn, "btn-primary");
|
||||
g_signal_connect(net_prev_btn, "clicked", G_CALLBACK(net_slide_prev), NULL);
|
||||
gtk_box_append(GTK_BOX(nav), net_prev_btn);
|
||||
|
||||
net_next_btn = gtk_button_new_with_label(tr("net_slide_next"));
|
||||
gtk_widget_add_css_class(net_next_btn, "btn-primary");
|
||||
g_signal_connect(net_next_btn, "clicked", G_CALLBACK(net_slide_next), NULL);
|
||||
gtk_box_append(GTK_BOX(nav), net_next_btn);
|
||||
|
||||
net_slide_idx = 0;
|
||||
net_slide_apply();
|
||||
|
||||
return page;
|
||||
return build_net_unit_page(&net_lessons[1], "net_unit2", slides, NET2_SLIDES);
|
||||
}
|
||||
|
||||
/* Solutions below are the canonical "largest subnet first, in order A–D"
|
||||
|
|
@ -1015,3 +1104,172 @@ GtkWidget *build_net_exercise_page(void) {
|
|||
|
||||
return page;
|
||||
}
|
||||
|
||||
/* ---- Unit 2: multiple-choice quiz on basic networking concepts ---- */
|
||||
|
||||
const ChoiceQ net2_qs[] = {
|
||||
{"Kolik bitů má jeden byte?",
|
||||
{"4", "8", "16", "32"}, 4, 1},
|
||||
{"Kolik různých hodnot nabývá jeden byte?",
|
||||
{"128", "255", "256", "512"}, 4, 2},
|
||||
{"Co je trvalé propojení sítě?",
|
||||
{"Modem", "Wi‑Fi", "Kabely", "Bluetooth"}, 4, 2},
|
||||
{"Co označuje zkratka WAN?",
|
||||
{"Lokální síť v budově", "Městskou síť",
|
||||
"Rozsáhlou síť (státy, kontinenty)", "Bezdrátovou síť"}, 4, 2},
|
||||
{"Co je topologie sítě?",
|
||||
{"Norma pro zpracování dat", "Způsob propojení uzlů",
|
||||
"Název serveru", "Rychlost přenosu"}, 4, 1},
|
||||
{"Architektura sítě je:",
|
||||
{"Jen topologie", "Jen standard", "Topologie + standard",
|
||||
"Pouze typ kabelu"}, 4, 2},
|
||||
{"Peer‑to‑peer síť znamená:",
|
||||
{"Síť s jedním výkonným serverem",
|
||||
"Síť bez serverů – stanice sdílejí data",
|
||||
"Jen internetovou síť", "Síť pouze s tiskárnami"}, 4, 1},
|
||||
{"Server v síti je:",
|
||||
{"Jednoduchá stanice pro uživatele",
|
||||
"Nadřazený uzel poskytující služby",
|
||||
"Jen aktivní prvek kabeláže", "Dočasné Wi‑Fi připojení"}, 4, 1},
|
||||
};
|
||||
|
||||
const char *net2_hints[] = {
|
||||
"1 B = 8 b",
|
||||
"2⁸ = 256 hodnot (0–255)",
|
||||
"Kabely – síť zůstává připojená i po přenosu",
|
||||
"WAN = Wide Area Network, např. internet",
|
||||
"Např. hvězda, kruh, sběrnice",
|
||||
"Architektura = topologie + standard",
|
||||
"Bez centrálního serveru – stanice si sdílejí data a tiskárny",
|
||||
"Server řídí a poskytuje služby, má vyšší výkon",
|
||||
};
|
||||
|
||||
void net_mcq_check(GtkButton *button, gpointer data) {
|
||||
NetMcqCtx *ctx = data;
|
||||
int ok = 0;
|
||||
|
||||
(void)button;
|
||||
|
||||
for (int i = 0; i < ctx->n; i++) {
|
||||
int active = -1;
|
||||
|
||||
for (int o = 0; o < ctx->n_opts; o++) {
|
||||
GtkToggleButton *tb = ctx->toggles[i * ctx->n_opts + o];
|
||||
|
||||
gtk_widget_remove_css_class(GTK_WIDGET(tb), "ok");
|
||||
gtk_widget_remove_css_class(GTK_WIDGET(tb), "wrong");
|
||||
if (gtk_toggle_button_get_active(tb))
|
||||
active = o;
|
||||
}
|
||||
if (active == ctx->qs[i].correct) {
|
||||
ok++;
|
||||
gtk_widget_add_css_class(
|
||||
GTK_WIDGET(ctx->toggles[i * ctx->n_opts + active]), "ok");
|
||||
} else if (active >= 0) {
|
||||
gtk_widget_add_css_class(
|
||||
GTK_WIDGET(ctx->toggles[i * ctx->n_opts + active]), "wrong");
|
||||
}
|
||||
if (ctx->hints && ctx->hints[i])
|
||||
gtk_widget_set_visible(ctx->hints[i], TRUE);
|
||||
}
|
||||
|
||||
if (ok == ctx->n)
|
||||
set_feedback(ctx->feedback, TRUE, tr("feedback_ok"));
|
||||
else
|
||||
set_feedback(ctx->feedback, FALSE, tr("feedback_retry_short"));
|
||||
}
|
||||
|
||||
GtkWidget *build_net_unit2_exercise_page(void) {
|
||||
GtkWidget *page;
|
||||
GtkWidget *scroll;
|
||||
GtkWidget *body;
|
||||
GtkWidget *check;
|
||||
GtkWidget *btns;
|
||||
NetMcqCtx *ctx = g_new0(NetMcqCtx, 1);
|
||||
int n = (int)G_N_ELEMENTS(net2_qs);
|
||||
int n_opts = net2_qs[0].n_options;
|
||||
|
||||
page = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);
|
||||
gtk_widget_set_margin_start(page, 32);
|
||||
gtk_widget_set_margin_end(page, 32);
|
||||
gtk_widget_set_margin_top(page, 24);
|
||||
gtk_widget_set_margin_bottom(page, 24);
|
||||
|
||||
gtk_box_append(GTK_BOX(page),
|
||||
top_bar("netunit2", "net_ex2_title", NULL));
|
||||
|
||||
scroll = gtk_scrolled_window_new();
|
||||
gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroll),
|
||||
GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
|
||||
gtk_widget_set_vexpand(scroll, TRUE);
|
||||
gtk_widget_set_margin_top(scroll, 12);
|
||||
gtk_box_append(GTK_BOX(page), scroll);
|
||||
|
||||
body = gtk_box_new(GTK_ORIENTATION_VERTICAL, 10);
|
||||
gtk_scrolled_window_set_child(GTK_SCROLLED_WINDOW(scroll), body);
|
||||
|
||||
net_heading(body, "Kvíz k základním pojmům sítí");
|
||||
net_paragraph(body,
|
||||
"Vyberte u každé otázky jednu správnou odpověď "
|
||||
"a stiskněte Zkontrolovat.");
|
||||
|
||||
ctx->qs = net2_qs;
|
||||
ctx->n = n;
|
||||
ctx->n_opts = n_opts;
|
||||
ctx->toggles = g_new0(GtkToggleButton *, n * n_opts);
|
||||
ctx->hints = g_new0(GtkWidget *, n);
|
||||
|
||||
for (int i = 0; i < n; i++) {
|
||||
GtkWidget *prompt;
|
||||
GtkWidget *row;
|
||||
GtkToggleButton *first = NULL;
|
||||
char *qtext;
|
||||
|
||||
qtext = g_strdup_printf("%d.) %s", i + 1, net2_qs[i].prompt);
|
||||
prompt = gtk_label_new(qtext);
|
||||
g_free(qtext);
|
||||
gtk_widget_set_halign(prompt, GTK_ALIGN_START);
|
||||
gtk_label_set_wrap(GTK_LABEL(prompt), TRUE);
|
||||
gtk_widget_add_css_class(prompt, "ex-prompt");
|
||||
gtk_widget_set_margin_top(prompt, 8);
|
||||
gtk_box_append(GTK_BOX(body), prompt);
|
||||
|
||||
row = gtk_flow_box_new();
|
||||
gtk_flow_box_set_selection_mode(GTK_FLOW_BOX(row), GTK_SELECTION_NONE);
|
||||
gtk_flow_box_set_min_children_per_line(GTK_FLOW_BOX(row), n_opts);
|
||||
gtk_flow_box_set_max_children_per_line(GTK_FLOW_BOX(row), n_opts);
|
||||
gtk_widget_set_halign(row, GTK_ALIGN_START);
|
||||
gtk_box_append(GTK_BOX(body), row);
|
||||
|
||||
for (int o = 0; o < n_opts; o++) {
|
||||
GtkWidget *tb =
|
||||
gtk_toggle_button_new_with_label(net2_qs[i].options[o]);
|
||||
|
||||
gtk_widget_add_css_class(tb, "pill");
|
||||
gtk_toggle_button_set_group(GTK_TOGGLE_BUTTON(tb), first);
|
||||
if (!first)
|
||||
first = GTK_TOGGLE_BUTTON(tb);
|
||||
gtk_flow_box_append(GTK_FLOW_BOX(row), tb);
|
||||
ctx->toggles[i * n_opts + o] = GTK_TOGGLE_BUTTON(tb);
|
||||
}
|
||||
|
||||
ctx->hints[i] = meaning_add(body, net2_hints[i]);
|
||||
}
|
||||
|
||||
btns = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 8);
|
||||
gtk_widget_set_margin_top(btns, 12);
|
||||
gtk_box_append(GTK_BOX(body), btns);
|
||||
|
||||
check = gtk_button_new();
|
||||
i18n_bind(check, "check", 1);
|
||||
gtk_widget_add_css_class(check, "pill");
|
||||
gtk_widget_set_halign(check, GTK_ALIGN_START);
|
||||
gtk_box_append(GTK_BOX(btns), check);
|
||||
g_signal_connect(check, "clicked", G_CALLBACK(net_mcq_check), ctx);
|
||||
|
||||
ctx->feedback = gtk_label_new("");
|
||||
gtk_widget_set_halign(ctx->feedback, GTK_ALIGN_START);
|
||||
gtk_box_append(GTK_BOX(body), ctx->feedback);
|
||||
|
||||
return page;
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue