diff --git a/src/devdrivers/keyboard.cpp b/src/devdrivers/keyboard.cpp index 99a44f852..7d53e367e 100644 --- a/src/devdrivers/keyboard.cpp +++ b/src/devdrivers/keyboard.cpp @@ -81,8 +81,6 @@ void Keyboard::begin(bool generateVirtualKeys, bool createVKQueue, int PS2Port) m_capsLockLED = false; m_scrollLockLED = false; - m_uiApp = nullptr; - reset(); enableVirtualKeys(generateVirtualKeys, createVKQueue); @@ -534,11 +532,12 @@ void Keyboard::injectVirtualKey(VirtualKeyItem const & item, bool insert) // has VK queue? Insert VK into it. if (m_virtualKeyQueue) { - auto ticksToWait = (m_uiApp ? 0 : portMAX_DELAY); // 0, and not portMAX_DELAY to avoid uiApp locks - if (insert) + auto ticksToWait = portMAX_DELAY; + if (insert) { xQueueSendToFront(m_virtualKeyQueue, &item, ticksToWait); - else + } else { xQueueSendToBack(m_virtualKeyQueue, &item, ticksToWait); + } } } @@ -562,24 +561,11 @@ void Keyboard::injectVirtualKey(VirtualKey virtualKey, bool keyDown, bool insert } -// inject a virtual key item into virtual key queue calling injectVirtualKey() and into m_uiApp +// inject a virtual key item into virtual key queue calling injectVirtualKey(). void Keyboard::postVirtualKeyItem(VirtualKeyItem const & item) { // add into m_virtualKeyQueue and update m_VKMap injectVirtualKey(item, false); - - // need to send events to uiApp? - if (m_uiApp) { - uiEvent evt = uiEvent(nullptr, item.down ? UIEVT_KEYDOWN : UIEVT_KEYUP); - evt.params.key.VK = item.vk; - evt.params.key.ASCII = item.ASCII; - evt.params.key.LALT = item.LALT; - evt.params.key.RALT = item.RALT; - evt.params.key.CTRL = item.CTRL; - evt.params.key.SHIFT = item.SHIFT; - evt.params.key.GUI = item.GUI; - m_uiApp->postEvent(&evt); - } } diff --git a/src/devdrivers/keyboard.h b/src/devdrivers/keyboard.h index 4fba7ec23..11359bf85 100644 --- a/src/devdrivers/keyboard.h +++ b/src/devdrivers/keyboard.h @@ -39,7 +39,6 @@ #include "fabglconf.h" #include "comdrivers/ps2device.h" -#include "fabui.h" #include "kbdlayouts.h" #include "codepages.h" @@ -65,7 +64,7 @@ namespace fabgl { * Example: * * fabgl::Keyboard Keyboard; - * + * * // Setup pins GPIO33 for CLK and GPIO32 for DATA * Keyboard.begin(GPIO_NUM_33, GPIO_NUM_32); // clk, dat * @@ -139,15 +138,6 @@ class Keyboard : public PS2Device { */ void enableVirtualKeys(bool generateVirtualKeys, bool createVKQueue); - /** - * @brief Sets current UI app - * - * To use this generateVirtualKeys must be true in begin(). - * - * @param app The UI app where to send keyboard events - */ - void setUIApp(uiApp * app) { m_uiApp = app; } - /** * @brief Sends a Reset command to the keyboard. * @@ -428,8 +418,6 @@ class Keyboard : public PS2Device { KeyboardLayout const * m_layout; - uiApp * m_uiApp; - bool m_CTRL; bool m_LALT; bool m_RALT; diff --git a/src/devdrivers/mouse.cpp b/src/devdrivers/mouse.cpp index d7ffc6db3..b6f298d62 100644 --- a/src/devdrivers/mouse.cpp +++ b/src/devdrivers/mouse.cpp @@ -51,9 +51,7 @@ Mouse::Mouse() m_movementAcceleration(180), m_wheelAcceleration(60000), m_absoluteQueue(nullptr), - m_updateDisplayController(nullptr), - m_uiApp(nullptr) -{ + m_updateDisplayController(nullptr) { } @@ -191,7 +189,7 @@ bool Mouse::getNextDelta(MouseDelta * delta, int timeOutMS, bool requestResendOn } -void Mouse::setupAbsolutePositioner(int width, int height, bool createAbsolutePositionsQueue, BitmappedDisplayController * updateDisplayController, uiApp * app) +void Mouse::setupAbsolutePositioner(int width, int height, bool createAbsolutePositionsQueue, BitmappedDisplayController * updateDisplayController) { if (m_area != Size(width, height)) { m_area = Size(width, height); @@ -206,8 +204,6 @@ void Mouse::setupAbsolutePositioner(int width, int height, bool createAbsolutePo m_updateDisplayController = updateDisplayController; - m_uiApp = app; - if (createAbsolutePositionsQueue && m_absoluteQueue == nullptr) { m_absoluteQueue = xQueueCreate(FABGLIB_MOUSE_EVENTS_QUEUE_SIZE, sizeof(MouseStatus)); } @@ -217,7 +213,7 @@ void Mouse::setupAbsolutePositioner(int width, int height, bool createAbsolutePo m_updateDisplayController->setMouseCursorPos(m_status.X, m_status.Y); } - m_absoluteUpdate = (m_updateDisplayController || createAbsolutePositionsQueue || m_uiApp); + m_absoluteUpdate = (m_updateDisplayController || createAbsolutePositionsQueue); } @@ -229,7 +225,6 @@ void Mouse::terminateAbsolutePositioner() } m_absoluteUpdate = false; m_updateDisplayController = nullptr; - m_uiApp = nullptr; } @@ -316,52 +311,9 @@ void Mouse::mouseUpdateTask(void * arg) if (mouse->m_absoluteQueue) { xQueueSend(mouse->m_absoluteQueue, &mouse->m_status, 0); } - - if (mouse->m_uiApp) { - // generate uiApp events - if (mouse->m_prevStatus.X != mouse->m_status.X || mouse->m_prevStatus.Y != mouse->m_status.Y) { - // X and Y movement: UIEVT_MOUSEMOVE - uiEvent evt = uiEvent(nullptr, UIEVT_MOUSEMOVE); - evt.params.mouse.status = mouse->m_status; - evt.params.mouse.changedButton = 0; - mouse->m_uiApp->postEvent(&evt); - } - if (mouse->m_status.wheelDelta != 0) { - // wheel movement: UIEVT_MOUSEWHEEL - uiEvent evt = uiEvent(nullptr, UIEVT_MOUSEWHEEL); - evt.params.mouse.status = mouse->m_status; - evt.params.mouse.changedButton = 0; - mouse->m_uiApp->postEvent(&evt); - } - if (mouse->m_prevStatus.buttons.left != mouse->m_status.buttons.left) { - // left button: UIEVT_MOUSEBUTTONDOWN, UIEVT_MOUSEBUTTONUP - uiEvent evt = uiEvent(nullptr, mouse->m_status.buttons.left ? UIEVT_MOUSEBUTTONDOWN : UIEVT_MOUSEBUTTONUP); - evt.params.mouse.status = mouse->m_status; - evt.params.mouse.changedButton = 1; - mouse->m_uiApp->postEvent(&evt); - } - if (mouse->m_prevStatus.buttons.middle != mouse->m_status.buttons.middle) { - // middle button: UIEVT_MOUSEBUTTONDOWN, UIEVT_MOUSEBUTTONUP - uiEvent evt = uiEvent(nullptr, mouse->m_status.buttons.middle ? UIEVT_MOUSEBUTTONDOWN : UIEVT_MOUSEBUTTONUP); - evt.params.mouse.status = mouse->m_status; - evt.params.mouse.changedButton = 2; - mouse->m_uiApp->postEvent(&evt); - } - if (mouse->m_prevStatus.buttons.right != mouse->m_status.buttons.right) { - // right button: UIEVT_MOUSEBUTTONDOWN, UIEVT_MOUSEBUTTONUP - uiEvent evt = uiEvent(nullptr, mouse->m_status.buttons.right ? UIEVT_MOUSEBUTTONDOWN : UIEVT_MOUSEBUTTONUP); - evt.params.mouse.status = mouse->m_status; - evt.params.mouse.changedButton = 3; - mouse->m_uiApp->postEvent(&evt); - } - } - } - } else { - xQueueOverwrite(mouse->m_receivedPacket, &mousePacket); - } } diff --git a/src/devdrivers/mouse.h b/src/devdrivers/mouse.h index da8985ef3..3f03f982f 100644 --- a/src/devdrivers/mouse.h +++ b/src/devdrivers/mouse.h @@ -41,7 +41,7 @@ #include "fabglconf.h" #include "fabutils.h" #include "comdrivers/ps2device.h" -#include "fabui.h" +#include "displaycontroller.h" namespace fabgl { @@ -271,14 +271,7 @@ class Mouse : public PS2Device { * * Mouse.setupAbsolutePositioner(Canvas.getWidth(), Canvas.getHeight(), true); */ - void setupAbsolutePositioner(int width, int height, bool createAbsolutePositionsQueue, BitmappedDisplayController * updateDisplayController = nullptr, uiApp * app = nullptr); - - /** - * @brief Sets current UI app - * - * @param app The UI app where to send mouse events - */ - void setUIApp(uiApp * app) { m_uiApp = app; } + void setupAbsolutePositioner(int width, int height, bool createAbsolutePositionsQueue, BitmappedDisplayController * updateDisplayController = nullptr); /** * @brief Terminates absolute position handler. @@ -398,8 +391,6 @@ class Mouse : public PS2Device { int m_wheelAcceleration; // reasonable values: 0...100000 QueueHandle_t m_absoluteQueue; // a queue of messages generated by updateAbsolutePosition() BitmappedDisplayController * m_updateDisplayController; - - uiApp * m_uiApp; }; diff --git a/src/fabgl.h b/src/fabgl.h index 5f41f9cb4..2c2885258 100644 --- a/src/fabgl.h +++ b/src/fabgl.h @@ -318,9 +318,6 @@ #include "dispdrivers/vga4controller.h" #include "dispdrivers/vga8controller.h" #include "dispdrivers/vga16controller.h" -#include "dispdrivers/vgadirectcontroller.h" -#include "fabui.h" -#include "inputbox.h" #include "comdrivers/ps2controller.h" #include "comdrivers/tsi2c.h" #include "devdrivers/keyboard.h" @@ -363,7 +360,6 @@ using fabgl::KbdMode; using fabgl::VirtualKey; using fabgl::VirtualKeyItem; using fabgl::FileBrowser; -using fabgl::ModalWindowState; using fabgl::Canvas; using fabgl::PixelFormat; using fabgl::RGB222; @@ -379,7 +375,3 @@ using fabgl::CharStyle; using fabgl::TerminalTransition; using fabgl::SupportedLayouts; using fabgl::CoreUsage; -using fabgl::InputResult; -using fabgl::InputBox; - - diff --git a/src/fabglconf.h b/src/fabglconf.h index fd7e8fc7a..7398f7e75 100644 --- a/src/fabglconf.h +++ b/src/fabglconf.h @@ -195,7 +195,7 @@ #define VGA_512x384_60Hz "\"512x384@60Hz\" 32.5 512 524 592 672 384 385 388 403 -HSync -VSync DoubleScan" /** Modeline for 640x480@60Hz resolution */ -#define QSVGA_640x480_60Hz "\"640x480@60Hz\" 25.175 640 656 752 800 480 490 492 525 -HSync -VSync" +#define VGA_640x480_60Hz "\"640x480@60Hz\" 25.175 640 656 752 800 480 490 492 525 -HSync -VSync" /** Modeline for 640x512@60Hz resolution (for pixel perfect 1280x1024 double scan resolution) */ #define QSVGA_640x512_60Hz "\"640x512@60Hz\" 54 640 664 720 844 512 513 515 533 -HSync -VSync DoubleScan" diff --git a/src/inputbox.cpp b/src/inputbox.cpp deleted file mode 100644 index 1ef22563d..000000000 --- a/src/inputbox.cpp +++ /dev/null @@ -1,946 +0,0 @@ -/* - Created by Fabrizio Di Vittorio (fdivitto2013@gmail.com) - - Copyright (c) 2019-2022 Fabrizio Di Vittorio. - All rights reserved. - - -* Please contact fdivitto2013@gmail.com if you need a commercial license. - - -* This library and related software is available under GPL v3. - - FabGL is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - FabGL is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with FabGL. If not, see . - */ - - -#include -#include - -#include "dispdrivers/vga2controller.h" -#include "dispdrivers/vga4controller.h" -#include "dispdrivers/vga8controller.h" -#include "dispdrivers/vga16controller.h" - -#include "devdrivers/keyboard.h" -#include "inputbox.h" - - -#pragma GCC optimize ("O2") - - -using std::unique_ptr; - - -namespace fabgl { - - -// well known InputForm::buttonText[] indexes -#define B_CANCEL ((int)(InputResult::Cancel) - 1) -#define B_OK ((int)(InputResult::Enter) - 1) - - - -//////////////////////////////////////////////////////////////////////////////////////////////////// -// InputBox - -InputBox::InputBox(uiApp * app) - : m_vgaCtrl(nullptr), - m_backgroundColor(RGB888(64, 64, 64)), - m_existingApp(app), - m_autoOK(0), - m_minButtonsWidth(40) -{ -} - - -InputBox::~InputBox() -{ - end(); -} - - -void InputBox::begin(char const * modeline, int viewPortWidth, int viewPortHeight, int displayColors) -{ - // setup display controller - if (displayColors <= 2) - m_vgaCtrl = new VGA2Controller; - else if (displayColors <= 4) - m_vgaCtrl = new VGA4Controller; - else if (displayColors <= 8) - m_vgaCtrl = new VGA8Controller; - else - m_vgaCtrl = new VGA16Controller; - m_dispCtrl = m_vgaCtrl; - m_vgaCtrl->begin(); - m_vgaCtrl->setResolution(modeline ? modeline : VESA_640x480_75Hz, viewPortWidth, viewPortHeight); - - // setup keyboard and mouse - if (!PS2Controller::initialized()) - PS2Controller::begin(PS2Preset::KeyboardPort0_MousePort1, KbdMode::GenerateVirtualKeys); - else - PS2Controller::keyboard()->enableVirtualKeys(true, true); -} - - -void InputBox::begin(BitmappedDisplayController * displayController) -{ - m_dispCtrl = displayController; -} - - -void InputBox::end() -{ - if (m_vgaCtrl) { - m_vgaCtrl->end(); - delete m_vgaCtrl; - m_vgaCtrl = nullptr; - } -} - - -void InputBox::setupButton(int index, char const * text, char const * subItems, int subItemsHeight) -{ - m_buttonText[index] = text; - m_buttonSubItems[index] = subItems; - m_buttonSubItemsHeight[index] = subItemsHeight; -} - - -void InputBox::resetButtons() -{ - for (int i = 0; i < InputForm::BUTTONS; ++i) { - m_buttonText[i] = nullptr; - m_buttonSubItems[i] = nullptr; - } -} - - -void InputBox::exec(InputForm * form) -{ - if (m_existingApp) { - form->init(m_existingApp, true); - m_existingApp->showModalWindow(form->mainFrame); - m_existingApp->destroyWindow(form->mainFrame); - } else { - // run in standalone mode - InputApp app(form); - app.run(m_dispCtrl); - } - resetButtons(); - m_buttonSubItem = form->buttonSubItem; - m_lastResult = form->retval; -} - - -InputResult InputBox::textInput(char const * titleText, char const * labelText, char * inOutString, int maxLength, char const * buttonCancelText, char const * buttonOKText, bool passwordMode) -{ - setupButton(B_CANCEL, buttonCancelText); - setupButton(B_OK, buttonOKText); - - TextInputForm form(this); - form.titleText = titleText; - form.labelText = labelText; - form.inOutString = inOutString; - form.maxLength = maxLength; - form.passwordMode = passwordMode; - form.autoOK = m_autoOK; - - exec(&form); - return form.retval; -} - - -InputResult InputBox::message(char const * titleText, char const * messageText, char const * buttonCancelText, char const * buttonOKText) -{ - setupButton(B_CANCEL, buttonCancelText); - setupButton(B_OK, buttonOKText); - - MessageForm form(this); - form.titleText = titleText; - form.messageText = messageText; - form.autoOK = m_autoOK; - - exec(&form); - return form.retval; -} - - -InputResult InputBox::messageFmt(char const * titleText, char const * buttonCancelText, char const * buttonOKText, const char * format, ...) -{ - auto r = InputResult::Cancel; - va_list ap; - va_start(ap, format); - int size = vsnprintf(nullptr, 0, format, ap) + 1; - if (size > 0) { - va_end(ap); - va_start(ap, format); - char buf[size + 1]; - vsnprintf(buf, size, format, ap); - r = message(titleText, buf, buttonCancelText, buttonOKText); - } - va_end(ap); - return r; -} - - -int InputBox::select(char const * titleText, char const * messageText, char const * itemsText, char separator, char const * buttonCancelText, char const * buttonOKText) -{ - setupButton(B_CANCEL, buttonCancelText); - setupButton(B_OK, buttonOKText); - - SelectForm form(this); - form.titleText = titleText; - form.messageText = messageText; - form.items = itemsText; - form.separator = separator; - form.itemsList = nullptr; - form.menuMode = false; - form.autoOK = m_autoOK; - - exec(&form); - return form.outSelected; -} - - -InputResult InputBox::select(char const * titleText, char const * messageText, StringList * items, char const * buttonCancelText, char const * buttonOKText) -{ - setupButton(B_CANCEL, buttonCancelText); - setupButton(B_OK, buttonOKText); - - SelectForm form(this); - form.titleText = titleText; - form.messageText = messageText; - form.items = nullptr; - form.separator = 0; - form.itemsList = items; - form.menuMode = false; - form.autoOK = m_autoOK; - - exec(&form); - return form.retval; -} - - -int InputBox::menu(char const * titleText, char const * messageText, char const * itemsText, char separator) -{ - SelectForm form(this); - form.titleText = titleText; - form.messageText = messageText; - form.items = itemsText; - form.separator = separator; - form.itemsList = nullptr; - form.menuMode = true; - form.autoOK = 0; // no timeout supported here - - exec(&form); - return form.outSelected; -} - - -int InputBox::menu(char const * titleText, char const * messageText, StringList * items) -{ - SelectForm form(this); - form.titleText = titleText; - form.messageText = messageText; - form.items = nullptr; - form.separator = 0; - form.itemsList = items; - form.menuMode = true; - form.autoOK = 0; // no timeout supported here - - exec(&form); - return items->getFirstSelected(); -} - - -InputResult InputBox::progressBoxImpl(ProgressForm & form, char const * titleText, char const * buttonCancelText, bool hasProgressBar, int width) -{ - setupButton(B_CANCEL, buttonCancelText); - - form.titleText = titleText; - form.hasProgressBar = hasProgressBar; - form.width = width; - form.autoOK = 0; // no timeout supported here - - exec(&form); - return form.retval; -} - - -InputResult InputBox::folderBrowser(char const * titleText, char const * directory, char const * buttonOKText) -{ - setupButton(B_OK, buttonOKText); - - FileBrowserForm form(this); - form.titleText = titleText; - form.autoOK = 0; // no timeout supported here - form.directory = directory; - - exec(&form); - return form.retval; -} - - -InputResult InputBox::fileSelector(char const * titleText, char const * messageText, char * inOutDirectory, int maxDirectoryLength, char * inOutFilename, int maxFilenameLength, char const * buttonCancelText, char const * buttonOKText) -{ - setupButton(B_CANCEL, buttonCancelText); - setupButton(B_OK, buttonOKText); - - FileSelectorForm form(this); - form.titleText = titleText; - form.labelText = messageText; - form.inOutDirectory = inOutDirectory; - form.maxDirectoryLength = maxDirectoryLength; - form.inOutFilename = inOutFilename; - form.maxFilenameLength = maxFilenameLength; - form.autoOK = 0; // no timeout supported here - - exec(&form); - return form.retval; -} - - - -//////////////////////////////////////////////////////////////////////////////////////////////////// -// InputForm - - -void InputForm::init(uiApp * app_, bool modalDialog_) -{ - retval = InputResult::None; - - app = app_; - modalDialog = modalDialog_; - - if (!modalDialog) { - app->rootWindow()->frameStyle().backgroundColor = inputBox->backgroundColor(); - app->rootWindow()->onPaint = [&]() { - inputBox->onPaint(app->canvas()); - }; - } - - font = &FONT_std_14; - - const int titleHeight = titleText && strlen(titleText) ? font->height : 0; - - constexpr int buttonsSpace = 10; - - int buttonsWidth = inputBox->minButtonsWidth(); - int totButtons = 0; - - for (int i = 0; i < BUTTONS; ++i) { - auto btext = inputBox->buttonText(i); - if (btext) { - int buttonExtent = app->canvas()->textExtent(font, btext) + 10; - buttonsWidth = imax(buttonsWidth, buttonExtent); - ++totButtons; - } - } - - const int buttonsHeight = totButtons ? font->height + 6 : 0; - - requiredWidth = buttonsWidth * totButtons + (2 * buttonsSpace) * totButtons; - requiredHeight = buttonsHeight + titleHeight + font->height * 2 + 5; - - calcRequiredSize(); - - requiredWidth = imin(requiredWidth, app->canvas()->getWidth()); - - controlToFocus = nullptr; - - mainFrame = new uiFrame(app->rootWindow(), titleText, UIWINDOW_PARENTCENTER, Size(requiredWidth, requiredHeight), false); - mainFrame->frameProps().resizeable = false; - mainFrame->frameProps().hasMaximizeButton = false; - mainFrame->frameProps().hasMinimizeButton = false; - mainFrame->frameProps().hasCloseButton = false; - mainFrame->onShow = [&]() { - if (controlToFocus) - app->setFocusedWindow(controlToFocus); - show(); - }; - - autoOKLabel = nullptr; - - if (totButtons) { - - // setup panel (where buttons are positioned) - - int panelHeight = buttonsHeight + 10; - panel = new uiPanel(mainFrame, Point(mainFrame->clientPos().X - 1, mainFrame->clientPos().Y + mainFrame->clientSize().height - panelHeight), Size(mainFrame->clientSize().width + 2, panelHeight)); - panel->windowStyle().borderColor = RGB888(128, 128, 128); - panel->panelStyle().backgroundColor = mainFrame->frameStyle().backgroundColor; - panel->anchors().top = false; - panel->anchors().bottom = true; - panel->anchors().right = true; - - // setup buttons - - int y = (panelHeight - buttonsHeight) / 2; - int x = panel->clientSize().width - buttonsWidth * totButtons - buttonsSpace * (totButtons - 1) - buttonsSpace / 2; // right aligned - - for (int i = 0; i < BUTTONS; ++i) - if (inputBox->buttonText(i)) { - uiWindow * ctrl; - if (inputBox->buttonSubItems(i)) { - auto splitButton = new uiSplitButton(panel, inputBox->buttonText(i), Point(x, y), Size(buttonsWidth, buttonsHeight), inputBox->buttonsSubItemsHeight(i), inputBox->buttonSubItems(i)); - splitButton->onSelect = [&, i](int idx) { - buttonSubItem = idx; - retval = (InputResult)(i + 1); - finalize(); - }; - ctrl = splitButton; - } else { - auto button = new uiButton(panel, inputBox->buttonText(i), Point(x, y), Size(buttonsWidth, buttonsHeight)); - button->onClick = [&, i]() { - retval = (InputResult)(i + 1); - finalize(); - }; - ctrl = button; - } - ctrl->anchors().left = false; - ctrl->anchors().right = true; - x += buttonsWidth + buttonsSpace; - controlToFocus = ctrl; - } - - if (autoOK > 0) { - autoOKLabel = new uiLabel(panel, "", Point(4, y + 2)); - - mainFrame->onTimer = [&](uiTimerHandle t) { - int now = esp_timer_get_time() / 1000; - if (app->lastUserActionTime() + 900 > now) { - app->killTimer(t); - app->destroyWindow(autoOKLabel); - return; - } - if (autoOK <= 0) { - app->killTimer(t); - retval = InputResult::Enter; - finalize(); - } - --autoOK; - autoOKLabel->setTextFmt("%d", autoOK); - }; - app->setTimer(mainFrame, 1000); - - } - - } else { - panel = nullptr; - } - - addControls(); - - if (!modalDialog) { - app->showWindow(mainFrame, true); - app->setActiveWindow(mainFrame); - } -} - - -void InputForm::defaultEnterHandler(uiKeyEventInfo const & key) -{ - if (key.VK == VK_RETURN || key.VK == VK_KP_ENTER) { - retval = InputResult::Enter; - finalize(); - } -} - - -void InputForm::defaultEscapeHandler(uiKeyEventInfo const & key) -{ - if (key.VK == VK_ESCAPE) { - retval = InputResult::Cancel; - finalize(); - } -} - - -void InputForm::doExit(int value) -{ - if (modalDialog) - mainFrame->exitModal(value); - else { - app->quit(value); - // this avoids flickering of content painted in onPaint - app->rootWindow()->frameProps().fillBackground = false; - } -} - - -//////////////////////////////////////////////////////////////////////////////////////////////////// -// TextInputForm - - -void TextInputForm::calcRequiredSize() -{ - labelExtent = app->canvas()->textExtent(font, labelText); - editExtent = imin(maxLength * app->canvas()->textExtent(font, "M") + 15, app->rootWindow()->clientSize().width - labelExtent); - requiredWidth = imax(requiredWidth, editExtent + labelExtent + 10); - requiredHeight += font->height; -} - - -void TextInputForm::addControls() -{ - mainFrame->frameProps().resizeable = true; - mainFrame->frameProps().hasMaximizeButton = true; - - const Point clientPos = mainFrame->clientPos(); - - int x = clientPos.X + 4; - int y = clientPos.Y + 8; - - new uiLabel(mainFrame, labelText, Point(x, y)); - - edit = new uiTextEdit(mainFrame, inOutString, Point(x + labelExtent + 5, y - 4), Size(editExtent - 15, font->height + 6)); - edit->anchors().right = true; - edit->textEditProps().passwordMode = passwordMode; - edit->onKeyType = [&](uiKeyEventInfo const & key) { defaultEnterHandler(key); defaultEscapeHandler(key); }; - - controlToFocus = edit; -} - - -void TextInputForm::finalize() -{ - if (retval == InputResult::Enter) { - int len = imin(maxLength, strlen(edit->text())); - memcpy(inOutString, edit->text(), len); - inOutString[len] = 0; - } - doExit(0); -} - - - -//////////////////////////////////////////////////////////////////////////////////////////////////// -// MessageForm - - -void MessageForm::calcRequiredSize() -{ - messageExtent = app->canvas()->textExtent(font, messageText); - requiredWidth = imax(requiredWidth, messageExtent + 20); - requiredHeight += font->height; -} - - -void MessageForm::addControls() -{ - int x = mainFrame->clientPos().X + (mainFrame->clientSize().width - messageExtent) / 2; - int y = mainFrame->clientPos().Y + 6; - - new uiLabel(mainFrame, messageText, Point(x, y)); - - mainFrame->onKeyUp = [&](uiKeyEventInfo const & key) { defaultEnterHandler(key); defaultEscapeHandler(key); }; -} - - -void MessageForm::finalize() -{ - doExit(0); -} - - - -//////////////////////////////////////////////////////////////////////////////////////////////////// -// SelectForm - - -void SelectForm::calcRequiredSize() -{ - auto messageExtent = app->canvas()->textExtent(font, messageText); - requiredWidth = imax(requiredWidth, messageExtent + 20); - - // calc space for message - requiredHeight += font->height; - - // calc space for list box - size_t maxLength; - auto itemsCount = countItems(&maxLength); - listBoxHeight = 16 * itemsCount + 2; - int requiredHeightUnCut = requiredHeight + listBoxHeight; - requiredHeight = imin(requiredHeightUnCut, app->canvas()->getHeight()); - requiredWidth = imax(requiredWidth, maxLength * app->canvas()->textExtent(font, "M")); - if (requiredHeightUnCut > requiredHeight) - listBoxHeight -= requiredHeightUnCut - requiredHeight; -} - - -void SelectForm::addControls() -{ - mainFrame->frameProps().resizeable = true; - mainFrame->frameProps().hasMaximizeButton = true; - - int x = mainFrame->clientPos().X + 4; - int y = mainFrame->clientPos().Y + 6; - - new uiLabel(mainFrame, messageText, Point(x, y)); - - y += font->height + 6; - - listBox = new uiListBox(mainFrame, Point(x, y), Size(mainFrame->clientSize().width - 10, listBoxHeight)); - listBox->anchors().right = true; - listBox->anchors().bottom = true; - if (items) { - listBox->items().appendSepList(items, separator); - } else { - listBox->items().copyFrom(*itemsList); - listBox->items().copySelectionMapFrom(*itemsList); - } - if (menuMode) { - listBox->listBoxProps().allowMultiSelect = false; - listBox->listBoxProps().selectOnMouseOver = true; - listBox->onClick = [&]() { - retval = InputResult::Enter; - finalize(); - }; - } else { - listBox->onDblClick = [&]() { - retval = InputResult::Enter; - finalize(); - }; - } - listBox->onKeyType = [&](uiKeyEventInfo const & key) { defaultEnterHandler(key); defaultEscapeHandler(key); }; - - controlToFocus = listBox; -} - - -void SelectForm::finalize() -{ - if (items) { - outSelected = (retval == InputResult::Enter ? listBox->firstSelectedItem() : -1); - } else { - if (retval == InputResult::Cancel) - itemsList->deselectAll(); - else - itemsList->copySelectionMapFrom(listBox->items()); - } - doExit(0); -} - - -int SelectForm::countItems(size_t * maxLength) -{ - *maxLength = 0; - int count = 0; - if (items) { - char const * start = items; - while (*start) { - auto end = strchr(start, separator); - if (!end) - end = strchr(start, 0); - int len = end - start; - *maxLength = imax(*maxLength, len); - start += len + (*end == 0 ? 0 : 1); - ++count; - } - } else if (itemsList) { - for (int i = 0; i < itemsList->count(); ++i) - *maxLength = imax(*maxLength, strlen(itemsList->get(i))); - count += itemsList->count(); - } - return count; -} - - - -//////////////////////////////////////////////////////////////////////////////////////////////////// -// ProgressForm - - -void ProgressForm::calcRequiredSize() -{ - requiredWidth = imax(requiredWidth, width); - requiredHeight += font->height + (hasProgressBar ? progressBarHeight : 0); -} - - -void ProgressForm::addControls() -{ - int x = mainFrame->clientPos().X + 4; - int y = mainFrame->clientPos().Y + 6; - - label = new uiLabel(mainFrame, "", Point(x, y)); - - if (hasProgressBar) { - y += font->height + 4; - progressBar = new uiProgressBar(mainFrame, Point(x, y), Size(mainFrame->clientSize().width - 8, font->height)); - } - - mainFrame->onKeyUp = [&](uiKeyEventInfo const & key) { defaultEscapeHandler(key); }; -} - - -void ProgressForm::show() -{ - execFunc(this); - if (retval != InputResult::Cancel) - retval = InputResult::Enter; - doExit(0); -} - - -// return True if not Abort -bool ProgressForm::update(int percentage, char const * format, ...) -{ - if (hasProgressBar) - progressBar->setPercentage(percentage); - - va_list ap; - va_start(ap, format); - int size = vsnprintf(nullptr, 0, format, ap) + 1; - if (size > 0) { - va_end(ap); - va_start(ap, format); - char buf[size + 1]; - vsnprintf(buf, size, format, ap); - label->setText(buf); - } - va_end(ap); - - app->processEvents(); - return retval == InputResult::None; -} - - - -//////////////////////////////////////////////////////////////////////////////////////////////////// -// FileBrowserForm - - -void FileBrowserForm::calcRequiredSize() -{ - requiredWidth = imax(requiredWidth, BROWSER_WIDTH + CTRLS_DIST + SIDE_BUTTONS_WIDTH); - requiredHeight = imax(requiredHeight, BROWSER_HEIGHT); -} - - -void FileBrowserForm::addControls() -{ - mainFrame->frameProps().resizeable = true; - mainFrame->frameProps().hasMaximizeButton = true; - - mainFrame->onKeyUp = [&](uiKeyEventInfo const & key) { defaultEscapeHandler(key); }; - - int x = mainFrame->clientPos().X + CTRLS_DIST; - int y = mainFrame->clientPos().Y + CTRLS_DIST; - - fileBrowser = new uiFileBrowser(mainFrame, Point(x, y), Size(mainFrame->clientSize().width - x - CTRLS_DIST - SIDE_BUTTONS_WIDTH, mainFrame->clientSize().height - panel->size().height - CTRLS_DIST * 2)); - fileBrowser->anchors().right = true; - fileBrowser->anchors().bottom = true; - fileBrowser->setDirectory(directory); - - x += fileBrowser->size().width + CTRLS_DIST; - - newFolderButton = new uiButton(mainFrame, "New Folder", Point(x, y), Size(SIDE_BUTTONS_WIDTH, SIDE_BUTTONS_HEIGHT)); - newFolderButton->anchors().left = false; - newFolderButton->anchors().right = true; - newFolderButton->onClick = [&]() { - unique_ptr dirname(new char[MAXNAME + 1] { 0 } ); - if (app->inputBox("Create Folder", "Name", dirname.get(), MAXNAME, "Create", "Cancel") == uiMessageBoxResult::Button1) { - fileBrowser->content().makeDirectory(dirname.get()); - fileBrowser->update(); - } - }; - - y += SIDE_BUTTONS_HEIGHT + CTRLS_DIST; - - renameButton = new uiButton(mainFrame, "Rename", Point(x, y), Size(SIDE_BUTTONS_WIDTH, SIDE_BUTTONS_HEIGHT)); - renameButton->anchors().left = false; - renameButton->anchors().right = true; - renameButton->onClick = [&]() { - if (strcmp(fileBrowser->filename(), "..") != 0) { - int maxlen = fabgl::imax(MAXNAME, strlen(fileBrowser->filename())); - unique_ptr filename(new char[MAXNAME + 1] { 0 } ); - strcpy(filename.get(), fileBrowser->filename()); - if (app->inputBox("Rename File", "New name", filename.get(), maxlen, "Rename", "Cancel") == uiMessageBoxResult::Button1) { - fileBrowser->content().rename(fileBrowser->filename(), filename.get()); - fileBrowser->update(); - } - } - }; - - y += SIDE_BUTTONS_HEIGHT + CTRLS_DIST; - - deleteButton = new uiButton(mainFrame, "Delete", Point(x, y), Size(SIDE_BUTTONS_WIDTH, SIDE_BUTTONS_HEIGHT)); - deleteButton->anchors().left = false; - deleteButton->anchors().right = true; - deleteButton->onClick = [&]() { - if (strcmp(fileBrowser->filename(), "..") != 0) { - if (app->messageBox("Delete file/directory", "Are you sure?", "Yes", "Cancel") == uiMessageBoxResult::Button1) { - fileBrowser->content().remove( fileBrowser->filename() ); - fileBrowser->update(); - } - } - }; - - y += SIDE_BUTTONS_HEIGHT + CTRLS_DIST; - - copyButton = new uiButton(mainFrame, "Copy", Point(x, y), Size(SIDE_BUTTONS_WIDTH, SIDE_BUTTONS_HEIGHT)); - copyButton->anchors().left = false; - copyButton->anchors().right = true; - copyButton->onClick = [&]() { doCopy(); }; - - y += SIDE_BUTTONS_HEIGHT + CTRLS_DIST; - - pasteButton = new uiButton(mainFrame, "Paste", Point(x, y), Size(SIDE_BUTTONS_WIDTH, SIDE_BUTTONS_HEIGHT)); - pasteButton->anchors().left = false; - pasteButton->anchors().right = true; - pasteButton->onClick = [&]() { doPaste(); }; - app->showWindow(pasteButton, false); - -} - - -void FileBrowserForm::finalize() -{ - doExit(0); -} - - -void FileBrowserForm::doCopy() -{ - if (!fileBrowser->isDirectory()) { - if (srcDirectory) - free(srcDirectory); - if (srcFilename) - free(srcFilename); - srcDirectory = strdup(fileBrowser->directory()); - srcFilename = strdup(fileBrowser->filename()); - app->showWindow(pasteButton, true); - } -} - - -void FileBrowserForm::doPaste() -{ - if (strcmp(srcDirectory, fileBrowser->content().directory()) == 0) { - app->messageBox("", "Please select a different folder", "OK", nullptr, nullptr, uiMessageBoxIcon::Error); - return; - } - FileBrowser fb_src(srcDirectory); - auto fileSize = fb_src.fileSize(srcFilename); - auto src = fb_src.openFile(srcFilename, "rb"); - if (!src) { - app->messageBox("", "Unable to find source file", "OK", nullptr, nullptr, uiMessageBoxIcon::Error); - return; - } - if (fileBrowser->content().exists(srcFilename, false)) { - if (app->messageBox("", "Overwrite file?", "Yes", "No", nullptr, uiMessageBoxIcon::Question) != uiMessageBoxResult::ButtonOK) - return; - } - auto dst = fileBrowser->content().openFile(srcFilename, "wb"); - - auto bytesToCopy = fileSize; - - InputBox ib(app); - ib.progressBox("Copying", "Abort", true, app->canvas()->getWidth() * 2 / 3, [&](fabgl::ProgressForm * form) { - constexpr int BUFLEN = 4096; - unique_ptr buf(new uint8_t[BUFLEN]); - while (bytesToCopy > 0) { - auto r = fread(buf.get(), 1, imin(BUFLEN, bytesToCopy), src); - fwrite(buf.get(), 1, r, dst); - bytesToCopy -= r; - if (r == 0) - break; - if (!form->update((int)((double)(fileSize - bytesToCopy) / fileSize * 100), "Writing %s (%d / %d bytes)", srcFilename, (fileSize - bytesToCopy), fileSize)) - break; - } - }); - - fclose(dst); - fclose(src); - if (bytesToCopy > 0) { - fileBrowser->content().remove(srcFilename); - app->messageBox("", "File not copied", "OK", nullptr, nullptr, uiMessageBoxIcon::Error); - } - fileBrowser->update(); -} - - - - -//////////////////////////////////////////////////////////////////////////////////////////////////// -// FileSelectorForm - - -void FileSelectorForm::calcRequiredSize() -{ - labelExtent = app->canvas()->textExtent(font, labelText); - editExtent = imin(maxFilenameLength * app->canvas()->textExtent(font, "M") + 15, app->rootWindow()->clientSize().width - labelExtent); - requiredWidth = imax(requiredWidth, imax(BROWSER_WIDTH, labelExtent + CTRLS_DIST + MINIMUM_EDIT_WIDTH) + CTRLS_DIST); - requiredHeight += font->height + CTRLS_DIST + BROWSER_HEIGHT; -} - - -void FileSelectorForm::addControls() -{ - mainFrame->frameProps().resizeable = true; - mainFrame->frameProps().hasMaximizeButton = true; - - mainFrame->onKeyUp = [&](uiKeyEventInfo const & key) { defaultEscapeHandler(key); }; - - int x = mainFrame->clientPos().X + CTRLS_DIST; - int y = mainFrame->clientPos().Y + CTRLS_DIST; - - new uiLabel(mainFrame, labelText, Point(x, y + 4)); - - edit = new uiTextEdit(mainFrame, inOutFilename, Point(x + labelExtent + CTRLS_DIST, y), Size(mainFrame->clientSize().width - labelExtent - x - CTRLS_DIST - 1, font->height + 6)); - edit->anchors().right = true; - - y += edit->size().height + CTRLS_DIST; - - fileBrowser = new uiFileBrowser(mainFrame, Point(x, y), Size(mainFrame->clientSize().width - x - 1, mainFrame->clientSize().height - panel->size().height - y + CTRLS_DIST * 2 )); - fileBrowser->anchors().right = true; - fileBrowser->anchors().bottom = true; - fileBrowser->setDirectory(inOutDirectory); - fileBrowser->onChange = [&]() { - if (!fileBrowser->isDirectory()) { - edit->setText(fileBrowser->filename()); - edit->repaint(); - } - }; - fileBrowser->onDblClick = [&]() { - if (!fileBrowser->isDirectory()) { - retval = InputResult::Enter; - finalize(); - } - }; - fileBrowser->onKeyType = [&](uiKeyEventInfo const & key) { defaultEnterHandler(key); defaultEscapeHandler(key); }; - - controlToFocus = edit; -} - - -void FileSelectorForm::finalize() -{ - if (retval == InputResult::Enter) { - // filename - int len = imin(maxFilenameLength, strlen(edit->text())); - memcpy(inOutFilename, edit->text(), len); - inOutFilename[len] = 0; - // directory - len = imin(maxDirectoryLength, strlen(fileBrowser->directory())); - memcpy(inOutDirectory, fileBrowser->directory(), len); - inOutDirectory[len] = 0; - } - doExit(0); -} - - - -} // namespace fabgl diff --git a/src/inputbox.h b/src/inputbox.h deleted file mode 100644 index f039775ea..000000000 --- a/src/inputbox.h +++ /dev/null @@ -1,704 +0,0 @@ -/* - Created by Fabrizio Di Vittorio (fdivitto2013@gmail.com) - - Copyright (c) 2019-2022 Fabrizio Di Vittorio. - All rights reserved. - - -* Please contact fdivitto2013@gmail.com if you need a commercial license. - - -* This library and related software is available under GPL v3. - - FabGL is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - FabGL is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with FabGL. If not, see . - */ - - -#pragma once - - -/** - * @file - * - * @brief This file contains the InputBox class - */ - - - -#include -#include - -#include "fabglconf.h" -#include "fabui.h" -#include "fabutils.h" -#include "dispdrivers/vgapalettedcontroller.h" -#include "comdrivers/ps2controller.h" - - - -namespace fabgl { - - - -/** \ingroup Enumerations - * @brief Result of InputBox dialogs helper class - */ -enum class InputResult { - None = 0, /**< Still running */ - ButtonExt0 = 1, /**< Button Ext 0 pressed */ - ButtonExt1 = 2, /**< Button Ext 1 pressed */ - ButtonExt2 = 3, /**< Button Ext 3 pressed */ - ButtonExt3 = 4, /**< Button Ext 4 pressed */ - Cancel = 5, /**< Button CANCEL or ESC key pressed */ - ButtonLeft = 5, /**< Left button (cancel) or ESC key pressed */ - Enter = 6, /**< Button OK, ENTER or RETURN pressed */ - ButtonRight = 6, /**< Right button (OK), ENTER or RETURN pressed */ -}; - - - -//////////////////////////////////////////////////////////////////////////////////////////////////// -// InputForm - - -class InputBox; - - -struct InputForm { - InputForm(InputBox * inputBox_) - : inputBox(inputBox_) - { - } - - void init(uiApp * app_, bool modalDialog_); - - virtual void addControls() = 0; - virtual void calcRequiredSize() = 0; - virtual void finalize() { } - virtual void show() { } - - void doExit(int value); - void defaultEnterHandler(uiKeyEventInfo const & key); - void defaultEscapeHandler(uiKeyEventInfo const & key); - - - static constexpr int BUTTONS = 6; - - InputBox * inputBox; - - uiApp * app; - - char const * titleText; - int autoOK; - - FontInfo const * font; - int requiredWidth; - int requiredHeight; - - uiFrame * mainFrame; - uiPanel * panel; - uiLabel * autoOKLabel; - - InputResult retval; - int buttonSubItem; // in case of button with subitems, specifies the selected subitem - - uiWindow * controlToFocus; - - bool modalDialog; -}; - - - -//////////////////////////////////////////////////////////////////////////////////////////////////// -// InputApp - - -struct InputApp : public uiApp { - InputApp(InputForm * form_) { form = form_; } - virtual void init() { form->init(this, false); } - - InputForm * form; -}; - - - - -//////////////////////////////////////////////////////////////////////////////////////////////////// -// TextInputForm - - -struct TextInputForm : public InputForm { - TextInputForm(InputBox * inputBox_) - : InputForm(inputBox_) - { - } - - void addControls(); - void calcRequiredSize(); - void finalize(); - - char const * labelText; - char * inOutString; - int maxLength; - bool passwordMode; - - int editExtent; - int labelExtent; - - uiTextEdit * edit; -}; - - - -//////////////////////////////////////////////////////////////////////////////////////////////////// -// MessageForm - - -struct MessageForm : public InputForm { - MessageForm(InputBox * inputBox_) - : InputForm(inputBox_) - { - } - - void addControls(); - void calcRequiredSize(); - void finalize(); - - char const * messageText; - - int messageExtent; -}; - - - -//////////////////////////////////////////////////////////////////////////////////////////////////// -// SelectForm - - -struct SelectForm : public InputForm { - SelectForm(InputBox * inputBox_) - : InputForm(inputBox_) - { - } - - void addControls(); - void calcRequiredSize(); - void finalize(); - - int countItems(size_t * maxLength); - - char const * messageText; - char const * items; // "separator" separated items (zero ends the list) - char separator; - StringList * itemsList; - bool menuMode; - - int listBoxHeight; - int outSelected; - - uiListBox * listBox; -}; - - - -//////////////////////////////////////////////////////////////////////////////////////////////////// -// ProgressForm - - -struct ProgressForm : public InputForm { - ProgressForm(InputBox * inputBox_) - : InputForm(inputBox_) - { - } - - void addControls(); - void calcRequiredSize(); - void show(); - - bool update(int percentage, char const * format, ...); - - static const int progressBarHeight = 16; - - bool hasProgressBar; - Delegate execFunc; - int width; - - uiLabel * label; - uiProgressBar * progressBar; -}; - - - -//////////////////////////////////////////////////////////////////////////////////////////////////// -// FileBrowserForm - - -struct FileBrowserForm : public InputForm { - static constexpr int SIDE_BUTTONS_WIDTH = 65; - static constexpr int SIDE_BUTTONS_HEIGHT = 18; - static constexpr int CTRLS_DIST = 4; - static constexpr int BROWSER_WIDTH = 150; - static constexpr int BROWSER_HEIGHT = 242; - static constexpr int MAXNAME = 32; - - FileBrowserForm(InputBox * inputBox_) - : InputForm(inputBox_) - { - } - ~FileBrowserForm() { - free(srcDirectory); - free(srcFilename); - } - void doCopy(); - void doPaste(); - - void addControls(); - void calcRequiredSize(); - void finalize(); - - char const * directory; - - char * srcDirectory = nullptr; - char * srcFilename = nullptr; - - uiFileBrowser * fileBrowser; - uiButton * newFolderButton; - uiButton * renameButton; - uiButton * deleteButton; - uiButton * copyButton; - uiButton * pasteButton; -}; - - - -//////////////////////////////////////////////////////////////////////////////////////////////////// -// FileSelectorForm - -struct FileSelectorForm : public InputForm { - static constexpr int CTRLS_DIST = 4; - static constexpr int BROWSER_WIDTH = 180; - static constexpr int BROWSER_HEIGHT = 150; - static constexpr int MINIMUM_EDIT_WIDTH = 64; - - FileSelectorForm(InputBox * inputBox_) - : InputForm(inputBox_) - { - } - - void addControls(); - void calcRequiredSize(); - void finalize(); - - char const * labelText; - char * inOutDirectory; - int maxDirectoryLength; - char * inOutFilename; - int maxFilenameLength; - - int editExtent; - int labelExtent; - - uiTextEdit * edit; - uiFileBrowser * fileBrowser; -}; - - - -//////////////////////////////////////////////////////////////////////////////////////////////////// -// InputBox - - -/** @brief InputBox is an helper class which allows to create simple UI interfaces, like wizards or simple input boxes */ -class InputBox { - -public: - - /** - * @brief Creates a new InputBox instance - * - * @param app Optional existing uiApp object. If specified applications can use InputBox helpers inside an uiApp object. - */ - InputBox(uiApp * app = nullptr); - - ~InputBox(); - - /** - * @brief Initializes InputBox from VGA modeline, using a VGA16Controller - * - * @param modeline Optional modeline (uses 640x480 resolution if not specified) - * @param viewPortWidth Viewport width (-1 = automatic) - * @param viewPortHeight Viewport height (-1 = automatic) - * @param displayColors Number of colors for the display (2, 4, 8 or 16) - */ - void begin(char const * modeline = nullptr, int viewPortWidth = -1, int viewPortHeight = -1, int displayColors = 16); - - /** - * @brief Initializes InputBox from already initialized display controller - * - * @param displayController Display controller already active - */ - void begin(BitmappedDisplayController * displayController); - - /** - * @brief Gets created or assigned display controller - * - * @return Display controller object - */ - BitmappedDisplayController * getDisplayController() { return m_dispCtrl; } - - /** - * @brief Cleanup resources and eventually disable VGA output - */ - void end(); - - /** - * @brief Sets the background color - * - * @param value Background color - */ - void setBackgroundColor(RGB888 const & value) { m_backgroundColor = value; } - - RGB888 backgroundColor() { return m_backgroundColor; } - - /** - * @brief Specifies a timeout for the dialog - * - * The timeout countdown stops if user moves mouse are type keyboard. - * - * @param timeout If >0, OK is automatically trigged after specified number of seconds - */ - void setAutoOK(int timeout) { m_autoOK = timeout; } - - /** - * @brief Setups extended button or split-button - * - * Extended button texts are reset to empty values after every dialog. - * - * @param index A value from 0 to 3. 0 = leftmost button ... 3 = rightmost button - * @param text Button text - * @param subItems If specified a Split Button is created. subItems contains a semicolon separated list of menu items - * @param subItemsHeight Determines split button sub items height in pixels - */ - void setupButton(int index, char const * text, char const * subItems = nullptr, int subItemsHeight = 80); - - /** - * @brief Sets minimum buttons size - * - * @param value Minimum button size in pixels - */ - void setMinButtonsWidth(int value) { m_minButtonsWidth = value; } - - int minButtonsWidth() { return m_minButtonsWidth; } - - char const * buttonText(int index) { return m_buttonText[index]; } - - char const * buttonSubItems(int index) { return m_buttonSubItems[index]; } - - int buttonsSubItemsHeight(int index) { return m_buttonSubItemsHeight[index]; } - - /** - * @brief Gets last dialog result - * - * @return Last result - */ - InputResult getLastResult() { return m_lastResult; } - - /** - * @brief Gets the selected item on a multichoice button - * - * return Selected sub item - */ - int selectedSubItem() { return m_buttonSubItem; } - - /** - * @brief Shows a dialog with a label and a text edit box - * - * @param titleText Optional title of the dialog (nullptr = the dialogs hasn't a title) - * @param labelText Label text - * @param inOutString This is the input and output edit box string - * @param maxLength Maximum length of the edit box string (not including ending zero) - * @param buttonCancelText Optional text for CANCEL button (nullptr = hasn't CANCEL button). Default is "Cancel". - * @param buttonOKText Optional text for OK button (nullptr = hasn't OK button). Default is "OK". - * @param passwordMode Optional password mode. If True all characters are shown using "*". Default is false. - * - * @return Dialog box result (Cancel or Enter) - * - * Example: - * - * char wifiName[32]; - * char wifiPsw[32]; - * InputBox ib; - * ib.begin(); - * if (ib.message("Network Configuration", "Configure WIFI network?", "No", "Yes") == InputResult::Enter) { - * ib.textInput("Network Configuration", "WiFi Name", wifiName, 31); - * ib.textInput("Network Configuration", "WiFi Password", wifiPsw, 31, "Cancel", "OK", true); - * } - * ib.end(); - */ - InputResult textInput(char const * titleText, char const * labelText, char * inOutString, int maxLength, char const * buttonCancelText = "Cancel", char const * buttonOKText = "OK", bool passwordMode = false); - - /** - * @brief Shows a dialog with just a label - * - * @param titleText Optional title of the dialog (nullptr = the dialogs hasn't a title) - * @param messageText Message to show - * @param buttonCancelText Optional test for CANCEL button (nullptr = hasn't CANCEL button). Default is nullptr. - * @param buttonOKText Optional text for OK button (nullptr = hasn't OK button). Default is "OK". - * - * @return Dialog box result (Cancel or Enter) - * - * Example: - * - * char wifiName[32]; - * char wifiPsw[32]; - * InputBox ib; - * ib.begin(); - * if (ib.message("Network Configuration", "Configure WIFI network?", "No", "Yes") == InputResult::Enter) { - * ib.textInput("Network Configuration", "WiFi Name", wifiName, 31); - * ib.textInput("Network Configuration", "WiFi Password", wifiPsw, 31, "Cancel", "OK", true); - * } - * ib.end(); - */ - InputResult message(char const * titleText, char const * messageText, char const * buttonCancelText = nullptr, char const * buttonOKText = "OK"); - - /** - * @brief Shows a dialog with a just a label. Allows printf like formatted text - * - * @param titleText Optional title of the dialog (nullptr = the dialogs hasn't a title) - * @param buttonCancelText Optional test for CANCEL button (nullptr = hasn't CANCEL button) - * @param buttonOKText Optional text for OK button (nullptr = hasn't OK button) - * @param format printf like format string - * @param ... printf like parameters - * - * @return Dialog box result (Cancel or Enter) - * - * Example: - * - * InputBox ib; - * ib.begin(); - * for (int i = 0; i < 3; ++i) - * if (ib.messageFmt(nullptr, "Abort", "Continue", "Iteration number %d of 3", i) == InputResult::Cancel) - * break; - * ib.end(); - */ - InputResult messageFmt(char const * titleText, char const * buttonCancelText, char const * buttonOKText, const char *format, ...); - - /** - * @brief Shows a dialog with a label and a list box - * - * @param titleText Optional title of the dialog (nullptr = the dialogs hasn't a title) - * @param messageText Message to show - * @param itemsText String containing a separated list of items to show into the listbox - * @param separator Optional items separator. Default is ';' - * @param buttonCancelText Optional text for CANCEL button (nullptr = hasn't CANCEL button). Default is "Cancel". - * @param buttonOKText Optional text for OK button (nullptr = hasn't OK button). Default is "OK". - * - * @return Index of the selected item or -1 if dialog has been canceled - * - * Example: - * - * InputBox ib; - * ib.begin(); - * int s = ib.select("Download Boot Disk", "Select boot disk to download", "FreeDOS;Minix 2.0;MS-DOS 3.3"); - * ib.messageFmt("", nullptr, "OK", "You have selected %d", s); - * ib.end(); - */ - int select(char const * titleText, char const * messageText, char const * itemsText, char separator = ';', char const * buttonCancelText = "Cancel", char const * buttonOKText = "OK"); - - /** - * @brief Shows a dialog with a label and a list box - * - * @param titleText Optional title of the dialog (nullptr = the dialogs hasn't a title) - * @param messageText Message to show - * @param items StringList object containing the items to show into the listbox. This parameter contains items selected before and after the dialog - * @param buttonCancelText Optional text for CANCEL button (nullptr = hasn't CANCEL button). Default is "Cancel". - * @param buttonOKText Optional text for OK button (nullptr = hasn't OK button). Default is "OK". - * - * @return Dialog box result (Cancel or Enter) - * - * Example: - * - * InputBox ib; - * ib.begin(); - * StringList list; - * list.append("Option 0"); - * list.append("Option 1"); - * list.append("Option 2"); - * list.append("Option 3"); - * list.select(1, true); // initially item 1 (Option 1) is selected - * if (ib.select("Select values", "Please select one or more items", &list) == InputResult::Enter) { - * for (int i = 0; i < list.count(); ++i) - * if (list.selected(i)) - * ib.messageFmt("", nullptr, "OK", "You have selected %d", i); - * } - * ib.end(); - */ - InputResult select(char const * titleText, char const * messageText, StringList * items, char const * buttonCancelText = "Cancel", char const * buttonOKText = "OK"); - - /** - * @brief Shows a dialog with a label and a list box. The dialog exits when an item is selected, just like a menu - * - * @param titleText Optional title of the dialog (nullptr = the dialogs hasn't a title) - * @param messageText Message to show - * @param itemsText String containing a separated list of items to show into the listbox - * @param separator Optional items separator. Default is ';' - * - * @return Index of the selected item or -1 if dialog has been canceled - * - * Example: - * - * InputBox ib; - * ib.begin(); - * int s = ib.menu("Menu", "Click on an item", "Item number one;Item number two;Item number three;Item number four"); - * ib.messageFmt("", nullptr, "OK", "You have selected %d", s); - * ib.end(); - */ - int menu(char const * titleText, char const * messageText, char const * itemsText, char separator = ';'); - - /** - * @brief Shows a dialog with a label and a list box. The dialog exits when an item is selected, just like a menu - * - * @param titleText Optional title of the dialog (nullptr = the dialogs hasn't a title) - * @param messageText Message to show - * @param items StringList object containing the items to show into the listbox - * - * @return Index of the selected item or -1 if dialog has been canceled - * - * Example: - * - * InputBox ib; - * ib.begin(); - * StringList list; - * list.append("Menu item 0"); - * list.append("Menu item 1"); - * list.append("Menu item 2"); - * list.append("Menu item 3"); - * int s = ib.menu("Menu", "Click on a menu item", &list); - * ib.messageFmt("", nullptr, "OK", "You have selected %d", s); - * ib.end(); - */ - int menu(char const * titleText, char const * messageText, StringList * items); - - /** - * @brief Shows a dialog with a label and a progress bar, updated dynamically by a user function - * - * @param titleText Optional title of the dialog (nullptr = the dialogs hasn't a title) - * @param buttonCancelText Optional text for CANCEL button (nullptr = hasn't CANCEL button) - * @param hasProgressBar If true a progress bar is shown - * @param width Width in pixels of the dialog - * @param execFunc A lambda function which updates the text and the progress bar calling the parameter object's update() function - * - * @return Dialog box result (Cancel or Enter) - * - * Example: - * - * InputBox ib; - * ib.begin(); - * auto r = ib.progressBox("This is the title", "Abort", true, 200, [&](fabgl::ProgressForm * form) { - * for (int i = 0; i <= 100; ++i) { - * if (!form->update(i, "Index is %d/100", i)) - * break; - * delay(100); - * } - * }); - * if (r == InputResult::Cancel) - * ib.message("", "Operation Aborted"); - * ib.end(); - */ - template - InputResult progressBox(char const * titleText, char const * buttonCancelText, bool hasProgressBar, int width, Func execFunc) { - ProgressForm form(this); - form.execFunc = execFunc; - return progressBoxImpl(form, titleText, buttonCancelText, hasProgressBar, width); - } - - /** - * @brief Shows a dialog with files and folders and buttons to create new folders, delete and rename folders and files - * - * @param titleText Optional title of the dialog (nullptr = the dialogs hasn't a title) - * @param directory Initial directory. At least one file system must be mounted - * @param buttonOKText Optional text for OK button (nullptr = hasn't OK button). Default is "Close". - * - * @return Dialog box result (Cancel or Enter) - * - * Example: - * - * InputBox ib; - * ib.begin(); - * if (FileBrowser::mountSDCard(false, "/SD")) - * ib.fileBrowser("File Browser", "/SD"); - * ib.end(); - */ - InputResult folderBrowser(char const * titleText, char const * directory = "/", char const * buttonOKText = "Close"); - - /** - * @brief Selects a file and directory starting from the specified path - * - * @param titleText Optional title of the dialog (nullptr = the dialogs hasn't a title) - * @param messageText Message to show - * @param inOutDirectory Starting directory as input, selected directory as output - * @param maxDirectoryLength Maximum length of directory buffer (not including ending zero) - * @param inOutFilename Initial filename as input, selected filename as output - * @param maxFilenameLength Maximum length of filename buffer (not including ending zero) - * @param buttonCancelText Optional text for CANCEL button (nullptr = hasn't CANCEL button). Default is "Cancel". - * @param buttonOKText Optional text for OK button (nullptr = hasn't OK button). Default is "OK". - * - * @return Dialog box result (Cancel or Enter) - * - * Example: - * - * InputBox ib; - * ib.begin(); - * if (FileBrowser::mountSDCard(false, "/SD")) { - * char filename[16] = ""; - * char directory[32] = "/SD" - * if (ib.fileSelector("File Select", "Filename: ", directory, sizeof(directory) - 1, filename, sizeof(filename) - 1) == InputResult::Enter) - * ib.messageFmt("", nullptr, "OK", "Folder = %s, File = %s", directory, filename); - * } - * ib.end(); - */ - InputResult fileSelector(char const * titleText, char const * messageText, char * inOutDirectory, int maxDirectoryLength, char * inOutFilename, int maxFilenameLength, char const * buttonCancelText = "Cancel", char const * buttonOKText = "OK"); - - - // delegates - - /** - * @brief Paint event delegate - */ - Delegate onPaint; - - - -private: - - InputResult progressBoxImpl(ProgressForm & form, char const * titleText, char const * buttonCancelText, bool hasProgressBar, int width); - - void exec(InputForm * form); - void resetButtons(); - - BitmappedDisplayController * m_dispCtrl; - VGAPalettedController * m_vgaCtrl; - RGB888 m_backgroundColor; - uiApp * m_existingApp; // uiApp in case of running on existing app - uint16_t m_autoOK; // auto ok in seconds - int16_t m_buttonSubItem; // in case of button with subitems, specifies the selected subitem // - char const * m_buttonText[InputForm::BUTTONS] = { }; - char const * m_buttonSubItems[InputForm::BUTTONS] = { }; // ext button is uiButton is nullptr, uiSplitButton otherwise - uint16_t m_buttonSubItemsHeight[InputForm::BUTTONS] = { }; - InputResult m_lastResult = InputResult::None; - int16_t m_minButtonsWidth; -}; - - - -} // namespace fabgl diff --git a/src/terminal.cpp b/src/terminal.cpp index 80b56a345..d3510a8a9 100644 --- a/src/terminal.cpp +++ b/src/terminal.cpp @@ -46,6 +46,7 @@ #include "esp_intr_alloc.h" +#include "fabfonts.h" #include "fabutils.h" #include "terminal.h" #include "devdrivers/mouse.h" @@ -4483,7 +4484,7 @@ void Terminal::consumeFabGLGraphicsSeq() // R (text) : red (0..255) when FORMAT is "MASK" // G (text) : green (0..255) when FORMAT is "MASK" // B (text) : blue (0..255) when FORMAT is "MASK" - // DATA (text) : 2 digits hex number + // DATA (text) : 2 digits hex number int sprite = extGetIntParam(); extGetByteParam(); int width = extGetIntParam(); @@ -4585,7 +4586,7 @@ void Terminal::keyboardReaderTask(void * pvParameters) if (term->m_keyboard->getNextVirtualKey(&item)) { if (term->isActive()) { - + term->onVirtualKey(&item.vk, item.down); term->onVirtualKeyItem(&item); @@ -4615,7 +4616,7 @@ void Terminal::keyboardReaderTask(void * pvParameters) // !keyDown term->m_lastPressedKey = VK_NONE; } - + } } else {