NewWidgets (временное название) это GUI подсистема на .Net, не зависимая от графического движка и базирующаяся на спрайтах. В качестве тестового примера сделан коннектор к WinForms для отрисовки графики. Планируется поддержка Unity, MonoGame, RunMobile (собственный движок), UIKit и других движков. Также планируется C++ порт.
Для работы с математикой используются System.Numerics.Vectors, но синтаксис совместим с OpenTK, MonoGame и другими реализациями, поэтому достаточно будет изменения заголовков и директив using в соответствующих файлах.
Поддержка для сторонних движков требует реализации интерфейса для спрайтов ISprite и абстрактного класса WindowController. Реализация ISprite икапсулирует платформо-зависимый спрайт и предоставляет интерфейс его использования (положение, вращение, масштабирование, цвет, прозрачность, проверка принадлежности точки спрайту). Все трансформации выполняются через вспомогательный класс Transform, который поддерживает восходящую иерархию (содержит указатель на родительский Transform). Реализация WindowControllerBase должна содержать вспомогательные функции системы - логирование, воспроизведение звука, создание спрайта, информацию о размере экрана. Примеры реализации классов для WinForms можно увидеть в каталоке WinForms и файлах WinFromsSprite и WinFormsController.
Для использования библиотеки надо создать экземпляр соответствующего WindowController, зарегистрировать в нем используемые спрайты, а также реализовать обработку событий с вызовом следующих методов WindowController:
Key(int code, bool up, char character)
- действие клавиатуры. Поддерживаются как специальные клавиши, так и букво-символьные, отдельная обработка для нажатия и отпускания;Touch(float x, float y, bool press, bool unpress, int pointer)
- действие указателя мыши или тачскрина (MouseUp/MouseDown/MouseMove и аналогичные события для тачскрина);Zoom(float x, float y, float value)
- действие масштабирования или прокрутки;Draw()
- отрисовка;Update()
- обновление анимаций и внутренних состояний (есть смысл вызывать с таймером на 60fps);
В примере WinFormsSample в классе TestForm есть пример реализации обработки этих событий. В случае WinForms во время Update() вызывается действие Invalidate() для графической области и уже ее событие OnPaint() вызывает операцию Draw(). В случае OpenGL или Direct3D имеет смысл вызывать в цикле рендера в начале Update(), потом Draw() и затем glFlush()/SwapBuffers()/ID3D11DeviceContext::Flush().
Пока нет визуального редактора для NewWidgets, разработка подразумевает создание контролов в коде:
WidgetPanel panel = new WidgetPanel(WidgetManager.DefaultWindowStyle);
panel.Size = new Vector2(600, 560);
panel.Scale = WindowControllerBase.Instance.ScreenScale;
panel.Position = this.Size / 2 - panel.Size * panel.Scale / 2;
this.AddChild(panel);
WidgetLabel loginLabel = new WidgetLabel();
loginLabel.Text = ResourceLoader.Instance.GetString("login_login");
loginLabel.Position = new Vector2(50, 160);
loginLabel.FontSize = WidgetManager.DefaultLabelStyle.FontSize * 1.25f;
panel.AddChild(loginLabel);
Это может быть не очень удобно, но в целом не должно составлять трудности для опытного программиста.
В библиотеке используется три слоя абстракции, каждый из которых позволяет создавать интерфейс пользователя различной сложности для различных задач.
Базовый класс спрайтов содержит все необходимое для создания самого простого интерфейса: в нем есть возможность отображать спрайтеы на экране, делать вложенность и группировку за счет использования Transform и их иерархии, проверять совпало ли нажатие клавиши мыши с положением спрайта с методом HitTest(). Также спрайт может содержать несколько кадров, что позволяет делать анимации, а за счет изменения параметров Alpha и Color возможны эффекты с прозрачностью и цветами.
Для организованной работы с интерфейсом существуют классы WindowObject и Window с коллекцией WindowObjectArray. Они поддерживают полноценную (нисходящую) иерархию, создание контейнеров, обработку события OnTouch и пр. С помощью данных объектов можно реализовывать интерфейсы на основе изображений (класс ImageObject), собственные компоненты, использовать текстовое отображение (класс LabelObject). Объекты ImageObject и LabelObject базируются на спрайтах. В случае LabelObject необходим ISprite, у которого разные кадры это разные символы шрифта.
Набор компонентов Widgets позволяет работать на высоком уровне абстракции, создавая привычные кнопки, чекбоксы, панели и области прокрутки. Все компоненты наследуются от WindowObject, позволяют организовывать произвольную структуру компонентов или портировать интерфейсы из других систем. Также поддерживается собственная система стилей с наследованием, которая позволяет описывать параметры компонентов в виде XML:
<style name="text_button">
<back_style>None</back_style>
<font>default</font>
<font_size>1.0</font_size>
<text_color>0xcceeff</text_color>
<padding>4;2;4;2</padding>
<hovered_style>text_button_hovered</hovered_style>
</style>
<style name="text_button_hovered" parent="default_button_hovered">
<back_style>None</back_style>
<text_color>#ffffff</text_color>
</style>
Для управления стилями, а также глобальных операций (отображение Tooltip поверх всех окон) используется класс WindgetManager. Отдельно можно отметить класс WidgetText, поддерживающий многострочный вывод текста, с переносом строк (без символа переноса), цветовое форматирование, вставку изображений в текст.
На данный момент у проекта есть следующие проблемы, которые планируется решить в ближайшее время:
- отсутствие документации и примеров;
- отсутствие тестов;
- минимальное количество документации в коде;
- не полная работоспособность компонентов, отсутствие специфичных контролов (Radio Button, List, ComboBox, Tab Control, etc.);
- архитектурные недочеты;
- почти полностью отсутствует работа с фокусом;
- проблемы в наследовании стилей и не полное покрытие ими свойств компонентов;
- поддержка нативных буферов обмена и выделения в целом;
- прочие не идентифицированные проблемы;
- отсутствие коммьюнити и живых проектов с NewWidgets;
- дурацкое название;
Долгосрочные задачи:
- коннекторы для Unity, MonoGame;
- коннекторы для нативных интерфейсов в iOS (UIKit) и Android;
- порт на C++;
- сериализация интерфейса в текстовый формат;
- WYSIWYG редактор;
- мировое господство;