Graduately/src/hw.c
pepaskopec-blip 59d40c886a Add short transitions for navigation, answers and progress on every platform.
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-08 21:13:32 +02:00

3020 lines
117 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

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

#include "graduately.h"
/* ---- Technical equipment (Technické vybavení) --------------------- */
NetLesson hw_lessons[HW_LESSONS] = {
{ .n_slides = HW_SLIDES, .unit_page = "hwunit1", .ex_page = "hwex1" },
{ .n_slides = HW2_SLIDES, .unit_page = "hwunit2", .ex_page = "hwex2" },
{ .n_slides = HW3_SLIDES, .unit_page = "hwunit3", .ex_page = "hwex3" },
{ .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" },
#define HW_ENTRY(n) { .n_slides = 2, .unit_page = "hwunit" #n, .ex_page = "hwex" #n }
HW_ENTRY(10), HW_ENTRY(11), HW_ENTRY(12), HW_ENTRY(13), HW_ENTRY(14),
HW_ENTRY(15), HW_ENTRY(16), HW_ENTRY(17), HW_ENTRY(18), HW_ENTRY(19),
HW_ENTRY(20), HW_ENTRY(21), HW_ENTRY(22), HW_ENTRY(23), HW_ENTRY(24),
HW_ENTRY(25), HW_ENTRY(26), HW_ENTRY(27), HW_ENTRY(28), HW_ENTRY(29),
#undef HW_ENTRY
};
void hw_rail_theme_reset(void);
void refresh_hw_completion_ui(void);
GtkWidget *hw_scroll;
GtkWidget *hw_fixed;
GtkWidget *hw_rail;
GtkWidget *hw_nodes[HW_UNITS];
GtkWidget *hw_labels[HW_UNITS];
double hw_cx[HW_UNITS];
double hw_cy[HW_UNITS];
int hw_cols = 1;
int hw_rows = 1;
int hw_cw = (int)(2.0 * ROAD_MX + (HW_UNITS - 1) * PATH_SPAC);
int hw_ch = (int)(2.0 * ROAD_MY);
guint hw_idle;
double hw_last_avail = -1.0;
int hw_last_cols = -1;
int hw_last_rows = -1;
int hw_last_cw = -1;
int hw_last_ch = -1;
cairo_surface_t *hw_rail_cache;
int hw_cache_w;
int hw_cache_h;
void hw_point(double t, double *ox, double *oy) {
int k = (int)t;
double u = t - (double)k;
double u2, u3;
double p0x, p0y, p1x, p1y, p2x, p2y, p3x, p3y;
if (k < 0) { k = 0; u = 0.0; }
if (k >= HW_UNITS - 1) { k = HW_UNITS - 2; u = 1.0; }
p1x = hw_cx[k]; p1y = hw_cy[k];
p2x = hw_cx[k + 1]; p2y = hw_cy[k + 1];
if (k - 1 >= 0) { p0x = hw_cx[k - 1]; p0y = hw_cy[k - 1]; }
else { p0x = p1x - (p2x - p1x); p0y = p1y - (p2y - p1y); }
if (k + 2 < HW_UNITS) { p3x = hw_cx[k + 2]; p3y = hw_cy[k + 2]; }
else { p3x = p2x + (p2x - p1x); p3y = p2y + (p2y - p1y); }
u2 = u * u;
u3 = u2 * u;
*ox = 0.5 * (2.0 * p1x + (-p0x + p2x) * u
+ (2.0 * p0x - 5.0 * p1x + 4.0 * p2x - p3x) * u2
+ (-p0x + 3.0 * p1x - 3.0 * p2x + p3x) * u3);
*oy = 0.5 * (2.0 * p1y + (-p0y + p2y) * u
+ (2.0 * p0y - 5.0 * p1y + 4.0 * p2y - p3y) * u2
+ (-p0y + 3.0 * p1y - 3.0 * p2y + p3y) * u3);
}
void hw_path(cairo_t *cr, double t0, double t1) {
const double steps_per_unit = 24.0;
int n = (int)((t1 - t0) * steps_per_unit);
double x, y;
int s;
if (n < 1)
n = 1;
hw_point(t0, &x, &y);
cairo_move_to(cr, x, y);
for (s = 1; s <= n; s++) {
hw_point(t0 + (t1 - t0) * (double)s / (double)n, &x, &y);
cairo_line_to(cr, x, y);
}
}
void hw_geometry(double avail) {
const double phase = 2.0 * G_PI * 1.7 / (double)(HW_UNITS - 1);
int rows;
int r, c, i;
for (rows = 1; rows <= HW_UNITS; rows++) {
int cols = (HW_UNITS + rows - 1) / rows;
if (2.0 * ROAD_MX + (cols - 1) * PATH_SPAC <= avail + 1.0)
break;
}
if (rows > HW_UNITS)
rows = HW_UNITS;
hw_rows = rows;
hw_cols = (HW_UNITS + rows - 1) / rows;
if (hw_cols < 1)
hw_cols = 1;
hw_cw = (int)(2.0 * ROAD_MX + (hw_cols - 1) * PATH_SPAC);
hw_ch = (int)(2.0 * ROAD_MY + (rows - 1) * ROAD_GAP);
for (r = 0; r < rows; r++) {
int base = r * hw_cols;
int len = MIN(hw_cols, HW_UNITS - base);
int fwd = (r % 2) == 0;
for (c = 0; c < len; c++) {
i = base + c;
int cc = fwd ? c : (hw_cols - 1 - c);
hw_cx[i] = ROAD_MX + cc * PATH_SPAC;
hw_cy[i] = ROAD_MY + r * ROAD_GAP
+ ROAD_WAVE * sin((double)i * phase);
}
}
}
void hw_apply_layout(void) {
if (!hw_fixed)
return;
if (hw_cols == hw_last_cols && hw_rows == hw_last_rows &&
hw_cw == hw_last_cw && hw_ch == hw_last_ch)
return;
hw_last_cols = hw_cols;
hw_last_rows = hw_rows;
hw_last_cw = hw_cw;
hw_last_ch = hw_ch;
if (hw_rail_cache) {
cairo_surface_destroy(hw_rail_cache);
hw_rail_cache = NULL;
}
for (int i = 0; i < HW_UNITS; i++) {
if (!hw_nodes[i] || !hw_labels[i])
continue;
gtk_fixed_move(GTK_FIXED(hw_fixed), hw_nodes[i],
(int)(hw_cx[i] - NODE_SIZE / 2.0),
(int)(hw_cy[i] - NODE_SIZE / 2.0));
gtk_fixed_move(GTK_FIXED(hw_fixed), hw_labels[i],
(int)(hw_cx[i] - (PATH_SPAC - 20.0) / 2.0),
(int)(hw_cy[i] + NODE_SIZE / 2.0 + 10.0));
}
gtk_widget_set_size_request(hw_fixed, hw_cw, hw_ch);
gtk_widget_set_size_request(hw_rail, hw_cw, hw_ch);
gtk_fixed_move(GTK_FIXED(hw_fixed), hw_rail, 0, 0);
gtk_widget_queue_draw(hw_rail);
}
void hw_relayout(void) {
GtkAdjustment *hadj;
double avail;
if (!hw_scroll)
return;
hadj = gtk_scrolled_window_get_hadjustment(
GTK_SCROLLED_WINDOW(hw_scroll));
avail = gtk_adjustment_get_page_size(hadj);
if (avail < 1.0)
return;
if (fabs(avail - hw_last_avail) < 1.0)
return;
hw_last_avail = avail;
hw_geometry(avail);
hw_apply_layout();
}
gboolean hw_relayout_idle(gpointer data) {
(void)data;
hw_idle = 0;
hw_relayout();
return G_SOURCE_REMOVE;
}
void hw_relayout_later(void) {
if (hw_idle == 0)
hw_idle = g_idle_add(hw_relayout_idle, NULL);
}
void hw_adjust_notify(GtkAdjustment *adj, GParamSpec *ps,
gpointer data) {
(void)adj;
(void)ps;
(void)data;
hw_relayout_later();
}
void hw_render_rail_to(cairo_t *cr) {
const double t_end = (double)(HW_UNITS - 1);
const Rgb rail = color_from_hex(app_theme.rail);
const Rgb muted = color_from_hex(app_theme.subtext);
cairo_set_operator(cr, CAIRO_OPERATOR_CLEAR);
cairo_paint(cr);
cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
cairo_set_line_cap(cr, CAIRO_LINE_CAP_ROUND);
cairo_set_line_join(cr, CAIRO_LINE_JOIN_ROUND);
cairo_new_path(cr);
hw_path(cr, 0.0, t_end);
cairo_set_line_width(cr, 12);
cairo_set_source_rgb(cr, rail.r, rail.g, rail.b);
cairo_stroke(cr);
cairo_set_source_rgba(cr, muted.r, muted.g, muted.b, 0.17);
cairo_set_dash(cr, (double[]){2.0, 40.0}, 2, 0.0);
cairo_new_path(cr);
hw_path(cr, 0.0, t_end);
cairo_stroke(cr);
cairo_set_dash(cr, NULL, 0, 0.0);
}
void hw_draw_rail(GtkDrawingArea *area, cairo_t *cr,
int width, int height, gpointer data) {
(void)area;
(void)width;
(void)height;
(void)data;
if (!hw_rail_cache || hw_cache_w != hw_cw || hw_cache_h != hw_ch) {
cairo_t *rcr;
if (hw_rail_cache)
cairo_surface_destroy(hw_rail_cache);
hw_cache_w = hw_cw;
hw_cache_h = hw_ch;
if (hw_cache_w < 1)
hw_cache_w = 1;
if (hw_cache_h < 1)
hw_cache_h = 1;
hw_rail_cache = cairo_image_surface_create(CAIRO_FORMAT_ARGB32,
hw_cache_w, hw_cache_h);
rcr = cairo_create(hw_rail_cache);
hw_render_rail_to(rcr);
cairo_destroy(rcr);
}
cairo_set_source_surface(cr, hw_rail_cache, 0, 0);
cairo_paint(cr);
}
void hw_rail_theme_reset(void) {
if (hw_rail_cache) {
cairo_surface_destroy(hw_rail_cache);
hw_rail_cache = NULL;
}
if (hw_rail)
gtk_widget_queue_draw(hw_rail);
}
void hw_add_node(GtkFixed *fixed, int index) {
int num = index + 1;
gboolean locked = index >= HW_LESSONS;
GtkWidget *card;
GtkWidget *vbox;
GtkWidget *number;
GtkWidget *icon;
GtkWidget *name;
char *text;
static char unit_keys[HW_LESSONS][16];
static gboolean unit_keys_ready = FALSE;
if (!unit_keys_ready) {
for (int i = 0; i < HW_LESSONS; i++)
g_snprintf(unit_keys[i], sizeof unit_keys[i], "hw_unit%d", i + 1);
unit_keys_ready = TRUE;
}
card = gtk_button_new();
gtk_widget_add_css_class(card, "unit-node");
gtk_widget_set_can_focus(card, FALSE);
gtk_widget_set_sensitive(card, !locked);
gtk_widget_set_size_request(card, (int)NODE_SIZE, (int)NODE_SIZE);
if (locked)
gtk_widget_add_css_class(card, "locked");
else
gtk_widget_add_css_class(card, "current");
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(card), vbox);
text = g_strdup_printf("%d", num);
number = gtk_label_new(text);
g_free(text);
gtk_widget_add_css_class(number, "unit-number");
gtk_box_append(GTK_BOX(vbox), number);
if (locked) {
icon = icon_area_new(draw_lock_icon, 0.3451, 0.3569, 0.4392, 16);
gtk_box_append(GTK_BOX(vbox), icon);
} else {
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);
hw_lessons[index].done_icon = icon;
g_signal_connect(card, "clicked", G_CALLBACK(net_open_unit),
&hw_lessons[index]);
}
hw_nodes[index] = card;
gtk_fixed_put(fixed, card, 0, 0);
name = gtk_label_new(NULL);
gtk_widget_set_size_request(name, (int)(PATH_SPAC - 20.0), -1);
gtk_widget_set_halign(name, GTK_ALIGN_CENTER);
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 < HW_LESSONS) {
i18n_bind(name, unit_keys[index], 0);
} else {
gtk_widget_add_css_class(name, "unit-name-locked");
}
hw_labels[index] = name;
gtk_fixed_put(fixed, name, 0, 0);
}
static GtkWidget *hw_year_button(int year, gboolean locked) {
static const char *year_keys[] = {
"hw_year1", "hw_year2", "hw_year3", "hw_year4",
};
GtkWidget *btn;
GtkWidget *row;
GtkWidget *num;
GtkWidget *texts;
GtkWidget *title;
char *num_text;
btn = gtk_button_new();
gtk_widget_add_css_class(btn, "unit-node");
gtk_widget_set_can_focus(btn, FALSE);
gtk_widget_set_hexpand(btn, TRUE);
gtk_widget_set_size_request(btn, -1, 72);
gtk_widget_set_sensitive(btn, !locked);
if (locked)
gtk_widget_add_css_class(btn, "locked");
else
gtk_widget_add_css_class(btn, "current");
row = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 14);
gtk_widget_set_halign(row, GTK_ALIGN_START);
gtk_widget_set_valign(row, GTK_ALIGN_CENTER);
gtk_widget_set_margin_start(row, 18);
gtk_widget_set_margin_end(row, 18);
gtk_button_set_child(GTK_BUTTON(btn), row);
num_text = g_strdup_printf("%d", year);
num = gtk_label_new(num_text);
g_free(num_text);
gtk_widget_add_css_class(num, "unit-number");
gtk_widget_set_valign(num, GTK_ALIGN_CENTER);
gtk_box_append(GTK_BOX(row), num);
texts = gtk_box_new(GTK_ORIENTATION_VERTICAL, 2);
gtk_widget_set_halign(texts, GTK_ALIGN_START);
gtk_widget_set_hexpand(texts, TRUE);
gtk_box_append(GTK_BOX(row), texts);
title = gtk_label_new(NULL);
i18n_bind(title, year_keys[year - 1], 0);
gtk_widget_set_halign(title, GTK_ALIGN_START);
gtk_widget_add_css_class(title, "unit-name");
gtk_box_append(GTK_BOX(texts), title);
if (locked) {
GtkWidget *sub = gtk_label_new(NULL);
GtkWidget *icon = icon_area_new(draw_lock_icon, 0.3451, 0.3569,
0.4392, 18);
i18n_bind(sub, "hw_year_locked_sub", 0);
gtk_widget_set_halign(sub, GTK_ALIGN_START);
gtk_widget_add_css_class(sub, "unit-name-locked");
gtk_box_append(GTK_BOX(texts), sub);
gtk_widget_set_valign(icon, GTK_ALIGN_CENTER);
gtk_box_append(GTK_BOX(row), icon);
} else {
static const char *pages[] = {
"hwmap", "hw2map", "hw3map", "hw4map",
};
static const char *subs[] = {
"hw_sub", "hw2_sub", "hw3_sub", "hw4_sub",
};
GtkWidget *sub = gtk_label_new(NULL);
i18n_bind(sub, subs[year - 1], 0);
gtk_widget_set_halign(sub, GTK_ALIGN_START);
gtk_label_set_wrap(GTK_LABEL(sub), TRUE);
gtk_widget_add_css_class(sub, "quiz-intro");
gtk_box_append(GTK_BOX(texts), sub);
g_object_set_data_full(G_OBJECT(btn), "target",
g_strdup(pages[year - 1]), g_free);
g_signal_connect(btn, "clicked", G_CALLBACK(on_nav_clicked), NULL);
}
return btn;
}
GtkWidget *build_hwyears_page(void) {
GtkWidget *page;
GtkWidget *scroll;
GtkWidget *list;
int y;
page = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);
gtk_widget_set_hexpand(page, TRUE);
gtk_widget_set_vexpand(page, TRUE);
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("subjects", "Technické vybavení", "hw_years_sub"));
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, 18);
gtk_box_append(GTK_BOX(page), scroll);
list = gtk_box_new(GTK_ORIENTATION_VERTICAL, 12);
gtk_widget_set_halign(list, GTK_ALIGN_CENTER);
gtk_widget_set_valign(list, GTK_ALIGN_CENTER);
gtk_widget_set_size_request(list, 360, -1);
gtk_scrolled_window_set_child(GTK_SCROLLED_WINDOW(scroll), list);
for (y = 1; y <= 4; y++)
gtk_box_append(GTK_BOX(list), hw_year_button(y, FALSE));
return page;
}
GtkWidget *build_hwmap_page(void) {
GtkWidget *page;
GtkWidget *scroll;
GtkWidget *wrap;
GtkWidget *fixed;
GtkWidget *rail;
GtkAdjustment *ha;
GtkAdjustment *va;
hw_geometry(1000.0);
page = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);
gtk_widget_set_hexpand(page, TRUE);
gtk_widget_set_vexpand(page, TRUE);
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("hwyears", "hw_year1", "hw_sub"));
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, 14);
gtk_box_append(GTK_BOX(page), scroll);
hw_scroll = scroll;
wrap = gtk_center_box_new();
gtk_widget_set_vexpand(wrap, TRUE);
gtk_widget_set_hexpand(wrap, TRUE);
gtk_scrolled_window_set_child(GTK_SCROLLED_WINDOW(scroll), wrap);
fixed = gtk_fixed_new();
gtk_widget_set_halign(fixed, GTK_ALIGN_CENTER);
gtk_widget_set_valign(fixed, GTK_ALIGN_CENTER);
gtk_widget_set_size_request(fixed, hw_cw, hw_ch);
gtk_center_box_set_center_widget(GTK_CENTER_BOX(wrap), fixed);
hw_fixed = fixed;
rail = gtk_drawing_area_new();
gtk_widget_set_size_request(rail, hw_cw, hw_ch);
gtk_drawing_area_set_draw_func(GTK_DRAWING_AREA(rail), hw_draw_rail,
NULL, NULL);
gtk_fixed_put(GTK_FIXED(fixed), rail, 0, 0);
hw_rail = rail;
for (int i = 0; i < HW_UNITS; i++)
hw_add_node(GTK_FIXED(fixed), i);
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",
G_CALLBACK(hw_adjust_notify), NULL);
g_signal_connect(va, "notify::page-size",
G_CALLBACK(hw_adjust_notify), NULL);
hw_apply_layout();
hw_relayout_later();
refresh_hw_completion_ui();
return page;
}
void hw_slide_apply(NetLesson *L);
void hw_slide_prev(GtkButton *button, gpointer data);
void hw_slide_next(GtkButton *button, gpointer data);
/* ---- Unit 1: Architektura počítače -------------------------------- */
static GtkWidget *hw_note_host;
static int hw_note_last_w = -1;
static void hw_rescale_notes_at(int w) {
int body, head, kick;
if (w < 160)
w = 160;
body = w / 46;
if (body < 14) body = 14;
if (body > 26) body = 26;
head = body + 14;
if (head > 46) head = 46;
kick = body - 3;
if (kick < 11) kick = 11;
for (int i = 0; i < HW_LESSONS; i++)
net_rescale_lesson_notes(&hw_lessons[i], body, head, kick);
}
static gboolean hw_note_tick(GtkWidget *w, GdkFrameClock *clock,
gpointer data) {
int width = gtk_widget_get_allocated_width(w);
(void)clock;
(void)data;
if (width != hw_note_last_w) {
hw_note_last_w = width;
hw_rescale_notes_at(width);
}
return G_SOURCE_CONTINUE;
}
static GtkWidget *build_hw_unit_page(NetLesson *L, const char *title_key,
const char *sub_key,
const NetSlide *slides, guint n_slides) {
GtkWidget *page;
GtkWidget *scroll;
GtkWidget *nav;
net_lesson_notes_ensure(L);
net_notes_target = L;
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("hwmap", title_key, sub_key));
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);
hw_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), "hw_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, hw_note_tick, NULL, NULL);
hw_note_last_w = -1;
hw_rescale_notes_at(0);
net_notes_target = NULL;
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(hw_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(hw_slide_next), L);
gtk_box_append(GTK_BOX(nav), L->next_btn);
L->idx = 0;
hw_slide_apply(L);
return page;
}
void hw_slide_apply(NetLesson *L) {
char name[16];
if (!L || !L->stack)
return;
g_snprintf(name, sizeof(name), "hw_slide%u", L->idx);
gtk_stack_set_visible_child_name(GTK_STACK(L->stack), name);
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 (L->next_btn) {
gtk_button_set_label(
GTK_BUTTON(L->next_btn),
L->idx + 1 >= L->n_slides ? tr("net_slide_start")
: tr("net_slide_next"));
}
}
void hw_slide_prev(GtkButton *button, gpointer data) {
NetLesson *L = data;
(void)button;
if (!L) return;
if (L->idx > 0) {
L->idx--;
hw_slide_apply(L);
}
}
void hw_slide_next(GtkButton *button, gpointer data) {
NetLesson *L = data;
(void)button;
if (!L) return;
if (L->idx + 1 < L->n_slides) {
L->idx++;
hw_slide_apply(L);
} else {
show_page(L->ex_page, 1);
}
}
void hw_lessons_apply_lang(void) {
for (int i = 0; i < HW_LESSONS; i++)
hw_slide_apply(&hw_lessons[i]);
}
GtkWidget *build_hw_unit1_page(void) {
static const NetSlide slides[HW_SLIDES] = {
{
"1 / 3 • Úvod", "Architektura počítače",
"Architektura popisuje, z jakých částí se počítač skládá "
"a jak spolu spolupracují.",
{
"Architektura počítače je základní model, podle kterého "
"jsou počítače navrhovány.",
"Nejznámější model je Von Neumannovo schéma.",
"Používá se dodnes u většiny běžných počítačů.",
NULL,
},
},
{
"2 / 3 • Osobnost", "John von Neumann",
"Tip: zapamatuj si jméno – podle něj se jmenuje celé schéma.",
{
"John von Neumann byl americký matematik.",
"Pracoval na poli digitálních počítačů a operační teorie "
"kvantové mechaniky.",
"Je autorem Von Neumannovy algebry.",
"Byl tvůrcem teorie her.",
"Podílel se na vývoji atomové a vodíkové bomby.",
NULL,
},
},
{
"3 / 3 • Schéma", "Von Neumannovo schéma",
"ALU = aritmeticko-logická jednotka",
{
"Von Neumannovo schéma má pět hlavních částí:",
"ALU – aritmeticko-logická jednotka (výpočty a logika)",
"Řadič – řídí činnost ostatních částí",
"Operační paměť – uchovává program i data",
"Vstupní jednotka – přivádí data do počítače",
"Výstupní jednotka – předává výsledky ven",
NULL,
},
},
};
return build_hw_unit_page(&hw_lessons[0], "hw_unit1", "hw_unit1_sub",
slides, HW_SLIDES);
}
/* ---- Quiz --------------------------------------------------------- */
static void hw_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"));
mark_hw_done(ctx->lesson_id);
} else {
set_feedback(ctx->feedback, FALSE, tr("feedback_retry_short"));
}
}
static GtkWidget *build_hw_mcq_page(int lesson_id, const char *back_page,
const char *title_key,
const char *heading_key,
const ChoiceQ *qs, const char **hints,
int n) {
GtkWidget *page;
GtkWidget *scroll;
GtkWidget *body;
GtkWidget *check;
GtkWidget *btns;
GtkWidget *head;
GtkWidget *intro;
NetMcqCtx *ctx = g_new0(NetMcqCtx, 1);
int n_opts = 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(back_page, title_key, 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, 14);
gtk_widget_set_halign(body, GTK_ALIGN_FILL);
gtk_widget_set_hexpand(body, TRUE);
gtk_widget_set_margin_start(body, 4);
gtk_widget_set_margin_end(body, 4);
gtk_scrolled_window_set_child(GTK_SCROLLED_WINDOW(scroll), body);
head = gtk_label_new(NULL);
i18n_bind(head, heading_key, 0);
gtk_widget_set_halign(head, GTK_ALIGN_START);
gtk_label_set_wrap(GTK_LABEL(head), TRUE);
gtk_widget_set_margin_top(head, 4);
gtk_widget_add_css_class(head, "quiz-heading");
gtk_box_append(GTK_BOX(body), head);
intro = gtk_label_new(NULL);
i18n_bind(intro, "net_quiz_intro", 0);
gtk_widget_set_halign(intro, GTK_ALIGN_START);
gtk_label_set_wrap(GTK_LABEL(intro), TRUE);
gtk_widget_add_css_class(intro, "quiz-intro");
gtk_widget_set_margin_bottom(intro, 4);
gtk_box_append(GTK_BOX(body), intro);
ctx->qs = qs;
ctx->n = n;
ctx->n_opts = n_opts;
ctx->lesson_id = lesson_id;
ctx->toggles = g_new0(GtkToggleButton *, n * n_opts);
ctx->hints = g_new0(GtkWidget *, n);
for (int i = 0; i < n; i++) {
GtkWidget *card = mcq_append_question(body, i + 1, &qs[i],
&ctx->toggles[i * n_opts]);
ctx->hints[i] = meaning_add(card, hints[i]);
}
btns = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 8);
gtk_widget_set_margin_top(btns, 8);
gtk_widget_set_margin_bottom(btns, 8);
gtk_box_append(GTK_BOX(body), btns);
check = gtk_button_new();
i18n_bind(check, "check", 1);
gtk_widget_add_css_class(check, "btn-primary");
gtk_widget_set_halign(check, GTK_ALIGN_START);
gtk_box_append(GTK_BOX(btns), check);
g_signal_connect(check, "clicked", G_CALLBACK(hw_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;
}
GtkWidget *build_hw_unit1_exercise_page(void) {
static const ChoiceQ qs[] = {
{"Kdo je autorem Von Neumannova schématu?",
{"Alan Turing", "John von Neumann", "Bill Gates", "Steve Jobs"},
4, 1},
{"Čím byl John von Neumann?",
{"Americký matematik", "Německý fyzik", "Anglický chemik",
"Francouzský lékař"},
4, 0},
{"Co znamená zkratka ALU?",
{"Automatická logická síť", "Aritmeticko-logická jednotka",
"Analogová linková sestava", "Adresová listová sekce"},
4, 1},
{"Která část Von Neumannova schématu řídí ostatní části?",
{"Operační paměť", "Vstupní jednotka", "Řadič", "Výstupní jednotka"},
4, 2},
{"Kde se podle Von Neumannova schématu uchovává program i data?",
{"Jen na pevném disku", "V operační paměti", "Jen ve vstupní jednotce",
"Jen v ALU"},
4, 1},
{"Čím se John von Neumann také zabýval?",
{"Jen malířstvím", "Teorií her", "Jen botanikou", "Jen hudbou"},
4, 1},
};
static const char *hints[] = {
"John von Neumann – americký matematik",
"Americký matematik s objevy v digitálních počítačích",
"ALU = aritmeticko-logická jednotka",
"Řadič řídí činnost ostatních částí",
"Operační paměť uchovává program i data",
"Byl tvůrcem teorie her",
};
return build_hw_mcq_page(0, "hwunit1", "hw_ex1_title", "hw_quiz1_head",
qs, hints, 6);
}
GtkWidget *build_hw_unit2_page(void) {
static const NetSlide slides[HW2_SLIDES] = {
{
"1 / 6 • Přehled", "Historie počítačů",
"Generace se dělí podle součástky, která v té době počítala: relé, elektronka, tranzistor, integrovaný obvod a nakonec mikroprocesor.",
{
"Předchůdci do 19. století jsou mechanické pomůcky. Pascaline sčítala ozubenými koly, Babbage navrhl analytický stroj a Ada Lovelace k němu popsala postup výpočtu. Elektronika ještě chyběla.",
"Nultá generace, zhruba 1938–1944, spíná elektromagnetická relé. Stroje jsou kusové a často vojenské.",
"První generace, 1944–1955, bere elektronku. Počítač zabere sál a program se dává děrnými štítky.",
"Druhá generace, 1955–1964, nahrazuje elektronku tranzistorem. Objevují se vyšší programovací jazyky.",
"Třetí generace, 1964–1971, staví na integrovaném obvodu. Vznikají rodiny počítačů a operační systémy.",
"Čtvrtá generace od roku 1971 staví na mikroprocesoru. Počítač se vejde na stůl a později do kapsy.",
NULL,
},
},
{
"2 / 6 • 0. generace", "Počítače 0. generace (1938–1944)",
"Tip: počítačů byly jednotky kusů a často sloužily armádě. Základem je relé, ne elektronka.",
{
"Relé je elektromagnetický spínač. Je pomalejší a hlučnější než pozdější elektronka, ale umí už skládat logické obvody.",
"Konrad Zuse dokončil v roce 1941 Z3: programovatelný binární stroj s plovoucí řádovou čárkou.",
"Harvard Mark I (1944) byl elektromechanický a počítal balistické tabulky pro americkou armádu.",
"Každý stroj se stavěl na zakázku. Obsluhoval ho tým, ne jeden člověk u stolu.",
"Program býval na děrné pásce nebo na přepínačích, ne v dnešní operační paměti.",
"Typická práce byla vojenská: šifry a tabulky střelby, ne kancelář nebo domácnost.",
NULL,
},
},
{
"3 / 6 • 1. generace", "Počítače 1. generace (1944–1955)",
"Klíčový objev je elektronka. Spíná rychleji než relé, ale hřeje, často se pálí a počítač kvůli ní zabere celý sál.",
{
"ENIAC (1945) měl kolem 18 tisíc elektronek a počítal hlavně balistiku.",
"Von Neumannova architektura ukládá program i data do stejné paměti. Na tom stojí i dnešní počítače.",
"UNIVAC I (1951) byl první sériově prodávaný komerční počítač v USA.",
"Program a data se děrovaly do štítků. Operátor vložil balík a čekal na výsledek.",
"Operační systém ani vyšší jazyk ještě nebyl. Psalo se ve strojovém kódu.",
"Sál potřeboval klimatizaci a stálý dohled. Do domácnosti se takový stroj nevešel.",
NULL,
},
},
{
"4 / 6 • 2. generace", "Počítače 2. generace (1955–1964)",
"Klíčový objev je tranzistor. V Bellových laboratořích vznikl roku 1947 a do počítačů se dostal zhruba od roku 1955.",
{
"Tranzistor nahradí elektronku: je menší, spolehlivější a méně se hřeje.",
"Stroj už nemusí zabírat celý sál, pořád je to ale zařízení pro firmu nebo ústav.",
"Vnitřní paměť bývá feritová. Vnější paměť jsou magnetické pásky a bubny.",
"FORTRAN (1957) a COBOL (1959) dovolí psát program blíž lidské řeči než strojový kód.",
"Úlohy se zpracovávají dávkově. Operátor seřadí balíky a počítač je jede postupně.",
"Typické stroje této doby jsou IBM 1401 a IBM 7090.",
NULL,
},
},
{
"5 / 6 • 3. generace", "Počítače 3. generace (1964–1971)",
"Klíčový objev je integrovaný obvod: mnoho tranzistorů na jednom křemíkovém čipu. Kilby a Noyce ho představili na konci 50. let.",
{
"IBM System/360 (1964) je rodina počítačů se stejným instrukčním souborem. Program z menšího modelu běží i na větším.",
"Operační systém už řídí více úloh a periferie. Objevuje se sdílení času mezi uživateli.",
"Magnetický disk doplňuje pásku a zkracuje čekání na data.",
"Minipočítače jako PDP-8 se vejdou do jedné skříně. Kupují je laboratoře a firmy, ne jen stát.",
"Stroj je menší a levnější než sál první generace, pořád to ale není osobní počítač na stůl.",
"Hlavní vnější pamětí zůstává magnetické médium, ne děrný štítek.",
NULL,
},
},
{
"6 / 6 • 4. generace", "Počítače 4. generace",
"Klíčová součástka je programovatelný mikroprocesor: celý procesor na jednom čipu.",
{
"Intel 4004 z roku 1971 je první komerční mikroprocesor. Pozdější čipy z něj udělaly mozek osobního počítače.",
"Na stůl se počítač dostává postupně: Altair 1975, Apple II 1977 a IBM PC 1981.",
"Roku 1972 vychází Pong, první komerčně úspěšná arkádová hra. Lekce ji bere jako první počítačovou hru.",
"Roku 1971 představuje IBM osmipalcovou disketu. Menší formáty přišly až v dalších letech.",
"Roku 1979 Philips a Sony předvádějí kompaktní disk. V obchodech je od roku 1982.",
"Paměti a disky rostou, takže počítač opouští sál a později se vejde i do kapsy.",
NULL,
},
},
};
return build_hw_unit_page(&hw_lessons[1], "hw_unit2", "hw_unit2_sub",
slides, HW2_SLIDES);
}
GtkWidget *build_hw_unit2_exercise_page(void) {
static const ChoiceQ qs[] = {
{"Kdy probíhala nultá generace počítačů?",
{"1938–1944", "1944–1955", "1955–1964", "1964–1971"}, 4, 0},
{"Co bylo typické pro počítače 0. generace?",
{"Byly v každé domácnosti", "Jen několik kusů, často vojenský účel",
"Měly mikroprocesory", "Používaly CD"},
4, 1},
{"Která technologie patří k 1. generaci?",
{"Tranzistor", "Elektronka", "Integrovaný obvod", "Mikroprocesor"},
4, 1},
{"Čím se zadávaly data v 1. generaci?",
{"USB fleškou", "Děrnými štítky", "CD", "Disketou"}, 4, 1},
{"Která technologie patří k 2. generaci?",
{"Elektronka", "Tranzistor", "Mikroprocesor", "CD"}, 4, 1},
{"Která technologie patří k 3. generaci?",
{"Elektronka", "Tranzistor", "Integrovaný obvod", "Disketa"},
4, 2},
{"Co je typické pro 4. generaci?",
{"Jen děrné štítky", "Programovatelné mikroprocesory",
"Jen vojenské použití", "Žádný software"},
4, 1},
{"Kdy vznikla první počítačová hra (podle lekce)?",
{"1964", "1972", "1973", "1979"}, 4, 1},
};
static const char *hints[] = {
"Nultá generace: 1938–1944",
"Jen několik počítačů, většinou vojenský účel",
"1. generace – objev elektronky",
"1. generace – děrné štítky",
"2. generace – objev tranzistoru",
"3. generace – integrovaný obvod",
"4. generace – programovatelné mikroprocesory",
"1972 – první počítačová hra",
};
return build_hw_mcq_page(1, "hwunit2", "hw_ex2_title", "hw_quiz2_head",
qs, hints, 8);
}
GtkWidget *build_hw_unit3_page(void) {
static const NetSlide slides[HW3_SLIDES] = {
{
"1 / 2 • Bit", "Bit – nejmenší jednotka informace",
"Bit = binary digit (dvojková číslice)",
{
"Bit je dvojková číslice – nabývá hodnoty 0 nebo 1.",
"Je to nejmenší zobrazitelná jednotka informace.",
"Z bitů se skládají větší jednotky (např. byte).",
NULL,
},
},
{
"2 / 2 • Byte", "Byte – adresovatelná jednotka paměti",
"Tip: 1 B = 8 b",
{
"Byte je nejmenší adresovatelná jednotka paměti.",
"Počítač tedy paměť adresuje po bytech, ne po jednotlivých "
"bitech.",
"Jeden byte obvykle obsahuje 8 bitů.",
NULL,
},
},
};
return build_hw_unit_page(&hw_lessons[2], "hw_unit3", "hw_unit3_sub",
slides, HW3_SLIDES);
}
GtkWidget *build_hw_unit3_exercise_page(void) {
static const ChoiceQ qs[] = {
{"Co je bit?",
{"Největší jednotka paměti", "Dvojková číslice – nejmenší jednotka "
"informace", "Jen klávesa na klávesnici", "Typ procesoru"},
4, 1},
{"Jaké hodnoty může nabývat bit?",
{"Jen 0", "Jen 1", "0 nebo 1", "0 až 255"}, 4, 2},
{"Co je byte?",
{"Nejmenší adresovatelná jednotka paměti",
"Nejmenší zobrazitelná jednotka informace",
"Jen síťový kabel", "Jen grafická karta"},
4, 0},
{"Kolik bitů má obvykle jeden byte?",
{"2", "4", "8", "16"}, 4, 2},
};
static const char *hints[] = {
"Bit = dvojková číslice, nejmenší jednotka informace",
"Bit nabývá hodnoty 0 nebo 1",
"Byte = nejmenší adresovatelná jednotka paměti",
"1 B = 8 b",
};
return build_hw_mcq_page(2, "hwunit3", "hw_ex3_title", "hw_quiz3_head",
qs, hints, 4);
}
GtkWidget *build_hw_unit4_page(void) {
static const NetSlide slides[HW4_SLIDES] = {
{
"1 / 2 • Integer", "Proměnná typu integer (celá čísla)",
"Tip: n bitů → 2ⁿ různých hodnot (např. 0 až 2ⁿ − 1)",
{
"Celá čísla se ukládají binárně v pevné řádové čárce.",
"Mají pevný počet bitů – standardně 16 nebo 32 "
"(tedy 2 nebo 4 byty).",
"Při 16bitovém formátu je 2¹⁶ = 65 536 různých hodnot; "
"u nezáporných čísel interval 0 až 2¹⁶ − 1, tedy 0–65 535.",
"Obecně u n bitů je M = 2ⁿ různých hodnot "
"(u 16 bitů je nejvyšší nezáporné číslo 65 535).",
"Ostatní čísla se do tohoto intervalu převádějí transformací "
"(mapováním na přirozená čísla z daného rozsahu).",
NULL,
},
},
{
"2 / 2 • Real", "Proměnná typu real (desetinná čísla)",
"Tip: tvar = mantisa × základ^exponent",
{
"Desetinná čísla se ukládají v pohyblivé řádové čárce "
"ve tvaru mantisa a exponent.",
"Mantisa je normalizovaná tak, že první platná číslice "
"je hned za desetinnou čárkou.",
"Posun řádové čárky vyrovná odpovídající změna exponentu.",
"Standardně zabírá 4 nebo 8 bytů v paměti.",
"Více bytů se používá jen tehdy, když potřebujeme vyšší "
"přesnost výpočtů.",
NULL,
},
},
};
return build_hw_unit_page(&hw_lessons[3], "hw_unit4", "hw_unit4_sub",
slides, HW4_SLIDES);
}
GtkWidget *build_hw_unit4_exercise_page(void) {
static const ChoiceQ qs[] = {
{"Jak se ukládají celá čísla (integer)?",
{"Jen jako text",
"Binárně v pevné řádové čárce s pevným počtem bitů",
"Jen jako obrázek",
"Jen v pohyblivé řádové čárce bez exponentu"},
4, 1},
{"Kolik různých hodnot má 16bitový nezáporný integer?",
{"256", "1024", "65 536 (0 až 65 535)", "4"},
4, 2},
{"Jak se ukládají desetinná čísla (real)?",
{"Jen jako celá čísla bez tečky",
"V pohyblivé řádové čárce jako mantisa a exponent",
"Jen jako 1 bit",
"Jen jako název souboru"},
4, 1},
{"Co znamená normalizace mantisy?",
{"Že se číslo smaže",
"Že první platná číslice je hned za desetinnou čárkou "
"a exponent se upraví",
"Že se použije jen 1 bit",
"Že se číslo uloží jako text"},
4, 1},
};
static const char *hints[] = {
"Integer = pevná řádová čárka, pevný počet bitů (16/32…)",
"16 bitů → 2¹⁶ = 65 536 hodnot (0–65 535 u nezáporných)",
"Real = pohyblivá řádová čárka = mantisa + exponent",
"Normalizace: 1. platná číslice hned za desetinnou čárkou",
};
return build_hw_mcq_page(3, "hwunit4", "hw_ex4_title", "hw_quiz4_head",
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);
}
GtkWidget *build_hw_unit10_page(void) {
static const NetSlide slides[] = {
{
"1 / 2 • Účel", "Počítačová skříň",
"Tip: skříň má být uzavřená, ale s větracími mřížkami.",
{
"Skříň zastřešuje a drží ostatní komponenty.",
"Součásti se propojují kabely nebo přímo do základní desky.",
"Při provozu vzniká teplo a skříň ho musí odvést.",
"Uzavřená skříň s mřížkami udržuje správné proudění vzduchu "
"(airflow).",
NULL,
},
},
{
"2 / 2 • Stěny", "Přední a zadní stěna, desktop a tower",
"Tip: desktop leží, tower stojí.",
{
"Přední stěna: zapnutí, restart, zelená kontrolka chodu "
"a červená kontrolka disku.",
"Vpředu bývají i USB porty a audio vstupy a výstupy.",
"Zadní stěna zpřístupňuje porty desky a přídavných karet.",
"Volné otvory kryjí záslepky, aby se dovnitř neprášilo.",
"Desktop je skříň naležato, monitor se na ni pokládá.",
"Tower stojí nastojato vedle monitoru nebo pod stolem.",
NULL,
},
},
};
return build_hw_unit_page(&hw_lessons[9], "hw_unit10", "hw_unit10_sub",
slides, G_N_ELEMENTS(slides));
}
GtkWidget *build_hw_unit10_exercise_page(void) {
static const ChoiceQ qs[] = {
{"K čemu slouží počítačová skříň?",
{"Jen jako ozdoba monitoru",
"Zastřešuje a uchycuje ostatní komponenty",
"Převádí 230 V na 12 V",
"Ukládá operační systém"},
4, 1},
{"Proč má být skříň uzavřená a mít větrací mřížky?",
{"Aby se dovnitř vešel jen jeden disk",
"Aby uvnitř správně proudil vzduch a odvádělo se teplo",
"Aby nešel zapnout restart",
"Aby odpadly kabely"},
4, 1},
{"Co typicky najdeme na přední stěně?",
{"Tlačítka, kontrolky, USB a audio",
"Jen patici procesoru",
"Jen sloty ISA",
"Jen plotny pevného disku"},
4, 0},
{"Jak se liší desktop a tower?",
{"Desktop je bez zdroje, tower bez desky",
"Desktop je jen pro notebooky",
"Desktop leží, tower stojí",
"Liší se jen barvou kontrolek"},
4, 2},
};
static const char *hints[] = {
"Skříň drží a chrání komponenty",
"Airflow odvádí teplo",
"Vpředu: power, reset, LED, USB, audio",
"Desktop naležato, tower nastojato",
};
return build_hw_mcq_page(9, "hwunit10", "hw_ex10_title", "hw_quiz10_head",
qs, hints, 4);
}
GtkWidget *build_hw_unit11_page(void) {
static const NetSlide slides[] = {
{
"1 / 2 • Převod", "Napájecí zdroj",
"Tip: ze sítě jde střídavých 230 V / 50 Hz.",
{
"Zdroj zásobuje všechny části počítače elektřinou.",
"Převádí střídavé napětí 230 V, 50 Hz na stejnosměrné "
"3,3 V, 5 V a 12 V.",
"Nejrozšířenější je standard ATX, včetně variant TFX a SFX.",
"ATX umí počítač vypnout softwarově přes základní desku.",
"Výkon se vyrábí v řadě hodnot, třeba od 350 W po 700 W "
"i víc.",
NULL,
},
},
{
"2 / 2 • Přívody", "Co se napájí přímo a kolik to bere",
"Tip: spotřeba není stálá.",
{
"Přímo ze zdroje: deska, pevné disky, mechaniky, aktivní "
"chladiče a grafické karty.",
"Přes desku: rozšiřující karty, některé ventilátory, "
"procesor, porty a LED kontrolky.",
"V klidu bere sestava zhruba 100 W.",
"V plné zátěži může spotřeba dosáhnout 500–600 W.",
NULL,
},
},
};
return build_hw_unit_page(&hw_lessons[10], "hw_unit11", "hw_unit11_sub",
slides, G_N_ELEMENTS(slides));
}
GtkWidget *build_hw_unit11_exercise_page(void) {
static const ChoiceQ qs[] = {
{"Co zdroj udělá se síťovým napětím?",
{"Nechá 230 V střídavých všude v počítači",
"Převede 230 V střídavých na stejnosměrné 3,3 V, 5 V a 12 V",
"Převede všechno na 230 V stejnosměrných",
"Vyrábí jen 1,5 V pro USB"},
4, 1},
{"Co umožňuje standard ATX?",
{"Softwarové vypnutí počítače přes základní desku",
"Jen napájení disketové mechaniky",
"Zrušení větracích mřížek",
"Uložení BIOSu na pásku"},
4, 0},
{"Co se ze zdroje napájí přímo?",
{"Jen LED na klávesnici",
"Jen porty na zadní stěně",
"Deska, disky, mechaniky, aktivní chladiče a grafické karty",
"Jen operační paměť"},
4, 2},
{"Jak se mění spotřeba počítače?",
{"Je pořád přesně 350 W",
"V klidu asi 100 W, v plné zátěži 500–600 W",
"V klidu 500 W a v zátěži 100 W",
"Nezávisí na tom, co počítač dělá"},
4, 1},
};
static const char *hints[] = {
"230 V AC → 3,3 / 5 / 12 V DC",
"ATX umí softwarové vypnutí",
"Přímo: deska, disky, mechaniky, chladiče, GPU",
"Klid cca 100 W, zátěž 500–600 W",
};
return build_hw_mcq_page(10, "hwunit11", "hw_ex11_title", "hw_quiz11_head",
qs, hints, 4);
}
GtkWidget *build_hw_unit12_page(void) {
static const NetSlide slides[] = {
{
"1 / 2 • Páteř", "Základní deska",
"Tip: deska rozhoduje o kompatibilitě a o tom, co půjde upgradovat.",
{
"Je to vícevrstvý plošný spoj, fundament a páteř počítače.",
"Propojuje procesor se všemi ostatními částmi.",
"Čipset tvoří dva čipy: severní a jižní most.",
"Sběrnice jsou měděné cestičky pro data a signály.",
NULL,
},
},
{
"2 / 2 • Čipy", "Patice, mosty a BIOS",
"Tip: nastavení BIOSu drží čip CMOS na baterii.",
{
"Patice (socket) mechanicky drží procesor a elektricky "
"ho propojí.",
"Severní most je systémový řadič blízko CPU a řeší rychlé "
"přesuny: FSB, AGP a paměťovou sběrnici.",
"Jižní most připojuje pomalejší periferie, BIOS, disky, "
"USB a porty.",
"BIOS je mezistupeň mezi hardwarem a softwarem a nese "
"instrukce pro zavedení operačního systému.",
NULL,
},
},
};
return build_hw_unit_page(&hw_lessons[11], "hw_unit12", "hw_unit12_sub",
slides, G_N_ELEMENTS(slides));
}
GtkWidget *build_hw_unit12_exercise_page(void) {
static const ChoiceQ qs[] = {
{"Co je základní deska?",
{"Vícevrstvý plošný spoj, páteř počítače",
"Jen kovový kryt zdroje",
"Jen ventilátor na procesoru",
"Externí disk"},
4, 0},
{"Z čeho se skládá čipset?",
{"Ze tří grafických karet",
"Ze severního a jižního mostu",
"Jen z baterie CMOS",
"Jen ze slotu ISA"},
4, 1},
{"Co řeší severní most?",
{"Jen pomalé USB porty",
"Jen zvukový výstup",
"Rychlé přesuny dat: FSB, AGP a paměťovou sběrnici",
"Jen tlačítko reset"},
4, 2},
{"Kde je uložené nastavení BIOSu?",
{"V čipu CMOS napájeném baterií",
"Jen na papírovém štítku skříně",
"V mechanice CD",
"V červeném vodiči zdroje"},
4, 0},
};
static const char *hints[] = {
"Deska je páteř a rozhoduje o kompatibilitě",
"Čipset = severní + jižní most",
"Severní most: FSB, AGP, paměť",
"BIOS zavádí OS, nastavení drží CMOS",
};
return build_hw_mcq_page(11, "hwunit12", "hw_ex12_title", "hw_quiz12_head",
qs, hints, 4);
}
GtkWidget *build_hw_unit13_page(void) {
static const NetSlide slides[] = {
{
"1 / 2 • Konektory", "Napájení a datové kabely",
"Tip: F_PANEL je svazek od předního panelu skříně.",
{
"Deska bere 24pinový napájecí konektor a procesor "
"zvlášť 4pinový nebo 8pinový.",
"Disky a mechaniky se připojují přes SATA.",
"Starší rozhraní jsou IDE a FDD.",
"F_PANEL připojuje Power, Reset, LED diody a PC speaker.",
NULL,
},
},
{
"2 / 2 • Sloty", "ISA, PCI, AGP a PCIe",
"Tip: dnešní rychlé rozhraní je PCI Express.",
{
"ISA je zastaralý 16bitový slot.",
"PCI je nezávislé na CPU, běží na 33 MHz a má propustnost "
"264 MB/s.",
"AGP vzniklo pro grafické karty a má přímé spojení s RAM.",
"PCI Express je sériové, vysokorychlostní a umí Hot Plug.",
NULL,
},
},
};
return build_hw_unit_page(&hw_lessons[12], "hw_unit13", "hw_unit13_sub",
slides, G_N_ELEMENTS(slides));
}
GtkWidget *build_hw_unit13_exercise_page(void) {
static const ChoiceQ qs[] = {
{"Jakými konektory se deska napájí?",
{"Jen jedním USB",
"24 piny pro desku a 4 nebo 8 piny pro CPU",
"Jen konektorem FDD",
"Jen slotem ISA"},
4, 1},
{"Co se připojuje na F_PANEL?",
{"Power, Reset, LED a PC speaker",
"Jen pevný disk",
"Jen monitor",
"Jen anténa Wi-Fi"},
4, 0},
{"Jaké má parametry sběrnice PCI?",
{"Sériová, jen pro tiskárny",
"16bitová a dnes jediná používaná",
"Nezávislá na CPU, 33 MHz, 264 MB/s",
"Jen pro procesor"},
4, 2},
{"K čemu vzniklo AGP?",
{"Pro disketové mechaniky",
"Speciálně pro grafické karty, s přímým spojením k RAM",
"Jako náhrada napájecího zdroje",
"Pro pomalé tiskárny"},
4, 1},
};
static const char *hints[] = {
"24 pinů deska, 4/8 pinů CPU",
"F_PANEL = tlačítka, LED, speaker",
"PCI: 33 MHz, 264 MB/s",
"AGP je pro grafiku a sahá přímo na RAM",
};
return build_hw_mcq_page(12, "hwunit13", "hw_ex13_title", "hw_quiz13_head",
qs, hints, 4);
}
GtkWidget *build_hw_unit14_page(void) {
static const NetSlide slides[] = {
{
"1 / 2 • Dělení", "Vnitřní a vnější paměť",
"Tip: RAM je rychlá, ale bez napájení data ztratí.",
{
"Vnitřní paměť je operační RAM: rychlá, pro rozpracovaná "
"data, bez napájení se smaže.",
"Vnější paměť jsou disky, USB a optická média.",
"Vnější paměť data udrží i bez napájení.",
"Je ale mnohem pomalejší než RAM.",
NULL,
},
},
{
"2 / 2 • Typy", "SRAM a DRAM",
"Tip: SRAM je cache v procesoru, DRAM se musí obnovovat.",
{
"SRAM (statická) je velmi rychlá a drahá.",
"Používá se jako cache v procesoru.",
"DRAM (dynamická) je levnější a data se musí neustále "
"obnovovat.",
"Patří sem SDR a řada DDR až po DDR3.",
NULL,
},
},
};
return build_hw_unit_page(&hw_lessons[13], "hw_unit14", "hw_unit14_sub",
slides, G_N_ELEMENTS(slides));
}
GtkWidget *build_hw_unit14_exercise_page(void) {
static const ChoiceQ qs[] = {
{"K čemu slouží operační RAM?",
{"Pro rozpracovaná data; je rychlá a potřebuje napájení",
"Pro trvalé uložení filmů bez elektřiny",
"Jen jako náhrada zdroje",
"Jen pro větrání skříně"},
4, 0},
{"Čím se vnější paměť liší od RAM?",
{"Je rychlejší a maže se při vypnutí",
"Drží data i bez napájení, ale je pomalejší",
"Je vždy jen v procesoru",
"Nepotřebuje žádný řadič"},
4, 1},
{"Kde se používá SRAM?",
{"Jako jediný pevný disk",
"Jen v optické mechanice",
"Jako rychlá a drahá cache v procesoru",
"Jen na předním panelu"},
4, 2},
{"Co platí o DRAM?",
{"Je levnější a data se musí obnovovat (SDR, DDR až DDR3)",
"Nikdy se neobnovuje a je dražší než SRAM",
"Slouží jen jako baterie CMOS",
"Je to jiný název pro zdroj ATX"},
4, 0},
};
static const char *hints[] = {
"RAM = rychlá vnitřní paměť, chce napájení",
"Vnější paměť je stálá a pomalejší",
"SRAM = cache CPU",
"DRAM se obnovuje, SDR a DDR až DDR3",
};
return build_hw_mcq_page(13, "hwunit14", "hw_ex14_title", "hw_quiz14_head",
qs, hints, 4);
}
GtkWidget *build_hw_unit15_page(void) {
static const NetSlide slides[] = {
{
"1 / 3 • Mozek", "Procesor",
"Tip: takt = základní hodiny 100 MHz × násobič.",
{
"CPU je hlavní výpočetní jednotka a řídí ostatní části.",
"Je to křemíkový čip z miliard tranzistorů, které pracují "
"jako spínače.",
"Frekvence je počet cyklů za sekundu (Hz, v praxi GHz).",
"Takt vznikne jako součin base clock (100 MHz) a násobiče.",
NULL,
},
},
{
"2 / 3 • Jádra", "Více jader, vlákna a cache",
"Tip: cache L1, L2 a L3 zmenšují čekání na pomalejší paměť.",
{
"Více jader jsou samostatné jednotky pro souběžnou práci.",
"Hyper-Threading / SMT nechá jedno jádro zpracovat dvě "
"vlákna najednou.",
"Cache je vyrovnávací paměť mezi rychlým jádrem a pomalejšími "
"součástmi.",
"Bývá ve třech úrovních: L1, L2 a L3.",
NULL,
},
},
{
"3 / 3 • Teplo", "Chlazení procesoru",
"Tip: chlazení prodlužuje životnost a dovolí přetaktování.",
{
"Chladič odvádí teplo z čipu.",
"Vzduchové chlazení je pasivní blok a ventilátor.",
"Je levné a spolehlivé.",
"Vodní all-in-one vede teplo kapalinou do radiátoru.",
"U procesoru tak zabere méně místa.",
NULL,
},
},
};
return build_hw_unit_page(&hw_lessons[14], "hw_unit15", "hw_unit15_sub",
slides, G_N_ELEMENTS(slides));
}
GtkWidget *build_hw_unit15_exercise_page(void) {
static const ChoiceQ qs[] = {
{"Jak vzniká takt procesoru?",
{"Jen z napětí 12 V",
"Jako součin base clock 100 MHz a násobiče",
"Jen z počtu USB portů",
"Z rychlosti ventilátoru ve skříni"},
4, 1},
{"Co umí Hyper-Threading / SMT?",
{"Jedno jádro zpracuje dvě vlákna současně",
"Vypne chlazení",
"Zdvojnásobí napětí zdroje",
"Nahradí operační paměť diskem"},
4, 0},
{"K čemu je cache L1, L2 a L3?",
{"K napájení grafické karty",
"K uložení BIOSu na baterii",
"Vyrovnává rychlostní rozdíl mezi procesorem a ostatními částmi",
"K větrání zadní stěny"},
4, 2},
{"Čím se vyznačuje vzduchové chlazení CPU?",
{"Jen kapalinou bez ventilátoru",
"Pasivním blokem a ventilátorem; je levné a spolehlivé",
"Tím, že procesor nehřeje",
"Tím, že se montuje jen na disk"},
4, 1},
};
static const char *hints[] = {
"Takt = 100 MHz × násobič",
"SMT = dvě vlákna na jedno jádro",
"Cache vyrovnává rychlost",
"Vzduch: blok + ventilátor",
};
return build_hw_mcq_page(14, "hwunit15", "hw_ex15_title", "hw_quiz15_head",
qs, hints, 4);
}
GtkWidget *build_hw_unit16_page(void) {
static const NetSlide slides[] = {
{
"1 / 2 • Karty", "Přídavné karty",
"Tip: karta je plošný spoj, který počítači přidá schopnost.",
{
"Rozšiřující karta vylepší nebo rozšíří to, co počítač umí.",
"Typické jsou grafické, zvukové, síťové a televizní karty.",
"Sloty se vyvíjely, proto karta obvykle nejde zasunout "
"do libovolného slotu.",
NULL,
},
},
{
"2 / 2 • PCIe", "Kam se karta dává",
"Tip: grafika chce nejširší slot.",
{
"Grafické karty patří do PCI Express ×16.",
"Ostatní karty se dnes dávají do PCI Express ×1 až ×4.",
"Číslo za × říká, kolik linek slot kartě dá.",
NULL,
},
},
};
return build_hw_unit_page(&hw_lessons[15], "hw_unit16", "hw_unit16_sub",
slides, G_N_ELEMENTS(slides));
}
GtkWidget *build_hw_unit16_exercise_page(void) {
static const ChoiceQ qs[] = {
{"K čemu je přídavná karta?",
{"Rozšíří nebo vylepší schopnosti počítače",
"Nahradí napájecí zdroj",
"Jen uzavře skříň",
"Ukládá BIOS"},
4, 0},
{"Do jakého slotu patří grafická karta?",
{"Do ISA", "Do PCI Express ×16", "Do FDD", "Do F_PANEL"},
4, 1},
{"Kam se dnes dávají ostatní karty?",
{"Jen do AGP",
"Jen na přední stěnu skříně",
"Do PCI Express ×1 až ×4",
"Přímo do patice procesoru"},
4, 2},
{"Proč nejde karta zasunout do každého slotu?",
{"Sloty se liší a karta sedí jen do odpovídajícího",
"Protože všechny sloty jsou stejné",
"Protože karty nemají kontakty",
"Protože to zakazuje airflow"},
4, 0},
};
static const char *hints[] = {
"Karta rozšiřuje schopnosti PC",
"GPU → PCIe ×16",
"Ostatní karty → PCIe ×1 až ×4",
"Slot a karta k sobě musí sedět",
};
return build_hw_mcq_page(15, "hwunit16", "hw_ex16_title", "hw_quiz16_head",
qs, hints, 4);
}
GtkWidget *build_hw_unit17_page(void) {
static const NetSlide slides[] = {
{
"1 / 3 • Obraz", "Z čeho se skládá obraz",
"Tip: hry skládají scénu hlavně z trojúhelníků.",
{
"Digitalizace obrazu je vzorkování, kvantování a kódování.",
"Jas může mít třeba 256 úrovní, nebo jen 2.",
"Pixel je bod v obraze.",
"Polygon je 2D mnohoúhelník; ve hrách často trojúhelník, "
"protože ho GPU zpracuje nejjednodušeji.",
"Vertex je vrchol, edge je hrana.",
"Textura je bitmapa namapovaná na 3D model.",
"Ray tracing je metoda sledování paprsku.",
NULL,
},
},
{
"2 / 3 • Typy", "Integrovaná a samostatná grafika",
"Tip: integrovaný čip šetří peníze, samostatná karta přidá výkon.",
{
"Integrovaná grafika je čip přímo na základní desce.",
"Bývá v levnějších a kancelářských sestavách i v noteboocích.",
"Má nižší výkon a nižší cenu a může brzdit zbytek systému.",
"Samostatná karta se dává do rozšiřujícího slotu.",
"Míří na hráče a náročnější uživatele.",
NULL,
},
},
{
"3 / 3 • Cesta", "Co je na kartě a kam jde obraz",
"Tip: obraz jde z CPU do grafické paměti, pak do GPU a dál na monitor.",
{
"Na kartě je GPU, RAMDAC, paměti, sběrnice, porty a často "
"konektor přídavného napájení (Molex).",
"GPU mívá aktivní chladič, okolo něj sedí paměťové čipy.",
"Datový tok začíná v procesoru počítače a jde do grafické "
"paměti.",
"GPU data zpracuje a pošle je do převodníku signálu.",
"Odtud obraz pokračuje do monitoru (framebuffer).",
NULL,
},
},
};
return build_hw_unit_page(&hw_lessons[16], "hw_unit17", "hw_unit17_sub",
slides, G_N_ELEMENTS(slides));
}
GtkWidget *build_hw_unit17_exercise_page(void) {
static const ChoiceQ qs[] = {
{"Co je pixel?",
{"Bod v obraze", "Hrana polygonu", "Napájecí konektor",
"Typ pevného disku"},
4, 0},
{"Proč hry často používají trojúhelník?",
{"Protože má víc hran než čtverec",
"Pro grafickou kartu je nejjednodušší na zpracování",
"Protože nepotřebuje texturu",
"Protože nahradí monitor"},
4, 1},
{"Čím se vyznačuje integrovaná grafika?",
{"Je vždy rychlejší než samostatná karta",
"Sedí jen v mechanice DVD",
"Čip je na desce, bývá levnější a má nižší výkon",
"Nemá vliv na zbytek počítače"},
4, 2},
{"Jakou cestou jde obraz?",
{"CPU → grafická paměť → GPU → převodník → monitor",
"Monitor → disk → zdroj → skříň",
"Jen z BIOSu přímo do reproduktoru",
"Z F_PANEL rovnou na tiskárnu"},
4, 0},
};
static const char *hints[] = {
"Pixel = bod obrazu",
"Trojúhelník je pro GPU nejjednodušší",
"Integrovaná grafika je na desce",
"CPU → VRAM → GPU → převodník → monitor",
};
return build_hw_mcq_page(16, "hwunit17", "hw_ex17_title", "hw_quiz17_head",
qs, hints, 4);
}
GtkWidget *build_hw_unit18_page(void) {
static const NetSlide slides[] = {
{
"1 / 3 • GPU", "Grafický procesor",
"Tip: pro výkon počítače je GPU stejně důležité jako CPU.",
{
"GPU přijímá data od CPU a počítá obraz.",
"Je to složitý čip se stovkami milionů tranzistorů.",
"Sleduje se takt v MHz, kapacita paměti a počet shaderů.",
"Dřív se počítaly vertex a pixel shadery, dnes spíš "
"unifikované, částečně programovatelné jednotky.",
NULL,
},
},
{
"2 / 3 • Programy", "Shader a renderování",
"Tip: vertex shader posouvá vrcholy, ale nové nevytváří.",
{
"Shader je program, který řídí části grafického řetězce.",
"Renderování tvoří obraz podle počítačového modelu, "
"nejčastěji 3D.",
"Render je vizualizace: model se přenese do 2D bitmapy.",
"Softwarový render počítá procesor. Je přesnější, ale "
"mnohonásobně pomalejší.",
"Hardwarový render slouží pro náhledy a hry.",
"Vertex shader transformuje vrcholy a nové nevytváří.",
"Pixel shader potom mapuje texturu a přidává efekty, "
"třeba ray tracing nebo bump mapping.",
NULL,
},
},
{
"3 / 3 • Výpočty", "CUDA a architektura GPU",
"Tip: většinu čipu tvoří mnoho jednoduchých procesorů.",
{
"CUDA je paralelní platforma NVIDIA a nechá GPU počítat "
"i jiné úlohy než obraz.",
"Zrychluje třeba lineární algebru, obraz, video a "
"hluboké učení.",
"Obdoba u AMD se jmenuje FireStream.",
"GPU vzniklo pro hry: miliony polygonů a velké textury.",
"Je stavěné na tisíce vláken, hodně počítání a málo "
"podmínek a na sekvenční čtení paměti.",
"Jednoduché skalární procesory jsou sdružené do "
"streaming multiprocesorů.",
NULL,
},
},
};
return build_hw_unit_page(&hw_lessons[17], "hw_unit18", "hw_unit18_sub",
slides, G_N_ELEMENTS(slides));
}
GtkWidget *build_hw_unit18_exercise_page(void) {
static const ChoiceQ qs[] = {
{"Co je shader?",
{"Program řídící části grafického řetězce",
"Napájecí konektor Molex",
"Typ pevného disku",
"Větrací mřížka"},
4, 0},
{"Co vertex shader nedělá?",
{"Neposouvá vrcholy",
"Nevytváří nové vertexy",
"Nesahá na grafickou kartu",
"Nepoužívá se ve 3D"},
4, 1},
{"Čím se liší softwarový render?",
{"Je rychlejší, protože ho počítá jen GPU",
"Umí jen černobíle",
"Počítá ho CPU, je přesnější a mnohem pomalejší",
"Nevytvoří bitmapu"},
4, 2},
{"Co je CUDA?",
{"Platforma NVIDIA pro výpočty na GPU",
"Standard napájecího zdroje",
"Starý slot ISA",
"Formát diskety"},
4, 0},
};
static const char *hints[] = {
"Shader řídí řetězec karty",
"Vertex shader nové vrcholy nezakládá",
"Softwarový render = CPU, přesný a pomalý",
"CUDA je od NVIDIA, u AMD je FireStream",
};
return build_hw_mcq_page(17, "hwunit18", "hw_ex18_title", "hw_quiz18_head",
qs, hints, 4);
}
GtkWidget *build_hw_unit19_page(void) {
static const NetSlide slides[] = {
{
"1 / 3 • Převod", "RAMDAC a grafická paměť",
"Tip: nižší CAS latency znamená kratší čekání.",
{
"RAMDAC převádí digitální data na analogová.",
"U dnešních karet je uvnitř GPU a má přednost při čtení "
"paměti.",
"Okolo GPU jsou grafické paměti, často DDR nebo GDDR5.",
"Hlavní parametry jsou kapacita a frekvence.",
"CAS latency je čekání, než se po zadání adresy sloupce "
"data objeví na pinech.",
"Čím nižší latence, tím lépe. Časy paměti se udávají "
"v nanosekundách.",
NULL,
},
},
{
"2 / 3 • Spojení", "Sběrnice grafické karty",
"Tip: PCIe 4.0 má na jedné lince 2 GB/s.",
{
"Typická sběrnice karty je PCI Express ×16, dřív to bylo AGP.",
"PCIe 4.0 zdvojnásobí propustnost proti předchozí verzi "
"při stejném počtu linek.",
"Rychlost jedné linky stoupla z 1 GB/s na 2 GB/s.",
"Slot ×16 tak teoreticky dává 32 GB/s.",
"M.2 se čtyřmi linkami dává 8 GB/s.",
NULL,
},
},
{
"3 / 3 • Výstupy", "Porty na kartě",
"Tip: stejný obraz může odejít analogově i digitálně.",
{
"Běžné výstupy jsou D-Sub, DVI, HDMI a DisplayPort.",
"Starší karty mají i TV výstup, S-Video nebo cinch.",
"Výrobci parametry přikrášlují, proto se karty srovnávají "
"benchmarkem.",
"Známý test je 3DMark. Podíl má i procesor, rozhoduje ale "
"grafická karta.",
NULL,
},
},
};
return build_hw_unit_page(&hw_lessons[18], "hw_unit19", "hw_unit19_sub",
slides, G_N_ELEMENTS(slides));
}
GtkWidget *build_hw_unit19_exercise_page(void) {
static const ChoiceQ qs[] = {
{"Co dělá RAMDAC?",
{"Převádí analogový signál na digitální",
"Převádí digitální data na analogová a dnes je v GPU",
"Počítá jen cache procesoru",
"Formátuje pevný disk"},
4, 1},
{"Co znamená nižší CAS latency?",
{"Data se objeví dřív, takže je to lepší",
"Karta má míň portů",
"Sběrnice je pomalejší",
"Monitor má nižší rozlišení"},
4, 0},
{"Jakou teoretickou propustnost má PCIe 4.0 ×16?",
{"2 GB/s", "8 GB/s", "32 GB/s", "264 MB/s"},
4, 2},
{"Co se stalo s rychlostí jedné linky u PCIe 4.0?",
{"Klesla z 2 GB/s na 1 GB/s",
"Stoupla z 1 GB/s na 2 GB/s",
"Zůstala 133 MB/s",
"Záleží jen na barvě slotu"},
4, 1},
};
static const char *hints[] = {
"RAMDAC = digital → analog, dnes v GPU",
"Nižší CAS = kratší čekání",
"PCIe 4.0 ×16 = 32 GB/s",
"Jedna linka: 1 GB/s → 2 GB/s",
};
return build_hw_mcq_page(18, "hwunit19", "hw_ex19_title", "hw_quiz19_head",
qs, hints, 4);
}
GtkWidget *build_hw_unit20_page(void) {
static const NetSlide slides[] = {
{
"1 / 2 • Více karet", "SLI, CrossFire a režimy",
"Tip: první režim IBM PC byl v roce 1982 MDA.",
{
"SLI od NVIDIA spojí dvě grafické karty do jednoho celku.",
"Vychází levněji než jedna špičková karta.",
"Obdoba u ATI se jmenuje CrossFire.",
"Režim určuje rozlišení a barevnou hloubku.",
"Dnešní karty zvládnou i 3200×2400 (QUXGA) při 32 bitech.",
NULL,
},
},
{
"2 / 2 • Názvy", "720p, 1080p, 4K a 8K",
"Tip: 4K má čtyřikrát víc pixelů než 1080p, 8K šestnáctkrát.",
{
"720p je 1280×720, tedy HD nebo HD Ready.",
"1080p je 1920×1080, tedy Full HD.",
"1440p je 2560×1440, tedy QHD, čtyřnásobek 720p.",
"4K (2160p) je 3840×2160, čtyřnásobek Full HD.",
"8K (4320p) je 7680×4320, šestnáctinásobek Full HD.",
NULL,
},
},
};
return build_hw_unit_page(&hw_lessons[19], "hw_unit20", "hw_unit20_sub",
slides, G_N_ELEMENTS(slides));
}
GtkWidget *build_hw_unit20_exercise_page(void) {
static const ChoiceQ qs[] = {
{"Co je 1080p?",
{"1920×1080, Full HD",
"1280×720, HD Ready",
"7680×4320, 8K",
"3200×2400, QUXGA"},
4, 0},
{"Co je 4K?",
{"1280×720",
"3840×2160, čtyřnásobek pixelů Full HD",
"2560×1440",
"640×480"},
4, 1},
{"Kolikrát víc pixelů má 8K proti 1080p?",
{"Dvakrát", "Čtyřikrát", "Šestnáctkrát", "Stejně"},
4, 2},
{"Co je SLI a co je CrossFire?",
{"SLI spojuje karty NVIDIA, CrossFire je obdoba ATI",
"Obojí je typ paměti DDR",
"SLI je port HDMI, CrossFire je D-Sub",
"Jsou to dva názvy stejné firmy"},
4, 0},
};
static const char *hints[] = {
"1080p = 1920×1080",
"4K = 3840×2160",
"8K má 16× víc pixelů než 1080p",
"SLI = NVIDIA, CrossFire = ATI",
};
return build_hw_mcq_page(19, "hwunit20", "hw_ex20_title", "hw_quiz20_head",
qs, hints, 4);
}
GtkWidget *build_hw_unit21_page(void) {
static const NetSlide slides[] = {
{
"1 / 3 • Výstup", "Zvuková karta",
"Tip: digitalizace zvuku je vzorkování, kvantování a kódování.",
{
"Karta zajistí zvukový výstup.",
"Převede digitální signál na analogový, který zahraje "
"reproduktor.",
"Rozlišujeme integrované, interní a externí karty.",
"CD má 44,1 kHz a bitovou hloubku 16 až 24 bitů.",
NULL,
},
},
{
"2 / 3 • Provedení", "Integrovaná, interní, externí a herní",
"Tip: externí karta se připojuje přes USB a sedí mimo skříň.",
{
"Integrovaný zvuk je na téměř každé desce a na multimédia "
"stačí.",
"Má slabší zesílení a méně konektorů.",
"Interní karta jde do PCIe a nabízí prostorový zvuk "
"a software pro nastavení.",
"Externí karta se hodí, když integrovaná nestačí, i do "
"notebooku.",
"Herní karta, interní nebo externí, drží prostorový zvuk, "
"malou odezvu a přesnou reprodukci.",
NULL,
},
},
{
"3 / 3 • Čip", "DSP a nahrávání",
"Tip: kondenzátorový mikrofon chce fantomové napájení 48 V.",
{
"Zvukový čip má jádra, D/A a A/D převodníky, sluchátkový "
"zesilovač a vstupy i výstupy.",
"DSP stojí na harvardské architektuře: paměť programu je "
"oddělená od paměti dat, na rozdíl od von Neumannova modelu.",
"Počet vstupů má odpovídat počtu nástrojů nahrávaných najednou.",
"Na zpěv stačí jeden analogový vstup.",
"Některé nástroje, třeba keyboard, chtějí vysokoimpedanční "
"vstup Hi-Z.",
NULL,
},
},
};
return build_hw_unit_page(&hw_lessons[20], "hw_unit21", "hw_unit21_sub",
slides, G_N_ELEMENTS(slides));
}
GtkWidget *build_hw_unit21_exercise_page(void) {
static const ChoiceQ qs[] = {
{"Co zvuková karta dělá se signálem?",
{"Převede digitální signál na analogový pro reproduktor",
"Převede jen obraz na texturu",
"Nahradí procesor",
"Ukládá data na pásku"},
4, 0},
{"Jak se připojuje interní zvuková karta?",
{"Jen přes VGA", "Přes slot PCIe", "Jen přes FDD", "Přes baterii CMOS"},
4, 1},
{"Jak se připojuje externí zvuková karta?",
{"Do patice procesoru", "Do slotu AGP", "Přes USB, mimo skříň",
"Jen na přední LED"},
4, 2},
{"K čemu je fantomové napájení 48 V?",
{"Pro kondenzátorové mikrofony",
"Pro vypnutí zdroje ATX",
"Pro chlazení procesoru",
"Pro slot ISA"},
4, 0},
};
static const char *hints[] = {
"Digitál → analog pro reproduktor",
"Interní karta sedí v PCIe",
"Externí karta jde přes USB",
"48 V je fantom pro kondenzátorový mikrofon",
};
return build_hw_mcq_page(20, "hwunit21", "hw_ex21_title", "hw_quiz21_head",
qs, hints, 4);
}
GtkWidget *build_hw_unit22_page(void) {
static const NetSlide slides[] = {
{
"1 / 2 • Síť", "Síťová karta",
"Tip: dnes nemusí jít jen o kabel, umí i Wi-Fi.",
{
"Integrovaná karta má ethernetový konektor přímo na desce.",
"Interní karta kombinuje kabel a Wi-Fi a jde do PCIe.",
"Externí karta se strčí do USB.",
"Wake on LAN umí počítač zapnout po datové síti.",
"Externí anténa zvětší dosah.",
"MIMO použije víc antén a zvedne propustnost.",
"WPS zjednoduší nastavení bezdrátového spojení.",
NULL,
},
},
{
"2 / 2 • Televize", "Televizní karta",
"Tip: tuner na základní desce integrovaný nebývá.",
{
"Televizní tuner na desce integrovaný není nikdy.",
"Přidá počítači příjem televizního signálu.",
"Umí signál i zaznamenat.",
"Je to další rozšiřující karta, ne součást čipsetu.",
NULL,
},
},
};
return build_hw_unit_page(&hw_lessons[21], "hw_unit22", "hw_unit22_sub",
slides, G_N_ELEMENTS(slides));
}
GtkWidget *build_hw_unit22_exercise_page(void) {
static const ChoiceQ qs[] = {
{"Kde je integrovaná síťová karta?",
{"Ethernetový konektor přímo na desce",
"Jen v optické mechanice",
"Jen jako externí disk",
"V patici procesoru"},
4, 0},
{"Co je Wake on LAN?",
{"Vypnutí monitoru při nečinnosti",
"Zapnutí počítače přes datovou síť",
"Zrychlení pevného disku",
"Jiný název pro BIOS"},
4, 1},
{"Co přináší MIMO?",
{"Jednu anténu a nižší dosah",
"Jen kabelový konektor",
"Více antén a vyšší propustnost",
"Zrušení Wi-Fi"},
4, 2},
{"Jak je to s televizní kartou na desce?",
{"Není integrovaná nikdy",
"Je na každé desce ATX",
"Nahrazuje zvukovou kartu",
"Je součást severního mostu"},
4, 0},
};
static const char *hints[] = {
"Integrovaná síťovka = LAN na desce",
"Wake on LAN zapne počítač po síti",
"MIMO = víc antén, vyšší propustnost",
"TV tuner na desce integrovaný nebývá",
};
return build_hw_mcq_page(21, "hwunit22", "hw_ex22_title", "hw_quiz22_head",
qs, hints, 4);
}
GtkWidget *build_hw_unit23_page(void) {
static const NetSlide slides[] = {
{
"1 / 3 • Trvalá data", "Vnější paměti a HDD",
"Tip: HDD je mechanický, otřes ho může poškodit.",
{
"Vnější paměť drží data dlouhodobě, má kapacitu v terabajtech "
"a je energeticky nezávislá.",
"Patří sem HDD, SSD a USB flash disky.",
"Pevný disk zaznamenává data magneticky.",
"Notebookové disky mají 2,5 palce, stolní 3,5 palce.",
NULL,
},
},
{
"2 / 3 • Čísla", "Parametry pevného disku",
"Tip: běžné otáčky jsou 5400 a 7200 za minutu.",
{
"Kapacita se udává v terabajtech.",
"Přístupová doba je v milisekundách.",
"Přenosová rychlost je ve stovkách MB/s.",
"Cache bývá třeba 256 MB.",
NULL,
},
},
{
"3 / 3 • Stopy", "Zápis, čtení a struktura",
"Tip: hlavy se ploten nedotýkají, vznášejí se na vzduchu.",
{
"Zápis dělá cívka magnetickým polem.",
"Čtení používá elektromagnetickou indukci.",
"Disk je hermeticky uzavřený.",
"Formátování vytvoří stopy a sektory.",
"Cylindr jsou stejné stopy na všech plotnách.",
"Defragmentace složí rozházená data k sobě, aby se četla "
"rychleji.",
NULL,
},
},
};
return build_hw_unit_page(&hw_lessons[22], "hw_unit23", "hw_unit23_sub",
slides, G_N_ELEMENTS(slides));
}
GtkWidget *build_hw_unit23_exercise_page(void) {
static const ChoiceQ qs[] = {
{"Na jakém principu pracuje HDD?",
{"Na magnetickém záznamu a je mechanický",
"Jen na optickém laseru",
"Nemá pohyblivé části",
"Drží data jen při zapnutém napájení"},
4, 0},
{"Jaké rozměry mají pevné disky?",
{"Jen 8 palců",
"2,5\" do notebooku a 3,5\" do stolního počítače",
"12 cm jako CD",
"Jen formát microSD"},
4, 1},
{"Jaké otáčky se u HDD běžně uvádějí?",
{"100 a 200 ot/min", "1000 ot/min", "5400 a 7200 ot/min",
"48 000 ot/min"},
4, 2},
{"Jak disk zapisuje a čte?",
{"Zápis cívkou, čtení elektromagnetickou indukcí",
"Zápis laserem, čtení ventilátorem",
"Obojí jen přes BIOS",
"Zápis do CMOS, čtení z baterie"},
4, 0},
};
static const char *hints[] = {
"HDD = magnetický a mechanický",
"2,5\" notebook, 3,5\" desktop",
"5400 a 7200 ot/min",
"Zápis = magnetické pole, čtení = indukce",
};
return build_hw_mcq_page(22, "hwunit23", "hw_ex23_title", "hw_quiz23_head",
qs, hints, 4);
}
GtkWidget *build_hw_unit24_page(void) {
static const NetSlide slides[] = {
{
"1 / 3 • Bez pohybu", "SSD",
"Tip: fragmentace u SSD problém není.",
{
"SSD je polovodičový disk bez pohyblivých částí.",
"Je odolnější, tiché, úspornější a rychlejší než HDD.",
"Buňky se opotřebovávají, počet zápisů je omezený.",
"Bývá dražší než plotnový disk stejné kapacity.",
NULL,
},
},
{
"2 / 3 • Buňky", "FTL, TRIM a záchrana",
"Tip: smazání smaže metadata. U SSD TRIM záchranu ztěžuje.",
{
"FTL rovnoměrně rozkládá zápisy, aby se buňky sjížděly stejně.",
"TRIM řekne disku, které bloky už nikdo nepoužívá, a zápis "
"se tím zrychlí.",
"Poškození může být hardwarové (mechanika, elektronika, "
"oheň, voda) nebo softwarové (smazání, formát, virus).",
"Smazání maže metadata, obsah na HDD často zůstane a dá "
"se obnovit.",
"U SSD je obnova kvůli TRIM obtížnější.",
NULL,
},
},
{
"3 / 3 • Přenos", "SSHD a USB flash",
"Tip: konektor USB flash disku je počítaný asi na 1500 cyklů.",
{
"SSHD je pevný disk s malou SSD částí, zhruba 8 GB.",
"Často používané soubory si přesune na rychlou část.",
"Dává smysl, když chcete kapacitu i rychlost za rozumnou cenu.",
"USB flash je malé médium na přenos dat po sběrnici USB.",
"Životnost buněk záleží na typu SLC, MLC nebo TLC a na "
"kvalitě hardwaru.",
NULL,
},
},
};
return build_hw_unit_page(&hw_lessons[23], "hw_unit24", "hw_unit24_sub",
slides, G_N_ELEMENTS(slides));
}
GtkWidget *build_hw_unit24_exercise_page(void) {
static const ChoiceQ qs[] = {
{"Co je hlavní výhoda SSD proti HDD?",
{"Má plotny a je hlučnější",
"Nemá pohyblivé části, je tiché a rychlejší",
"Data ztratí při vypnutí",
"Nejde ho použít jako systémový disk"},
4, 1},
{"Jaká je nevýhoda SSD?",
{"Buňky se opotřebovávají a disk bývá dražší",
"Musí se defragmentovat každý den",
"Nepřežije přesun po stole",
"Nemá TRIM ani FTL"},
4, 0},
{"Co dělá příkaz TRIM?",
{"Zvýší otáčky ploten",
"Smaže BIOS",
"Oznámí SSD, které bloky už nejsou použité",
"Zapne fantomové napájení"},
4, 2},
{"Co je SSHD?",
{"Jen jiný název pro disketu",
"HDD doplněné o malou SSD část, asi 8 GB",
"Optický disk s modrým laserem",
"Paměťová karta SD"},
4, 1},
};
static const char *hints[] = {
"SSD = bez pohyblivých částí",
"Buňky se sjíždějí a cena je vyšší",
"TRIM hlásí volné bloky",
"SSHD = HDD + asi 8 GB SSD",
};
return build_hw_mcq_page(23, "hwunit24", "hw_ex24_title", "hw_quiz24_head",
qs, hints, 4);
}
GtkWidget *build_hw_unit25_page(void) {
static const NetSlide slides[] = {
{
"1 / 3 • Přehled", "Výměnná média",
"Tip: páska se musí převinout, proto se hodí na archiv, ne na denní práci.",
{
"Mechanická média: děrné štítky a děrné pásky.",
"Magnetická: pásky a diskety.",
"Optická: CD, DVD a Blu-ray.",
"Elektrická: paměťové karty a USB flash.",
"K souboru na pásce nejde skočit, páska se na místo přetočí.",
NULL,
},
},
{
"2 / 3 • Pásky", "Magnetická páska",
"Tip: páska pořád slouží velkým firmám na dlouhodobou zálohu.",
{
"Jedna raná páska unesla data asi deseti tisíc děrných štítků.",
"Kapacita začínala u stovek kilobajtů, třeba 850 kB.",
"Dlouho měla vyšší kapacitu než pevné disky; zlom přišel "
"kolem roku 2010 s terabajtovými disky.",
"Podle IBM ji v USA používá přímo nebo nepřímo až 82 % "
"velkých firem.",
"Odhad je stovky miliard gigabajtů dat na páskách po světě.",
"Sklad CSCS v Curychu má 27 PB na 17 000 páskách LTO-5 "
"po 1500 GB.",
NULL,
},
},
{
"3 / 3 • Diskety", "Z pásky na kotouč",
"Tip: ikona ukládání je 3,5\" disketa.",
{
"Stopa se přesunula na otáčející se mylarový kotouč.",
"Soustředné stopy umožní náhodný přístup, ne jen převíjení.",
"8\" disketa (1971) měla 100 kB a zápis z jedné strany.",
"5,25\" (1976) se dala poslat poštou; kapacita 80 až 1200 kB.",
"3,5\" zavedla Sony v roce 1981.",
"Standard 1990–1995 je 1,44 MB, pevný obal a dvířka, "
"vloží se jen správně.",
NULL,
},
},
};
return build_hw_unit_page(&hw_lessons[24], "hw_unit25", "hw_unit25_sub",
slides, G_N_ELEMENTS(slides));
}
GtkWidget *build_hw_unit25_exercise_page(void) {
static const ChoiceQ qs[] = {
{"Proč se páska hodí na archiv a ne na běžnou práci?",
{"K souboru se musí převinout, přístup není náhodný",
"Nemá žádnou kapacitu",
"Nejde ji vyjmout z mechaniky",
"Maže se při každém čtení"},
4, 0},
{"Jaká byla raná 8\" disketa?",
{"Z roku 1981 a měla 1,44 MB",
"Z roku 1971 a měla 100 kB",
"Z roku 2010 a měla 1 TB",
"Byla optická"},
4, 1},
{"Co platí o 3,5\" disketě?",
{"Zavedla ji IBM v roce 1960 a měla 850 kB",
"Neměla pevný obal",
"Sony, 1981, standardně 1,44 MB",
"Šla vložit oběma směry"},
4, 2},
{"Čím disketa zrychlila přístup proti pásce?",
{"Soustředné stopy dovolí náhodný přístup",
"Má modrý laser",
"Nemá magnetickou vrstvu",
"Čte se jen od konce"},
4, 0},
};
static const char *hints[] = {
"Páska je sekvenční",
"8\" = 1971, 100 kB",
"3,5\" = Sony 1981, 1,44 MB",
"Stopy na kotouči = náhodný přístup",
};
return build_hw_mcq_page(24, "hwunit25", "hw_ex25_title", "hw_quiz25_head",
qs, hints, 4);
}
GtkWidget *build_hw_unit26_page(void) {
static const NetSlide slides[] = {
{
"1 / 3 • Laser", "Jak se čte optický disk",
"Tip: land odrazí paprsek (1), pit ho rozptýlí (0).",
{
"Kotouč má průměr 12 cm a tloušťku 1,2 mm.",
"Data leží ve spirále od středu ke kraji.",
"U 700MB CD je stopa dlouhá 6,244 km.",
"Spirála střídá pity (prohlubně) a landy (plochy).",
NULL,
},
},
{
"2 / 3 • Generace", "CD, DVD a Blu-ray",
"Tip: Blu-ray používá modrý laser 405 nm, DVD červený 650 nm.",
{
"CD má 650–870 MB. CD-R vypálí organické barvivo asi při "
"290 °C a zápis je nevratný.",
"CD-RW jde přepsat tisíckrát až stotisíckrát. Slitina "
"AgInSbTe mění krystaly zahřátím a chlazením.",
"DVD má 1,4 až 15,82 GB, stopu 11,84 km a umí dvě vrstvy "
"i obě strany.",
"Blu-ray má 25–128 GB. Kratší vlnová délka znamená hustší "
"záznam.",
"Optika ustoupila kvůli kapacitě, pomalému zápisu, "
"spolehlivosti a tomu, že obsah je online.",
NULL,
},
},
{
"3 / 3 • Karty", "Flash karty",
"Tip: NAND paměť vytlačila optické mechaniky.",
{
"Flash je statická vnější paměť: malá, s velkou kapacitou, "
"odolná vůči vibracím a magnetickému poli.",
"Buňky mají plovoucí hradlo: SLC, MLC, TLC nebo QLC.",
"Karty: SD (i mini a micro), MMC, Memory Stick a "
"CompactFlash.",
"Čtečka na USB mívá víc slotů, aby vzala víc formátů.",
NULL,
},
},
};
return build_hw_unit_page(&hw_lessons[25], "hw_unit26", "hw_unit26_sub",
slides, G_N_ELEMENTS(slides));
}
GtkWidget *build_hw_unit26_exercise_page(void) {
static const ChoiceQ qs[] = {
{"Co se stane, když laser trefí land a když trefí pit?",
{"Obojí je signál 0",
"Land se odrazí jako 1, pit se rozptýlí jako 0",
"Land je 0 a pit je 1",
"Laser se na disku nepoužívá"},
4, 1},
{"Jak se zapisuje CD-R?",
{"Vypálením barviva, zápis je nevratný",
"Magnetickou cívkou jako HDD",
"Libovolně mnohokrát jako RAM",
"Jen změnou názvu souboru"},
4, 0},
{"Čím se laser Blu-ray liší od DVD?",
{"Má červený laser 650 nm a menší kapacitu",
"Nemá spirálu",
"Má modrý laser 405 nm a kapacitu 25–128 GB",
"Má stejný laser jako CD"},
4, 2},
{"Které karty patří mezi flash média?",
{"Jen děrné štítky",
"SD, MMC, Memory Stick a CompactFlash",
"Jen 8\" diskety",
"Jen pásky LTO"},
4, 1},
};
static const char *hints[] = {
"Land = odraz = 1, pit = rozptyl = 0",
"CD-R pálí barvivo a nejde vrátit",
"Blu-ray: 405 nm, 25–128 GB",
"SD, MMC, MS, CF",
};
return build_hw_mcq_page(25, "hwunit26", "hw_ex26_title", "hw_quiz26_head",
qs, hints, 4);
}
GtkWidget *build_hw_unit27_page(void) {
static const NetSlide slides[] = {
{
"1 / 2 • Vstup", "Polohovací zařízení a klávesnice",
"Tip: klávesnice má šest částí.",
{
"Polohovací zařízení hýbe kurzorem a bývá drátové i bezdrátové.",
"Hlavní písmenková část.",
"Speciální a české znaky.",
"Ovládací tlačítka a posunovací tlačítka.",
"Numerická klávesnice a funkční klávesy.",
NULL,
},
},
{
"2 / 2 • Typy", "Membrána, guma, nůžky a laser",
"Tip: scissor-switch je notebookový, mělký a tichý.",
{
"Membránová je nejčastější u stolních počítačů. Stisk "
"propojí membránu a je velmi tichá.",
"U vodivé gumy se guma prohne ke kontaktu a sepne obvod. "
"Pod ní je izolační destička a pozlacený kontakt.",
"Scissor-switch nemá gumovou membránu. Klávesa se propadne "
"po nůžkovém mechanismu.",
"Laserová klávesnice promítá rozložení na podložku a senzor "
"snímá stisk. Hodí se k mobilu.",
NULL,
},
},
};
return build_hw_unit_page(&hw_lessons[26], "hw_unit27", "hw_unit27_sub",
slides, G_N_ELEMENTS(slides));
}
GtkWidget *build_hw_unit27_exercise_page(void) {
static const ChoiceQ qs[] = {
{"Z kolika částí se skládá běžná klávesnice?",
{"Ze šesti", "Ze dvou", "Z dvanácti", "Jen z numerického bloku"},
4, 0},
{"Jaká je membránová klávesnice?",
{"Nejhlučnější a jen pro notebooky",
"Nejpoužívanější u stolních počítačů a velmi tichá",
"Promítá se laserem",
"Nemá žádný kontakt"},
4, 1},
{"Co je scissor-switch?",
{"Gumová membrána ve stolním PC",
"Laser na podložce",
"Notebookový nůžkový mechanismus, mělký a tichý stisk",
"Jen funkční klávesy"},
4, 2},
{"Jak pracuje laserová klávesnice?",
{"Promítne rozložení a senzor snímá virtuální stisk",
"Používá vodivou gumu",
"Je jen mechanická s nejhlubším stiskem",
"Čte jen numerický blok"},
4, 0},
};
static const char *hints[] = {
"Šest částí: písmena, znaky, ovládání, posun, numerická, funkce",
"Membrána = nejčastější stolní, tichá",
"Scissor = nůžky, notebook",
"Laser promítá klávesy na podložku",
};
return build_hw_mcq_page(26, "hwunit27", "hw_ex27_title", "hw_quiz27_head",
qs, hints, 4);
}
GtkWidget *build_hw_unit28_page(void) {
static const NetSlide slides[] = {
{
"1 / 3 • Kulička", "Kuličková myš",
"Tip: pohyb se měří prosvícením otvorů v kotoučcích.",
{
"Posuv otáčí kuličkou.",
"Kulička točí válečky pro osy x a y.",
"Kotoučky na válečcích mají otvory.",
"Infračervené diody otvory prosvěcují.",
"Senzory záblesky převedou na polohu.",
NULL,
},
},
{
"2 / 3 • Prostor", "Spaceball, trackball, tablet a digitizér",
"Tip: tablet pozná tlak, až ve stovkách až 1024 úrovních.",
{
"Spaceball má pohyb a rotaci po třech osách. V CAD a "
"grafice zvedá efektivitu zhruba o 30–50 %.",
"Trackball je jako obrácená kuličková myš. Na rychlý "
"a přesný pohyb se nehodí.",
"Tablet má síť vodičů, která reaguje na pero. Hodí se "
"do CAD a grafiky, kreslit jde i na LCD.",
"Digitizér je speciální myš na přesnou polohu a chce "
"speciální podložku. Měří odpor mezi ukazovátkem a podložkou.",
NULL,
},
},
{
"3 / 3 • Notebook", "Trackpoint a touchpad",
"Tip: trackpoint sedí mezi klávesami G, H a B.",
{
"Trackpoint je malý joystick a šetří místo.",
"Touchpad je nejčastější polohovací zařízení notebooku.",
"Snímá elektrickou kapacitu prstu.",
"Hotspoty na ploše mají zvláštní účel, třeba posuvník.",
NULL,
},
},
};
return build_hw_unit_page(&hw_lessons[27], "hw_unit28", "hw_unit28_sub",
slides, G_N_ELEMENTS(slides));
}
GtkWidget *build_hw_unit28_exercise_page(void) {
static const ChoiceQ qs[] = {
{"Jak kuličková myš pozná pohyb?",
{"Laserem na podložce bez kuličky",
"Kulička točí válečky a infračervené diody prosvěcují otvory",
"Jen kapacitou prstu",
"Měřením 48 V"},
4, 1},
{"Kde je trackpoint?",
{"Mezi klávesami G, H a B",
"Na zadní stěně skříně",
"V optické mechanice",
"Jen u stolní myši"},
4, 0},
{"Jak touchpad snímá prst?",
{"Kuličkou a válečky",
"Magnetickou páskou",
"Elektrickou kapacitou prstu",
"Fantomovým napájením"},
4, 2},
{"Co umí grafický tablet?",
{"Jen zapnout počítač",
"Reaguje na pero a tlak, až 1024 úrovní",
"Nahradí napájecí zdroj",
"Čte jen děrné štítky"},
4, 1},
};
static const char *hints[] = {
"Kulička, válečky, IR diody",
"Trackpoint je mezi G, H a B",
"Touchpad měří kapacitu",
"Tablet: pero a tlak až 1024 úrovní",
};
return build_hw_mcq_page(27, "hwunit28", "hw_ex28_title", "hw_quiz28_head",
qs, hints, 4);
}
GtkWidget *build_hw_unit29_page(void) {
static const NetSlide slides[] = {
{
"1 / 3 • Hry", "Gamepad, joystick a volant",
"Tip: force feedback přidá vibrace a nárazy.",
{
"Gamepad ovládá hry a mívá programovatelná tlačítka.",
"DualShock přidává vibrace.",
"Joystick je páka na základně. Dřív byl analogový, "
"dnes digitální.",
"Používá se i v letadlech nebo bagrech.",
"Volant napodobuje řízení: pedály, řadící páka a "
"programovatelná tlačítka.",
NULL,
},
},
{
"2 / 3 • Tělo", "Kinect",
"Tip: sleduje celé tělo ve 3D, ne jen ovladač v ruce.",
{
"Kombinuje RGB kameru, hloubkové čidlo, mikrofony a "
"vlastní procesor.",
"Sleduje pohyb celého těla v prostoru.",
"Reaguje na pokyny a pozná i změnu zabarvení hlasu a emoce.",
NULL,
},
},
{
"3 / 3 • Displej", "Odporová a kapacitní vrstva",
"Tip: kapacitního displeje se musíte dotknout vodivě, třeba prstem.",
{
"Odporová vrstva má tvrzenou a vodivou vrstvu, odporové "
"vrstvy, vymezovací bodovou síť a sklo.",
"Dotyk vrstvy přitlačí k sobě a obvod se sepne.",
"Kapacitní displej má dvě vodivé vrstvy pod napětím, "
"oddělené mezerou.",
"Chovají se jako kondenzátor a kolem sebe mají slabé pole.",
"Změna kapacity prozradí místo dotyku.",
"Funguje to s vodivým předmětem, ne s libovolným plastem.",
NULL,
},
},
};
return build_hw_unit_page(&hw_lessons[28], "hw_unit29", "hw_unit29_sub",
slides, G_N_ELEMENTS(slides));
}
GtkWidget *build_hw_unit29_exercise_page(void) {
static const ChoiceQ qs[] = {
{"Co přidává DualShock?",
{"Vibrace gamepadu",
"Optickou mechaniku",
"Slot PCIe",
"Magnetickou pásku"},
4, 0},
{"Co je force feedback?",
{"Jen jiné rozlišení monitoru",
"Vibrace a nárazy u joysticku a volantu",
"Typ paměti DDR3",
"Způsob formátování disku"},
4, 1},
{"Co Kinect sleduje?",
{"Jen stisk jedné klávesy",
"Jen otáčky pevného disku",
"Pohyb celého těla ve 3D, pomocí kamery, hloubky a mikrofonů",
"Jen napětí zdroje"},
4, 2},
{"Čím se musíte dotknout kapacitního displeje?",
{"Vodivým předmětem, například prstem",
"Jen nevodivým plastem",
"Jen speciálním perem bez elektřiny",
"Děrnou páskou"},
4, 0},
};
static const char *hints[] = {
"DualShock = vibrace",
"Force feedback = vibrace a nárazy",
"Kinect: RGB, hloubka, mikrofony, tělo ve 3D",
"Kapacitní vrstva chce vodivý dotyk",
};
return build_hw_mcq_page(28, "hwunit29", "hw_ex29_title", "hw_quiz29_head",
qs, hints, 4);
}