diff --git a/.ci/clang-tidy.sh b/.ci/clang-tidy.sh new file mode 100644 index 0000000..13b2ac7 --- /dev/null +++ b/.ci/clang-tidy.sh @@ -0,0 +1,32 @@ +#!/bin/sh + +echo "Doing clang-tidy..." +bool=false +# explicitly set IFS to contain only a line feed +IFS=' +' +filelist="$(find . -not \( -path './*build*' -prune \) -not \( -path './include' -prune \) -not \( -path './lib' -prune \) -type f ! -name "$(printf "*\n*")")" +for file in $filelist; do + if echo "$file" | grep -q -E ".*(\.cpp|\.h|\.hpp)$" ; then + #Extra check missing dependencies due to clang-tidy doesn't toggle exit code. + clang_tidy_lib_check="$(clang-tidy -warnings-as-errors='*' -header-filter='.*,-cpptoml.hpp' "$file" -- -I. -std=c++14 2>&1)" + for tidy_line in $clang_tidy_lib_check; do + echo "$tidy_line" | grep -q -v -E "^Error while processing*" + if [ $? -eq 1 ]; then + bool=true + fi + echo "$tidy_line" | grep -q -v -E ".* error: .*" + if [ $? -eq 1 ]; then + bool=true + fi + echo "$tidy_line" + done + fi +done +if $bool; then + exit 1 +else + echo "No clang-tidy errors found." +fi + +exit 0 diff --git a/.clang-tidy b/.clang-tidy new file mode 100644 index 0000000..6e8db98 --- /dev/null +++ b/.clang-tidy @@ -0,0 +1,2 @@ +Checks: '*,-llvm-header-guard,-fuchsia*,-cppcoreguidelines-pro-bounds-pointer-arithmetic,-cppcoreguidelines-pro-bounds-constant-array-index,-bugprone-narrowing-conversions,-cppcoreguidelines-narrowing-conversions,-cppcoreguidelines-pro-type-const-cast,-cppcoreguidelines-pro-type-reinterpret-cast,-hicpp-signed-bitwise,-bugprone-exception-escape,-cppcoreguidelines-pro-type-member-init,-cppcoreguidelines-pro-type-cstyle-cast,-hicpp-member-init,-google-readability-namespace-comments,-llvm-namespace-comment,-cppcoreguidelines-pro-type-vararg,-hicpp-vararg,-modernize-use-trailing-return-type,-readability-magic-numbers,-cppcoreguidelines-avoid-magic-numbers' +WarningsAsErrors: 'true' diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml new file mode 100644 index 0000000..2815013 --- /dev/null +++ b/.gitlab-ci.yml @@ -0,0 +1,77 @@ +--- + +image: samueldebruyn/debian-git:latest + +stages: + - style + - test + - build + + +clang_tidy: + image: joethei/clang_tidy + stage: style + tags: + - docker-ci + script: + - mkdir current + - ls -d .[!.]* | grep -v current | xargs mv -t current + - git clone https://gitlab-ci-token:${CI_JOB_TOKEN}@gitlab.repo.digitech.hs-emden-leer.de/link/projekte/ws19/vkvm-new/library.git + - mkdir library/build + - cd library/build + - cmake .. + - make + - cd ../../current/.ci + - sh clang-tidy.sh + + +make_test: + stage: test + tags: + - docker-ci + script: + - apt-get update + - apt-get install -y g++ make cmake clang-tidy libfltk1.3 libfltk1.3-dev + - mkdir current + - ls | grep -v current | xargs mv -t current + - git clone https://github.com/catchorg/Catch2.git + - cd Catch2 + - cmake -Bbuild -H. -DBUILD_TESTING=OFF + - cmake --build build/ --target install + - cd .. + - git clone https://gitlab-ci-token:${CI_JOB_TOKEN}@gitlab.repo.digitech.hs-emden-leer.de/link/projekte/ws19/vkvm-new/library.git + - mkdir library/build + - cd library/build + - cmake .. + - make + - cd ../../current + - mkdir build + - cd build + - cmake .. + - make + - make test + +cmake_build: + stage: build + tags: + - docker-ci + script: + - apt-get update + - apt-get install -y g++ make cmake clang-tidy libfltk1.3 libfltk1.3-dev + - mkdir current + - ls | grep -v current | xargs mv -t current + - git clone https://github.com/catchorg/Catch2.git + - cd Catch2 + - cmake -Bbuild -H. -DBUILD_TESTING=OFF + - cmake --build build/ --target install + - cd .. + - git clone https://gitlab-ci-token:${CI_JOB_TOKEN}@gitlab.repo.digitech.hs-emden-leer.de/link/projekte/ws19/vkvm-new/library.git + - mkdir library/build + - cd library/build + - cmake .. + - make + - cd ../../current + - mkdir build + - cd build + - cmake .. + - make diff --git a/CMakeLists.txt b/CMakeLists.txt index ac80de4..3eb4a05 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -8,15 +8,15 @@ if ("${CMAKE_BINARY_DIR}" STREQUAL "${CMAKE_SOURCE_DIR}") endif() set_property(DIRECTORY APPEND PROPERTY ADDITIONAL_MAKE_CLEAN_FILES "bin" "doc" "CMakeFiles" "lib" "include") + project(GUI) set(CMAKE_CXX_STANDARD 14) -# enable clang_tidy -set(CMAKE_CXX_CLANG_TIDY "clang-tidy;-checks=*") -set(CMAKE_CXX_CLANG_TIDY clang-tidy;-header-filter=.;-checks=*;) +set(CMAKE_CXX_CLANG_TIDY "clang-tidy;") +set(CMAKE_CXX_CLANG_TIDY clang-tidy;-header-filter=.;) file(GLOB_RECURSE SOURCES src/*.cpp) -file(GLOB_RECURSE HEADERS src/*.h) +file(GLOB_RECURSE HEADERS src/*.hpp) file(GLOB_RECURSE TESTS test/*.cpp) set(LIB_PATH "${CMAKE_SOURCE_DIR}/../library") @@ -26,13 +26,25 @@ add_executable(GUI ${SOURCES} ${HEADERS} main/main.cpp) target_link_libraries(GUI ${LIB_PATH}/lib/liblibrary.a) -#TODO: add fltk here +set(FLTK_SKIP_FLUID true) +if(FALSE) +include_directories(../fltk-1.3.5/FL) +link_directories(${PROJECT_NAME} ../fltk-1.3.5/lib) +target_link_libraries(${PROJECT_NAME} fltk) +else() +find_package(FLTK REQUIRED) +include_directories(${FLTK_INCLUDE_DIR}) +target_link_libraries(${PROJECT_NAME} ${FLTK_PLATFORM_DEPENDENT_LIBS} ${FLTK_LIBRARIES} ${OPENGL_LIBRARIES}) +endif() enable_testing() find_package(Catch2 REQUIRED) add_executable(UnitTests ${SOURCES} ${HEADERS} ${TESTS}) target_link_libraries(UnitTests Catch2::Catch2) +target_link_libraries(UnitTests ${LIB_PATH}/lib/liblibrary.a) +target_link_libraries(UnitTests ${FLTK_PLATFORM_DEPENDENT_LIBS} ${FLTK_LIBRARIES} ${OPENGL_LIBRARIES}) include(CTest) include(Catch) catch_discover_tests(UnitTests) + diff --git a/README.md b/README.md index 830c863..5d78a92 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,7 @@ # vKVM GUI - +The GUI is based on the FLTK (Fast Light Toolkit) and creates a window, +which processes incoming signals from the Shared Memory into an visual image. +The image refreshes on each change within the Shared Memory and periodically by itself. ## Installation Use the installation script provided in the Scripts repository diff --git a/main/main.cpp b/main/main.cpp index 53edc26..f84d01f 100644 --- a/main/main.cpp +++ b/main/main.cpp @@ -1,5 +1,10 @@ -#include "../src/demo.h" +#include "../src/GUI.hpp" + +/** main + * The main function executes the functions of the GUI. + */ + +int main(int argc, char **argv) { + GUI_run(argc,argv); -int main() { - return test(); } \ No newline at end of file diff --git a/src/GUI.cpp b/src/GUI.cpp new file mode 100644 index 0000000..2cde0d1 --- /dev/null +++ b/src/GUI.cpp @@ -0,0 +1,64 @@ +#include "GUI.hpp" + + +/** GUI_run + * The GUI_run-function starts all functions needed for the GUI. + */ + +auto GUI_run(int argc, char **argv) -> int { + vkvm::initialize(0); + int window_height, window_width; + window_height = vkvm::getHeight(); + window_width = vkvm::getWidth(); + char *resolusion = get_resolusion(window_height, window_width); + std::cout << resolusion << std::endl; + auto *window = new GUI_Window(window_width, window_height + 30, "example"); + Statusbar *status[5]; + //Dummy-Values TBD + window->begin(); + auto *image = new Image(0, 30, window_width, window_height); + + status[0] = new Statusbar(0, 0, 300, 30, resolusion); + status[1] = new Statusbar(300, 0, 170, 30, "Event:"); + status[2] = new Statusbar(470, 0, 200, 30, "Mouse Position:"); + vkvm::registerEvent(vkvm::EventType::Redraw, [image]() { + redraw(image); + }); + vkvm::registerEvent(vkvm::EventType::UpdateControlRegisters, [image]() { + image->setDelay(vkvm::getRedrawInterval()); + }); + Fl::repeat_timeout(image->getDelay(), get_new_image, image); + window->end(); + window->show(argc, argv); + return Fl::run(); +} + +char *get_resolusion(int window_height, int window_width) { + char *resolusion = new char[25]; + std::string str_temp; + strcpy(resolusion, "Resolution Height:"); + str_temp = std::to_string(window_height); + strcat(resolusion, str_temp.c_str()); + strcat(resolusion, " Width:"); + str_temp = std::to_string(window_width); + strcat(resolusion, str_temp.c_str()); + return resolusion; +} + +void redraw(Image *image) { + image->getPixels(); + image->redraw(); +} + +void get_new_image(void *pointer) { + Image *image = ((Image *) pointer); + image->getPixels(); + Fl::repeat_timeout(image->getDelay(), refresh_image, pointer); +} + +void refresh_image(void *pointer) { + ((Image *) pointer)->redraw(); + get_new_image(pointer); +} + + diff --git a/src/GUI.hpp b/src/GUI.hpp new file mode 100644 index 0000000..7943393 --- /dev/null +++ b/src/GUI.hpp @@ -0,0 +1,79 @@ +#include +#include +#include +#include +#include +#include +#include +#include "Mouse_Status.hpp" +#include "vkvm.hpp" +#include "internal.hpp" + +#ifndef GUI_GUI_HPP +#define GUI_GUI_HPP + +/** GUI_Window + * The GUI_Window-class generates a window, within the window it recognizes the curretn mouse-position. + * It also recognizes if a button is pushed on the keyboard or the mouse. Furthermore the class depict the + * content of the Image-class and provides functions to refresh it. + * @param x The mouse-position on the x-axis. + * @param y The mouse-position on the y-axis. + * @param button The button that was pushed last. + */ +class GUI_Window : public Fl_Window { + int x, y, button,lastX,lastY,mouse_status; + vkvm::KeyCode keyCode; + + int handle(int e) override; + + static char *position_to_string(int x, int y); + +public: + GUI_Window(int x, int y, const char *l); +}; + +/** The constructor of the image class, get additional + * @param x: The mouse-position on the x-axis. + * @param y: The mouse-position on the y-axis: + * @param w: The width of a single pixel, + * @param h: The height of a single pixel. + */ + +class Image : public Fl_Widget { + uchar *buf; + double delay; + +public: + Image(int x, int y, int w, int h); + + void draw() override; + + void getPixels(); + + void setDelay(double delay); + + double getDelay(); +}; + +/** Statusbar + * The class inherits a char *text from the Fl_Box. It also shows the window-resolution and the mouse-position. + * @param text: A pointer to a char-array, that can contain a text like a status or whatever you want. + */ +class Statusbar : public Fl_Box { + char* text; +public: + Statusbar(int x, int y, int w, int h, char *text); +}; + +char *get_resolusion(int window_height, int window_width); + +void refresh_image(void *pointer); + +void get_new_image(void *pointer); + +void redraw(Image *image); + +int GUI_run(int argc, char **argv); + + +#endif //GUI_GUI_HPP diff --git a/src/GUI_Window.cpp b/src/GUI_Window.cpp new file mode 100644 index 0000000..13e1d75 --- /dev/null +++ b/src/GUI_Window.cpp @@ -0,0 +1,127 @@ +#include "GUI.hpp" + + +/*Function to handle the input*/ +auto GUI_Window::handle(int e) -> int { + switch (e) { + /*Mousebutton*/ + case FL_PUSH: + x = Fl::event_x(); + y = Fl::event_y(); + vkvm::setMousePosition(x, y); + if (Fl::event_button() == FL_LEFT_MOUSE) { + mouse_status |= Mouse_Status::left_down; + this->child(2)->label("Event:Mouse Left Down"); + vkvm::callEvent(vkvm::EventType::MouseLeftDown); + // std::cout<child(2)->label("Event:Mouse Right Down"); + vkvm::callEvent(vkvm::EventType::MouseRightDown); + // std::cout<child(2)->label("Event:Mouse Middle Down"); + vkvm::callEvent(vkvm::EventType::MouseMiddleDown); + // std::cout<child(2)->label("Event:Mouse Left Up"); + vkvm::callEvent(vkvm::EventType::MouseLeftUp); + // std::cout<child(2)->label("Event:Mouse Right Up"); + vkvm::callEvent(vkvm::EventType::MouseRightUp); + // std::cout<child(2)->label("Event:Mouse Middle Up"); + vkvm::callEvent(vkvm::EventType::MouseMiddleUp); + // std::cout<child(3)->label(position_to_string(x, y)); + switch (mouse_status) { + case Mouse_Status::left_down : + this->child(2)->label("Event:Mouse Left Drag"); + vkvm::callEvent(vkvm::EventType::MouseMove); + break; + case Mouse_Status::right_down : + this->child(2)->label("Event:Mouse Right Drag"); + vkvm::callEvent(vkvm::EventType::MouseMove); + break; + case Mouse_Status::middle_down : + this->child(2)->label("Event:Mouse Middle Drag"); + vkvm::callEvent(vkvm::EventType::MouseMove); + } + return 1; + + /*Mousemovement*/ + case FL_MOVE: + if (mouse_status == 0) { + x = Fl::event_x(); + y = Fl::event_y(); + if (lastX != x || lastY != y) { + lastX = x; + lastY = y; + vkvm::setMousePosition(x, y); + vkvm::callEvent(vkvm::EventType::MouseMove); + this->child(2)->label("Event:Mouse Move"); + this->child(3)->label(position_to_string(x, y)); + } + } else { + handle(FL_DRAG); + } + return 1; + /*keyboardbutton*/ + case FL_KEYBOARD: + button = Fl::event_button(); + keyCode = vkvm::KeyCode(button); + vkvm::buttonPressed(keyCode); + vkvm::callEvent(vkvm::EventType::KeyDown); + this->child(2)->label("Event:Key Down"); + return 1; + case FL_KEYUP: + button = Fl::event_button(); + std::cout << button << std::endl; + keyCode = vkvm::KeyCode(button); + vkvm::buttonPressed(keyCode); + vkvm::callEvent(vkvm::EventType::KeyUp); + this->child(2)->label("Event:Key Up"); + return 1; + } + + return -1; +} + +GUI_Window::GUI_Window(int x, int y, const char *l) : Fl_Window(x, y, l) { + lastX = 0; + lastY = 0; + mouse_status = 0; +} + +auto GUI_Window::position_to_string(int x, int y) -> char * { + auto *str = new char[25]; + std::string str_temp; + str = strcpy(str, "Mouse Position X:"); + str_temp = std::to_string(x); + str = strcat(str, str_temp.c_str()); + str = strcat(str, " Y:"); + str_temp = std::to_string(y); + str = strcat(str, str_temp.c_str()); + return str; +} + + diff --git a/src/Image.cpp b/src/Image.cpp new file mode 100644 index 0000000..9ebee9f --- /dev/null +++ b/src/Image.cpp @@ -0,0 +1,37 @@ +#include "GUI.hpp" + +/** Image + * The Image-class draws the bitmap that it get from the Shared Memory. + * @param *buf: A pointer to the bitmap, that the image-class has to draw. Three chars are needed to get the RGB-value of a pixel, so the size equals window_height * window_width * 3. + */ + +//Function to draw a bitmap +auto Image::draw() -> void { + fl_draw_image(buf, x(), y(), w(), h()); +} + +Image::Image(int x, int y, int w, int h) : + Fl_Widget(x, y, w, h, nullptr) { + buf = new uchar[w * h * 3]; + delay = ((double)vkvm::getRedrawInterval())/1000; +} + +/*A function to change the colors of the image-class. It reads the colors from the Shared Memory-Class*/ +auto Image::getPixels() -> void { + for (int i = 0; i < h(); i++) { + for (int j = 0; j < w(); j++) { + vkvm::Color c = vkvm::getPixel(j, i); + buf[(i * w() + j) * 3 + 0] = c.getRed(); + buf[(i * w() + j) * 3 + 1] = c.getGreen(); + buf[(i * w() + j) * 3 + 2] = c.getBlue(); + } + } +} + +auto Image::getDelay() -> double { + return delay; +} + +auto Image::setDelay(double delay) -> void { + this->delay = delay; +} diff --git a/src/Mouse_Status.hpp b/src/Mouse_Status.hpp new file mode 100644 index 0000000..9ebb122 --- /dev/null +++ b/src/Mouse_Status.hpp @@ -0,0 +1,12 @@ + + enum Mouse_Status { + left_down = 0b100, + right_down = 0b010, + middle_down = 0b001, + left_up = 0b011, + right_up = 0b101, + middle_up = 0b110, + }; + + + diff --git a/src/Statusbar.cpp b/src/Statusbar.cpp new file mode 100644 index 0000000..694d84a --- /dev/null +++ b/src/Statusbar.cpp @@ -0,0 +1,14 @@ +#include "GUI.hpp" + + +/** The constructor of Statusbar has to get additional parameters. + * @param x: The mouse-position on the x-axis. + * @param y: The mouse-position on the y-axis: + * @param w: The width of a single pixel, + * @param h: The height of a single pixel. + */ +Statusbar::Statusbar(int x, int y, int w, int h, char *text) : + Fl_Box(x, y, w, h, text) { + this->text = text; +}; + diff --git a/src/demo.cpp b/src/demo.cpp deleted file mode 100644 index 1cc01fc..0000000 --- a/src/demo.cpp +++ /dev/null @@ -1,5 +0,0 @@ -#include "demo.h" - -int test() { - return 42; -} diff --git a/src/demo.h b/src/demo.h deleted file mode 100644 index 9b77cb9..0000000 --- a/src/demo.h +++ /dev/null @@ -1,8 +0,0 @@ -#ifndef SHARED_MEMORY_DEMO_H -#define SHARED_MEMORY_DEMO_H - - -int test(); - - -#endif //SHARED_MEMORY_DEMO_H diff --git a/test/test_GUI.cpp b/test/test_GUI.cpp new file mode 100644 index 0000000..2010995 --- /dev/null +++ b/test/test_GUI.cpp @@ -0,0 +1,6 @@ +#include +#include "../src/GUI.hpp" + +TEST_CASE("GUI Test") { + REQUIRE(42 == 42); +} \ No newline at end of file diff --git a/test/test_demo.cpp b/test/test_demo.cpp deleted file mode 100644 index 7cb240e..0000000 --- a/test/test_demo.cpp +++ /dev/null @@ -1,6 +0,0 @@ -#include -#include "../src/demo.h" - -TEST_CASE("Demo test") { - REQUIRE(test() == 42); -} \ No newline at end of file