From eaee5b2e94b2e72594a56dc4dca6e38fa2950b2b Mon Sep 17 00:00:00 2001 From: Igor Timofeev Date: Mon, 5 Jun 2017 23:48:49 +0300 Subject: [PATCH] =?UTF-8?q?=D0=BC=D1=8F=D1=83-=D0=BC=D1=8F=D1=83?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Documentation/GUI.md | 1305 ++++++------------------------------------ 1 file changed, 178 insertions(+), 1127 deletions(-) diff --git a/Documentation/GUI.md b/Documentation/GUI.md index cc002582..fd327aeb 100644 --- a/Documentation/GUI.md +++ b/Documentation/GUI.md @@ -1,1245 +1,296 @@ - О библиотеке ====== -GUI - многофункциональная графическая библиотека, отлаженная под использование маломощными компьютерами с максимально возможной производительностью. Она поддерживает множество элементов интерфейса: от привычных кнопок, слайдеров, текстовых полей и картинок до графиков и инструментов работы с цветовыми режимами. Быстродействие достигается за счет использования двойной буферизации и сложных группировочных алгоритмов. +DoubleBuffering - низкоуровневая библиотека для эффективного использования ресурсов GPU и отрисовки содержимого экрана с предельной скоростью. К примеру, с ее помощью реализован наш игровой движок с динамическим освещением сцен, а также небольшая игра на алгоритме рейкастинга, выдающие более чем достойные значения FPS: -К примеру, моя операционная система и среда разработки полностью реализованы методами данной библиотеки: +![Imgur](http://i.imgur.com/YgL9fCo.png?1) -![Imgur](http://i.imgur.com/U1Jybei.png?1) +![Imgur](http://i.imgur.com/yHEwiNo.png?1) -![Imgur](http://i.imgur.com/RPozLwZ.png?1) +Сама суть библиотеки очень проста: в оперативной памяти хранится два массива, содержащих информацию о пикселях на экране. Первый хранит то, что отображено в данный момент, а второй - то, что пользователь желает отрисовать. После осуществления всех операций отрисовки пользователь вызывает метод buffer.**draw**(), затем система автоматически определяет изменившиеся пиксели, группирует их в промежуточный буфер, чтобы число GPU-операций было минимальным, а затем выводит изменения на экран. + +По сравнению с стандартной отрисовкой время отображения сокращается в сотни и тысячи раз. На рисунке ниже наглядно показана эффективность библиотеки: + +![meow](http://i60.fastpic.ru/big/2015/1026/8a/4c72bfcbe8fbee5993bfd7a058a5f88a.png) + +Цена таких космических скоростей - повышенный расход оперативной памяти. Чтобы предельно уменьшить ее расход, мы используем одномерную структуру экранных массивов вместо трехмерной: + +![Imgur](http://i.imgur.com/Y0McdjR.png?1) + +Для получения данных о пикселях используются специальные методы, преобразующие экранные координаты в индексы экранного буфера и наоборот, подробнее об этом написано ниже в разделе "**Вспомогательные методы**". -Пусть синтаксис и обилие текста вас не пугают, в документации имеется множество наглядных иллюстрированных примеров и практических задач. Установка ====== | Библиотека | Функционал | | ------ | ------ | -| *[GUI](https://github.com/IgorTimofeev/OpenComputers/blob/master/lib/GUI.lua)* | Данная библиотека | -| *[advancedLua](https://github.com/IgorTimofeev/OpenComputers/blob/master/lib/advancedLua.lua)* | Дополнение стандартных библиотек Lua множеством функций: быстрой сериализацией таблиц, переносом строк, методами обработки бинарных данных и т.д. | -| *[doubleBuffering](https://github.com/IgorTimofeev/OpenComputers/blob/master/lib/doubleBuffering.lua)* | Низкоуровневая библиотека двойной буферизации для максималььно быстрой отрисовки графики с поддержкой полу-пиксельных методов | +| *[doubleBuffering](https://github.com/IgorTimofeev/OpenComputers/blob/master/lib/doubleBuffering.lua)* | Данная библиотека | | *[color](https://github.com/IgorTimofeev/OpenComputers/blob/master/lib/color.lua)* | Низкоуровневая библиотека для работы с цветом, предоставляющая методы получения цветовых каналов, различные палитры и конвертацию цвета в 8-битный формат | | *[image](https://github.com/IgorTimofeev/OpenComputers/blob/master/lib/image.lua)* | Библиотека, реализующая стандарт изображений для OpenComputers и методы их обработки: транспонирование, обрезку, поворот, отражение и т.д. | | *[OCIF](https://github.com/IgorTimofeev/OpenComputers/blob/master/lib/ImageFormatModules/OCIF.lua)* | Модуль формата изображения OCIF (OpenComputers Image Format) для библиотеки image, написанный с учетом особенностей мода и реализующий эффективное сжатие пиксельных данных | -| *[syntax](https://github.com/IgorTimofeev/OpenComputers/blob/master/lib/syntax.lua)* | Подсветка lua-синтаксиса для виджета CodeView | -| *[palette](https://github.com/IgorTimofeev/OpenComputers/blob/master/lib/palette.lua)* | Библиотека-окно для работы с цветом в режиме HSV и выборе конкретных цветовых данных для виджета ColorSelector | -Вы можете использовать имеющиеся выше ссылки для установки зависимостей вручную или запустить автоматический [установщик](https://pastebin.com/ryhyXUKZ), загружающий все необходимые файлы за вас: +Вы можете использовать имеющиеся выше ссылки для установки зависимостей вручную или запустить автоматический [установщик](https://pastebin.com/vTM8nbSZ), загружающий все необходимые файлы за вас: - pastebin run ryhyXUKZ + pastebin run vTM8nbSZ -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**()| Добавить в контекстное меню визуальный разделитель | +| *int* | buffer.**width**| Текущее разрешение буфера по ширине | +| *int* | buffer.**height**| Текущее разрешение буфера по высоте | +| *table* | buffer.**currentFrame**| Таблица с пиксельными данными, содержащая то, что в данный момент отображено на экране. Она имеет структуру ```{ 0xFFFFFF, 0x000000, "Q", 0xFFFFFF, 0x000000, "W", ... }```, где первый элемент - цвет фона, второй - цвет текста, третий - символ. И так до конца размера буфера | +| *table* | buffer.**newFrame**| Таблица с пиксельными данными, содержащая то, что пользователь отрисовывает в него в данный момент. Структура аналогична предыдущей | -Пример реализации контекстного меню: - -```lua -local buffer = require("doubleBuffering") -local GUI = require("GUI") - -buffer.clear(0x2D2D2D) -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() -``` - -Результат: - -![Imgur](http://i.imgur.com/kw6jjtY.png) - -GUI.**error**( text ) ------------------------------------------------------------------------- -| Тип | Аргумент | Описание | -| ------ | ------ | ------ | -| *string* | text | Текст информационного окна | - - -Показать отладочное окно с текстовой информацией. Слишком длинная строка будет автоматически перенесена. Для закрытия окна необходимо использовать клавишу return или нажать на кнопку "ОК". - -Пример реализации: - -```lua -local buffer = require("doubleBuffering") -local GUI = require("GUI") - -buffer.clear(0x2D2D2D) -GUI.error("Something went wrong here, my friend") -``` - -Результат: - -![Imgur](http://i.imgur.com/s8mA2FL.png?1) - -Методы для создания контейнеров +Основные методы ====== -Вся библиотека делится на две основные кострукции: контейнеры и виджеты. Контейнер предназначен для группировки нескольких виджетов и их конвеерной обработки, поэтому в первую очередь необходимо изучить особенности работы с контейнерами. - -GUI.**container**( x, y, width, height ): *table* container +buffer.**setResolution**( width, height ) ----------------------------------------------------------- | Тип | Аргумент | Описание | | ------ | ------ | ------ | -| *int* | x | Координата контейнера по оси x | -| *int* | y | Координата контейнера по оси y | -| *int* | width | Ширина контейнера | -| *int* | height | Высота контейнера | +| *int* | width | Ширина буфера | +| *int* | height | Высота буфера | -Каждый контейнер - это группировщик для других объектов, его поведение очень похоже на папку, содержащую множество вложенных файлов и других папок. Для создания контейнера по размеру экрана используйте метод GUI.**fullScreenContainer**(). - -Все дочерние элементы контейнера имеют свою *localPosition* в контейнере (к примеру, *{x = 4, y = 2}*). После добавления дочернего элемента в контейнер для дальнейших рассчетов используется именно его локальная позиция. Для получения глобальных (экранных) координат дочернего элемента необходимо обращаться к *element.x* и *element.y*. Глобальная (экранная) позиция дочерних элементов рассчитывается при каждой отрисовке содержимого контейнера. Таким образом, изменяя глобальные координаты дочернего элемента вручную, вы, в сущности, ничего не добьётесь. - -Наглядно система иерархии и позиционирования контейнеров и дочерних элементов представлена на следущем изображении: - -![Imgur](http://i.imgur.com/nU2bLU8.png?1) - -У контейнеров имеется немаловажная особенность: любой дочерний элемент, выступающий за границы контейнера, будет отрисован только в рамках размера этого контейнера: - -![Imgur](http://i.imgur.com/PMtOpNS.png?1) - -Для добавления в контейнер дочернего элемента используйте синтаксическую конструкцию :**addChild**(**<Объект>**). При этом глобальные координаты объекта становятся локальными. К примеру, для добавления кнопки на локальную позицию *x = 5, y = 10* используйте :**addChild**(GUI.**button**(5, 10, ...)). В контейнер можно добавлять другие контейнеры, а в добавленные - еще одни, создавая сложные иерархические цепочки и группируя дочерние объекты по своему усмотрению. - -Наконец, самая важная особенность контейнеров - это автоматизированная обработка системных событий. Для запуска обработки событий необходимо вызвать метод :**startEventHandling**. После этого при каждом событии текущий контейнер и всего его вложенные объекты будут рекурсивно проанализированы на наличие метода-обработчика .**eventHandler**. - -Если метод-обработчик имеется, то он будет вызван со следующими аргументами: *container* mainContainer, *object* object, *table* eventData, где первым аргументом является контейнер, обрабатывающий события, вторым является текущий рассматриваемый объект обработчика событий, а третьим - таблица с данными события. Многие объекты, перечисленные ниже, уже имеют собственный .**eventHandler** - к примеру, кнопка автоматически нажимается, слайдер перемещается влево-вправо, а селектор цвета открывает палитру для выбора желаемого оттенка. Все это реализовано именно на методе-обработчике. - -В качестве примера ниже приведен исходный код обработчика событий GUI.**button**. Как видите, в начале событие анализируется на соответствие "touch", затем кнопка визуально "нажимается", а в конце вызывается метод кнопки .*onTouch*, если он вообще имеется. -```lua -button.eventHandler = function(mainContainer, button, eventData) - if eventData[1] == "touch" then - button.pressed = true - mainContainer:draw() - buffer.draw() - - os.sleep(0.2) - - button.pressed = false - mainContainer:draw() - buffer.draw() - - if button.onTouch then - button.onTouch(mainContainer, object, eventData) - end - end -end -``` - -Ключевая деталь обработчика событий в том, что если событие "экранное", то есть относящееся к клику пользователя на монитор (touch, drag, drop, scroll), то метод-обработчик объекта будет вызван только в том случае, если на пути прослеживания клика не имеется никаких других объектов, после чего обработка событий для оставшихся необработанных дочерних элементов завершится. Если событие не относится к экрану (key_down, clipboard и т.д.), или же объект не имеет метода-обработчика, то обработка оставшихся дочерних элементов продолжится в прежнем виде. - -Если необходимо прекратить обработку событий, то необходимо вызвать метод :**stopEventHandling**. - -| Тип свойства | Свойство |Описание | -| ------ | ------ | ------ | -| *function* | :**addChild**( *table* child ): *table* child| Добавить произвольный объект в контейнер в качестве дочернего - таким образом вы способны создавать собственные виджеты с индивидуальными особенностями. Уточняю, что у добавляемого объекта **обязательно** должен иметься метод *:draw* (подробнее см. ниже). При добавлении объекта его глобальные координаты становятся локальными | -| *function* | :**deleteChildren**(): *table* container | Удалить все дочерние элементы контейнера | -| *function* | :**draw**(): *table* container | Рекурсивная отрисовка содержимого контейнера в порядке очереди его дочерних элементов. Обращаю внимание на то, что данный метод осуществляет отрисовку только в экранный буфер. Для отображения изменений на экране необходимо использовать метод библиотеки двойного буфера *.draw()* | -| *function* | :**startEventHandling**([*float* delay]): *table* container | Запуск обработчика событий для данного контейнера и всех вложенных в него дочерних элементов. Параметр *delay* аналогичен таковому в computer.**pullSignal** | -| *function* | :**stopEventHandling**(): *table* container | Остановка обработчика событий для данного контейнера | - -GUI.**layout**( x, y, width, height, columns, rows ): *table* container ------------------------------------------------------ +Установить разрешение экранного буфера и GPU равным указанному. Содержимое буфера при этом будет заполнено черными пикселями с символом пробела. +buffer.**draw**( [force] ) +----------------------------------------------------------- | Тип | Аргумент | Описание | | ------ | ------ | ------ | -| *int* | x | Координата объекта по оси x | -| *int* | y | Координата объекта по оси y | -| *int* | width | Ширина объекта | -| *int* | height | Высота объекта | -| *int* | columnCount | Количество рядов сетки | -| *int* | rowCount | Количество строк сетки | +| [*boolean* | force] | Принудительная отрисовка | -Layout является наследником GUI.**container**, автоматически располагающим дочерние объекты внутри себя. К примеру, если вам хочется визуально красиво отобразить множество объектов, не тратя время на ручной расчет координат, то layout создан для вас. На картинке ниже подробно показана структура layout размером 3x2: +Отрисовать содержимое буфера на экран. Если имеется опциональный аргумент *force*, то содержимое буфера будет полностью отрисовано вне зависимости от изменившихся пикселей. -![Imgur](http://i.imgur.com/nypo5Fj.png?1) - -Видно, что имеется 6 ячеек, каждая из которых может иметь собственную ориентацию объектов, расстояние между ними, а также выравнивание по границам. Границы ячеек условны, так что дочерние объекты могут без проблем выходить за них, если это допускает указанный alignment. - -| Тип свойства | Свойство |Описание | +buffer.**setDrawLimit**( x1, y1, x2, y2 ) +----------------------------------------------------------- +| Тип | Аргумент | Описание | | ------ | ------ | ------ | -| *int* | .**columnCount**| Количество рядов сетки | -| *int* | .**rowCount**| Количество строк сетки | -| *function* | :**setGridSize**(*int* columnCount, *int* columnCount): *layout* layout | Установить размер сетки. Все объекты, находящиеся вне диапазона нового размера, должны быть размещены в сетке заново через :**setCellPosition**() | -| *function* | :**setCellPosition**(*int* column, *int* row, *object* child): *object* child| Назначить дочернему объекту layout конкретную ячейку сетки. В одной ячейке может располагаться сколь угодно много объектов. | -| *function* | :**setCellDirection**(*int* column, *int* row, *enum* direction): *layout* layout | Назначить ячейке сетки ориентацию дочерних объектов. Поддерживаются GUI.directions.horizontal и GUI.directions.vertical | -| *function* | :**setCellAlignment**(*int* column, *int* row, *enum* GUI.alignment.vertical, *enum* GUI.alignment.horizontal): *layout* layout | Назначить ячейке сетки метод выравнивания дочерних объектов. Поддерживаются все 9 вариантов | -| *function* | :**setCellSpacing**(*int* column, *int* row, *int* spacing): *layout* layout | Назначить ячейке сетки расстояние в пикселях между объектами. По умолчанию оно равняется 1 | +| *int* | x1 | Координата первой точки лимита отрисовки по оси x | +| *int* | y1 | Координата первой точки лимита отрисовки по оси y | +| *int* | x2 | Координата второй точки лимита отрисовки по оси x | +| *int* | y2 | Координата второй точки лимита отрисовки по оси y | -Пример реализации layout: -```lua -local image = require("image") -local buffer = require("doubleBuffering") -local GUI = require("GUI") +Установить лимит отрисовки буфера до указанного. При этом любые операции, выходящие за границы лимита, будут игнорироваться. По умолчанию буфер всегда имеет лимит отрисовки в диапазонах **x ∈ [1; buffer.width]** и **y ∈ [1; buffer.height]** --- Создаем полноэкранный контейнер, добавляем на него загруженное изображение и полупрозрачную черную панель -local mainContainer = GUI.fullScreenContainer() -mainContainer:addChild(GUI.image(1, 1, image.load("/MineOS/Pictures/Raspberry.pic"))) -mainContainer:addChild(GUI.panel(1, 1, mainContainer.width, mainContainer.height, 0x000000, 40)) +buffer.**getDrawLimit**( ): *int* x1, *int* y1, *int* x2, *int* y2 +----------------------------------------------------------- +Получить текущий лимит отрисовки. --- Добавляем в созданный контейнер layout с сеткой размером 5x1 -local layout = mainContainer:addChild(GUI.layout(1, 1, mainContainer.width, mainContainer.height, 5, 1)) +buffer.**copy**( x, y, width, height ): *table* pixelData +----------------------------------------------------------- +| Тип | Аргумент | Описание | +| ------ | ------ | ------ | +| *int* | x | Координата копируемой области по оси x | +| *int* | y | Координата копируемой области по оси y | +| *int* | width | Ширина копируемой области | +| *int* | height | Высота копируемой области | --- Добавяляем в layout 9 кнопок, назначая им соответствующие позиции в сетке. --- Как видите, сначала создается объект кнопки, затем он добавляется в качестве дочернего к layout, --- а в конце концов ему назначается позиция сетки. -layout:setCellPosition(1, 1, layout:addChild(GUI.button(1, 1, 26, 3, 0xEEEEEE, 0x000000, 0xAAAAAA, 0x000000, "Button 1"))) -layout:setCellPosition(2, 1, layout:addChild(GUI.button(1, 1, 26, 3, 0xEEEEEE, 0x000000, 0xAAAAAA, 0x000000, "Button 2"))) -layout:setCellPosition(2, 1, layout:addChild(GUI.button(1, 1, 26, 3, 0xEEEEEE, 0x000000, 0xAAAAAA, 0x000000, "Button 3"))) -layout:setCellPosition(3, 1, layout:addChild(GUI.button(1, 1, 26, 3, 0xEEEEEE, 0x000000, 0xAAAAAA, 0x000000, "Button 4"))) -layout:setCellPosition(3, 1, layout:addChild(GUI.button(1, 1, 26, 3, 0xEEEEEE, 0x000000, 0xAAAAAA, 0x000000, "Button 5"))) -layout:setCellPosition(3, 1, layout:addChild(GUI.button(1, 1, 26, 3, 0xEEEEEE, 0x000000, 0xAAAAAA, 0x000000, "Button 6"))) -layout:setCellPosition(4, 1, layout:addChild(GUI.button(1, 1, 26, 3, 0xEEEEEE, 0x000000, 0xAAAAAA, 0x000000, "Button 7"))) -layout:setCellPosition(4, 1, layout:addChild(GUI.button(1, 1, 26, 3, 0xEEEEEE, 0x000000, 0xAAAAAA, 0x000000, "Button 8"))) -layout:setCellPosition(5, 1, layout:addChild(GUI.button(1, 1, 26, 3, 0xEEEEEE, 0x000000, 0xAAAAAA, 0x000000, "Button 9"))) +Скопировать содержимое указанной области из буфера и выдать в виде таблицы. Впоследствии можно использовать с buffer.**paste**(...). -mainContainer:draw() -buffer.draw(true) -mainContainer:startEventHandling() -``` +buffer.**paste**( x, y, pixelData ) +----------------------------------------------------------- +| Тип | Аргумент | Описание | +| ------ | ------ | ------ | +| *int* | x | Координата вставки по оси x | +| *int* | y | Координата вставки по оси y | +| *table* | pixelData | Таблица со скопированной ранее областью буфера | -Результат: +Вставить скопированное содержимое буфера по указанным координатам. -![Imgur](http://i.imgur.com/ti58Z75.png?1) - -Как видите, 9 кнопок автоматически сгруппировались по 5 ячейкам сетки. Визуально структура созданного layout выглядит так: - -![Imgur](http://i.imgur.com/1JSFFv1.png?1) - -Также мы можем модифицировать код, чтобы кнопки группировались в 3 колонки, а расстояние между ними было равным 4 пикселям: - -```lua --- Изменяем размер сетки на 3x1 -layout:setGridSize(3, 1) --- Устанавливаем расстояние между объектами для каждой колонки -for column = 1, 3 do - layout:setCellSpacing(column, 1, 4) -end --- Обновляем позиции трех последних кнопок, чтобы они принадлежали третьей колонке -for child = 7, 9 do - layout:setCellPosition(3, 1, layout.children[child]) -end -``` -Результат: - -![Imgur](http://i.imgur.com/QD0BqWx.png?1) - -Более подробно работа с layout рассмотрена в практическом примере 4 в конце документа. - -Методы для создания виджетов +Методы отрисовки ====== -После понимания концепции контейнеров можно с легкостью приступить к добавлению виджетов в созданный контейнер. Каждый виджет - это наследник объекта типа GUI.**object** - -GUI.**object**( x, y, width, height ): *table* object ------------------------------------------------------ +buffer.**set**( x, y, background, foreground, symbol ) +----------------------------------------------------------- | Тип | Аргумент | Описание | | ------ | ------ | ------ | -| *int* | x | Координата объекта по оси x | -| *int* | y | Координата объекта по оси y | -| *int* | width | Ширина объекта | -| *int* | height | Высота объекта | +| *int* | x | Координата по оси x | +| *int* | y | Координата по оси y | +| *int* | background | Цвет фона | +| *int* | foreground | Цвет символа | +| *char* | symbol | Символ | -Помимо координат и размера GUI.**object** имеет несколько универсальных свойств: +Установить значение конкретного пикселя на экране. Полезно для мелкого и точного редактирования. -| Тип свойства| Свойство |Описание | -| ------ | ------ | ------ | -| *boolean* | .**hidden** | Является ли объект скрытым. Если объект скрыт, то его отрисовка и анализ системных событий игнорируются | -| *boolean* | .**disabled** | Является ли объект отключенным. Если объект отключен, то все системные события при обработке игнорируются | -| *function* | :**draw**() | Обязательный метод, вызываемый для отрисовки виджета на экране. Он может быть определен пользователем любым удобным для него образом. Данный метод осуществляет отрисовку только в экранный буфер, а не на экран | -| *function* | :**isClicked**( *int* x, *int* y ): *boolean* isClicked | Метод для проверки валидности клика на объект. Используется родительскими методами контейнеров и удобен для ручной проверки пересечения указанных координат с расположением объекта на экране | - -После добавления объекта в контейнер с помощью метода *:addChild* он приобретает дополнительные свойства для удобства использования: - -| Тип свойства| Свойство |Описание | -| ------ | ------ | ------ | -| *table* | .**parent** | Указатель на таблицу-контейнер родителя этого виджета | -| *table* | .**localPosition** | Таблица вида {x = *int*, y = *int*} с локальными координатами виджета в родительском контейнере | -| *function* | :**indexOf**() | Получить индекс данного виджета в родительском контейнере | -| *function* | :**moveForward**() | Передвинуть виджет "назад" в иерархии виджетов контейнера | -| *function* | :**moveBackward**() | Передвинуть виджет "вперед" в иерархии виджетов контейнера | -| *function* | :**moveToFront**() | Передвинуть виджет в конец иерархии виджетов контейнера | -| *function* | :**moveToBack**() | Передвинуть виджет в начало иерархии виджетов контейнера | -| *function* | :**getFirstParent**() | Получить первый родительский контейнер для рассматриваемой системы родительских контейнеров. К примеру, при существовании множества вложенных контейнеров метод вернет первый и "главный" из них | -| *function* | :**delete**() | Удалить этот объект из родительского контейнера. Грубо говоря, это удобный способ самоуничтожения | -| [*callback-function* | .**eventHandler**(*container* mainContainer, *object* object, *table* eventData) ]| Необязательный метод для обработки системных событий, вызываемый обработчиком родительского контейнера. Если он имеется у рассматриваемого объекта, то будет вызван с соотвествующими аргументами | - -Далее перечислены виджеты, уже созданные мной на основе описанных выше инструкций. При желании вы можете сделать абсолютно аналогичные или технически гораздо более продвинутые виджеты без каких-либо затруднений. Подробнее о создании собственных виджетов см. практические примеры в конце документации. - -GUI.**panel**( x, y, width, height, color, [transparency] ): *table* panel ------------------------------------------------------------------------- +buffer.**get**( x, y ): *int* background, *int* foreground, *char* symbol +----------------------------------------------------------- | Тип | Аргумент | Описание | | ------ | ------ | ------ | -| *int* | x | Координата объекта по оси x | -| *int* | y | Координата объекта по оси y | -| *int* | width | Ширина объекта | -| *int* | height | Высота объекта | -| *int* | color | Цвет панели | -| [*int* | transparency] | Опциональная прозрачность панели | +| *int* | x | Координата по оси x | +| *int* | y | Координата по оси y | -Создать объект типа "панель", представляющий собой закрашенный прямоугольник с определенной опциональной прозрачностью. В большинстве случаев служит декоративным элементом. +Получить значение конкретного пикселя на экране. -Пример реализации панели: -```lua -local buffer = require("doubleBuffering") -local GUI = require("GUI") - -local mainContainer = GUI.fullScreenContainer() - -local panel1 = mainContainer:addChild(GUI.panel(1, 1, mainContainer.width, math.floor(mainContainer.height / 2), 0x444444)) -mainContainer:addChild(GUI.panel(1, panel1.height, mainContainer.width, mainContainer.height - panel1.height + 1, 0x880000)) - -mainContainer:draw() -buffer.draw(true) -mainContainer:startEventHandling() -``` - -Результат: - -![enter image description here](http://i91.fastpic.ru/big/2017/0402/46/d2516c735ef5a92d294caa560aa87546.png) - -GUI.**button**( x, y, width, height, buttonColor, textColor, buttonPressedColor, textPressedColor, text ): *table* button ------------------------------------------------------------------------- +buffer.**square**( x, y, width, height, background, foreground, symbol, transparency ) +----------------------------------------------------------- | Тип | Аргумент | Описание | | ------ | ------ | ------ | -| *int* | x | Координата объекта по оси x | -| *int* | y | Координата объекта по оси y | -| *int* | width | Ширина объекта | -| *int* | height | Высота объекта | -| *int* | buttonColor | Цвет кнопки | -| *int* | textColor | Цвет текса | -| *int* | buttonPressedColor | Цвет кнопки при нажатии | -| *int* | textPressedColor | Цвет текста при нажатии | -| *string* | text | Текст на кнопке | +| *int* | x | Координата прямоугольника по оси x | +| *int* | y | Координата прямоугольника по оси y | +| *int* | width | Ширина прямоугольника | +| *int* | height | Высота прямоугольника | +| *int* | background | Цвет фона прямоугольника | +| *int* | foreground | Цвет символов прямоугольника | +| *char* | symbol | Символ, которым будет заполнен прямоугольник | +| [*int* | transparency] | Опциональная прозрачность прямоугольника | -Создать объект типа "кнопка". Каждая кнопка имеет два состояния (*isPressed = true/false*), автоматически переключаемые методом-обработчиком .*eventHandler*. Для назначения какого-либо действия кнопке после ее нажатия создайте для нее метод *.onTouch()*. +Заполнить прямоугольную область указанными данными. При указании прозрачности в диапазоне [0; 100] прямоугольник будет накладываться поверх существующей информации, словно прозрачное стеклышко. -Имеется также три альтернативных варианта кнопки: - - - 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 )| Нажать и отжать кнопку в течение указанного временного периода. Примечание: этот метод использует отрисовку содержимого двойного буфера | - -Пример реализации кнопки: -```lua -local buffer = require("doubleBuffering") -local GUI = require("GUI") - -local mainContainer = GUI.fullScreenContainer() -mainContainer:addChild(GUI.panel(1, 1, mainContainer.width, mainContainer.height, 0x2D2D2D)) - -mainContainer:addChild(GUI.button(2, 2, 30, 3, 0xFFFFFF, 0x000000, 0xAAAAAA, 0x000000, "Button text")).onTouch = function() - -- Do something on button click -end - -mainContainer:draw() -buffer.draw(true) -mainContainer:startEventHandling() -``` - -Результат: - -![Imgur](http://i.imgur.com/KiPqftB.png?1) - -GUI.**label**( x, y, width, height, textColor, text ): *table* label --------------------------------------------------------------------- +buffer.**clear**( [background, foreground, symbol] ) +----------------------------------------------------------- | Тип | Аргумент | Описание | | ------ | ------ | ------ | -| *int* | x | Координата объекта по оси x | -| *int* | y | Координата объекта по оси y | -| *int* | width | Ширина объекта | -| *int* | height | Высота объекта | -| *int* | textColor | Цвет текста лейбла| -| *string* | text | Текст лейбла | +| [*int* | background] | Опциональный цвет фона | +| [*int* | foreground] | Опциональный цвет символов | +| [*char* | symbol] | Опциональный символ | -Создать объект типа "лейбл", предназначенный для отображения текстовой информации в различных вариациях расположения. +Работает как buffer.**square**(...), однако применяется сразу ко всей области экрана. Если аргументов не передается, то буфер заполняется стандартным черным цветом и символом пробела. Удобно для быстрого заполнения содержимого буфера. -| Тип свойства | Свойство |Описание | -| ------ | ------ | ------ | -| *callback-function* | .**onTouch**( *table* eventData )| Метод, вызываемый после нажатия на лейбл в обработчике событий | -| *function* | :**setAlignment**( *enum* GUI.alignment.vertical, *enum* GUI.alignment.horizontal ): *table* label| Выбрать вариант отображения текста относительно границ лейбла | - -Пример реализации лейбла: -```lua -local buffer = require("doubleBuffering") -local GUI = require("GUI") - -local mainContainer = GUI.fullScreenContainer() -mainContainer:addChild(GUI.panel(1, 1, mainContainer.width, mainContainer.height, 0x2D2D2D)) - -mainContainer:addChild(GUI.label(2, 2, mainContainer.width, mainContainer.height, 0xFFFFFF, "Centered text")):setAlignment(GUI.alignment.horizontal.center, GUI.alignment.vertical.center) - -mainContainer:draw() -buffer.draw(true) -mainContainer:startEventHandling() -``` - -Результат: - -![Imgur](http://i.imgur.com/4Hl5G7l.png?1) - -GUI.**inputField**( x, y, width, height, backgroundColor, textColor, placeholderTextColor, backgroundFocusedColor, textFocusedColor, text, [placeholderText, eraseTextOnFocus, textMask ): *table* inputField ------------------------------------------------------------------------- +buffer.**text**( x, y, color, text, transparency ) +----------------------------------------------------------- | Тип | Аргумент | Описание | | ------ | ------ | ------ | -| *int* | x | Координата объекта по оси x | -| *int* | y | Координата объекта по оси y | -| *int* | width | Ширина объекта | -| *int* | height | Высота объекта | -| *int* | backgroundColor | Цвет фона | -| *int* | textColor | Цвет текста | -| *int* | placeholderTextColor | Цвет текста *placeholder* при условии, что он указан ниже | -| *int* | backgroundFocusedColor | Цвет фона в состоянии *focused* | -| *int* | textFocusedColor |Цвет текста в состоянии *focused* | -| *string* | text | Введенный на момент создания поля текст | -| [*string* | placeholderText] | Текст, появляющийся при условии, что введенный текст отсутствует | -| [*boolean* | eraseTextOnFocus] | Необходимо ли удалять текст при активации ввода | -| [*char* | textMask] | Символ-маска для вводимого текста. Удобно для создания поля ввода пароля | +| *int* | x | Координата текста по оси x | +| *int* | y | Координата текста по оси y | +| *int* | foreground | Цвет текста | +| *string* | text | Текст | +| [*int* | transparency] | Опциональная прозрачность текста | -Создать объект, предназначенный для ввода и анализа текстовых данных с клавиатуры. Объект универсален и подходит как для создания простых форм для ввода логина/пароля, так и для сложных структур наподобие интерпретаторов команд. К примеру, окно *палитры* со скриншота в начале документации полностью основано на использовании этого объекта. +Нарисовать текст указанного цвета поверх имеющихся пикселей. Цвет фона при этом остается прежним. Можно также указать опциональную прозрачность текста текста в диапазоне [0; 100]. -| Тип свойства | Свойство |Описание | -| ------ | ------ | ------ | -| *function* | :**startInput**()| Начать ввод в текстовое поле. Метод полезен, если хочется сразу сделать | -| *callback-function* | .**validator**( *string* text )| Метод, вызывающийся после окончания ввода текста в поле. Если возвращает *true*, то текст в текстовом поле меняется на введенный, в противном случае введенные данные игнорируются. К примеру, в данном методе удобно проверять, является ли введенная текстовая информация числом через *tonumber()* | -| *callback-function* | .**onInputFinished**( *string* text, *table* eventData )| Метод, вызываемый после ввода данных в обработчике событий. Удобная штука, если хочется выполнить какие-либо действия сразу после ввода текста. Если у объекта имеется *validator*, и текст не прошел проверку через него, то *onInputFinished* вызван не будет. | - -Пример реализации поля ввода: - -```lua -local buffer = require("doubleBuffering") -local GUI = require("GUI") - -local mainContainer = GUI.fullScreenContainer() -mainContainer:addChild(GUI.panel(1, 1, mainContainer.width, mainContainer.height, 0x2D2D2D)) - -local inputField = mainContainer:addChild(GUI.inputField(2, 2, 30, 3, 0xEEEEEE, 0x555555, 0x999999, 0xFFFFFF, 0x2D2D2D, "Hello world", "Placeholder text")) - -mainContainer:draw() -buffer.draw(true) -mainContainer:startEventHandling() -``` - -Результат: - -![Imgur](http://i.imgur.com/8cUO1vy.png) - -![Imgur](http://i.imgur.com/4jHPQfl.png) - -![Imgur](http://i.imgur.com/PV0RQOq.png) - -GUI.**slider**( x, y, width, primaryColor, secondaryColor, pipeColor, valueColor, minimumValue, maximumValue, value, [showCornerValues, currentValuePrefix, currentValuePostfix] ): *table* slider ------------------------------------------------------------------------- +buffer.**image**( x, y, picture ) +----------------------------------------------------------- | Тип | Аргумент | Описание | | ------ | ------ | ------ | -| *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] | Постфикс для значения слайдера | +| *int* | x | Координата изображения по оси x | +| *int* | y | Координата изображения по оси y | +| *table* | picture | Загруженное изображение | -Создать объект типа "слайдер", предназначенный для манипуляцией числовыми данными. Значение слайдера всегда будет варьироваться в диапазоне от минимального до максимального значений. Опционально можно указать значение поля *слайдер.**roundValues** = true*, если необходимо округлять изменяющееся число. +Нарисовать загруженное через image.**load**(*string* path) изображение. Альфа-канал изображения также поддерживается. -| Тип свойства | Свойство |Описание | -| ------ | ------ | ------ | -| *callback-function* | .**onValueChanged**( *float* value, *table* eventData )| Метод, вызывающийся после изменения значения слайдера | +Методы полупиксельной отрисовки +====== -Пример реализации слайдера: +Все полупиксельные методы позволяют избежать эффекта удвоения высоты пикселя консольной графики, используя специальные символы наподобие "▄". При этом передаваемые координаты по оси **Y** должны принадлежать промежутку **[0; 100]**. -```lua -local buffer = require("doubleBuffering") -local GUI = require("GUI") -local mainContainer = GUI.fullScreenContainer() -mainContainer:addChild(GUI.panel(1, 1, mainContainer.width, mainContainer.height, 0x2D2D2D)) - -local slider = mainContainer:addChild(GUI.slider(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 - -mainContainer:draw() -buffer.draw(true) -mainContainer:startEventHandling() -``` - -Результат: - -![Imgur](http://i.imgur.com/P4vQmNA.png?1) - -GUI.**switch**( x, y, width, primaryColor, secondaryColor, pipeColor, state ): *table* switch ------------------------------------------------------------------------- +buffer.**semiPixelSet**( x, y, color ) +----------------------------------------------------------- | Тип | Аргумент | Описание | | ------ | ------ | ------ | -| *int* | x | Координата объекта по оси x | -| *int* | y | Координата объекта по оси y | -| *int* | width | Ширина объекта | -| *int* | primaryColor | Основной цвет переключателя | -| *int* | secondaryColor | Вторичный цвет переключателя | -| *int* | pipeColor | Цвет "пимпочки" переключателя | -| *boolean* | state | Состояние переключателя | +| *int* | x1 | Координата пикселя по оси x | +| *int* | y1 | Координата пикселя по оси y | +| *int* | color | Цвет пикселя | -Создать объект типа "переключатель", для определения истинности или ложности того или иного события. При клике на объект меняет состояние на противоположное. +Установка пиксельного значения в указанной точке. -| Тип свойства | Свойство |Описание | -| ------ | ------ | ------ | -| *callback-function* | .**onStateChanged**( *boolean* state, *table* eventData )| Метод, вызывающийся после изменения состояния переключателя | - -Пример реализации свитча: - -```lua -local buffer = require("doubleBuffering") -local GUI = require("GUI") - -local mainContainer = GUI.fullScreenContainer() -mainContainer:addChild(GUI.panel(1, 1, mainContainer.width, mainContainer.height, 0x2D2D2D)) - -local switch1 = mainContainer:addChild(GUI.switch(2, 2, 8, 0xFFDB40, 0xAAAAAA, 0xEEEEEE, true)) -local switch2 = mainContainer:addChild(GUI.switch(12, 2, 8, 0xFFDB40, 0xAAAAAA, 0xEEEEEE, false)) -switch2.onStateChanged = function(state) - -- Do something when switch's state changed -end - -mainContainer:draw() -buffer.draw(true) -mainContainer:startEventHandling() - -``` - -Результат: - -![Imgur](http://i.imgur.com/wpJNU2F.png?1) - -GUI.**colorSelector**( x, y, width, height, color, text ): *table* colorSelector ------------------------------------------------------------------------- +buffer.**semiPixelSquare**( x, y, width, height, color ) +----------------------------------------------------------- | Тип | Аргумент | Описание | | ------ | ------ | ------ | -| *int* | x | Координата объекта по оси x | -| *int* | y | Координата объекта по оси y | -| *int* | width | Ширина объекта | -| *int* | height | Высота объекта | -| *int* | color | Текущий цвет селектора | -| *string* | text | Текст селектора | +| *int* | x | Координата прямоугольника по оси x | +| *int* | y | Координата прямоугольника по оси y | +| *int* | width | Ширина прямоугольника | +| *int* | height | Высота прямоугольника | +| *int* | color | Цвет прямоугольника | -Создать объект типа "селектор цвета", представляющий собой аналог кнопки, позволяющей выбрать цвет при помощи удобной палитры. +Отрисовка прямоугольника с указанными параметрами. -| Тип свойства | Свойство |Описание | -| ------ | ------ | ------ | -| *callback-function* | .**onTouch**( *table* eventData )| Метод, вызываемый после нажатия на селектор цвета в обработчике событий | - -Пример реализации селектора цвета: - -```lua -local buffer = require("doubleBuffering") -local GUI = require("GUI") - -local mainContainer = GUI.fullScreenContainer() -mainContainer:addChild(GUI.panel(1, 1, mainContainer.width, mainContainer.height, 0x2D2D2D)) - -mainContainer:addChild(GUI.colorSelector(2, 2, 30, 3, 0xFF55FF, "Choose color")).onTouch = function() - -- Do something after choosing color -end - -mainContainer:draw() -buffer.draw(true) -mainContainer:startEventHandling() -``` - -Результат: - -![Imgur](http://i.imgur.com/n0nLIzx.png?1) - -GUI.**comboBox**( x, y, width, elementHeight, backgroundColor, textColor, arrowBackgroundColor, arrowTextColor ): *table* comboBox ------------------------------------------------------------------------- +buffer.**semiPixelLine**( x1, y1, x2, y2, color ) +----------------------------------------------------------- | Тип | Аргумент | Описание | | ------ | ------ | ------ | -| *int* | x | Координата объекта по оси x | -| *int* | y | Координата объекта по оси y | -| *int* | width | Ширина объекта | -| *int* | elementHeight | Высота элемента комбо-бокса | -| *int* | backgroundColor | Цвет фона комбо-бокса | -| *int* | textColor | Цвет текста комбо-бокса | -| *int* | arrowBackgroundColor | Цвет фона стрелки комбо-бокса | -| *int* | arrowTextColor | Цвет текста стрелки комбо-бокса | +| *int* | x1 | Координата первой точки линии по оси x | +| *int* | y1 | Координата первой точки линии по оси y | +| *int* | x2 | Координата второй точки линии по оси x | +| *int* | y2 | Координата второй точки линии по оси y | +| *int* | color | Цвет линии | -Создать объект типа "комбо-бокс", позволяющий выбирать объекты из множества перечисленных вариантов. Методика обращения к комбо-боксу схожа с обращением к контекстному меню. +Растеризация отрезка указанного цвета -| Тип свойства | Свойство |Описание | -| ------ | ------ | ------ | -| *function* | :**addItem**( *string* text, *boolean* disabled, *string* shortcut, *int* color )| Добавить в комбо-бокс элемент с указанными параметрами. При параметре disabled элемент не будет реагировать на клики мышью. Каждый элемент может иметь собственный callback-метод .**onTouch** для последующей обработки данных | -| *function* | :**addSeparator**()| Добавить визуальный в комбо-бокс разделитель | -| *table* | .**items** | Таблица элементов комбо-бокса | -| *int* | .**currentItem** | Индекс выбранного элемента комбо-бокса | - -Пример реализации комбо-бокса: - -```lua -local buffer = require("doubleBuffering") -local GUI = require("GUI") - -local mainContainer = GUI.fullScreenContainer() -mainContainer:addChild(GUI.panel(1, 1, mainContainer.width, mainContainer.height, 0x2D2D2D)) - -local comboBox = mainContainer:addChild(GUI.comboBox(2, 2, 30, 3, 0xEEEEEE, 0x2D2D2D, 0xCCCCCC, 0x888888)) -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 - -mainContainer:draw() -buffer.draw(true) -mainContainer:startEventHandling() -``` - -Результат: - -![Imgur](http://i.imgur.com/4oTgrUV.png?1) - -GUI.**menu**( x, y, width, backgroundColor, textColor, backgroundPressedColor, textPressedColor, backgroundTransparency ): *table* menu ------------------------------------------------------------------------- +buffer.**semiPixelCircle**( xCenter, yCenter, radius, color ) +----------------------------------------------------------- | Тип | Аргумент | Описание | | ------ | ------ | ------ | -| *int* | x | Координата объекта по оси x | -| *int* | y | Координата объекта по оси y | -| *int* | width | Ширина объекта | -| *int* | backgroundColor | Цвет фона меню | -| *int* | textColor | Цвет текста меню | -| *int* | backgroundPressedColor | Цвет фона меню при нажатии на элемент | -| *int* | textPressedColor | Цвет текста меню при нажатии на элемент | -| *int* | backgroundTransparency | Прозрачность фона меню | +| *int* | xCenter | Координата центральной точки окружности по оси x | +| *int* | yCenter | Координата центральной точки окружности по оси y | +| *int* | radius | Радиус окружности | +| *int* | color | Цвет окружности | -Создать объект типа "горизонтальное меню", позволяющий выбирать объекты из множества перечисленных вариантов. По большей части применяется в структурах типа "Файл - Редактировать - Вид - Помощь" и подобных. +Растеризация окружности указанного цвета -| Тип свойства | Свойство |Описание | -| ------ | ------ | ------ | -| *function* | :**addItem**( *string* text, *int* color ): *table* item | Добавить в меню элемент с указанными параметрами. Каждый элемент имеет собственный callback-метод .**onTouch** | -| *callback-function* | .**onItemSelected**( *table* item, *table* eventData )| Метод, вызывающийся после выборе какого-либо элемента комбо-бокса | +Вспомогательные методы +====== -Пример реализации меню: +Ниже перечислены методы, используемые самой библиотекой или приложениями, требующими максимального быстродействия и рассчитывающими пиксельные данные буфера вручную. В большинстве случаев они не пригождаются, однако для ознакомления указаны. -```lua -local buffer = require("doubleBuffering") -local GUI = require("GUI") - -local mainContainer = GUI.fullScreenContainer() -mainContainer:addChild(GUI.panel(1, 1, mainContainer.width, mainContainer.height, 0x2D2D2D)) - -local menu = mainContainer:addChild(GUI.menu(1, 1, mainContainer.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") - -mainContainer:draw() -buffer.draw(true) -mainContainer:startEventHandling() -``` - -Результат: - -![Imgur](http://i.imgur.com/jWyVhTP.png?1) - -GUI.**image**( x, y, loadedImage ): *table* image -------------------------------------------------- +buffer.**flush**( [width, height] ) +----------------------------------------------------------- | Тип | Аргумент | Описание | | ------ | ------ | ------ | -| *int* | x | Координата объекта по оси x | -| *int* | y | Координата объекта по оси y | -| *table* | loadedImage | Изображение, загруженное методом *image.load()* | +| *int* | width | Ширина буфера | +| *int* | height | Высота буфера | -Создать объект типа "изображение", представляющий из себя аналог объекта *panel* с тем лишь исключением, что вместо статичного цвета используется загруженное изображение. +Метод, устанавливающий разрешение экранного буфера равным указанному и заполняющий его черными пикселями с символом пробела. В отличие от buffer.**setResolution** не изменяет текущего разрешения GPU. Если опциональные аргументы не указаны, то размер буфера становится эквивалентным текущему разрешению GPU. -| Тип свойства | Свойство |Описание | -| ------ | ------ | ------ | -| *callback-function* | .**onTouch**( *table* eventData )| Метод, вызываемый после нажатия на изображение в обработчике событий | -| *table* | .**image**| Таблица пиксельных данных изображения | - -Пример реализации изображения: - -```lua -local image = require("image") -local buffer = require("doubleBuffering") -local GUI = require("GUI") - -local mainContainer = GUI.fullScreenContainer() -mainContainer:addChild(GUI.panel(1, 1, mainContainer.width, mainContainer.height, 0x0)) - -mainContainer:addChild(GUI.image(2, 2, image.load("/Furnance.pic"))) - -mainContainer:draw() -buffer.draw(true) -mainContainer:startEventHandling() -``` - -Результат: - -![enter image description here](http://i91.fastpic.ru/big/2017/0402/80/3b0ec81c3b2f660b9a4c6f18908f4280.png) - -GUI.**progressBar**( x, y, width, primaryColor, secondaryColor, valueColor, value, [thin, showValue, valuePrefix, valuePostfix] ): *table* progressBar ------------------------------------------------------------------------- +buffer.**getBufferIndexByCoordinates**( x, y ): int index +----------------------------------------------------------- | Тип | Аргумент | Описание | | ------ | ------ | ------ | -| *int* | x | Координата объекта по оси x | -| *int* | y | Координата объекта по оси y | -| *int* | width | Ширина объекта | -| *int* | primaryColor | Основной цвет шкалы прогресса | -| *int* | secondaryColor | Вторичный цвет шкалы прогресса | -| *int* | valueColor | Цвет текста значений шкалы прогресса | -| *float* | value | Значение шкалы прогресса | -| [*bool* | thin] | Активировать ли режим отрисовки "тонкого" объекта | -| [*bool* | showValue] | Показывать ли значение шкалы прогресса | -| [*string* | valuePrefix] | Префикс для значения шкалы прогресса | -| [*string* | valuePostfix] | Постфикс для значения шкалы прогресса | +| *int* | x | Координата пикселя экрана по оси x | +| *int* | y | Координата пикселя экрана по оси y | -Создать объект типа "шкала прогресса", значение которой меняется от 0 до 100. +Метод, преобразующий экранные координаты в индекс экраннного буфера. К примеру, пиксель 2x1 имеет индекс буфера 4, а пиксель 3x1 имеет индекс буфера 7. -| Тип свойства | Свойство |Описание | -| ------ | ------ | ------ | -| *int* | .**value**| Текущее числовое значение шкалы прогресса | - -Пример реализации шкалы прогресса: - -```lua -local buffer = require("doubleBuffering") -local GUI = require("GUI") - -local mainContainer = GUI.fullScreenContainer() -mainContainer:addChild(GUI.panel(1, 1, mainContainer.width, mainContainer.height, 0x0)) - -mainContainer:addChild(GUI.progressBar(2, 2, 50, 0x3366CC, 0xEEEEEE, 0xEEEEEE, 80, true, true, "Value prefix: ", " value postfix")) - -mainContainer:draw() -buffer.draw(true) -mainContainer:startEventHandling() -``` - -Результат: - -![enter image description here](http://i89.fastpic.ru/big/2017/0402/f1/ef1da27531ccf899eb9eb59c010180f1.png) - -GUI.**scrollBar**( x, y, width, height, backgroundColor, foregroundColor, minimumValue, maximumValue, value, shownValueCount, onScrollValueIncrement, thinHorizontalMode ): *table* scrollBar ------------------------------------------------------------------------- +buffer.**getBufferCoordinatesByIndex**( index ): int x, int y +----------------------------------------------------------- | Тип | Аргумент | Описание | | ------ | ------ | ------ | -| *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 в полупиксельном виде при горизонтальной ориентации | +| *int* | index | Индекс экранного буфера | -Создать объект типа "ScrollBar", предназначенный для визуальной демонстрации числа показанных объектов на экране. Сам по себе практически не используется, полезен в совокупности с другими виджетами. +Метод, преобразующий индекс буфера в соответствующие ему координаты на экране. -| Тип свойства | Свойство |Описание | -| ------ | ------ | ------ | -| *callback-function* | .**onTouch**( *table* eventData )| Метод, вызываемый при клике на скорллбар. Значение скроллбара будет изменяться автоматически в указанном диапазоне | -| *callback-function* | .**onScroll**( *table* eventData )| Метод, вызываемый при использовании колеса мыши на скроллбаре. Значение скроллбара будет изменяться в зависимости от величины *.onScrollValueIncrement* | +buffer.**rawSet**( index, background, foreground, symbol ) +----------------------------------------------------------- +| *int* | index | Индекс экранного буфера | +| *int* | background | Цвет фона | +| *int* | foreground | Цвет символа | +| *char* | symbol | Символ | -Пример реализации ScrollBar: +Метод, устанавливающий соответствующие значения цветов и символа пикселю с указанным индексом. -```lua -local buffer = require("doubleBuffering") -local GUI = require("GUI") +buffer.**rawGet**( index ): int background, int foreground, char symbol +----------------------------------------------------------- +| *int* | index | Индекс экранного буфера | -local mainContainer = GUI.fullScreenContainer() -mainContainer:addChild(GUI.panel(1, 1, mainContainer.width, mainContainer.height, 0x0)) - -local scrollBar = mainContainer:addChild(GUI.scrollBar(2, 2, 1, 30, 0xEEEEEE, 0x3366CC, 1, 100, 1, 10, 1, false)) -scrollBar.onTouch = function() - -- Do something on scrollBar touch -end - -mainContainer:draw() -buffer.draw(true) -mainContainer:startEventHandling() -``` - -Результат: - -![enter image description here](http://i89.fastpic.ru/big/2017/0402/90/b78e291e777f9bcb84802ef6451bc790.png) - -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**| Таблица со строковыми данными текстбокса | - -Пример реализации текстбокса: - -```lua -local buffer = require("doubleBuffering") -local GUI = require("GUI") - -local mainContainer = GUI.fullScreenContainer() -mainContainer:addChild(GUI.panel(1, 1, mainContainer.width, mainContainer.height, 0x0)) - -local textBox = mainContainer:addChild(GUI.textBox(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 - -mainContainer:draw() -buffer.draw(true) -mainContainer:startEventHandling() -``` - -Результат: - -![enter image description here](http://i89.fastpic.ru/big/2017/0402/ad/01cdcf7aec919051f64ac2b7d9daf0ad.png) - - -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: - -```lua -local buffer = require("doubleBuffering") -local GUI = require("GUI") - -local mainContainer = GUI.fullScreenContainer() -mainContainer:addChild(GUI.panel(1, 1, mainContainer.width, mainContainer.height, 0x0)) - -local treeView = mainContainer:addChild(GUI.treeView(2, 2, 30, 41, 0xCCCCCC, 0x2D2D2D, 0x3C3C3C, 0xEEEEEE, 0x666666, 0xEEEEEE, 0x3366CC, "/")) -treeView.onFileSelected = function(filePath) - -- Do something when file was selected -end - -mainContainer:draw() -buffer.draw(true) -mainContainer:startEventHandling() - -``` - -Результат: - -![enter image description here](http://i89.fastpic.ru/big/2017/0402/d2/25b46010c6050d65ed4894c9092a0fd2.png) - -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: - -```lua -local buffer = require("doubleBuffering") -local GUI = require("GUI") -local unicode = require("unicode") - -local mainContainer = GUI.fullScreenContainer() -mainContainer:addChild(GUI.panel(1, 1, mainContainer.width, mainContainer.height, 0x0)) - -local codeView = mainContainer: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() - -mainContainer:draw() -buffer.draw(true) -mainContainer:startEventHandling() -``` - -Результат: - -![enter image description here](http://i89.fastpic.ru/big/2017/0402/a9/a00b12a34bf367940dccde93d28b03a9.png) - -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: - -```lua -local buffer = require("doubleBuffering") -local GUI = require("GUI") - -local mainContainer = GUI.fullScreenContainer() -mainContainer:addChild(GUI.panel(1, 1, mainContainer.width, mainContainer.height, 0x0)) - -local chart = mainContainer:addChild(GUI.chart(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 - -mainContainer:draw() -buffer.draw(true) -mainContainer:startEventHandling() - -``` - -Результат: - -![enter image description here](http://i91.fastpic.ru/big/2017/0402/5b/66ff353492298f6a0c9b01c0fc8a525b.png) +Метод, возвращающий соответствующие значения цветов и символа пикселя с указанным индексом. Практический пример #1 ====== - В качестве стартового примера возьмем простейшую задачу: расположим на экране 5 кнопок по вертикали и заставим их показывать окно с порядковым номером этой кнопки при нажатии на нее. Напишем следующий код: - ```lua --- Подключаем необходимые библиотеки +-- Подключаем библиотеку local buffer = require("doubleBuffering") -local GUI = require("GUI") --- Создаем полноэкранный контейнер -local mainContainer = GUI.fullScreenContainer() --- Добавляем на окно темно-серую панель по всей его ширине и высоте -mainContainer:addChild(GUI.panel(1, 1, mainContainer.width, mainContainer.height, 0x2D2D2D)) - --- Создаем 5 объектов-кнопок, располагаемых все ниже и ниже -local y = 2 -for i = 1, 5 do - -- При нажатии на конкретную кнопку будет вызван указанный метод .onTouch() - mainContainer:addChild(GUI.button(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 +-- Рисуем 10 квадратиков, заполненных произвольным цветом +local x, y, xStep, yStep = 2, 2, 4, 2 +for i = 1, 10 do + buffer.square(x, y, 6, 3, math.random(0x0, 0xFFFFFF), 0x0, " ") + x, y = x + xStep, y + yStep end --- Отрисовываем содержимое окно -mainContainer:draw() --- Отрисовываем содержимое экранного буфера +-- Рисуем черную окружность +buffer.semiPixelCircle(22, 22, 10, 0x0) +-- Рисуем белую линию +buffer.semiPixelLine(2, 36, 35, 3, 0xFFFFFF) + +-- Выводим содержимое буфера на экран buffer.draw() --- Активируем режим обработки событий -mainContainer:startEventHandling() -``` -При нажатии на любую из созданных кнопок будет показываться дебаг-окно с информацией, указанной в методе *.onTouch*: - -![enter image description here](http://i90.fastpic.ru/big/2017/0402/32/90656de1b96b157284fb21e2467d9632.png) - -![enter image description here](http://i91.fastpic.ru/big/2017/0402/c3/e02d02fb39a28dd17220b535e59292c3.png) - -Практический пример #2 -====== - -Поскольку в моде OpenComputers имеется интернет-плата, я написал небольшой клиент для работы с VK.com. Разумеется, для этого необходимо реализовать авторизацию на серверах, вводя свой e-mail/номер телефона и пароль к аккаунту. В качестве тренировки привожу часть кода, отвечающую за это. - -```lua --- Подключаем библиотеки -local image = require("image") -local buffer = require("doubleBuffering") -local GUI = require("GUI") - --- Создаем контейнер с синей фоновой панелью -local mainContainer = GUI.fullScreenContainer() -mainContainer:addChild(GUI.panel(1, 1, mainContainer.width, mainContainer.height, 0x002440)) - --- Указываем размеры полей ввода текста и кнопок -local elementWidth, elementHeight = 40, 3 -local x, y = math.floor(mainContainer.width / 2 - elementWidth / 2), math.floor(mainContainer.height / 2) - 2 - --- Загружаем и добавляем изображение логотипа "нашей компании" -local logotype = image.load("/MineOS/Applications/VK.app/Resources/VKLogo.pic") -mainContainer:addChild(GUI.image(math.floor(mainContainer.width / 2 - image.getWidth(logotype) / 2) - 2, y - image.getHeight(logotype) - 1, logotype)); y = y + 2 - --- Создаем поле для ввода адреса почты -local emailTextBox = mainContainer:addChild(GUI.inputTextBox(x, y, elementWidth, elementHeight, 0xEEEEEE, 0x777777, 0xEEEEEE, 0x2D2D2D, nil, "E-mail", false, nil, nil, nil)) --- Создаем красный текстовый лейбл, показывающийся только в том случае, когда адрес почты неверен -local invalidEmailLabel = mainContainer:addChild(GUI.label(emailTextBox.localPosition.x + emailTextBox.width + 2, y + 1, mainContainer.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 - mainContainer:draw() - buffer.draw() -end --- Создаем поле для ввода пароля -mainContainer:addChild(GUI.inputTextBox(x, y, elementWidth, elementHeight, 0xEEEEEE, 0x777777, 0xEEEEEE, 0x2D2D2D, nil, "Password", false, "*", nil, nil)); y = y + elementHeight + 1 - --- Добавляем малоприметную кнопку для закрытия программы -mainContainer:addChild(GUI.button(mainContainer.width, 1, 1, 1, 0x002440, 0xEEEEEE, 0x002440, 0xAAAAAA, "X")).onTouch = function() - mainContainer:stopEventHandling() - buffer.clear(0x0) - buffer.draw(true) -end - --- Добавляем кнопку для логина -mainContainer:addChild(GUI.button(x, y, elementWidth, elementHeight, 0x666DFF, 0xEEEEEE, 0xEEEEEE, 0x666DFF, "Login")).onTouch = function() - -- Код, выполняемый при успешном логине -end - -mainContainer:draw() -buffer.draw(true) -mainContainer:startEventHandling() ``` -Результат: +Результат: -![enter image description here](http://i.imgur.com/PT0AUGR.png?1) - -![enter image description here](http://i.imgur.com/dphuFtb.png?1) - -![enter image description here](http://i.imgur.com/LXfsT0o.png?1) - -Практический пример #3 -====== - -Для демонстрации возможностей библиотеки предлагаю создать кастомный виджет с нуля. К примеру, создать панель, реагирующую на клики мыши, позволяющую рисовать на ней произвольным цветом по аналогии со школьной доской. - -```lua -local buffer = require("doubleBuffering") -local GUI = require("GUI") - ---------------------------------------------------------------------- - --- Создаем полноэкранный контейнер -local mainContainer = GUI.fullScreenContainer() - --- Создаем метод-обработчик событий для нашего виджета --- Грамотнее будет вынести его создание вне функции-конструктора, дабы не засорять память -local function myWidgetEventHandler(mainContainer, object, eventData) - if eventData[1] == "touch" or eventData[1] == "drag" then - 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 - - mainContainer:draw() - buffer.draw() - end -end - --- Создаем метод, возвращающий кастомный виджет -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.eventHandler = myWidgetEventHandler - - return object -end - --- Добавляем темно-серую панель в контейнер -mainContainer:addChild(GUI.panel(1, 1, mainContainer.width, mainContainer.height, 0x2D2D2D)) --- Создаем экземпляр виджета-рисовалки и добавляем его в контейнер -mainContainer:addChild(createMyWidget(2, 2, 32, 16, 0x3C3C3C, 0xEEEEEEE)) - -mainContainer:draw() -buffer.draw(true) -mainContainer:startEventHandling() -``` ---------------------------------------------------------------------- -При нажатии на левую кнопку мыши в нашем виджете устанавливается пиксель указанного цвета, а на правую - удаляется. - -![enter image description here](http://i89.fastpic.ru/big/2017/0402/fd/be80c13085824bebf68f64a329e226fd.png) - -Для разнообразия модифицируем код, создав несколько виджетов с рандомными цветами: -```lua -local x = 2 -for i = 1, 5 do - mainContainer:addChild(createMyWidget(x, 2, 32, 16, math.random(0x0, 0xFFFFFF), math.random(0x0, 0xFFFFFF))) - x = x + 34 -end -``` - -В результате получаем 5 индивидуальных экземпляров виджета рисования: - -![enter image description here](http://i90.fastpic.ru/big/2017/0402/96/96aba372bdb3c1e61007170132f00096.png) - -Как видите, в создании собственных виджетов нет совершенно ничего сложного, главное - обладать информацией по наиболее эффективной работе с библиотекой. - -Практический пример #4 -====== - -Предлагаю немного попрактиковаться в использовании layout. В качестве примера создадим контейнер-окно, в котором нам не придется ни разу вручную считать координаты при измененнии его размеров. - -```lua -local buffer = require("doubleBuffering") -local GUI = require("GUI") - ---------------------------------------------------------------------- - --- Создаем полноэкранный контейнер, добавляем темно-серую панель -local mainContainer = GUI.fullScreenContainer() -mainContainer:addChild(GUI.panel(1, 1, mainContainer.width, mainContainer.height, 0x2D2D2D)) - --- Добавляем в главный контенер другой контейнер, который и будет нашим окошком -local window = mainContainer:addChild(GUI.container(2, 2, 80, 25)) --- Добавляем в контейнер-окно светло-серую фоновую панель -local backgroundPanel = window:addChild(GUI.panel(1, 1, window.width, window.height, 0xCCCCCC)) --- Добавляем layout размером 3x1 чуть меньший, чем размер окна -local layout = window:addChild(GUI.layout(3, 2, window.width - 4, window.height - 2, 3, 1)) - --- В ячейку 2х1 добавляем загруженное изображение и label с определенным текстом -layout:setCellPosition(2, 1, layout:addChild(GUI.image(1, 1, image.load("/MineOS/System/OS/Icons/Steve.pic")))) -layout:setCellPosition(2, 1, layout:addChild(GUI.label(1, 1, 10, 1, 0x0, "Картиночка" ):setAlignment(GUI.alignment.horizontal.center, GUI.alignment.vertical.top))) --- В ячейке 2х1 задаем вертикальную ориентацию объектов и расстояние между ними в 1 пиксель -layout:setCellDirection(2, 1, GUI.directions.vertical) -layout:setCellSpacing(2, 1, 1) - --- В ячейку 3х1 добавляем 3 кнопки -layout:setCellPosition(3, 1, layout:addChild(GUI.adaptiveButton(1, 1, 3, 0, 0xFFFFFF, 0x000000, 0x444444, 0xFFFFFF, "Подробности"))) -layout:setCellPosition(3, 1, layout:addChild(GUI.adaptiveButton(1, 1, 3, 0, 0xFFFFFF, 0x000000, 0x444444, 0xFFFFFF, "Отмена"))) -layout:setCellPosition(3, 1, layout:addChild(GUI.adaptiveButton(1, 1, 3, 0, 0x3392FF, 0xFFFFFF, 0x444444, 0xFFFFFF, "OK"))).onTouch = function() - -- При нажатии на кнопку "ОК" наше окно растянется на 10 пикселей - window.width, backgroundPanel.width, layout.width = window.width + 10, backgroundPanel.width + 10, layout.width + 10 - mainContainer:draw() - buffer.draw() -end --- В ячейке 3x1 задаем горизонтальную ориентацию объектов, расстояние между ними в 2 пикселя, а также выравнивание по правому верхнему краю -layout:setCellDirection(3, 1, GUI.directions.horizontal) -layout:setCellSpacing(3, 1, 2) -layout:setCellAlignment(3, 1, GUI.alignment.horizontal.right, GUI.alignment.vertical.bottom) - -mainContainer:draw() -buffer.draw(true) -mainContainer:startEventHandling() -``` - -В результате получаем симпатичное окошко с тремя кнопками, автоматически расположенными в его правой части: - -![Imgur](http://i.imgur.com/b3CmBfS.png?1) - -Если несколько раз нажать на кнопку "ОК", то окошко растянется, однако все объекты останутся на законных местах. Причем без каких-либо хардкорных расчетов вручную: - -![Imgur](http://i.imgur.com/JQ2togt.png?1) \ No newline at end of file +![Imgur](http://i.imgur.com/4jxCxXG.png) \ No newline at end of file