2017-04-02 04:09:03 +03:00

50 KiB
Raw Blame History

О библиотеке

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

Пусть синтаксис и обилие текста вас не пугает, в конце файла документации вы сможете найти несколько наглядных иллюстрированных примеров.

Установка

Зависимость Функционал
advancedLua Дополнение стандартных библиотек Lua особыми функциями, такими как быстрая сериализация таблиц, перенос строк, округление чисел и т.д.
colorlib Низкоуровневая библиотека для обработки цветовых каналов в бинарном режиме
image Работа со сжатым форматом изображений OCIF и различные операции по обработке и трансформированию результирующих изображений
doubleBuffering Низкоуровневая библиотека тройной (несмотря на название) буферизации для быстрой отрисовки графики с поддержкой полу-пиксельных методов и шрифта Брайля
syntax Подсветка lua-синтаксиса для виджета CodeView
palette Библиотека-окно для работы с цветом в режиме HSV и выборе конкретных цветовых данных для виджета ColorSelector

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

pastebin run ryhyXUKZ

Методы для создания контейнеров

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

GUI.container( x, y, width, height ): table container

Тип Аргумент Описание
int x Координата объекта по оси x
int y Координата объекта по оси y
int width Ширина объекта
int height Высота объекта

Как было сказано выше, каждый контейнер - это объект-группировщик для других объектов, перечисленных ниже. К примеру, при изменении позиции контейнера на экране все его дочерние элементы будут также смещены на соответствующие координаты. Контейнер также содержит все основные методы по добавлению дочерних элементов (виджетов) и работе с ними.

Все дочерние элементы контейнера имеют свою localPosition в контейнере (к примеру, {x = 4, y = 2}), при добавлении нового элемента в контейнер используются именно локальные координаты. Для получения глобальных (экранных) координат дочернего элемента необходимо обращаться к element.x и element.y. Глобальная (экранная) позиция дочерних элементов рассчитывается при каждой отрисовке содержимого контейнера. Таким образом, изменяя глобальные координаты дочернего элемента вручную, вы, в сущности, ничего не добьетесь.

Для добавления в контейнер любого существующего виджета (см. ниже) используйте синтаксическую конструкцию :addОбъект(...). К примеру, для добавления кнопки используйте :addButton, а для добавления изображения :addImage. Кроме того, в контейнер можно добавлять другие контейнеры, а в добавленные - еще одни, создавая сложные иерархические цепочки и группируя дочерние объекты по своему усмотрению. Ниже перечислены дополнительные методы контейнера, способные оказаться полезными

Тип свойства Свойство объекта Описание
function :addChild( table child ): table child Добавить произвольный объект в контейнер в качестве дочернего - таким образом вы способны создавать собственные виджеты с индивидуальными особенностями. Уточняю, что у добавляемого объекта обязательно должен иметься метод :draw (подробнее см. ниже). При добавлении объекта его глобальные координаты становятся локальными
function :deleteChildren() Удалить все дочерние элементы контейнера
function :getClickedObject(int x, int y): table object or nil Получить объект по указанным координатам, используя иерархический порядок расположения элементов. То есть при наличии двух объектов на одних и тех же координатах будет выдан тот, что находится ближе к глазам пользователя. Вложенные контейнеры для данного метода являются невидимыми
function :draw(): table container Рекурсивная отрисовка содержимого контейнера в порядке очереди его дочерних элементов. Обращаю внимание на то, что данный метод осуществляет отрисовку только в экранный буфер. Для отображения изменений на экране необходимо использовать метод библиотеки тройного буфера .draw()

GUI.window( x, y, width, height ): table window

Тип Аргумент Описание
int x Координата объекта по оси x
int y Координата объекта по оси y
int width Ширина объекта
int height Высота объекта

Создание объекта типа "окно" для дальнейшей работы. Каждое окно - это наследник объекта объекта типа "контейнер" (см. выше), содержащий дополнительные методы обработки системных событий и возврата данных окна.

Тип свойства Свойство объекта Описание
function :handleEvents([int timeout]) Запустить обработчик событий и ожидать действий со стороны пользователя. К примеру, при нажатии на кнопку на экране система автоматически определит "нажатый" элемент, осуществит нажатие кнопки и отрисовку. Опциональный аргумент timeout эквивалентен аналогичному аргументу в computer.pullSignal(timeout)
function .onTouch(table eventData) Метод, вызывающийся при каждом событии типа touch
function .onDrag(table eventData) Метод, вызывающийся при каждом событии типа drag
function .onScroll(table eventData) Метод, вызывающийся при каждом событии типа scroll
function .onKeyDown(table eventData) Метод, вызывающийся при каждом событии типа key_down
function .onAnyEvent(table eventData) Метод, вызывающийся всегда, при любом событии. Полезен для дальнейшей обработки разработчиком
function .onDrawStarted() Метод, вызывающийся до начала отрисовки содержимого окна в экранный буфер
function .onDrawFinished() Метод, вызывающийся после отрисовки содержимого окна в экранный буфер
function :returnData(...) Закрыть окно и вернуть множество данных любого типа
function :close() Закрыть окно без возврата данных

Методы для создания виджетов

После понимания концепции контейнеров можно с легкостью приступить к добавлению виджетов в созданное окно или контейнер. Каждый виджет - это наследник объекта типа GUI.object

GUI.object( x, y, width, height ): table object

Тип Аргумент Описание
int x Координата объекта по оси x
int y Координата объекта по оси y
int width Ширина объекта
int height Высота объекта

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

Тип свойства Свойство Описание
function :draw() Обязательный метод, вызываемый для отрисовки виджета на экране. Он может быть определен пользователем любым удобным для него образом. Повторюсь, что данный метод осуществляет отрисовку только в экранный буфер, а не на экран.
function :isClicked( int x, int y ): boolean isClicked Метод для проверки валидности клика на объект. Используется родительскими методами контейнеров и удобен для ручной проверки пересечения указанных координат с расположением объекта на экране
boolean .isHidden Является ли объект скрытым. Если объект скрыт, от его отрисовка и анализ системных событий игнорируются

После добавления виджета-объекта в контейнер с помощью метода :addChild он приобретает дополнительные свойства для удобства использования:

Тип свойства Свойство Описание
table .parent Указатель на таблицу-контейнер родителя этого виджета
table .localPosition Таблица вида {x = int, y = int} с локальными координатами виджета в родительском контейнере
function :indexOf() Получить индекс данного виджета в родительском контейнере
function :moveForward() Передвинуть виджет "назад" в иерархии виджетов контейнера
function :moveBackward() Передвинуть виджет "вперед" в иерархии виджетов контейнера
function :moveToFront() Передвинуть виджет в конец иерархии виджетов контейнера
function :moveToBack() Передвинуть виджет в начало иерархии виджетов контейнера
function :getFirstParent() Получить первый родительский контейнер для рассматриваемой системы родительских контейнеров. К примеру, при существовании множества вложенных контейнеров метод вернет первый и "главный" из них

Ниже перечислены виджеты, уже созданные мной на основе описанных выше инструкций. При желании вы можете сделать абсолютно аналогичные или гораздо более технически продвинутые виджеты без каких-либо затруднений.

GUI.button( x, y, width, height, buttonColor, textColor, buttonPressedColor, textPressedColor, text ): table button

Тип Аргумент Описание
int x Координата объекта по оси x
int y Координата объекта по оси y
int width Ширина объекта
int height Высота объекта
int buttonColor Цвет кнопки
int textColor Цвет текса
int buttonPressedColor Цвет кнопки при нажатии
int textPressedColor Цвет текста при нажатии
string text Текст на кнопке

Создать объект типа "кнопка". Каждая кнопка имеет два состояния (isPressed = true/false), автоматически переключаемые оконным методом handleEvents. Для назначения какого-либо действия кнопке после ее нажатия создайте для нее метод .onTouch().

Имеется также три альтернативных варианта кнопки:

  • GUI.adaptiveButton(...), отличающаяся тем, что вместо width и height использует отступ в пикселях со всех сторон от текста. Она удобна для автоматического расчета размера кнопки без получения размера текста.
  • GUI.framedButton(...), эквивалентный GUI.button за исключением того, что отрисовывается в рамочном режиме.
  • GUI.adaptiveFramedButton(...), отрисовывающийся по такому же методу, что и GUI.framedButton и рассчитывающийся по аналогии с GUI.adaptiveButton.
Тип свойства Свойство объекта Описание
function .onTouch( table eventData ) Метод, вызываемый после нажатия кнопки в обработчике событий
function :press() Изменить состояние кнопки на "нажатое"
function :release() Изменить состояние кнопки на "отжатое"
function :pressAndRelease( float time ) Нажать и отжать кнопку в течение указанного временного периода. Примечание: этот метод использует отрисовку содержимого двойного буфера

GUI.panel( x, y, width, height, color, transparency ): table panel

Тип Аргумент Описание
int x Координата объекта по оси x
int y Координата объекта по оси y
int width Ширина объекта
int height Высота объекта
int color Цвет панели
[byte transparency] Опциональная прозрачность панели

Создать объект типа "панель", представляющий собой закрашенный прямоугольник с определенной опциональной прозрачностью. В большинстве случаев служит декоративным элементом, однако способен обрабатывать индивидуальный метод .onTouch().

Тип свойства Свойство объекта Описание
function .onTouch( table eventData ) Метод, вызываемый после нажатия на панель в обработчике событий

GUI.label( x, y, width, height, textColor, text ): table label

Тип Аргумент Описание
int x Координата объекта по оси x
int y Координата объекта по оси y
int width Ширина объекта
int height Высота объекта
int textColor Цвет текста лейбла
string text Текст лейбла

Создать объект типа "лейбл", предназначенный для отображения текстовой информации в различных вариациях расположения.

Тип свойства Свойство объекта Описание
function .onTouch( table eventData ) Метод, вызываемый после нажатия на лейбл в обработчике событий
function :setAlignment( enum GUI.alignment.vertical, enum GUI.alignment.horizontal ) Выбрать вариант отображения текста относительно границ лейбла

GUI.inputTextBox( x, y, width, height, backgroundColor, textColor, backgroundFocusedColor, textFocusedColor, text, [placeholderText, eraseTextOnFocus, textMask, highlightLuaSyntax, autocompleteVariables] ): table inputTextBox

Тип Аргумент Описание
int x Координата объекта по оси x
int y Координата объекта по оси y
int width Ширина объекта
int height Высота объекта
int backgroundColor Цвет поля ввода
int textColor Цвет текста поля ввода
int backgroundFocusedColor Цвет поля ввода в состоянии focused
int textFocusedColor Цвет текста поля ввода в состоянии focused
string text Введенный на момент создания поля текст
[string placeholderText] Текст, появляющийся при условии, что text == nil
[boolean eraseTextOnFocus] Необходимо ли удалять текст при активации ввода
[string textMask] Символ-маска для вводимого текста. Полезно для создания поля ввода пароля
[boolean highlightLuaSyntax] Режим подсветки синтаксиса Lua для вводимой строки. Цвет текста при этом игнорируется
[boolean autocompleteVariables] Режим автодополнения текстовых данных на основе поиска таковых переменных в оперативной памяти

Создать объект типа "поле ввода текста", предназначенный для ввода и анализа текстовых данных с клавиатуры. Объект универсален и подходит как для создания простых форм для ввода логина/пароля, так и для сложных структур наподобие командных консолей. К примеру, окно палитры выше целиком и полностью основано на использовании этого объекта.

Тип свойства Свойство объекта Описание
function .validator( string text ) Метод, вызывающийся после окончания ввода текста в поле. Если возвращает true, то текст в текстовом поле меняется на введенный, в противном случае введенные данные игнорируются. К примеру, в данном методе удобно проверять, является ли введенная текстовая информация числом через tonumber()
function .onInputFinished( string text, table eventData ) Метод, вызываемый после ввода данных в обработчике событий

GUI.horizontalSlider( x, y, width, primaryColor, secondaryColor, pipeColor, valueColor, minimumValue, maximumValue, value, [showCornerValues, currentValuePrefix, currentValuePostfix] ): table horizontalSlider

Тип Аргумент Описание
int x Координата объекта по оси x
int y Координата объекта по оси y
int width Ширина объекта
int primaryColor Основной цвет слайдера
int secondaryColor Вторичный цвет слайдера
int pipeColor Цвет "пимпочки" слайдера
int valueColor Цвет текста значений слайдера
float minimumValue Минимальное значение слайдера
float maximumValue Максимальное значение слайдера
float value Значение слайдера
[bool showCornerValues] Показывать ли пиковые значения слайдера по сторонам от него
[string currentValuePrefix] Префикс для значения слайдера
[string currentValuePostfix] Постфикс для значения слайдера

Создать объект типа "горизонтальный слайдер", предназначенный для манипуляцией числовыми данными. Значение слайдера всегда будет варьироваться в диапазоне от минимального до максимального значений. Опционально можно указать значение поля слайдер.roundValues = true, если необходимо округлять изменяющееся число.

Тип свойства Свойство объекта Описание
function .onValueChanged( float value, table eventData ) Метод, вызывающийся после изменения значения слайдера

GUI.switch( x, y, width, primaryColor, secondaryColor, pipeColor, state ): table switch

Тип Аргумент Описание
int x Координата объекта по оси x
int y Координата объекта по оси y
int width Ширина объекта
int primaryColor Основной цвет переключателя
int secondaryColor Вторичный цвет переключателя
int pipeColor Цвет "пимпочки" переключателя
boolean state Состояние переключателя

Создать объект типа "переключатель", для определения истинности или ложности того или иного события. При клике на объект меняет состояние на противоположное.

Тип свойства Свойство объекта Описание
function .onStateChanged( boolean state, table eventData ) Метод, вызывающийся после изменения состояния переключателя

GUI.colorSelector( x, y, width, height, color, text ): table colorSelector

Тип Аргумент Описание
int x Координата объекта по оси x
int y Координата объекта по оси y
int width Ширина объекта
int height Высота объекта
int color Текущий цвет селектора
string text] Текст селектора

Создать объект типа "селектор цвета", представляющий собой аналог кнопки, позволяющей выбрать цвет при помощи удобной палитры.

Тип свойства Свойство объекта Описание
function .onTouch( table eventData ) Метод, вызываемый после нажатия на селектор цвета в обработчике событий

GUI.comboBox( x, y, width, height, backgroundColor, textColor, arrowBackgroundColor, arrowTextColor, items ): table comboBox

Тип Аргумент Описание
int x Координата объекта по оси x
int y Координата объекта по оси y
int width Ширина объекта
int backgroundColor Цвет фона комбо-бокса
int textColor Цвет текста комбо-бокса
int arrowBackgroundColor Цвет фона стрелки комбо-бокса
int arrowTextColor Цвет текста стрелки комбо-бокса

Создать объект типа "комбо-бокс", позволяющий выбирать объекты из множества перечисленных вариантов.

Тип свойства Свойство объекта Описание
function :addItem( string text, boolean disabled, string shortcut, int color ) Добавить в комбо-бокс элемент с указанными параметрами
function :addSeparator() Добавить визуальный в комбо-бокс разделитель
function .onItemSelected( table item, table eventData ) Метод, вызывающийся после выборе какого-либо элемента комбо-бокса

GUI.menu( x, y, width, backgroundColor, textColor, backgroundPressedColor, textPressedColor, backgroundTransparency ): table menu

Тип Аргумент Описание
int x Координата объекта по оси x
int y Координата объекта по оси y
int width Ширина объекта
int backgroundColor Цвет фона меню
int textColor Цвет текста меню
int backgroundPressedColor Цвет фона меню при нажатии на элемент
int textPressedColor Цвет текста меню при нажатии на элемент
int backgroundTransparency Прозрачность фона меню

Создать объект типа "горизонтальное меню", позволяющий выбирать объекты из множества перечисленных вариантов. По большей части применяется в структурах типа "Файл - Редактировать - Вид - Помощь" и подобных.

Тип свойства Свойство объекта Описание
function :addItem( string text, int color ) Добавить в меню элемент с указанными параметрами
function .onItemSelected( table item, table eventData ) Метод, вызывающийся после выборе какого-либо элемента комбо-бокса

GUI.image( x, y, loadedImage ): table image

Тип Аргумент Описание
int x Координата объекта по оси x
int y Координата объекта по оси y
table loadedImage Изображение, загруженное методом image.load()

Создать объект типа "изображение", представляющий из себя аналог объекта panel с тем лишь исключением, что вместо статичного цвета используется загруженное изображение.

Тип свойства Свойство объекта Описание
function .onTouch( table eventData ) Метод, вызываемый после нажатия на изображение в обработчике событий

GUI.progressBar( x, y, width, primaryColor, secondaryColor, valueColor, value, thin, showValue, valuePrefix, valuePostfix ): table progressBar

Тип Аргумент Описание
int x Координата объекта по оси x
int y Координата объекта по оси y
int width Ширина объекта
int primaryColor Основной цвет шкалы прогресса
int secondaryColor Вторичный цвет шкалы прогресса
int valueColor Цвет текста значений шкалы прогресса
float value Значение шкалы прогресса
[bool thin] Активировать ли режим отрисовки "тонкого" объекта
[bool showValue] Показывать ли значение шкалы прогресса
[string valuePrefix] Префикс для значения шкалы прогресса
[string valuePostfix] Постфикс для значения шкалы прогресса

Создать объект типа "шкала прогресса", значение которой меняется от 0 до 100.

GUI.textBox(x, y, width, height, backgroundColor, textColor, lines, currentLine, horizontalOffset, verticalOffset): table textBox

Тип Аргумент Описание
int x Координата объекта по оси x
int y Координата объекта по оси y
int width Ширина объекта
int height Высота объекта
int or nil backgroundColor Цвет фона текстбокса. При значении nil фон не рисуется
int textColor Цвет текста текстбокса
table lines Таблица отображаемых строк текстбокса
int currentLine Текущая строка текстбокса, с которой осуществляется отображение текста
int horizontalOffset Отступ отображения текста от левого и правого краев текстбокса
int verticalOffset Отступ отображения текста от верхнего и нижнего краев текстбокса

Создать объект типа "текстбокс", предназначенный для отображения большого количества текстовых данных в небольшом контейнере с полосами прокрутки. При использовании колесика мыши и активации события scroll содержимое текстбокса будет автоматически "скроллиться" в нужном направлении.

Тип свойства Свойство объекта Описание
function .onTouch( table eventData ) Метод, вызываемый после нажатия на текстбокс в обработчике событий

GUI.treeView( x, y, width, height, backgroundColor, textColor, selectionBackgroundColor, selectionTextColor, arrowColor, scrollBarPrimaryColor, scrollBarSecondaryColor, workPath ): table treeView

Тип Аргумент Описание
int x Координата объекта по оси x
int y Координата объекта по оси y
int width Ширина объекта
int height Высота объекта
int or nil backgroundColor Цвет фона TreeView
int textColor Цвет текста TreeView
int selectionBackgroundColor Цвет выделения фона TreeView
int selectionTextColor Цвет выделения текста TreeView
int arrowColor Цвет стрелки директорий TreeView
int scrollBarPrimaryColor Первичный цвет скроллбара TreeView
int scrollBarSecondaryColor Вторичный цвет скроллбара TreeView
string workPath Стартовая директория TreeView

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

Тип свойства Свойство объекта Описание
function .onFileSelected( int currentFile ) Метод, вызываемый после выбора файла в TreeView

GUI.codeView( x, y, width, height, lines, fromSymbol, fromLine, maximumLineLength, selections, highlights, highlightLuaSyntax, indentationWidth ): table codeView

Тип Аргумент Описание
int x Координата объекта по оси x
int y Координата объекта по оси y
int width Ширина объекта
int height Высота объекта
table lines Таблица с отображаемыми строками
int fromSymbol С какого символа начинать отображение кода
int fromLine С какой строки начинать отображение кода
int maximumLineLength Максимальная длина строки из имеющихся строк
table selections Таблица вида { {from = {line = int line, symbol = int symbol}, to = {line = int line, symbol = int symbol}}, ... }, позволяющая осуществлять выделение кода таким образом, как если бы пользователь выделил бы его мышью
table highlights Таблица вида { [int lineIndex] = int color, ... }, позволяющая подсвечивать указанные строки указанными цветом
boolean highlightLuaSyntax Подсвечивать ли синтаксис Lua
int indentationWidth Ширина индентации кода

Создать объект типа "CodeView", предназначенный для наглядного отображения Lua-кода с номерами строк, подсветкой синтаксиса, выделениям и скроллбарами.

GUI.chart( x, y, width, height, axisColor, axisValueColor, axisHelpersColor, chartColor, xAxisValueInterval, yAxisValueInterval, xAxisPostfix, yAxisPostfix, fillChartArea, values ): table chart

Тип Аргумент Описание
int x Координата объекта по оси x
int y Координата объекта по оси y
int width Ширина объекта
int height Высота объекта
int axisColor Цвет координатных осей
int axisValueColor Цвет числовых значений координатных осей
int axisHelpersColor Цвет вспомогательных линий координатных осей
int chartColor Цвет графика
float xAxisValueInterval Интервал от 0 до 1, с которым будут итерироваться значения графика на конкретной оси
float yAxisValueInterval Интервал от 0 до 1, с которым будут итерироваться значения графика на конкретной оси
string xAxisPostfix Текстовый постфикс для значений графика конкретной оси
string yAxisPostfix Текстовый постфикс для значений графика конкретной оси
boolean fillChartArea Необходимо ли закрашивать область графика или же рисовать его линией
table values Таблица вида {{x = float x, y = float y}, ...} со значениями графика

Создать объект типа "график", предназначенный для отображения статистической информации в виде графика с подписью значений осей.

Практический пример #1

В качестве стартового примера возьмем простейшую задачу: расположим на экране 5 кнопок по вертикали и заставим их показывать окно с порядковым номером этой кнопки при нажатии на нее. Напишем следующий код:

-- Подключаем необходимые библиотеки
local buffer = require("doubleBuffering")
local GUI = require("GUI")

-- Создаем полноэкранное окно
local window = GUI.fullScreenWindow()
-- Добавляем на окно темно-серую панель по всей его ширине и высоте
window:addPanel(1, 1, window.width, window.height, 0x2D2D2D)

-- Создаем 5 объектов-кнопок, располагаемых все ниже и ниже
local y = 2
for i = 1, 5 do
	-- При нажатии на конкретную кнопку будет вызван указанный метод .onTouch()
	window:addButton(2, y, 30, 3, 0xEEEEEE, 0x2D2D2D, 0x666666, 0xEEEEEE, "This is button " .. i).onTouch = function()
		GUI.error("You've pressed button " .. i .. "!")
	end
	y = y + 4
end

-- Отрисовываем содержимое окно
window:draw()
-- Отрисовываем содержимое экранного буфера
buffer.draw()
-- Активируем режим обработки событий
window:handleEvents()

При нажатии на любую из созданных кнопок будет показываться дебаг-окно с информацией, указанной в методе .onTouch:

enter image description here

enter image description here

Практический пример #2

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

local buffer = require("doubleBuffering")
local GUI = require("GUI")

local window = GUI.fullScreenWindow()
local panel = window:addPanel(1, 1, window.width, window.height, 0x2D2D2D)

-- Добавляем селектор цвета
local colorSelector = window:addColorSelector(2, 2, 30, 3, 0xFFDB40, "Choose color")
-- Создаем метод .onTouch, в котором цвет фона станет эквивалентным выбранному цвету селектора, а цвет селектора будет инвертироваться на противоположный
colorSelector.onTouch = function()
	panel.colors.background = colorSelector.color
	colorSelector.color = 0xFFFFFF - colorSelector.color
	-- После обработки цветов вызываем методы отрисовки окна и экранного буфера
	window:draw()
	buffer.draw()
end

window:draw()
buffer.draw()
window:handleEvents()

При нажатии на цветовой селектор цвет фона изменится на выбранный, а цвет селектора на инвертированный:

enter image description here

enter image description here

enter image description here

Практический пример #3

Для демонстрации возможностей библиотеки предлагаю создать кастомный виджет с нуля. К примеру, накодить панель для рисования на ней произвольным цветом по аналогии со школьной доской.

local buffer = require("doubleBuffering")
local GUI = require("GUI")

---------------------------------------------------------------------

-- Создаем полноэкранное окно
local window = GUI.fullScreenWindow()

-- Создаем метод, возвращающий кастомный виджет
local function createMyWidget(x, y, width, height, backgroundColor, paintColor)
	-- Наследуемся от GUI.object, дополняем его параметрами цветов и пиксельной карты
	local object = GUI.object(x, y, width, height)
	object.colors = {background = backgroundColor, paint = paintColor}
	object.pixels = {}
	
	-- Реализуем метод отрисовки виджета
	object.draw = function(object)
		-- Рисуем подложку цветом фона виджета
		buffer.square(object.x, object.y, object.width, object.height, object.colors.background, 0x0, " ")
		
		-- Перебираем пиксельную карту, отрисовывая соответствующие пиксели в экранный буфер
		for y = 1, object.height do
			for x = 1, object.width do
				if object.pixels[y] and object.pixels[y][x] then
					buffer.set(object.x + x - 1, object.y + y - 1, object.colors.paint, 0x0, " ")
				end
			end
		end
	end

	-- Реализуем метод клика на объект, устанавливая или удаляя пиксели в зависимости от кнопки мыши
	object.onTouch = function(eventData)
		local x, y = eventData[3] - object.x + 1, eventData[4] - object.y + 1
		object.pixels[y] = object.pixels[y] or {}
		object.pixels[y][x] = eventData[5] == 0 and true or nil
		window:draw()
		buffer.draw()
	end
	-- Дублируем метод onTouch, чтобы рисование было непрерывным
	object.onDrag = object.onTouch

	return object
end

---------------------------------------------------------------------

-- Добавляем темно-серую панель на окно
window:addPanel(1, 1, window.width, window.height, 0x2D2D2D)
-- Создаем экземпляр виджета-рисовалки и добавляем его на окно
window:addChild(createMyWidget(2, 2, 32, 16, 0x3C3C3C, 0xEEEEEEE))

window:draw()
buffer.draw(true)
window:handleEvents()

При нажатии на левую кнопку мыши в нашем виджете устанавливается пиксель указанного цвета, а на правую - удаляется.

enter image description here

Для разнообразия модифицируем код, создав несколько виджетов с рандомными цветами:

local x = 2
for i = 1, 5 do
	window:addChild(createMyWidget(x, 2, 32, 16, math.random(0x0, 0xFFFFFF), math.random(0x0, 0xFFFFFF)))
	x = x + 34
end

В результате получаем 5 индивидуальных экземпляров виджета рисования:

enter image description here