Skip to content

Latest commit

 

History

History
193 lines (151 loc) · 14.3 KB

File metadata and controls

193 lines (151 loc) · 14.3 KB

Как выглядит FreeOS

Документ описывает внешний вид системы: из чего он собран, какими числами задан и где в коде что лежит. Он нужен, чтобы правка одного окна не разошлась с остальными. Снимки того, что из этого получилось, — в docs/SHOTS.md.

Что изменилось и почему

До этой работы стол был нарисован растровым шрифтом 8×8, растянутым в два раза, прямыми углами и сплошными заливками. Это не было стилем — это было отсутствие выбора: другого способа нарисовать букву у системы не существовало. Плата видна на любом снимке: все буквы одной ширины, ступеньки на каждой наклонной, разница между заголовком и подписью — только в цвете.

Теперь есть три вещи, которых не было:

  1. Настоящий шрифт со сглаживанием. Inter для интерфейса, JetBrains Mono для всего, что выравнивается по столбцам. Оба под SIL OFL, оба лежат в tools/font/ttf/.
  2. Сглаженные скругления, градиенты и прозрачность. Скруглённый прямоугольник считается по знаковому расстоянию до фигуры, а не рисуется четвертями окружности по Брезенхэму.
  3. Две темы. Тёмная и светлая, одна геометрия на обе; переключаются правым щелчком по столу и в «Параметрах».

Где что лежит

файл что в нём
tools/font/genfont.py растеризация шрифтов в таблицы; запускается руками
crates/mini-ui/src/typeface.rs начертания, измерение и вывод текста
crates/mini-ui/src/typeface/data.rs сгенерированные таблицы глифов
crates/mini-ui/src/draw.rs примитивы: скругления, градиенты, обводки, тени
crates/mini-ui/src/glyphicon.rs штриховые значки, нарисованные кодом
crates/kernel/src/ui/theme.rs палитра обеих тем и все размеры
crates/kernel/src/ui/paint.rs словарь элементов: кнопки, карточки, строки
crates/kernel/src/ui/window.rs заголовок окна и кнопки управления
crates/kernel/src/ui/compositor.rs обои, тени, срез углов при выводе
crates/kernel/src/ui/panel.rs панель задач и меню запуска
crates/kernel/src/ui/settings.rs окно «Параметры», в том числе выбор темы
crates/kernel/src/ui/files.rs файловый менеджер
crates/kernel/src/ui/icons.rs значки на столе
crates/kernel/src/ui/context.rs меню по правому щелчку

Шрифт

Растеризация идёт на машине разработчика, а не в ядре. Разбор TrueType внутри ядра означал бы парсер бинарного формата, растеризатор кривых Безье и кэш глифов — три подсистемы со своими переполнениями ради задачи, ответ на которую известен заранее. Поэтому глифы растеризованы заранее через FreeType, и в ядро попадает таблица полутоновых картинок: 168 КиБ на все восемнадцать начертаний, по четыре бита на точку.

Шрифт не масштабируется: растровый глиф, растянутый вдвое, — это ровно те ступеньки, ради избавления от которых всё делалось. Вместо этого есть два размерных ряда, и каждый растеризован отдельно. Ряд выбирается по ширине экрана один раз при запуске: от 2560 точек — крупный, иначе обычный.

Начертание выбирается ролью, а не кеглем: кегль зависит от экрана, а назначение — нет.

роль обычный ряд крупный ряд где
Caption 11 15 подписи, мелкий текст
Body 13 18 обычный текст, пункты меню
Label 12 16 подписи значков, вкладки
Title 13 18 заголовок окна, выделенная строка
Strong 14 19 заголовок карточки
Heading 20 27 заголовок раздела
Mono 12 16 пути, числа, терминал
MonoSmall 11 14 технические подписи
MonoCaps 10 13 ЗАГОЛОВКИ СЕКЦИЙ, с разрядкой

Чтобы поменять набор знаков или список начертаний, правят tools/font/genfont.py и запускают:

python tools/font/genfont.py

Файл data.rs руками не правят — следующий запуск генератора всё перепишет.

Палитра

Цвета задаются вместе с прозрачностью, ровно так, как записаны в макете: окно — шестьдесят процентов над обоями, панель — пятьдесят два над окном, линия — семь процентов белого. Это не украшение: именно из-за прозрачности вложенные поверхности отличаются друг от друга на несколько единиц яркости, а границы между ними держатся на однопиксельных линиях, а не на разнице заливок.

Поверхность в памяти прозрачности не хранит, поэтому цвета сводятся к непрозрачным поверх той подложки, на которой окажутся. Слои, лежащие прямо на обоях — панель задач, меню запуска, подсветка значка, — не сводятся, а смешиваются по-настоящему: обои считаются по формуле, и цвет под любой точкой известен.

Тем ровно две. Третья не отвечает ни на один вопрос, на который не отвечают эти две, а стоит столько же, сколько первые две вместе: каждый оттенок надо подобрать заново и проверить на всех поверхностях.

Геометрия

Все числа — в theme.rs, и все умножаются на множитель геометрии (geometry_scale): 1 на обычном экране, 2 от 2560 точек.

элемент значение
скругление окна 14
скругление панели, меню, карточки 12
скругление строки, кнопки, поля 10
скругление мелкой кнопки 9
скругление вкладки 7
заголовок окна 44
кнопки заголовка 30×30, зазор 6, отступ от края 10
панель инструментов 48
строка состояния 30
строка бокового списка 34
боковая колонка 240
панель задач 52, отступ от краёв 14
строка меню запуска 36
плитка значка 46×46, скругление 13
ячейка значка 110×100, зазор 12, отступ сетки 28

Толщина обводки везде одна точка, внутрь границы.

Высота заголовка не зависит от фокуса, хотя в макете у неактивного окна полоса ниже. Иначе при каждом переключении окон область содержимого меняла бы размер, и список файлов пересобирал бы раскладку. Неактивное окно отличается тем, что теряет градиент, светлую кромку и заливку кнопок.

Скругление окон

Поверхность окна прямоугольна, и прозрачности в ней нет. Скруглённый угол — это место, где сквозь окно видны обои, а обои знает только композитор. Поэтому окно рисует себя во всю поверхность, а углы срезаются при выводе, смешиванием с уже нарисованным фоном. Строки, проходящие мимо углов, копируются целиком: срез касается четырёх квадратов со стороной в радиус, то есть восьмисот точек на окно любого размера.

Обои

Считаются, а не хранятся картинкой: картинка размером с экран — четыре мегабайта при куче в шестнадцать. Цвет любой точки — функция от её координат.

Состав: эллиптическое световое пятно у верхнего края, два размытых цветных круга по противоположным углам и редкая сетка точек с шагом 24. Пятна и сетка не украшение — на однородной заливке перетаскиваемое окно кажется стоящим на месте, и глазу нужна опора, чтобы увидеть движение.

У кругов квадратичное затухание, а не настоящее размытие: размытие — это свёртка, то есть проход по окрестности каждой точки, а затухание (1 - d²)² даёт от центра к краю ту же дугу за два умножения.

Смена темы

Тема — глобальный признак в theme.rs. Меняется двумя дорогами:

  • правым щелчком по столу — пункт «Светлая тема» / «Тёмная тема»;
  • в «Параметрах», раздел «Экран», щелчком по образцу.

Пункт в меню стола есть по той же причине, по которой обои везде меняют щелчком по столу: это свойство самого стола, и идти за ним в окно настроек человек не должен. Он же называется тем, что произойдёт, а не тем, что есть сейчас: «Тёмная тема» при включённой тёмной читалась бы как признак, а не как действие.

Из «Параметров» окно сообщает о смене наружу через Window::took_theme_change. В обоих случаях перекрашивает стол Compositor::restyle — целиком и сразу. Оставить хоть один слой в прежней палитре значит показать наполовину перекрашенный стол, который человек примет за поломку.

Обе дороги проверяются прогоном: сценарий mouse переключает тему пунктом меню и снимает стол в обеих палитрах (12-light, 13-dark-again) при открытом окне, панели и значках — то есть ровно то, что ломается, если перекрасить не всех.

Поверхности при этом не пересоздаются: размеры от темы не зависят. Напечатанное в терминале сохраняется — сетка перерисовывается из теневого буфера, который она и так ведёт ради прокрутки.

Имена на экране и имена в журнале

У программы два имени. App::title — латиницей, попадает в журнал; по нему стенд находит окно на экране и сверяет строки прогона. App::caption — по-русски, это то, что видит человек в заголовке, в панели задач и в меню.

Разделение не косметическое: журнал — инструмент разработчика, и сценарии стенда написаны против него; заголовок окна читает человек, и он на его языке.

Правило для правок

Числа геометрии живут в одном месте — theme.rs, — и по ним же стенд наводит указатель (xtask/src/harness/aim.rs). Разойдись они, прицел молча попадает в кнопку соседа, и «свернул вместо закрыл» выглядит как ошибка системы, а не стенда. Меняя размер, меняют оба файла.