diff options
Diffstat (limited to 'src/bin')
31 files changed, 2156 insertions, 0 deletions
diff --git a/src/bin/CMakeLists.txt b/src/bin/CMakeLists.txt new file mode 100644 index 0000000..5e1ebd3 --- /dev/null +++ b/src/bin/CMakeLists.txt @@ -0,0 +1,5 @@ +cmake_minimum_required(VERSION 3.16) + +if(BUILD_CLI) + add_subdirectory(cli) +endif()
\ No newline at end of file diff --git a/src/bin/cli/CMakeLists.txt b/src/bin/cli/CMakeLists.txt new file mode 100644 index 0000000..07d080f --- /dev/null +++ b/src/bin/cli/CMakeLists.txt @@ -0,0 +1,63 @@ +cmake_minimum_required(VERSION 3.16) + +option(UPDATE_TRANSLATIONS "update Translation" OFF) +option(NO_PAINTER_OPERATOR "No PAINTING" OFF) +MESSAGE(STATUS "UPDATE TRANSLATIONS: ${UPDATE_TRANSLATIONS}") + +project(dice) + +# Find includes in corresponding build directories +set(CMAKE_INCLUDE_CURRENT_DIR ON) +# Instruct CMake to run moc automatically when needed. +set(CMAKE_AUTOMOC ON) +set(EXECUTABLE_OUTPUT_PATH bin/) + +# Find the QtWidgets library +set(QT_REQUIRED_VERSION "6.2.0") + +IF(NO_PAINTER_OPERATOR) + find_package(Qt6 ${QT_REQUIRED_VERSION} CONFIG REQUIRED COMPONENTS Core Svg LinguistTools) +else() + MESSAGE(STATUS "Compilation of operator Paint") + find_package(Qt6 ${QT_REQUIRED_VERSION} CONFIG REQUIRED COMPONENTS Core Gui Svg LinguistTools) + add_definitions(-DPAINTER_OP) +endif() + +set(MODE "cli") + +set(dice_RESOURCES diceparser.qrc) +find_package(Qt6LinguistTools) +find_package(Qt6Svg) + +IF(UPDATE_TRANSLATIONS) + MESSAGE( update Translation ) + FILE(GLOB_RECURSE translate_dice_SRCS ../*.cpp ../*.h) + SET(translate_SRCS ${translate_dice_SRCS}) + SET(dice_TS "${CMAKE_CURRENT_SOURCE_DIR}/i18n/dice_en.ts" "${CMAKE_CURRENT_SOURCE_DIR}/i18n/dice_fr.ts") +ELSE() + MESSAGE( NO updates for translations) + FILE(GLOB dice_TS "${CMAKE_CURRENT_SOURCE_DIR}/i18n/*.ts") +ENDIF(UPDATE_TRANSLATIONS) + +if(Qt6Core_FOUND) + MESSAGE(status "find" ${dice_TS} ${translate_SRCS} ) + QT_ADD_RESOURCES(dice_RESOURCES_RCC ${dice_RESOURCES}) + set(QT_PLUGINS_DIR "${Qt6Core_DIR}/../../../plugins") + get_target_property(QT_LIBRARY_DIR Qt6::Core LOCATION) + get_filename_component(QT_LIBRARY_DIR ${QT_LIBRARY_DIR} PATH) +endif() + +SET( cli_sources + main.cpp + displaytoolbox.cpp +) + +add_executable( dice ${cli_sources} ${dice_QM}) +set(diceparser_shared_INCLUDE_DIRS "../diceparser") +link_directories(BEFORE ${CMAKE_BINARY_DIR}) +IF(NO_PAINTER_OPERATOR) + target_link_libraries(dice PUBLIC Qt6::Core Qt6::Svg PRIVATE diceparser_shared) +ELSE() + target_link_libraries(dice PUBLIC Qt6::Core Qt6::Gui Qt6::Svg PRIVATE diceparser_shared) +ENDIF() +INSTALL_TARGETS(/bin dice) diff --git a/src/bin/cli/cli.pri b/src/bin/cli/cli.pri new file mode 100644 index 0000000..69aa44f --- /dev/null +++ b/src/bin/cli/cli.pri @@ -0,0 +1,2 @@ +SOURCES += \ + $$PWD/main.cpp diff --git a/src/bin/cli/cmds.txt b/src/bin/cli/cmds.txt new file mode 100644 index 0000000..f5c7e1e --- /dev/null +++ b/src/bin/cli/cmds.txt @@ -0,0 +1,56 @@ +1L[cheminée,chocolat,épée,arc,chute_de_pierre] +10d10c[>=6]-@c[=1] +10d10c[>=6]-@c[=1]-@c[=1] +10d10c[>6]+@c[=10] +1+1D10 +3d10c[>=5] +1+(4*3)D10 +2+4/4 +2D10*2D20*8 +1+(4*3)D10 +(4D6)D10 +1D100a[>=95]a[>=96]a[>=97]a[>=98]a[>=99]e[>=100] +3D100 +4k3 +10D10e[>=6]sc[>=6] +10D10e10s +10D10s +15D10e10c[8-10] +10d10e11 +1D8+2D6+7 +D25 +1L[tete[10],ventre[50],jambe[40]] +2d6c[%2=0] +D25+D10 +D25;D10 +8+8+8 +1D20-88 +100*1D20*2D6 +100/28*3 +100/8 +100*3*8 +help +la +10D10c[<2|>7] +1L[tete,bras_droit,bras_gauche,jambe_droite,jambe_gauche,ventre[6-7],buste[8-10]] +10D6c[=2|=4|=6] +10D10e[=1|=10]k4 +10+10s +1d6e6;1d4e4mk1 +1d6e6;1d4e4mk1 +1d100e[>=95]i[<5]{-1d100e95} +100*3*8 +1d100i[<70]{1d10i[=10]{1d100i[<70]{1d10e10}}} +10d[-8--1] +4d6p[4:black]c[>=4]+1d6p[1:white]c6-@c1+1d6p[1:red]c[>=4]+@c6-@c1 +10d[0-9] +10d10g10 +1d100 #Comment +1d6;1d8mk1 +1d20;1d10;$1-$2 +1d100i[<50]{"success %1"}{"fail %1"} +2d100i:[<201]{"success %2"}{"fail %2"} +3d100i*[<101]{"Success"}{"Fail"} +3d100i.[%2=0]{"%1 is even"}{"%1 is odd"} +d100+3;d20+8 + diff --git a/src/bin/cli/dice.qrc b/src/bin/cli/dice.qrc new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/src/bin/cli/dice.qrc diff --git a/src/bin/cli/displaytoolbox.cpp b/src/bin/cli/displaytoolbox.cpp new file mode 100644 index 0000000..1709d18 --- /dev/null +++ b/src/bin/cli/displaytoolbox.cpp @@ -0,0 +1,168 @@ +#include "displaytoolbox.h" +#include <QBuffer> +#include <QJsonArray> +#include <QJsonObject> + +#ifdef PAINTER_OP +#include <QFont> +#include <QFontMetrics> +#include <QPainter> +#include <QSvgRenderer> +#endif + +#include <QDebug> + +#define LINE_SPACING 5 + +DisplayToolBox::DisplayToolBox() {} +#ifdef PAINTER_OP +QString DisplayToolBox::makeImage(QByteArray svgCode) +{ + QSvgRenderer svg(svgCode); + + QImage image(500, 60, QImage::Format_ARGB32); + image.fill(QColor(255, 255, 255, 100)); // partly transparent red-ish background + + // Get QPainter that paints to the image + QPainter painter(&image); + svg.render(&painter); + QByteArray ba; + QBuffer buffer(&ba); + buffer.open(QIODevice::WriteOnly); + image.save(&buffer, "PNG"); + return ba.toBase64(); +} +#endif + +QString DisplayToolBox::colorToIntCode(QString str) +{ + if(str.isEmpty() || str == QStringLiteral("black")) + { + return QStringLiteral("0;31"); + } + else if(str == QStringLiteral("white")) + { + return QStringLiteral("97"); + } + else if(str == QStringLiteral("blue")) + { + return QStringLiteral("34"); + } + else if(str == QStringLiteral("red")) + { + return QStringLiteral("31"); + } + else if(str == QStringLiteral("black")) + { + return QStringLiteral("30"); + } + else if(str == QStringLiteral("green")) + { + return QStringLiteral("32"); + } + else if(str == QStringLiteral("yellow")) + { + return QStringLiteral("33"); + } + else if(str == QStringLiteral("cyan")) + { + return QStringLiteral("36"); + } + else if(str == QStringLiteral("reset")) + { + return QStringLiteral("0"); + } + return {}; +} + +QString DisplayToolBox::colorToTermCode(QString str) +{ + return QStringLiteral("\e[").append(DisplayToolBox::colorToIntCode(str)).append("m"); +} + +QString DisplayToolBox::diceToSvg(QJsonArray array, bool withColor, bool allSameColor, bool allSameFaceCount) +{ + Q_UNUSED(allSameColor) + if(allSameFaceCount) + { + QStringList result; + for(auto item : array) + { + QStringList subResult; + auto obj= item.toObject(); + auto values= obj["values"].toArray(); + for(auto valRef : values) + { + subResult.append(diceResultToString(valRef.toObject(), Output::Svg, withColor)); + } + result.append(subResult.join(',')); + } + return result.join(""); + } + else + { + QStringList result; + for(auto item : array) + { + QStringList subResult; + auto obj= item.toObject(); + auto values= obj["values"].toArray(); + + for(auto valRef : values) + { + subResult.append(diceResultToString(valRef.toObject(), Output::Svg, withColor)); + } + result.append(QStringLiteral("d%1:(").arg(obj["face"].toInt())); + if(withColor) + { + result.append(QStringLiteral("<tspan fill=\"%1\">").arg(obj["color"].toString())); + } + result.append(subResult.join(',')); + if(withColor) + { + result.append(QStringLiteral("</tspan>)")); + } + else + { + result.append(QStringLiteral(")")); + } + } + return result.join(""); + } +} +#include <QVariantList> + +QString DisplayToolBox::diceResultToString(QJsonObject val, Output type, bool hasColor) +{ + auto total= QString::number(val["total"].toDouble()); + auto color= val["color"].toString(); + auto subvalues= val["subvalues"].toArray(); + QStringList subStr; + + for(auto subval : subvalues) + { + subStr << QString::number(subval.toDouble()); + } + if(!subStr.isEmpty()) + { + total.append(QStringLiteral(" [%1]").arg(subStr.join(','))); + } + if(hasColor && !color.isEmpty()) + { + if(type == Output::Terminal) + { + total= QStringLiteral("%1%2%3") + .arg(DisplayToolBox::colorToTermCode(color)) + .arg(total) + .arg(DisplayToolBox::colorToTermCode(QStringLiteral("reset"))); + } + else if(type == Output::Svg) + { + total= QStringLiteral("%1%2%3") + .arg(QStringLiteral("<tspan fill=\"%1\">").arg(color)) + .arg(total) + .arg(QStringLiteral("</tspan>")); + } + } + return total; +} diff --git a/src/bin/cli/displaytoolbox.h b/src/bin/cli/displaytoolbox.h new file mode 100644 index 0000000..5a22b0f --- /dev/null +++ b/src/bin/cli/displaytoolbox.h @@ -0,0 +1,29 @@ +#ifndef GENERATEIMAGE_H +#define GENERATEIMAGE_H + +#include <QJsonArray> +#include <QString> + +#include "diceparser/diceparser.h" + +class DisplayToolBox +{ +public: + enum class Output + { + Svg, + Terminal, + Json, + Image + }; + DisplayToolBox(); +#ifdef PAINTER_OP + static QString makeImage(QByteArray svgCode); +#endif + static QString colorToIntCode(QString str); + static QString colorToTermCode(QString str); + static QString diceToSvg(QJsonArray array, bool withColor, bool allSameColor, bool allSameFaceCount); + static QString diceResultToString(QJsonObject val, Output type, bool hasColor); +}; + +#endif // GENERATEIMAGE_H diff --git a/src/bin/cli/i18n/dice_en.ts b/src/bin/cli/i18n/dice_en.ts new file mode 100644 index 0000000..3efc610 --- /dev/null +++ b/src/bin/cli/i18n/dice_en.ts @@ -0,0 +1,74 @@ +<?xml version="1.0" encoding="utf-8"?> +<!DOCTYPE TS> +<TS version="2.1" language="en_US"> +<context> + <name>QObject</name> + <message> + <location filename="../../diceparser.cpp" line="186"/> + <source>Nothing was understood</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../../diceparser.cpp" line="603"/> + <source>Dice with %1 face(s) does not exist. Please, put a value higher than 0</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../../diceparser.cpp" line="648"/> + <source>List is missing after the L operator. Please, add it (e.g : 1L[sword,spear,gun,arrow])</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../../diceparser.cpp" line="905"/> + <source>Validator is missing after the c operator. Please, change it</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../../diceparser.cpp" line="931"/> + <source>Validator is missing after the %1 operator. Please, change it</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../../diceparser.cpp" line="943"/> + <source>This condition %1 introduces an endless loop. Please, change it</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../../diceparser.cpp" line="954"/> + <source>Validator is missing after the e operator. Please, change it</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../../node/keepdiceexecnode.cpp" line="48"/> + <source> You ask to keep %1 dice but the result only has %2</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../../node/listaliasnode.cpp" line="55"/> + <source>List of Alias: +</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../../node/helpnode.cpp" line="37"/> + <source>Rolisteam Dice Parser: +Full documentation at: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../../node/jumpbackwardnode.cpp" line="75"/> + <source> The @ operator expects dice result. Please check the documentation to fix your command.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../../node/dicerollernode.cpp" line="30"/> + <source>No dice to roll</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../../node/scalaroperatornode.cpp" line="128"/> + <source>Division by zero</source> + <translation type="unfinished"></translation> + </message> +</context> +</TS> diff --git a/src/bin/cli/i18n/dice_fr.ts b/src/bin/cli/i18n/dice_fr.ts new file mode 100644 index 0000000..438e99b --- /dev/null +++ b/src/bin/cli/i18n/dice_fr.ts @@ -0,0 +1,75 @@ +<?xml version="1.0" encoding="utf-8"?> +<!DOCTYPE TS> +<TS version="2.1" language="fr_FR"> +<context> + <name>QObject</name> + <message> + <location filename="../../diceparser.cpp" line="186"/> + <source>Nothing was understood</source> + <translation>Rien n'a été compris</translation> + </message> + <message> + <location filename="../../diceparser.cpp" line="603"/> + <source>Dice with %1 face(s) does not exist. Please, put a value higher than 0</source> + <translation>Dés avec %1 face(s) n'existe pas. Si vous plait, demander une valeur supérieure à 0</translation> + </message> + <message> + <location filename="../../diceparser.cpp" line="648"/> + <source>List is missing after the L operator. Please, add it (e.g : 1L[sword,spear,gun,arrow])</source> + <translation>Liste manquante après l'operateur L. Veuillez l'ajouter (e.g : 1L[épée,lance,flingue,flèche]) </translation> + </message> + <message> + <location filename="../../diceparser.cpp" line="905"/> + <source>Validator is missing after the c operator. Please, change it</source> + <translation>Validateur est manquant après l'opérateur c, veuillez le définir</translation> + </message> + <message> + <location filename="../../diceparser.cpp" line="931"/> + <source>Validator is missing after the %1 operator. Please, change it</source> + <translation>Validateur est manquant après l'opérateur %1, veuillez le définir</translation> + </message> + <message> + <location filename="../../diceparser.cpp" line="943"/> + <source>This condition %1 introduces an endless loop. Please, change it</source> + <translation>La condition %1 introduit une boucle infinie. Veuillez la changer</translation> + </message> + <message> + <location filename="../../diceparser.cpp" line="954"/> + <source>Validator is missing after the e operator. Please, change it</source> + <translation>Validateur est manquant après l'opérateur e, veuillez le définir</translation> + </message> + <message> + <location filename="../../node/keepdiceexecnode.cpp" line="48"/> + <source> You ask to keep %1 dice but the result only has %2</source> + <translation>Vous souhaitez garder %1 dés mais le resultat n'a seulement que %2 dés</translation> + </message> + <message> + <location filename="../../node/listaliasnode.cpp" line="55"/> + <source>List of Alias: +</source> + <translation>Liste d'alias:</translation> + </message> + <message> + <location filename="../../node/helpnode.cpp" line="37"/> + <source>Rolisteam Dice Parser: +Full documentation at: %1</source> + <translation>Rolisteam Dice Parser: +Documentation complète sur: %1</translation> + </message> + <message> + <location filename="../../node/jumpbackwardnode.cpp" line="75"/> + <source> The @ operator expects dice result. Please check the documentation to fix your command.</source> + <translation>L'opérateur @ attend un résultat de dés. Veuillez vérifier la documentation pour réparer votre commande.</translation> + </message> + <message> + <location filename="../../node/dicerollernode.cpp" line="30"/> + <source>No dice to roll</source> + <translation>Aucun dé à lancer</translation> + </message> + <message> + <location filename="../../node/scalaroperatornode.cpp" line="128"/> + <source>Division by zero</source> + <translation>Division par zéro</translation> + </message> +</context> +</TS> diff --git a/src/bin/cli/main.cpp b/src/bin/cli/main.cpp new file mode 100644 index 0000000..0420ac3 --- /dev/null +++ b/src/bin/cli/main.cpp @@ -0,0 +1,621 @@ +/*************************************************************************** + * Copyright (C) 2014 by Renaud Guezennec * + * http://www.rolisteam.org/contact * + * * + * This file is part of DiceParser * + * * + * DiceParser 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 2 of the License, or * + * (at your option) any later version. * + * * + * This program 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 this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ + +#include <QCommandLineOption> +#include <QCommandLineParser> +#include <QDebug> +#include <QFile> +#include <QJsonArray> +#include <QJsonDocument> +#include <QJsonObject> +#include <QRegularExpression> +#include <QSettings> +#include <QStringList> +#include <QTextStream> +#include <set> + +#ifdef PAINTER_OP +#include <QGuiApplication> +#else +#include <QCoreApplication> +#endif + +#include "diceparser/dicealias.h" +#include "diceparser/diceparser.h" +#include "diceparser/highlightdice.h" +#include "diceparser/parsingtoolbox.h" +#include "displaytoolbox.h" + +/** + * @page Dice + * The cli for DiceParser the new dice system from rolisteam. + * @section Build and install + * To build this program, type these command: + * - mkdir build + * - cd build + * - cmake ../ + * - make + * - make install + * @return + */ + +QTextStream out(stdout, QIODevice::WriteOnly); +QTextStream err(stderr, QIODevice::WriteOnly); +bool markdown= false; +constexpr char const* colorkey= {"dicecolor"}; +#ifdef PAINTER_OP +enum EXPORTFORMAT +{ + TERMINAL, + SVG, + IMAGE, + MARKDOWN, + JSON, + BOT, + TEXT +}; +#else +enum EXPORTFORMAT +{ + TERMINAL, + SVG, + MARKDOWN, + JSON, + BOT, + TEXT +}; +#endif +int returnValue= 0; + +void displayJSon(QString json) +{ + out << json << "\n"; +} +void displayMarkdown(QString json) +{ + QJsonDocument doc= QJsonDocument::fromJson(json.toUtf8()); + auto obj= doc.object(); + auto error= obj["error"].toString(); + auto warning= obj["warning"].toString(); + auto comment= obj["comment"].toString(); + auto arrayInst= obj["instructions"].toArray(); + QStringList diceResults; + for(auto inst : arrayInst) + { + auto obj= inst.toObject(); + auto diceVals= obj["diceval"].toArray(); + for(auto diceval : diceVals) + { + auto objval= diceval.toObject(); + auto resultStr= QString::number(objval["value"].toDouble()); + + auto subvalues= objval["subvalues"].toArray(); + QStringList subValueStr; + for(auto sub : subvalues) + { + subValueStr << QString::number(sub.toDouble()); + } + diceResults << resultStr; + if(!subValueStr.isEmpty()) + diceResults << QString("[%1]").arg(subValueStr.join(" ")); + } + } + auto diceList= diceResults.join(" "); + auto resultStr= obj["string"].toString(); + auto scalarText= obj["scalar"].toString(); + auto cmd= obj["command"].toString(); + + QString str("```Markdown\n"); + if(!error.isEmpty()) + { + str.append(QStringLiteral("Error: %1\n").arg(error)); + } + else + { + if(!warning.isEmpty()) + str.append(QStringLiteral("Warning: %1\n").arg(warning)); + + if(!comment.isEmpty()) + { + str.prepend(QStringLiteral("%1\n").arg(comment)); + } + if(!resultStr.isEmpty() && resultStr != scalarText) + { + // resultStr.replace("%2", diceList.trimmed()); + str.append(QStringLiteral("%1\n").arg(resultStr)); + } + else + { + str.append(QStringLiteral("# %1\nDetails:[%3 (%2)]\n").arg(scalarText).arg(diceList).arg(cmd)); + } + } + str.append(QStringLiteral("```")); + out << str; +} +QString displaySVG(QString json, bool withColor) +{ + QJsonDocument doc= QJsonDocument::fromJson(json.toUtf8()); + auto obj= doc.object(); + auto error= obj["error"].toString(); + auto warning= obj["warning"].toString(); + auto comment= obj["warning"].toString(); + auto arrayInst= obj["instructions"].toArray(); + QStringList diceResults; + for(auto inst : arrayInst) + { + auto obj= inst.toObject(); + auto diceVals= obj["diceval"].toArray(); + for(auto diceval : diceVals) + { + auto objval= diceval.toObject(); + auto resultStr= objval["string"].toString(); + diceResults << resultStr; + } + } + auto diceList= diceResults.join(","); + auto resultStr= obj["string"].toString(); + auto scalarText= obj["scalar"].toString(); + auto cmd= obj["command"].toString(); + + QString str("<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<svg version=\"1.1\" " + "xmlns=\"http://www.w3.org/2000/svg\" " + "xmlns:xlink=\"http://www.w3.org/1999/xlink\">\n"); + if(!error.isEmpty()) + { + str.append(QStringLiteral("<text font-size=\"16\" x=\"0\" y=\"20\"><tspan " + "fill=\"red\">%1</tspan></text>") + .arg(error)); + } + else + { + if(!warning.isEmpty()) + str.append(QStringLiteral("<text font-size=\"16\" x=\"0\" y=\"20\"><tspan " + "fill=\"orange\">%1</tspan></text>") + .arg(warning)); + + int y= 20; + if(!comment.isEmpty()) + { + str.append(QStringLiteral("<text font-size=\"16\" x=\"0\" y=\"%2\"><tspan " + "fill=\"blue\">%1</tspan></text>") + .arg(comment) + .arg(y)); + y+= 20; + } + // auto diceList= DisplayToolBox::diceToSvg(array, withColor, allSameColor, allSameFaceCount); + if(!resultStr.isEmpty() && resultStr != scalarText) + { + resultStr.replace("%2", diceList.trimmed()); + str.append(QStringLiteral("<text font-size=\"16\" x=\"0\" y=\"%2\">%1</text>").arg(resultStr).arg(y)); + } + else + { + if(withColor) + str.append(QStringLiteral("<text font-size=\"16\" x=\"0\" y=\"%4\"><tspan " + "fill=\"red\">%1</tspan>\n" + "<tspan x=\"0\" y=\"%5\">details:</tspan>[%3 (%2)]</text>") + .arg(scalarText) + .arg(diceList) + .arg(cmd) + .arg(y) + .arg(y * 2)); + else + str.append(QStringLiteral("<text font-size=\"16\" x=\"0\" y=\"%4\"><tspan>%1</tspan>\n" + "<tspan x=\"0\" y=\"%5\">details:</tspan>[%3 (%2)]</text>") + .arg(scalarText) + .arg(diceList) + .arg(cmd) + .arg(y) + .arg(y * 2)); + } + } + str.append(QStringLiteral("</svg>\n")); + return str; +} + +#ifdef PAINTER_OP +void displayImage(QString json, bool withColor) +{ + auto svg= displaySVG(json, withColor); + out << DisplayToolBox::makeImage(svg.toUtf8()); +} +#endif + +void displayCommandResult(QString json, bool withColor, QString color) +{ + QJsonDocument doc= QJsonDocument::fromJson(json.toUtf8()); + auto obj= doc.object(); + auto error= obj["error"].toString(); + auto warning= obj["warning"].toString(); + auto comment= obj["comment"].toString(); + auto arrayInst= obj["instructions"].toArray(); + QStringList diceResults; + for(const auto& inst : qAsConst(arrayInst)) + { + auto obj= inst.toObject(); + auto diceVals= obj["diceval"].toArray(); + for(const auto& diceval : qAsConst(diceVals)) + { + auto objval= diceval.toObject(); + auto resultStr= objval["string"].toString(); + diceResults << resultStr; + } + } + auto diceList= diceResults.join(","); + auto scalarText= obj["scalar"].toString(); + auto cmd= obj["command"].toString(); + auto resultStr= obj["string"].toString(); + + if(!error.isEmpty()) + { + err << "Error" << error << "\n"; + return; + } + + if(!warning.isEmpty()) + err << "Warning: " << warning << "\n"; + + QString str; + + if(withColor) + str= QString("Result: \e[0;%4;1m%1\e[0m - details:[%3 (%2)]") + .arg(scalarText, diceList, cmd, DisplayToolBox::colorToIntCode(color)); + else + str= QString("Result: %1 - details:[%3 (%2)]").arg(scalarText, diceList, cmd); + + if(!resultStr.isEmpty() && resultStr != scalarText) + { + resultStr.replace("%2", diceList.trimmed()); + str= resultStr; + } + + if(!comment.isEmpty()) + { + if(withColor) + out << "\033[1m" << comment << "\033[0m\n"; + else + out << comment << " "; + } + out << str << "\n"; +} + +int startDiceParsing(QStringList& cmds, bool withColor, QString baseColor, EXPORTFORMAT format, QJsonArray array, + const QString& filePath) +{ + DiceParser parser; + parser.insertAlias(new DiceAlias("L5R5R", QStringLiteral("L[-,⨀,⨀⬢,❂⬢,❁,❁⬢]")), 0); + parser.insertAlias(new DiceAlias("L5R5S", QStringLiteral("L[-,-,⨀,⨀,⨀❁,⨀⬢,⨀⬢,❂,❂⬢,❁,❁,❁]")), 1); + int i= 2; + for(auto alias : array) + { + auto objAlias= alias.toObject(); + parser.insertAlias(new DiceAlias(objAlias["pattern"].toString(), objAlias["cmd"].toString(), + objAlias["comment"].toString(), !objAlias["regexp"].toBool()), + i++); + } + + int rt= 0; + bool in_markdown= true; + + for(QString cmd : cmds) + { + if(cmd.startsWith('&') && format == BOT) + { + cmd= cmd.remove(0, 1); + in_markdown= false; + } + + if(parser.parseLine(cmd)) + { + parser.start(); + + std::set<EXPORTFORMAT> svgFormat({SVG, IMAGE, BOT}); + QString json; + bool allSameColor= true; + if(svgFormat.find(format) != svgFormat.end()) + { + allSameColor= true; + QString colorP; + json= parser.resultAsJSon( + [&colorP, &allSameColor](const QString& value, const QString& color, bool) { + if(colorP.isNull()) + colorP= color; + else if(colorP != color) + allSameColor= false; + + return value; + }, + true); + + if(!allSameColor) + { + json= parser.resultAsJSon([](const QString& value, const QString& color, bool highlight) { + QString result= value; + bool hasColor= !color.isEmpty(); + QString style; + if(hasColor) + { + style+= QStringLiteral("fill=\"%1\" ").arg(color); + } + if(highlight) + { + if(style.isEmpty()) + style+= QStringLiteral("fill=\"%1\" ") + .arg("red"); // default color must get the value from the setting object + style+= QStringLiteral("font-weight=\"bold\" "); + } + if(!style.isEmpty()) + result= QString("<tspan %2>%1</tspan>").arg(value).arg(style); + return result; + }); + } + } + else if(TERMINAL == format) + { + allSameColor= true; + QString colorP; + json= parser.resultAsJSon( + [&colorP, &allSameColor, &baseColor](const QString& result, const QString& color, bool hightlight) { + auto trueColor= color; + if(color.isEmpty()) + trueColor= baseColor; + + if(colorP.isEmpty()) + colorP= trueColor; + else if(colorP != trueColor) + allSameColor= false; + + auto front= DisplayToolBox::colorToTermCode(trueColor); + auto end= front.isEmpty() ? "" : DisplayToolBox::colorToTermCode("reset"); + return hightlight ? QString("%1%2%3").arg(front).arg(result).arg(end) : result; + }); + } + else + { + allSameColor= true; + json= parser.resultAsJSon([](const QString& result, const QString&, bool) { return result; }); + } + + if(format == BOT) + { + if(allSameColor) + { + format= in_markdown ? MARKDOWN : TEXT; + } + else + { +#ifdef PAINTER_OP + format= IMAGE; +#else + format= MARKDOWN; +#endif + } + if(!parser.humanReadableError().isEmpty()) + { + format= MARKDOWN; + } + } + if(!withColor && format == TERMINAL) + format= TEXT; + + // qDebug().noquote() << json << format; + + switch(format) + { + case TERMINAL: + displayCommandResult(json, withColor, baseColor); + break; + case SVG: + out << displaySVG(json, withColor) << "\n"; + break; + case BOT: + case MARKDOWN: + displayMarkdown(json); + break; + case TEXT: + displayCommandResult(json, false, baseColor); + break; + case JSON: + displayJSon(json); + break; +#ifdef PAINTER_OP + case IMAGE: + displayImage(json, withColor); + break; +#endif + } + if(!filePath.isEmpty()) + { + parser.writeDownDotTree(filePath); + } + } + else + rt= 1; + } + return rt; +} + +int main(int argc, char* argv[]) +{ +#ifdef PAINTER_OP + QGuiApplication a(argc, argv); +#else + QCoreApplication a(argc, argv); +#endif + + QStringList commands; + QString cmd; + QString dotFileStr; + bool colorb= true; + QSettings settings("rolisteam", "diceparser"); + QString formatColor; + EXPORTFORMAT format= TERMINAL; + + QCommandLineParser optionParser; + QCommandLineOption color(QStringList() << "c" + << "color-off", + "Disable color to highlight result"); + QCommandLineOption version(QStringList() << "v" + << "version", + "Show the version and quit."); + QCommandLineOption reset(QStringList() << "reset-settings", "Erase the settings and use the default parameters"); + QCommandLineOption alias(QStringList() << "a" + << "alias", + "path to alias json files: <aliasfile>", "aliasfile"); + + QCommandLineOption aliasData(QStringList() << "alias-data", "alias in json data <aliasdata>", "aliasdata"); + + QCommandLineOption character(QStringList() << "s" + << "charactersheet", + "set Parameters to simulate character sheet: <sheetfile>", "sheetfile"); + QCommandLineOption markdown(QStringList() << "m" + << "markdown", + "The output is formatted in markdown."); + QCommandLineOption bot(QStringList() << "b" + << "bot", + "Discord bot."); + QCommandLineOption svg(QStringList() << "g" + << "svg", + "The output is formatted in svg."); + QCommandLineOption outColor(QStringList() << "C" + << "color", + "Use color for result: <color>", "color"); + QCommandLineOption json(QStringList() << "j" + << "json", + "The output is formatted in json."); + QCommandLineOption line(QStringList() << "l" + << "line", + "The output is in one line [default]."); + QCommandLineOption dotFile(QStringList() << "d" + << "dot-file", + "Instead of rolling dice, generate the execution tree and write it in " + "<dotfile>", + "dotfile"); + QCommandLineOption translation(QStringList() << "t" + << "translation", + "path to the translation file: <translationfile>", "translationfile"); + QCommandLineOption help(QStringList() << "h" + << "help", + "Display this help"); + + optionParser.addOption(color); + optionParser.addOption(version); + optionParser.addOption(reset); + optionParser.addOption(dotFile); + optionParser.addOption(alias); + optionParser.addOption(aliasData); + optionParser.addOption(character); + optionParser.addOption(line); + optionParser.addOption(markdown); + optionParser.addOption(bot); + optionParser.addOption(svg); + optionParser.addOption(outColor); + optionParser.addOption(json); + optionParser.addOption(translation); + optionParser.addOption(help); + for(int i= 0; i < argc; ++i) + { + commands << QString::fromUtf8(argv[i]); + } + + optionParser.process(commands); + + if(optionParser.isSet(color)) + { + commands.removeAt(0); + colorb= false; + } + else if(optionParser.isSet(version)) + { + out << "Rolisteam DiceParser v1.0.0" + << "\n"; + out << "More Details: www.rolisteam.org" + << "\n"; + return 0; + } + else if(optionParser.isSet(reset)) + { + return 0; + } + else if(optionParser.isSet(dotFile)) + { + dotFileStr= optionParser.value(dotFile); + } + if(optionParser.isSet(markdown)) + { + format= MARKDOWN; + } + else if(optionParser.isSet(bot)) + { + format= BOT; + } + else if(optionParser.isSet(svg)) + { + format= SVG; + } + else if(optionParser.isSet(json)) + { + format= JSON; + } + else if(optionParser.isSet(line)) + { + format= TEXT; + } + if(optionParser.isSet(outColor)) + { + settings.setValue(colorkey, optionParser.value(outColor)); + } + + if(optionParser.isSet(help)) + { + cmd= "help"; + } + QStringList cmdList= optionParser.positionalArguments(); + + QJsonArray aliases; + if(optionParser.isSet(alias)) + { + auto aliasstr= optionParser.value(alias); + + QFile file(aliasstr); + + if(file.open(QIODevice::ReadOnly)) + { + QJsonDocument doc= QJsonDocument::fromJson(file.readAll()); + aliases= doc.array(); + } + } + else if(optionParser.isSet(aliasData)) + { + auto aliasstr= optionParser.value(aliasData); + QJsonDocument doc= QJsonDocument::fromJson(aliasstr.toUtf8()); + aliases= doc.array(); + } + + formatColor= settings.value(colorkey, "red").value<QString>(); + returnValue= startDiceParsing(cmdList, colorb, formatColor, format, aliases, dotFileStr); + if(optionParser.isSet(help)) + { + out << optionParser.helpText(); + } + return returnValue; +} diff --git a/src/bin/gui/gui.pri b/src/bin/gui/gui.pri new file mode 100644 index 0000000..c31fd79 --- /dev/null +++ b/src/bin/gui/gui.pri @@ -0,0 +1,10 @@ +QT += gui + +FORMS += \ + $$PWD/mainwindow.ui + +HEADERS += \ + $$PWD/mainwindow.h + +SOURCES += \ + $$PWD/mainwindow.cpp diff --git a/src/bin/gui/mainwindow.cpp b/src/bin/gui/mainwindow.cpp new file mode 100644 index 0000000..5b8422e --- /dev/null +++ b/src/bin/gui/mainwindow.cpp @@ -0,0 +1,27 @@ +#include "mainwindow.h" +#include "ui_mainwindow.h" + +#include "diceparser.h" + +MainWindow::MainWindow(QWidget* parent) : QMainWindow(parent), ui(new Ui::MainWindow) +{ + ui->setupUi(this); + + connect(ui->m_rollButton, SIGNAL(pressed()), this, SLOT(rollDiceCommand())); + m_dieParser= new DiceParser(); +} + +MainWindow::~MainWindow() +{ + delete ui; +} +void MainWindow::rollDiceCommand() +{ + QString cmd= ui->m_cmdEdit->text(); + + if(m_dieParser->parseLine(cmd)) + { + m_dieParser->Start(); + m_dieParser->displayResult(); + } +} diff --git a/src/bin/gui/mainwindow.h b/src/bin/gui/mainwindow.h new file mode 100644 index 0000000..bd19b34 --- /dev/null +++ b/src/bin/gui/mainwindow.h @@ -0,0 +1,28 @@ +#ifndef MAINWINDOW_H +#define MAINWINDOW_H + +#include <QMainWindow> + +class DiceParser; +namespace Ui +{ + class MainWindow; +} + +class MainWindow : public QMainWindow +{ + Q_OBJECT + +public: + explicit MainWindow(QWidget* parent= 0); + ~MainWindow(); + +protected slots: + void rollDiceCommand(); + +private: + Ui::MainWindow* ui; + DiceParser* m_dieParser; +}; + +#endif // MAINWINDOW_H diff --git a/src/bin/gui/mainwindow.ui b/src/bin/gui/mainwindow.ui new file mode 100644 index 0000000..d09f866 --- /dev/null +++ b/src/bin/gui/mainwindow.ui @@ -0,0 +1,75 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>MainWindow</class> + <widget class="QMainWindow" name="MainWindow"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>800</width> + <height>600</height> + </rect> + </property> + <property name="windowTitle"> + <string>MainWindow</string> + </property> + <widget class="QWidget" name="centralwidget"> + <layout class="QVBoxLayout" name="verticalLayout_2"> + <item> + <layout class="QHBoxLayout" name="horizontalLayout"> + <item> + <widget class="QLineEdit" name="m_cmdEdit"/> + </item> + <item> + <widget class="QPushButton" name="m_rollButton"> + <property name="text"> + <string>Roll</string> + </property> + </widget> + </item> + </layout> + </item> + <item> + <layout class="QHBoxLayout" name="horizontalLayout_2" stretch="0,1"> + <item> + <widget class="QListView" name="m_historicView"/> + </item> + <item> + <layout class="QVBoxLayout" name="verticalLayout"> + <item> + <widget class="QWidget" name="m_display" native="true"/> + </item> + <item> + <spacer name="horizontalSpacer"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>40</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + </layout> + </item> + </layout> + </item> + </layout> + </widget> + <widget class="QMenuBar" name="menubar"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>800</width> + <height>29</height> + </rect> + </property> + </widget> + <widget class="QStatusBar" name="statusbar"/> + </widget> + <resources/> + <connections/> +</ui> diff --git a/src/bin/mobile/CMakeLists.txt b/src/bin/mobile/CMakeLists.txt new file mode 100644 index 0000000..ddc0543 --- /dev/null +++ b/src/bin/mobile/CMakeLists.txt @@ -0,0 +1,109 @@ +cmake_minimum_required(VERSION 3.16) + +option(UPDATE_TRANSLATIONS "update Translation" OFF) +MESSAGE(STATUS "UPDATE TRANSLATIONS: ${UPDATE_TRANSLATIONS}") + + +project(diceGui) + + +# Find includes in corresponding build directories +set(CMAKE_INCLUDE_CURRENT_DIR ON) +# Instruct CMake to run moc automatically when needed. +set(CMAKE_AUTOMOC ON) + +# Find the QtWidgets library +find_package(Qt6 COMPONENTS Quick Qml Core Widgets Gui) +#find_package(Qt6QuickCompiler) + +set(EXECUTABLE_OUTPUT_PATH bin/) + +include_directories(${Qt5Core_INCLUDES} ${Qt5Widgets_INCLUDES} ${Qt5Gui_INCLUDES} ${Qt5Qml_INCLUDES} ${Qt5Quick_INCLUDES}../) +add_definitions(${Qt5Core_DEFINITIONS} ${Qt5Qml_DEFINITIONS} ${Qt5Quick_DEFINITIONS} ${Qt5Widgets_DEFINITIONS} ${Qt5Gui_DEFINITIONS} ) + +ADD_DEFINITIONS( + -std=c++11 +) + +set(diceGui_RESOURCES diceparser.qrc) +FIND_PACKAGE(Qt6LinguistTools) + + +IF(UPDATE_TRANSLATIONS) + MESSAGE( update Translation ) + FILE(GLOB_RECURSE translate_diceGui_SRCS ../*.cpp ../*.h) + SET(translate_SRCS ${translate_dice_SRCS}) + SET(diceGui_TS "${CMAKE_CURRENT_SOURCE_DIR}/i18n/diceGui_en.ts" "${CMAKE_CURRENT_SOURCE_DIR}/i18n/diceGui_fr.ts") +ELSE() + MESSAGE( NO updates for translations) + FILE(GLOB diceGui_TS "${CMAKE_CURRENT_SOURCE_DIR}/i18n/*.ts") +ENDIF(UPDATE_TRANSLATIONS) + +if(Qt5Core_FOUND) + + IF(UPDATE_TRANSLATIONS) + MESSAGE(status "find" ${diceGui_TS} ${translate_SRCS} ) + QT5_CREATE_TRANSLATION(diceGui_QM ${translate_SRCS} ${diceGui_TS}) + ELSE() + QT5_ADD_TRANSLATION(diceGui_QM ${diceGui_TS}) + ENDIF() + + QT5_ADD_RESOURCES(diceGui_RESOURCES_RCC ${diceGui_RESOURCES}) + + # guess plugins and libraries directory + set(QT_PLUGINS_DIR "${Qt5Core_DIR}/../../../plugins") + get_target_property(QT_LIBRARY_DIR Qt6::Core LOCATION) + get_filename_component(QT_LIBRARY_DIR ${QT_LIBRARY_DIR} PATH) +endif() + +SET( diceGui_sources + ../diceparser.cpp + ../range.cpp + ../booleancondition.cpp + ../validator.cpp + ../compositevalidator.cpp + ../operationcondition.cpp + ../die.cpp + ../parsingtoolbox.cpp + ../dicealias.cpp + ../result/result.cpp + ../result/scalarresult.cpp + ../result/stringresult.cpp + ../result/diceresult.cpp + ../node/countexecutenode.cpp + ../node/dicerollernode.cpp + ../node/executionnode.cpp + ../node/explodedicenode.cpp + ../node/helpnode.cpp + ../node/mergenode.cpp + ../node/jumpbackwardnode.cpp + ../node/keepdiceexecnode.cpp + ../node/listaliasnode.cpp + ../node/listsetrollnode.cpp + ../node/numbernode.cpp + ../node/parenthesesnode.cpp + ../node/paintnode.cpp + ../node/rerolldicenode.cpp + ../node/scalaroperatornode.cpp + ../node/sortresult.cpp + ../node/startingnode.cpp + ../node/ifnode.cpp + ../node/filternode.cpp + ../node/stringnode.cpp + ../node/splitnode.cpp + ../node/groupnode.cpp + ../node/variablenode.cpp + ../node/bind.cpp + main.cpp + maincontroller.cpp + commandmodel.cpp + ../highlightdice.cpp +) +qt5_add_resources(RESOURCE_ADDED mobile.qrc) + +add_executable( diceGui ${diceGui_sources} ${diceGui_QM} ${RESOURCE_ADDED} ) + +target_link_libraries(diceGui ${Qt5Core_LIBRARIES} ${Qt5Widgets_LIBRARIES} ${Qt5Gui_LIBRARIES} ${Qt5Qml_LIBRARIES} ${Qt5Quick_LIBRARIES}) +INSTALL_TARGETS(/bin diceGui) + +#qt5_use_modules() diff --git a/src/bin/mobile/commandmodel.cpp b/src/bin/mobile/commandmodel.cpp new file mode 100644 index 0000000..7b50397 --- /dev/null +++ b/src/bin/mobile/commandmodel.cpp @@ -0,0 +1,54 @@ +/*************************************************************************** + * Copyright (C) 2016 by Renaud Guezennec * + * http://www.rolisteam.org/contact * + * * + * rolisteam 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 2 of the License, or * + * (at your option) any later version. * + * * + * This program 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 this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ +#include "commandmodel.h" + +CommandModel::CommandModel() {} + +QVariant CommandModel::data(const QModelIndex& index, int role) const +{ + QPair<QString, QString> indexP= m_data.at(index.row()); + if(role == NameRole) + { + return indexP.first; + } + else if(role == CmdRole) + { + return indexP.second; + } +} + +int CommandModel::rowCount(const QModelIndex& parent) const +{ + return m_data.count(); +} +QHash<int, QByteArray> CommandModel::roleNames() const +{ + QHash<int, QByteArray> roles; + roles[NameRole]= "name"; + roles[CmdRole]= "cmd"; + return roles; +} +void CommandModel::insertCmd(QString name, QString cmd) +{ + QModelIndex index; + beginInsertRows(index, 0, 0); + m_data.prepend(QPair<QString, QString>(name, cmd)); + endInsertRows(); +} diff --git a/src/bin/mobile/commandmodel.h b/src/bin/mobile/commandmodel.h new file mode 100644 index 0000000..4037032 --- /dev/null +++ b/src/bin/mobile/commandmodel.h @@ -0,0 +1,50 @@ +/*************************************************************************** + * Copyright (C) 2016 by Renaud Guezennec * + * http://www.rolisteam.org/contact * + * * + * rolisteam 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 2 of the License, or * + * (at your option) any later version. * + * * + * This program 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 this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ +#ifndef COMMANDMODEL_H +#define COMMANDMODEL_H + +#include <QObject> + +#include <QAbstractListModel> + +class CommandModel : public QAbstractListModel +{ + Q_OBJECT +public: + enum CustomRole + { + NameRole= Qt::UserRole + 1, + CmdRole + }; + CommandModel(); + + virtual QVariant data(const QModelIndex& index, int role= Qt::DisplayRole) const; + virtual int rowCount(const QModelIndex& parent) const; + + QHash<int, QByteArray> roleNames() const; + +public slots: + void insertCmd(QString name, QString cmd); + +private: + QList<QPair<QString, QString>> m_data; +}; + +#endif // COMMANDMODEL_H diff --git a/src/bin/mobile/deployment.pri b/src/bin/mobile/deployment.pri new file mode 100644 index 0000000..265ce71 --- /dev/null +++ b/src/bin/mobile/deployment.pri @@ -0,0 +1,13 @@ +unix:!android { + isEmpty(target.path) { + qnx { + target.path = /tmp/$${TARGET}/bin + } else { + target.path = /opt/$${TARGET}/bin + } + export(target.path) + } + INSTALLS += target +} + +export(INSTALLS) diff --git a/src/bin/mobile/main.cpp b/src/bin/mobile/main.cpp new file mode 100644 index 0000000..9b81329 --- /dev/null +++ b/src/bin/mobile/main.cpp @@ -0,0 +1,38 @@ +/*************************************************************************** + * Copyright (C) 2016 by Renaud Guezennec * + * http://www.rolisteam.org/contact * + * * + * rolisteam 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 2 of the License, or * + * (at your option) any later version. * + * * + * This program 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 this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ +#include <QGuiApplication> +#include <QQmlApplicationEngine> + +#include "maincontroler.h" + +int main(int argc, char* argv[]) +{ + QGuiApplication app(argc, argv); + + MainControler* main= new MainControler(); + + QQmlApplicationEngine engine; + main->initEngine(&engine); + engine.load(QUrl(QStringLiteral("qrc:/main.qml"))); + + // main->setConnections(&engine); + + return app.exec(); +} diff --git a/src/bin/mobile/main.qml b/src/bin/mobile/main.qml new file mode 100644 index 0000000..700f3a7 --- /dev/null +++ b/src/bin/mobile/main.qml @@ -0,0 +1,172 @@ +import QtQuick 2.7 +import QtQuick.Window 2.2 + +Window { + id:root + visible: true + signal addRoll(string name, string cmd ) + signal roll(string cmd) + color: "black" + height: 1280 + width: 720 + + Column{ + + anchors.fill: parent + leftPadding: width*0.025 + rightPadding: width*0.025 + topPadding: width*0.025 + Rectangle { + height: parent.height*0.12 + width: parent.width*0.95 + Image { + anchors.fill: parent + horizontalAlignment: Image.AlignHCenter + verticalAlignment:Image.AlignVCenter + fillMode: Image.PreserveAspectFit + source: "qrc:/resources/images/add.png" + } + gradient: Gradient { + GradientStop { position: 0.0; color: "darkblue" } + GradientStop { position: 1.0; color: "blue" } + } + MouseArea { + anchors.fill: parent + onClicked:popupAdd.visible = true + } + } + + ListView { + model: _model + focus: true + height: parent.height*0.88 + width: parent.width*0.95 + delegate: Item{ + height: parent.height + width: parent.width + Column{ + width: parent.width + height: parent.height + Text{ + text: name + font.pointSize: 40 + color: "white" + + + } + Text{ + text: cmd + font.pointSize:30 + color: "white" + + } + } + MouseArea{ + anchors.fill:parent + onClicked: roll(cmd) + } + } + } + + } + Rectangle { + id: popupAdd + color: "black" + x: parent.width*0.1 + y: parent.height*0.1 + height: parent.height*0.80 + width: parent.width*0.80 + visible: false + border.color: "white" + border.width: 1 + + Column{ + id:form + anchors.top: parent.top + anchors.left: parent.left + anchors.right: parent.right + height: parent.height*0.80 + leftPadding: width*0.025 + rightPadding: width*0.025 + topPadding: width*0.025 + property alias name : nameInp + property alias cmd : cmdInp + Text { + text: qsTr("Name") + color: "white" + height: parent.height*0.1 + font.pointSize: 40 + } + Rectangle{ + height: parent.height*0.1 + width: parent.width*0.90 + border.color: "#BBBBBB" + border.width: 1 + color: "black" + TextInput{ + id: nameInp + color: "white" + anchors.fill: parent + font.pointSize: 40 + } + } + + Text { + text: qsTr("Command") + color: "white" + height: parent.height*0.1 + font.pointSize: 40 + } + Rectangle{ + height: parent.height*0.1 + width: parent.width*0.90 + border.color: "#BBBBBB" + border.width: 1 + color: "black" + TextInput{ + id: cmdInp + color: "white" + anchors.fill: parent + font.pointSize: 40 + } + } + } + + Rectangle { + color:"red" + id: cancel + anchors.top: form.bottom + anchors.left: form.left + anchors.right: form.horizontalCenter + anchors.bottom: parent.bottom + radius: height/2 + MouseArea { + anchors.fill: parent + onClicked:{ + nameInp.text="" + cmdInp.text="" + popupAdd.visible = false + } + } + } + Rectangle { + color:"green" + anchors.top: form.bottom + anchors.left: cancel.right + anchors.right: form.right + anchors.bottom: parent.bottom + radius: height/2 + MouseArea { + anchors.fill: parent + onClicked: + { + root.addRoll(nameInp,cmdInp.text); + nameInp.text="" + cmdInp.text="" + popupAdd.visible = false + } + } + + } + } +} diff --git a/src/bin/mobile/maincontroller.cpp b/src/bin/mobile/maincontroller.cpp new file mode 100644 index 0000000..6f301ff --- /dev/null +++ b/src/bin/mobile/maincontroller.cpp @@ -0,0 +1,44 @@ +#include "maincontroler.h" + +#include <QJSValue> +#include <QQmlEngine> + +MainControler::MainControler(QObject* parent) : QObject(parent) +{ + + m_diceParser= new DiceParser(); + qmlRegisterSingletonType("DiceParser", 1, 0, "Model", [](QQmlEngine* engine, QJSEngine* scriptEngine) -> QObject* { + Q_UNUSED(engine) + static CommandModel model; + static bool initialized= false; + if(!initialized) + { + model.insertCmd("L5R", "8D10e10k4"); + initialized= true; + } + return &model; + }); +} +void MainControler::initEngine(QQmlApplicationEngine* engine) +{ + m_engine= engine; + engine->rootContext()->setContextProperty("_model", m_model); + connect(m_engine, SIGNAL(objectCreated(QObject*, QUrl)), this, SLOT(setConnections(QObject*, QUrl))); +} +void MainControler::rollDice(QString cmd) +{ + if(m_diceParser->parseLine(cmd)) + { + m_diceParser->start(); + for(int i= 0; i < m_diceParser->getStartNodeCount(); ++i) + { + // qDebug() << m_diceParser->getSumOfDiceResult(i); + } + } +} +void MainControler::setConnections(QObject* root, QUrl url) +{ + // QObject* root = engine->rootContext()->contextObject(); + connect(root, SIGNAL(roll(QString)), this, SLOT(rollDice(QString))); + connect(root, SIGNAL(addRoll(QString, QString)), m_model, SLOT(insertCmd(QString, QString))); +} diff --git a/src/bin/mobile/maincontroller.h b/src/bin/mobile/maincontroller.h new file mode 100644 index 0000000..43fc1ae --- /dev/null +++ b/src/bin/mobile/maincontroller.h @@ -0,0 +1,29 @@ +#ifndef MAINCONTROLER_H +#define MAINCONTROLER_H + +#include <QObject> +#include <QQmlApplicationEngine> + +#include "commandmodel.h" +#include "diceparser.h" + +class MainControler : public QObject +{ + Q_OBJECT +public: + explicit MainControler(QObject* parent= 0); + + void initEngine(QQmlApplicationEngine*); +signals: + +public slots: + void setConnections(QObject* root, QUrl url); + void rollDice(QString cmd); + +private: + // CommandModel* m_model; + DiceParser* m_diceParser; + QQmlApplicationEngine* m_engine; +}; + +#endif // MAINCONTROLER_H diff --git a/src/bin/mobile/mobile.pro b/src/bin/mobile/mobile.pro new file mode 100644 index 0000000..2e33522 --- /dev/null +++ b/src/bin/mobile/mobile.pro @@ -0,0 +1,20 @@ +TEMPLATE = app + +QT += qml quick +CONFIG += c++11 + +SOURCES += main.cpp maincontroler.cpp \ + commandmodel.cpp + +HEADERS += maincontroler.h \ + commandmodel.h + +RESOURCES += qml.qrc + +include(../diceparser.pri) + +# Additional import path used to resolve QML modules in Qt Creator's code model +QML_IMPORT_PATH = + +# Default rules for deployment. +include(deployment.pri) diff --git a/src/bin/mobile/mobile.qrc b/src/bin/mobile/mobile.qrc new file mode 100644 index 0000000..69145a8 --- /dev/null +++ b/src/bin/mobile/mobile.qrc @@ -0,0 +1,5 @@ +<RCC> + <qresource prefix="/"> + <file>qml/main.qml</file> + </qresource> +</RCC> diff --git a/src/bin/mobile/qml.qrc b/src/bin/mobile/qml.qrc new file mode 100644 index 0000000..2cbbe08 --- /dev/null +++ b/src/bin/mobile/qml.qrc @@ -0,0 +1,6 @@ +<RCC> + <qresource prefix="/"> + <file>main.qml</file> + <file>resources/images/add.png</file> + </qresource> +</RCC> diff --git a/src/bin/mobile/qml/main.qml b/src/bin/mobile/qml/main.qml new file mode 100644 index 0000000..ed9d480 --- /dev/null +++ b/src/bin/mobile/qml/main.qml @@ -0,0 +1,17 @@ +import QtQuick 2.4 + +Item { + id:root + + ListView { + id: diceList + } + + Item{ + id: popupInput + + } + Item { + id: popupResult + } +} diff --git a/src/bin/mobile/resources/images/add.png b/src/bin/mobile/resources/images/add.png Binary files differnew file mode 100644 index 0000000..c8e1bd2 --- /dev/null +++ b/src/bin/mobile/resources/images/add.png diff --git a/src/bin/webserver/CMakeLists.txt b/src/bin/webserver/CMakeLists.txt new file mode 100644 index 0000000..3fa9b56 --- /dev/null +++ b/src/bin/webserver/CMakeLists.txt @@ -0,0 +1,78 @@ +cmake_minimum_required(VERSION 3.16) + +option(UPDATE_TRANSLATIONS "update Translation" OFF) +MESSAGE(STATUS "UPDATE TRANSLATIONS: ${UPDATE_TRANSLATIONS}") + + +project(diceserver) + + +# Find includes in corresponding build directories +set(CMAKE_INCLUDE_CURRENT_DIR ON) +# Instruct CMake to run moc automatically when needed. +set(CMAKE_AUTOMOC ON) + +# Find the QtWidgets library +find_package(Qt6 COMPONENTS Core Network) +#find_package(Qt6QuickCompiler) + +set(EXECUTABLE_OUTPUT_PATH bin/) + +include_directories(${Qt5Core_INCLUDES} ${Qt5Network_INCLUDES} webserver/qhttp/src ../) +add_definitions(${Qt5Core_DEFINITIONS} ${Qt5Network_DEFINITIONS} ) + +ADD_DEFINITIONS( + -std=c++11 +) + +#set(diceserver_RESOURCES diceparser.qrc) +FIND_PACKAGE(Qt6LinguistTools) + + + +SET( diceserver_sources + ../diceparser.cpp + ../range.cpp + ../booleancondition.cpp + ../validator.cpp + ../compositevalidator.cpp + ../operationcondition.cpp + ../die.cpp + ../parsingtoolbox.cpp + ../dicealias.cpp + ../result/result.cpp + ../result/scalarresult.cpp + ../result/stringresult.cpp + ../result/diceresult.cpp + ../node/countexecutenode.cpp + ../node/dicerollernode.cpp + ../node/executionnode.cpp + ../node/explodedicenode.cpp + ../node/helpnode.cpp + ../node/mergenode.cpp + ../node/jumpbackwardnode.cpp + ../node/keepdiceexecnode.cpp + ../node/listaliasnode.cpp + ../node/listsetrollnode.cpp + ../node/numbernode.cpp + ../node/parenthesesnode.cpp + ../node/paintnode.cpp + ../node/rerolldicenode.cpp + ../node/scalaroperatornode.cpp + ../node/sortresult.cpp + ../node/startingnode.cpp + ../node/ifnode.cpp + ../node/filternode.cpp + ../node/stringnode.cpp + main.cpp + diceserver.cpp + ../highlightdice.cpp +) +#qt5_add_resources(RESOURCE_ADDED mobile.qrc) + +add_executable( diceserver ${diceserver_sources} ) + +target_link_libraries(diceserver ${Qt5Core_LIBRARIES} ${Qt5Network_LIBRARIES} /home/renaud/application/mine/DiceParser/webserver/qhttp/xbin/libqhttp.so) +INSTALL_TARGETS(/bin diceserver) + +#qt5_use_modules() diff --git a/src/bin/webserver/diceserver.cpp b/src/bin/webserver/diceserver.cpp new file mode 100644 index 0000000..a3f094d --- /dev/null +++ b/src/bin/webserver/diceserver.cpp @@ -0,0 +1,237 @@ +#include "diceserver.h" +#include "qhttp/src/qhttpfwd.hpp" +#include "qhttp/src/qhttpserver.hpp" +#include "qhttp/src/qhttpserverrequest.hpp" +#include "qhttp/src/qhttpserverresponse.hpp" +#include <QHostAddress> +#include <QUrl> + +DiceServer::DiceServer(int port) : QObject(), m_diceParser(new DiceParser()) +{ + m_diceParser->setPathToHelp( + "<span><a href=\"https://github.com/Rolisteam/DiceParser/blob/master/HelpMe.md\">Documentation</a>"); + // using namespace ; + m_server= new qhttp::server::QHttpServer(this); + m_server->listen( // listening on 0.0.0.0:8080 + QHostAddress::Any, port, [=](qhttp::server::QHttpRequest* req, qhttp::server::QHttpResponse* res) { + req->collectData(1024); + + // qhttp::THeaderHash hash = req->headers(); + // qDebug() << hash << res->headers() << qhttp::Stringify::toString(req->method()) << + // qPrintable(req->url().toString()) << req->collectedData().constData(); + QString getArg= req->url().toString(); + getArg= getArg.replace("/?", ""); + QStringList args= getArg.split('&'); + QHash<QString, QString> m_hashArgs; + for(auto argument : args) + { + QStringList keyValue= argument.split('='); + if(keyValue.size() == 2) + { + m_hashArgs.insert(keyValue[0], keyValue[1]); + } + } + + if(m_hashArgs.contains("cmd")) + { + qDebug() << QUrl::fromPercentEncoding(m_hashArgs["cmd"].toLocal8Bit()); + QString result= startDiceParsing(QUrl::fromPercentEncoding(m_hashArgs["cmd"].toLocal8Bit())); + qDebug() << result; + + res->setStatusCode(qhttp::ESTATUS_OK); + res->addHeader("Access-Control-Allow-Origin", "*"); + res->addHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS"); + res->addHeader("Access-Control-Allow-Headers", "x-requested-with"); + + QString html("<!doctype html>\n" + "<html>\n" + "<head>\n" + " <meta charset=\"utf-8\">\n" + " <title>Rolisteam Dice System Webservice</title>\n" + " <style>.dice {color:#FF0000;font-weight: bold;}</style>" + "</head>\n" + "<body>\n" + "%1\n" + "</body>\n" + "</html>\n"); + + res->end(html.arg(result).toLocal8Bit()); + } + else + { + res->setStatusCode(qhttp::ESTATUS_OK); + res->end("No Command found!\n"); + } + }); + if(!m_server->isListening()) + { + qDebug() << "failed to listen"; + } + else + { + qDebug() << "Server is On!!"; + } +} + +DiceServer::~DiceServer() +{ + qDebug() << "destructor"; +} +QString DiceServer::diceToText(ExportedDiceResult& dice, bool highlight, bool homogeneous) +{ + QStringList resultGlobal; + foreach(int face, dice.keys()) + { + QStringList result; + QStringList currentStreak; + QList<QStringList> allStreakList; + ListDiceResult diceResult= dice.value(face); + bool previousHighlight= false; + QString previousColor; + QString patternColor("<span class=\"dice\">"); + foreach(HighLightDice tmp, diceResult) + { + if(previousColor != tmp.getColor()) + { + if(!currentStreak.isEmpty()) + { + QStringList list; + list << patternColor + currentStreak.join(',') + "</span>"; + allStreakList.append(list); + currentStreak.clear(); + } + if(tmp.getColor().isEmpty()) + { + patternColor= QStringLiteral("<span class=\"dice\">"); + } + else + { + patternColor= QStringLiteral("<span style=\"color:%1;font-weight:bold\">").arg(tmp.getColor()); + } + } + QStringList diceListStr; + if((previousHighlight) && (!tmp.isHighlighted())) + { + if(!currentStreak.isEmpty()) + { + QStringList list; + list << patternColor + currentStreak.join(',') + "</span>"; + allStreakList.append(list); + currentStreak.clear(); + } + } + else if((!previousHighlight) && (tmp.isHighlighted())) + { + if(!currentStreak.isEmpty()) + { + QStringList list; + list << currentStreak.join(','); + allStreakList.append(list); + currentStreak.clear(); + } + } + previousHighlight= tmp.isHighlighted(); + previousColor= tmp.getColor(); + for(int i= 0; i < tmp.getResult().size(); ++i) + { + qint64 dievalue= tmp.getResult()[i]; + diceListStr << QString::number(dievalue); + } + if(diceListStr.size() > 1) + { + QString first= diceListStr.takeFirst(); + first= QString("%1 [%2]").arg(first).arg(diceListStr.join(',')); + diceListStr.clear(); + diceListStr << first; + } + currentStreak << diceListStr.join(' '); + } + + if(previousHighlight) + { + QStringList list; + list << patternColor + currentStreak.join(',') + "</span>"; + allStreakList.append(list); + } + else + { + if(!currentStreak.isEmpty()) + { + QStringList list; + list << currentStreak.join(','); + allStreakList.append(list); + } + } + foreach(QStringList a, allStreakList) + { + result << a; + } + if(dice.keys().size() > 1) + { + resultGlobal << QString(" d%2:(%1)").arg(result.join(",")).arg(face); + } + else + { + resultGlobal << result.join(","); + } + } + return resultGlobal.join(""); +} + +QString DiceServer::startDiceParsing(QString cmd) +{ + QString result(""); + bool highlight= true; + if(m_diceParser->parseLine(cmd)) + { + m_diceParser->Start(); + if(!m_diceParser->getErrorMap().isEmpty()) + { + result+= "<span style=\"color: #FF0000\">Error:</span>" + m_diceParser->humanReadableError() + "<br/>"; + } + else + { + ExportedDiceResult list; + bool homogeneous= true; + m_diceParser->getLastDiceResult(list, homogeneous); + QString diceText= diceToText(list, highlight, homogeneous); + QString scalarText; + QString str; + + if(m_diceParser->hasIntegerResultNotInFirst()) + { + scalarText= QString("%1").arg(m_diceParser->getLastIntegerResult()); + } + else if(!list.isEmpty()) + { + scalarText= QString("%1").arg(m_diceParser->getSumOfDiceResult()); + } + if(highlight) + { + str= QString("Result: <span class=\"dice\">%1</span>, details:[%3 (%2)]") + .arg(scalarText) + .arg(diceText) + .arg(m_diceParser->getDiceCommand()); + } + else + { + str= QString("Result: %1, details:[%3 (%2)]") + .arg(scalarText) + .arg(diceText) + .arg(m_diceParser->getDiceCommand()); + } + + if(m_diceParser->hasStringResult()) + { + str= m_diceParser->getStringResult(); + } + result+= str + "<br/>"; + } + } + else + { + result+= "<span style=\"color: #00FF00\">Error:</span>" + m_diceParser->humanReadableError() + "<br/>"; + } + + return result; +} diff --git a/src/bin/webserver/diceserver.h b/src/bin/webserver/diceserver.h new file mode 100644 index 0000000..fa32814 --- /dev/null +++ b/src/bin/webserver/diceserver.h @@ -0,0 +1,18 @@ +#include "diceparser.h" +#include "qhttp/src/qhttpserver.hpp" +#include <QObject> + +class DiceServer : public QObject +{ + Q_OBJECT +public: + DiceServer(int port= 8085); + virtual ~DiceServer(); + + QString startDiceParsing(QString cmd); + QString diceToText(ExportedDiceResult& dice, bool highlight, bool homogeneous); + +private: + DiceParser* m_diceParser; + qhttp::server::QHttpServer* m_server; +}; diff --git a/src/bin/webserver/main.cpp b/src/bin/webserver/main.cpp new file mode 100644 index 0000000..664a026 --- /dev/null +++ b/src/bin/webserver/main.cpp @@ -0,0 +1,33 @@ +/*************************************************************************** + * Copyright (C) 2016 by Renaud Guezennec * + * http://www.rolisteam.org/contact * + * * + * rolisteam 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 2 of the License, or * + * (at your option) any later version. * + * * + * This program 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 this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ +#include <QCoreApplication> + +#include "diceparser.h" + +#include "diceserver.h" + +int main(int argc, char* argv[]) +{ + QCoreApplication app(argc, argv); + + DiceServer diceServer; + diceServer.setParent(&app); + return app.exec(); +} |