From 05b68b261edcf9d24e24ac419aec9e7f0dc8f3a0 Mon Sep 17 00:00:00 2001 From: igor Date: Wed, 3 Jan 2018 00:42:55 +0300 Subject: [PATCH] =?UTF-8?q?=D0=9F=D0=B5=D1=80=D0=B5=D1=85=D0=BE=D0=B4?= =?UTF-8?q?=D0=B8=D0=BC=20=D0=BD=D0=B0=20=D0=B0=D0=BD=D0=B8=D0=BC=D0=B8?= =?UTF-8?q?=D1=80=D0=BE=D0=B2=D0=B0=D0=BD=D0=BD=D1=8B=D0=B5=20=D0=BA=D0=BD?= =?UTF-8?q?=D0=BE=D0=BF=D0=BA=D0=B8,=20=D0=BC=D0=BE=D0=B3=D1=83=D1=82=20?= =?UTF-8?q?=D0=B1=D1=8B=D1=82=D1=8C=20=D0=B1=D0=B0=D0=B3=D0=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Applications.cfg | 23 +-- Applications/Stargate/Main.lua | 13 +- Documentation/GUI.md | 12 +- lib/GUI.lua | 282 ++++++++++++++++++++------------- lib/color.lua | 39 ++--- lib/palette.lua | 4 +- 6 files changed, 206 insertions(+), 167 deletions(-) diff --git a/Applications.cfg b/Applications.cfg index 781f2973..15e20a57 100644 --- a/Applications.cfg +++ b/Applications.cfg @@ -279,7 +279,7 @@ url="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/lib/color.lua", type="Library", preloadFile=true, - version=1.11, + version=1.12, }, { path="/lib/FormatModules/OCIF.lua", @@ -319,7 +319,7 @@ url="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/lib/GUI.lua", type="Library", preloadFile=true, - version=2.05, + version=2.06, }, { path="/lib/rayEngine.lua", @@ -355,7 +355,7 @@ path="/lib/palette.lua", url="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/lib/palette.lua", type="Library", - version=1.22, + version=1.23, }, { path="/lib/doubleBuffering.lua", @@ -595,21 +595,6 @@ } }, }, - { - path="/MineOS/Applications/VK", - url="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/Applications/VK/Main.lua", - about="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/Applications/VK/About/", - type="Application", - icon="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/Applications/VK/Icon.pic", - createShortcut=true, - version=1.39, - resources={ - { - path="/VKLogo.pic", - url="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/Applications/VK/VKLogo.pic", - }, - }, - }, { path="/MineOS/Applications/Finder", url="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/Applications/Finder/Main.lua", @@ -828,7 +813,7 @@ type="Application", icon="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/Applications/Stargate/Icon.pic", createShortcut=true, - version=1.14, + version=1.15, resources={ { path="/Ch1.pic", diff --git a/Applications/Stargate/Main.lua b/Applications/Stargate/Main.lua index 16f4955f..7de608d2 100755 --- a/Applications/Stargate/Main.lua +++ b/Applications/Stargate/Main.lua @@ -163,6 +163,7 @@ mainContainer:addChild(newThing(mainContainer.SGImage.localX + mainContainer.SGI mainContainer:addChild(GUI.label(x, y, width, 1, 0xEEEEEE, "Stargate " .. stargate.localAddress())):setAlignment(GUI.alignment.horizontal.center, GUI.alignment.vertical.top); y = y + 1 mainContainer.connectedToLabel = mainContainer:addChild(GUI.label(x, y, width, 1, 0x555555, "(Not connected)")):setAlignment(GUI.alignment.horizontal.center, GUI.alignment.vertical.top); y = y + 2 mainContainer.connectionButton = mainContainer:addChild(GUI.framedButton(x, y, width, 3, 0xEEEEEE, 0xEEEEEE, 0xBBBBBB, 0xBBBBBB, "Connect")); y = y + 3 +-- mainContainer.connectionButton.animated = false mainContainer.connectionButton.onTouch = function() if stargate.stargateState() == "Idle" then local container = MineOSInterface.addUniversalContainer(mainContainer, "Connect") @@ -179,8 +180,10 @@ mainContainer.connectionButton.onTouch = function() end end - container.panel.eventHandler = function() - input.onInputFinished() + container.panel.eventHandler = function(mainContainer, object, eventData) + if eventData[1] == "touch" then + input.onInputFinished() + end end mainContainer:draw() @@ -213,8 +216,10 @@ mainContainer.messageContactButton.onTouch = function() end end - container.panel.eventHandler = function() - input.onInputFinished() + container.panel.eventHandler = function(mainContainer, object, eventData) + if eventData[1] == "touch" then + input.onInputFinished() + end end mainContainer:draw() diff --git a/Documentation/GUI.md b/Documentation/GUI.md index 3d69f945..561e0e01 100644 --- a/Documentation/GUI.md +++ b/Documentation/GUI.md @@ -554,9 +554,9 @@ GUI.**button**( x, y, width, height, buttonColor, textColor, buttonPressedColor, | *int* | textPressedColor | Цвет текста при нажатии | | *string* | text | Текст на кнопке | -Создать объект типа "кнопка". Каждая кнопка имеет два состояния (*isPressed = true/false*), автоматически переключаемые методом-обработчиком .*eventHandler*. Для назначения какого-либо действия кнопке после ее нажатия создайте для нее метод *.onTouch()*. +Создать объект типа "кнопка". Каждая кнопка имеет два состояния (*pressed = true/false*), автоматически переключаемые при нажатии. Для назначения какого-либо действия кнопке после ее нажатия создайте для нее метод *.onTouch()*. -Существует два дополнительных виджета кнопки, имеющие визуально разные стили: +Существует два дополнительных варианта кнопки, имеющие визуально разные стили: - GUI.**framedButton**(...) отрисовывается с рамкой по краям кнопки @@ -572,10 +572,10 @@ GUI.**button**( x, y, width, height, buttonColor, textColor, buttonPressedColor, | Тип свойства | Свойство |Описание | | ------ | ------ | ------ | -| *callback-function* | .**onTouch**( *table* eventData )| Метод, вызываемый после нажатия кнопки в обработчике событий | -| *function* | :**press**()| Изменить состояние кнопки на "нажатое" | -| *function* | :**release**()| Изменить состояние кнопки на "отжатое" | -| *function* | :**pressAndRelease**( *float* time )| Нажать и отжать кнопку в течение указанного временного периода. Примечание: этот метод использует отрисовку содержимого двойного буфера | +| *callback-function* | .**onTouch**( *table* eventData )| Метод, вызываемый после нажатия на кнопку | +| *boolean* | .**pressed**| Параметр, отвечающий за состояние "нажатости" кнопки | +| *boolean* | .**switchMode**| Режим, при котором кнопка будет вести себя как переключатель: при нажатии она будет изменять свое состояние на противоположное. По умолчанию имеет значение *false* | +| *boolean* | .**animated**| Параметр, отвечающий за активность анимации перехода цветов кнопки при нажатии. По умолчанию имеет значение *true* | Пример реализации кнопки: ```lua diff --git a/lib/GUI.lua b/lib/GUI.lua index 8a4e8fa6..bc46fac9 100755 --- a/lib/GUI.lua +++ b/lib/GUI.lua @@ -5,6 +5,7 @@ local keyboard = require("keyboard") local fs = require("filesystem") local unicode = require("unicode") local event = require("event") +local color = require("color") local image = require("image") local buffer = require("doubleBuffering") @@ -234,9 +235,7 @@ local function containerObjectAnimationDelete(animation) end local function containerObjectAddAnimation(object, frameHandler, onFinish) - local firstParent = object:getFirstParent() - firstParent.animations = firstParent.animations or {} - table.insert(firstParent.animations, { + local animation = { object = object, position = 0, start = containerObjectAnimationStart, @@ -244,9 +243,13 @@ local function containerObjectAddAnimation(object, frameHandler, onFinish) delete = containerObjectAnimationDelete, frameHandler = frameHandler, onFinish = onFinish, - }) + } - return firstParent.animations[#firstParent.animations] + local firstParent = object:getFirstParent() + firstParent.animations = firstParent.animations or {} + table.insert(firstParent.animations, animation) + + return animation end function GUI.addChildToContainer(container, object, atIndex) @@ -402,6 +405,10 @@ local function containerStartEventHandling(container, eventHandlingDelay) if animation.deleteLater then table.remove(container.animations, animationIndex) + if #container.animations == 0 then + container.animations = nil + break + end else if animation.started then animationNeedDraw = true @@ -468,152 +475,199 @@ end ----------------------------------------- Buttons ----------------------------------------- -local function buttonDraw(object) - local xText, yText = GUI.getAlignmentCoordinates(object, {width = unicode.len(object.text), height = 1}) - - local buttonColor, textColor = object.colors.default.background, object.colors.default.text - if object.disabled then - buttonColor, textColor = object.colors.disabled.background, object.colors.disabled.text - else - if object.pressed then - buttonColor, textColor = object.colors.pressed.background, object.colors.pressed.text - end - end - - if buttonColor then - if object.buttonType == 1 then - buffer.square(object.x, object.y, object.width, object.height, buttonColor, textColor, " ") - elseif object.buttonType == 2 then - local x2, y2 = object.x + object.width - 1, object.y + object.height - 1 - - if object.height > 1 then - buffer.text(object.x + 1, object.y, buttonColor, string.rep("▄", object.width - 2)) - buffer.text(object.x, object.y, buttonColor, "⣠") - buffer.text(x2, object.y, buttonColor, "⣄") - - buffer.square(object.x, object.y + 1, object.width, object.height - 2, buttonColor, textColor, " ") - - buffer.text(object.x + 1, y2, buttonColor, string.rep("▀", object.width - 2)) - buffer.text(object.x, y2, buttonColor, "⠙") - buffer.text(x2, y2, buttonColor, "⠋") +local function buttonPlayAnimation(button, onFinish) + button.animationStarted = true + button:addAnimation( + function(mainContainer, animation) + if button.pressed then + if button.colors.default.background and button.colors.pressed.background then + button.animationCurrentBackground = color.transition(button.colors.pressed.background, button.colors.default.background, animation.position) + end + button.animationCurrentText = color.transition(button.colors.pressed.text, button.colors.default.text, animation.position) else - buffer.square(object.x, object.y, object.width, object.height, buttonColor, textColor, " ") - GUI.roundedCorners(object.x, object.y, object.width, object.height, buttonColor) + if button.colors.default.background and button.colors.pressed.background then + button.animationCurrentBackground = color.transition(button.colors.default.background, button.colors.pressed.background, animation.position) + end + button.animationCurrentText = color.transition(button.colors.default.text, button.colors.pressed.text, animation.position) end - else - buffer.frame(object.x, object.y, object.width, object.height, buttonColor) + end, + function(mainContainer, animation) + button.animationStarted = false + button.pressed = not button.pressed + onFinish(mainContainer, animation) end - end - - buffer.text(xText, yText, textColor, object.text) - - return object + ):start(button.animationDuration) end -local function buttonPress(object) - object.pressed = true - buttonDraw(object) -end - -local function buttonRelease(object) - object.pressed = nil - buttonDraw(object) -end - -local function buttonPressAndRelease(object, pressTime) - buttonPress(object) - buffer.draw() - os.sleep(pressTime or 0.2) - buttonRelease(object) - buffer.draw() -end - -local function buttonEventHandler(mainContainer, object, eventData) +local function buttonEventHandler(mainContainer, button, eventData) if eventData[1] == "touch" then - if object.switchMode then - object.pressed = not object.pressed - mainContainer:draw() - buffer.draw() - callMethod(object.onTouch, mainContainer, object, eventData) + if button.animated then + buttonPlayAnimation(button, function(mainContainer, animation) + if button.onTouch then + button.onTouch(mainContainer, button, eventData) + end + + animation:delete() + + if not button.switchMode then + buttonPlayAnimation(button, function(mainContainer, animation) + animation:delete() + end) + end + end) else - object.pressed = true - mainContainer:draw() - buffer.draw() - os.sleep(0.2) - object.pressed = false - mainContainer:draw() - buffer.draw() - callMethod(object.onTouch, mainContainer, object, eventData) + button.pressed = not button.pressed + + if button.switchMode then + mainContainer:draw() + buffer.draw() + else + mainContainer:draw() + buffer.draw() + button.pressed = not button.pressed + + os.sleep(0.2) + + mainContainer:draw() + buffer.draw() + end + + if button.onTouch then + button.onTouch(mainContainer, button, eventData) + end end end end -local function buttonCreate(buttonType, x, y, width, height, buttonColor, textColor, buttonPressedColor, textPressedColor, text, disabledState) - local object = GUI.object(x, y, width, height) +local function buttonGetColors(button) + if button.disabled then + return button.colors.disabled.background, button.colors.disabled.text + else + if button.animated and button.animationStarted then + return button.animationCurrentBackground, button.animationCurrentText + else + if button.pressed then + return button.colors.pressed.background, button.colors.pressed.text + else + return button.colors.default.background, button.colors.default.text + end + end + end +end - object.colors = { +local function buttonDrawText(button, textColor) + buffer.text(math.floor(button.x + button.width / 2 - unicode.len(button.text) / 2), math.floor(button.y + button.height / 2), textColor, button.text) +end + +local function buttonDraw(button) + local backgroundColor, textColor = buttonGetColors(button) + if backgroundColor then + buffer.square(button.x, button.y, button.width, button.height, backgroundColor, textColor, " ") + end + + buttonDrawText(button, textColor) +end + +local function framedButtonDraw(button) + local backgroundColor, textColor = buttonGetColors(button) + if backgroundColor then + buffer.frame(button.x, button.y, button.width, button.height, backgroundColor) + end + + buttonDrawText(button, textColor) +end + +local function roundedButtonDraw(button) + local backgroundColor, textColor = buttonGetColors(button) + + if backgroundColor then + local x2, y2 = button.x + button.width - 1, button.y + button.height - 1 + if button.height > 1 then + buffer.text(button.x + 1, button.y, backgroundColor, string.rep("▄", button.width - 2)) + buffer.text(button.x, button.y, backgroundColor, "⣠") + buffer.text(x2, button.y, backgroundColor, "⣄") + + buffer.square(button.x, button.y + 1, button.width, button.height - 2, backgroundColor, textColor, " ") + + buffer.text(button.x + 1, y2, backgroundColor, string.rep("▀", button.width - 2)) + buffer.text(button.x, y2, backgroundColor, "⠙") + buffer.text(x2, y2, backgroundColor, "⠋") + else + buffer.square(button.x, button.y, button.width, button.height, backgroundColor, textColor, " ") + GUI.roundedCorners(button.x, button.y, button.width, button.height, backgroundColor) + end + end + + buttonDrawText(button, textColor) +end + +local function buttonCreate(x, y, width, height, backgroundColor, textColor, backgroundPressedColor, textPressedColor, text) + local button = GUI.object(x, y, width, height) + + button.colors = { default = { - background = buttonColor, + background = backgroundColor, text = textColor }, pressed = { - background = buttonPressedColor, + background = backgroundPressedColor, text = textPressedColor }, disabled = { background = GUI.colors.disabled.background, - text = GUI.colors.disabled.text, + text = GUI.colors.disabled.text } } + button.animationCurrentBackground = backgroundColor + button.animationCurrentText = textColor - object.eventHandler = buttonEventHandler - object.buttonType = buttonType - object.disabled = disabledState - object.text = text - object.press = buttonPress - object.release = buttonRelease - object.pressAndRelease = buttonPressAndRelease - object.draw = buttonDraw - object.setAlignment = GUI.setAlignment - object:setAlignment(GUI.alignment.horizontal.center, GUI.alignment.vertical.center) + button.text = text + button.animationDuration = 0.2 + button.animated = true + button.pressed = false + + button.eventHandler = buttonEventHandler + return button +end - return object +local function adaptiveButtonCreate(x, y, xOffset, yOffset, backgroundColor, textColor, backgroundPressedColor, textPressedColor, text) + return buttonCreate(x, y, unicode.len(text) + xOffset * 2, yOffset * 2 + 1, backgroundColor, textColor, backgroundPressedColor, textPressedColor, text) end function GUI.button(...) - return buttonCreate(1, ...) + local button = buttonCreate(...) + button.draw = buttonDraw + return button end -function GUI.adaptiveButton(x, y, xOffset, yOffset, buttonColor, textColor, buttonPressedColor, textPressedColor, text, ...) - return buttonCreate(1, x, y, unicode.len(text) + xOffset * 2, yOffset * 2 + 1, buttonColor, textColor, buttonPressedColor, textPressedColor, text, ...) -end - -function GUI.roundedButton(...) - return buttonCreate(2, ...) -end - -function GUI.adaptiveRoundedButton(x, y, xOffset, yOffset, buttonColor, textColor, buttonPressedColor, textPressedColor, text, ...) - return buttonCreate(2, x, y, unicode.len(text) + xOffset * 2, yOffset * 2 + 1, buttonColor, textColor, buttonPressedColor, textPressedColor, text, ...) +function GUI.adaptiveButton(...) + local button = adaptiveButtonCreate(...) + button.draw = buttonDraw + return button end function GUI.framedButton(...) - return buttonCreate(3, ...) + local button = buttonCreate(...) + button.draw = framedButtonDraw + return button end -function GUI.adaptiveFramedButton(x, y, xOffset, yOffset, buttonColor, textColor, buttonPressedColor, textPressedColor, text, ...) - return buttonCreate(3, x, y, unicode.len(text) + xOffset * 2, yOffset * 2 + 1, buttonColor, textColor, buttonPressedColor, textPressedColor, text, ...) +function GUI.adaptiveFramedButton(...) + local button = adaptiveButtonCreate(...) + button.draw = framedButtonDraw + return button end -function GUI.adaptiveTexturedButton(x, y, defaultTexture, pressedTexture) - local button = buttonCreate(4, x, y, defaultTexture[1], defaultTexture[2], 0x0, 0x0, 0x0, 0x0, "") - - button.defaultTexture = defaultTexture - button.pressedTexture = pressedTexture - button.draw = function(button) - buffer.image(button.x, button.y, button.pressed and button.pressedTexture or button.defaultTexture) - end +function GUI.roundedButton(...) + local button = buttonCreate(...) + button.draw = roundedButtonDraw + return button +end +function GUI.adaptiveRoundedButton(...) + local button = adaptiveButtonCreate(...) + button.draw = roundedButtonDraw return button end @@ -707,6 +761,7 @@ end local function menuAddItem(menu, text, textColor) local x = 2; for i = 1, #menu.children do x = x + unicode.len(menu.children[i].text) + 2; end local item = menu:addChild(GUI.adaptiveButton(x, 1, 1, 0, nil, textColor or menu.colors.default.text, menu.colors.pressed.background, menu.colors.pressed.text, text)) + item.animated = false item.eventHandler = menuItemEventHandler return item @@ -3429,6 +3484,7 @@ end local function tabBarAddItem(tabBar, text) local item = tabBar:addChild(GUI.button(1, 1, unicode.len(text) + tabBar.horizontalTabOffset * 2, tabBar.height, tabBar.colors.default.background, tabBar.colors.default.text, tabBar.colors.selected.background, tabBar.colors.selected.text, text)) + item.animated = false item.switchMode = true item.eventHandler = tabBarTabEventHandler diff --git a/lib/color.lua b/lib/color.lua index 52a054f6..eadd0078 100755 --- a/lib/color.lua +++ b/lib/color.lua @@ -76,13 +76,13 @@ end ----------------------------------------------------------------------------------------------------------------------- local function blend(firstColor, secondColor, secondColorTransparency) - local invertedTransparency, firstColorR, firstColorG, firstColorB = 1 - secondColorTransparency, HEXToRGB(firstColor) - local secondColorR, secondColorG, secondColorB = HEXToRGB(secondColor) + local invertedTransparency, r1, g1, b1 = 1 - secondColorTransparency, HEXToRGB(firstColor) + local r2, g2, b2 = HEXToRGB(secondColor) return RGBToHEX( - secondColorR * invertedTransparency + firstColorR * secondColorTransparency, - secondColorG * invertedTransparency + firstColorG * secondColorTransparency, - secondColorB * invertedTransparency + firstColorB * secondColorTransparency + r2 * invertedTransparency + r1 * secondColorTransparency, + g2 * invertedTransparency + g1 * secondColorTransparency, + b2 * invertedTransparency + b1 * secondColorTransparency ) end @@ -95,21 +95,15 @@ end ----------------------------------------------------------------------------------------------------------------------- -local function difference(r1, g1, b1, r2, g2, b2) - return r2 - r1, g2 - g1, b2 - b1 -end +local function transition(color1, color2, position) + local r1, g1, b1 = HEXToRGB(color1) + local r2, g2, b2 = HEXToRGB(color2) -local function sum(r1, g1, b1, r2, g2, b2) - return r2 + r1, g2 + g1, b2 + b1 -end - -local function multiply(r, g, b, multiplyer) - r, g, b = r * multiplyer, g * multiplyer, b * multiplyer - if r > 255 then r = 255 end - if g > 255 then g = 255 end - if b > 255 then b = 255 end - - return r, g, b + return RGBToHEX( + r1 + (r2 - r1) * position, + g1 + (g2 - g1) * position, + b1 + (b2 - b1) * position + ) end local function average(colors) @@ -170,10 +164,9 @@ return { HSBToHEX = HSBToHEX, blend = blend, blendRGBA = blendRGBA, - difference = difference, - sum = sum, - multiply = multiply, - average = average, + + transition = transition, + to8Bit = to8Bit, to24Bit = to24Bit, optimize = optimize, diff --git a/lib/palette.lua b/lib/palette.lua index 93e0fbfd..631b23ad 100755 --- a/lib/palette.lua +++ b/lib/palette.lua @@ -138,8 +138,8 @@ function palette.container(x, y, startColor) end window.colorPanel = window:addChild(GUI.panel(58, 2, 12, 3, 0x0)) - window.OKButton = window:addChild(GUI.roundedButton(58, 6, 12, 1, 0x444444, 0xFFFFFF, 0x88FF88, 0xFFFFFF, "OK")) - window.cancelButton = window:addChild(GUI.roundedButton(58, 8, 12, 1, 0xFFFFFF, 0x444444, 0x88FF88, 0xFFFFFF, "Cancel")) + window.OKButton = window:addChild(GUI.roundedButton(58, 6, 12, 1, 0x444444, 0xFFFFFF, 0x2D2D2D, 0xFFFFFF, "OK")) + window.cancelButton = window:addChild(GUI.roundedButton(58, 8, 12, 1, 0xFFFFFF, 0x444444, 0x2D2D2D, 0xFFFFFF, "Cancel")) local function onAnyInputFinished() refreshBigRainbow(window)