#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); }