/* * unittest_gui.cpp * * Created on: 29 kwi 2019 * Author: robert */ #include #include #include #include #include #include #include #include #include #include "../gui/core/ImageManager.hpp" #include "log/log.hpp" #include "utf8/UTF8.hpp" #include "vfs.hpp" #include "gui/core/Font.hpp" #include "gui/core/BoundingBox.hpp" #include "gui/core/Context.hpp" #include "gui/core/Renderer.hpp" #include "gui/core/DrawCommand.hpp" #include "gui/core/Font.hpp" #include "gui/widgets/Window.hpp" #include "gui/widgets/Item.hpp" #include "gui/widgets/Label.hpp" #include "gui/widgets/BoxLayout.hpp" #include "gui/widgets/Image.hpp" class vfs vfs; static const int FrameBufferWidth = 480; static const int FrameBufferHeight = 600; static const int FrameBufferSize = FrameBufferWidth * FrameBufferHeight; typedef struct { uint32_t frameCount; uint32_t width; uint32_t height; } shared_memory; uint8_t *createSHMBuffer(std::string name) { shared_memory *shared_mem_ptr; int fd_shm; // check if shared memory blok is already created if ((fd_shm = shm_open(name.c_str(), O_RDWR | O_CREAT, 0660)) == -1) { std::cerr << "shm is already created" << std::endl; } else { std::cout << "shm created" << std::endl; if (ftruncate(fd_shm, sizeof(shared_memory) + FrameBufferSize) == -1) { std::cerr << "shm is already created" << std::endl; } } if ((shared_mem_ptr = static_cast( mmap(NULL, sizeof(shared_memory) + FrameBufferSize, PROT_READ | PROT_WRITE, MAP_SHARED, fd_shm, 0))) == MAP_FAILED) { std::cerr << "mmap failed" << std::endl; } return reinterpret_cast(shared_mem_ptr); } using namespace std; bool bouindingBoxTest() { gui::BoundingBox result; if (gui::BoundingBox::intersect(gui::BoundingBox(0, 0, 15, 15), gui::BoundingBox(15, 0, 15, 15), result)) return false; if (gui::BoundingBox::intersect(gui::BoundingBox(0, 0, 15, 15), gui::BoundingBox(0, 15, 15, 15), result)) return false; if (gui::BoundingBox::intersect(gui::BoundingBox(0, 0, 15, 15), gui::BoundingBox(-15, 0, 15, 15), result)) return false; if (gui::BoundingBox::intersect(gui::BoundingBox(0, 0, 15, 15), gui::BoundingBox(0, -15, 15, 15), result)) return false; if (gui::BoundingBox::intersect(gui::BoundingBox(0, 0, 15, 15), gui::BoundingBox(14, 0, 15, 15), result) == false) return false; return true; } bool getContextBoxTest() { gui::Context *ctx = new gui::Context(static_cast(30), static_cast(30)); ctx->fill(0); gui::Context *test = ctx->get(17, 17, 30, 30); delete test; test = ctx->get(-17, -17, 30, 30); delete test; delete ctx; return true; } bool insertContextTest() { gui::Context *dstCtx; gui::Context *insCtx; LOG_INFO("RECTANGLE INSIDE"); dstCtx = new gui::Context(static_cast(30), static_cast(30)); dstCtx->fill(0); insCtx = new gui::Context(static_cast(28), static_cast(28)); insCtx->fill(15); dstCtx->insert(1, 1, insCtx); delete dstCtx; delete insCtx; LOG_INFO("2 COLUMNS ON RIGHT SIDE, TOP AND BOTTOM ROW UNTOUCHED"); dstCtx = new gui::Context(static_cast(30), static_cast(30)); dstCtx->fill(0); insCtx = new gui::Context(static_cast(28), static_cast(28)); insCtx->fill(15); dstCtx->insert(28, 1, insCtx); delete dstCtx; delete insCtx; LOG_INFO("2 COLUMNS ON LEFT SIDE, TOP AND BOTTOM ROW UNTOUCHED"); dstCtx = new gui::Context(static_cast(30), static_cast(30)); dstCtx->fill(0); insCtx = new gui::Context(static_cast(28), static_cast(28)); insCtx->fill(15); dstCtx->insert(-26, 1, insCtx); delete dstCtx; delete insCtx; LOG_INFO("2 COLUMNS ON RIGHT SIDE"); dstCtx = new gui::Context(static_cast(30), static_cast(30)); dstCtx->fill(0); insCtx = new gui::Context(static_cast(32), static_cast(32)); insCtx->fill(15); dstCtx->insert(28, -1, insCtx); delete dstCtx; delete insCtx; LOG_INFO("2 COLUMNS ON LEFT SIDE"); dstCtx = new gui::Context(static_cast(30), static_cast(30)); dstCtx->fill(0); insCtx = new gui::Context(static_cast(32), static_cast(32)); insCtx->fill(15); dstCtx->insert(-30, -1, insCtx); delete dstCtx; delete insCtx; return true; } bool drawRectangleTest(uint8_t *frameBuffer) { // context for drawing commands gui::Context *context = new gui::Context(static_cast(480), static_cast(600)); context->fill(15); // renderer class that will perform drawing gui::Renderer renderer; // vector with draw commands std::vector commands; // simple filled rectangle with no rounded corners gui::CommandRectangle *rectTop = new gui::CommandRectangle(); gui::CommandRectangle *rectBottom = new gui::CommandRectangle(); gui::CommandRectangle *rectLeft = new gui::CommandRectangle(); gui::CommandRectangle *rectRight = new gui::CommandRectangle(); gui::CommandRectangle *rectFull = new gui::CommandRectangle(); rectTop->areaX = 5; rectTop->areaY = 5; rectTop->areaW = 8; rectTop->areaH = 8; rectTop->x = 5; rectTop->y = 5; rectTop->w = 8; rectTop->h = 8; rectTop->edges = gui::RectangleEdgeFlags::GUI_RECT_EDGE_LEFT | gui::RectangleEdgeFlags::GUI_RECT_EDGE_RIGHT | gui::RectangleEdgeFlags::GUI_RECT_EDGE_BOTTOM; *rectBottom = *rectTop; rectBottom->areaX = 31; rectBottom->areaY = 5; rectBottom->x = 31; rectBottom->y = 5; rectBottom->edges = gui::RectangleEdgeFlags::GUI_RECT_EDGE_LEFT | gui::RectangleEdgeFlags::GUI_RECT_EDGE_RIGHT | gui::RectangleEdgeFlags::GUI_RECT_EDGE_TOP; *rectLeft = *rectTop; rectLeft->areaX = 5; rectLeft->areaY = 31; rectLeft->x = 5; rectLeft->y = 31; rectLeft->edges = gui::RectangleEdgeFlags::GUI_RECT_EDGE_TOP | gui::RectangleEdgeFlags::GUI_RECT_EDGE_RIGHT | gui::RectangleEdgeFlags::GUI_RECT_EDGE_BOTTOM; *rectRight = *rectTop; rectRight->areaX = 31; rectRight->areaY = 31; rectRight->x = 31; rectRight->y = 31; rectRight->edges = gui::RectangleEdgeFlags::GUI_RECT_EDGE_TOP | gui::RectangleEdgeFlags::GUI_RECT_EDGE_LEFT | gui::RectangleEdgeFlags::GUI_RECT_EDGE_BOTTOM; *rectFull = *rectTop; rectFull->areaX = 18; rectFull->areaY = 18; rectFull->x = 18; rectFull->y = 18; rectFull->edges = gui::RectangleEdgeFlags::GUI_RECT_ALL_EDGES; commands.push_back(rectTop); commands.push_back(rectBottom); commands.push_back(rectLeft); commands.push_back(rectRight); commands.push_back(rectFull); gui::CommandRectangle *rect = new gui::CommandRectangle(); rect->areaX = 5; rect->areaY = 50; rect->areaW = 50; rect->areaH = 50; rect->x = 5; rect->y = 50; rect->w = 50; rect->h = 50; rect->borderColor = gui::Color(12, 15); rect->fillColor = rect->borderColor; rect->filled = true; rect->edges = gui::RectangleEdgeFlags::GUI_RECT_ALL_EDGES; commands.push_back(rect); gui::CommandRectangle *rectRoundTR = new gui::CommandRectangle(); rectRoundTR->areaX = 5; rectRoundTR->areaY = 150; rectRoundTR->areaW = 150; rectRoundTR->areaH = 150; rectRoundTR->x = 5; rectRoundTR->y = 150; rectRoundTR->w = 150; rectRoundTR->h = 150; rectRoundTR->edges = gui::RectangleEdgeFlags::GUI_RECT_ALL_EDGES; rectRoundTR->radius = 25; rectRoundTR->penWidth = 5; commands.push_back(rectRoundTR); // render commands renderer.render(context, commands); // copy context to shared memory memcpy(frameBuffer, context->getData(), FrameBufferSize); // cleanup for (auto cmd : commands) delete cmd; delete context; return true; } bool drawWindowWithLabelsTest(uint8_t *frameBuffer) { gui::Context *context = new gui::Context(static_cast(480), static_cast(600)); context->fill(15); // renderer class that will perform drawing gui::Renderer renderer; gui::Window *win = new gui::Window("MAIN"); win->setSize(480, 600); // add label with time gui::Label *label = new gui::Label(win, 20, 80, 440, 120, "TOP LEFT"); label->setAlignement(gui::Alignment(gui::Alignment::ALIGN_HORIZONTAL_LEFT, gui::Alignment::ALIGN_VERTICAL_TOP)); label->setRadius(5); label->setFont("gt_pressura_bold_65"); label = new gui::Label(win, 20, 280, 440, 120, "2xCENTER#####"); label->setAlignement( gui::Alignment(gui::Alignment::ALIGN_HORIZONTAL_CENTER, gui::Alignment::ALIGN_VERTICAL_CENTER)); label->setRadius(10); label->setPenWidth(5); label->setFont("gt_pressura_bold_65"); label = new gui::Label(win, 20, 480, 440, 120, "BOTTOM RIGHT"); label->setAlignement(gui::Alignment(gui::Alignment::ALIGN_HORIZONTAL_RIGHT, gui::Alignment::ALIGN_VERTICAL_BOTTOM)); label->setRadius(15); label->setDotsMode(true); label->setFont("gt_pressura_bold_65"); // vector with draw commands // context for drawing commands std::list commandsList = win->buildDrawList(); std::vector commands{commandsList.begin(), commandsList.end()}; delete win; // render commands renderer.render(context, commands); // copy context to shared memory memcpy(frameBuffer, context->getData(), FrameBufferSize); // cleanup for (auto cmd : commands) delete cmd; delete context; return true; } bool drawWindowWithHBoxTest(uint8_t *frameBuffer) { gui::Context *context = new gui::Context(static_cast(480), static_cast(600)); context->fill(15); // renderer class that will perform drawing gui::Renderer renderer; gui::Window *win = new gui::Window("MAIN"); win->setSize(480, 600); gui::HBox *hBox = new gui::HBox(win, 50, 50, 380, 500); gui::Rect *maxW1 = new gui::Rect(); maxW1->setFillColor(gui::Color(5, 0)); maxW1->setFilled(true); maxW1->setMaxSize(50, 300); gui::Label *maxW4 = new gui::Label(); maxW4->setText("Top Left corner"); maxW4->setDotsMode(true); // maxW4->setRadius( 20 ); // maxW4->setMargins( gui::Margins(20,20,20,20)); maxW4->setMaxSize(275, 60); gui::Rect *maxW2 = new gui::Rect(); maxW2->setFillColor(gui::Color(8, 0)); maxW2->setFilled(true); maxW2->setMaxSize(35, 300); gui::Rect *maxW3 = new gui::Rect(); maxW3->setFillColor(gui::Color(11, 0)); maxW3->setFilled(true); maxW3->setMaxSize(30, 300); hBox->addWidget(maxW1); hBox->addWidget(maxW4); hBox->addWidget(maxW2); gui::VBox *vBox = new gui::VBox(hBox, 10, 155, 460, 600 - 160); gui::Rect *maxH1 = new gui::Rect(); maxH1->setMaxSize(10, 80); gui::Rect *maxH2 = new gui::Rect(); maxH2->setMaxSize(15, 300); gui::Rect *maxH3 = new gui::Rect(); maxH3->setMaxSize(30, 300); gui::Label *maxH4 = new gui::Label(); maxH4->setText("Hello Mudita"); maxH4->setRadius(20); maxH4->setAlignement( gui::Alignment(gui::Alignment::ALIGN_HORIZONTAL_CENTER, gui::Alignment::ALIGN_VERTICAL_CENTER)); maxH4->setMaxSize(75, 60); // TODO:M.P unit test for GUI should be fixed/updated gui::Image* img1 = new gui::Image(); // TODO:M.P unit test for GUI should be fixed/updated uint16_t id = // gui::ImageManager::getInstance().load("loudspeaker.mpi"); // TODO:M.P unit test for GUI should be fixed/updated img1->setImageWithID( id ); vBox->addWidget(maxH1); vBox->addWidget(maxH2); vBox->addWidget(maxH4); // TODO:M.P unit test for GUI should be fixed/updated vBox->addWidget( img1 ); vBox->addWidget(maxH3); hBox->addWidget(maxW3); // context for drawing commands std::list commandsList = win->buildDrawList(); std::vector commands{commandsList.begin(), commandsList.end()}; delete win; // render commands renderer.render(context, commands); // copy context to shared memory memcpy(frameBuffer, context->getData(), FrameBufferSize); // cleanup for (auto cmd : commands) delete cmd; delete context; return true; } #include #include bool set_working_directory(std::string &dir) { char *currdirname = get_current_dir_name(); if (dir.c_str()[0] != '/') { if (dir.c_str()[0] == '.') { dir = std::string(dir.begin() + 1, dir.end()); } else { dir = "/" + dir; } dir = std::string(currdirname) + dir; } free(currdirname); if (chdir(dir.c_str())) { LOG_ERROR("Changing directory to: %s failed", dir.c_str()); } dir += "/assets"; DIR *check_path = opendir(dir.c_str()); if (ENOENT == errno || check_path == NULL) { LOG_ERROR("Working directory set: %s failure", dir.c_str()); return 1; } else { closedir(check_path); } return 0; } int main(int argc, char *argv[]) { LOG_INFO("RUNNING UNIT TEST FOR GUI"); char cwd[256] = {0}; if (getcwd(cwd, sizeof(cwd)) != NULL) { LOG_INFO("Current working directory: %s", cwd); } else { LOG_ERROR("getcwd() error"); } string basePath = cwd; if (argc != 2) { LOG_INFO("No working directory provided. Using current one."); } else { basePath = argv[1]; } if (set_working_directory(basePath)) { LOG_INFO("Tu run this test successfully provide path to assets, i.e. ./build/unittest_gui build/sys"); return 1; } gui::FontManager::getInstance().init(basePath); // TODO:M.P unit test for GUI should be fixed/updated gui::PixMapManager::getInstance().init( assetsPath ); // create and map shared memory std::string shmName = "pure_gui_fmbuf"; uint8_t *shmMemPtr = createSHMBuffer(shmName.c_str()) + sizeof(shared_memory); // BoundingBox tests if (!bouindingBoxTest()) LOG_ERROR("BOUNDING BOX TEST: failed"); else LOG_INFO("BOUNDING BOX TEST: pass"); // getContextBox tests if (!getContextBoxTest()) LOG_ERROR("GET CONTEXT TEST: failed"); else LOG_INFO("GET CONTEXT TEST: pass"); // insertContext tests if (!insertContextTest()) LOG_ERROR("INSERT CONTEXT TEST: failed"); else LOG_INFO("INSERT CONTEXT TEST: pass"); // draw rectangle tests if (!drawRectangleTest(shmMemPtr)) LOG_ERROR("DRAW RECTANGLE TEST: failed"); else LOG_INFO("DRAW RECTANGLE TEST: pass"); // draw labels if (!drawWindowWithLabelsTest(shmMemPtr)) LOG_ERROR("DRAW WINDOW TEST: failed"); else LOG_INFO("DRAW WINDOW TEST: pass"); // draw labels if (!drawWindowWithHBoxTest(shmMemPtr)) LOG_ERROR("DRAW HBOX TEST: failed"); else LOG_INFO("DRAW HBOX TEST: pass"); return 0; }