Igor Timofeev ff8257f94d Ну ты и жирный, ебать! Вот это обновка
Крч, формат пикч новый, парочка багфиксов, формат .app чутка изменен, и
ваще прям мяу. Но багов может быть дохуя
2017-04-22 01:34:18 +03:00

71 KiB
Raw Blame History

О библиотеке

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

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

Imgur

Imgur

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

Установка

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

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

pastebin run ryhyXUKZ

Standalone-методы

Библиотека имеет несколько полезных независимых методов, упрощающих разработку программ. К таковым относятся, к примеру, контекстное меню и информационное alert-окно.

GUI.contextMenu( x, y ): table contextMenu

Тип Аргумент Описание
int x Координата меню по оси x
int y Координата меню по оси y

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

Тип свойства Свойство Описание
function :addItem( string text, boolean disabled, string shortcut, int color ) Добавить в контекстное меню элемент с указанными параметрами. При параметре disabled элемент не будет реагировать на клики мышью. Каждый элемент может иметь собственный callback-метод .onTouch для последующей обработки данных
function :addSeparator() Добавить в контекстное меню визуальный разделитель
table .items Таблица элементов контекстного меню

Пример реализации контекстного меню:

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

buffer.clear(0x0)
local contextMenu = GUI.contextMenu(2, 2)
contextMenu:addItem("New")
contextMenu:addItem("Open").onTouch = function()
	-- Do something to open file or whatever
end
contextMenu:addSeparator()
contextMenu:addItem("Save", true)
contextMenu:addItem("Save as")
contextMenu:show()

Результат:

enter image description here

GUI.error( text, [parameters] )

Тип Аргумент Описание
string text Текст информационного окна
table parameters Опциональные параметры информационного окна. К примеру, {title = {text = "Alert", color = 0xFFDB40}, backgroundColor = 0x2D2D2D} добавит окну желтый заголовок и сделает фон окна темно-серым

Показать отладочное окно с текстовой информацией. Слишком длинная строка будет автоматически перенесена. Для закрытия окна необходимо использовать клавишу return или нажать на кнопку "ОК".

Пример реализации:

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

buffer.clear(0x0)
GUI.error("Something went wrong here, my friend", {title = {text = "Alert", color = 0xFFDB40}})

Результат:

enter image description here

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

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

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. Глобальная (экранная) позиция дочерних элементов рассчитывается при каждой отрисовке содержимого контейнера. Таким образом, изменяя глобальные координаты дочернего элемента вручную, вы, в сущности, ничего не добьётесь.

Наглядно система иерархии и позиционирования контейнеров и дочерних элементов представлена на следущем изображении:

enter image description here

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

Тип свойства Свойство Описание
function :add<Объект>( table object ): table object Добавить в контейнер один из объектов-шаблонов, перечисленных ниже. Как уже было сказано, для добавления, к примеру, объекта GUI.chart используйте метод :addChart(...)
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 Высота объекта

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

Некоторые методы обработки событий могут иметь аргумент eventData, представляющий собой нумерически индексированную таблицу с данными метода computer.pullSignal. Подробнее об ивентах (сигналах, событиях) можно прочесть по ссылке.

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

GUI.fullScreenWindow( ): table window

Создать объект окна на основе текущего разрешения экранного буфера.

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

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

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

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

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

Тип свойства Свойство Описание
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.panel( x, y, width, height, color, [transparency] ): table panel

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

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

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

Пример реализации панели:

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

local window = GUI.fullScreenWindow()

local panel1 = window:addPanel(1, 1, window.width, math.floor(window.height / 2), 0x444444)
window:addPanel(1, panel1.height, window.width, window.height - panel1.height + 1, 0x880000)

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

Результат:

enter image description here

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.
Тип свойства Свойство Описание
callback-function .onTouch( table eventData ) Метод, вызываемый после нажатия кнопки в обработчике событий
function :press() Изменить состояние кнопки на "нажатое"
function :release() Изменить состояние кнопки на "отжатое"
function :pressAndRelease( float time ) Нажать и отжать кнопку в течение указанного временного периода. Примечание: этот метод использует отрисовку содержимого тройного буфера

Пример реализации кнопки:

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

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

window:addButton(2, 2, 30, 3, 0xFFFFFF, 0x000000, 0xAAAAAA, 0x000000, "Button text").onTouch = function()
	-- Do something on button click
end

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

Результат:

enter image description here

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

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

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

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

Пример реализации лейбла:

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

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

window:addLabel(2, 2, window.width, window.height, 0xFFFFFF, "Centered text"):setAlignment(GUI.alignment.horizontal.center, GUI.alignment.vertical.center)

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

Результат:

enter image description here

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] Режим автодополнения текстовых данных на основе поиска таковых переменных в оперативной памяти

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

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

Пример реализации поля ввода:

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

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

local inputTextBox = window:addInputTextBox(2, 2, 32, 3, 0xEEEEEE, 0x555555, 0xEEEEEE, 0x2D2D2D, nil, "Type number here", true, nil, nil, nil)
inputTextBox.validator = function(text)
	if tonumber(text) then return true end
end
inputTextBox.onInputFinished = function()
	-- Do something when input finished
end

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

Результат:

enter image description here

enter image description here

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, если необходимо округлять изменяющееся число.

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

Пример реализации слайдера:

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

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

local slider = window:addHorizontalSlider(4, 2, 30, 0xFFDB40, 0xEEEEEE, 0xFFDB80, 0xBBBBBB, 0, 100, 50, true, "Prefix: ", " postfix")
slider.roundValues = true
slider.onValueChanged = function(value)
	-- Do something when slider's value changed
end

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

Результат:

enter image description here

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 Состояние переключателя

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

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

Пример реализации свитча:

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

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

local switch1 = window:addSwitch(2, 2, 8, 0xFFDB40, 0xAAAAAA, 0xEEEEEE, true)
local switch2 = window:addSwitch(12, 2, 8, 0xFFDB40, 0xAAAAAA, 0xEEEEEE, false)
switch2.onStateChanged = function(state)
	-- Do something when switch's state changed
end

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

Результат:

enter image description here

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

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

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

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

Пример реализации селектора цвета:

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

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

window:addColorSelector(2, 2, 30, 3, 0xFF55FF, "Choose color").onTouch = function()
	-- Do something after choosing color
end

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

Результат:

enter image description here

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

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

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

Тип свойства Свойство Описание
function :addItem( string text, boolean disabled, string shortcut, int color ) Добавить в комбо-бокс элемент с указанными параметрами. При параметре disabled элемент не будет реагировать на клики мышью. Каждый элемент может иметь собственный callback-метод .onTouch для последующей обработки данных
function :addSeparator() Добавить визуальный в комбо-бокс разделитель
table .items Таблица элементов комбо-бокса
int .currentItem Индекс выбранного элемента комбо-бокса

Пример реализации комбо-бокса:

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

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

local comboBox = window:addComboBox(2, 2, 30, 3, 0xEEEEEE, 0x2D2D2D, 0xCCCCCC, 0x999999)
comboBox:addItem(".PNG")
comboBox:addItem(".JPG").onTouch = function()
	-- Do something when .JPG was selected
end
comboBox:addItem(".GIF")
comboBox:addSeparator()
comboBox:addItem(".PSD")

comboBox.onItemSelected = function(item)
	-- Do something after item selection
end

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

Результат:

enter image description here

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 ): table item Добавить в меню элемент с указанными параметрами. Каждый элемент имеет собственный callback-метод .onTouch
callback-function .onItemSelected( table item, table eventData ) Метод, вызывающийся после выборе какого-либо элемента комбо-бокса

Пример реализации меню:

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

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

local menu = window:addMenu(1, 1, window.width, 0xEEEEEE, 0x2D2D2D, 0x3366CC, 0xFFFFFF, nil)
menu:addItem("MineCode IDE", 0x0)
menu:addItem("File").onTouch = function(eventData)
	local contextMenu = GUI.contextMenu(eventData[3], eventData[4] + 1)
	contextMenu:addItem("New")
	contextMenu:addItem("Open").onTouch = function()
		-- Do something to open file or whatever
	end
	contextMenu:addSeparator()
	contextMenu:addItem("Save")
	contextMenu:addItem("Save as")
	contextMenu:show()
end
menu:addItem("Edit")
menu:addItem("View")
menu:addItem("About")

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

Результат:

enter image description here

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

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

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

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

Пример реализации изображения:

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

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

window:addImage(2, 2, image.load("/Furnance.pic"))

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

Результат:

enter image description here

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.

Тип свойства Свойство Описание
int .value Текущее числовое значение шкалы прогресса

Пример реализации шкалы прогресса:

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

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

window:addProgressBar(2, 2, 50, 0x3366CC, 0xEEEEEE, 0xEEEEEE, 80, true, true, "Value prefix: ", " value postfix")

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

Результат:

enter image description here

GUI.scrollBar( x, y, width, height, backgroundColor, foregroundColor, minimumValue, maximumValue, value, shownValueCount, onScrollValueIncrement, thinHorizontalMode ): table scrollBar

Тип Аргумент Описание
int x Координата объекта по оси x
int y Координата объекта по оси y
int width Ширина объекта
int height Высота объекта
int backgroundColor Цвет фона scrollBar
int foregroundColor Цвет текста scrollBar
int minimumValue Минимальное значение scrollBar
int maximumValue Максимальное значение scrollBar
int value Текущее значение scrollBar
int shownValueCount Число "отображаемых" значений scrollBar
int onScrollValueIncrement Количество строк, пролистываемых при прокрутке
boolean thinHorizontalMode Режим отображения scrollBar в полупиксельном виде при горизонтальной ориентации

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

Тип свойства Свойство Описание
callback-function .onTouch( table eventData ) Метод, вызываемый при клике на скорллбар. Значение скроллбара будет изменяться автоматически в указанном диапазоне
callback-function .onScroll( table eventData ) Метод, вызываемый при использовании колеса мыши на скроллбаре. Значение скроллбара будет изменяться в зависимости от величины .onScrollValueIncrement

Пример реализации ScrollBar:

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

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

local scrollBar = window:addScrollBar(2, 2, 1, 30, 0xEEEEEE, 0x3366CC, 1, 100, 1, 10, 1, false)
scrollBar.onTouch = function()
	-- Do something on scrollBar touch
end

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

Результат:

enter image description here

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 Таблица отображаемых строк текстбокса. Имеется опциональная возможность установки цвета конкретной строки, для этого элемент таблицы должен иметь вид {text = string, color = int}
int currentLine Текущая строка текстбокса, с которой осуществляется отображение текста
int horizontalOffset Отступ отображения текста от левого и правого краев текстбокса
int verticalOffset Отступ отображения текста от верхнего и нижнего краев текстбокса

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

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

Пример реализации текстбокса:

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

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

local textBox = window:addTextBox(2, 2, 32, 16, 0xEEEEEE, 0x2D2D2D, {}, 1, 1, 0)
table.insert(textBox.lines, {text = "Sample colored line ", color = 0x880000})
for i = 1, 100 do
	table.insert(textBox.lines, "Sample line " .. i)
end

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

Результат:

enter image description here

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", предназначенный для навигации по файловой системе в виде иерархического древа. При клике на директорию будет показано ее содержимое, а во время прокрутки колесиком мыши содержимое будет "скроллиться" в указанном направлении.

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

Пример реализации TreeView:

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

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

local treeView = window:addTreeView(2, 2, 30, 41, 0xCCCCCC, 0x2D2D2D, 0x3C3C3C, 0xEEEEEE, 0x666666, 0xEEEEEE, 0x3366CC, "/")
treeView.onFileSelected = function(filePath)
	-- Do something when file was selected
end

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

Результат:

enter image description here

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-кода с номерами строк, подсветкой синтаксиса, выделениям и скроллбарами.

Пример реализации CodeView:

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

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

local codeView = window:addCodeView(2, 2, 130, 40, {}, 1, 1, 1, {}, {}, true, 2)
local file = io.open("/lib/OpenComputersGL/Main.lua", "r")
for line in file:lines() do
	line = line:gsub("\t", " ")
	table.insert(codeView.lines, line)
	codeView.maximumLineLength = math.max(codeView.maximumLineLength, unicode.len(line))
end
file:close()

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

Результат:

enter image description here

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 Таблица вида {{float x, float y}, ...} со значениями графика

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

Пример реализации Chart:

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

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

local chart = window:addChart(2, 2, 100, 30, 0xEEEEEE, 0xAAAAAA, 0x888888, 0xFFDB40, 0.25, 0.25, "s", "t", true, {})
for i = 1, 100 do
	table.insert(chart.values, {i, math.random(0, 80)})
end

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

Результат:

enter image description here

Практический пример #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

Поскольку в моде OpenComputers имеется интернет-плата, я написал небольшой клиент для работы с VK.com. Разумеется, для этого необходимо реализовать авторизацию на серверах, вводя свой e-mail/номер телефона и пароль к аккаунту. В качестве тренировки привожу часть кода, отвечающую за это.

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

-- Создаем окно с синей фоновой панелью
local window = GUI.fullScreenWindow()
window:addPanel(1, 1, window.width, window.height, 0x002440)

-- Указываем размеры полей ввода текста и кнопок
local elementWidth, elementHeight = 40, 3
local x, y = math.floor(window.width / 2 - elementWidth / 2), math.floor(window.height / 2) - 2

-- Загружаем и добавляем изображение логотипа "нашей компании"
local logotype = image.load("/MineOS/Applications/VK.app/Resources/VKLogo.pic")
window:addImage(math.floor(window.width / 2 - image.getWidth(logotype) / 2) - 2, y - image.getHeight(logotype) - 1, logotype); y = y + 2

-- Создаем поле для ввода адреса почты
local emailTextBox = window:addInputTextBox(x, y, elementWidth, elementHeight, 0xEEEEEE, 0x777777, 0xEEEEEE, 0x2D2D2D, nil, "E-mail", false, nil, nil, nil)
-- Создаем красный текстовый лейбл, показывающийся только в том случае, когда адрес почты неверен
local invalidEmailLabel = window:addLabel(emailTextBox.localPosition.x + emailTextBox.width + 2, y + 1, window.width, 1, 0xFF5555, "Invalid e-mail"); y = y + elementHeight + 1
invalidEmailLabel.isHidden = true
-- Создаем callback-функцию, вызывающуюся после ввода текста и проверяющую корректность введенного адреса
emailTextBox.onInputFinished = function(text)
	invalidEmailLabel.isHidden = text:match("%w+@%w+%.%w+") and true or false
	window:draw()
	buffer.draw()
end
-- Создаем поле для ввода пароля
window:addInputTextBox(x, y, elementWidth, elementHeight, 0xEEEEEE, 0x777777, 0xEEEEEE, 0x2D2D2D, nil, "Password", false, "*", nil, nil); y = y + elementHeight + 1

-- Добавляем малоприметную кнопку для закрытия программы
window:addButton(window.width, 1, 1, 1, 0x002440, 0xEEEEEE, 0x002440, 0xAAAAAA, "X").onTouch = function()
	window:close()
	buffer.clear(0x0)
	buffer.draw(true)
end

-- Добавляем кнопку для логина
window:addButton(x, y, elementWidth, elementHeight, 0x666DFF, 0xEEEEEE, 0xEEEEEE, 0x666DFF, "Login").onTouch = function()
	-- Код, выполняемый при успешном логине
end

window:draw()
buffer.draw(true)
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

Как видите, в создании виджетов нет совершенно ничего сложного, главное - обладать информацией по наиболее эффективной работе с библиотекой.