Графика и UI (стандартная_библиотека/графика.код)
Отдельная, необязательная библиотека поверх SDL2 — требует установленных
SDL2/SDL2_ttf и флагов --линковать SDL2 --линковать SDL2_ttf --линковать m
при компиляции. Подключается через подключить графика;.
Окно, холст, события
инициализировать(беззнак32(32));
инициализировать_шрифты();
текст окно = создать_окно("Заголовок", целое32(0), целое32(0), целое32(400), целое32(700), беззнак32(0));
текст рендерер = создать_холст(окно, целое32(-1), беззнак32(2));
Кнопка
Цветной прямоугольник со скруглёнными углами и необязательной, автоматически
центрированной текстовой подписью (пустая строка "" — кнопка без текста).
Кнопка моя_кнопка = Кнопка(целое32(20), целое32(15), целое32(160), целое32(50),
беззнак8(70), беззнак8(130), беззнак8(230), "Нажми меня");
моя_кнопка.нарисовать(рендерер, шрифт);
если (моя_кнопка.содержит_точку(х_клика, у_клика)) ... конец
Панель (навбар)
Фон на всю ширину плюс список кнопок внутри — то, что нужно для верхнего или нижнего навбара. Каждая кнопка несёт свои собственные координаты — панель их не вычисляет автоматически, только рисует фон и все кнопки по очереди.
Список из Кнопка кнопки = Список из Кнопка();
кнопки.добавить(кнопка1);
кнопки.добавить(кнопка2);
Панель навбар = Панель(целое32(0), целое32(0), целое32(400), целое32(80),
беззнак8(40), беззнак8(45), беззнак8(60), кнопки);
навбар.нарисовать(рендерер, шрифт);
целое32 индекс = навбар.кнопка_под_точкой(х_клика, у_клика); // -1, если мимо
Якоря — адаптивное расположение под реальный размер экрана
⚠️ Честная, найденная реальной проверкой на Android причина: размер,
переданный в создать_окно, лишь ориентировочный — на Android (и iOS) ОС
всегда даёт приложению полноэкранное окно, запрошенный размер игнорируется.
Жёстко зашитая координата вроде целое32(630) для нижнего навбара была бы
верна только случайно, если экран устройства окажется точно того же
размера, что был запрошен при разработке — на реальном устройстве экран
почти всегда другой.
текст окно = создать_окно("Моё приложение", целое32(0), целое32(0), целое32(400), целое32(700), беззнак32(0));
РазмерЭкрана размер = размер_окна(окно); // РЕАЛЬНЫЙ размер, не запрошенный
Панель нижний_навбар = Панель(целое32(0), целое32(620), целое32(400), целое32(80), ...);
нижний_навбар.закрепить_снизу(размер, целое32(0)); // ровно у низа экрана
нижний_навбар.растянуть_по_ширине(размер); // на всю ширину экрана
закрепить_снизу(размер, отступ) — пересчитывает у панели и **сдвигает
все её кнопки на ту же величину**, сохраняя их взаимное расположение (кнопки
хранят свои координаты абсолютно, не относительно панели — без сдвига
кнопок панель переместилась бы, а кнопки внутри остались бы на старом
месте). Симметричный закрепить_сверху(отступ) — для отступа под системную
область (вырез камеры, статус-бар).
⚠️ Честное, узкое ограничение: растянуть_по_ширине меняет только ширину
фона самой панели — не переставляет и не растягивает кнопки внутри неё
(равномерное распределение N кнопок по новой ширине — отдельная, более
сложная задача, не решена).
Картинки
Только формат .bmp — встроен в сам SDL2, без дополнительных библиотек.
⚠️ Честное, узкое ограничение: PNG/JPG потребовали бы отдельной библиотеки
SDL2_image, которую пришлось бы собирать отдельно. Конвертировать нужные
картинки в .bmp можно любым графическим редактором.
текст поверхность = загрузить_картинку("иконка.bmp");
текст текстура = создать_текстуру(рендерер, поверхность);
нарисовать_картинку_текстурой(рендерер, текстура, целое32(20), целое32(160), целое32(64), целое32(64));
Поле ввода — ПолеВвода
Фон со скруглёнными углами (тот же вид, что и у Кнопка), поверх
которого рисуется введённый текст и мигающий текстовый курсор. Само поле
не подписывается на события самостоятельно — программа сама решает,
когда вызывать добавить_текст/удалить_символ, реагируя на события
ввод_текста/нажатие_клавиши в своём собственном цикле:
ПолеВвода поле = ПолеВвода(целое32(20), целое32(20), целое32(300), целое32(40),
беззнак8(255), беззнак8(255), беззнак8(255), "", да);
// внутри цикла обработки событий:
если (тип_события == целое32(771)) // ввод_текста
текст кусок = прочитать_текст_по_смещению(буфер_события, целое32(12));
поле.добавить_текст(кусок);
конец
если (тип_события == целое32(768)) // нажатие_клавиши
целое32 код = прочитать_целое32(буфер_события, целое32(20));
если (код == целое32(8)) // backspace
поле.удалить_символ();
конец
конец
поле.нарисовать(рендерер, шрифт, кадр); // "кадр" — счётчик кадров, для мигания курсора
удалить_символ() корректно удаляет ровно один символ, а не байт —
важно для кириллицы (2 байта на символ в UTF-8): встроенная функция
байт_текста(текст, индекс) и вспомогательная удалить_последний_символ
находят правильную границу символа перед обрезкой строки.