diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..e394b6e --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,74 @@ +CMAKE_MINIMUM_REQUIRED (VERSION 3.10.1) + +PROJECT (Pocketbook-Texteditor VERSION 0.0.1) + +set(CMAKE_CXX_STANDARD 14) + +set(CMAKE_SYSTEM_NAME Linux) +set(CMAKE_SYSTEM_VERSION 1.0) +set(CMAKE_SYSTEM_PROCESSOR armv7a) +set(BUILD_SHARED_LIBS ON) + +SET (TOOLCHAIN_PATH "../../SDK/SDK_6.3.0/SDK-B288") +set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) + +set(CMAKE_FIND_ROOT_PATH "${TOOLCHAIN_PATH}/usr/arm-obreey-linux-gnueabi/sysroot/") +set(CMAKE_INCLUDE_PATH "/usr/include") +message("CMAKE_FIND_ROOT_PATH=${CMAKE_FIND_ROOT_PATH}") +set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) +set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) +set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) +include_directories("${TOOLCHAIN_PATH}/usr/arm-obreey-linux-gnueabi/sysroot/usr/include/freetype2") +list(APPEND CMAKE_MODULE_PATH "${TOOLCHAIN_PATH}/usr/share/cmake/modules") +list(REMOVE_DUPLICATES CMAKE_MODULE_PATH) +set(QT_QMAKE_EXECUTABLE "${TOOLCHAIN_PATH}/usr/arm-obreey-linux-gnueabi/sysroot/usr/qt5/bin/qmake") +set(CMAKE_PREFIX_PATH "${TOOLCHAIN_PATH}/usr/arm-obreey-linux-gnueabi/sysroot/ebrmain/lib/cmake") + +set(CMAKE_C_COMPILER "${TOOLCHAIN_PATH}/usr/bin/arm-obreey-linux-gnueabi-clang") +set(CMAKE_CXX_COMPILER "${TOOLCHAIN_PATH}/usr/bin/arm-obreey-linux-gnueabi-clang++") +set(CMAKE_C_FLAGS "-fsigned-char -Werror-return-type" CACHE STRING "" FORCE) +set(CMAKE_CXX_FLAGS "-fsigned-char -Werror-return-type" CACHE STRING "" FORCE) +set(CMAKE_CXX_FLAGS_RELEASE "-DNDEBUG -O2 -pipe -fomit-frame-pointer -march=armv7-a -mtune=cortex-a8 -mfpu=neon -mfloat-abi=softfp " CACHE STRING "" FORCE) +set(CMAKE_C_FLAGS_RELEASE "-DNDEBUG -O2 -pipe -fomit-frame-pointer -march=armv7-a -mtune=cortex-a8 -mfpu=neon -mfloat-abi=softfp " CACHE STRING "" FORCE) +set(CMAKE_C_FLAGS_DEBUG "-DDEBUG -O0 -g -pipe -fomit-frame-pointer -march=armv7-a -mtune=cortex-a8 -mfpu=neon -mfloat-abi=softfp " CACHE STRING "" FORCE) +set(CMAKE_CXX_FLAGS_DEBUG "-DDEBUG -O0 -g -pipe -fomit-frame-pointer -march=armv7-a -mtune=cortex-a8 -mfpu=neon -mfloat-abi=softfp " CACHE STRING "" FORCE) +set(CMAKE_EXE_LINKER_FLAGS_RELEASE "-s" CACHE STRING "" FORCE) +set(CMAKE_SHARED_LINKER_FLAGS_RELEASE "-s" CACHE STRING "" FORCE) +set(CMAKE_SHARED_LINKER_FLAGS "-Wl,-z,defs" CACHE STRING "" FORCE) + +add_definitions(-DPLATFORM_FC) +set(PB_PLATFORM "ARM" CACHE STRING "ARM|PC Readonly!") + +set(CMAKE_INSTALL_PREFIX "${TOOLCHAIN_PATH}/usr/arm-obreey-linux-gnueabi/sysroot/usr/local" CACHE PATH "Installation Prefix") +set(CMAKE_BUILD_TYPE Release CACHE STRING "Debug|Release|RelWithDebInfo|MinSizeRel") +set(ENV{PKG_CONFIG_DIR} "") +set(ENV{PKG_CONFIG_LIBDIR} ${CMAKE_FIND_ROOT_PATH}/usr/lib/pkgconfig) +set(ENV{PKG_CONFIG_SYSROOT_DIR} ${CMAKE_FIND_ROOT_PATH}) +set(ENV{LD_LIBRARY_PATH} ${TOOLCHAIN_PATH}/usr/lib) +list(APPEND PB_LINK_DIRECTORIES "${TOOLCHAIN_PATH}/usr/arm-obreey-linux-gnueabi/sysroot/usr/lib") +list(APPEND PB_LINK_DIRECTORIES "${TOOLCHAIN_PATH}/usr/arm-obreey-linux-gnueabi/sysroot/usr/local/lib") +list(APPEND PB_INCLUDE_DIRECTORIES "${TOOLCHAIN_PATH}/usr/arm-obreey-linux-gnueabi/sysroot/usr/include") + + +set(SOURCES ${CMAKE_SOURCE_DIR}/src/main.cpp + ${CMAKE_SOURCE_DIR}/src/handler/eventHandler.cpp + ${CMAKE_SOURCE_DIR}/src/handler/mainMenu.cpp + ${CMAKE_SOURCE_DIR}/src/util/log.cpp + ${CMAKE_SOURCE_DIR}/src/ui/devicesView.cpp + ${CMAKE_SOURCE_DIR}/src/ui/devicesViewEntry.cpp + ${CMAKE_SOURCE_DIR}/src/ui/listView.cpp + ${CMAKE_SOURCE_DIR}/src/ui/listViewEntry.cpp + +) + +add_executable(Texteditor.app ${SOURCES}) + +include_directories( + ${CMAKE_SOURCE_DIR}/src/handler/ + ${CMAKE_SOURCE_DIR}/src/util/ + ${CMAKE_SOURCE_DIR}/src/ui/ +) + +target_link_libraries(Texteditor.app PRIVATE inkview pthread freetype) + +INSTALL (TARGETS Texteditor.app) diff --git a/README.md b/README.md index f6d5d3c..58d22fa 100644 --- a/README.md +++ b/README.md @@ -1,16 +1,33 @@ # Pocketbook Texteditor Texteditor for Pocketbook using a bluetooth keyboard. -//TODO add screenshots +     -## Features +## Tested on -## Requirements +### Devices +* Pocketbook Touch HD3 (PB632) + +### Keyboard +* Logitech K380 +## Requirements +* Bluetooth interface at PB +* Application PBTerm (https://userpage.physik.fu-berlin.de/~jtt/PB/) +* Root Access is necessary to register new inputs and access key events. (It is necessary to execute "jailbreak.app".) (https://www.mobileread.com/forums/showthread.php?t=325185) ## Installation Download and unzip the file from releases and place the texteditor.app into the "applications" folder of your pocketbook. +## Usage + +Currenlty the first pairing is not integrated into the application. Via the settings menu of the PB the registration of an keyboard is blocked. Therefore that has to be done once manually. +Enable Bluetooth on the Pocketbook in the Settings menu. +Open the PBTerm application and start bluetoothctl. +There you have to pair your bluetooth keyboard. (https://wiki.archlinux.org/title/bluetooth_keyboard) + +Once you have the keyboard paired you can open the texteditor.app and should be able to see your keyboard. Once the keyboard is selected, the input mode is opened. (To exit input mode press "ESC") + ## How to build First you need to install the basic build tools for linux. diff --git a/screenshots/textEditorDeviceSelection.bmp b/screenshots/textEditorDeviceSelection.bmp new file mode 100755 index 0000000..8e41e19 Binary files /dev/null and b/screenshots/textEditorDeviceSelection.bmp differ diff --git a/screenshots/textEditorInput.bmp b/screenshots/textEditorInput.bmp new file mode 100755 index 0000000..ea6dc8f Binary files /dev/null and b/screenshots/textEditorInput.bmp differ diff --git a/screenshots/textEditorNoDevices.bmp b/screenshots/textEditorNoDevices.bmp new file mode 100755 index 0000000..fc04c4a Binary files /dev/null and b/screenshots/textEditorNoDevices.bmp differ diff --git a/src/handler/eventHandler.cpp b/src/handler/eventHandler.cpp new file mode 100644 index 0000000..460d389 --- /dev/null +++ b/src/handler/eventHandler.cpp @@ -0,0 +1,456 @@ +//------------------------------------------------------------------ +// eventHandler.cpp +// +// Author: JuanJakobo +// Date: 22.04.2021 +// +//------------------------------------------------------------------- + +#include "eventHandler.h" +#include "inkview.h" + +#include "mainMenu.h" + +#include "log.h" + +#include "deviceModel.h" +#include "devicesView.h" + +#include +#include +#include + +#include +#include +#include + +#include + +using std::string; +using std::vector; + +std::unique_ptr EventHandler::_eventHandlerStatic; + +struct input_event event; + +EventHandler::EventHandler() +{ + //create an copy of the eventhandler to handle methods that require static functions + _eventHandlerStatic = std::unique_ptr(this); + + if (iv_access(CONFIG_FOLDER.c_str(), W_OK) != 0) + iv_mkdir(CONFIG_FOLDER.c_str(), 0777); + if (iv_access(ARTICLE_FOLDER.c_str(), W_OK) != 0) + iv_mkdir(ARTICLE_FOLDER.c_str(), 0777); + + createInputEvent(); +} + +EventHandler::~EventHandler() +{ +} + +int EventHandler::eventDistributor(const int type, const int par1, const int par2) +{ + if (ISPOINTEREVENT(type)) + return EventHandler::pointerHandler(type, par1, par2); + return 0; +} + +void EventHandler::mainMenuHandlerStatic(const int index) +{ + _eventHandlerStatic->mainMenuHandler(index); +} + +void EventHandler::mainMenuHandler(const int index) +{ + switch (index) + { + //create input event + case 101: + { + createInputEvent(); + break; + } + //start input mode + case 102: + { + startInputMode(); + break; + } + //Exit + case 103: + { + CloseApp(); + break; + } + default: + break; + } +} + +int EventHandler::pointerHandler(const int type, const int par1, const int par2) +{ + if (type == EVT_POINTERUP) + { + //if menu is clicked + if (IsInRect(par1, par2, _menu.getMenuButtonRect()) == 1) + { + return _menu.createMenu(EventHandler::mainMenuHandlerStatic); + } + else if (_currentView == Views::DEVICEVIEW) + { + if (_devicesView->checkIfEntryClicked(par1,par2)) + { + _devicesView->invertCurrentEntryColor(); + + if (iv_access("mnt/secure/su", R_OK) != 0){ + Message(ICON_ERROR,"Error","No root access available.",2000); + Log::writeInfoLog("no root access"); + _devicesView->invertCurrentEntryColor(); + return 1; + } + + _currentDevice = *_devicesView->getCurrentEntry(); + + std::ifstream infile("/sys" + _currentDevice.sysfs + "/event" + std::to_string(_currentDevice.eventID) + "/uevent"); + string line; + string major, minor, devname; + + while(std::getline(infile, line)) + { + if(line.find("MAJOR") != std::string::npos) + major = line.substr(line.find('=')+1); + if(line.find("MINOR") != std::string::npos) + minor = line.substr(line.find('=')+1); + if(line.find("DEVNAME") != std::string::npos) + devname = line.substr(line.find('=')+1); + } + + //auto z = system ("/mnt/secure/su rm event7"); + string mknod = "/mnt/secure/su mknod -m 664 /dev/input/event" + std::to_string(_currentDevice.eventID) + " c " + major + " " + minor; + Log::writeInfoLog(mknod); + auto i = system(mknod.c_str()); + Log::writeInfoLog("system return code " + std::to_string(i)); + startInputMode(); + + } + + } + } + return 0; +} + +void EventHandler::createInputEvent() +{ + //auto a = GetBluetoothStatus(); + //Log::writeInfoLog("bluetooth status " + std::to_string(a)); + + if (GetBluetoothMode() == BLUETOOTH_OFF) + SetBluetoothOn(); + + if(IsBluetoothAwake() == 0) + BluetoothWakeUp(); + + if(IsBluetoothEnabled() == 1){ + std::ifstream infile("/proc/bus/input/devices"); + string line; + + Device temp; + vector devices; + + while(std::getline(infile, line)) + { + if(line.front() == 'N') + temp.name = line.substr(line.find('=')+1); + if(line.front() == 'S') + temp.sysfs = line.substr(line.find('=')+1); + if(line.front() == 'U'){ + temp.uniq = line.substr(line.find('=')+1); + } + if(line.front() == 'H'){ + string handlers =line.substr(line.find('=')+1); + int t = handlers.find("event"); + if(t != std::string::npos){ + handlers = handlers.substr(t); + handlers = handlers.substr(5,1); + temp.eventID = std::stoi(handlers); + } + } + //TODO filter by type + //B: --> EV + //B: --> KEY + else if(line.empty() && !temp.name.empty() && temp.eventID > 6){ + devices.push_back(temp); + temp = {}; + } + } + + //write devices to list + if(devices.size() > 0){ + _devicesView.reset(new DevicesView(_menu.getContentRect(),devices,1)); + _devicesView->draw(); + _currentView = Views::DEVICEVIEW; + }else{ + FillAreaRect(_menu.getContentRect(), WHITE); + DrawTextRect2(_menu.getContentRect(), "No bluetooth keyboards available. Please pair a new one using bluetoothctl"); + _currentView = Views::DEFAULTVIEW; + PartialUpdate(_menu.getContentRect()->x, _menu.getContentRect()->y, _menu.getContentRect()->w, _menu.getContentRect()->h); + } + + }else{ + Message(ICON_ERROR,"Error", "Could not enable Bluetooth",2000); + } +} + +void EventHandler::startInputMode(){ + + if(_currentDevice.name.empty()){ + createInputEvent(); + }else{ + + FillArea(_menu.getContentRect()->x, _menu.getContentRect()->y, _menu.getContentRect()->w, _menu.getContentRect()->h,WHITE); + PartialUpdate(_menu.getContentRect()->x, _menu.getContentRect()->y, _menu.getContentRect()->w, _menu.getContentRect()->h); + + std::ifstream eventFile("/dev/input/event" + std::to_string(_currentDevice.eventID), std::ifstream::in); + + auto textHeight = 30; + auto textNextLineY = textHeight + 10; + auto charWidth = 20; + auto textBeginX = 0; + auto textEndX = ScreenWidth()-20; + auto textBeginY = _menu.getContentRect()->y; + auto textFont = OpenFont("Roboto", textHeight , FONT_STD); + SetFont(textFont, BLACK); + + if(eventFile.is_open()) { + + auto currentX = textBeginX; + auto currentY = textBeginY; + + string currentText; + + string textPath = ARTICLE_FOLDER + std::string("/text.txt"); + + if (iv_access(textPath.c_str(), W_OK) == 0){ + std::ifstream inFile(textPath); + string line; + bool multipleLines = false; + + if(inFile.is_open()){ + while ( getline(inFile,line)){ + if(multipleLines){ + currentX = textBeginX; + currentY += textNextLineY; + currentText += "\n"; + } + + for(const char &c : line) + { + //here function + multipleLines = true; + if(currentX > textEndX){ + currentX = textBeginX; + currentY += textNextLineY; + } + DrawTextRect(currentX,currentY,CharWidth(c),textHeight,&c,ALIGN_CENTER); + PartialUpdate(currentX,currentY,CharWidth(c),textHeight); + currentX += charWidth; //CharWidth(c); + } + + currentText += line; + } + inFile.close(); + } + + //PartialUpdate(_menu.getContentRect()->x, _menu.getContentRect()->y, _menu.getContentRect()->w, _menu.getContentRect()->h); + + } + + bool writeToScreen; + char data[sizeof(event)]; + bool inputSession = true; + Message(ICON_INFORMATION, "Information", "To cancel input mode press ESC.", 2000); + while(inputSession) { + eventFile.read(data,sizeof(event)); + memcpy(&event, data, sizeof(event)); + + char key; + writeToScreen = true; + + if(event.type == EV_KEY) { + if(event.value == EV_KEY) + { + //https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/include/uapi/linux/input-event-codes.h + + if(event.code == KEY_SPACE) { + key = ' '; + }else if(event.code == KEY_BACKSPACE) { + writeToScreen = false; + if(!currentText.empty()){ + if(currentText.back() == '\n'){ + currentText.pop_back(); + int last = currentText.find_last_of('\n'); + if(last != std::string::npos){ + currentText.pop_back(); + currentX = currentText.substr(last).size() * charWidth; + }else{ + currentX = currentText.size() * charWidth; + currentText.pop_back(); + } + currentY -= textNextLineY; + currentX -= charWidth; + FillArea(currentX,currentY, charWidth, textHeight, WHITE); + PartialUpdate(currentX,currentY,charWidth,textHeight); + + }else{ + if(currentX < textBeginX && currentY > textBeginY){ + //TODO other method needed + currentX = textEndX; + currentY -= textNextLineY; + } + currentX -= charWidth; + currentText.pop_back(); + FillArea(currentX,currentY, charWidth, textHeight, WHITE); + PartialUpdate(currentX,currentY,charWidth,textHeight); + } + + }else{ + Message(ICON_INFORMATION, "Information", "no more characters to delete.", 2000); + } + //TODO write to text + }else if(event.code == KEY_ENTER) { + currentX = textBeginX; + currentY += textNextLineY; + currentText += "\n"; + writeToScreen = false; + }else if(event.code == KEY_DOT) { + key = '.'; + }else if(event.code == KEY_COMMA) { + key = ','; + }else if(event.code == KEY_A) { + key = 'A'; + }else if(event.code == KEY_B) { + key = 'B'; + }else if(event.code == KEY_C) { + key = 'C'; + }else if(event.code == KEY_D) { + key = 'D'; + }else if(event.code == KEY_E) { + key = 'E'; + }else if(event.code == KEY_F) { + key = 'F'; + }else if(event.code == KEY_G) { + key = 'G'; + }else if(event.code == KEY_H) { + key = 'H'; + }else if(event.code == KEY_I) { + key = 'I'; + }else if(event.code == KEY_J) { + key = 'J'; + }else if(event.code == KEY_K) { + key = 'K'; + }else if(event.code == KEY_L) { + key = 'L'; + }else if(event.code == KEY_M) { + key = 'M'; + }else if(event.code == KEY_N) { + key = 'N'; + }else if(event.code == KEY_O) { + key = 'O'; + }else if(event.code == KEY_P) { + key = 'P'; + }else if(event.code == KEY_Q) { + key = 'Q'; + }else if(event.code == KEY_R) { + key = 'R'; + }else if(event.code == KEY_S) { + key = 'S'; + }else if(event.code == KEY_T) { + key = 'T'; + }else if(event.code == KEY_U) { + key = 'U'; + }else if(event.code == KEY_V) { + key = 'V'; + }else if(event.code == KEY_W) { + key = 'W'; + }else if(event.code == KEY_X) { + key = 'X'; + }else if(event.code == KEY_Y) { + key = 'Y'; + }else if(event.code == KEY_Z) { + key = 'Z'; + }else if(event.code == KEY_0) { + key = '0'; + }else if(event.code == KEY_1) { + key = '1'; + }else if(event.code == KEY_2) { + key = '2'; + }else if(event.code == KEY_3) { + key = '3'; + }else if(event.code == KEY_4) { + key = '4'; + }else if(event.code == KEY_5) { + key = '5'; + }else if(event.code == KEY_6) { + key = '6'; + }else if(event.code == KEY_7) { + key = '7'; + }else if(event.code == KEY_8) { + key = '8'; + }else if(event.code == KEY_9) { + key = '9'; + }else if(event.code == KEY_ESC) { + inputSession = false; + if(!currentText.empty()){ + std::ofstream text(textPath); + text << currentText; + text.close(); + Message(ICON_INFORMATION,"Information", "Input Mode closed. File saved.",1000); + }else{ + string path = ARTICLE_FOLDER + "/text.txt"; + remove(path.c_str()); + Message(ICON_INFORMATION,"Information", "Input Mode closed. File removed.",1000); + } + + + writeToScreen = false; + } + else { + Log::writeInfoLog("event code not included yet " + std::to_string(event.code)); + writeToScreen = false; + } + + if (writeToScreen){ + //FillArea(currentX+charWidth+10,currentY,currentX+charWidth+10,currentY + textHeight, WHITE); + currentText += key; + if(currentX > textEndX){ + currentX = textBeginX; + currentY += textNextLineY; + } + string text = {key}; + DrawTextRect(currentX,currentY, charWidth, textHeight, text.c_str(), ALIGN_CENTER); + PartialUpdate(currentX,currentY,charWidth,textHeight); + currentX += charWidth;//CharWidth(key); + //DrawLine(currentX+charWidth+10,currentY,currentX+charWidth+10,currentY + textHeight,BLACK); + //PartialUpdate(currentX+charWidth+10,currentY,currentX+charWidth+10,currentY + textHeight); + } + } + } + else + { + //Log::writeInfoLog("event type " + std::to_string(event.type)); + } + } + eventFile.close(); + } + else { + DrawTextRect(0, (ScreenHeight() / 3) * 2, ScreenWidth(), 30, strerror(errno), ALIGN_CENTER); + PartialUpdate(_menu.getContentRect()->x, _menu.getContentRect()->y, _menu.getContentRect()->w, _menu.getContentRect()->h); + } + + Log::writeInfoLog("closing input mode"); + CloseFont(textFont); + } +} + diff --git a/src/handler/eventHandler.h b/src/handler/eventHandler.h new file mode 100644 index 0000000..9e0f50e --- /dev/null +++ b/src/handler/eventHandler.h @@ -0,0 +1,88 @@ +//------------------------------------------------------------------ +// eventHandler.h +// +// Author: JuanJakob +// Date: 22.04.2021 +// Description: Handles all events and directs them +//------------------------------------------------------------------- + +#ifndef EVENT_HANDLER +#define EVENT_HANDLER + +#include "inkview.h" + +#include "mainMenu.h" + +#include "devicesView.h" + +#include +#include +#include +#include + +enum Views +{ + DEFAULTVIEW, + DEVICEVIEW +}; + +const std::string CONFIG_FOLDER = "/mnt/ext1/system/config/textEditor"; +const std::string ARTICLE_FOLDER = "/mnt/ext1/textEditor"; + +class EventHandler +{ +public: + /** + * Defines fonds, sets global Event Handler and starts new content + */ + EventHandler(); + + ~EventHandler(); + + /** + * Handles events and redirects them + * + * @param type event type + * @param par1 first argument of the event + * @param par2 second argument of the event + * @return int returns if the event was handled + */ + int eventDistributor(const int type, const int par1, const int par2); + +private: + static std::unique_ptr _eventHandlerStatic; + MainMenu _menu = MainMenu("Text Editor"); + std::unique_ptr _devicesView; + Views _currentView; + Device _currentDevice; + + /** + * Function needed to call C function, redirects to real function + * + * @param index int of the menu that is set + */ + static void mainMenuHandlerStatic(const int index); + + /** + * Handles menu events and redirects them + * + * @param index int of the menu that is set + */ + void mainMenuHandler(const int index); + + /** + * Handles pointer Events + * + * @param type event type + * @param par1 first argument of the event + * @param par2 second argument of the event + * @return int returns if the event was handled + */ + int pointerHandler(const int type, const int par1, const int par2); + + void createInputEvent(); + + void startInputMode(); + +}; +#endif diff --git a/src/handler/mainMenu.cpp b/src/handler/mainMenu.cpp new file mode 100644 index 0000000..fd980d5 --- /dev/null +++ b/src/handler/mainMenu.cpp @@ -0,0 +1,66 @@ +//------------------------------------------------------------------ +// mainMenu.cpp +// +// Author: JuanJakobo +// Date: 14.06.2020 +// +//------------------------------------------------------------------- + +#include "inkview.h" +#include "mainMenu.h" + +#include + +using std::string; + +MainMenu::MainMenu(const string &name) +{ + _panelMenuHeight = ScreenHeight() / 18; + _panelMenuBeginY = 0; + _mainMenuWidth = ScreenWidth() / 3; + _panelMenuBeginX = ScreenWidth() - _mainMenuWidth; + + _menuButtonRect = iRect(_mainMenuWidth * 2, _panelMenuBeginY, _mainMenuWidth, _panelMenuHeight, ALIGN_RIGHT); + + _menuFont = OpenFont("LiberationMono-Bold", _panelMenuHeight / 2, FONT_STD); + + SetFont(_menuFont, BLACK); + DrawTextRect(0, _panelMenuBeginY, ScreenWidth(), _panelMenuHeight, name.c_str(), ALIGN_CENTER); + DrawTextRect2(&_menuButtonRect, "Menu"); + DrawLine(0, _panelMenuHeight - 1, ScreenWidth(), _panelMenuHeight - 1, BLACK); + + _contentRect = iRect(0, _panelMenuHeight, ScreenWidth(), (ScreenHeight() - PanelHeight() - _panelMenuHeight), 0); + + SetHardTimer("PANELUPDATE", panelHandlerStatic, 110000); + DrawPanel(NULL, "", NULL, -1); +} + +MainMenu::~MainMenu() +{ + CloseFont(_menuFont); + free(_menu); + free(_connect); + free(_open); + free(_exit); +} + +void MainMenu::panelHandlerStatic() +{ + DrawPanel(NULL, "", NULL, -1); + SetHardTimer("PANELUPDATE", panelHandlerStatic, 110000); +} + +int MainMenu::createMenu(const iv_menuhandler &handler) +{ + imenu mainMenu[] = + { + {ITEM_HEADER, 0, _menu, NULL}, + {ITEM_ACTIVE, 101, _connect, NULL}, + {ITEM_ACTIVE, 102, _open, NULL}, + {ITEM_ACTIVE, 103, _exit, NULL}, + {0, 0, NULL, NULL}}; + + OpenMenu(mainMenu, 0, _panelMenuBeginX, _panelMenuBeginY, handler); + + return 1; +} diff --git a/src/handler/mainMenu.h b/src/handler/mainMenu.h new file mode 100644 index 0000000..71515cf --- /dev/null +++ b/src/handler/mainMenu.h @@ -0,0 +1,60 @@ +//------------------------------------------------------------------ +// mainMenu.h +// +// Author: JuanJakobo +// Date: 14.06.2020 +// Description: Handles the menubar and the menu +//------------------------------------------------------------------- + +#ifndef MAIN_MENU +#define MAIN_MENU + +#include "inkview.h" + +#include + +class MainMenu +{ +public: + /** + * Defines fonds, sets global Event Handler and starts new content + * + * @param name name of the application + */ + MainMenu(const std::string &name); + + ~MainMenu(); + + irect *getContentRect() { return &_contentRect; }; + irect *getMenuButtonRect() { return &_menuButtonRect; }; + + /** + * Shows the menu on the screen, lets the user choose menu options and then redirects the handler to the caller + * + * @return int returns if the event was handled + */ + int createMenu(const iv_menuhandler &handler); + +private: + ifont *_menuFont; + + int _panelMenuBeginX; + int _panelMenuBeginY; + int _panelMenuHeight; + int _mainMenuWidth; + irect _menuButtonRect; + + imenu _mainMenu; + irect _contentRect; + + char *_menu = strdup("Menu"); + char *_open = strdup("Open editor"); + char *_connect = strdup("Register keyboard"); + char *_exit = strdup("Close App"); + + /** + * Functions needed to call C function, handles the panel + */ + static void panelHandlerStatic(); +}; +#endif diff --git a/src/main.cpp b/src/main.cpp new file mode 100644 index 0000000..c51ce87 --- /dev/null +++ b/src/main.cpp @@ -0,0 +1,65 @@ +//------------------------------------------------------------------ +// main.h +// +// Author: JuanJakobo +// Date: 14.06.2020 +// Description: sets the inkview main handler +//------------------------------------------------------------------- + +#include "inkview.h" +#include "eventHandler.h" +#include "log.h" + +EventHandler *events = nullptr; +/** +* Handles events and redirects them +* +* @param type event type +* @param par1 first argument of the event +* @param par2 second argument of the event +* @return int returns if the event was handled +*/ +int Inkview_handler(int type, int par1, int par2) +{ + //Log::writeInfoLog(std::to_string(type)); + switch (type) + { + case EVT_INIT: + { + events = new EventHandler(); + return 1; + break; + } + case EVT_EXIT: + case EVT_HIDE: + { + delete events; + return 1; + break; + } + default: + { + return events->eventDistributor(type, par1, par2); + break; + } + } + return 0; +} + +int main() +{ + OpenScreen(); + SetOrientation(0); + + + //draw startscreen + //auto textHeight = ScreenHeight() / 30; + //auto startscreenFont = OpenFont("LiberationMono", textHeight, FONT_BOLD); + //SetFont(startscreenFont, BLACK); + //DrawTextRect(0, (ScreenHeight() / 3) * 2, ScreenWidth(), textHeight, "Text Editor", ALIGN_CENTER); + //CloseFont(startscreenFont); + //FullUpdate(); + + InkViewMain(Inkview_handler); + return 0; +} diff --git a/src/ui/deviceModel.h b/src/ui/deviceModel.h new file mode 100644 index 0000000..407d81f --- /dev/null +++ b/src/ui/deviceModel.h @@ -0,0 +1,23 @@ +//------------------------------------------------------------------ +// devicesModel.h +// +// Author: JuanJakobo +// Date: 23.04.2021 +// Description: +//------------------------------------------------------------------- + +#ifndef DEVICESMODEL +#define DEVICESMODEL + +#include "model.h" + +#include + +struct Device : Entry{ + std::string name; + std::string sysfs; + std::string uniq; + int eventID; +}; + +#endif diff --git a/src/ui/devicesView.cpp b/src/ui/devicesView.cpp new file mode 100644 index 0000000..c0a40a6 --- /dev/null +++ b/src/ui/devicesView.cpp @@ -0,0 +1,43 @@ +//------------------------------------------------------------------ +// devicesView.cpp +// +// Author: JuanJakobo +// Date: 08.09.2021 +// +//------------------------------------------------------------------- + +#include "devicesView.h" +#include "devicesViewEntry.h" +#include "deviceModel.h" + +#include +#include + +using std::vector; + +DevicesView::DevicesView(const irect *contentRect, const vector &devices, int page) : ListView(contentRect, page) +{ + auto pageHeight = 0; + auto contentHeight = _contentRect->h - _footerHeight; + auto entrycount = devices.size(); + + _entries.reserve(entrycount); + + auto i = 0; + while (i < entrycount) + { + auto entrySize = TextRectHeight(contentRect->w, devices.at(i).name.c_str(), 0) + 2.5 * _entryFontHeight; + if ((pageHeight + entrySize) > contentHeight) + { + pageHeight = 0; + _page++; + } + irect rect = iRect(_contentRect->x, _contentRect->y + pageHeight, _contentRect->w, entrySize, 0); + + _entries.emplace_back(std::unique_ptr(new DevicesViewEntry(_page, rect, devices.at(i)))); + + i++; + pageHeight = pageHeight + entrySize; + } + draw(); +} diff --git a/src/ui/devicesView.h b/src/ui/devicesView.h new file mode 100644 index 0000000..f30b10b --- /dev/null +++ b/src/ui/devicesView.h @@ -0,0 +1,35 @@ +//------------------------------------------------------------------ +// devicesView.h +// +// Author: JuanJakobo +// Date: 08.09.2021 +// Description: An UI class to display items in a listview +//------------------------------------------------------------------- + +#ifndef DEVICESVIEW +#define DEVICESVIEW + +#include "deviceModel.h" +#include "listView.h" +#include "devicesViewEntry.h" + +#include +#include + +class DevicesView final : public ListView +{ +public: + /** + * Displays a list view + * + * @param ContentRect area of the screen where the list view is placed + * @param Items items that shall be shown in the listview + * @param page page that is shown, default is 1 + */ + DevicesView(const irect *contentRect, const std::vector &devices, int page = 1); + + Device *getCurrentEntry() { return getEntry(_selectedEntry); }; + + Device *getEntry(int entryID) { return std::dynamic_pointer_cast(_entries.at(entryID))->get(); }; +}; +#endif diff --git a/src/ui/devicesViewEntry.cpp b/src/ui/devicesViewEntry.cpp new file mode 100644 index 0000000..14b2417 --- /dev/null +++ b/src/ui/devicesViewEntry.cpp @@ -0,0 +1,33 @@ +//------------------------------------------------------------------ +// devicesViewEntry.cpp +// +// Author: JuanJakobo +// Date: 08.09.2021 +// +//------------------------------------------------------------------- + +#include "devicesViewEntry.h" +#include "deviceModel.h" + +#include + +DevicesViewEntry::DevicesViewEntry(int page, const irect &position, const Device &entry) : ListViewEntry(page, position), _entry(entry) +{ +} + +void DevicesViewEntry::draw(const ifont *entryFont, const ifont *entryFontBold, int fontHeight) +{ + SetFont(entryFontBold, BLACK); + int heightOfTitle = TextRectHeight(_position.w, _entry.name.c_str(), 0); + DrawTextRect(_position.x, _position.y, _position.w, heightOfTitle, _entry.name.c_str(), ALIGN_LEFT); + + SetFont(entryFont, BLACK); + + DrawTextRect(_position.x, _position.y + heightOfTitle, _position.w, fontHeight, _entry.sysfs.c_str(), ALIGN_LEFT); + + DrawTextRect(_position.x, _position.y + heightOfTitle + fontHeight, _position.w, fontHeight, _entry.uniq.c_str(), ALIGN_LEFT); + DrawTextRect(_position.x, _position.y + heightOfTitle + fontHeight, _position.w, fontHeight, std::to_string(_entry.eventID).c_str(), ALIGN_RIGHT); + + int line = (_position.y + _position.h) - 1; + DrawLine(0, line, ScreenWidth(), line, BLACK); +} diff --git a/src/ui/devicesViewEntry.h b/src/ui/devicesViewEntry.h new file mode 100644 index 0000000..5bd307c --- /dev/null +++ b/src/ui/devicesViewEntry.h @@ -0,0 +1,41 @@ +//------------------------------------------------------------------ +// devicesViewEntry.h +// +// Author: JuanJakobo +// Date: 08.09.2021 +// Description: +//------------------------------------------------------------------- + +#ifndef DEVICESVIEWENTRY +#define DEVICESVIEWENTRY + +#include "listViewEntry.h" +#include "deviceModel.h" + +class DevicesViewEntry : public ListViewEntry +{ +public: + /** + * Creates an DevicesViewEntry + * + * @param Page site of the listView the Entry is shown + * @param Rect area of the screen the item is positioned + * @param entry entry that shall be drawn + */ + DevicesViewEntry(int page, const irect &position, const Device &entry); + + /** + * draws the DeviceViewEntry to the screen + * + * @param entryFont font for the entry itself + * @param entryFontBold bold font for the header + * @param fontHeight height of the font + */ + void draw(const ifont *entryFont, const ifont *entryFontBold, int fontHeight) override; + + Device *get() override { return &_entry; }; + +private: + Device _entry; +}; +#endif diff --git a/src/ui/listView.cpp b/src/ui/listView.cpp new file mode 100644 index 0000000..6bba12a --- /dev/null +++ b/src/ui/listView.cpp @@ -0,0 +1,149 @@ +//------------------------------------------------------------------ +// listView.cpp +// +// Author: JuanJakobo +// Date: 04.08.2020 +// +//------------------------------------------------------------------- + +#include "inkview.h" +#include "listView.h" +#include "listViewEntry.h" + +#include +#include + +using std::string; +using std::vector; + +ListView::ListView(const irect *contentRect, int page) : _contentRect(contentRect), _shownPage(page) +{ + _entries.clear(); + + _footerHeight = _contentRect->h / 10; + _footerFontHeight = 0.3 * _footerHeight; + _entryFontHeight = 30; //0.2 * _footerFontHeight;//entrySize; //TODO how much? + + _footerFont = OpenFont("LiberationMono", _footerFontHeight, 1); + _entryFont = OpenFont("LiberationMono", _entryFontHeight, 1); + _entryFontBold = OpenFont("LiberationMono-Bold", _entryFontHeight, 1); + + SetFont(_entryFont, BLACK); + + _pageIcon = iRect(_contentRect->w - 100, _contentRect->h + _contentRect->y - _footerHeight, 100, _footerHeight, ALIGN_CENTER); + _firstPageButton = iRect(_contentRect->x, _contentRect->h + _contentRect->y - _footerHeight, 130, _footerHeight, ALIGN_CENTER); + _prevPageButton = iRect(_contentRect->x + 150, _contentRect->h + _contentRect->y - _footerHeight, 130, _footerHeight, ALIGN_CENTER); + _nextPageButton = iRect(_contentRect->x + 300, _contentRect->h + _contentRect->y - _footerHeight, 130, _footerHeight, ALIGN_CENTER); + _lastPageButton = iRect(_contentRect->x + 450, _contentRect->h + _contentRect->y - _footerHeight, 130, _footerHeight, ALIGN_CENTER); +} + +ListView::~ListView() +{ + CloseFont(_entryFont); + CloseFont(_entryFontBold); + CloseFont(_footerFont); +} + +void ListView::draw() +{ + FillAreaRect(_contentRect, WHITE); + drawEntries(); + drawFooter(); + PartialUpdate(_contentRect->x, _contentRect->y, _contentRect->w, _contentRect->h); +} + +void ListView::reDrawCurrentEntry() +{ + FillAreaRect(_entries.at(_selectedEntry)->getPosition(), WHITE); + _entries.at(_selectedEntry)->draw(_entryFont, _entryFontBold, _entryFontHeight); + updateEntry(_selectedEntry); +} + +void ListView::invertCurrentEntryColor() +{ + InvertAreaBW(_entries.at(_selectedEntry)->getPosition()->x, _entries.at(_selectedEntry)->getPosition()->y, _entries.at(_selectedEntry)->getPosition()->w, _entries.at(_selectedEntry)->getPosition()->h); + updateEntry(_selectedEntry); +} + +void ListView::drawEntries() +{ + for (unsigned int i = 0; i < _entries.size(); i++) + { + if (_entries.at(i)->getPage() == _shownPage) + _entries.at(i)->draw(_entryFont, _entryFontBold, _entryFontHeight); + } +} + +bool ListView::checkIfEntryClicked(int x, int y) +{ + if (IsInRect(x, y, &_firstPageButton)) + { + firstPage(); + } + else if (IsInRect(x, y, &_nextPageButton)) + { + nextPage(); + } + else if (IsInRect(x, y, &_prevPageButton)) + { + prevPage(); + } + else if (IsInRect(x, y, &_lastPageButton)) + { + actualizePage(_page); + } + else + { + for (unsigned int i = 0; i < _entries.size(); i++) + { + if (_entries.at(i)->getPage() == _shownPage && IsInRect(x, y, _entries.at(i)->getPosition()) == 1) + { + _selectedEntry = i; + return true; + } + } + } + return false; +} + +void ListView::drawFooter() +{ + SetFont(_footerFont, WHITE); + string footer = std::to_string(_shownPage) + "/" + std::to_string(_page); + FillAreaRect(&_pageIcon, BLACK); + + DrawTextRect2(&_pageIcon, footer.c_str()); + FillAreaRect(&_firstPageButton, BLACK); + DrawTextRect2(&_firstPageButton, "First"); + FillAreaRect(&_prevPageButton, BLACK); + DrawTextRect2(&_prevPageButton, "Prev"); + FillAreaRect(&_nextPageButton, BLACK); + DrawTextRect2(&_nextPageButton, "Next"); + FillAreaRect(&_lastPageButton, BLACK); + DrawTextRect2(&_lastPageButton, "Last"); +} + +void ListView::updateEntry(int entryID) +{ + PartialUpdate(_entries.at(entryID)->getPosition()->x, _entries.at(entryID)->getPosition()->y, _entries.at(entryID)->getPosition()->w, _entries.at(entryID)->getPosition()->h); +} + +void ListView::actualizePage(int pageToShow) +{ + if (pageToShow > _page) + { + Message(ICON_INFORMATION, "Info", "You have reached the last page, to return to the first, please click \"first.\"", 1200); + } + else if (pageToShow < 1) + { + Message(ICON_INFORMATION, "Info", "You are already on the first page.", 1200); + } + else + { + _shownPage = pageToShow; + FillArea(_contentRect->x, _contentRect->y, _contentRect->w, _contentRect->h, WHITE); + drawEntries(); + drawFooter(); + PartialUpdate(_contentRect->x, _contentRect->y, _contentRect->w, _contentRect->h); + } +} \ No newline at end of file diff --git a/src/ui/listView.h b/src/ui/listView.h new file mode 100644 index 0000000..263f65d --- /dev/null +++ b/src/ui/listView.h @@ -0,0 +1,123 @@ +//------------------------------------------------------------------ +// listView.h +// +// Author: JuanJakobo +// Date: 04.08.2020 +// Description: An UI class to display items in a listview +//------------------------------------------------------------------- + +#ifndef LISTVIEW +#define LISTVIEW + +#include "inkview.h" +#include "listViewEntry.h" +#include "model.h" + +#include +#include + +class ListView +{ +public: + /** + * Displays a list view + * + * @param ContentRect area of the screen where the list view is placed + * @param Items items that shall be shown in the listview + */ + ListView(const irect *contentRect, int page); + + virtual ~ListView(); + + virtual Entry *getCurrentEntry() = 0; + + virtual Entry *getEntry(int entryID) = 0; + + int getShownPage(){return _shownPage;}; + + /** + * Navigates to the next page + */ + void nextPage() { this->actualizePage(_shownPage + 1); }; + + /** + * Navigates to the prev page + */ + void prevPage() { this->actualizePage(_shownPage - 1); }; + + /** + * Navigates to first page + */ + void firstPage() { this->actualizePage(1); }; + + /** + * Draws an single entry to the screen + */ + void reDrawCurrentEntry(); + + /** + * inverts the color of the currently selected entry + */ + void invertCurrentEntryColor(); + + /** + * Checkes if the listview has been clicked and either changes the page or returns item ID + * + * @param x x-coordinate + * @param y y-coordinate + * @return true if was clicked + */ + bool checkIfEntryClicked(int x, int y); + + int getCurrentEntryItertator() const {return _selectedEntry;}; + + /** + * Clears the screen and draws entries and footer + * + */ + void draw(); + +protected: + int _footerHeight; + int _footerFontHeight; + int _entryFontHeight; + const irect *_contentRect; + std::vector> _entries; + ifont *_footerFont; + ifont *_entryFont; + ifont *_entryFontBold; + int _page = 1; + int _shownPage; + irect _pageIcon; + irect _nextPageButton; + irect _prevPageButton; + irect _firstPageButton; + irect _lastPageButton; + int _selectedEntry; + + + /** + * Iterates through the items and sends them to the listViewEntry Class for drawing + */ + void drawEntries(); + + /** + * Draws the footer including a page changer + */ + void drawFooter(); + + /** + * updates an entry + * + * @param entryID the id of the item that shall be inverted + */ + void updateEntry(int entryID); + + /** + * Navigates to the selected page + * + * @param pageToShow page that shall be shown + */ + void actualizePage(int pageToShow); +}; +#endif diff --git a/src/ui/listViewEntry.cpp b/src/ui/listViewEntry.cpp new file mode 100644 index 0000000..4421b14 --- /dev/null +++ b/src/ui/listViewEntry.cpp @@ -0,0 +1,14 @@ +//------------------------------------------------------------------ +// hnCommentViewEntry.cpp +// +// Author: JuanJakobo +// Date: 04.08.2020 +// +//------------------------------------------------------------------- + +#include "inkview.h" +#include "listViewEntry.h" + +ListViewEntry::ListViewEntry(int page, const irect &rect) : _page(page), _position(rect) +{ +} \ No newline at end of file diff --git a/src/ui/listViewEntry.h b/src/ui/listViewEntry.h new file mode 100644 index 0000000..e25aed2 --- /dev/null +++ b/src/ui/listViewEntry.h @@ -0,0 +1,46 @@ +//------------------------------------------------------------------ +// listViewEntry.h +// +// Author: JuanJakobo +// Date: 04.08.2020 +// Description: An listViewEntry that handles an item of a listview +//------------------------------------------------------------------- + +#ifndef LISTVIEWENTRY +#define LISTVIEWENTRY + +#include "inkview.h" +#include "model.h" + +class ListViewEntry +{ +public: + /** + * Creates an ListViewEntry + * + * @param Page site of the listView the Entry is shown + * @param Rect area of the screen the item is positioned + */ + ListViewEntry(int page, const irect &position); + + virtual ~ListViewEntry(){}; + + irect *getPosition() { return &_position; } + int getPage() const { return _page; } + + /** + * draws the listViewEntry to the screen + * + * @param entryFont font for the entry itself + * @param entryFontBold bold font for the header + * @param fontHeight height of the font + */ + virtual void draw(const ifont *entryFont, const ifont *entryFontBold, int fontHeight) = 0; + + virtual Entry* get() = 0; + +protected: + int _page; + irect _position; +}; +#endif \ No newline at end of file diff --git a/src/ui/model.h b/src/ui/model.h new file mode 100644 index 0000000..91cbb4e --- /dev/null +++ b/src/ui/model.h @@ -0,0 +1,15 @@ +//------------------------------------------------------------------ +// model.h +// +// Author: JuanJakobo +// Date: 23.04.2021 +// Description: +//------------------------------------------------------------------- + +#ifndef MODEL +#define MODEL + +struct Entry +{ +}; +#endif diff --git a/src/util/log.cpp b/src/util/log.cpp new file mode 100644 index 0000000..169f239 --- /dev/null +++ b/src/util/log.cpp @@ -0,0 +1,41 @@ +//------------------------------------------------------------------ +// log.cpp +// +// Author: JuanJakobo +// Date: 04.08.2020 +// +//------------------------------------------------------------------- + +#include "log.h" +#include "eventHandler.h" + +#include +#include + +void Log::writeInfoLog(const std::string &text) +{ + writeLog("Info:" + text); +} + +void Log::writeErrorLog(const std::string &text) +{ + writeLog("Error:" + text); +} + +void Log::writeLog(const std::string &text) +{ + std::ofstream log(CONFIG_FOLDER + std::string("/logfile.txt"), std::ios_base::app | std::ios_base::out); + + time_t rawtime; + struct tm *timeinfo; + char buffer[80]; + + time(&rawtime); + timeinfo = localtime(&rawtime); + + strftime(buffer, sizeof(buffer), "%d/%b/%Y:%H:%M:%S %z", timeinfo); + + log << buffer << ':' << text << "\n"; + + log.close(); +} diff --git a/src/util/log.h b/src/util/log.h new file mode 100644 index 0000000..991b968 --- /dev/null +++ b/src/util/log.h @@ -0,0 +1,43 @@ +//------------------------------------------------------------------ +// log.h +// +// Author: JuanJakobo +// Date: 05.08.2020 +// Description: Deals with log entries +//------------------------------------------------------------------- + +#ifndef LOG +#define LOG + +#include "inkview.h" + +#include + +class Log +{ +public: + /** + * Writes a error log entry to the log file + * + * @param text that shall be written to the log + */ + static void writeErrorLog(const std::string &text); + + /** + * Writes a info log entry to the log file + * + * @param text that shall be written to the log + */ + static void writeInfoLog(const std::string &text); + +private: + Log() {} + + /** + * Writes a log entry to the log file + * + * @param text that shall be written to the log + */ + static void writeLog(const std::string &text); +}; +#endif