[
  {
    "path": ".gitignore",
    "content": "!/.gitignore\n!*.pro\n!*.pri\n!*.bat\n!/common-src/\n!/vsedit/src/\n!/vsedit-job-server/src/\n!/vsedit-job-server-watcher/src/\n!/resources/\n!/BUILDING\n!/CHANGELOG\n!/LICENSE\n!/README\n!/TODO.txt\n!/msvc/vsedit/vsedit.rc\n!/msvc/vsedit/resource.h\n!/msvc/vsedit-previewer/vsedit-previewer.rc\n!/msvc/vsedit-previewer/resource.h\n!/msvc/vsedit-job-server/vsedit-job-server.rc\n!/msvc/vsedit-job-server/resource.h\n!/msvc/vsedit-job-server-watcher/vsedit-job-server-watcher.rc\n!/msvc/vsedit-job-server-watcher/resource.h\n\nbuild\npro/*/*.rc\npro/*/Makefile.Release\npro/*/Makefile.Debug\npro/*/Makefile\npro/*/*.cpp\npro/dist\npro/.qmake.stash\npro/Makefile\npro/local_quirks.pri\n**/generated\n**/Release\n**/Debug\n\nmsvc/**/*.aps\n\n*.d\n*.slo\n*.lo\n*.o\n*.obj\n*.gch\n*.pch\n*.so\n*.dylib\n*.dll\n*.mod\n*.smod\n*.lai\n*.la\n*.a\n*.lib\n*.exe\n*.out\n*.app\n*/.vs\n*.vcxproj.user\n*.log\n*.props"
  },
  {
    "path": "BUILDING",
    "content": "THIS MANUAL IS A DRAFT. PLEASE REPORT ANY MISTAKES OR ADDITIONS AT https://github.com/YomikoR/VapourSynth-Editor/issues\n\n## Prerequisites\n\nYou need C++17 (or higher) compiler and Qt 6 development distribution.\nIn Ubuntu 22.04 LTS, for example, the packages qt6-base-dev and libqt6websockets6-dev are required.\n\n## Building VapourSynth Editor from source:\n\n1) make sure you meet the above prerequisites;\n2) open the system terminal and change working directory to the \"pro\" directory in the source tree;\n3) (optional) set environment variable `VS_INCLUDE_PATH` for the include path of VapourSynth header files, e.g. for Windows CMD\n    ```CMD\n    FOR /F \"USEBACKQ tokens=*\" %I IN (`python -c \"import vapoursynth;print(vapoursynth.get_include())\"`) DO (SET VS_INCLUDE_PATH=%I)\n    ```\n    and for *nix\n    ```shell\n    export VS_INCLUDE_PATH=`/usr/bin/env python3 -c \"import vapoursynth;print(vapoursynth.get_include())\"`\n    ```\n\n4) execute following command to generate the Makefile and other intermediate files\n\n    `qmake6 -norecursive pro.pro CONFIG+=release`\n\n5) \"make\" the Makefile with platform specific make-tool, e.g. `nmake` for MS Visual Studio.\n\nThe program files will be built in compiler specific sub-directory in the \"build\" directory in source tree and ready to use.\n\nIf you encounter path issues during the building related to missing headers, etc., you may include them in the file \"pro/local_quirks.pri\".\n\nBelow are some tested compilers:\n\n    Windows     MSVC\n    Linux       GCC\n    MacOS       clang (within brew)\n"
  },
  {
    "path": "CHANGELOG",
    "content": "r19-mod-6.10\n-BUGFIX: Cannot load old vsscript from list due to change on the file name.\n\nr19-mod-6.9\n-BUGFIX: Aborting dead process in job server watcher causes ghost entry.\n-Add match/case keywords to text editor highlighting (chrschmidt).\n-Make \"Home\" toggle between the block start and the first column (chrschmidt).\n-Disable color filling in the progress bars of job server watcher.\n-Add display support for _Range frame property since VS R73.\n-Search for vsscript library in environments since VS R74.\n-Switch to Qt6 regex functions.\n\nr19-mod-6.8\n-BUGFIX: Switching output index could fail after immediate playback.\n-Add hotkey options for switching to previous or next output index.\n-Add standalone console launcher for encode panel.\n\nr19-mod-6.7\n-BUGFIX: Messages sent by core logging are missing after preview refresh.\n-Add combo box for switching output index (enabled with VS R69 or later).\n\nr19-mod-6.6\n-BUGFIX: Previewer does not launch.\n-Allow all VS versions with API4.\n-Remove option that reloads script from disk before evaluation.\n-Add option to periodically reload script from disk to sync with external changes.\n-Add an asterisk in preview window title that indicates change in text editor.\n-Add info texts to certain reserved frame props when displayed.\n-Improve error handling of the previewer.\n-Better sync output frame numbers by timestamp.\n\nr19-mod-6.5\n-Use same vapoursynth library as used for script evaluation for plugin list.\n\nr19-mod-6.4\n-BUGFIX: Filter logs are not shown before script is evaluated.\n-BUGFIX: VS messages sent from core are duplicated.\n-BUGFIX: Each frame from script is requested twice (no influence in performance).\n-BUGFIX: Loading vsscript library from VS R66 portable directory fails.\n-BUGFIX: output nodes #10-#19 are not properly cleared.\nAdd audio playback (Windows only).\nAdd options to set output syncing mode.\nAdd core cache usage data in status bar.\n2020_CL option is removed from preview advanced settings.\n\nr19-mod-6.3\n-BUGFIX: On Linux the previewer refuses to quit.\n-In Windows 10 and later console window can show colored text (with ANSI escape sequences).\n-Add option to hide (VS and Qt) debug messages.\n-Add option to set dither type.\n-Show _AbsoluteTime frame props on title of preview panel.\n-Do not load chapter for VFR clips.\n-Add hotkey in preview panel for jumping to frame by frame number.\n\nr19-mod-6.2\n-BUGFIX: Encoding CLI won't start in Linux.\n-BUGFIX: Script is not loaded when file path encoding is not UTF-8.\n-VSEditor is a GUI app again with an option to toggle console window.\n-Adapt to Windows dark theme.\n-Offer qdarkstyle theme for all platforms.\n\nr19-mod-6.1\n-BUGFIX: Memory leak when closing preview window (regression from mod-6).\n-Support switching to output indices 10-19.\n-Add a standalone preview panel launcher, i.e. a script previewer.\n\nr19-mod-6\n-Drop Qt 5 support.\n-Switch to VapourSynth API4 (won't work with API3 VSScript libraries).\n-Add support for previewing video nodes with variational format or dimensions.\n\nr19-mod-5.6\n-BUGFIX: Chroma location parameter ignored when resampling to RGB for preview.\n-A panel is added for displaying frame properties.\n\nr19-mod-5.5\n-BUGFIX: Wrong dimensions in cropping when there are multiple video outputs.\n-Binaries are now working as console applications (instead of GUI apps) in Windows.\n-Binaries print version in Windows if the console is not automatically hidden on start.\n-A shortcut launching VSEditor in CMD is added to the installer.\n-Unused doc path options are removed.\n-Added an option to prefer loading VS libs from settings (other than Windows registry or sys PATH).\n\nr19-mod-5.4\n-BUGFIX: Reject problematic output nodes with invalid format.\n-Binaries print version and exit with -v or --version.\n\nr19-mod-5.3\n-BUGFIX: Flickering in playback due to a regression introduced with the dark theme.\n-BUGFIX: Image doesn't align to the top-left corner of the preview window in dark theme.\n-BUGFIX: Bright and dark themes were using the same setting groups.\n-BUGFIX: Image distortion with large zoom ratio.\n-Any change of switching between bright and dark themes will only take effect on program relaunching.\n-Modified zoom ratio step lengths when using fixed ratio.\n\nr19-mod-5.2\n-BUGFIX: VapourSynth lib searching not working in Qt6 on Windows. (SaltyChiang)\n-BUGFIX: Certain UI fonts look horrible in Qt6 on Windows with kerning enabled.\n-BUGFIX: Cursor pixelation in color panel in HIDPI.\n-BUGFIX: Wrong pipette info when cropping.\n-BUGFIX: Drop file template panel crashing when empty.\n-BUGFIX: Incorrect scroll navigator ratio in HIDPI.\n-Add dark theme (Windows only).\n-Introduce snapshot template with a silent mode (in preview advanced settings).\n-Slightly enlarged timeline bar.\n-Show \"Name\" and \"SceneName\" frame properties on window title.\n-Show Qt version in About menu.\n-Color and font settings will be saved only when differing from default values.\n\nr19-mod-5\n-BUGFIX: Building fails in Ubuntu LTS with older Qt versions.\n-BUGFIX: A blank .config file may be mistakenly created.\n-BUGFIX: Benchmark window doesn't normally stop and exit when pressing Escape.\n-Adapt to internal resizer changes since VS R58.\n-Support building with Qt 6 (with certain progress bar features disabled).\n-Enable HIDPI support (only with Qt 6).\n-Let playback rate respect frame durations (i.e. VFR).\n-Let inno installer work with Windows 7 SP1 and later.\n-Add .vpy file association in the inno installer.\n-Rename chroma location options by their position names and remove DV.\n-Set default chroma subsampling method to Bicubic b=0 c=0.5.\n-Let GRAY clip with RGB matrix be previewed as usual.\n-Edit program descriptions.\n-Don't search Program Files by path for finding vsscript.\n-Default hotkeys for zoom modes changed from 1/2/3 to Alt + 1/2/3.\n-When previewing, switch output nodes 0-9 by hotkeys 0-9.\n\nr19-mod-4:\n-BUGFIX: Encode preset header not correctly loaded.\n-BUGFIX: Loading chapters for VFR video results in division by zero.\n-BUGFIX: Failure when building in a recent version of MacOS.\n-BUGFIX: Program crashes when launching from second screen in MacOS with Qt 5.12.\n-BUGFIX: Only the main screen's bit depth is reported.\n-BUGFIX: Settings are lost in current session when switching to portable mode while config file is not writable.\n-Add Inno build script for a Windows installer (by rlaphoenix).\n-Add a setting entry for reloading script from disk before execution.\n-Improve open-box experience of the text editor: using spaces as tabs, 12pt font size, adjusted colors for dark themes.\n-Raise minimum VapourSynth version requirement to R47 (API 3.6).\n-Remove a number of obsolete Qt methods (raising Qt version requirement to 5.8).\n-Frame numbers computed from chapter timestamps are rounded instead of ceiling.\n-\"Shell commands\" in job server won't be executed with cmd /c or sh -c prefix anymore.\n\nr19-mod-3:\n-BUGFIX: Crash on file drop setting menu.\n-BUGFIX: Black screen for 10-bit preview.\n-Add back support for YCOCG and COMPAT colorspaces.\n-Show cursur position and on screen RGB values with color panel.\n-Add a setting entry for snapshot compression level.\n\nr19-mod-2:\n-Improve performance for RGB format packing (thanks to DJATOM and sekrit-twc).\n\nr19-mod-1:\n-Drop support for YCOCG and COMPAT colorspaces.\n-Work with VapourSynth v4 API (built with v3).\n-Dither to RGB for preview output.\n-Preview in 10-bit color depth in Unix when allowed.\n-Compress PNG file size when saving snapshots.\n-Replace legacy get_core() from the template.\n\nr19:\n-BUGFIX: Rapid settings updating on windows geometry change.\n-BUGFIX: Theme settings corruption when using job server.\n-Color picker update with a still mouse cursor in play mode.\n-Benchmark dialog remembers first and last frame for current script.\n\nr18:\n-BUGFIX: Crash on encode dialog initialization error.\n-BUGFIX: No error in log on encode dialog initialization error.\n-Import chapter files as preview bookmarks (by brainvlad@gmail.com).\n\nr17:\n-BUGFIX: Blank preview on variable size video with fixed zoom ratio.\n-BUGFIX: Saving new script.\n-BUGFIX: Invalid context menu for editor.\n-BUGFIX: Context menu behavior in preview.\n-New multi-app architecture: editor, job server, server watcher.\n\nr16:\n-BUGFIX: Default hotkey forced when trying to save an empty hotkey.\n-BUGFIX: Inactive actions in the log context menu.\n-Jobs queue with dependencies tracking.\n-Adjustable jobs table.\n-Pausable CLI encoding jobs.\n-Pausable process run jobs.\n-Shell command execute jobs.\n-Removed framebuffer monitoring.\n-Move text block up action.\n-Move text block down action.\n-Toggle comment action.\n-Fixed VS API version requested for internal plugins polling.\n-Larger settings dialog to remove the warning.\n\nr15:\n-BUGFIX: crash on colour picking while refreshing preview.\n-BUGFIX: random junk instead of black frame on preview refresh.\n-BUGFIX: wrong hours displayed in estimated finish time for benchmark and encoding.\n-Buildable with Qt version lower than 5.4.\n-Float formats support in yuv4mpeg video header for encoding.\n\nr14:\n-BUGFIX: Encoding logic.\n-Core buffer usage display.\n-Relative paths are resolved from the application directory, not CWD.\n-Benchmark and encoding progress in window title.\n-MS Windows: taskbar button progress for benchmark and encoding.\n-Script dialogs status bar reorganized.\n-WebP snapshots support.\n\nr13:\n-yuv4mpeg header for video encoding.\n\nr12:\n-Improved log.\n-Crash log is saved as HTML from the main log.\n\nr11:\n-BUGFIX: Default file drop template.\n-BUGFIX: Preview non-YUV clips.\n-An option to keep the currently previewed frame number on previewing different script.\n\nr10:\n-BUGFIX: Colour picking.\n-BUGFIX: VapourSynth messages handling.\n-BUGFIX: Frame processing errors handling in different modes.\n-BUGFIX: Pasting crop snippet into the last script line.\n-BUGFIX: Benchmark and encode dialogs forward initialization error to main window log and hide on error if open.\n-Crashlog on VapourSynth fatal errors.\n-Keep preview scrolling and frame number on refreshing the same script.\nReset on previewing new script. Unsaved script preview is always reset.\n-Editor: selected text/current line duplication action.\n-Editor: comment/uncomment selected lines actions.\n-Editor: multiline tab and backtab.\n-Options to use spaces as Tab and set Tab size.\n-Editor: Replace Tab characters with spaces action.\n-Editor: smart Home key behaviour.\n-An option to remember and restore the last previewed frame between sessions.\n-New script template setting.\n-Code snippets.\n-File drop templates.\n-Option to highlight selection matches in script editor.\n-Timeline bookmarks with auto-saving/loading bookmarks file along the script file.\n-Remember timeline panel visibility.\n-Most timeline colours are bound to OS theme.\n-Changes in default standard hotkeys. Many default hotkeys are now OS-dependent. CTRL + arrows in preview window now move between bookmarks and CTRL + SHIFT + arrows jump time intervals.\n-Frames number and subsampling string tokens in encoder.\n-Estimated finish time output in benchmark and encoder.\n-Encoder argument tokens format changed into more readable one.\n-Colour picker moved into status bar.\n-Paste shown frame number into script action.\n\nr⑨:\n-Asynchronous frames processing. More responsive GUI.\n-Preview video playback.\n-Script processing benchmarking.\n-Encoding video with CLI tools.\n\nr8:\n-BUGFIX: Preview stride.\n\nr7:\n-BUGFIX: Bt.601 YUV to RGB conversion matrix. Not sure if it works correctly, but it works.\n-BUGFIX: Massive memory leak.\n-Late linking to vsscript library. Can start with no VapourSynth installed.\n-Better detection of VapourSynth installation on Windows.\n-Experimental colour picker. Shows values under cursor in preview window. Not thoroughly tested.\n\nr6:\n-Added some theme settings.\n-Switched preview to use the internal resizer instead of zimg. Requires VapourSynth R29+.\n-Support for building under MacOS X (not tested).\n\nr5:\nFix release.\n-Fixed compatibility with VapourSynth r27. Patch by Myrsloik.\n-Fixed \"Copy frame to clipboard\" action.\n\nr4:\n-Custom font is embedded.\n-Internal format conversion for preview. All VapourSynth video formats are now supported.\n\nr3:\n-Fixed zoom ratio changed to real number.\n-New line autoindentation.\n\nr2:\n-File paths are changed to canonical before adding to recent files list to eliminate doubling records.\n-Change window title when script path changes.\n-Always create new script on start before trying to open any.\n"
  },
  {
    "path": "LICENSE",
    "content": "Copyright (c) 2014 - 2017 Aleksey [Mystery Keeper] Lyashin\nmystkeeper@gmail.com\nCopyright (c) 2022 - 2026 YomikoR\n\nPermission is hereby granted, free of charge, to any person\nobtaining a copy of this software and associated documentation\nfiles (the \"Software\"), to deal in the Software without\nrestriction, including without limitation the rights to use,\ncopy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the\nSoftware is furnished to do so, subject to the following\nconditions:\n\nThe above copyright notice and this permission notice shall be\nincluded in all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND,\nEXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES\nOF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\nNONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT\nHOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\nWHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\nFROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR\nOTHER DEALINGS IN THE SOFTWARE.\n"
  },
  {
    "path": "README",
    "content": "VapourSynth Editor r19-mod-6.10\n\nBy Aleksey [Mystery Keeper] Lyashin\nmystkeeper@gmail.com\nhttp://mysterykeeper.ru\n\nModified by YomikoR\n\nThis software is free and distributed under MIT license.\n\nSoftware uses Qt framework by The Qt Company, distributed under LGPL license.\nhttps://qt.io/\n\nSoftware includes Silk icons v1.3 by Mark James,\ndistributed under Creative Commons Attribution 2.5 License.\nhttp://www.famfamfam.com/lab/icons/silk/\n\nSoftware includes FatCow free icons,\ndistributed under Creative Commons Attribution 3.0 License.\nhttp://www.fatcow.com/free-icons\n\nSoftware includes QDarkStyleSheet v3.0.3,\ndistributed under MIT License for code,\nand Creative Commons Attribution 4.0 International License for images.\nhttps://github.com/ColinDuquesnoy/QDarkStyleSheet\n\nFor additional information see LICENSE file.\n"
  },
  {
    "path": "TODO.txt",
    "content": "- search and replace text\n- choose the default vsscript library load path\n- insert formatted data from preview window into script\n- functions autocompletion refinement\n- python error parsing and script line highlighting\n- multiple output nodes comparison\n- reference and documentation\n"
  },
  {
    "path": "common-src/application_instance_file_guard/application_instance_file_guard.cpp",
    "content": "#include \"application_instance_file_guard.h\"\n\n#include <QObject>\n#include <QStandardPaths>\n\n#ifndef Q_OS_WIN\n\t#include <sys/file.h>\n#endif\n\n//==============================================================================\n\nApplicationInstanceFileGuard::ApplicationInstanceFileGuard(\n\tconst QString & a_fileName)\n{\n\tm_tempDir =\n\t\tQStandardPaths::writableLocation(QStandardPaths::TempLocation);\n\tif(!a_fileName.isEmpty())\n\t\tlock(a_fileName);\n}\n\n//==============================================================================\n\nApplicationInstanceFileGuard::~ApplicationInstanceFileGuard()\n{\n\tif(m_file.isOpen())\n\t\tunlock();\n}\n\n//==============================================================================\n\nbool ApplicationInstanceFileGuard::lock(const QString & a_fileName)\n{\n\tif(m_file.isOpen())\n\t{\n\t\tif(a_fileName == m_fileName)\n\t\t\treturn true;\n\n\t\tbool unlocked = unlock();\n\t\tif(!unlocked)\n\t\t\treturn false;\n\t}\n\n\tQString filePath = m_tempDir + \"/\" + a_fileName;\n\n#ifdef Q_OS_WIN\n\tif(QFile::exists(filePath))\n\t{\n\t\tbool deleted = QFile::remove(filePath);\n\t\tif(!deleted)\n\t\t{\n\t\t\tm_error = QObject::tr(\"Could not delete file %1\")\n\t\t\t\t.arg(filePath);\n\t\t\treturn false;\n\t\t}\n\t}\n#endif\n\n\tm_fileName = a_fileName;\n\tm_file.setFileName(filePath);\n\tbool opened = m_file.open(QIODevice::ReadWrite);\n\tif(!opened)\n\t{\n\t\tm_error = QObject::tr(\"Could not open file %1\").arg(filePath);\n\t\treturn false;\n\t}\n\n#ifndef Q_OS_WIN\n\tint result = flock(m_file.handle(), LOCK_EX | LOCK_NB);\n\tif(result != 0)\n\t{\n\t\tm_error = QObject::tr(\"Could not lock file %1\").arg(filePath);\n\t\tm_file.close();\n\t\treturn false;\n\t}\n#endif\n\n\treturn true;\n}\n\n//==============================================================================\n\nbool ApplicationInstanceFileGuard::unlock()\n{\n\tif(m_file.isOpen())\n\t{\n\t#ifndef Q_OS_WIN\n\t\tflock(m_file.handle(), LOCK_UN | LOCK_NB);\n\t#endif\n\t\tm_file.close();\n\t}\n\n\tQString filePath = m_file.fileName();\n\n\tif(filePath.isEmpty())\n\t{\n\t\tm_error = QObject::tr(\"File name is empty.\");\n\t\treturn false;\n\t}\n\n\tif(!QFile::exists(filePath))\n\t\treturn true;\n\n\tbool deleted = QFile::remove(filePath);\n\tif(!deleted)\n\t\tm_error = QObject::tr(\"Could not delete file %1\").arg(filePath);\n\treturn deleted;\n}\n\n//==============================================================================\n\nbool ApplicationInstanceFileGuard::isLocked() const\n{\n\treturn m_file.isOpen();\n}\n\n//==============================================================================\n\nQString ApplicationInstanceFileGuard::error() const\n{\n\treturn m_error;\n}\n\n//==============================================================================\n"
  },
  {
    "path": "common-src/application_instance_file_guard/application_instance_file_guard.h",
    "content": "#ifndef APPLICATION_INSTANCE_FILE_GUARD_H_INCLUDED\n#define APPLICATION_INSTANCE_FILE_GUARD_H_INCLUDED\n\n#include <QString>\n#include <QFile>\n\nclass ApplicationInstanceFileGuard\n{\npublic:\n\n\tApplicationInstanceFileGuard(const QString & a_fileName = QString());\n\tvirtual ~ApplicationInstanceFileGuard();\n\tbool lock(const QString & a_fileName);\n\tbool unlock();\n\tbool isLocked() const;\n\tQString error() const;\n\nprivate:\n\n\tQFile m_file;\n\tQString m_error;\n\tQString m_fileName;\n\tQString m_tempDir;\n};\n\n#endif // APPLICATION_INSTANCE_FILE_GUARD_H_INCLUDED\n"
  },
  {
    "path": "common-src/chrono.h",
    "content": "#ifndef CHRONO_H_INCLUDED\n#define CHRONO_H_INCLUDED\n\n#include <chrono>\n\ntypedef std::chrono::high_resolution_clock::time_point hr_time_point;\ntypedef std::chrono::high_resolution_clock hr_clock;\ntypedef std::chrono::duration<double, std::ratio<1, 1> > double_duration;\n\ntemplate <typename T> double duration_to_double(const T & a_duration)\n{\n\treturn std::chrono::duration_cast<double_duration>(a_duration).count();\n}\n\n#endif // CHRONO_H_INCLUDED\n"
  },
  {
    "path": "common-src/frame_header_writers/frame_header_writer.cpp",
    "content": "#include \"frame_header_writer.h\"\n\n//==============================================================================\n\nFrameHeaderWriter::FrameHeaderWriter(const VSAPI * a_cpVSAPI,\n\tconst VSVideoInfo * a_cpVideoInfo, QObject * a_pParent) :\n\t  QObject(a_pParent)\n\t, m_cpVSAPI(a_cpVSAPI)\n\t, m_cpVideoInfo(a_cpVideoInfo)\n{\n}\n\n// END OF FrameHeaderWriter::FrameHeaderWriter(const VSAPI * a_cpVSAPI,\n//\t\tconst VSVideoInfo * a_cpVideoInfo, QObject * a_pParent)\n//==============================================================================\n\nFrameHeaderWriter::~FrameHeaderWriter()\n{\n}\n\n// END OF FrameHeaderWriter::~FrameHeaderWriter()\n//==============================================================================\n\nvoid FrameHeaderWriter::setVSAPI(const VSAPI * a_cpVSAPI)\n{\n\tm_cpVSAPI = a_cpVSAPI;\n}\n\n// END OF void FrameHeaderWriter::setVSAPI(const VSAPI * a_cpVSAPI)\n//==============================================================================\n\nvoid FrameHeaderWriter::setVideoInfo(const VSVideoInfo * a_cpVideoInfo)\n{\n\tm_cpVideoInfo = a_cpVideoInfo;\n}\n\n// END OF void FrameHeaderWriter::setVideoInfo(\n//\t\tconst VSVideoInfo * a_cpVideoInfo)\n//==============================================================================\n"
  },
  {
    "path": "common-src/frame_header_writers/frame_header_writer.h",
    "content": "#ifndef FRAME_HEADER_WRITER_H_INCLUDED\n#define FRAME_HEADER_WRITER_H_INCLUDED\n\n#include <VapourSynth4.h>\n\n#include <QObject>\n\nclass FrameHeaderWriter : public QObject\n{\n\tQ_OBJECT\n\npublic:\n\n\tFrameHeaderWriter(const VSAPI * a_cpVSAPI = nullptr,\n\t\tconst VSVideoInfo * a_cpVideoInfo = nullptr,\n\t\tQObject * a_pParent = nullptr);\n\tvirtual ~FrameHeaderWriter();\n\n\tvirtual void setVSAPI(const VSAPI * a_cpVSAPI);\n\tvirtual void setVideoInfo(const VSVideoInfo * a_cpVideoInfo);\n\n\tvirtual bool isCompatible() = 0;\n\n\tvirtual bool needVideoHeader() = 0;\n\tvirtual QByteArray videoHeader(int a_totalFrames = -1) = 0;\n\n\tvirtual bool needFramePrefix() = 0;\n\tvirtual QByteArray framePrefix(const VSFrame * a_cpFrame) = 0;\n\n\tvirtual bool needFramePostfix() = 0;\n\tvirtual QByteArray framePostfix(const VSFrame * a_cpFrame) = 0;\n\nprotected:\n\n\tconst VSAPI * m_cpVSAPI;\n\tconst VSVideoInfo * m_cpVideoInfo;\n};\n\n#endif // FRAME_HEADER_WRITER_H_INCLUDED\n"
  },
  {
    "path": "common-src/frame_header_writers/frame_header_writer_null.cpp",
    "content": "#include \"frame_header_writer_null.h\"\n\n//==============================================================================\n\nFrameHeaderWriterNull::FrameHeaderWriterNull(const VSAPI * a_cpVSAPI,\n\tconst VSVideoInfo * a_cpVideoInfo, QObject * a_pParent) :\n\tFrameHeaderWriter(a_cpVSAPI, a_cpVideoInfo, a_pParent)\n{\n}\n\n// END OF FrameHeaderWriterNull::FrameHeaderWriterNull(const VSAPI * a_cpVSAPI,\n//\t\tconst VSVideoInfo * a_cpVideoInfo, QObject * a_pParent)\n//==============================================================================\n\nbool FrameHeaderWriterNull::isCompatible()\n{\n    Q_ASSERT(m_cpVideoInfo);\n    if(!m_cpVideoInfo)\n\t\treturn false;\n\treturn true;\n}\n\n// END OF bool FrameHeaderWriterNull::isCompatible()\n//==============================================================================\n\nbool FrameHeaderWriterNull::needVideoHeader()\n{\n\treturn false;\n}\n\n// END OF bool FrameHeaderWriterNull::needVideoHeader()\n//==============================================================================\n\nQByteArray FrameHeaderWriterNull::videoHeader(int a_totalFrames)\n{\n\t(void)a_totalFrames;\n\treturn QByteArray();\n}\n\n// END OF QByteArray FrameHeaderWriterNull::videoHeader(int a_totalFrames)\n//==============================================================================\n\nbool FrameHeaderWriterNull::needFramePrefix()\n{\n\treturn false;\n}\n\n// END OF bool FrameHeaderWriterNull::needFramePrefix()\n//==============================================================================\n\nQByteArray FrameHeaderWriterNull::framePrefix(const VSFrame * a_cpFrame)\n{\n\t(void)a_cpFrame;\n\treturn QByteArray();\n}\n\n// END OF QByteArray FrameHeaderWriterNull::framePrefix(\n//\t\tconst VSFrame * a_cpFrame)\n//==============================================================================\n\nbool FrameHeaderWriterNull::needFramePostfix()\n{\n\treturn false;\n}\n\n// END OF bool FrameHeaderWriterNull::needFramePostfix()\n//==============================================================================\n\nQByteArray FrameHeaderWriterNull::framePostfix(const VSFrame * a_cpFrame)\n{\n\t(void)a_cpFrame;\n\treturn QByteArray();\n}\n\n// END OF QByteArray FrameHeaderWriterNull::framePostfix(\n//\t\tconst VSFrame * a_cpFrame)\n//==============================================================================\n"
  },
  {
    "path": "common-src/frame_header_writers/frame_header_writer_null.h",
    "content": "#ifndef FRAME_HEADER_WRITER_NULL_H_INCLUDED\n#define FRAME_HEADER_WRITER_NULL_H_INCLUDED\n\n#include \"frame_header_writer.h\"\n\nclass FrameHeaderWriterNull : public FrameHeaderWriter\n{\n\tQ_OBJECT\n\npublic:\n\n\tFrameHeaderWriterNull(const VSAPI * a_cpVSAPI = nullptr,\n\t\tconst VSVideoInfo * a_cpVideoInfo = nullptr,\n\t\tQObject * a_pParent = nullptr);\n\n\tvirtual bool isCompatible() override;\n\n\tvirtual bool needVideoHeader() override;\n\tvirtual QByteArray videoHeader(int a_totalFrames = -1) override;\n\n\tvirtual bool needFramePrefix() override;\n\tvirtual QByteArray framePrefix(const VSFrame * a_cpFrame) override;\n\n\tvirtual bool needFramePostfix() override;\n\tvirtual QByteArray framePostfix(const VSFrame * a_cpFrame) override;\n};\n\n#endif // FRAME_HEADER_WRITER_NULL_H_INCLUDED\n"
  },
  {
    "path": "common-src/frame_header_writers/frame_header_writer_y4m.cpp",
    "content": "#include \"frame_header_writer_y4m.h\"\n\n#include \"../../../common-src/helpers.h\"\n\n#include <string>\n#include <map>\n\n//==============================================================================\n\nFrameHeaderWriterY4M::FrameHeaderWriterY4M(const VSAPI * a_cpVSAPI,\n\tconst VSVideoInfo * a_cpVideoInfo, QObject * a_pParent) :\n\tFrameHeaderWriter(a_cpVSAPI, a_cpVideoInfo, a_pParent)\n{\n}\n\n// END OF FrameHeaderWriterY4M::FrameHeaderWriterY4M(const VSAPI * a_cpVSAPI,\n//\t\tconst VSVideoInfo * a_cpVideoInfo, QObject * a_pParent)\n//==============================================================================\n\nbool FrameHeaderWriterY4M::isCompatible()\n{\n    Q_ASSERT(m_cpVideoInfo);\n    if(!m_cpVideoInfo)\n\t\treturn false;\n\n\tconst VSVideoFormat * cpFormat = &m_cpVideoInfo->format;\n\n\tint compatibleColorFamily[] = {cfGray, cfYUV};\n\tif(!vsedit::contains(compatibleColorFamily, cpFormat->colorFamily))\n\t\treturn false;\n\n\tif(cpFormat->sampleType == stFloat)\n\t{\n\t\tint acceptableBitDepths[] = {16, 32, 64};\n\t\tif(!vsedit::contains(acceptableBitDepths, cpFormat->bitsPerSample))\n\t\t\treturn false;\n\t}\n\n\tstd::pair<int, int> compatibleSubsampling[] =\n\t\t{{0, 0}, {0, 1}, {1, 0}, {1, 1}, {2, 0}, {2, 2}};\n\tstd::pair<int, int> subsampling(cpFormat->subSamplingW,\n\t\tcpFormat->subSamplingH);\n\tif(!vsedit::contains(compatibleSubsampling, subsampling))\n\t\treturn false;\n\n\treturn true;\n}\n\n// END OF bool FrameHeaderWriterY4M::isCompatible()\n//==============================================================================\n\nbool FrameHeaderWriterY4M::needVideoHeader()\n{\n\treturn true;\n}\n\n// END OF bool FrameHeaderWriterY4M::needVideoHeader()\n//==============================================================================\n\nQByteArray FrameHeaderWriterY4M::videoHeader(int a_totalFrames)\n{\n\tQ_ASSERT(m_cpVideoInfo);\n\tQ_ASSERT(isCompatible());\n\tconst VSVideoFormat * cpFormat = &m_cpVideoInfo->format;\n\n\tstd::string header;\n\n\theader += \"YUV4MPEG2 C\";\n\n\tif(cpFormat->colorFamily == cfGray)\n\t{\n\t\theader += \"mono\";\n\t\tif(cpFormat->bitsPerSample > 8)\n\t\t\theader += std::to_string(cpFormat->bitsPerSample);\n\t}\n\telse if(cpFormat->colorFamily == cfYUV)\n\t{\n\t\tstd::map<std::pair<int, int>, std::string> subsamplingStringMap =\n\t\t{\n\t\t\t{{0, 0}, \"444\"},\n\t\t\t{{0, 1}, \"440\"},\n\t\t\t{{1, 0}, \"422\"},\n\t\t\t{{1, 1}, \"420\"},\n\t\t\t{{2, 0}, \"411\"},\n\t\t\t{{2, 2}, \"410\"},\n\t\t};\n\t\tstd::pair<int, int> subsampling(cpFormat->subSamplingW,\n\t\t\tcpFormat->subSamplingH);\n\t\theader += subsamplingStringMap[subsampling];\n\n\t\tif((cpFormat->bitsPerSample > 8) && (cpFormat->sampleType == stInteger))\n\t\t\theader += \"p\" + std::to_string(cpFormat->bitsPerSample);\n\t\telse if(cpFormat->sampleType == stFloat)\n\t\t{\n\t\t\theader += \"p\";\n\t\t\tif(cpFormat->bitsPerSample == 16)\n\t\t\t\theader += \"h\";\n\t\t\telse if(cpFormat->bitsPerSample == 32)\n\t\t\t\theader += \"s\";\n\t\t\telse if(cpFormat->bitsPerSample == 64)\n\t\t\t\theader += \"d\";\n\t\t\telse\n\t\t\t{\n\t\t\t\tQ_ASSERT(false);\n\t\t\t\theader += \"u\";\n\t\t\t}\n\t\t}\n\t}\n\telse\n\t{\n\t\tQ_ASSERT(false);\n\t}\n\n\tint totalFrames = (a_totalFrames < 0) ? m_cpVideoInfo->numFrames :\n\t\ta_totalFrames;\n\n\theader = header\n\t\t+ \" W\" + std::to_string(m_cpVideoInfo->width)\n\t\t+ \" H\" + std::to_string(m_cpVideoInfo->height)\n\t\t+ \" F\" + std::to_string(m_cpVideoInfo->fpsNum)\n\t\t+ \":\" + std::to_string(m_cpVideoInfo->fpsDen)\n        + \" Ip A0:0\"\n        + \" XLENGTH=\" + std::to_string(totalFrames)\n        + \"\\n\";\n\n\tQByteArray headerData(header.c_str());\n\treturn headerData;\n}\n\n// END OF QByteArray FrameHeaderWriterY4M::videoHeader(int a_totalFrames)\n//==============================================================================\n\nbool FrameHeaderWriterY4M::needFramePrefix()\n{\n\treturn true;\n}\n\n// END OF bool FrameHeaderWriterY4M::needFramePrefix()\n//==============================================================================\n\nQByteArray FrameHeaderWriterY4M::framePrefix(const VSFrame * a_cpFrame)\n{\n\t(void)a_cpFrame;\n\tstd::string prefix = \"FRAME\\n\";\n\tQByteArray prefixData(prefix.c_str());\n\treturn prefixData;\n}\n\n// END OF QByteArray FrameHeaderWriterY4M::framePrefix(\n//\t\tconst VSFrame * a_cpFrame)\n//==============================================================================\n\nbool FrameHeaderWriterY4M::needFramePostfix()\n{\n\treturn false;\n}\n\n// END OF bool FrameHeaderWriterY4M::needFramePostfix()\n//==============================================================================\n\nQByteArray FrameHeaderWriterY4M::framePostfix(const VSFrame * a_cpFrame)\n{\n\t(void)a_cpFrame;\n\treturn QByteArray();\n}\n\n// END OF QByteArray FrameHeaderWriterY4M::framePostfix(\n//\t\tconst VSFrame * a_cpFrame)\n//==============================================================================\n"
  },
  {
    "path": "common-src/frame_header_writers/frame_header_writer_y4m.h",
    "content": "#ifndef FRAME_HEADER_WRITER_Y4M_H_INCLUDED\n#define FRAME_HEADER_WRITER_Y4M_H_INCLUDED\n\n#include \"frame_header_writer.h\"\n\nclass FrameHeaderWriterY4M : public FrameHeaderWriter\n{\n\tQ_OBJECT\n\npublic:\n\n\tFrameHeaderWriterY4M(const VSAPI * a_cpVSAPI = nullptr,\n\t\tconst VSVideoInfo * a_cpVideoInfo = nullptr,\n\t\tQObject * a_pParent = nullptr);\n\n\tvirtual bool isCompatible() override;\n\n\tvirtual bool needVideoHeader() override;\n\tvirtual QByteArray videoHeader(int a_totalFrames = -1) override;\n\n\tvirtual bool needFramePrefix() override;\n\tvirtual QByteArray framePrefix(const VSFrame * a_cpFrame) override;\n\n\tvirtual bool needFramePostfix() override;\n\tvirtual QByteArray framePostfix(const VSFrame * a_cpFrame) override;\n};\n\n#endif // FRAME_HEADER_WRITER_Y4M_H_INCLUDED\n"
  },
  {
    "path": "common-src/helpers.cpp",
    "content": "#include \"helpers.h\"\n\n#include <QDir>\n#include <QFileInfo>\n#include <QCoreApplication>\n#include <cmath>\n#include <functional>\n#include <vector>\n\n/* https://www.ffmpeg.org/ffmpeg-utils.html#Channel-Layout */\nstatic std::map<VSAudioChannels, QString> audioChannelToString =\n{\n\t{acFrontLeft, \"FL\"},\n\t{acFrontRight, \"FR\"},\n\t{acFrontCenter, \"FC\"},\n\t{acLowFrequency, \"LFE\"},\n\t{acBackLeft, \"BL\"},\n\t{acBackRight, \"BR\"},\n\t{acFrontLeftOFCenter, \"FLC\"},\n\t{acFrontRightOFCenter, \"FRC\"},\n\t{acBackCenter, \"BC\"},\n\t{acSideLeft, \"SL\"},\n\t{acSideRight, \"SR\"},\n\t{acTopCenter, \"TC\"},\n\t{acTopFrontLeft, \"TFL\"},\n\t{acTopFrontCenter, \"TFC\"},\n\t{acTopFrontRight, \"TFR\"},\n\t{acTopBackLeft, \"TBL\"},\n\t{acTopBackCenter, \"TBC\"},\n\t{acTopBackRight, \"TBR\"},\n\t{acStereoLeft, \"DL\"}, // \"downmix left\"\n\t{acStereoRight, \"DR\"}, // \"downmix right\"\n\t{acWideLeft, \"WL\"},\n\t{acWideRight, \"WR\"},\n\t{acSurroundDirectLeft, \"SDL\"},\n\t{acSurroundDirectRight, \"SDR\"},\n\t{acLowFrequency2, \"LFE2\"}\n};\n\nstatic uint64_t genAudioChannelFlag(std::vector<VSAudioChannels> channels)\n{\n\tuint64_t flag = 0;\n\tfor(VSAudioChannels c : channels)\n\t{\n\t\tflag |= (static_cast<uint64_t>(1) << c);\n\t}\n\treturn flag;\n}\n\n#define gACF genAudioChannelFlag\n\nstatic std::map<uint64_t, QString> audioChannelToPreset =\n{\n\t{gACF({acFrontCenter}), \"mono\"},\n\t{gACF({acFrontLeft, acFrontRight}), \"stereo\"},\n\t{gACF({acFrontLeft, acFrontRight, acLowFrequency}), \"2.1\"},\n\t{gACF({acFrontLeft, acFrontRight, acFrontCenter}), \"3.0\"},\n\t{gACF({acFrontLeft, acFrontRight, acBackCenter}), \"3.0(back)\"},\n\t{gACF({acFrontLeft, acFrontRight, acFrontCenter, acBackCenter}), \"4.0\"},\n\t{gACF({acFrontLeft, acFrontRight, acBackLeft, acBackRight}), \"quad\"},\n\t{gACF({acFrontLeft, acFrontRight, acSideLeft, acSideRight}), \"quad(side)\"},\n\t{gACF({acFrontLeft, acFrontRight, acFrontCenter, acLowFrequency}), \"3.1\"},\n\t{gACF({acFrontLeft, acFrontRight, acFrontCenter, acSideLeft, acSideRight}), \"5.0\"},\n\t{gACF({acFrontLeft, acFrontRight, acFrontCenter, acLowFrequency, acBackCenter}), \"4.1\"},\n\t{gACF({acFrontLeft, acFrontRight, acFrontCenter, acLowFrequency, acBackLeft, acBackRight}), \"5.1\"},\n\t{gACF({acFrontLeft, acFrontRight, acFrontCenter, acLowFrequency, acSideLeft, acSideRight}), \"5.1(side)\"},\n\t{gACF({acFrontLeft, acFrontRight, acFrontCenter, acBackCenter, acSideLeft, acSideRight}), \"6.0\"},\n\t{gACF({acFrontLeft, acFrontRight, acFrontLeftOFCenter, acFrontRightOFCenter, acSideLeft, acSideRight}), \"6.0(front)\"},\n\t{gACF({acFrontLeft, acFrontRight, acFrontCenter, acBackLeft, acBackRight, acBackCenter}), \"hexagonal\"},\n\t{gACF({acFrontLeft, acFrontRight, acFrontCenter, acLowFrequency, acBackLeft, acBackRight, acBackCenter}), \"6.1\"},\n\t{gACF({acFrontLeft, acFrontRight, acLowFrequency, acFrontLeftOFCenter, acFrontRightOFCenter, acSideLeft, acSideRight}), \"6.1(front)\"},\n\t{gACF({acFrontLeft, acFrontRight, acFrontCenter, acBackLeft, acBackRight, acSideLeft, acSideRight}), \"7.0\"},\n\t{gACF({acFrontLeft, acFrontRight, acFrontCenter, acFrontLeftOFCenter, acFrontRightOFCenter, acSideLeft, acSideRight}), \"7.0(front)\"},\n\t{gACF({acFrontLeft, acFrontRight, acFrontCenter, acLowFrequency, acBackLeft, acBackRight, acSideLeft, acSideRight}), \"7.1\"},\n\t{gACF({acFrontLeft, acFrontRight, acFrontCenter, acLowFrequency, acBackLeft, acBackRight, acFrontLeftOFCenter, acFrontRightOFCenter}), \"7.1(wide)\"},\n\t{gACF({acFrontLeft, acFrontRight, acFrontCenter, acLowFrequency, acFrontLeftOFCenter, acFrontRightOFCenter, acSideLeft, acSideRight}), \"7.1(wide-side)\"},\n\t{gACF({acFrontLeft, acFrontRight, acFrontCenter, acBackLeft, acBackRight, acBackCenter, acSideLeft, acSideRight}), \"octagonal\"},\n\t{gACF({acFrontLeft, acFrontRight, acFrontCenter, acBackLeft, acBackRight, acBackCenter, acSideLeft, acSideRight, acWideLeft, acWideRight, acTopBackLeft, acTopBackRight, acTopBackCenter, acTopFrontCenter, acTopFrontLeft, acTopFrontRight}), \"hexadecagonal\"},\n\t{gACF({acStereoLeft, acStereoRight}), \"downmix\"}\n};\n\n//==============================================================================\n\nQString vsedit::timeToString(double a_seconds, bool a_fullFormat)\n{\n\tif(a_seconds <= 0.0)\n\t\treturn QString(\"0\");\n\n\t// Milliseconds cut-off\n\ta_seconds = std::round(a_seconds * 1000.0) / 1000.0;\n\n\t// Seconds\n\tuint64_t integer = (uint64_t)a_seconds;\n\tint seconds = integer % 60ll;\n\tinteger /= 60ll;\n\tint minutes = integer % 60ll;\n\tinteger /= 60ll;\n\tint hours = integer;\n\n\tQString timeString;\n\n\tif((hours > 0) || a_fullFormat)\n\t{\n\t\ttimeString = QString(\"%1:%2:%3\").arg(hours)\n\t\t\t.arg(minutes, 2, 10, QChar('0')).arg(seconds, 2, 10, QChar('0'));\n\t}\n\telse\n\t{\n\t\ttimeString = QString(\"%1:%2\") .arg(minutes)\n\t\t\t.arg(seconds, 2, 10, QChar('0'));\n\t}\n\n\t// Fraction\n\tdouble fraction = a_seconds - std::floor(a_seconds);\n\tif((fraction > 0.0) || a_fullFormat)\n\t\ttimeString += QString::number(fraction, 'f', 3).mid(1);\n\n\treturn timeString;\n}\n\n// END OF QString vsedit::timeToString(double a_seconds, bool a_fullFormat)\n//==============================================================================\n\nint vsedit::mod(int a_value)\n{\n\tint l_mod = 1 << 6;\n\twhile(a_value % l_mod != 0)\n\t\tl_mod >>= 1;\n\treturn l_mod;\n}\n\n// END OF int vsedit::mod(int a_value)\n//==============================================================================\n\nQString vsedit::videoInfoString(const VSVideoInfo * a_cpVideoInfo,\n\tconst VSAPI * a_cpVSAPI)\n{\n\tdouble fps = 0.0;\n\tdouble time = 0.0;\n\tif(a_cpVideoInfo->fpsDen != 0)\n\t{\n\t\tfps = (double)a_cpVideoInfo->fpsNum / (double)a_cpVideoInfo->fpsDen;\n\t\ttime = (double)a_cpVideoInfo->numFrames *\n\t\t(double)a_cpVideoInfo->fpsDen / (double)a_cpVideoInfo->fpsNum;\n\t}\n\n\tQString infoString = QString(\"Frames: %frames% | Time: %time% | Size: \"\n\t\t\"%width%x%height% | FPS: %fpsnum%/%fpsden% = %fps% | Format: %format%\");\n\tinfoString.replace(\"%frames%\", QString::number(a_cpVideoInfo->numFrames));\n\tinfoString.replace(\"%time%\", vsedit::timeToString(time, true));\n\tinfoString.replace(\"%width%\", QString::number(a_cpVideoInfo->width));\n\tinfoString.replace(\"%height%\", QString::number(a_cpVideoInfo->height));\n\tinfoString.replace(\"%fpsnum%\", QString::number(a_cpVideoInfo->fpsNum));\n\tinfoString.replace(\"%fpsden%\", QString::number(a_cpVideoInfo->fpsDen));\n\tinfoString.replace(\"%fps%\", QString::number(fps));\n\tchar formatName[32];\n\ta_cpVSAPI->getVideoFormatName(&a_cpVideoInfo->format, formatName);\n\tinfoString.replace(\"%format%\", formatName);\n\n\treturn infoString;\n}\n\n// END OF QString vsedit::videoInfoString(const VSVideoInfo * a_cpVideoInfo)\n//==============================================================================\n\nQString vsedit::audioInfoString(const VSAudioInfo * a_cpAudioInfo,\n\tconst VSAPI * a_cpVSAPI)\n{\n\tQString infoString = QString(\"Frames: %frames% | Time: %time% | \"\n\t\t\"Sample Rate: %srate% Hz | Samples: %ns% | \"\n\t\t\"Channels: %channels%| Format: %format%\");\n\tinfoString.replace(\"%frames%\", QString::number(a_cpAudioInfo->numFrames));\n\tinfoString.replace(\"%time%\", vsedit::timeToString(\n\t\tdouble(a_cpAudioInfo->numSamples) / a_cpAudioInfo->sampleRate, true));\n\tinfoString.replace(\"%srate%\", QString::number(a_cpAudioInfo->sampleRate));\n\tinfoString.replace(\"%ns%\", QString::number(a_cpAudioInfo->numSamples));\n\n\tQString channelsString(\"\");\n\tuint64_t channelLayoutFlag = a_cpAudioInfo->format.channelLayout;\n\tauto found = audioChannelToPreset.find(channelLayoutFlag);\n\tif(found != audioChannelToPreset.end())\n\t{\n\t\tchannelsString += QString(\"[%1] \")\n\t\t\t.arg(audioChannelToPreset.at(channelLayoutFlag));\n\t}\n\tfor(auto it : audioChannelToString)\n\t{\n\t\tif((static_cast<uint64_t>(1) << it.first) & channelLayoutFlag)\n\t\t{\n\t\t\tchannelsString += QString(\"%1 \").arg(it.second);\n\t\t}\n\t}\n\tinfoString.replace(\"%channels%\", channelsString);\n\n\tchar formatName[32];\n\ta_cpVSAPI->getAudioFormatName(&a_cpAudioInfo->format, formatName);\n\tinfoString.replace(\"%format%\", formatName);\n\n\treturn infoString;\n}\n\n// END OF QString vsedit::audioInfoString(const VSAudioInfo * a_cpAudioInfo,\n//\tconst VSAPI * a_cpVSAPI)\n//==============================================================================\n\nQString vsedit::nodeInfoString(const VSNodeInfo & a_nodeInfo,\n\tconst VSAPI * a_cpVSAPI)\n{\n\tif(a_nodeInfo.isInvalid())\n\t\treturn QString(\"\");\n\telse if(a_nodeInfo.isAudio())\n\t\treturn vsedit::audioInfoString(a_nodeInfo.getAsAudio(),\n\t\t\ta_cpVSAPI);\n\telse\n\t{\n\t\tQ_ASSERT(a_cpVSAPI);\n\t\treturn vsedit::videoInfoString(a_nodeInfo.getAsVideo(),\n\t\t\ta_cpVSAPI);\n\t}\n}\n\n// END OF QString vsedit::nodeInfoString(const VSNodeInfo & a_nodeInfo,\n//\tconst VSAPI * a_cpVSAPI)\n//==============================================================================\n\ndouble vsedit::qtimeToSeconds(const QTime & a_qtime)\n{\n    double seconds = (double)a_qtime.msec() / 1000.0;\n    seconds += (double)a_qtime.second();\n    seconds += (double)a_qtime.minute() * 60.0;\n    seconds += (double)a_qtime.hour() * 360.0;\n    return seconds;\n}\n\n// END OF double vsedit::qtimeToSeconds(const QTime & a_qtime)\n//==============================================================================\n\nQTime vsedit::secondsToQTime(double a_seconds)\n{\n\tQTime qtime;\n\n\tif(a_seconds <= 0.0)\n\t\treturn qtime;\n\n\t// Milliseconds cut-off\n\ta_seconds = std::round(a_seconds * 1000.0) / 1000.0;\n\n\t// Seconds\n\tuint64_t integer = (uint64_t)a_seconds;\n\tint seconds = integer % 60ll;\n\tinteger /= 60ll;\n\tint minutes = integer % 60ll;\n\tinteger /= 60ll;\n\tint hours = integer % 60ll;\n\n\tint milliseconds = (int)(((a_seconds - std::round(a_seconds)) * 1000.0));\n\n\tqtime.setHMS(hours, minutes, seconds, milliseconds);\n\treturn qtime;\n}\n\n// END OF QTime vsedit::secondsToQTime(double a_seconds)\n//==============================================================================\n\nvoid vsedit::wait(int a_msec)\n{\n\tif(a_msec <= 0)\n\t\treturn;\n\n\tQTime mark = QTime::currentTime().addMSecs(a_msec);\n    while(QTime::currentTime() < mark)\n        QCoreApplication::processEvents(QEventLoop::AllEvents, 100);\n}\n\n// END OF void vsedit::wait(int a_msec)\n//==============================================================================\n\nQString vsedit::subsamplingString(int a_subsamplingW, int a_subsamplingH)\n{\n\tif((a_subsamplingW == 0) && (a_subsamplingH == 0))\n\t\treturn QString(\"444\");\n\n\tif((a_subsamplingW == 0) && (a_subsamplingH == 1))\n\t\treturn QString(\"440\");\n\n\tif((a_subsamplingW == 1) && (a_subsamplingH == 0))\n\t\treturn QString(\"422\");\n\n\tif((a_subsamplingW == 1) && (a_subsamplingH == 1))\n\t\treturn QString(\"420\");\n\n\tif((a_subsamplingW == 2) && (a_subsamplingH == 0))\n\t\treturn QString(\"411\");\n\n\tif((a_subsamplingW == 2) && (a_subsamplingH == 2))\n\t\treturn QString(\"410\");\n\n\treturn QString();\n}\n\n// END OF QString vsedit::subsamplingString(int a_subsamplingW,\n//\t\tint a_subsamplingH)\n//==============================================================================\n\nQString vsedit::subsamplingString(const VSVideoFormat * a_cpFormat)\n{\n\tif(!a_cpFormat)\n\t\treturn QString();\n\n\treturn subsamplingString(a_cpFormat->subSamplingW,\n\t\ta_cpFormat->subSamplingH);\n}\n\n// END OF QString vsedit::subsamplingString(const VSVideoFormat * a_cpFormat)\n//==============================================================================\n\nQString vsedit::resolvePathFromApplication(const QString & a_relativePath)\n{\n\t// Remember the working directory and change it to application directory.\n\tQString cwd = QDir::currentPath();\n\tQString applicationDirPath = QCoreApplication::applicationDirPath();\n\tQDir::setCurrent(applicationDirPath);\n\n\tQFileInfo fileInfo(a_relativePath);\n\t// If no parent directory is specified - leave the path as it is.\n\tif(fileInfo.path() == \".\")\n\t\treturn(a_relativePath);\n\tQString absolutePath = fileInfo.absoluteFilePath();\n\n\t// Restore the working directory.\n\tQDir::setCurrent(cwd);\n\n\treturn absolutePath;\n}\n\n// END OF QString vsedit::resolvePathFromApplication(\n//\t\tconst QString & a_relativePath)\n//==============================================================================\n\nQByteArray vsedit::jsonMessage(const QString & a_command,\n\tconst QJsonObject & a_jsonObject)\n{\n\treturn vsedit::jsonMessage(a_command, QJsonDocument(a_jsonObject));\n}\n\n// END OF QByteArray vsedit::jsonMessage(const QString & a_command,\n//\t\tconst QJsonObject & a_jsonObject)\n//==============================================================================\n\nQByteArray vsedit::jsonMessage(const QString & a_command,\n\tconst QJsonArray & a_jsonArray)\n{\n\treturn vsedit::jsonMessage(a_command, QJsonDocument(a_jsonArray));\n}\n\n// END OF QByteArray vsedit::jsonMessage(const QString & a_command,\n//\t\tconst QJsonArray & a_jsonArray)\n//==============================================================================\n\nQByteArray vsedit::jsonMessage(const QString & a_command,\n\tconst QJsonDocument & a_jsonDocument)\n{\n\treturn a_command.toUtf8() + ' ' + a_jsonDocument.toJson();\n}\n\n// END OF QByteArray vsedit::jsonMessage(const QString & a_command,\n//\t\tconst QJsonDocument & a_jsonDocument)\n//==============================================================================\n\nvsedit::FP32 vsedit::halfToSingle(vsedit::FP16 a_half)\n{\n\tFP32 o = { 0 };\n\n\t// From ISPC ref code\n\tif (a_half.parts.Exponent == 0 && a_half.parts.Mantissa == 0)\n\t\t// (Signed) zero\n\t\to.parts.Sign = a_half.parts.Sign;\n\telse\n\t{\n\t\tif (a_half.parts.Exponent == 0) // Denormal (will convert to normalized)\n\t\t{\n\t\t\t// Adjust mantissa so it's normalized (and keep track of exp adjust)\n\t\t\tint e = -1;\n\t\t\tunsigned int m = a_half.parts.Mantissa;\n\t\t\tdo\n\t\t\t{\n\t\t\t\te++;\n\t\t\t\tm <<= 1;\n\t\t\t} while ((m & 0x400) == 0);\n\n\t\t\to.parts.Mantissa = (m & 0x3ff) << 13;\n\t\t\to.parts.Exponent = 127 - 15 - e;\n\t\t\to.parts.Sign = a_half.parts.Sign;\n\t\t}\n\t\telse if (a_half.parts.Exponent == 0x1f) // Inf/NaN\n\t\t{\n\t\t\t// NOTE: It's safe to treat both with the same code path\n\t\t\t// by just truncating lower Mantissa bits in NaNs (this is valid).\n\t\t\to.parts.Mantissa = a_half.parts.Mantissa << 13;\n\t\t\to.parts.Exponent = 255;\n\t\t\to.parts.Sign = a_half.parts.Sign;\n\t\t}\n\t\telse // Normalized number\n\t\t{\n\t\t\to.parts.Mantissa = a_half.parts.Mantissa << 13;\n\t\t\to.parts.Exponent = 127 - 15 + a_half.parts.Exponent;\n\t\t\to.parts.Sign = a_half.parts.Sign;\n\t\t}\n\t}\n\n\treturn o;\n}\n\n// END OF vsedit::FP32 vsedit::halfToSingle(vsedit::FP16 a_half)\n//==============================================================================\n"
  },
  {
    "path": "common-src/helpers.h",
    "content": "#ifndef HELPERS_H_INCLUDED\n#define HELPERS_H_INCLUDED\n\n#include <VapourSynth4.h>\n\n#include \"helpers_vs.h\"\n\n#include <QString>\n#include <QTime>\n#include <QJsonObject>\n#include <QJsonArray>\n#include <QJsonDocument>\n#include <QByteArray>\n#include <QDataStream>\n#include <QIODevice>\n#include <QFont>\n#include <algorithm>\n#include <functional>\n\nnamespace vsedit\n{\nstruct VariableToken\n{\n\tQString token;\n\tQString description;\n\tstd::function<QString()> evaluate;\n};\n\nQString timeToString(double a_seconds, bool a_fullFormat = false);\n\nint mod(int a_value);\n\nQString videoInfoString(const VSVideoInfo * a_cpVideoInfo,\n\tconst VSAPI * a_cpVSAPI);\n\nQString audioInfoString(const VSAudioInfo * a_cpAudioInfo,\n\tconst VSAPI * a_cpVSAPI);\n\nQString nodeInfoString(const VSNodeInfo &a_nodeInfo,\n\tconst VSAPI * a_cpVSAPI);\n\ndouble qtimeToSeconds(const QTime & a_qtime);\n\nQTime secondsToQTime(double a_seconds);\n\nvoid wait(int a_msec);\n\nQString subsamplingString(int a_subsamplingW, int a_subsamplingH);\n\nQString subsamplingString(const VSVideoFormat * a_cpFormat);\n\nQString resolvePathFromApplication(const QString & a_relativePath);\n\nQByteArray jsonMessage(const QString & a_command,\n\tconst QJsonObject & a_jsonObject);\nQByteArray jsonMessage(const QString & a_command,\n\tconst QJsonArray & a_jsonArray);\nQByteArray jsonMessage(const QString & a_command,\n\tconst QJsonDocument & a_jsonDocument);\n\ntemplate<typename T1, typename T2, typename T3>\n\tvoid clamp(T1& a_value, const T2& a_low, const T3& a_high)\n{\n\tQ_ASSERT(a_high > a_low);\n\tif(a_value < a_low)\n\t\ta_value = a_low;\n\telse if(a_value > a_high)\n\t\ta_value = a_high;\n}\n\ntemplate<typename Container_T, typename Value_T>\n\tbool contains(const Container_T & a_container, const Value_T & a_value)\n{\n\treturn (std::find(std::begin(a_container), std::end(a_container),\n\t\ta_value) != std::end(a_container));\n}\n\ntemplate<typename T>\n\tT roundUp(T a_number, T a_multiple)\n{\n\tif(a_multiple == 0)\n\t\treturn a_number;\n\n\tT remainder = a_number % a_multiple;\n\tif(remainder == 0)\n\t\treturn a_number;\n\n\treturn a_number + a_multiple - remainder;\n}\n\ntemplate<typename T>\n\tQByteArray toByteArray(const T & a_data)\n{\n\tQByteArray buf;\n\tQDataStream stream(&buf, QIODevice::WriteOnly);\n\tstream << a_data;\n\treturn buf;\n}\n\ntemplate<typename T>\n\tT fromByteArray(const QByteArray & a_array)\n{\n\tQDataStream stream(a_array);\n\tT data;\n\tstream >> data;\n\treturn data;\n}\n\n//------------------------------------------------------------------------------\n// Half to single precision float conversion\n// by Fabian \"ryg\" Giesen.\n\nunion FP32\n{\n\tuint32_t u;\n\tfloat f;\n\tstruct\n\t{\n\t\tunsigned int Mantissa : 23;\n\t\tunsigned int Exponent : 8;\n\t\tunsigned int Sign : 1;\n\t} parts;\n};\n\nunion FP16\n{\n\tuint16_t u;\n\tstruct\n\t{\n\t\tunsigned int Mantissa : 10;\n\t\tunsigned int Exponent : 5;\n\t\tunsigned int Sign : 1;\n\t} parts;\n};\n\nFP32 halfToSingle(FP16 a_half);\n\n/* This is a patch for Qt 6 in Windows */\ntemplate<typename T>\nvoid disableFontKerning(T * a_pWidget)\n{\n\tQFont font(a_pWidget->font());\n\tfont.setKerning(false);\n\ta_pWidget->setFont(font);\n}\n\n//------------------------------------------------------------------------------\n\n}\n\n#endif // HELPERS_H_INCLUDED\n"
  },
  {
    "path": "common-src/helpers_vs.h",
    "content": "#ifndef HELPERS_VS_H_INCLUDED\n#define HELPERS_VS_H_INCLUDED\n\n#include <VapourSynth4.h>\n#include <VSHelper4.h>\n\n#include <utility>\n\nenum class ProcessReason\n{\n\tPreview,\n\tCheck,\n\tBenchmark,\n\tEncode,\n};\n\ntemplate <typename TV, typename TA>\nclass VSMediaTypePicker\n{\nprotected:\n\tconst TV * m_pTV;\n\tconst TA * m_pTA;\n\tint m_mediaType;\n\npublic:\n\tVSMediaTypePicker()\n\t\t: m_pTV(nullptr)\n\t\t, m_pTA(nullptr)\n\t\t, m_mediaType(-1)\n\t{}\n\n\tVSMediaTypePicker(const TV * a_pTV) : VSMediaTypePicker()\n\t{\n\t\tif(a_pTV)\n\t\t{\n\t\t\tm_pTV = a_pTV;\n\t\t\tm_mediaType = mtVideo;\n\t\t}\n\t}\n\n\tVSMediaTypePicker(const TA * a_pTA) : VSMediaTypePicker()\n\t{\n\t\tif(a_pTA)\n\t\t{\n\t\t\tm_pTA = a_pTA;\n\t\t\tm_mediaType = mtAudio;\n\t\t}\n\t}\n\n\tconst void * get() const\n\t{\n\t\tswitch (m_mediaType)\n\t\t{\n\t\tcase mtAudio:\n\t\t\treturn reinterpret_cast<const void *>(m_pTA);\n\t\tcase mtVideo:\n\t\t\treturn reinterpret_cast<const void *>(m_pTV);\n\t\tdefault:\n\t\t\treturn nullptr;\n\t\t}\n\t}\n\n\tconst TV * getAsVideo() const\n\t{\n\t\treturn m_pTV;\n\t}\n\n\tconst TA * getAsAudio() const\n\t{\n\t\treturn m_pTA;\n\t}\n\n\tvoid set(const TV * a_pTV)\n\t{\n\t\tm_pTV = a_pTV;\n\t\tm_pTA = nullptr;\n\t\tm_mediaType = a_pTV ? mtVideo : -1;\n\t}\n\n\tvoid set(const TA * a_pTA)\n\t{\n\t\tm_pTV = nullptr;\n\t\tm_pTA = a_pTA;\n\t\tm_mediaType = a_pTA ? mtAudio : -1;\n\t}\n\n\tvoid setNull()\n\t{\n\t\tm_pTV = nullptr;\n\t\tm_pTA = nullptr;\n\t\tm_mediaType = -1;\n\t}\n\n\tbool isAudio() const\n\t{\n\t\treturn m_mediaType == mtAudio;\n\t}\n\n\tbool isVideo() const\n\t{\n\t\treturn m_mediaType == mtVideo;\n\t}\n\n\tbool isInvalid() const\n\t{\n\t\treturn (!isVideo()) && (!isAudio());\n\t}\n\n\tint mediaType() const\n\t{\n\t\treturn m_mediaType;\n\t}\n};\n\nclass VSNodeInfo : public VSMediaTypePicker<VSVideoInfo, VSAudioInfo>\n{\npublic:\n\tVSNodeInfo() : VSMediaTypePicker<VSVideoInfo, VSAudioInfo>() {}\n\n\tVSNodeInfo(VSNode * a_pNode, const VSAPI * a_cpVSAPI)\n\t{\n\t\tint mediaType = a_cpVSAPI->getNodeType(a_pNode);\n\t\tif(mediaType == mtAudio)\n\t\t\tset(a_cpVSAPI->getAudioInfo(a_pNode));\n\t\telse\n\t\t\tset(a_cpVSAPI->getVideoInfo(a_pNode));\n\t}\n\n\tint numFrames() const\n\t{\n\t\tswitch (m_mediaType)\n\t\t{\n\t\tcase mtAudio:\n\t\t\treturn m_pTA->numFrames;\n\t\tcase mtVideo:\n\t\t\treturn m_pTV->numFrames;\n\t\tdefault:\n\t\t\treturn -1;\n\t\t}\n\t}\n\n\tstd::pair<int64_t, int64_t> fpsPair() const\n\t{\n\t\tif (m_mediaType == mtAudio)\n\t\t{\n\t\t\tstd::pair<int64_t, int64_t> res = {m_pTA->sampleRate, VS_AUDIO_FRAME_SAMPLES};\n\t\t\tvsh::reduceRational(&res.first, &res.second);\n\t\t\treturn res;\n\t\t}\n\t\telse if (m_mediaType == mtVideo)\n\t\t\treturn {m_pTV->fpsNum, m_pTV->fpsDen};\n\t\telse\n\t\t\treturn {0, 0};\n\t}\n\n};\n\nclass VSFrameFormat : public VSMediaTypePicker<VSVideoFormat, VSAudioFormat>\n{\npublic:\n\tVSFrameFormat() : VSMediaTypePicker<VSVideoFormat, VSAudioFormat>() {}\n\n\tVSFrameFormat(const VSFrame * a_cpFrame, const VSAPI * a_cpVSAPI)\n\t{\n\t\tint mediaType = a_cpVSAPI->getFrameType(a_cpFrame);\n\t\tif(mediaType == mtAudio)\n\t\t\tset(a_cpVSAPI->getAudioFrameFormat(a_cpFrame));\n\t\telse\n\t\t\tset(a_cpVSAPI->getVideoFrameFormat(a_cpFrame));\n\t}\n};\n\ninline bool isVariableSize(const VSVideoInfo *vi)\n{\n\treturn vi->width == 0 && vi->height == 0;\n}\n\ninline bool isVariableFPS(const VSVideoInfo *vi)\n{\n\treturn vi->fpsDen == 0 && vi->fpsNum == 0;\n}\n\ninline bool isVariableFormat(const VSVideoInfo *vi)\n{\n\treturn vi->format.colorFamily == cfUndefined ||\n\t\tvi->format.bitsPerSample == 0 ||\n\t\tvi->format.bytesPerSample == 0 ||\n\t\tvi->format.numPlanes == 0;\n}\n\n#endif\n"
  },
  {
    "path": "common-src/ipc_defines.h",
    "content": "#ifndef IPC_DEFINES_H_INCLUDED\n#define IPC_DEFINES_H_INCLUDED\n\n// Watcher <-> Job server communication\n\nstatic const char JOB_SERVER_NAME[] = \"vsedit_job_server\";\nstatic const uint16_t JOB_SERVER_PORT = 3370;\n\n// Client messages\nstatic const char MSG_GET_JOBS_INFO[] = \"GJI\";\nstatic const char MSG_GET_LOG[] = \"GL\";\nstatic const char MSG_SUBSCRIBE[] = \"SS\";\nstatic const char MSG_UNSUBSCRIBE[] = \"USS\";\nstatic const char MSG_CLOSE_SERVER[] = \"CS\";\nstatic const char MSG_GET_TRUSTED_CLIENTS[] = \"GTC\";\nstatic const char MSG_SET_TRUSTED_CLIENTS[] = \"STC\";\n\nstatic const char MSG_CREATE_JOB[] = \"CJ\";\nstatic const char MSG_CHANGE_JOB[] = \"CHJ\";\nstatic const char MSG_SET_JOB_DEPENDENCIES[] = \"SJD\";\nstatic const char MSG_SWAP_JOBS[] = \"SJ\";\nstatic const char MSG_RESET_JOBS[] = \"RJ\";\nstatic const char MSG_DELETE_JOBS[] = \"DJ\";\n\nstatic const char MSG_START_ALL_WAITING_JOBS[] = \"SAWJ\";\nstatic const char MSG_PAUSE_ACTIVE_JOBS[] = \"PACJ\";\nstatic const char MSG_RESUME_PAUSED_JOBS[] = \"RPJ\";\nstatic const char MSG_ABORT_ACTIVE_JOBS[] = \"AACJ\";\n\n// Server messages\nstatic const char SMSG_JOBS_INFO[] = \"JI\";\nstatic const char SMSG_COMPLETE_LOG[] = \"LOG\";\nstatic const char SMSG_LOG_MESSAGE[] = \"LM\";\nstatic const char SMSG_JOB_CREATED[] = \"JC\";\nstatic const char SMSG_JOB_UPDATE[] = \"JU\";\nstatic const char SMSG_JOB_STATE_UPDATE[] = \"JSU\";\nstatic const char SMSG_JOB_PROGRESS_UPDATE[] = \"JPU\";\nstatic const char SMSG_JOB_START_TIME_UPDATE[] = \"JSTU\";\nstatic const char SMSG_JOB_END_TIME_UPDATE[] = \"JETU\";\nstatic const char SMSG_JOB_DEPENDENCIES_UPDATE[] = \"JDU\";\nstatic const char SMSG_JOBS_SWAPPED[] = \"JSW\";\nstatic const char SMSG_JOBS_DELETED[] = \"JD\";\nstatic const char SMSG_REFUSE[] = \"RF\";\nstatic const char SMSG_CLOSING_SERVER[] = \"SCS\";\nstatic const char SMSG_TRUSTED_CLIENTS_INFO[] = \"TCI\";\n\n// Editor <-> Watcher communication\n\nstatic const char JOB_SERVER_WATCHER_LOCAL_SERVER_NAME[] =\n\t\"vsedit_job_server_watcher\";\n\nstatic const char WMSG_SHOW_WINDOW[] = \"S\";\nstatic const char WMSG_CLI_ENCODE_JOB[] = \"CEJ\";\n\n#endif // IPC_DEFINES_H_INCLUDED\n"
  },
  {
    "path": "common-src/jobs/job.cpp",
    "content": "#include \"job.h\"\n\n#include \"../../../common-src/helpers.h\"\n#include \"../../../common-src/settings/settings_manager_core.h\"\n#include \"../../../common-src/vapoursynth/vs_script_library.h\"\n#include \"../../../common-src/vapoursynth/vapoursynth_script_processor.h\"\n#include \"../frame_header_writers/frame_header_writer_null.h\"\n#include \"../frame_header_writers/frame_header_writer_y4m.h\"\n#include \"../../../common-src/jobs/job_variables.h\"\n\n#include <QFileInfo>\n#include <QFile>\n#include <algorithm>\n#include <VSHelper4.h>\n\n#ifdef Q_OS_WIN\n\t#ifndef NOMINMAX\n\t\t#define NOMINMAX\n\t#endif\n\t#include <windows.h>\n#else\n\t#include <signal.h>\n#endif\n\n//==============================================================================\n\nvsedit::Job::Job(const JobProperties & a_properties,\n\tSettingsManagerCore * a_pSettingsManager,\n\tVSScriptLibrary * a_pVSScriptLibrary,\n\tQObject * a_pParent) :\n\t  QObject(a_pParent)\n\t, JobVariables()\n\t, m_properties(a_properties)\n\t, m_lastFrameProcessed(-1)\n\t, m_lastFrameRequested(-1)\n\t, m_encodingState(EncodingState::Idle)\n\t, m_bytesToWrite(0u)\n\t, m_bytesWritten(0u)\n\t, m_pSettingsManager(a_pSettingsManager)\n\t, m_pVSScriptLibrary(a_pVSScriptLibrary)\n\t, m_pVapourSynthScriptProcessor(nullptr)\n\t, m_cpVSAPI(nullptr)\n\t, m_cpVideoInfo(nullptr)\n\t, m_pFrameHeaderWriter(nullptr)\n\t, m_cachedFramesLimit(100)\n\t, m_framesInQueue(0)\n\t, m_framesInProcess(0)\n\t, m_maxThreads(0)\n\t, m_memorizedEncodingTime(0.0)\n{\n\tfillVariables();\n\tif(a_pVSScriptLibrary)\n\t\tm_cpVSAPI = m_pVSScriptLibrary->getVSAPI();\n\n\tconnect(&m_process, SIGNAL(started()),\n\t\tthis, SLOT(slotProcessStarted()));\n\tconnect(&m_process, SIGNAL(finished(int, QProcess::ExitStatus)),\n\t\tthis, SLOT(slotProcessFinished(int, QProcess::ExitStatus)));\n\tconnect(&m_process, SIGNAL(errorOccurred(QProcess::ProcessError)),\n\t\tthis, SLOT(slotProcessError(QProcess::ProcessError)));\n\tconnect(&m_process, SIGNAL(readChannelFinished()),\n\t\tthis, SLOT(slotProcessReadChannelFinished()));\n\tconnect(&m_process, SIGNAL(bytesWritten(qint64)),\n\t\tthis, SLOT(slotProcessBytesWritten(qint64)));\n\tconnect(&m_process, SIGNAL(readyReadStandardError()),\n\t\tthis, SLOT(slotProcessReadyReadStandardError()));\n}\n\n// END OF vsedit::Job::Job(const JobProperties & a_properties,\n//\t\tSettingsManagerCore * a_pSettingsManager,\n//\t\tVSScriptLibrary * a_pVSScriptLibrary, QObject * a_pParent)\n//==============================================================================\n\nvsedit::Job::~Job()\n{\n}\n\n// END OF vsedit::Job::~Job()\n//==============================================================================\n\nbool vsedit::Job::isActive() const\n{\n\treturn vsedit::contains(ACTIVE_JOB_STATES, m_properties.jobState);\n}\n\n// END OF bool vsedit::Job::isActive() const\n//==============================================================================\n\nQUuid vsedit::Job::id() const\n{\n\treturn m_properties.id;\n}\n\n// END OF QUuid vsedit::Job::id() const\n//==============================================================================\n\nbool vsedit::Job::setId(const QUuid & a_id)\n{\n\tif(isActive())\n\t\treturn false;\n\tm_properties.id = a_id;\n\treturn true;\n}\n\n// END OF bool vsedit::Job::setId(const QUuid & a_id)\n//==============================================================================\n\nJobType vsedit::Job::type() const\n{\n\treturn m_properties.type;\n}\n\n// END OF JobType vsedit::Job::type() const\n//==============================================================================\n\nbool vsedit::Job::setType(JobType a_type)\n{\n\tif(isActive())\n\t\treturn false;\n\tm_properties.type = a_type;\n\treturn true;\n}\n\n// END OF bool vsedit::Job::setType(JobType a_type)\n//==============================================================================\n\nQString vsedit::Job::scriptName() const\n{\n\treturn m_properties.scriptName;\n}\n\n// END OF QString vsedit::Job::scriptName() const\n//==============================================================================\n\nbool vsedit::Job::setScriptName(const QString & a_scriptName)\n{\n\tif(isActive())\n\t\treturn false;\n\tm_properties.scriptName = a_scriptName;\n\treturn true;\n}\n\n// END OF bool vsedit::Job::setScriptName(const QString & a_scriptName)\n//==============================================================================\n\nQString vsedit::Job::scriptText() const\n{\n\treturn m_properties.scriptText;\n}\n\n// END OF QString vsedit::Job::scriptText() const\n//==============================================================================\n\nbool vsedit::Job::setScriptText(const QString & a_scriptText)\n{\n\tif(isActive())\n\t\treturn false;\n\tm_properties.scriptText = a_scriptText;\n\treturn true;\n}\n\n// END OF bool vsedit::Job::setScriptName(const QString & a_scriptText)\n//==============================================================================\n\nEncodingHeaderType vsedit::Job::encodingHeaderType() const\n{\n\treturn m_properties.encodingHeaderType;\n}\n\n// END OF EncodingHeaderType vsedit::Job::encodingHeaderType() const\n//==============================================================================\n\nbool vsedit::Job::setEncodingHeaderType(EncodingHeaderType a_headerType)\n{\n\tm_properties.encodingHeaderType = a_headerType;\n\treturn true;\n}\n\n// END OF bool vsedit::Job::setEncodingHeaderType(\n//\t\tEncodingHeaderType a_headerType)\n//==============================================================================\n\nQString vsedit::Job::executablePath() const\n{\n\treturn m_properties.executablePath;\n}\n\n// END OF QString vsedit::Job::executablePath() const\n//==============================================================================\n\nbool vsedit::Job::setExecutablePath(const QString & a_path)\n{\n\tm_properties.executablePath = a_path;\n\treturn true;\n}\n\n// END OF bool vsedit::Job::setExecutablePath(const QString & a_path)\n//==============================================================================\n\nQString vsedit::Job::arguments() const\n{\n\treturn m_properties.arguments;\n}\n\n// END OF QString vsedit::Job::arguments() const\n//==============================================================================\n\nbool vsedit::Job::setArguments(const QString & a_arguments)\n{\n\tif(isActive())\n\t\treturn false;\n\tm_properties.arguments = a_arguments;\n\treturn true;\n}\n\n// END OF bool vsedit::Job::setArguments(const QString & a_arguments)\n//==============================================================================\n\nQString vsedit::Job::shellCommand() const\n{\n\treturn m_properties.shellCommand;\n}\n\n// END OF QString vsedit::Job::shellCommand() const\n//==============================================================================\n\nbool vsedit::Job::setShellCommand(const QString & a_command)\n{\n\tif(isActive())\n\t\treturn false;\n\tm_properties.shellCommand = a_command;\n\treturn true;\n}\n\n// END OF bool vsedit::Job::setShellCommand(const QString & a_command)\n//==============================================================================\n\nJobState vsedit::Job::state() const\n{\n\treturn m_properties.jobState;\n}\n\n// END OF JobState vsedit::Job::state() const\n//==============================================================================\n\nbool vsedit::Job::setState(JobState a_state)\n{\n\tif(isActive())\n\t\treturn false;\n\tchangeStateAndNotify(a_state);\n\treturn true;\n}\n\n// END OF bool vsedit::Job::setState(JobState a_state)\n//==============================================================================\n\nstd::vector<QUuid> vsedit::Job::dependsOnJobIds() const\n{\n\treturn m_properties.dependsOnJobIds;\n}\n\n// END OF std::vector<QUuid> vsedit::Job::dependsOnJobIds() const\n//==============================================================================\n\nbool vsedit::Job::setDependsOnJobIds(const std::vector<QUuid> & a_ids)\n{\n\tif(isActive())\n\t\treturn false;\n\tm_properties.dependsOnJobIds = a_ids;\n\treturn true;\n}\n\n// END OF bool vsedit::Job::setDependsOnJobIds(const std::vector<QUuid> & a_ids)\n//==============================================================================\n\nQString vsedit::Job::subject() const\n{\n\tQString subjectString;\n\n\tif(m_properties.type == JobType::EncodeScriptCLI)\n\t{\n\t\tsubjectString = QString(\"%sn%:\\n\\\"%ep%\\\" %arg%\");\n\t\tsubjectString = subjectString.replace(\"%sn%\",\n\t\t\tresolvePathFromApplication(m_properties.scriptName));\n\t\tsubjectString = subjectString.replace(\"%ep%\",\n\t\t\tresolvePathFromApplication(m_properties.executablePath));\n\t\tsubjectString = subjectString.replace(\"%arg%\",\n\t\t\tdecodeArguments(m_properties.arguments));\n\t}\n\telse if(m_properties.type == JobType::RunProcess)\n\t{\n\t\tsubjectString = QString(\"\\\"%ep%\\\" %arg%\");\n\t\tsubjectString = subjectString.replace(\"%ep%\",\n\t\t\tresolvePathFromApplication(m_properties.executablePath));\n\t\tsubjectString = subjectString.replace(\"%arg%\",\n\t\t\tm_properties.arguments.simplified());\n\t}\n\telse if(m_properties.type == JobType::RunShellCommand)\n\t\tsubjectString = m_properties.shellCommand.simplified();\n\n\treturn subjectString;\n}\n\n// END OF QString vsedit::Job::subject() const\n//==============================================================================\n\nint vsedit::Job::firstFrame() const\n{\n\tif(m_properties.type != JobType::EncodeScriptCLI)\n\t\treturn -1;\n\n\tif(m_properties.firstFrameReal >= 0)\n\t\treturn m_properties.firstFrameReal;\n\n\treturn m_properties.firstFrame;\n}\n\n// END OF int vsedit::Job::firstFrame() const\n//==============================================================================\n\nbool vsedit::Job::setFirstFrame(int a_frame)\n{\n\tif(isActive())\n\t\treturn false;\n\n\tif(m_properties.type != JobType::EncodeScriptCLI)\n\t\treturn false;\n\n\tif(a_frame < 0)\n\t\treturn false;\n\n\tm_properties.firstFrame = a_frame;\n\tif(m_pVapourSynthScriptProcessor->isInitialized())\n\t{\n\t\tQ_ASSERT(m_cpVideoInfo);\n\t\tm_properties.firstFrameReal = std::min(m_properties.firstFrame,\n\t\t\tm_cpVideoInfo->numFrames - 1);\n\t}\n\telse\n\t\tm_properties.firstFrameReal = -1;\n\n\treturn true;\n}\n\n// END OF bool vsedit::Job::setFirstFrame(int a_frame)\n//==============================================================================\n\nint vsedit::Job::lastFrame() const\n{\n\tif(m_properties.type != JobType::EncodeScriptCLI)\n\t\treturn -1;\n\n\tif(m_properties.lastFrameReal >= 0)\n\t\treturn m_properties.lastFrameReal;\n\n\treturn m_properties.lastFrame;\n}\n\n// END OF int vsedit::Job::lastFrame() const\n//==============================================================================\n\nbool vsedit::Job::setLastFrame(int a_frame)\n{\n\tif(isActive())\n\t\treturn false;\n\n\tif(m_properties.type != JobType::EncodeScriptCLI)\n\t\treturn false;\n\n\tif(a_frame < 0)\n\t\treturn false;\n\n\tm_properties.lastFrame = a_frame;\n\tif(m_pVapourSynthScriptProcessor->isInitialized())\n\t{\n\t\tQ_ASSERT(m_cpVideoInfo);\n\t\tm_properties.lastFrameReal = std::min(m_properties.lastFrame,\n\t\t\tm_cpVideoInfo->numFrames - 1);\n\t}\n\telse\n\t\tm_properties.lastFrameReal = -1;\n\n\treturn true;\n}\n\n// END OF bool vsedit::Job::setFirstFrame(int a_frame)\n//==============================================================================\n\nint vsedit::Job::framesProcessed() const\n{\n\tif(m_properties.type == JobType::EncodeScriptCLI)\n\t\treturn m_properties.framesProcessed;\n\treturn 0;\n}\n\n// END OF int vsedit::Job::framesProcessed() const\n//==============================================================================\n\nint vsedit::Job::framesTotal() const\n{\n\tif(m_properties.type == JobType::EncodeScriptCLI)\n\t\treturn (m_properties.lastFrameReal - m_properties.firstFrameReal + 1);\n\treturn 0;\n}\n\n// END OF int vsedit::Job::framesTotal() const\n//==============================================================================\n\ndouble vsedit::Job::fps() const\n{\n\treturn m_properties.fps;\n}\n\n// END OF double vsedit::Job::fps() const\n//==============================================================================\n\ndouble vsedit::Job::secondsToFinish() const\n{\n\tint framesLeft = framesTotal() - framesProcessed();\n\tdouble seconds = (double)framesLeft / m_properties.fps;\n\treturn seconds;\n}\n\n// END OF double vsedit::Job::secondsToFinish() const\n//==============================================================================\n\nsize_t vsedit::Job::framesInQueue() const\n{\n\treturn m_framesInQueue;\n}\n\n// END OF size_t vsedit::Job::framesInQueue() const\n//==============================================================================\n\nsize_t vsedit::Job::framesInProcess() const\n{\n\treturn m_framesInProcess;\n}\n\n// END OF size_t vsedit::Job::framesInProcess() const\n//==============================================================================\n\nsize_t vsedit::Job::maxThreads() const\n{\n\treturn m_maxThreads;\n}\n\n// END OF size_t vsedit::Job::maxThreads() const\n//==============================================================================\n\nJobProperties vsedit::Job::properties() const\n{\n\treturn m_properties;\n}\n\n// END OF JobProperties vsedit::Job::properties() const\n//==============================================================================\n\nbool vsedit::Job::setProperties(const JobProperties & a_properties)\n{\n\tif(isActive())\n\t\treturn false;\n\tm_properties = a_properties;\n\treturn true;\n}\n\n// END OF bool vsedit::Job::setProperties(const JobProperties & a_properties)\n//==============================================================================\n\nconst VSVideoInfo * vsedit::Job::videoInfo() const\n{\n\tif(m_properties.type != JobType::EncodeScriptCLI)\n\t\treturn nullptr;\n\tif(!m_pVapourSynthScriptProcessor)\n\t\treturn nullptr;\n\treturn m_pVapourSynthScriptProcessor->nodeInfo().getAsVideo();\n}\n\n// END OF const VSVideoInfo * vsedit::Job::videoInfo() const\n//==============================================================================\n\nbool vsedit::Job::initialize()\n{\n\tif(m_properties.type != JobType::EncodeScriptCLI)\n\t\treturn false;\n\n\tif(isActive() && (m_encodingState != EncodingState::Idle))\n\t{\n\t\temit signalLogMessage(tr(\"Can not initialize an active job\"),\n\t\t\tLOG_STYLE_ERROR);\n\t\treturn false;\n\t}\n\n\tif(m_properties.scriptText.isEmpty())\n\t{\n\t\tQString absoluteScriptPath =\n\t\t\tresolvePathFromApplication(m_properties.scriptName);\n\t\tQFile scriptFile(absoluteScriptPath);\n\t\tbool opened = scriptFile.open(QIODevice::ReadOnly);\n\t\tif(!opened)\n\t\t{\n\t\t\temit signalLogMessage(tr(\"Could not open script file \\\"%1\\\".\")\n\t\t\t\t.arg(m_properties.scriptName), LOG_STYLE_ERROR);\n\t\t\tchangeStateAndNotify(JobState::Failed);\n\t\t\treturn false;\n\t\t}\n\n\t\tm_properties.scriptText = QString::fromUtf8(scriptFile.readAll());\n\t\tscriptFile.close();\n\t}\n\n\tif((!m_pVSScriptLibrary) || (!m_pSettingsManager))\n\t{\n\t\temit signalLogMessage(tr(\"Job is not created properly.\"),\n\t\t\tLOG_STYLE_ERROR);\n\t\tchangeStateAndNotify(JobState::Failed);\n\t\treturn false;\n\t}\n\n\tm_cpVSAPI = m_pVSScriptLibrary->getVSAPI();\n\tQ_ASSERT(m_cpVSAPI);\n\n\tif(!m_pVapourSynthScriptProcessor)\n\t{\n\t\tm_pVapourSynthScriptProcessor = new VapourSynthScriptProcessor(\n\t\t\tm_pSettingsManager, m_pVSScriptLibrary, this);\n\t\tconnect(m_pVapourSynthScriptProcessor,\n\t\t\tSIGNAL(signalWriteLogMessage(int, const QString &)),\n\t\t\tthis, SLOT(slotWriteLogMessage(int, const QString &)));\n\t\tconnect(m_pVapourSynthScriptProcessor,\n\t\t\tSIGNAL(signalFrameQueueStateChanged(size_t, size_t, size_t, double)),\n\t\t\tthis, SLOT(slotFrameQueueStateChanged(size_t, size_t, size_t, double)));\n\t\tconnect(m_pVapourSynthScriptProcessor, SIGNAL(signalFinalized()),\n\t\t\tthis, SLOT(slotScriptProcessorFinalized()));\n\t\tconnect(m_pVapourSynthScriptProcessor,\n\t\t\tSIGNAL(signalDistributeFrame(int, int, const VSFrame *,\n\t\t\t\tconst VSFrame *)),\n\t\t\tthis, SLOT(slotReceiveFrame(int, int, const VSFrame *,\n\t\t\t\tconst VSFrame *)));\n\t\tconnect(m_pVapourSynthScriptProcessor,\n\t\t\tSIGNAL(signalFrameRequestDiscarded(int, int, const QString &)),\n\t\t\tthis, SLOT(slotFrameRequestDiscarded(int, int, const QString &)));\n\t\tconnect(m_pVapourSynthScriptProcessor,\n\t\t\tSIGNAL(signalFrameQueueStateChanged(size_t, size_t, size_t, double)),\n\t\t\tthis, SLOT(slotFrameQueueStateChanged(size_t, size_t, size_t, double)));\n\t}\n\n\tif((!m_pVapourSynthScriptProcessor->isInitialized()) ||\n\t\t(m_pVapourSynthScriptProcessor->scriptName() !=\n\t\tm_properties.scriptName) || (m_pVapourSynthScriptProcessor->script() !=\n\t\tm_properties.scriptText))\n\t{\n\t\tbool scriptProcessorInitialized =\n\t\t\tm_pVapourSynthScriptProcessor->initialize(\n\t\t\tm_properties.scriptText, m_properties.scriptName, 0,\n\t\t\tProcessReason::Encode);\n\t\tif(!scriptProcessorInitialized)\n\t\t{\n\t\t\temit signalLogMessage(tr(\"Failed to initialize script.\\n%1\")\n\t\t\t\t.arg(m_pVapourSynthScriptProcessor->error()), LOG_STYLE_ERROR);\n\t\t\tchangeStateAndNotify(JobState::Failed);\n\t\t\treturn false;\n\t\t}\n\t}\n\n\tVSNodeInfo info = m_pVapourSynthScriptProcessor->nodeInfo();\n\tQ_ASSERT(!info.isInvalid());\n\tif(info.isAudio())\n\t{\n\t\temit signalLogMessage(tr(\"Audio encoding is not supported.\"));\n\t\tchangeStateAndNotify(JobState::Failed);\n\t\treturn false;\n\t}\n\tm_cpVideoInfo = info.getAsVideo();\n\n\tm_properties.framesProcessed = 0;\n\tm_properties.firstFrameReal = m_properties.firstFrame;\n\tvsedit::clamp(m_properties.firstFrameReal, 0, m_cpVideoInfo->numFrames - 1);\n\tm_properties.lastFrameReal = m_properties.lastFrame;\n\tif((m_properties.lastFrameReal < m_properties.firstFrameReal) ||\n\t\t(m_properties.lastFrameReal >= m_cpVideoInfo->numFrames))\n\t\tm_properties.lastFrameReal = m_cpVideoInfo->numFrames - 1;\n\tm_lastFrameRequested = m_properties.firstFrameReal - 1;\n\tm_lastFrameProcessed = m_lastFrameRequested;\n\tm_encodingState = EncodingState::Idle;\n\tm_bytesToWrite = 0u;\n\tm_bytesWritten = 0u;\n\n\treturn true;\n}\n\n// END OF bool vsedit::Job::initialize()\n//==============================================================================\n\nvoid vsedit::Job::cleanUpEncoding()\n{\n\tif(m_process.state() == QProcess::Running)\n\t{\n\t\tif(m_encodingState != EncodingState::Aborting)\n\t\t\tm_encodingState = EncodingState::Finishing;\n\t\tm_process.closeWriteChannel();\n\t}\n\n\tif(m_pVapourSynthScriptProcessor)\n\t\tm_pVapourSynthScriptProcessor->finalize();\n\n\tclearFramesCache();\n\tm_framebuffer.clear();\n\tm_cpVideoInfo = nullptr;\n}\n\n// END OF void vsedit::Job::cleanUpEncoding()\n//==============================================================================\n\nvoid vsedit::Job::start()\n{\n\tif(m_properties.jobState == JobState::Paused)\n\t{\n\t\tchangeStateAndNotify(JobState::Running);\n\t\tif(m_properties.type == JobType::EncodeScriptCLI)\n\t\t\tprocessFramesQueue();\n\t\telse if(m_properties.type == JobType::RunProcess)\n\t\t{\n#ifdef Q_OS_WIN\n\t\t\tBOOL result = DebugActiveProcessStop((DWORD)m_process.processId());\n\t\t\tif(result)\n\t\t\t\tchangeStateAndNotify(JobState::Running);\n\t\t\telse\n\t\t\t\temit signalLogMessage(tr(\"Failed to resume process. \"\n\t\t\t\t\t\"Error %1.\").arg(GetLastError()), LOG_STYLE_ERROR);\n#else\n\t\t\tint error = kill((pid_t)m_process.processId(), SIGCONT);\n\t\t\tif(!error)\n\t\t\t\tchangeStateAndNotify(JobState::Running);\n\t\t\telse\n\t\t\t\temit signalLogMessage(tr(\"Failed to resume process. \"\n\t\t\t\t\t\"Error %1.\").arg(error), LOG_STYLE_ERROR);\n#endif\n\t\t}\n\t}\n\telse if(!isActive())\n\t{\n\t\tm_properties.timeStarted = QDateTime::currentDateTimeUtc();\n\t\tchangeStateAndNotify(JobState::Running);\n\t\temit signalStartTimeChanged();\n\t\tif(m_properties.type == JobType::EncodeScriptCLI)\n\t\t\tstartEncodeScriptCLI();\n\t\telse if(m_properties.type == JobType::RunProcess)\n\t\t\tstartRunProcess();\n\t\telse if(m_properties.type == JobType::RunShellCommand)\n\t\t\tstartRunShellCommand();\n\t}\n}\n\n// END OF void vsedit::Job::start()\n//==============================================================================\n\nvoid vsedit::Job::pause()\n{\n\tif(m_properties.jobState != JobState::Running)\n\t\treturn;\n\n\tif(m_properties.type == JobType::EncodeScriptCLI)\n\t{\n\t\tEncodingState invalidEncodingStates[] = {EncodingState::Idle,\n\t\t\tEncodingState::EncoderCrashed, EncodingState::Finishing,\n\t\t\tEncodingState::Aborting};\n\t\tif(vsedit::contains(invalidEncodingStates, m_encodingState))\n\t\t\treturn;\n\n\t\tchangeStateAndNotify(JobState::Pausing);\n\t}\n\telse if(m_properties.type == JobType::RunProcess)\n\t{\n#ifdef Q_OS_WIN\n\t\tBOOL result = DebugActiveProcess((DWORD)m_process.processId());\n\t\tif(result)\n\t\t\tchangeStateAndNotify(JobState::Paused);\n\t\telse\n\t\t\temit signalLogMessage(tr(\"Failed to pause process. Error %1.\")\n\t\t\t\t.arg(GetLastError()), LOG_STYLE_ERROR);\n#else\n\t\tint error = kill((pid_t)m_process.processId(), SIGSTOP);\n\t\tif(!error)\n\t\t\tchangeStateAndNotify(JobState::Paused);\n\t\telse\n\t\t\temit signalLogMessage(tr(\"Failed to pause process. Error %1.\")\n\t\t\t\t.arg(error), LOG_STYLE_ERROR);\n#endif\n\t}\n}\n\n// END OF void vsedit::Job::pause()\n//==============================================================================\n\nvoid vsedit::Job::abort()\n{\n\tif(!isActive())\n\t\treturn;\n\n\tif(m_process.state() != QProcess::Running){\n\t\tcleanUpEncoding();\n\t\tchangeStateAndNotify(JobState::Aborted);\n\t\treturn;\n\t}\n\n\tchangeStateAndNotify(JobState::Aborting);\n\tif(m_properties.type == JobType::EncodeScriptCLI)\n\t{\n\t\tm_encodingState = EncodingState::Aborting;\n\t\tcleanUpEncoding();\n\t\treturn;\n\t}\n\telse if(m_properties.type == JobType::RunProcess)\n\t{\n\t\tif(m_process.state() == QProcess::Running)\n\t\t{\n\t\t\tm_process.kill();\n\t\t\tm_process.waitForFinished(-1);\n\t\t}\n\t}\n\n\tchangeStateAndNotify(JobState::Aborted);\n}\n\n// END OF void vsedit::Job::abort()\n//==============================================================================\n\nvoid vsedit::Job::slotProcessStarted()\n{\n\tif(m_encodingState == EncodingState::CheckingEncoderSanity)\n\t\treturn;\n\n\tif(m_properties.type == JobType::EncodeScriptCLI)\n\t{\n\t\temit signalLogMessage(tr(\"Encoder started. Beginning encoding.\"));\n\n\t\tif(!m_process.isWritable())\n\t\t{\n\t\t\tm_encodingState = EncodingState::Aborting;\n\t\t\tm_properties.jobState = JobState::Aborting;\n\t\t\temit signalLogMessage(tr(\"Can not write to encoder. Aborting.\"),\n\t\t\t\tLOG_STYLE_ERROR);\n\t\t\tcleanUpEncoding();\n\t\t\treturn;\n\t\t}\n\n\t\tQ_ASSERT(m_pFrameHeaderWriter);\n\t\tif(m_pFrameHeaderWriter->needVideoHeader())\n\t\t{\n\t\t\tQByteArray videoHeader =\n\t\t\t\tm_pFrameHeaderWriter->videoHeader(framesTotal());\n\n\t\t\tif(m_properties.encodingHeaderType == EncodingHeaderType::Y4M)\n\t\t\t\temit signalLogMessage(tr(\"Y4M header: \") +\n\t\t\t\t\tQString::fromLatin1(videoHeader), LOG_STYLE_DEBUG);\n\n\t\t\tm_bytesToWrite = videoHeader.size();\n\t\t\tif(m_bytesToWrite > 0)\n\t\t\t{\n\t\t\t\tm_bytesWritten = 0;\n\t\t\t\tm_encodingState = EncodingState::WritingHeader;\n\t\t\t\tqint64 bytesWritten = m_process.write(videoHeader);\n\t\t\t\tif(bytesWritten < 0)\n\t\t\t\t{\n\t\t\t\t\tm_encodingState = EncodingState::Aborting;\n\t\t\t\t\tchangeStateAndNotify(JobState::FailedCleanUp);\n\t\t\t\t\temit signalLogMessage(\n\t\t\t\t\t\ttr(\"Error on writing header to encoder. Aborting.\"),\n\t\t\t\t\t\tLOG_STYLE_ERROR);\n\t\t\t\t\tcleanUpEncoding();\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\n\t\tm_memorizedEncodingTime = 0.0;\n\t\tm_encodeRangeStartTime = hr_clock::now();\n\n\t\tm_encodingState = EncodingState::WaitingForFrames;\n\t\tprocessFramesQueue();\n\t}\n}\n\n// END OF void vsedit::Job::slotProcessStarted()\n//==============================================================================\n\nvoid vsedit::Job::slotProcessFinished(int a_exitCode,\n\tQProcess::ExitStatus a_exitStatus)\n{\n\tif(m_properties.type == JobType::EncodeScriptCLI)\n\t{\n\t\tEncodingState workingStates[] = {EncodingState::WaitingForFrames,\n\t\t\tEncodingState::WritingFrame, EncodingState::WritingHeader};\n\n\t\tif(m_encodingState == EncodingState::CheckingEncoderSanity)\n\t\t\treturn;\n\t\telse if(m_encodingState == EncodingState::Idle)\n\t\t\treturn;\n\t\telse if(m_encodingState == EncodingState::Finishing)\n\t\t\tchangeStateAndNotify(JobState::CompletedCleanUp);\n\t\telse if(vsedit::contains(workingStates, m_encodingState))\n\t\t{\n\t\t\tQString exitStatusString = (a_exitStatus == QProcess::CrashExit) ?\n\t\t\t\ttr(\"crash\") : tr(\"normal exit\");\n\t\t\temit signalLogMessage(tr(\"Encoder has finished \"\n\t\t\t\t\"unexpectedly.\\nReason: %1; exit code: %2\")\n\t\t\t\t.arg(exitStatusString).arg(a_exitCode), LOG_STYLE_ERROR);\n\t\t\tchangeStateAndNotify(JobState::FailedCleanUp);\n\t\t}\n\n\t\tcleanUpEncoding();\n\t\tfinishEncodingCLI();\n\t}\n\telse if(m_properties.type == JobType::RunProcess)\n\t{\n\t\tQString message = tr(\"Process has finished.\");\n\t\tQString logStyle = LOG_STYLE_POSITIVE;\n\t\tJobState nextState = JobState::Completed;\n\n\t\tif(a_exitStatus == QProcess::CrashExit)\n\t\t{\n\t\t\tmessage = tr(\"Process has crashed.\");\n\t\t\tlogStyle = LOG_STYLE_ERROR;\n\t\t\tnextState = JobState::Failed;\n\t\t}\n\t\telse if(a_exitCode != 0)\n\t\t\tlogStyle = LOG_STYLE_WARNING;\n\n\t\temit signalLogMessage(tr(\"%1 Exit code: %2\")\n\t\t\t.arg(message).arg(a_exitCode), logStyle);\n\t\tchangeStateAndNotify(nextState);\n\t}\n}\n\n// END OF void vsedit::Job::slotProcessFinished(int a_exitCode,\n//\t\tQProcess::ExitStatus a_exitStatus)\n//==============================================================================\n\nvoid vsedit::Job::slotProcessError(QProcess::ProcessError a_error)\n{\n\tif(m_properties.type == JobType::EncodeScriptCLI)\n\t{\n\t\tif(m_encodingState == EncodingState::CheckingEncoderSanity)\n\t\t\treturn;\n\n\t\tif(m_encodingState == EncodingState::Idle)\n\t\t{\n\t\t\temit signalLogMessage(tr(\"Encoder has reported \"\n\t\t\t\t\"an error while it shouldn't be running at all. Ignoring.\"),\n\t\t\t\tLOG_STYLE_WARNING);\n\t\t\treturn;\n\t\t}\n\n\t\tswitch(a_error)\n\t\t{\n\t\tcase QProcess::FailedToStart:\n\t\t\temit signalLogMessage(tr(\"Encoder has failed to start. \"\n\t\t\t\t\"Aborting.\"), LOG_STYLE_ERROR);\n\t\t\tm_encodingState = EncodingState::Aborting;\n\t\t\tchangeStateAndNotify(JobState::FailedCleanUp);\n\t\t\tcleanUpEncoding();\n\t\t\tbreak;\n\n\t\tcase QProcess::Crashed:\n\t\t\temit signalLogMessage(tr(\"Encoder has crashed. \"\n\t\t\t\t\"Aborting.\"), LOG_STYLE_ERROR);\n\t\t\tm_encodingState = EncodingState::EncoderCrashed;\n\t\t\tchangeStateAndNotify(JobState::FailedCleanUp);\n\t\t\tcleanUpEncoding();\n\t\t\tbreak;\n\n\t\tcase QProcess::Timedout:\n\t\t\tbreak;\n\n\t\tcase QProcess::WriteError:\n\t\t\tif(m_encodingState == EncodingState::WritingFrame)\n\t\t\t{\n\t\t\t\temit signalLogMessage(tr(\"Writing to encoder \"\n\t\t\t\t\t\"failed. Aborting.\"), LOG_STYLE_ERROR);\n\t\t\t\tm_encodingState = EncodingState::Aborting;\n\t\t\t\tchangeStateAndNotify(JobState::FailedCleanUp);\n\t\t\t\tcleanUpEncoding();\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\temit signalLogMessage(tr(\"Encoder has returned a \"\n\t\t\t\t\t\"writing error, but we were not writing. Ignoring.\"),\n\t\t\t\t\tLOG_STYLE_WARNING);\n\t\t\t}\n\t\t\tbreak;\n\n\t\tcase QProcess::ReadError:\n\t\t\temit signalLogMessage(tr(\"Error on reading the \"\n\t\t\t\t\"encoder feedback.\"), LOG_STYLE_WARNING);\n\t\t\tbreak;\n\n\t\tcase QProcess::UnknownError:\n\t\t\temit signalLogMessage(tr(\"Unknown error in encoder.\"),\n\t\t\t\tLOG_STYLE_WARNING);\n\t\t\tbreak;\n\n\t\tdefault:\n\t\t\tQ_ASSERT(false);\n\t\t}\n\t}\n\telse if(m_properties.type == JobType::RunProcess)\n\t{\n\t\tswitch(a_error)\n\t\t{\n\t\tcase QProcess::FailedToStart:\n\t\t\temit signalLogMessage(tr(\"Process has failed to start.\"),\n\t\t\t\tLOG_STYLE_ERROR);\n\t\t\tchangeStateAndNotify(JobState::Failed);\n\t\t\tbreak;\n\n\t\tcase QProcess::Crashed:\n\t\t\temit signalLogMessage(tr(\"Process has crashed.\"),\n\t\t\t\tLOG_STYLE_ERROR);\n\t\t\tchangeStateAndNotify(JobState::Failed);\n\t\t\tbreak;\n\n\t\tdefault:\n\t\t\tbreak;\n\t\t}\n\t}\n}\n\n// END OF void vsedit::Job::slotProcessError(QProcess::ProcessError a_error)\n//==============================================================================\n\nvoid vsedit::Job::slotProcessReadChannelFinished()\n{\n\tif(m_properties.type != JobType::EncodeScriptCLI)\n\t\treturn;\n\n\tif(m_encodingState == EncodingState::CheckingEncoderSanity)\n\t\treturn;\n\n\tif(m_encodingState == EncodingState::Idle)\n\t{\n\t\temit signalLogMessage(tr(\"Encoder has suddenly stopped \"\n\t\t\t\"accepting data while it shouldn't be running at all. Ignoring.\"),\n\t\t\tLOG_STYLE_WARNING);\n\t\treturn;\n\t}\n\n\tif((m_encodingState != EncodingState::Finishing) &&\n\t\t(m_encodingState != EncodingState::Aborting))\n\t{\n\t\temit signalLogMessage(tr(\"Encoder has suddenly stopped \"\n\t\t\t\"accepting data. Aborting.\"), LOG_STYLE_ERROR);\n\t\tm_encodingState = EncodingState::Aborting;\n\t\tchangeStateAndNotify(JobState::FailedCleanUp);\n\t\tcleanUpEncoding();\n\t}\n}\n\n// END OF void vsedit::Job::slotProcessReadChannelFinished()\n//==============================================================================\n\nvoid vsedit::Job::slotProcessBytesWritten(qint64 a_bytes)\n{\n\tif(m_properties.type != JobType::EncodeScriptCLI)\n\t\treturn;\n\n\tif(m_encodingState == EncodingState::CheckingEncoderSanity)\n\t\treturn;\n\n\tif(m_encodingState == EncodingState::Idle)\n\t{\n\t\temit signalLogMessage(tr(\"Encoder has reported written \"\n\t\t\t\"data while it shouldn't be running at all. Ignoring.\"),\n\t\t\tLOG_STYLE_WARNING);\n\t\treturn;\n\t}\n\n\tif((m_encodingState == EncodingState::Aborting) ||\n\t\t(m_encodingState == EncodingState::Finishing))\n\t\treturn;\n\n\tif((m_encodingState != EncodingState::WritingFrame) &&\n\t\t(m_encodingState != EncodingState::WritingHeader))\n\t{\n\t\temit signalLogMessage(tr(\"Encoder reports successful \"\n\t\t\t\"write, but we were not writing anything.\\nData written: \"\n\t\t\t\"%1 bytes.\").arg(a_bytes), LOG_STYLE_WARNING);\n\t\treturn;\n\t}\n\n\tif(a_bytes <= 0)\n\t{\n\t\temit signalLogMessage(tr(\"Error on writing data to \"\n\t\t\t\"encoder.\\nExpected to write: %1 bytes. Data written: %2 bytes.\\n\"\n\t\t\t\"Aborting.\").arg(m_bytesToWrite).arg(m_bytesWritten),\n\t\t\tLOG_STYLE_ERROR);\n\t\tm_encodingState = EncodingState::Aborting;\n\t\tchangeStateAndNotify(JobState::FailedCleanUp);\n\t\tcleanUpEncoding();\n\t\treturn;\n\t}\n\n\tm_bytesWritten += a_bytes;\n\n\tif((m_bytesWritten + m_process.bytesToWrite()) < m_bytesToWrite)\n\t{\n\t\temit signalLogMessage(tr(\"Encoder has lost written \"\n\t\t\t\"data. Aborting.\"), LOG_STYLE_ERROR);\n\t\tm_encodingState = EncodingState::Aborting;\n\t\tchangeStateAndNotify(JobState::FailedCleanUp);\n\t\tcleanUpEncoding();\n\t\treturn;\n\t}\n\n\tif(m_bytesWritten < m_bytesToWrite)\n\t\treturn;\n\n\tQ_ASSERT(m_cpVSAPI);\n\tif(m_encodingState == EncodingState::WritingHeader)\n\t{\n\t\tm_memorizedEncodingTime = 0.0;\n\t\tm_encodeRangeStartTime = hr_clock::now();\n\t}\n\telse if(m_encodingState == EncodingState::WritingFrame)\n\t{\n\t\tFrame referenceFrame(m_lastFrameProcessed + 1, 0, nullptr);\n\t\tstd::list<Frame>::iterator it =\n\t\t\tstd::find(m_framesCache.begin(), m_framesCache.end(),\n\t\t\treferenceFrame);\n\t\tQ_ASSERT(it != m_framesCache.end());\n\n\t\tm_cpVSAPI->freeFrame(it->cpOutputFrame);\n\t\tm_framesCache.erase(it);\n\t\tm_lastFrameProcessed++;\n\t\tm_properties.framesProcessed++;\n\t\tupdateFPS();\n\n\t\temit signalProgressChanged();\n\t}\n\n\tm_encodingState = EncodingState::WaitingForFrames;\n\n\tif((m_properties.jobState == JobState::Pausing) && (m_framesInProcess == 0))\n\t{\n\t\tchangeStateAndNotify(JobState::Paused);\n\t\treturn;\n\t}\n\n\tprocessFramesQueue();\n}\n\n// END OF void vsedit::Job::slotProcessBytesWritten(qint64 a_bytes)\n//==============================================================================\n\nvoid vsedit::Job::slotProcessReadyReadStandardError()\n{\n\tQByteArray standardError = m_process.readAllStandardError();\n\tQString standardErrorText = QString::fromUtf8(standardError);\n\tstandardErrorText = standardErrorText.trimmed();\n\tif(!standardErrorText.isEmpty())\n\t\temit signalLogMessage(standardErrorText);\n}\n\n// END OF void vsedit::Job::slotProcessReadyReadStandardError()\n//==============================================================================\n\nvoid vsedit::Job::slotWriteLogMessage(int a_messageType,\n\tconst QString & a_message)\n{\n\tQString style = vsMessageTypeToStyleName(a_messageType);\n\temit signalLogMessage(a_message, style);\n}\n\n// END OF void vsedit::Job::slotWriteLogMessage(int a_messageType,\n//\t\tconst QString & a_message)\n//==============================================================================\n\nvoid vsedit::Job::slotFrameQueueStateChanged(size_t a_inQueue,\n\tsize_t a_inProcess, size_t a_maxThreads, double a_usedCacheRatio)\n{\n\tm_framesInQueue = a_inQueue;\n\tm_framesInProcess = a_inProcess;\n\tm_maxThreads = a_maxThreads;\n}\n\n// END OF void vsedit::Job::slotFrameQueueStateChanged(size_t a_inQueue,\n//\t\tsize_t a_inProcess, size_t a_maxThreads, double a_usedCacheRatio)\n//==============================================================================\n\nvoid vsedit::Job::slotScriptProcessorFinalized()\n{\n\tQ_ASSERT(m_properties.type == JobType::EncodeScriptCLI);\n\tfinishEncodingCLI();\n}\n\n// END OF void vsedit::Job::slotScriptProcessorFinalized()\n//==============================================================================\n\nvoid vsedit::Job::slotReceiveFrame(int a_frameNumber, int a_outputIndex,\n\tconst VSFrame * a_cpOutputFrame,\n\tconst VSFrame * a_cpPreviewFrameRef)\n{\n\t(void)a_cpPreviewFrameRef;\n\n\tEncodingState validStates[] = {EncodingState::WaitingForFrames,\n\t\tEncodingState::WritingHeader, EncodingState::WritingFrame};\n\tif(!vsedit::contains(validStates, m_encodingState))\n\t\treturn;\n\n\tif((a_frameNumber < m_properties.firstFrameReal) ||\n\t\t(a_frameNumber > m_properties.lastFrameReal))\n\t\treturn;\n\n\tQ_ASSERT(m_cpVSAPI);\n\tconst VSFrame * cpFrameRef =\n\t\tm_cpVSAPI->addFrameRef(a_cpOutputFrame);\n\tFrame newFrame(a_frameNumber, a_outputIndex, cpFrameRef);\n\tm_framesCache.push_back(newFrame);\n\n\tif(m_encodingState == EncodingState::WaitingForFrames)\n\t\tprocessFramesQueue();\n}\n\n// END OF void vsedit::Job::slotReceiveFrame(int a_frameNumber,\n//\t\tint a_outputIndex, const VSFrame * a_cpOutputFrame,\n//\t\tconst VSFrame * a_cpPreviewFrameRef)\n//==============================================================================\n\nvoid vsedit::Job::slotFrameRequestDiscarded(int a_frameNumber,\n\tint a_outputIndex, const QString & a_reason)\n{\n\t(void)a_frameNumber;\n\t(void)a_outputIndex;\n\t(void)a_reason;\n\n\tEncodingState validStates[] = {EncodingState::WaitingForFrames,\n\t\tEncodingState::WritingHeader, EncodingState::WritingFrame};\n\tif(!vsedit::contains(validStates, m_encodingState))\n\t\treturn;\n\n\tm_encodingState = EncodingState::Aborting;\n\tchangeStateAndNotify(JobState::FailedCleanUp);\n\tcleanUpEncoding();\n}\n\n// END OF void vsedit::Job::slotFrameRequestDiscarded(int a_frameNumber,\n//\t\tint a_outputIndex, const QString & a_reason)\n//==============================================================================\n\nvoid vsedit::Job::fillVariables()\n{\n\tJobVariables::fillVariables();\n\n\tstruct JobVariableEvaluator\n\t{\n\t\tQString token;\n\t\tstd::function<QString()> evaluate;\n\t};\n\n\tJobVariableEvaluator evaluators[] =\n\t{\n\t\t{TOKEN_WIDTH,\n\t\t\t[&]() -> QString\n\t\t\t{\n\t\t\t\tif(!m_cpVideoInfo)\n\t\t\t\t\treturn TOKEN_WIDTH;\n\t\t\t\treturn QString::number(m_cpVideoInfo->width);\n\t\t\t}\n\t\t},\n\n\t\t{TOKEN_HEIGHT,\n\t\t\t[&]() -> QString\n\t\t\t{\n\t\t\t\tif(!m_cpVideoInfo)\n\t\t\t\t\treturn TOKEN_HEIGHT;\n\t\t\t\treturn QString::number(m_cpVideoInfo->height);\n\t\t\t}\n\t\t},\n\n\t\t{TOKEN_FPS_NUMERATOR,\n\t\t\t[&]() -> QString\n\t\t\t{\n\t\t\t\tif(!m_cpVideoInfo)\n\t\t\t\t\treturn TOKEN_FPS_NUMERATOR;\n\t\t\t\treturn QString::number(m_cpVideoInfo->fpsNum);\n\t\t\t}\n\t\t},\n\n\t\t{TOKEN_FPS_DENOMINATOR,\n\t\t\t[&]() -> QString\n\t\t\t{\n\t\t\t\tif(!m_cpVideoInfo)\n\t\t\t\t\treturn TOKEN_FPS_DENOMINATOR;\n\t\t\t\treturn QString::number(m_cpVideoInfo->fpsDen);\n\t\t\t}\n\t\t},\n\n\t\t{TOKEN_FPS,\n\t\t\t[&]() -> QString\n\t\t\t{\n\t\t\t\tif(!m_cpVideoInfo)\n\t\t\t\t\treturn TOKEN_FPS;\n\t\t\t\tdouble fps = (double)m_cpVideoInfo->fpsNum /\n\t\t\t\t\t(double)m_cpVideoInfo->fpsDen;\n\t\t\t\treturn QString::number(fps, 'f', 10);\n\t\t\t}\n\t\t},\n\n\t\t{TOKEN_BITDEPTH,\n\t\t\t[&]() -> QString\n\t\t\t{\n\t\t\t\tif(!m_cpVideoInfo)\n\t\t\t\t\treturn TOKEN_BITDEPTH;\n\t\t\t\treturn QString::number(m_cpVideoInfo->format.bitsPerSample);\n\t\t\t}\n\t\t},\n\n\t\t{TOKEN_SCRIPT_DIRECTORY,\n\t\t\t[&]() -> QString\n\t\t\t{\n\t\t\t\tQFileInfo scriptFile(m_properties.scriptName);\n\t\t\t\treturn scriptFile.canonicalPath();\n\t\t\t}\n\t\t},\n\n\t\t{TOKEN_SCRIPT_NAME,\n\t\t\t[&]() -> QString\n\t\t\t{\n\t\t\t\tQFileInfo scriptFile(m_properties.scriptName);\n\t\t\t\treturn scriptFile.completeBaseName();\n\t\t\t}\n\t\t},\n\n\t\t{TOKEN_FRAMES_NUMBER,\n\t\t\t[&]() -> QString\n\t\t\t{\n\t\t\t\treturn QString::number(framesTotal());\n\t\t\t}\n\t\t},\n\n\t\t{TOKEN_SUBSAMPLING,\n\t\t\t[&]() -> QString\n\t\t\t{\n\t\t\t\tif(!m_cpVideoInfo)\n\t\t\t\t\treturn TOKEN_SUBSAMPLING;\n\t\t\t\tconst VSVideoFormat * cpFormat = &m_cpVideoInfo->format;\n\t\t\t\treturn vsedit::subsamplingString(cpFormat->subSamplingW,\n\t\t\t\t\tcpFormat->subSamplingH);\n\t\t\t}\n\t\t},\n\t};\n\n\tfor(JobVariableEvaluator & evaluator : evaluators)\n\t{\n\t\tstd::vector<vsedit::VariableToken>::iterator it =\n\t\t\tstd::find_if(m_variables.begin(), m_variables.end(),\n\t\t\t\t[&](const vsedit::VariableToken & a_variable) -> bool\n\t\t\t\t{\n\t\t\t\t\treturn (a_variable.token == evaluator.token);\n\t\t\t\t});\n\t\tit->evaluate = evaluator.evaluate;\n\t}\n}\n\n// END OF void vsedit::Job::fillVariables()\n//==============================================================================\n\nvoid vsedit::Job::changeStateAndNotify(JobState a_state)\n{\n\tif(m_properties.jobState == a_state && a_state != JobState::Aborted)\n\t\treturn;\n\n\tJobState oldState = m_properties.jobState;\n\tm_properties.jobState = a_state;\n\n\tif(oldState == JobState::Waiting)\n\t\tm_properties.timeStarted = QDateTime::currentDateTimeUtc();\n\n\tconst JobState finishStates[] = {JobState::Aborted, JobState::Failed,\n\t\tJobState::DependencyNotMet, JobState::Completed};\n\tif(vsedit::contains(finishStates, a_state))\n\t{\n\t\tm_properties.timeEnded = QDateTime::currentDateTimeUtc();\n\t\tmemorizeEncodingTime();\n\t\temit signalEndTimeChanged();\n\t}\n\n\tif(a_state == JobState::Paused)\n\t\tmemorizeEncodingTime();\n\n\tif((oldState == JobState::Paused) && (a_state == JobState::Running))\n\t\tm_encodeRangeStartTime = hr_clock::now();\n\n\tif(a_state == JobState::Waiting)\n\t{\n\t\tm_properties.timeStarted = QDateTime();\n\t\tm_properties.timeEnded = QDateTime();\n\t\tm_memorizedEncodingTime = 0.0;\n\t\tm_properties.fps = 0.0;\n\t\tm_properties.framesProcessed = 0;\n\t}\n\n\temit signalStateChanged(m_properties.jobState, oldState);\n}\n\n// END OF void vsedit::Job::changeStateAndNotify(JobState a_state)\n//==============================================================================\n\nvoid vsedit::Job::startEncodeScriptCLI()\n{\n\tif(!initialize())\n\t\treturn;\n\n\temit signalPropertiesChanged();\n\n\tif(m_pFrameHeaderWriter)\n\t\tdelete m_pFrameHeaderWriter;\n\n\tif(m_properties.encodingHeaderType == EncodingHeaderType::Y4M)\n\t\tm_pFrameHeaderWriter =\n\t\t\tnew FrameHeaderWriterY4M(m_cpVSAPI, m_cpVideoInfo, this);\n\telse\n\t\tm_pFrameHeaderWriter =\n\t\t\tnew FrameHeaderWriterNull(m_cpVSAPI, m_cpVideoInfo, this);\n\n\tbool compatibleHeader = m_pFrameHeaderWriter->isCompatible();\n\tif(!compatibleHeader)\n\t{\n\t\temit signalLogMessage(tr(\"Video is not compatible \"\n\t\t\t\"with the chosen header.\"), LOG_STYLE_ERROR);\n\t\tchangeStateAndNotify(JobState::FailedCleanUp);\n\t\tcleanUpEncoding();\n\t\treturn;\n\t}\n\n\tQString executable = vsedit::resolvePathFromApplication(\n\t\tm_properties.executablePath);\n\tQString decodedArguments =\n\t\tdecodeArguments(m_properties.arguments);\n\tQString commandLine = QString(\"\\\"%1\\\" %2\").arg(executable)\n\t\t.arg(decodedArguments);\n\n\temit signalLogMessage(tr(\"Command line:\"));\n\temit signalLogMessage(commandLine);\n\n\temit signalLogMessage(tr(\"Checking the encoder sanity.\"));\n\tm_encodingState = EncodingState::CheckingEncoderSanity;\n\n\tm_process.startCommand(commandLine);\n\tif(!m_process.waitForStarted(3000))\n\t{\n\t\temit signalLogMessage(tr(\"Encoder wouldn't start.\"),\n\t\t\tLOG_STYLE_ERROR);\n\t\tchangeStateAndNotify(JobState::FailedCleanUp);\n\t\tcleanUpEncoding();\n\t\treturn;\n\t}\n\n\tm_process.closeWriteChannel();\n\tif(!m_process.waitForFinished(3000))\n\t{\n\t\temit signalLogMessage(tr(\"Program is not behaving \"\n\t\t\t\"like a CLI encoder. Terminating.\"), LOG_STYLE_ERROR);\n\t\tm_process.kill();\n\t\tm_process.waitForFinished(-1);\n\t\tchangeStateAndNotify(JobState::FailedCleanUp);\n\t\tcleanUpEncoding();\n\t\treturn;\n\t}\n\n\temit signalLogMessage(tr(\"Encoder seems sane. Starting.\"));\n\tm_encodingState = EncodingState::StartingEncoder;\n\tm_process.startCommand(commandLine);\n}\n\n// END OF void vsedit::Job::startEncodeScriptCLI()\n//==============================================================================\n\nvoid vsedit::Job::startRunProcess()\n{\n\tchangeStateAndNotify(JobState::Running);\n\n\tQString executable = vsedit::resolvePathFromApplication(\n\t\tm_properties.executablePath);\n\tQString commandLine = QString(\"\\\"%1\\\" %2\").arg(executable)\n\t\t.arg(m_properties.arguments);\n\n\temit signalLogMessage(tr(\"Command line:\"));\n\temit signalLogMessage(commandLine);\n\n\tm_process.startCommand(commandLine);\n}\n\n// END OF void vsedit::Job::startRunProcess()\n//==============================================================================\n\nvoid vsedit::Job::startRunShellCommand()\n{\n\tchangeStateAndNotify(JobState::Running);\n\n\tQString command = \"%1\";\n\tm_process.startDetached(m_properties.shellCommand, QStringList());\n\tchangeStateAndNotify(JobState::Completed);\n}\n\n// END OF void vsedit::Job::startRunShellCommand()\n//==============================================================================\n\nQString vsedit::Job::decodeArguments(const QString & a_arguments) const\n{\n\tQString decodedString = a_arguments.simplified();\n\n\tfor(const vsedit::VariableToken & variable : m_variables)\n\t{\n\t\tdecodedString = decodedString.replace(variable.token,\n\t\t\tvariable.evaluate());\n\t}\n\n\treturn decodedString;\n}\n\n// END OF QString vsedit::Job::decodeArguments(\n//\t\tconst QString & a_arguments) const\n//==============================================================================\n\nvoid vsedit::Job::clearFramesCache()\n{\n\tif(m_framesCache.empty())\n\t\treturn;\n\n\tQ_ASSERT(m_cpVSAPI);\n\tfor(Frame & frame : m_framesCache)\n\t{\n\t\tm_cpVSAPI->freeFrame(frame.cpOutputFrame);\n\t\tm_cpVSAPI->freeFrame(frame.cpPreviewFrame);\n\t}\n\tm_framesCache.clear();\n}\n\n// END OF void vsedit::Job::clearFramesCache()\n//==============================================================================\n\nvoid vsedit::Job::processFramesQueue()\n{\n\tif(m_encodingState != EncodingState::WaitingForFrames)\n\t\treturn;\n\n\tif(m_properties.framesProcessed == framesTotal())\n\t{\n\t\tQ_ASSERT(m_framesCache.empty());\n\t\tmemorizeEncodingTime();\n\t\tupdateFPS();\n\t\tchangeStateAndNotify(JobState::CompletedCleanUp);\n\t\tm_encodingState = EncodingState::Finishing;\n\t\tcleanUpEncoding();\n\t\treturn;\n\t}\n\n\twhile((m_lastFrameRequested < m_properties.lastFrameReal) &&\n\t\t(m_framesInProcess < m_maxThreads) &&\n\t\t(m_framesCache.size() < m_cachedFramesLimit) &&\n\t\t(m_properties.jobState == JobState::Running))\n\t{\n\t\tm_pVapourSynthScriptProcessor->requestFrameAsync(\n\t\t\tm_lastFrameRequested + 1);\n\t\tm_lastFrameRequested++;\n\t}\n\n\tFrame frame(m_lastFrameProcessed + 1, 0, nullptr);\n\tstd::list<Frame>::iterator it = std::find(m_framesCache.begin(),\n\t\tm_framesCache.end(), frame);\n\tif(it == m_framesCache.end())\n\t\treturn;\n\n\tframe.cpOutputFrame = it->cpOutputFrame;\n\n\t// VapourSynth frames are padded so every line has aligned address.\n\t// But encoder expects frames tightly packed. We pack frame lines\n\t// into an intermediate buffer, because writing whole frame at once\n\t// is faster than feeding it to encoder line by line.\n\n\tsize_t currentDataSize = 0;\n\n\tQ_ASSERT(m_cpVideoInfo);\n\tconst VSVideoFormat * cpFormat = &m_cpVideoInfo->format;\n\n\tif(m_pFrameHeaderWriter->needFramePrefix())\n\t{\n\t\tQByteArray framePrefix =\n\t\t\tm_pFrameHeaderWriter->framePrefix(frame.cpOutputFrame);\n\t\tint prefixSize = framePrefix.size();\n\t\tif(prefixSize > 0)\n\t\t{\n\t\t\tif((size_t)prefixSize > m_framebuffer.size())\n\t\t\t\tm_framebuffer.resize(prefixSize);\n\t\t\tmemcpy(m_framebuffer.data(), framePrefix.data(), prefixSize);\n\t\t\tcurrentDataSize += prefixSize;\n\t\t}\n\t}\n\n\tfor(int i = 0; i < cpFormat->numPlanes; ++i)\n\t{\n\t\tconst uint8_t * cpPlane =\n\t\t\tm_cpVSAPI->getReadPtr(frame.cpOutputFrame, i);\n\t\tint stride = m_cpVSAPI->getStride(frame.cpOutputFrame, i);\n\t\tint width = m_cpVSAPI->getFrameWidth(frame.cpOutputFrame, i);\n\t\tint height = m_cpVSAPI->getFrameHeight(frame.cpOutputFrame, i);\n\t\tint bytes = cpFormat->bytesPerSample;\n\n\t\tsize_t planeSize = width * bytes * height;\n\t\tsize_t neededFramebufferSize = currentDataSize + planeSize;\n\t\tif(neededFramebufferSize > m_framebuffer.size())\n\t\t\tm_framebuffer.resize(neededFramebufferSize);\n\t\tint framebufferStride = width * bytes;\n\n\t\tvsh::bitblt(m_framebuffer.data() + currentDataSize, framebufferStride,\n\t\t\tcpPlane, stride, framebufferStride, height);\n\n\t\tcurrentDataSize += planeSize;\n\t}\n\n\tif(m_pFrameHeaderWriter->needFramePostfix())\n\t{\n\t\tQByteArray framePostfix =\n\t\t\tm_pFrameHeaderWriter->framePostfix(frame.cpOutputFrame);\n\t\tint postfixSize = framePostfix.size();\n\t\tif(postfixSize > 0)\n\t\t{\n\t\t\tsize_t neededFramebufferSize = currentDataSize + postfixSize;\n\t\t\tif(neededFramebufferSize > m_framebuffer.size())\n\t\t\t\tm_framebuffer.resize(neededFramebufferSize);\n\t\t\tmemcpy(m_framebuffer.data() + currentDataSize,\n\t\t\t\tframePostfix.data(), postfixSize);\n\t\t\tcurrentDataSize += postfixSize;\n\t\t}\n\t}\n\n\tm_encodingState = EncodingState::WritingFrame;\n\tm_bytesToWrite = currentDataSize;\n\tm_bytesWritten = 0;\n\tqint64 bytesWritten =\n\t\tm_process.write(m_framebuffer.data(), (qint64)m_bytesToWrite);\n\tif(bytesWritten < 0)\n\t{\n\t\tm_encodingState = EncodingState::Aborting;\n\t\tchangeStateAndNotify(JobState::FailedCleanUp);\n\t\temit signalLogMessage(tr(\"Error on writing data to encoder. \"\n\t\t\t\"Aborting.\"), LOG_STYLE_ERROR);\n\t\tcleanUpEncoding();\n\t\treturn;\n\t}\n\n\t// Wait until encoder reads the frame.\n\t// Then this function will be called again.\n}\n\n// END OF void vsedit::Job::processFramesQueue()\n//==============================================================================\n\nvoid vsedit::Job::finishEncodingCLI()\n{\n\tif((m_process.state() == QProcess::Running) ||\n\t\tm_pVapourSynthScriptProcessor->isInitialized())\n\t\treturn;\n\n\tif(m_encodingState == EncodingState::Finishing)\n\t{\n\t\temit signalLogMessage(tr(\"Finished encoding.\"), LOG_STYLE_POSITIVE);\n\t\tchangeStateAndNotify(JobState::CompletedCleanUp);\n\t}\n\telse if(m_encodingState == EncodingState::Aborting)\n\t{\n\t\temit signalLogMessage(tr(\"Aborted encoding.\"), LOG_STYLE_WARNING);\n\t}\n\n\tm_encodingState = EncodingState::Idle;\n\n\tconst std::map<JobState, JobState> stateToSwitch =\n\t{\n\t\t{JobState::Aborting, JobState::Aborted},\n\t\t{JobState::FailedCleanUp, JobState::Failed},\n\t\t{JobState::CompletedCleanUp, JobState::Completed},\n\t};\n\n\tstd::map<JobState, JobState>::const_iterator it =\n\t\tstateToSwitch.find(m_properties.jobState);\n\tif(it != stateToSwitch.cend())\n\t\tchangeStateAndNotify(it->second);\n}\n\n// END OF void vsedit::Job::finishEncodingCLI()\n//==============================================================================\n\nvoid vsedit::Job::memorizeEncodingTime()\n{\n\tif(m_properties.type != JobType::EncodeScriptCLI)\n\t\treturn;\n\n\tm_memorizedEncodingTime += currentEncodingRangeTime();\n\tm_encodeRangeStartTime = hr_clock::now();\n}\n\n// END OF void vsedit::Job::memorizeEncodingTime()\n//==============================================================================\n\nvoid vsedit::Job::updateFPS()\n{\n\tif(m_properties.type != JobType::EncodeScriptCLI)\n\t\treturn;\n\n\tdouble totalTime = m_memorizedEncodingTime;\n\tconst JobState validStates[] = {JobState::Running, JobState::Pausing};\n\tif(vsedit::contains(validStates, m_properties.jobState))\n\t\ttotalTime += currentEncodingRangeTime();\n\tm_properties.fps = (double)m_properties.framesProcessed / totalTime;\n}\n\n// END OF void vsedit::Job::updateFPS()\n//==============================================================================\n\ndouble vsedit::Job::currentEncodingRangeTime() const\n{\n\tif(m_properties.type != JobType::EncodeScriptCLI)\n\t\treturn 0.0;\n\n\thr_time_point now = hr_clock::now();\n\tdouble rangeTime = duration_to_double(now - m_encodeRangeStartTime);\n\treturn rangeTime;\n}\n\n// END OF double vsedit::Job::currentEncodingRangeTime() const\n//==============================================================================\n"
  },
  {
    "path": "common-src/jobs/job.h",
    "content": "#ifndef JOB_H_INCLUDED\n#define JOB_H_INCLUDED\n\n#include \"../../../common-src/settings/settings_definitions_core.h\"\n#include \"../../../common-src/chrono.h\"\n#include \"../../../common-src/helpers.h\"\n#include \"../../../common-src/log/styled_log_view_core.h\"\n#include \"../../../common-src/log/vs_editor_log_definitions.h\"\n#include \"../../../common-src/vapoursynth/vs_script_processor_structures.h\"\n#include \"../../../common-src/jobs/job_variables.h\"\n\n#include <QObject>\n#include <QUuid>\n#include <QDateTime>\n#include <QProcess>\n#include <vector>\n\nclass SettingsManagerCore;\nclass VSScriptLibrary;\nclass VapourSynthScriptProcessor;\nclass FrameHeaderWriter;\n\nnamespace vsedit\n{\n\nclass Job : public QObject, public JobVariables\n{\n\tQ_OBJECT\n\npublic:\n\n\tJob(const JobProperties & a_properties = JobProperties(),\n\t\tSettingsManagerCore * a_pSettingsManager = nullptr,\n\t\tVSScriptLibrary * a_pVSScriptLibrary = nullptr,\n\t\tQObject * a_pParent = nullptr);\n\tvirtual ~Job();\n\n\tenum class EncodingState\n\t{\n\t\tIdle,\n\t\tCheckingEncoderSanity,\n\t\tStartingEncoder,\n\t\tWritingHeader,\n\t\tWaitingForFrames,\n\t\tWritingFrame,\n\t\tEncoderCrashed,\n\t\tFinishing,\n\t\tAborting,\n\t};\n\n\tvirtual bool isActive() const;\n\n\tvirtual QUuid id() const;\n\tvirtual bool setId(const QUuid & a_id);\n\n\tvirtual JobType type() const;\n\tvirtual bool setType(JobType a_type);\n\n\tvirtual QString scriptName() const;\n\tvirtual bool setScriptName(const QString & a_scriptName);\n\n\tvirtual QString scriptText() const;\n\tvirtual bool setScriptText(const QString & a_scriptText);\n\n\tvirtual EncodingHeaderType encodingHeaderType() const;\n\tvirtual bool setEncodingHeaderType(EncodingHeaderType a_headerType);\n\n\tvirtual QString executablePath() const;\n\tvirtual bool setExecutablePath(const QString & a_path);\n\n\tvirtual QString arguments() const;\n\tvirtual bool setArguments(const QString & a_arguments);\n\n\tvirtual QString shellCommand() const;\n\tvirtual bool setShellCommand(const QString & a_command);\n\n\tvirtual JobState state() const;\n\tvirtual bool setState(JobState a_state);\n\n\tvirtual std::vector<QUuid> dependsOnJobIds() const;\n\tvirtual bool setDependsOnJobIds(const std::vector<QUuid> & a_ids);\n\n\tvirtual QString subject() const;\n\n\tvirtual int firstFrame() const;\n\tvirtual bool setFirstFrame(int a_frame);\n\n\tvirtual int lastFrame() const;\n\tvirtual bool setLastFrame(int a_frame);\n\n\tvirtual int framesProcessed() const;\n\tvirtual int framesTotal() const;\n\tvirtual double fps() const;\n\tvirtual double secondsToFinish() const;\n\n\tvirtual size_t framesInQueue() const;\n\tvirtual size_t framesInProcess() const;\n\tvirtual size_t maxThreads() const;\n\n\tvirtual JobProperties properties() const;\n\tvirtual bool setProperties(const JobProperties & a_properties);\n\n\tvirtual const VSVideoInfo * videoInfo() const;\n\n\tvirtual bool initialize();\n\n\tvirtual void cleanUpEncoding();\n\npublic slots:\n\n\tvirtual void start();\n\tvirtual void pause();\n\tvirtual void abort();\n\nsignals:\n\n\tvoid signalPropertiesChanged();\n\tvoid signalStateChanged(JobState a_newState, JobState a_oldState);\n\tvoid signalProgressChanged();\n\tvoid signalStartTimeChanged();\n\tvoid signalEndTimeChanged();\n\n\tvoid signalLogMessage(const QString & a_message,\n\t\tconst QString & a_style = LOG_STYLE_DEFAULT);\n\nprotected slots:\n\n\tvirtual void slotProcessStarted();\n\tvirtual void slotProcessFinished(int a_exitCode,\n\t\tQProcess::ExitStatus a_exitStatus);\n\tvirtual void slotProcessError(QProcess::ProcessError a_error);\n\tvirtual void slotProcessReadChannelFinished();\n\tvirtual void slotProcessBytesWritten(qint64 a_bytes);\n\tvirtual void slotProcessReadyReadStandardError();\n\n\tvirtual void slotWriteLogMessage(int a_messageType,\n\t\tconst QString & a_message);\n\tvirtual void slotFrameQueueStateChanged(size_t a_inQueue,\n\t\tsize_t a_inProcess, size_t a_maxThreads, double a_usedCacheRatio);\n\tvirtual void slotScriptProcessorFinalized();\n\tvirtual void slotReceiveFrame(int a_frameNumber, int a_outputIndex,\n\t\tconst VSFrame * a_cpOutputFrame,\n\t\tconst VSFrame * a_cpPreviewFrame);\n\tvirtual void slotFrameRequestDiscarded(int a_frameNumber,\n\t\tint a_outputIndex, const QString & a_reason);\n\nprotected:\n\n\tvirtual void fillVariables() override;\n\n\tvirtual void changeStateAndNotify(JobState a_state);\n\n\tvirtual void startEncodeScriptCLI();\n\tvirtual void startRunProcess();\n\tvirtual void startRunShellCommand();\n\n\tvirtual QString decodeArguments(const QString & a_arguments) const;\n\n\tvirtual void clearFramesCache();\n\n\tvirtual void processFramesQueue();\n\n\tvirtual void finishEncodingCLI();\n\n\tvirtual void memorizeEncodingTime();\n\n\tvirtual void updateFPS();\n\n\tvirtual double currentEncodingRangeTime() const;\n\n\tJobProperties m_properties;\n\n\tQProcess m_process;\n\n\tstd::vector<char> m_framebuffer;\n\n\tint m_lastFrameProcessed;\n\tint m_lastFrameRequested;\n\n\tEncodingState m_encodingState;\n\n\tsize_t m_bytesToWrite;\n\tsize_t m_bytesWritten;\n\n\tSettingsManagerCore * m_pSettingsManager;\n\n\tVSScriptLibrary * m_pVSScriptLibrary;\n\n\tVapourSynthScriptProcessor * m_pVapourSynthScriptProcessor;\n\n\tconst VSAPI * m_cpVSAPI;\n\n\tconst VSVideoInfo * m_cpVideoInfo;\n\n\tFrameHeaderWriter * m_pFrameHeaderWriter;\n\n\tstd::list<Frame> m_framesCache;\n\tsize_t m_cachedFramesLimit;\n\n\tsize_t m_framesInQueue;\n\tsize_t m_framesInProcess;\n\tsize_t m_maxThreads;\n\n\thr_time_point m_encodeRangeStartTime;\n\tdouble m_memorizedEncodingTime;\n};\n\n}\n\n#endif // JOB_H_INCLUDED\n"
  },
  {
    "path": "common-src/jobs/job_variables.cpp",
    "content": "#include \"job_variables.h\"\n\n#include <QObject>\n\n//==============================================================================\n\nconst QString JobVariables::TOKEN_WIDTH = \"{w}\";\nconst QString JobVariables::TOKEN_HEIGHT = \"{h}\";\nconst QString JobVariables::TOKEN_FPS_NUMERATOR = \"{fpsn}\";\nconst QString JobVariables::TOKEN_FPS_DENOMINATOR = \"{fpsd}\";\nconst QString JobVariables::TOKEN_FPS = \"{fps}\";\nconst QString JobVariables::TOKEN_BITDEPTH = \"{bits}\";\nconst QString JobVariables::TOKEN_SCRIPT_DIRECTORY = \"{sd}\";\nconst QString JobVariables::TOKEN_SCRIPT_NAME = \"{sn}\";\nconst QString JobVariables::TOKEN_FRAMES_NUMBER = \"{f}\";\nconst QString JobVariables::TOKEN_SUBSAMPLING = \"{ss}\";\n\n//==============================================================================\n\nJobVariables::JobVariables()\n{\n\tfillVariables();\n}\n\n// END OF JobVariables::JobVariables()\n//==============================================================================\n\nstd::vector<vsedit::VariableToken> JobVariables::variables() const\n{\n\tstd::vector<vsedit::VariableToken> cutVariables;\n\tfor(const vsedit::VariableToken & variable : m_variables)\n\t{\n\t\tvsedit::VariableToken cutVariable =\n\t\t\t{variable.token, variable.description, std::function<QString()>()};\n\t\tcutVariables.push_back(cutVariable);\n\t}\n\treturn cutVariables;\n}\n\n// END OF std::vector<vsedit::VariableToken> JobVariables::variables() const\n//==============================================================================\n\nvoid JobVariables::fillVariables()\n{\n\tm_variables =\n\t{\n\t\t{TOKEN_WIDTH, QObject::tr(\"video width\"),\n\t\t\tstd::function<QString()>()},\n\t\t{TOKEN_HEIGHT, QObject::tr(\"video height\"),\n\t\t\tstd::function<QString()>()},\n\t\t{TOKEN_FPS_NUMERATOR, QObject::tr(\"video framerate numerator\"),\n\t\t\tstd::function<QString()>()},\n\t\t{TOKEN_FPS_DENOMINATOR, QObject::tr(\"video framerate denominator\"),\n\t\t\tstd::function<QString()>()},\n\t\t{TOKEN_FPS, QObject::tr(\"video framerate as fraction\"),\n\t\t\tstd::function<QString()>()},\n\t\t{TOKEN_BITDEPTH, QObject::tr(\"video colour bitdepth\"),\n\t\t\tstd::function<QString()>()},\n\t\t{TOKEN_SCRIPT_DIRECTORY, QObject::tr(\"script directory\"),\n\t\t\tstd::function<QString()>()},\n\t\t{TOKEN_SCRIPT_NAME, QObject::tr(\"script name without extension\"),\n\t\t\tstd::function<QString()>()},\n\t\t{TOKEN_FRAMES_NUMBER, QObject::tr(\"total frames number\"),\n\t\t\tstd::function<QString()>()},\n\t\t{TOKEN_SUBSAMPLING, QObject::tr(\"subsampling string (like 420)\"),\n\t\t\tstd::function<QString()>()},\n\t};\n\n\tstd::sort(m_variables.begin(), m_variables.end(),\n\t\t[&](const vsedit::VariableToken & a_first,\n\t\t\tconst vsedit::VariableToken & a_second) -> bool\n\t\t{\n\t\t\treturn (a_first.token.length() > a_second.token.length());\n\t\t});\n}\n\n// END OF void JobVariables::fillVariables()\n//==============================================================================\n"
  },
  {
    "path": "common-src/jobs/job_variables.h",
    "content": "#ifndef JOB_VARIABLES_H_INCLUDED\n#define JOB_VARIABLES_H_INCLUDED\n\n#include \"../helpers.h\"\n\n#include <functional>\n#include <vector>\n\nclass JobVariables\n{\npublic:\n\n\tJobVariables();\n\n\tvirtual std::vector<vsedit::VariableToken> variables() const;\n\nprotected:\n\n\tstatic const QString TOKEN_WIDTH;\n\tstatic const QString TOKEN_HEIGHT;\n\tstatic const QString TOKEN_FPS_NUMERATOR;\n\tstatic const QString TOKEN_FPS_DENOMINATOR;\n\tstatic const QString TOKEN_FPS;\n\tstatic const QString TOKEN_BITDEPTH;\n\tstatic const QString TOKEN_SCRIPT_DIRECTORY;\n\tstatic const QString TOKEN_SCRIPT_NAME;\n\tstatic const QString TOKEN_FRAMES_NUMBER;\n\tstatic const QString TOKEN_SUBSAMPLING;\n\n\tvirtual void fillVariables();\n\n\tstd::vector<vsedit::VariableToken> m_variables;\n};\n\n#endif // JOB_VARIABLES_H_INCLUDED\n"
  },
  {
    "path": "common-src/libp2p/COPYING",
    "content": "            DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE\n                    Version 2, December 2004\n\n Copyright (C) 2004 Sam Hocevar <sam@hocevar.net>\n\n Everyone is permitted to copy and distribute verbatim or modified\n copies of this license document, and changing it is allowed as long\n as the name is changed.\n\n            DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE\n   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION\n\n  0. You just DO WHAT THE FUCK YOU WANT TO.\n\n"
  },
  {
    "path": "common-src/libp2p/README.md",
    "content": "# libp2p\nPack/unpack pixels.\n\nThe \"p2p\" library implements conversion between packed and planar image\nformats. A packed format is any memory layout that stores more than one image\ncomponent (\"plane\") in a single array. For example, the common ARGB format\nstores pixels as an array of DWORDs holding all components for each pixel. In\ncontrast, a planar format stores each image component in its own array.\n\nBuilding\n------\nlibp2p is intended for embedding within other libraries and applications. The\nheader \"p2p.h\" contains a template library for generating packing and unpacking\nroutines, which can be used to instantiate functions for various pixel formats.\n\"v210.cpp\" holds a special-case implementation for the Apple ProRes \"v210\"\nformat. \"p2p_api.h\" and \"p2p_api.cpp\" implement a \"C\" wrapper for a fixed set\nof commonly encountered packed formats. If the \"C\" wrapper is used from another\nlibrary, a method to control symbol visibility should be used to prevent name\nconflicts with other, potentially incompatible, instances of libp2p.\n"
  },
  {
    "path": "common-src/libp2p/p2p.h",
    "content": "#ifndef P2P_H_\n#define P2P_H_\n\n#include <cstddef>\n#include <cstdint>\n#include <climits>\n#include <type_traits>\n#ifdef P2P_SIMD\n#include <typeinfo>\n#endif\n\n#ifdef _WIN32\n  #include <stdlib.h> // _byteswap_x\n#endif\n\n#ifdef P2P_USER_NAMESPACE\n  #define P2P_NAMESPACE P2P_USER_NAMESPACE\n#else\n  #define P2P_NAMESPACE p2p\n#endif\n\n#ifdef _WIN32\n  #define P2P_LITTLE_ENDIAN\n#elif defined(__BYTE_ORDER__)\n  #if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__\n    #define P2P_BIG_ENDIAN\n  #elif __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__\n    #define P2P_LITTLE_ENDIAN\n  #endif\n#endif\n\nstatic_assert(CHAR_BIT == 8, \"8-bit char required\");\n\nnamespace P2P_NAMESPACE {\n\n// Tag types for endian.\nstruct little_endian_t {};\nstruct big_endian_t {};\n\n#if defined(P2P_BIG_ENDIAN)\n  typedef big_endian_t native_endian_t;\n#elif defined(P2P_LITTLE_ENDIAN)\n  typedef little_endian_t native_endian_t;\n#else\n  #error wrong endian\n#endif\n\n#undef P2P_BIG_ENDIAN\n#undef P2P_LITTLE_ENDIAN\n\nnamespace detail {\n\n// Size of object in bits.\ntemplate <class T>\nstruct bit_size {\n\tstatic const size_t value = sizeof(T) * CHAR_BIT;\n};\n\n\n// Make integers from bytes.\nconstexpr uint16_t make_u16(uint8_t a, uint8_t b)\n{\n\treturn (a << 8) | b;\n}\n\nconstexpr uint32_t make_u32(uint8_t a, uint8_t b, uint8_t c, uint8_t d)\n{\n\treturn (static_cast<uint32_t>(make_u16(a, b)) << 16) | make_u16(c, d);\n}\n\nconstexpr uint64_t make_u64(uint8_t a, uint8_t b, uint8_t c, uint8_t d, uint8_t e, uint8_t f, uint8_t g, uint8_t h)\n{\n\treturn (static_cast<uint64_t>(make_u32(a, b, c, d)) << 32) | make_u32(e, f, g, h);\n}\n\ntemplate <class T>\nconstexpr uint8_t get_u8(T x, unsigned i)\n{\n\treturn static_cast<uint8_t>((x >> (bit_size<T>::value - 8 * i - 8)) & 0xFF);\n}\n\n\n// Fake 24 and 48-bit integers.\nstruct uint24 {\n\tuint8_t x[3];\n\n\tuint24() = default;\n\n\tconstexpr uint24(uint8_t a, uint8_t b, uint8_t c) : x{ a, b, c }\n\t{\n\t}\n\n\ttemplate <class T = native_endian_t>\n\texplicit constexpr uint24(uint32_t val,\n\t                          typename std::enable_if<std::is_same<T, big_endian_t>::value>::type * = 0) :\n\t\tx{ get_u8(val, 1), get_u8(val, 2), get_u8(val, 3) }\n\t{\n\t}\n\n\ttemplate <class T = native_endian_t>\n\texplicit constexpr uint24(uint32_t val,\n\t                          typename std::enable_if<std::is_same<T, little_endian_t>::value>::type * = 0) :\n\t\tx{ get_u8(val, 3), get_u8(val, 2), get_u8(val, 1) }\n\t{\n\t}\n\n\ttemplate <class T = native_endian_t,\n\t          typename std::enable_if<std::is_same<T, big_endian_t>::value>::type * = nullptr>\n\tconstexpr uint32_t to_u32() const\n\t{\n\t\treturn make_u32(0, x[0], x[1], x[2]);\n\t}\n\n\ttemplate <class T = native_endian_t,\n\t          typename std::enable_if<std::is_same<T, little_endian_t>::value>::type * = nullptr>\n\tconstexpr uint32_t to_u32() const\n\t{\n\t\treturn make_u32(0, x[2], x[1], x[0]);\n\t}\n\n\tconstexpr operator uint32_t() const { return to_u32(); }\n};\n\nstruct uint48 {\n\tuint8_t x[6];\n\n\tuint48() = default;\n\n\tconstexpr uint48(uint8_t a, uint8_t b, uint8_t c, uint8_t d, uint8_t e, uint8_t f) : x{ a, b, c, d, e, f }\n\t{\n\t}\n\n\ttemplate <class T = native_endian_t>\n\texplicit constexpr uint48(uint64_t val,\n\t                          typename std::enable_if<std::is_same<T, big_endian_t>::value>::type * = 0) :\n\t\tx{ get_u8(val, 2), get_u8(val, 3), get_u8(val, 4), get_u8(val, 5), get_u8(val, 6), get_u8(val, 7) }\n\t{\n\t}\n\n\ttemplate <class T = native_endian_t>\n\texplicit constexpr uint48(uint64_t val,\n\t                          typename std::enable_if<std::is_same<T, little_endian_t>::value>::type * = 0) :\n\t\tx{ get_u8(val, 7), get_u8(val, 6), get_u8(val, 5), get_u8(val, 4), get_u8(val, 3), get_u8(val, 2) }\n\t{\n\t}\n\n\ttemplate <class T = native_endian_t,\n\t          typename std::enable_if<std::is_same<T, big_endian_t>::value>::type * = nullptr>\n\tconstexpr uint64_t to_u64() const\n\t{\n\t\treturn make_u64(0, 0, x[0], x[1], x[2], x[3], x[4], x[5]);\n\t}\n\n\ttemplate <class T = native_endian_t,\n\t          typename std::enable_if<std::is_same<T, little_endian_t>::value>::type * = nullptr>\n\tconstexpr uint64_t to_u64() const\n\t{\n\t\treturn make_u64(0, 0, x[5], x[4], x[3], x[2], x[1], x[0]);\n\t}\n\n\tconstexpr operator uint64_t() const { return to_u64(); }\n};\n\nstatic_assert(std::is_pod<uint24>::value, \"uint24 must be POD\");\nstatic_assert(std::is_pod<uint48>::value, \"uint48 must be POD\");\nstatic_assert(sizeof(uint24) == 3, \"uint24 must not have padding\");\nstatic_assert(sizeof(uint48) == 6, \"uint48 must not have padding\");\n\n\n// Endian conversions.\ntemplate <class Endian, class T,\n          typename std::enable_if<std::is_same<Endian, native_endian_t>::value>::type * = nullptr>\nT endian_swap(T x)\n{\n\treturn x;\n}\n\ntemplate <class Endian,\n          typename std::enable_if<!std::is_same<Endian, native_endian_t>::value>::type * = nullptr>\nuint16_t endian_swap(uint16_t x)\n{\n#ifdef _WIN32\n\treturn _byteswap_ushort(x);\n#else\n\treturn __builtin_bswap16(x);\n#endif\n}\n\ntemplate <class Endian,\n          typename std::enable_if<!std::is_same<Endian, native_endian_t>::value>::type * = nullptr>\nuint32_t endian_swap(uint32_t x)\n{\n#ifdef _WIN32\n\treturn _byteswap_ulong(x);\n#else\n\treturn __builtin_bswap32(x);\n#endif\n}\n\ntemplate <class Endian,\n          typename std::enable_if<!std::is_same<Endian, native_endian_t>::value>::type * = nullptr>\nuint64_t endian_swap(uint64_t x)\n{\n#ifdef _WIN32\n\treturn _byteswap_uint64(x);\n#else\n\treturn __builtin_bswap64(x);\n#endif\n}\n\ntemplate <class Endian,\n          typename std::enable_if<!std::is_same<Endian, native_endian_t>::value>::type * = nullptr>\nuint24 endian_swap(uint24 x)\n{\n\treturn{ x.x[2], x.x[1], x.x[0] };\n}\n\ntemplate <class Endian,\n          typename std::enable_if<!std::is_same<Endian, native_endian_t>::value>::type * = nullptr>\nuint48 endian_swap(uint48 x)\n{\n\treturn{ x.x[5], x.x[4], x.x[3], x.x[2], x.x[1], x.x[0] };\n}\n\n\n// Treat u32 as array of u8.\nstruct mask4 {\n\tuint32_t x;\n\n\tconstexpr uint8_t operator[](unsigned i) const { return get_u8(x, i); }\n\tconstexpr bool contains(unsigned val) const\n\t{\n\t\treturn (*this)[0] == val || (*this)[1] == val || (*this)[2] == val || (*this)[3] == val;\n\t}\n\tconstexpr unsigned find(uint8_t val) const\n\t{\n\t\treturn (*this)[0] == val ? 0 : (*this)[1] == val ? 1 : (*this)[2] == val ? 2 : (*this)[3] == val ? 3 : ~0U;\n\t}\n};\n\n\n// Native integer type for arithmetic.\ntemplate <class T>\nstruct numeric_type {\n\ttypedef T type;\n};\n\ntemplate <>\nstruct numeric_type<uint24> {\n\ttypedef uint32_t type;\n};\n\ntemplate <>\nstruct numeric_type<uint48> {\n\ttypedef uint64_t type;\n};\n\n} // namespace detail\n\n\nenum {\n\tC_Y = 0,\n\tC_U = 1,\n\tC_V = 2,\n\tC_R = 0,\n\tC_G = 1,\n\tC_B = 2,\n\tC_A = 3,\n\tC__ = 0xFF,\n};\n\n\n// Packed integer constants for template parameters.\nconstexpr uint32_t make_mask(uint8_t x)\n{\n\treturn detail::make_u32(x, x, x, x);\n}\n\nconstexpr uint32_t make_mask(uint8_t a, uint8_t b, uint8_t c, uint8_t d)\n{\n\treturn detail::make_u32(a, b, c, d);\n}\n\n\n// Select type by endian.\ntemplate <class Big, class Little>\nstruct endian_select {\n\ttypedef typename std::conditional<std::is_same<native_endian_t, big_endian_t>::value, Big, Little>::type type;\n};\n\n\ntemplate <class Planar,\n          class Packed,\n          class Endian,\n          unsigned PelPerPack,\n          unsigned Subsampling,\n          uint32_t ComponentMask,\n          uint32_t ShiftMask,\n          uint32_t DepthMask>\nstruct pack_traits {\n\tstatic_assert(std::is_pod<Planar>::value, \"must be POD\");\n\tstatic_assert(std::is_pod<Packed>::value, \"must be POD\");\n\n\ttypedef Planar planar_type;\n\ttypedef Packed packed_type;\n\ttypedef Endian endian;\n\n\tstatic const unsigned pel_per_pack = PelPerPack;\n\tstatic const unsigned subsampling = Subsampling;\n\n\tstatic constexpr detail::mask4 component_mask{ ComponentMask };\n\tstatic constexpr detail::mask4 shift_mask{ ShiftMask };\n\tstatic constexpr detail::mask4 depth_mask{ DepthMask };\n};\n\ntemplate <class Planar, class Packed, class Endian, unsigned PelPerPack, unsigned Subsampling, uint32_t ComponentMask, uint32_t ShiftMask, uint32_t DepthMask>\nconstexpr detail::mask4 pack_traits<Planar, Packed, Endian, PelPerPack, Subsampling, ComponentMask, ShiftMask, DepthMask>::component_mask;\n\ntemplate <class Planar, class Packed, class Endian, unsigned PelPerPack, unsigned Subsampling, uint32_t ComponentMask, uint32_t ShiftMask, uint32_t DepthMask>\nconstexpr detail::mask4 pack_traits<Planar, Packed, Endian, PelPerPack, Subsampling, ComponentMask, ShiftMask, DepthMask>::shift_mask;\n\ntemplate <class Planar, class Packed, class Endian, unsigned PelPerPack, unsigned Subsampling, uint32_t ComponentMask, uint32_t ShiftMask, uint32_t DepthMask>\nconstexpr detail::mask4 pack_traits<Planar, Packed, Endian, PelPerPack, Subsampling, ComponentMask, ShiftMask, DepthMask>::depth_mask;\n\n\n// Base template for 4:4:4 packings.\n//\n// Much literature treats 4:4:4 triplets as single machine words, implying a\n// reversed component order on LE and BE.\n//\n// The _be and _le templates accept a component mask beginning from the MSB of\n// the packed word to accomodate this.\ntemplate <class Planar, class Packed, uint32_t ComponentMask>\nusing byte_packed_444_be = pack_traits<\n\tPlanar, Packed, big_endian_t, 1, 0,\n\tComponentMask,\n\tmake_mask(3, 2, 1, 0) * detail::bit_size<Planar>::value,\n\tmake_mask(detail::bit_size<Planar>::value)>;\n\ntemplate <class Planar, class Packed, uint32_t ComponentMask>\nusing byte_packed_444_le = pack_traits<\n\tPlanar, Packed, little_endian_t, 1, 0,\n\tComponentMask,\n\tmake_mask(3, 2, 1, 0) * detail::bit_size<Planar>::value,\n\tmake_mask(detail::bit_size<Planar>::value)>;\n\n// Common 444 packings.\nusing packed_rgb24_be = byte_packed_444_be<uint8_t, detail::uint24, make_mask(C__, C_R, C_G, C_B)>;\nusing packed_rgb24_le = byte_packed_444_le<uint8_t, detail::uint24, make_mask(C__, C_R, C_G, C_B)>;\nusing packed_rgb24 = endian_select<packed_rgb24_be, packed_rgb24_le>::type;\n\nusing packed_argb32_be = byte_packed_444_be<uint8_t, uint32_t, make_mask(C_A, C_R, C_G, C_B)>;\nusing packed_argb32_le = byte_packed_444_le<uint8_t, uint32_t, make_mask(C_A, C_R, C_G, C_B)>;\nusing packed_argb32 = endian_select<packed_argb32_be, packed_argb32_le>::type;\n\nusing packed_ayuv_be = packed_argb32_be;\nusing packed_ayuv_le = packed_argb32_le;\nusing packed_ayuv = packed_argb32;\n\nusing packed_rgb48_be = byte_packed_444_be<uint16_t, detail::uint48, make_mask(C__, C_R, C_G, C_B)>;\nusing packed_rgb48_le = byte_packed_444_le<uint16_t, detail::uint48, make_mask(C__, C_R, C_G, C_B)>;\nusing packed_rgb48 = endian_select<packed_rgb48_be, packed_rgb48_le>::type;\n\nusing packed_argb64_be = byte_packed_444_be<uint16_t, uint64_t, make_mask(C_A, C_R, C_G, C_B)>;\nusing packed_argb64_le = byte_packed_444_le<uint16_t, uint64_t, make_mask(C_A, C_R, C_G, C_B)>;\nusing packed_argb64 = endian_select<packed_argb64_be, packed_argb64_le>::type;\n\nusing packed_rgba32_be = byte_packed_444_be<uint8_t, uint32_t, make_mask(C_R, C_G, C_B, C_A)>;\nusing packed_rgba32_le = byte_packed_444_le<uint8_t, uint32_t, make_mask(C_R, C_G, C_B, C_A)>;\nusing packed_rgba32 = endian_select<packed_rgba32_be, packed_rgba32_le>::type;\n\nusing packed_rgba64_be = byte_packed_444_be<uint16_t, uint64_t, make_mask(C_R, C_G, C_B, C_A)>;\nusing packed_rgba64_le = byte_packed_444_le<uint16_t, uint64_t, make_mask(C_R, C_G, C_B, C_A)>;\nusing packed_rgba64 = endian_select<packed_rgba64_be, packed_rgba64_le>::type;\n\nusing packed_abgr64_be = byte_packed_444_be<uint16_t, uint64_t, make_mask(C_A, C_B, C_G, C_R)>;\nusing packed_abgr64_le = byte_packed_444_le<uint16_t, uint64_t, make_mask(C_A, C_B, C_G, C_R)>;\nusing packed_abgr64 = endian_select<packed_abgr64_be, packed_abgr64_le>::type;\n\nusing packed_bgr48_be = byte_packed_444_be<uint16_t, detail::uint48, make_mask(C__, C_B, C_G, C_R)>;\nusing packed_bgr48_le = byte_packed_444_le<uint16_t, detail::uint48, make_mask(C__, C_B, C_G, C_R)>;\nusing packed_bgr48 = endian_select<packed_bgr48_be, packed_bgr48_le>::type;\n\nusing packed_bgra64_be = byte_packed_444_be<uint16_t, uint64_t, make_mask(C_B, C_G, C_R, C_A)>;\nusing packed_bgra64_le = byte_packed_444_le<uint16_t, uint64_t, make_mask(C_B, C_G, C_R, C_A)>;\nusing packed_bgra64 = endian_select<packed_bgra64_be, packed_bgra64_le>::type;\n\n// D3D A2R10G10B10.\nusing packed_rgb30_be = pack_traits<\n\tuint16_t, uint32_t, big_endian_t, 1, 0,\n\tmake_mask(C_A, C_R, C_G, C_B),\n\tmake_mask(30, 20, 10, 0),\n\tmake_mask(2, 10, 10, 10)>;\nusing packed_rgb30_le = pack_traits<\n\tuint16_t, uint32_t, little_endian_t, 1, 0,\n\tmake_mask(C_A, C_R, C_G, C_B),\n\tmake_mask(30, 20, 10, 0),\n\tmake_mask(2, 10, 10, 10)>;\nusing packed_rgb30 = endian_select<packed_rgb30_be, packed_rgb30_le>::type;\n\n// MS Y410 and Y416 formats.\nusing packed_y410_be = pack_traits<\n\tuint16_t, uint32_t, big_endian_t, 1, 0,\n\tmake_mask(C_A, C_V, C_Y, C_U),\n\tmake_mask(30, 20, 10, 0),\n\tmake_mask(2, 10, 10, 10)>;\nusing packed_y410_le = pack_traits<\n\tuint16_t, uint32_t, little_endian_t, 1, 0,\n\tmake_mask(C_A, C_V, C_Y, C_U),\n\tmake_mask(30, 20, 10, 0),\n\tmake_mask(2, 10, 10, 10)>;\nusing packed_y410 = endian_select<packed_y410_be, packed_y410_le>::type;\n\nusing packed_y416_be = byte_packed_444_be<uint16_t, uint64_t, make_mask(C_A, C_V, C_Y, C_U)>;\nusing packed_y416_le = byte_packed_444_le<uint16_t, uint64_t, make_mask(C_A, C_V, C_Y, C_U)>;\nusing packed_y416 = endian_select<packed_y416_be, packed_y416_le>::type;\n\n\n// Base template for YUY2-like 4:2:2 packings.\n//\n// The component order in both BE and LE is the same. Only the bytes of the\n// individual component words are reversed.\n//\n// The _be and _le templates accept a component mask beginning from the low\n// memory address of the packed word to accomodate this.\ntemplate <class Planar, class Packed, uint32_t ComponentMask, unsigned ExtraShift = 0>\nusing byte_packed_422_be = pack_traits<\n\tPlanar, Packed, big_endian_t, 2, 1,\n\tComponentMask,\n\tmake_mask(3, 2, 1, 0) * detail::bit_size<Planar>::value + make_mask(ExtraShift),\n\tmake_mask(detail::bit_size<Planar>::value) - make_mask(ExtraShift)>;\n\ntemplate <class Planar, class Packed, uint32_t ComponentMask, unsigned ExtraShift = 0>\nusing byte_packed_422_le = pack_traits<\n\tPlanar, Packed, little_endian_t, 2, 1,\n\tComponentMask,\n\tmake_mask(0, 1, 2, 3) * detail::bit_size<Planar>::value + make_mask(ExtraShift),\n\tmake_mask(detail::bit_size<Planar>::value) - make_mask(ExtraShift)>;\n\n// YUY2.\nusing packed_yuy2 = byte_packed_422_be<uint8_t, uint32_t, make_mask(C_Y, C_U, C_Y, C_V)>;\nusing packed_uyvy = byte_packed_422_be<uint8_t, uint32_t, make_mask(C_U, C_Y, C_V, C_Y)>;\n\n// MS Y210 and Y216 formats.\nusing packed_y210_be = byte_packed_422_be<uint16_t, uint64_t, make_mask(C_Y, C_U, C_Y, C_V), 6>;\nusing packed_y210_le = byte_packed_422_le<uint16_t, uint64_t, make_mask(C_Y, C_U, C_Y, C_V), 6>;\nusing packed_y210 = endian_select<packed_y210_be, packed_y210_le>::type;\n\nusing packed_y216_be = byte_packed_422_be<uint16_t, uint64_t, make_mask(C_Y, C_U, C_Y, C_V)>;\nusing packed_y216_le = byte_packed_422_le<uint16_t, uint64_t, make_mask(C_Y, C_U, C_Y, C_V)>;\nusing packed_y216 = endian_select<packed_y216_be, packed_y216_le>::type;\n\n// Apple v210 format. Handled by special-case code. Only the LE ordering is found in Qt files.\nstruct packed_v210_be {};\nstruct packed_v210_le {};\nusing packed_v210 = endian_select<packed_v210_le, packed_v210_be>::type;\n\n// Apple v216 format. Only the LE ordering is found in Qt files.\nusing packed_v216_be = byte_packed_422_be<uint16_t, uint64_t, make_mask(C_U, C_Y, C_V, C_Y)>;\nusing packed_v216_le = byte_packed_422_le<uint16_t, uint64_t, make_mask(C_U, C_Y, C_V, C_Y)>;\nusing packed_v216 = endian_select<packed_v216_le, packed_v216_be>::type;\n\n\n// Base template for chroma-interleaved half packings.\n//\n// The literature treats UV pairs as single machine words, implying a reversed\n// component order between BE and LE.\ntemplate <class Planar, class Packed, unsigned ExtraShift = 0>\nusing byte_packed_nv_be = pack_traits<\n\tPlanar, Packed, big_endian_t, 2, 1,\n\tmake_mask(C__, C__, C_V, C_U),\n\tmake_mask(0, 0, 1, 0) * detail::bit_size<Planar>::value + make_mask(ExtraShift),\n\tmake_mask(detail::bit_size<Planar>::value) - make_mask(ExtraShift)>;\n\ntemplate <class Planar, class Packed, unsigned ExtraShift = 0>\nusing byte_packed_nv_le = pack_traits<\n\tPlanar, Packed, little_endian_t, 2, 1,\n\tmake_mask(C__, C__, C_V, C_U),\n\tmake_mask(0, 0, 1, 0) * detail::bit_size<Planar>::value + make_mask(ExtraShift),\n\tmake_mask(detail::bit_size<Planar>::value) - make_mask(ExtraShift)>;\n\nusing packed_nv12_be = byte_packed_nv_be<uint8_t, uint16_t>; // AKA NV21.\nusing packed_nv12_le = byte_packed_nv_le<uint8_t, uint16_t>;\nusing packed_nv12 = endian_select<packed_nv12_be, packed_nv12_le>::type;\n\n// MS P010, P016, P210, and P216 formats.\nusing packed_p010_be = byte_packed_nv_be<uint16_t, uint32_t, 6>;\nusing packed_p010_le = byte_packed_nv_le<uint16_t, uint32_t, 6>;\nusing packed_p010 = endian_select<packed_p010_be, packed_p010_le>::type;\n\nusing packed_p016_be = byte_packed_nv_be<uint16_t, uint32_t>;\nusing packed_p016_le = byte_packed_nv_le<uint16_t, uint32_t>;\nusing packed_p016 = endian_select<packed_p016_be, packed_p016_le>::type;\n\nusing packed_p210_be = packed_p010_be;\nusing packed_p210_le = packed_p010_le;\nusing packed_p210 = packed_p010;\n\nusing packed_p216_be = packed_p016_be;\nusing packed_p216_le = packed_p016_le;\nusing packed_p216 = packed_p016;\n\n\n#ifdef P2P_SIMD\nnamespace detail {\n\n// Runtime function dispatch.\ntypedef void (*unpack_func)(const void *, void * const *, unsigned, unsigned);\ntypedef void (*pack_func)(const void * const *, void *, unsigned, unsigned);\n\nunpack_func search_unpack_func(const std::type_info &ti);\npack_func search_pack_func(const std::type_info &ti, bool alpha_one_fill);\n\ntemplate <class Traits>\nunpack_func search_unpack_func(unpack_func default_func)\n{\n\tunpack_func func = search_unpack_func(typeid(Traits));\n\treturn func ? func : default_func;\n}\n\ntemplate <class Traits, bool AlphaOneFill>\npack_func search_pack_func(pack_func default_func)\n{\n\tpack_func func = search_pack_func(typeid(Traits), AlphaOneFill);\n\treturn func ? func : default_func;\n}\n\n} // namespace detail\n#endif // P2P_SIMD\n\n\n// Conversions.\ntemplate <class Traits>\nclass packed_to_planar {\n\ttypedef typename Traits::planar_type planar_type;\n\ttypedef typename Traits::packed_type packed_type;\n\ttypedef typename detail::numeric_type<packed_type>::type numeric_type;\n\n\ttypedef typename Traits::endian endian;\n\n#ifdef P2P_SIMD\n\tstatic detail::unpack_func s_delegate;\n#endif\n\n\tstatic numeric_type get_mask(unsigned c)\n\t{\n\t\treturn ~static_cast<numeric_type>(0) >> (detail::bit_size<numeric_type>::value - Traits::depth_mask[c]);\n\t}\n\n\tstatic planar_type get_component(numeric_type x, unsigned c)\n\t{\n\t\treturn static_cast<planar_type>((x >> Traits::shift_mask[c]) & get_mask(c));\n\t}\n\n\tstatic void unpack_impl(const void *src, void * const dst[4], unsigned left, unsigned right)\n\t{\n\t\tconst packed_type *src_p = static_cast<const packed_type *>(src);\n\t\tplanar_type *dst_p[4] = {\n\t\t\tstatic_cast<planar_type *>(dst[0]), static_cast<planar_type *>(dst[1]),\n\t\t\tstatic_cast<planar_type *>(dst[2]), static_cast<planar_type *>(dst[3]),\n\t\t};\n\t\tbool alpha_enabled = dst[C_A] != nullptr;\n\n\t\t// Adjust pointers.\n\t\tsrc_p += left / Traits::pel_per_pack;\n\t\tdst_p[0] += Traits::component_mask.contains(0) ? left : 0;\n\t\tdst_p[1] += Traits::component_mask.contains(1) ? (left >> Traits::subsampling) : 0;\n\t\tdst_p[2] += Traits::component_mask.contains(2) ? (left >> Traits::subsampling) : 0;\n\t\tdst_p[3] += Traits::component_mask.contains(3) ? left : 0;\n\n#define P2P_COMPONENT_ENABLED(c) ((Traits::component_mask[c] != C__) && (Traits::component_mask[c] != C_A || alpha_enabled))\n\t\tfor (unsigned i = left; i < right; i += Traits::pel_per_pack) {\n\t\t\tnumeric_type x = detail::endian_swap<endian>(*src_p++);\n\n\t\t\tif (P2P_COMPONENT_ENABLED(0))\n\t\t\t\t*dst_p[Traits::component_mask[0]]++ = get_component(x, 0);\n\t\t\tif (P2P_COMPONENT_ENABLED(1))\n\t\t\t\t*dst_p[Traits::component_mask[1]]++ = get_component(x, 1);\n\t\t\tif (P2P_COMPONENT_ENABLED(2))\n\t\t\t\t*dst_p[Traits::component_mask[2]]++ = get_component(x, 2);\n\t\t\tif (P2P_COMPONENT_ENABLED(3))\n\t\t\t\t*dst_p[Traits::component_mask[3]]++ = get_component(x, 3);\n\t\t}\n#undef P2P_COMPONENT_ENABLED\n\t}\npublic:\n\tstatic void unpack(const void *src, void * const dst[4], unsigned left, unsigned right)\n\t{\n#ifdef P2P_SIMD\n\t\ts_delegate(src, dst, left, right);\n#else\n\t\tunpack_impl(src, dst, left, right);\n#endif\n\t}\n};\n\n#ifdef P2P_SIMD\ntemplate <class Traits>\ndetail::unpack_func packed_to_planar<Traits>::s_delegate = detail::search_unpack_func<Traits>(packed_to_planar::unpack_impl);\n#endif\n\n\ntemplate <class Traits, bool AlphaOneFill = false>\nclass planar_to_packed {\n\ttypedef typename Traits::planar_type planar_type;\n\ttypedef typename Traits::packed_type packed_type;\n\ttypedef typename detail::numeric_type<packed_type>::type numeric_type;\n\n\ttypedef typename Traits::endian endian;\n\n#ifdef P2P_SIMD\n\tstatic detail::pack_func s_delegate;\n#endif\n\n\tstatic numeric_type get_mask(unsigned c)\n\t{\n\t\treturn ~static_cast<numeric_type>(0) >> (detail::bit_size<numeric_type>::value - Traits::depth_mask[c]);\n\t}\n\n\tstatic numeric_type get_component(planar_type x, unsigned c)\n\t{\n\t\treturn (static_cast<numeric_type>(x) & get_mask(c)) << Traits::shift_mask[c];\n\t}\n\n\tstatic void pack_impl(const void * const src[4], void *dst, unsigned left, unsigned right)\n\t{\n\t\tconst planar_type *src_p[4] = {\n\t\t\tstatic_cast<const planar_type *>(src[0]), static_cast<const planar_type *>(src[1]),\n\t\t\tstatic_cast<const planar_type *>(src[2]), static_cast<const planar_type *>(src[3]),\n\t\t};\n\t\tpacked_type *dst_p = static_cast<packed_type *>(dst);\n\t\tbool alpha_enabled = src[C_A] != nullptr;\n\n\t\t// Adjust pointers.\n\t\tsrc_p[0] += Traits::component_mask.contains(0) ? left : 0;\n\t\tsrc_p[1] += Traits::component_mask.contains(1) ? (left >> Traits::subsampling) : 0;\n\t\tsrc_p[2] += Traits::component_mask.contains(2) ? (left >> Traits::subsampling) : 0;\n\t\tsrc_p[3] += Traits::component_mask.contains(3) ? left : 0;\n\t\tdst_p += left / Traits::pel_per_pack;\n\n#define P2P_COMPONENT_ENABLED(c) ((Traits::component_mask[c] != C__) && (Traits::component_mask[c] != C_A || alpha_enabled))\n\t\tfor (unsigned i = left; i < right; i += Traits::pel_per_pack) {\n\t\t\tnumeric_type x = 0;\n\n\t\t\tif (AlphaOneFill && Traits::component_mask.contains(C_A) && !alpha_enabled)\n\t\t\t\tx |= get_component(~static_cast<planar_type>(0), Traits::component_mask.find(C_A));\n\n\t\t\tif (P2P_COMPONENT_ENABLED(0))\n\t\t\t\tx |= get_component(*src_p[Traits::component_mask[0]]++, 0);\n\t\t\tif (P2P_COMPONENT_ENABLED(1))\n\t\t\t\tx |= get_component(*src_p[Traits::component_mask[1]]++, 1);\n\t\t\tif (P2P_COMPONENT_ENABLED(2))\n\t\t\t\tx |= get_component(*src_p[Traits::component_mask[2]]++, 2);\n\t\t\tif (P2P_COMPONENT_ENABLED(3))\n\t\t\t\tx |= get_component(*src_p[Traits::component_mask[3]]++, 3);\n\n\t\t\t*dst_p++ = detail::endian_swap<endian>(static_cast<packed_type>(x));\n\t\t}\n#undef P2P_COMPONENT_ENABLED\n\t}\npublic:\n\tstatic void pack(const void * const src[4], void *dst, unsigned left, unsigned right)\n\t{\n#ifdef P2P_SIMD\n\t\ts_delegate(src, dst, left, right);\n#else\n\t\tpack_impl(src, dst, left, right);\n#endif\n\t}\n};\n\n#ifdef P2P_SIMD\ntemplate <class Traits, bool AlphaOneFill>\ndetail::pack_func planar_to_packed<Traits, AlphaOneFill>::s_delegate = detail::search_pack_func<Traits, AlphaOneFill>(planar_to_packed::pack_impl);\n#endif\n\n\n// v210 specializations.\ntemplate <>\nclass packed_to_planar<packed_v210_be> {\npublic:\n\tstatic void unpack(const void *src, void * const dst[4], unsigned left, unsigned right);\n};\n\ntemplate <>\nclass packed_to_planar<packed_v210_le> {\npublic:\n\tstatic void unpack(const void *src, void * const dst[4], unsigned left, unsigned right);\n};\n\ntemplate <>\nclass planar_to_packed<packed_v210_be, false> {\npublic:\n\tstatic void pack(const void * const src[4], void *dst, unsigned left, unsigned right);\n};\n\ntemplate <>\nclass planar_to_packed<packed_v210_be, true> {\npublic:\n\tstatic void pack(const void * const src[4], void *dst, unsigned left, unsigned right);\n};\n\ntemplate <>\nclass planar_to_packed<packed_v210_le, false> {\npublic:\n\tstatic void pack(const void * const src[4], void *dst, unsigned left, unsigned right);\n};\n\ntemplate <>\nclass planar_to_packed<packed_v210_le, true> {\npublic:\n\tstatic void pack(const void * const src[4], void *dst, unsigned left, unsigned right);\n};\n\n} // namespace p2p\n\n#endif // P2P_H_\n"
  },
  {
    "path": "common-src/libp2p/p2p_api.cpp",
    "content": "#include <algorithm>\n#include <cassert>\n#include <cstring>\n#include \"p2p.h\"\n#include \"p2p_api.h\"\n\n#ifdef P2P_USER_NAMESPACE\n  #error API build must not use custom namespace\n#endif\n\nnamespace {\n\nstruct packing_traits {\n\tenum p2p_packing packing;\n\tp2p_unpack_func unpack;\n\tp2p_pack_func pack;\n\tp2p_pack_func pack_one_fill;\n\tbool native_endian;\n\tunsigned char subsample_w;\n\tunsigned char subsample_h;\n\tbool is_nv;\n\tunsigned char bytes_per_sample; // Only used to copy luma plane for NV12.\n\tunsigned char nv_shift; // Extra LSB to shift away for MS P010/P210, etc.\n};\n\n#define CASE(x, ...) \\\n\t{ p2p_##x, &p2p::packed_to_planar<p2p::packed_##x>::unpack, &p2p::planar_to_packed<p2p::packed_##x, false>::pack, &p2p::planar_to_packed<p2p::packed_##x, true>::pack, ##__VA_ARGS__ }\n#define CASE2(x, ...) \\\n\tCASE(x##_be, std::is_same<p2p::native_endian_t, p2p::big_endian_t>::value, ##__VA_ARGS__), \\\n\tCASE(x##_le, std::is_same<p2p::native_endian_t, p2p::little_endian_t>::value, ##__VA_ARGS__), \\\n\tCASE(x, true, ##__VA_ARGS__)\nconst packing_traits traits_table[] = {\n\tCASE2(rgb24, 0, 0),\n\tCASE2(argb32, 0, 0),\n\tCASE2(ayuv, 0, 0),\n\tCASE2(rgb48, 0, 0),\n\tCASE2(argb64, 0, 0),\n\tCASE2(rgb30, 0, 0),\n\tCASE2(y410, 0, 0),\n\tCASE2(y416, 0, 0),\n\tCASE(yuy2, true, 1, 0),\n\tCASE(uyvy, true, 1, 0),\n\tCASE2(y210, 1, 0),\n\tCASE2(y216, 1, 0),\n\tCASE2(v210, 1, 0),\n\tCASE2(v216, 1, 0),\n\tCASE2(nv12, 1, 1, true, 1),\n\tCASE2(p010, 1, 1, true, 2, 6),\n\tCASE2(p016, 1, 1, true, 2),\n\tCASE2(p210, 1, 0, true, 2, 6),\n\tCASE2(p216, 1, 0, true, 2),\n\tCASE2(rgba32, 0, 0),\n\tCASE2(rgba64, 0, 0),\n\tCASE2(abgr64, 0, 0),\n\tCASE2(bgr48, 0, 0),\n\tCASE2(bgra64, 0, 0),\n};\n#undef CASE2\n#undef CASE\n\nconst packing_traits &lookup_traits(enum p2p_packing packing)\n{\n\tassert(packing >= 0);\n\tassert(packing < sizeof(traits_table) / sizeof(traits_table[0]));\n\n\tconst packing_traits &traits = traits_table[packing];\n\tassert(traits.packing == packing);\n\tassert(traits.subsample_h == 0 || traits.is_nv);\n\treturn traits;\n}\n\ntemplate <class T>\nT *increment_ptr(T *ptr, ptrdiff_t n)\n{\n\treturn (T *)((const unsigned char *)ptr + n);\n}\n\nvoid copy_plane_fast(const void *src, void *dst, ptrdiff_t src_stride, ptrdiff_t dst_stride,\n                     unsigned linesize, unsigned height)\n{\n\tfor (unsigned i = 0; i < height; ++i) {\n\t\tmemcpy(dst, src, linesize);\n\n\t\tsrc = increment_ptr(src, src_stride);\n\t\tdst = increment_ptr(dst, dst_stride);\n\t}\n}\n\nvoid unpack_nv16_plane(const void *src, void *dst, ptrdiff_t src_stride, ptrdiff_t dst_stride,\n                       const packing_traits &traits, unsigned width, unsigned height)\n{\n\tassert(traits.bytes_per_sample == 2);\n\n\tfor (unsigned i = 0; i < height; ++i) {\n\t\tstd::transform(static_cast<const uint16_t *>(src), static_cast<const uint16_t *>(src) + width, static_cast<uint16_t *>(dst), [=](uint16_t x)\n\t\t{\n\t\t\tx = traits.native_endian ? x : (x >> 8) | (x << 8);\n\t\t\treturn x >> traits.nv_shift;\n\t\t});\n\n\t\tsrc = increment_ptr(src, src_stride);\n\t\tdst = increment_ptr(dst, dst_stride);\n\t}\n}\n\nvoid pack_nv16_plane(const void *src, void *dst, ptrdiff_t src_stride, ptrdiff_t dst_stride,\n                     const packing_traits &traits, unsigned width, unsigned height)\n{\n\tassert(traits.bytes_per_sample == 2);\n\n\tfor (unsigned i = 0; i < height; ++i) {\n\t\tstd::transform(static_cast<const uint16_t *>(src), static_cast<const uint16_t *>(src) + width, static_cast<uint16_t *>(dst), [=](uint16_t x)\n\t\t{\n\t\t\tx = x << traits.nv_shift;\n\t\t\treturn traits.native_endian ? x : (x >> 8) | (x << 8);\n\t\t});\n\n\t\tsrc = increment_ptr(src, src_stride);\n\t\tdst = increment_ptr(dst, dst_stride);\n\t}\n}\n\n} // namespace\n\n\np2p_unpack_func p2p_select_unpack_func(enum p2p_packing packing)\n{\n\treturn lookup_traits(packing).unpack;\n}\n\np2p_pack_func p2p_select_pack_func(enum p2p_packing packing)\n{\n\treturn p2p_select_pack_func_ex(packing, 0);\n}\n\np2p_pack_func p2p_select_pack_func_ex(enum p2p_packing packing, int alpha_one_fill)\n{\n\tconst packing_traits &traits = lookup_traits(packing);\n\treturn alpha_one_fill ? traits.pack_one_fill : traits.pack;\n}\n\nvoid p2p_unpack_frame(const struct p2p_buffer_param *param, unsigned long flags)\n{\n\tconst packing_traits &traits = lookup_traits(param->packing);\n\n\t// Process interleaved plane.\n\tconst void *src_p = traits.is_nv ? param->src[1] : param->src[0];\n\tptrdiff_t src_stride = traits.is_nv ? param->src_stride[1] : param->src_stride[0];\n\n\tvoid *dst_p[4] = { param->dst[0], param->dst[1], param->dst[2], param->dst[3] };\n\n\tfor (unsigned i = 0; i < (param->height >> traits.subsample_h); ++i) {\n\t\ttraits.unpack(src_p, dst_p, 0, param->width);\n\n\t\tsrc_p = increment_ptr(src_p, src_stride);\n\n\t\tif (!traits.is_nv) {\n\t\t\tdst_p[0] = increment_ptr(dst_p[0], param->dst_stride[0]);\n\t\t\tdst_p[3] = increment_ptr(dst_p[3], param->dst_stride[3]);\n\t\t}\n\t\tdst_p[1] = increment_ptr(dst_p[1], param->dst_stride[1]);\n\t\tdst_p[2] = increment_ptr(dst_p[2], param->dst_stride[2]);\n\t}\n\n\tif (traits.is_nv && !(flags & P2P_SKIP_UNPACKED_PLANES) && param->src[0] && param->dst[0]) {\n\t\tif ((traits.bytes_per_sample == 1 || traits.native_endian) && !traits.nv_shift) {\n\t\t\tcopy_plane_fast(param->src[0], param->dst[0], param->src_stride[0], param->dst_stride[0],\n\t\t\t                traits.bytes_per_sample * param->width, param->height);\n\t\t} else {\n\t\t\tunpack_nv16_plane(param->src[0], param->dst[0], param->src_stride[0], param->dst_stride[0], traits, param->width, param->height);\n\t\t}\n\t}\n}\n\nvoid p2p_pack_frame(const struct p2p_buffer_param *param, unsigned long flags)\n{\n\tconst packing_traits &traits = lookup_traits(param->packing);\n\tp2p_pack_func pack_func = flags & P2P_ALPHA_SET_ONE ? traits.pack_one_fill : traits.pack;\n\n\t// Process interleaved plane.\n\tconst void *src_p[4] = { param->src[0], param->src[1], param->src[2], param->src[3] };\n\n\tvoid *dst_p = traits.is_nv ? param->dst[1] : param->dst[0];\n\tptrdiff_t dst_stride = traits.is_nv ? param->dst_stride[1] : param->dst_stride[0];\n\n\tfor (unsigned i = 0; i < (param->height >> traits.subsample_h); ++i) {\n\t\tpack_func(src_p, dst_p, 0, param->width);\n\n\t\tif (!traits.is_nv) {\n\t\t\tsrc_p[0] = increment_ptr(src_p[0], param->src_stride[0]);\n\t\t\tsrc_p[3] = increment_ptr(src_p[3], param->src_stride[3]);\n\t\t}\n\t\tsrc_p[1] = increment_ptr(src_p[1], param->src_stride[1]);\n\t\tsrc_p[2] = increment_ptr(src_p[2], param->src_stride[2]);\n\n\t\tdst_p = increment_ptr(dst_p, dst_stride);\n\t}\n\n\tif (traits.is_nv && !(flags & P2P_SKIP_UNPACKED_PLANES) && param->src[0] && param->dst[0]) {\n\t\tif ((traits.bytes_per_sample == 1 || traits.native_endian) && !traits.nv_shift) {\n\t\t\tcopy_plane_fast(param->src[0], param->dst[0], param->src_stride[0], param->dst_stride[0],\n\t\t\t                traits.bytes_per_sample * param->width, param->height);\n\t\t} else {\n\t\t\tpack_nv16_plane(param->src[0], param->dst[0], param->src_stride[0], param->dst_stride[0], traits, param->width, param->height);\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "common-src/libp2p/p2p_api.h",
    "content": "#ifndef P2P_API_H_\n#define P2P_API_H_\n\n#include <stddef.h>\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n/**\n * Notation: [Xa-Ya-Za]\n *\n * [] denotes a machine word of the specified endianness.  Xa-Ya-Za denote\n * component X, Y, and Z packed in the word, with bit depths a, b, c, in order\n * from MSB to LSB.  Padding bits are represented by the component '!'.\n */\nenum p2p_packing {\n\t/** [R8-G8-B8] */\n\tp2p_rgb24_be, /* RGB */\n\tp2p_rgb24_le, /* BGR */\n\tp2p_rgb24,\n\t/** [A8-R8-G8-B8] */\n\tp2p_argb32_be, /* ARGB */\n\tp2p_argb32_le, /* BGRA */\n\tp2p_argb32,\n\t/** [A8-Y8-U8-V8] */\n\tp2p_ayuv_be, /* AYUV */\n\tp2p_ayuv_le, /* VUYA */\n\tp2p_ayuv,\n\t/** [R16-G16-B16] */\n\tp2p_rgb48_be, /* RGB, big-endian components */\n\tp2p_rgb48_le, /* BGR, little-endian components */\n\tp2p_rgb48,\n\t/** [A16-R16-G16-B16] */\n\tp2p_argb64_be, /* ARGB big-endian components */\n\tp2p_argb64_le, /* BGRA little-endian components */\n\tp2p_argb64,\n\t/** [A2-R10-G10-B10] */\n\tp2p_rgb30_be, /* ARGB packed in big-endian DWORD */\n\tp2p_rgb30_le, /* ARGB packed in little-endian DWORD */\n\tp2p_rgb30,\n\t/** [A2-V10-Y10-U10] */\n\tp2p_y410_be, /* AVYU packed in big-endian DWORD */\n\tp2p_y410_le, /* AVYU packed in little-endian DWORD */\n\tp2p_y410,\n\t/** [A16-V16-Y16-U16] */\n\tp2p_y416_be, /* AVYU, big-endian components */\n\tp2p_y416_le, /* UYVA, little-endian components */\n\tp2p_y416,\n\t/** [Y8] [U8] [Y8] [V8] */\n\tp2p_yuy2,\n\t/** [U8] [Y8] [V8] [Y8] */\n\tp2p_uyvy,\n\t/** [Y10-!6] [U10-!6] [Y10-!6] [V10-!6] */\n\tp2p_y210_be, /* YUYV, big-endian components, lower 6 bits zero */\n\tp2p_y210_le, /* YUYV, little-endian components, lower 6 bits zero. Microsoft Y210. */\n\tp2p_y210,\n\t/** [Y16] [U16] [Y16] [V16] */\n\tp2p_y216_be, /* YUYV, big-endian components */\n\tp2p_y216_le, /* YUYV, little-endian components. Microsoft Y216. */\n\tp2p_y216,\n\t/** [!2-V10-Y10-U10] [!2-Y10-U10-Y10] [!2-U10-Y10-V10] [!2-Y10-V10-Y10] */\n\tp2p_v210_be, /* v210 with big-endian DWORDs */\n\tp2p_v210_le, /* Apple/QuickTime v210 */\n\tp2p_v210,\n\t/** [U16] [Y16] [V16] [Y16] */\n\tp2p_v216_be, /* UYVY, big-endian components */\n\tp2p_v216_le, /* UYVY, little-endian components. Apple/QuickTime v216. */\n\tp2p_v216,\n\t/** [U8-V8] */\n\tp2p_nv12_be, /* aka NV21, V first */\n\tp2p_nv12_le, /* NV12 */\n\tp2p_nv12,\n\t/** [U10-!6-V10-!6] */\n\tp2p_p010_be, /* NV21, big-endian components, lower 6 bits zero */\n\tp2p_p010_le, /* NV12, little-endian components, lower 6 bits zero. Microsoft P010. */\n\tp2p_p010,\n\t/** [U16-V16] */\n\tp2p_p016_be, /* NV21, big-endian components */\n\tp2p_p016_le, /* NV12, little-endian components. Microsoft P016. */\n\tp2p_p016,\n\t/** [U10-!6-V10-!6] */\n\tp2p_p210_be, /* NV21, big-endian components, lower 6 bits zero */\n\tp2p_p210_le, /* NV12, little-endian components, lower 6 bits zero. Microsoft P210. */\n\tp2p_p210,\n\t/** [U16-V16] */\n\tp2p_p216_be, /* NV21, big-endian components */\n\tp2p_p216_le, /* NV12, little-endian components. Microsoft P216. */\n\tp2p_p216,\n\t/** [R8-G8-B8-A8] */\n\tp2p_rgba32_be, /* RGBA */\n\tp2p_rgba32_le, /* ABGR */\n\tp2p_rgba32,\n\t/** [R16-G16-B16-A16] */\n\tp2p_rgba64_be, /* RGBA, big-endian components */\n\tp2p_rgba64_le, /* ABGR, little-endian components */\n\tp2p_rgba64,\n\t/** [A16-B16-G16-R16] */\n\tp2p_abgr64_be, /* ABGR, big-endian components */\n\tp2p_abgr64_le, /* RGBA, little-endian components */\n\tp2p_abgr64,\n\t/** [B16-G16-R16] */\n\tp2p_bgr48_be, /* BGR, big-endian components */\n\tp2p_bgr48_le, /* RGB, little-endian components */\n\tp2p_bgr48,\n\t/** [B16-G16-R16-A16] */\n\tp2p_bgra64_be, /* BGRA, big-endian components */\n\tp2p_bgra64_le, /* ARGB, little-endian components */\n\tp2p_bgra64,\n\n\tp2p_packing_max,\n};\n\nstruct p2p_buffer_param {\n\t/**\n\t * Planar order: R-G-B-A or Y-U-V-A. Alpha is optional.\n\t * Packed order: Y-UV if NV12/21, else single plane. Y optional for NV12/21.\n\t */\n\tconst void *src[4];\n\tvoid *dst[4];\n\tptrdiff_t src_stride[4];\n\tptrdiff_t dst_stride[4];\n\tunsigned width;\n\tunsigned height;\n\tenum p2p_packing packing;\n};\n\n/** Pack/unpack a range of pixels from a scanline. */\ntypedef void (*p2p_unpack_func)(const void *src, void * const dst[4], unsigned left, unsigned right);\ntypedef void (*p2p_pack_func)(const void * const src[4], void *dst, unsigned left, unsigned right);\n\n/** Select a line pack/unpack function. */\np2p_unpack_func p2p_select_unpack_func(enum p2p_packing packing);\np2p_pack_func p2p_select_pack_func(enum p2p_packing packing);\np2p_pack_func p2p_select_pack_func_ex(enum p2p_packing packing, int alpha_one_fill);\n\n\n/** When processing formats like NV12, ignore the unpacked plane. */\n#define P2P_SKIP_UNPACKED_PLANES (1UL << 0)\n/** When packing, store a bit pattern of all ones in the alpha channel instead of all zeros. */\n#define P2P_ALPHA_SET_ONE (1UL << 1)\n\n/** Helper function to pack/unpack between memory locations. */\nvoid p2p_unpack_frame(const struct p2p_buffer_param *param, unsigned long flags);\nvoid p2p_pack_frame(const struct p2p_buffer_param *param, unsigned long flags);\n\n#ifdef __cplusplus\n} /* extern \"C\" */\n#endif\n\n#endif /* P2P_API_H_ */\n"
  },
  {
    "path": "common-src/libp2p/simd/cpuinfo_x86.cpp",
    "content": "#ifdef P2P_SIMD\n#if defined(__x86_64__) || defined(__i386__) || defined(_M_IX86) || defined(_M_X64)\n\n#if 0\n  #include <stdio.h>\n  #define TRACE(fmt, ...) fprintf(stderr, \"[cpuinfo] \" fmt, __VA_ARGS__)\n#else\n  #define TRACE(fmt, ...) do {} while (0)\n#endif\n\n#if defined(_MSC_VER)\n  #include <intrin.h>\n#elif defined(__GNUC__)\n  #include <cpuid.h>\n#endif\n\n#include \"../p2p.h\"\n#include \"cpuinfo_x86.h\"\n\nnamespace P2P_NAMESPACE {\nnamespace simd {\n\nnamespace {\n\n/**\n * Execute the CPUID instruction.\n *\n * @param regs array to receive eax, ebx, ecx, edx\n * @param eax argument to instruction\n * @param ecx argument to instruction\n */\nvoid do_cpuid(int regs[4], int eax, int ecx)\n{\n#if defined(_MSC_VER)\n\t__cpuidex(regs, eax, ecx);\n#elif defined(__GNUC__)\n\t__cpuid_count(eax, ecx, regs[0], regs[1], regs[2], regs[3]);\n#else\n\tregs[0] = 0;\n\tregs[1] = 0;\n\tregs[2] = 0;\n\tregs[3] = 0;\n#endif\n}\n\n/**\n * Execute the XGETBV instruction.\n *\n * @param ecx argument to instruction\n * @return (edx << 32) | eax\n */\nunsigned long long do_xgetbv(unsigned ecx)\n{\n#if defined(_MSC_VER)\n\treturn _xgetbv(ecx);\n#elif defined(__GNUC__)\n\tunsigned eax, edx;\n\t__asm(\"xgetbv\" : \"=a\"(eax), \"=d\"(edx) : \"c\"(ecx) : );\n\treturn (static_cast<unsigned long long>(edx) << 32) | eax;\n#else\n\treturn 0;\n#endif\n}\n\nX86Capabilities do_query_x86_capabilities() noexcept\n{\n\tX86Capabilities caps = { 0 };\n\tunsigned long long xcr0 = 0;\n\tint regs[4] = { 0 };\n\tint xmmymm = 0;\n\tint zmm = 0;\n\n\tdo_cpuid(regs, 1, 0);\n\tcaps.sse = !!(regs[3] & (1U << 25));\n\tcaps.sse2 = !!(regs[3] & (1U << 26));\n\tcaps.sse3 = !!(regs[2] & (1U << 0));\n\tcaps.ssse3 = !!(regs[2] & (1U << 9));\n\tcaps.fma = !!(regs[2] & (1U << 12));\n\tcaps.sse41 = !!(regs[2] & (1U << 19));\n\tcaps.sse42 = !!(regs[2] & (1U << 20));\n\n\t// osxsave\n\tif (regs[2] & (1U << 27)) {\n\t\txcr0 = do_xgetbv(0);\n\t\txmmymm = (xcr0 & 0x06) == 0x06;\n\t\tzmm = (xcr0 & 0xE0) == 0xE0;\n\t}\n\n\t// XMM and YMM state.\n\tif (xmmymm) {\n\t\tcaps.avx = !!(regs[2] & (1U << 28));\n\t\tcaps.f16c = !!(regs[2] & (1U << 29));\n\t}\n\n\tdo_cpuid(regs, 7, 0);\n\tif (xmmymm) {\n\t\tcaps.avx2 = !!(regs[1] & (1U << 5));\n\t}\n\n\t// ZMM state.\n\tif (zmm) {\n\t\tcaps.avx512f = !!(regs[1] & (1U << 16));\n\t\tcaps.avx512dq = !!(regs[1] & (1U << 17));\n\t\tcaps.avx512ifma = !!(regs[1] & (1U << 21));\n\t\tcaps.avx512cd = !!(regs[1] & (1U << 28));\n\t\tcaps.avx512bw = !!(regs[1] & (1U << 30));\n\t\tcaps.avx512vl = !!(regs[1] & (1U << 31));\n\t\tcaps.avx512vbmi = !!(regs[2] & (1U << 1));\n\t\tcaps.avx512vbmi2 = !!(regs[2] & (1U << 6));\n\t\tcaps.avx512vnni = !!(regs[2] & (1U << 11));\n\t\tcaps.avx512bitalg = !!(regs[2] & (1U << 12));\n\t\tcaps.avx512vpopcntdq = !!(regs[2] & (1U << 14));\n\t\tcaps.avx512vp2intersect = !!(regs[3] & (1U << 8));\n\t\tcaps.avx512fp16 = !!(regs[3] & (1U << 23));\n\t}\n\n\tdo_cpuid(regs, 7, 1);\n\tif (zmm) {\n\t\tcaps.avx512bf16 = !!(regs[0] & (1U << 5));\n\t}\n\n\t// Extended processor info.\n\tdo_cpuid(regs, 0x80000001U, 0);\n\tcaps.xop = !!(regs[2] & (1U << 11));\n\n\t// Zen1 vs Zen2.\n\tdo_cpuid(regs, 0, 1);\n\tif (regs[1] == 0x68747541U && regs[3] == 0x69746E65U && regs[2] == 0x444D4163U /* AuthenticAMD */) {\n\t\tunsigned model;\n\t\tunsigned family;\n\n\t\tdo_cpuid(regs, 1, 0);\n\t\tmodel = (regs[0] >> 4) & 0x0FU;\n\t\tfamily = (regs[0] >> 8) & 0x0FU;\n\n\t\tif (family == 15) {\n\t\t\tfamily += ((regs[0] >> 20) & 0x0FU);\n\t\t\tmodel += ((regs[0] >> 16) & 0x0FU) << 4;\n\t\t}\n\n\t\tcaps.piledriver = family == 0x15 && model == 0x02;\n\t\tcaps.zen1 = family == 0x17 && model <= 0x2F;\n\t\tcaps.zen2 = family == 0x17 && model >= 0x30;\n\t\tcaps.zen3 = family == 0x19;\n\t}\n\n\treturn caps;\n}\n\n// Query leaf 4h (Intel) or leaf 8000001Dh (AMD).\nvoid do_query_x86_deterministic_cache_parameters(X86CacheHierarchy &cache, int leaf) noexcept\n{\n\tint regs[4];\n\n\tfor (int i = 0; i < 8; ++i) {\n\t\tunsigned threads;\n\t\tunsigned long line_size;\n\t\tunsigned long partitions;\n\t\tunsigned long ways;\n\t\tunsigned long sets;\n\t\tunsigned long cache_size;\n\t\tint cache_type;\n\t\tbool inclusive;\n\n\t\tdo_cpuid(regs, leaf, i);\n\t\tcache_type = regs[0] & 0x1FU;\n\t\tTRACE(\"L%u cache, type %d\\n\", (static_cast<unsigned>(regs[0]) >> 5) & 0x07U, cache_type);\n\n\t\t// No more caches.\n\t\tif (cache_type == 0)\n\t\t\tbreak;\n\n\t\t// Not data or unified cache.\n\t\tif (cache_type != 1 && cache_type != 3)\n\t\t\tcontinue;\n\n\t\tthreads = ((static_cast<unsigned>(regs[0]) >> 14) & 0x0FFFU) + 1;\n\t\tline_size = ((static_cast<unsigned>(regs[1]) >> 0) & 0x0FFFU) + 1;\n\t\tpartitions = ((static_cast<unsigned>(regs[1]) >> 12) & 0x03FFU) + 1;\n\t\tways = ((static_cast<unsigned>(regs[1]) >> 22) & 0x03FFU) + 1;\n\t\tsets = static_cast<unsigned>(regs[2]) + 1;\n\n\t\tcache_size = line_size * partitions * ways * sets;\n\t\tinclusive = regs[3] & (1U << 1);\n\t\tTRACE(\"%u threads, %lu bytes, %s\\n\", threads, cache_size, inclusive ? \"inclusive\" : \"non-inclusive\");\n\n\t\t// Cache level.\n\t\tswitch ((static_cast<unsigned>(regs[0]) >> 5) & 0x07U) {\n\t\tcase 1:\n\t\t\tcache.l1d = cache_size;\n\t\t\tcache.l1d_threads = threads;\n\t\t\tbreak;\n\t\tcase 2:\n\t\t\tcache.l2 = cache_size;\n\t\t\tcache.l2_threads = threads;\n\t\t\tcache.l2_inclusive = inclusive;\n\t\t\tbreak;\n\t\tcase 3:\n\t\t\tcache.l3 = cache_size;\n\t\t\tcache.l3_threads = threads;\n\t\t\tcache.l3_inclusive = inclusive;\n\t\t\tbreak;\n\t\tdefault:\n\t\t\tbreak;\n\t\t}\n\t}\n}\n\nX86CacheHierarchy do_query_x86_cache_hierarchy_intel(int max_feature) noexcept\n{\n\tX86CacheHierarchy cache = { 0 };\n\tint regs[4];\n\n\tif (max_feature < 2)\n\t\treturn cache;\n\n\t// Detect cache size of single-threaded CPU from flags.\n\tif (max_feature >= 2 && max_feature < 4)\n\t\treturn cache;\n\n\t// Detect cache hierarchy.\n\tif (max_feature >= 4)\n\t\tdo_query_x86_deterministic_cache_parameters(cache, 4);\n\n\t// Detect logical processor count on x2APIC systems.\n\tif (max_feature >= 0x0B) {\n\t\tunsigned l1d_threads = cache.l1d_threads;\n\t\tunsigned l2_threads = cache.l2_threads;\n\t\tunsigned l3_threads = cache.l3_threads;\n\n\t\tfor (int i = 0; i < 8; ++i) {\n\t\t\tunsigned logical_processors;\n\n\t\t\tdo_cpuid(regs, 0x0B, i);\n\t\t\tTRACE(\"APIC level %u\\n\", (static_cast<unsigned>(regs[2]) >> 8) & 0xFFU);\n\n\t\t\tif (((regs[2] >> 8) & 0xFFU) == 0)\n\t\t\t\tbreak;\n\n\t\t\tlogical_processors = regs[1] & 0xFFFFU;\n\t\t\tTRACE(\"logical processors: %u\\n\", logical_processors);\n\n\t\t\tl1d_threads = logical_processors <= cache.l1d_threads ? logical_processors : l1d_threads;\n\t\t\tl2_threads = logical_processors <= cache.l2_threads ? logical_processors : l2_threads;\n\t\t\tl3_threads = logical_processors <= cache.l3_threads ? logical_processors : l3_threads;\n\t\t\tTRACE(\"updated cache sharing: %u %u %u\\n\", l1d_threads, l2_threads, l3_threads);\n\t\t}\n\n\t\tcache.l1d_threads = l1d_threads;\n\t\tcache.l2_threads = l2_threads;\n\t\tcache.l3_threads = l3_threads;\n\t}\n\n\treturn cache;\n}\n\nX86CacheHierarchy do_query_x86_cache_hierarchy_amd(int max_feature) noexcept\n{\n\tX86CacheHierarchy cache = { 0 };\n\tint regs[4];\n\tunsigned max_extended_feature;\n\n\tdo_cpuid(regs, 0x80000000U, 0);\n\tmax_extended_feature = static_cast<unsigned>(regs[0]);\n\tTRACE(\"max extended feature #: 0x%x\\n\", max_extended_feature);\n\n\tif (max_extended_feature >= 0x80000005U) {\n\t\tdo_cpuid(regs, 0x80000005U, 0);\n\t\tcache.l1d = ((static_cast<unsigned>(regs[2]) >> 24) & 0xFFU) * 1024U;\n\t\tcache.l1d_threads = cache.l1d ? 1 : cache.l1d_threads;\n\t\tTRACE(\"L1d: %lu\\n\", cache.l1d);\n\t}\n\n\tif (max_extended_feature >= 0x80000006U) {\n\t\tdo_cpuid(regs, 0x80000006U, 0);\n\t\tcache.l2 = ((static_cast<unsigned>(regs[2]) >> 16) & 0xFFFFU) * 1024U;\n\t\tcache.l3 = ((static_cast<unsigned>(regs[3]) >> 18) & 0x3FFFU) * 512U * 1024U;\n\t\tcache.l2_threads = cache.l2 ? 1 : cache.l2_threads;\n\t\tcache.l3_threads = cache.l3 ? 1 : cache.l3_threads;\n\t\tTRACE(\"L2: %lu\\n\", cache.l2);\n\t\tTRACE(\"L3: %lu\\n\", cache.l3);\n\t}\n\n\tif (max_extended_feature >= 0x80000008U) {\n\t\tunsigned threads;\n\t\tunsigned family;\n\n\t\tdo_cpuid(regs, 0x80000008U, 0);\n\t\tthreads = (regs[2] & 0xFFU) + 1;\n\t\tcache.l3_threads = cache.l3 ? threads : cache.l3_threads;\n\t\tTRACE(\"package threads: %u\\n\", threads);\n\n\t\tdo_cpuid(regs, 1, 0);\n\t\tfamily = ((static_cast<unsigned>(regs[0]) >> 20) & 0xFFU) + ((static_cast<unsigned>(regs[0]) >> 8) & 0x0FU);\n\t\tTRACE(\"family %xh\\n\", family);\n\n\t\tif (family == 0x15)\n\t\t\tcache.l2_threads = 2; // Bulldozer shared L2 cache.\n\t\telse if (family == 0x16)\n\t\t\tcache.l2_threads = threads; // Jaguar L2 LLC.\n\t}\n\n\tif (max_extended_feature >= 0x8000001DU)\n\t\tdo_query_x86_deterministic_cache_parameters(cache, 0x8000001DU);\n\n\treturn cache;\n}\n\nX86CacheHierarchy do_query_x86_cache_hierarchy() noexcept\n{\n\tenum { GENUINEINTEL, AUTHENTICAMD, OTHER } vendor;\n\n\tX86CacheHierarchy cache = { 0 };\n\tint regs[4] = { 0 };\n\tint max_feature;\n\n\tdo_cpuid(regs, 0, 1);\n\tmax_feature = regs[0] & 0xFFU;\n\tTRACE(\"max feature #: %d\\n\", max_feature);\n\n\tif (regs[1] == 0x756E6547U && regs[3] == 0x49656E69U && regs[2] == 0x6C65746EU) {\n\t\tvendor = GENUINEINTEL;\n\t\tTRACE(\"%s\\n\", \"GenuineIntel\");\n\t} else if (regs[1] == 0x68747541U && regs[3] == 0x69746E65U && regs[2] == 0x444D4163U) {\n\t\tvendor = AUTHENTICAMD;\n\t\tTRACE(\"%s\\n\", \"AuthenticAMD\");\n\t} else {\n\t\tvendor = OTHER;\n\t\tTRACE(\"vendor %08x-%08x-%08x\\n\", regs[0], regs[2], regs[1]);\n\t}\n\n\tif (vendor == GENUINEINTEL)\n\t\tcache = do_query_x86_cache_hierarchy_intel(max_feature);\n\telse if (vendor == AUTHENTICAMD)\n\t\tcache = do_query_x86_cache_hierarchy_amd(max_feature);\n\n\tTRACE(\"final hierarchy: L1 %lu / %lu, L2: %lu / %lu, L3: %lu / %lu\\n\",\n\t\tcache.l1d, cache.l1d_threads, cache.l2, cache.l2_threads, cache.l3, cache.l3_threads);\n\n\tcache.valid = cache.l1d && cache.l1d_threads && !(cache.l2 && !cache.l2_threads) && !(cache.l3 && !cache.l3_threads);\n\treturn cache;\n}\n\n} // namespace\n\n\nX86Capabilities query_x86_capabilities() noexcept\n{\n\tstatic const X86Capabilities caps = do_query_x86_capabilities();\n\treturn caps;\n}\n\nX86CacheHierarchy query_x86_cache_hierarchy() noexcept\n{\n\tstatic const X86CacheHierarchy cache = do_query_x86_cache_hierarchy();\n\treturn cache;\n}\n\nunsigned long cpu_cache_size_x86() noexcept\n{\n\tconst X86CacheHierarchy cache = query_x86_cache_hierarchy();\n\n\tif (!cache.valid)\n\t\treturn 0;\n\n\t// Detect Skylake-SP cache hierarchy and report L2 size instead of L3.\n\tif (cache.l3 && !cache.l3_inclusive && cache.l2 >= 1024 * 1024U && cache.l2_threads <= 2)\n\t\treturn cache.l2 / cache.l2_threads;\n\n\tif (cache.l3)\n\t\treturn cache.l3 / cache.l3_threads;\n\telse if (cache.l2)\n\t\treturn cache.l2 / cache.l2_threads;\n\telse\n\t\treturn cache.l1d / cache.l1d_threads;\n}\n\n} // namespace simd\n} // namespace p2p\n\n#endif // x86\n#endif // P2P_SIMD\n"
  },
  {
    "path": "common-src/libp2p/simd/cpuinfo_x86.h",
    "content": "#pragma once\n\n#ifndef P2P_CPUINFO_X86_H_\n#define P2P_CPUINFO_X86_H_\n\n#ifdef P2P_SIMD\n#if defined(__x86_64__) || defined(__i386__) || defined(_M_IX86) || defined(_M_X64)\n\n#include \"../p2p.h\"\n\nnamespace P2P_NAMESPACE {\nnamespace simd {\n\n/**\n * Bitfield of selected x86 feature flags.\n */\nstruct X86Capabilities {\n\tunsigned sse : 1;\n\tunsigned sse2 : 1;\n\tunsigned sse3 : 1;\n\tunsigned ssse3 : 1;\n\tunsigned fma : 1;\n\tunsigned sse41 : 1;\n\tunsigned sse42 : 1;\n\tunsigned avx : 1;\n\tunsigned f16c : 1;\n\tunsigned avx2 : 1;\n\tunsigned avx512f : 1;\n\tunsigned avx512dq : 1;\n\tunsigned avx512ifma : 1;\n\tunsigned avx512cd : 1;\n\tunsigned avx512bw : 1;\n\tunsigned avx512vl : 1;\n\tunsigned avx512vbmi : 1;\n\tunsigned avx512vbmi2 : 1;\n\tunsigned avx512vnni : 1;\n\tunsigned avx512bitalg : 1;\n\tunsigned avx512vpopcntdq : 1;\n\tunsigned avx512vp2intersect : 1;\n\tunsigned avx512fp16 : 1;\n\tunsigned avx512bf16 : 1;\n\t/* AMD architectures needing workarounds. */\n\tunsigned xop : 1;\n\tunsigned piledriver : 1;\n\tunsigned zen1 : 1;\n\tunsigned zen2 : 1;\n\tunsigned zen3 : 1;\n};\n\n/**\n * Representation of processor cache topology.\n */\nstruct X86CacheHierarchy {\n\tunsigned long l1d;\n\tunsigned long l1d_threads;\n\tunsigned long l2;\n\tunsigned long l2_threads;\n\tunsigned long l3;\n\tunsigned long l3_threads;\n\tbool l2_inclusive;\n\tbool l3_inclusive;\n\tbool valid;\n};\n\n/**\n * Get the x86 feature flags on the current CPU.\n *\n * @return capabilities\n */\nX86Capabilities query_x86_capabilities() noexcept;\n\n/**\n * Get the cache topology of the current CPU.\n *\n * On a multi-processor system, the returned topology corresponds to the first\n * processor package on which the function is called. The behaviour is\n * undefined if the platform contains non-identical processors.\n *\n * @return cache hierarchy\n */\nX86CacheHierarchy query_x86_cache_hierarchy() noexcept;\n\nunsigned long cpu_cache_size_x86() noexcept;\n\n} // namespace simd\n} // namespace p2p\n\n#endif // x86\n#endif // P2P_SIMD\n\n#endif // P2P_CPUINFO_X86_H_\n"
  },
  {
    "path": "common-src/libp2p/simd/p2p_simd.cpp",
    "content": "#ifdef P2P_SIMD\n\n#include <array>\n#include <typeinfo>\n#include <tuple>\n#include <utility>\n#include \"../p2p.h\"\n#include \"cpuinfo_x86.h\"\n#include \"p2p_simd.h\"\n\nnamespace P2P_NAMESPACE {\nnamespace detail {\n\nnamespace {\n\ntypedef std::pair<const std::type_info *, detail::unpack_func> unpack_table_entry;\ntypedef std::tuple<const std::type_info *, detail::pack_func, detail::pack_func> pack_table_entry;\n\nauto populate_unpack_table()\n{\n\tstd::array<unpack_table_entry, 100> table;\n\tsize_t idx = 0;\n\n#if defined(__x86_64__) || defined(__i386__) || defined(_M_IX86) || defined(_M_X64)\n\tsimd::X86Capabilities x86 = simd::query_x86_capabilities();\n\n\tif (x86.sse41) {\n#define ENTRY(format, cpu) table[idx++] = unpack_table_entry{ &typeid(packed_##format), simd::unpack_##format##_##cpu }\n\t\tENTRY(argb32_be, sse41);\n\t\tENTRY(argb32_le, sse41);\n\t\tENTRY(rgba32_be, sse41);\n\t\tENTRY(rgba32_le, sse41);\n#undef ENTRY\n\t}\n#endif\n\n\treturn table;\n}\n\nauto populate_pack_table()\n{\n\tstd::array<pack_table_entry, 100> table;\n\tsize_t idx = 0;\n\n#if defined(__x86_64__) || defined(__i386__) || defined(_M_IX86) || defined(_M_X64)\n\tsimd::X86Capabilities x86 = simd::query_x86_capabilities();\n\n\tif (x86.sse41) {\n#define ENTRY(format, cpu) table[idx++] = pack_table_entry{ &typeid(packed_##format), simd::pack_##format##_0_##cpu, simd::pack_##format##_1_##cpu }\n\t\tENTRY(argb32_be, sse41);\n\t\tENTRY(argb32_le, sse41);\n\t\tENTRY(rgba32_be, sse41);\n\t\tENTRY(rgba32_le, sse41);\n#undef ENTRY\n\t}\n#endif\n\n\treturn table;\n}\n\n} // namespace\n\n\nunpack_func search_unpack_func(const std::type_info &ti)\n{\n\tstatic const auto g_unpack_table = populate_unpack_table();\n\n\tfor (const auto &entry : g_unpack_table) {\n\t\tif (entry.first == &ti)\n\t\t\treturn entry.second;\n\t\tif (!entry.first)\n\t\t\tbreak;\n\t}\n\treturn nullptr;\n}\n\npack_func search_pack_func(const std::type_info &ti, bool alpha_one_fill)\n{\n\tstatic const auto g_pack_table = populate_pack_table();\n\n\tfor (const auto &entry : g_pack_table) {\n\t\tif (std::get<0>(entry) == &ti)\n\t\t\treturn alpha_one_fill ? std::get<2>(entry) : std::get<1>(entry);\n\t\tif (!std::get<0>(entry))\n\t\t\tbreak;\n\t}\n\n\treturn nullptr;\n}\n\n} // namespace detail\n} // namespace p2p\n\n#endif // P2P_SIMD\n"
  },
  {
    "path": "common-src/libp2p/simd/p2p_simd.h",
    "content": "#pragma once\n\n#ifndef P2P_SIMD_H_\n#define P2P_SIMD_H_\n\n#ifdef P2P_SIMD\n\n#include \"../p2p.h\"\n\nnamespace P2P_NAMESPACE {\nnamespace simd {\n\n#define UNPACK(format, cpu) void unpack_##format##_##cpu(const void *, void * const *, unsigned, unsigned);\n#define PACK(format, cpu) \\\n  void pack_##format##_0_##cpu(const void * const *, void *, unsigned, unsigned); \\\n  void pack_##format##_1_##cpu(const void * const *, void *, unsigned, unsigned);\n\n#if defined(__x86_64__) || defined(__i386__) || defined(_M_IX86) || defined(_M_X64)\nUNPACK(argb32_be, sse41)\nUNPACK(argb32_le, sse41)\nUNPACK(rgba32_be, sse41)\nUNPACK(rgba32_le, sse41)\n\nPACK(argb32_be, sse41)\nPACK(argb32_le, sse41)\nPACK(rgba32_be, sse41)\nPACK(rgba32_le, sse41)\n#endif // x86\n\n#undef PACK\n#undef UNPACK\n\n} // namespace simd\n} // namespace p2p\n\n#endif // P2P_SIMD\n\n#endif // P2P_SIMD_H_\n"
  },
  {
    "path": "common-src/libp2p/simd/p2p_sse41.cpp",
    "content": "#ifdef P2P_SIMD\n#if defined(__x86_64__) || defined(__i386__) || defined(_M_IX86) || defined(_M_X64)\n\n#include <cstdint>\n#include <smmintrin.h>\n#include \"../p2p.h\"\n\nnamespace P2P_NAMESPACE {\nnamespace simd {\n\nnamespace {\n\ntemplate <unsigned Idx>\nuint32_t extract_epi32(__m128i x)\n{\n\treturn Idx == 0 ? _mm_cvtsi128_si32(x) : _mm_extract_epi32(x, Idx);\n}\n\ntemplate <unsigned IdxR, unsigned IdxG, unsigned IdxB, unsigned IdxA>\nvoid unpack_rgb32_sse41(const void *src, void * const * dst, unsigned left, unsigned right)\n{\n\tconst __m128i shuffle = _mm_set_epi8(15, 11, 7, 3, 14, 10, 6, 2, 13, 9, 5, 1, 12, 8, 4, 0);\n\n\tconst uint32_t *src_p = static_cast<const uint32_t *>(src);\n\tuint8_t *dst_r = static_cast<uint8_t *>(dst[0]);\n\tuint8_t *dst_g = static_cast<uint8_t *>(dst[1]);\n\tuint8_t *dst_b = static_cast<uint8_t *>(dst[2]);\n\tuint8_t *dst_a = static_cast<uint8_t *>(dst[3]);\n\n\tif (!dst_a)\n\t\tdst_a = dst_r; // Write alpha to some other channel if disabled.\n\n\tsize_t vec4_left = (left + 3) & ~3U;\n\tsize_t vec16_left = (left + 15) & ~15U;\n\tsize_t vec16_right = right & ~15U;\n\tsize_t vec4_right = right & ~3U;\n\n\t// Must always write alpha component first!\n\tauto scalar_iter = [&](size_t i)\n\t{\n\t\tuint32_t x = src_p[i];\n\t\tdst_a[i] = static_cast<uint8_t>((x >> (IdxA * 8)) & 0xFFU);\n\t\tdst_r[i] = static_cast<uint8_t>((x >> (IdxR * 8)) & 0xFFU);\n\t\tdst_g[i] = static_cast<uint8_t>((x >> (IdxG * 8)) & 0xFFU);\n\t\tdst_b[i] = static_cast<uint8_t>((x >> (IdxB * 8)) & 0xFFU);\n\t};\n\tauto vec4_iter = [&](size_t i)\n\t{\n\t\t__m128i x = _mm_loadu_si128((const __m128i *)(src_p + i));\n\t\tx = _mm_shuffle_epi8(x, shuffle);\n\n\t\t*reinterpret_cast<uint32_t *>(dst_a + i) = extract_epi32<IdxA>(x);\n\t\t*reinterpret_cast<uint32_t *>(dst_r + i) = extract_epi32<IdxR>(x);\n\t\t*reinterpret_cast<uint32_t *>(dst_g + i) = extract_epi32<IdxG>(x);\n\t\t*reinterpret_cast<uint32_t *>(dst_b + i) = extract_epi32<IdxB>(x);\n\t};\n\tauto vec16_iter = [&](size_t i)\n\t{\n\t\t__m128i x0 = _mm_loadu_si128((const __m128i *)(src_p + i));\n\t\t__m128i x1 = _mm_loadu_si128((const __m128i *)(src_p + i + 4));\n\t\t__m128i x2 = _mm_loadu_si128((const __m128i *)(src_p + i + 8));\n\t\t__m128i x3 = _mm_loadu_si128((const __m128i *)(src_p + i + 12));\n\n\t\tx0 = _mm_shuffle_epi8(x0, shuffle);\n\t\tx1 = _mm_shuffle_epi8(x1, shuffle);\n\t\tx2 = _mm_shuffle_epi8(x2, shuffle);\n\t\tx3 = _mm_shuffle_epi8(x3, shuffle);\n\n\t\t__m128 x0s = _mm_castsi128_ps(x0), x1s = _mm_castsi128_ps(x1), x2s = _mm_castsi128_ps(x2), x3s = _mm_castsi128_ps(x3);\n\t\t_MM_TRANSPOSE4_PS(x0s, x1s, x2s, x3s);\n\t\tx0 = _mm_castps_si128(x0s); x1 = _mm_castps_si128(x1s); x2 = _mm_castps_si128(x2s); x3 = _mm_castps_si128(x3s);\n\n\t\t__m128i regs[4] = { x0, x1, x2, x3 };\n\t\t_mm_storeu_si128((__m128i *)(dst_a + i), regs[IdxA]);\n\t\t_mm_storeu_si128((__m128i *)(dst_r + i), regs[IdxR]);\n\t\t_mm_storeu_si128((__m128i *)(dst_g + i), regs[IdxG]);\n\t\t_mm_storeu_si128((__m128i *)(dst_b + i), regs[IdxB]);\n\t};\n\n\tfor (size_t i = left; i < vec4_left; ++i)\n\t\tscalar_iter(i);\n\tfor (size_t i = vec4_left; i < vec16_left; i += 4)\n\t\tvec4_iter(i);\n\tfor (size_t i = vec16_left; i < vec16_right; i += 16)\n\t\tvec16_iter(i);\n\tfor (size_t i = vec16_right; i < vec4_right; i += 4)\n\t\tvec4_iter(i);\n\tfor (size_t i = vec4_right; i < right; ++i)\n\t\tscalar_iter(i);\n}\n\ntemplate <unsigned IdxR, unsigned IdxG, unsigned IdxB, unsigned IdxA, bool AlphaOneFill>\nvoid pack_rgb32_sse41(const void * const *src, void *dst, unsigned left, unsigned right)\n{\n#define X (AlphaOneFill ? 0xFF : 0)\n\talignas(16) static constexpr uint8_t alpha_fill[16] = { X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X };\n#undef X\n\tconst __m128i shuffle = _mm_set_epi8(15, 11, 7, 3, 14, 10, 6, 2, 13, 9, 5, 1, 12, 8, 4, 0);\n\n\tconst uint8_t *src_r = static_cast<const uint8_t *>(src[0]);\n\tconst uint8_t *src_g = static_cast<const uint8_t *>(src[1]);\n\tconst uint8_t *src_b = static_cast<const uint8_t *>(src[2]);\n\tconst uint8_t *src_a = static_cast<const uint8_t *>(src[3]);\n\tsize_t alpha_addr_mask = ~static_cast<size_t>(0);\n\tuint32_t *dst_p = static_cast<uint32_t *>(dst);\n\n\tsize_t vec4_left = (left + 3) & ~3U;\n\tsize_t vec16_left = (left + 15) & ~15U;\n\tsize_t vec16_right = right & ~15U;\n\tsize_t vec4_right = right & ~3U;\n\n\tif (!src_a) {\n\t\tsrc_a = alpha_fill;\n\t\talpha_addr_mask = 15;\n\t}\n\n\tauto scalar_iter = [&](size_t i)\n\t{\n\t\tuint8_t r = src_r[i];\n\t\tuint8_t g = src_g[i];\n\t\tuint8_t b = src_b[i];\n\t\tuint8_t a = src_a[i & alpha_addr_mask];\n\n\t\tuint32_t val = (static_cast<uint32_t>(r) << (IdxR * 8)) |\n\t\t\t(static_cast<uint32_t>(g) << (IdxG * 8)) |\n\t\t\t(static_cast<uint32_t>(b) << (IdxB * 8)) |\n\t\t\t(static_cast<uint32_t>(a) << (IdxA * 8));\n\t\tdst_p[i] = val;\n\t};\n\tauto vec4_iter = [&](size_t i)\n\t{\n\t\tuint32_t r = *reinterpret_cast<const uint32_t *>(src_r + i);\n\t\tuint32_t g = *reinterpret_cast<const uint32_t *>(src_g + i);\n\t\tuint32_t b = *reinterpret_cast<const uint32_t *>(src_b + i);\n\t\tuint32_t a = *reinterpret_cast<const uint32_t *>(src_a + (i & alpha_addr_mask));\n\n\t\t__m128i x = IdxR == 0 ? _mm_cvtsi32_si128(r) :\n\t\t\tIdxG == 0 ? _mm_cvtsi32_si128(g) :\n\t\t\tIdxB == 0 ? _mm_cvtsi32_si128(b) :\n\t\t\tIdxA == 0 ? _mm_cvtsi32_si128(a) :\n\t\t\t\tthrow 1;\n\n\t\tx = IdxR == 0 ? x : _mm_insert_epi32(x, r, IdxR);\n\t\tx = IdxG == 0 ? x : _mm_insert_epi32(x, g, IdxG);\n\t\tx = IdxB == 0 ? x : _mm_insert_epi32(x, b, IdxB);\n\t\tx = IdxA == 0 ? x : _mm_insert_epi32(x, a, IdxA);\n\t\tx = _mm_shuffle_epi8(x, shuffle);\n\t\t_mm_storeu_si128((__m128i *)(dst_p + i), x);\n\t};\n\tauto vec16_iter = [&](size_t i)\n\t{\n\t\t__m128i r = _mm_loadu_si128((const __m128i *)(src_r + i));\n\t\t__m128i g = _mm_loadu_si128((const __m128i *)(src_g + i));\n\t\t__m128i b = _mm_loadu_si128((const __m128i *)(src_b + i));\n\t\t__m128i a = _mm_loadu_si128((const __m128i *)(src_a + (i & alpha_addr_mask)));\n\n\t\t__m128 regs[4];\n\t\tregs[IdxR] = _mm_castsi128_ps(r);\n\t\tregs[IdxG] = _mm_castsi128_ps(g);\n\t\tregs[IdxB] = _mm_castsi128_ps(b);\n\t\tregs[IdxA] = _mm_castsi128_ps(a);\n\t\t_MM_TRANSPOSE4_PS(regs[0], regs[1], regs[2], regs[3]);\n\n\t\t__m128i x0 = _mm_castps_si128(regs[0]), x1 = _mm_castps_si128(regs[1]), x2 = _mm_castps_si128(regs[2]), x3 = _mm_castps_si128(regs[3]);\n\t\tx0 = _mm_shuffle_epi8(x0, shuffle);\n\t\tx1 = _mm_shuffle_epi8(x1, shuffle);\n\t\tx2 = _mm_shuffle_epi8(x2, shuffle);\n\t\tx3 = _mm_shuffle_epi8(x3, shuffle);\n\n\t\t_mm_storeu_si128((__m128i *)(dst_p + i + 0), x0);\n\t\t_mm_storeu_si128((__m128i *)(dst_p + i + 4), x1);\n\t\t_mm_storeu_si128((__m128i *)(dst_p + i + 8), x2);\n\t\t_mm_storeu_si128((__m128i *)(dst_p + i + 12), x3);\n\t};\n\n\tfor (size_t i = left; i < vec4_left; ++i)\n\t\tscalar_iter(i);\n\tfor (size_t i = vec4_left; i < vec16_left; i += 4)\n\t\tvec4_iter(i);\n\tfor (size_t i = vec16_left; i < vec16_right; i += 16)\n\t\tvec16_iter(i);\n\tfor (size_t i = vec16_right; i < vec4_right; i += 4)\n\t\tvec4_iter(i);\n\tfor (size_t i = vec4_right; i < right; ++i)\n\t\tscalar_iter(i);\n}\n\n} // namespace\n\n\n#define RGB32_SSE41(format, a, b, c, d) \\\n  void unpack_##format##_sse41(const void *src, void * const * dst, unsigned left, unsigned right) \\\n  { \\\n    unpack_rgb32_sse41<a, b, c, d>(src, dst, left, right); \\\n  } \\\n  void pack_##format##_0_sse41(const void * const *src, void *dst, unsigned left, unsigned right) \\\n  { \\\n    pack_rgb32_sse41<a, b, c, d, 0>(src, dst, left, right); \\\n  } \\\n  void pack_##format##_1_sse41(const void * const *src, void *dst, unsigned left, unsigned right) \\\n  { \\\n    pack_rgb32_sse41<a, b, c, d, 1>(src, dst, left, right); \\\n  }\n\nRGB32_SSE41(argb32_be, 1, 2, 3, 0)\nRGB32_SSE41(argb32_le, 2, 1, 0, 3)\nRGB32_SSE41(rgba32_be, 0, 1, 2, 3)\nRGB32_SSE41(rgba32_le, 3, 2, 1, 0)\n\n} // namespace simd\n} // namespace p2p\n\n#endif // x86\n#endif // P2P_SIMD\n"
  },
  {
    "path": "common-src/libp2p/v210.cpp",
    "content": "#include \"p2p.h\"\n\nnamespace P2P_NAMESPACE {\n\nnamespace {\n\ntemplate <class Endian>\nvoid unpack_v210(const void *src, void * const dst[4], unsigned left, unsigned right)\n{\n\tconst unsigned lsb_10b = 0x3FF;\n\n\tconst uint32_t *src_p = static_cast<const uint32_t *>(src);\n\tuint16_t *dst_p[3] = { static_cast<uint16_t *>(dst[0]), static_cast<uint16_t *>(dst[1]), static_cast<uint16_t *>(dst[2]) };\n\n\t// v210 packs 6 pixels in 4 DWORDs.\n\tleft = left - (left % 6);\n\n\t// Adjust pointers.\n\tsrc_p += left * 4 / 6;\n\tdst_p[C_Y] += left;\n\tdst_p[C_U] += left / 2;\n\tdst_p[C_V] += left / 2;\n\n\tfor (unsigned i = left; i < right - right % 6; i += 6) {\n\t\tuint32_t w0 = detail::endian_swap<Endian>(*src_p++);\n\t\tuint32_t w1 = detail::endian_swap<Endian>(*src_p++);\n\t\tuint32_t w2 = detail::endian_swap<Endian>(*src_p++);\n\t\tuint32_t w3 = detail::endian_swap<Endian>(*src_p++);\n\n\t\t*dst_p[C_U]++ = static_cast<uint16_t>((w0 >> 0) & lsb_10b);\n\t\t*dst_p[C_Y]++ = static_cast<uint16_t>((w0 >> 10) & lsb_10b);\n\t\t*dst_p[C_V]++ = static_cast<uint16_t>((w0 >> 20) & lsb_10b);\n\t\t*dst_p[C_Y]++ = static_cast<uint16_t>((w1 >> 0) & lsb_10b);\n\n\t\t*dst_p[C_U]++ = static_cast<uint16_t>((w1 >> 10) & lsb_10b);\n\t\t*dst_p[C_Y]++ = static_cast<uint16_t>((w1 >> 20) & lsb_10b);\n\t\t*dst_p[C_V]++ = static_cast<uint16_t>((w2 >> 0) & lsb_10b);\n\t\t*dst_p[C_Y]++ = static_cast<uint16_t>((w2 >> 10) & lsb_10b);\n\n\t\t*dst_p[C_U]++ = static_cast<uint16_t>((w2 >> 20) & lsb_10b);\n\t\t*dst_p[C_Y]++ = static_cast<uint16_t>((w3 >> 0) & lsb_10b);\n\t\t*dst_p[C_V]++ = static_cast<uint16_t>((w3 >> 10) & lsb_10b);\n\t\t*dst_p[C_Y]++ = static_cast<uint16_t>((w3 >> 20) & lsb_10b);\n\t}\n\tif (right % 6) {\n\t\t// No check needed as v210 is 128-byte aligned.\n\t\tuint32_t w0 = detail::endian_swap<Endian>(*src_p++);\n\t\tuint32_t w1 = detail::endian_swap<Endian>(*src_p++);\n\t\tuint32_t w2 = detail::endian_swap<Endian>(*src_p++);\n\t\tuint32_t w3 = detail::endian_swap<Endian>(*src_p++);\n\n\t\t{\n\t\t\t*dst_p[C_U]++ = static_cast<uint16_t>((w0 >> 0) & lsb_10b);\n\t\t\t*dst_p[C_Y]++ = static_cast<uint16_t>((w0 >> 10) & lsb_10b);\n\t\t\t*dst_p[C_V]++ = static_cast<uint16_t>((w0 >> 20) & lsb_10b);\n\t\t\t*dst_p[C_Y]++ = static_cast<uint16_t>((w1 >> 0) & lsb_10b);\n\t\t}\n\n\t\tif (right % 6 > 2) {\n\t\t\t*dst_p[C_U]++ = static_cast<uint16_t>((w1 >> 10) & lsb_10b);\n\t\t\t*dst_p[C_Y]++ = static_cast<uint16_t>((w1 >> 20) & lsb_10b);\n\t\t\t*dst_p[C_V]++ = static_cast<uint16_t>((w2 >> 0) & lsb_10b);\n\t\t\t*dst_p[C_Y]++ = static_cast<uint16_t>((w2 >> 10) & lsb_10b);\n\t\t}\n\n\t\tif (right % 6 > 4) {\n\t\t\t*dst_p[C_U]++ = static_cast<uint16_t>((w2 >> 20) & lsb_10b);\n\t\t\t*dst_p[C_Y]++ = static_cast<uint16_t>((w3 >> 0) & lsb_10b);\n\t\t\t*dst_p[C_V]++ = static_cast<uint16_t>((w3 >> 10) & lsb_10b);\n\t\t\t*dst_p[C_Y]++ = static_cast<uint16_t>((w3 >> 20) & lsb_10b);\n\t\t}\n\t}\n}\n\ntemplate <class Endian>\nvoid pack_v210(const void * const src[4], void *dst, unsigned left, unsigned right)\n{\n\tconst unsigned lsb_10b = 0x3FF;\n\n\tconst uint16_t *src_p[3] = { static_cast<const uint16_t *>(src[0]), static_cast<const uint16_t *>(src[1]), static_cast<const uint16_t *>(src[2]) };\n\tuint32_t *dst_p = static_cast<uint32_t *>(dst);\n\n\t// v210 packs 6 pixels in 4 DWORDs.\n\tleft = left - (left % 6);\n\n\t// Adjust pointers.\n\tsrc_p[C_Y] += left;\n\tsrc_p[C_U] += left / 2;\n\tsrc_p[C_V] += left / 2;\n\tdst_p += left * 4 / 6;\n\n\tfor (unsigned i = left; i < right - right % 6; i += 6) {\n\t\tuint32_t w0 = 0;\n\t\tuint32_t w1 = 0;\n\t\tuint32_t w2 = 0;\n\t\tuint32_t w3 = 0;\n\n\t\tw0 |= static_cast<uint32_t>(*src_p[C_U]++ & lsb_10b) << 0;\n\t\tw0 |= static_cast<uint32_t>(*src_p[C_Y]++ & lsb_10b) << 10;\n\t\tw0 |= static_cast<uint32_t>(*src_p[C_V]++ & lsb_10b) << 20;\n\t\tw1 |= static_cast<uint32_t>(*src_p[C_Y]++ & lsb_10b) << 0;\n\n\t\tw1 |= static_cast<uint32_t>(*src_p[C_U]++ & lsb_10b) << 10;\n\t\tw1 |= static_cast<uint32_t>(*src_p[C_Y]++ & lsb_10b) << 20;\n\t\tw2 |= static_cast<uint32_t>(*src_p[C_V]++ & lsb_10b) << 0;\n\t\tw2 |= static_cast<uint32_t>(*src_p[C_Y]++ & lsb_10b) << 10;\n\n\t\tw2 |= static_cast<uint32_t>(*src_p[C_U]++ & lsb_10b) << 20;\n\t\tw3 |= static_cast<uint32_t>(*src_p[C_Y]++ & lsb_10b) << 0;\n\t\tw3 |= static_cast<uint32_t>(*src_p[C_V]++ & lsb_10b) << 10;\n\t\tw3 |= static_cast<uint32_t>(*src_p[C_Y]++ & lsb_10b) << 20;\n\n\t\t*dst_p++ = detail::endian_swap<Endian>(w0);\n\t\t*dst_p++ = detail::endian_swap<Endian>(w1);\n\t\t*dst_p++ = detail::endian_swap<Endian>(w2);\n\t\t*dst_p++ = detail::endian_swap<Endian>(w3);\n\t}\n\tif (right % 6) {\n\t\tuint32_t w0 = 0;\n\t\tuint32_t w1 = 0;\n\t\tuint32_t w2 = 0;\n\t\tuint32_t w3 = 0;\n\n\t\t{\n\t\t\tw0 |= static_cast<uint32_t>(*src_p[C_U]++ & lsb_10b) << 0;\n\t\t\tw0 |= static_cast<uint32_t>(*src_p[C_Y]++ & lsb_10b) << 10;\n\t\t\tw0 |= static_cast<uint32_t>(*src_p[C_V]++ & lsb_10b) << 20;\n\t\t\tw1 |= static_cast<uint32_t>(*src_p[C_Y]++ & lsb_10b) << 0;\n\t\t}\n\n\t\tif (right % 6 > 2) {\n\t\t\tw1 |= static_cast<uint32_t>(*src_p[C_U]++ & lsb_10b) << 10;\n\t\t\tw1 |= static_cast<uint32_t>(*src_p[C_Y]++ & lsb_10b) << 20;\n\t\t\tw2 |= static_cast<uint32_t>(*src_p[C_V]++ & lsb_10b) << 0;\n\t\t\tw2 |= static_cast<uint32_t>(*src_p[C_Y]++ & lsb_10b) << 10;\n\t\t}\n\n\t\tif (right % 6 > 4) {\n\t\t\tw2 |= static_cast<uint32_t>(*src_p[C_U]++ & lsb_10b) << 20;\n\t\t\tw3 |= static_cast<uint32_t>(*src_p[C_Y]++ & lsb_10b) << 0;\n\t\t\tw3 |= static_cast<uint32_t>(*src_p[C_V]++ & lsb_10b) << 10;\n\t\t\tw3 |= static_cast<uint32_t>(*src_p[C_Y]++ & lsb_10b) << 20;\n\t\t}\n\n\t\t// No check needed as v210 is 128-byte aligned.\n\t\t*dst_p++ = detail::endian_swap<Endian>(w0);\n\t\t*dst_p++ = detail::endian_swap<Endian>(w1);\n\t\t*dst_p++ = detail::endian_swap<Endian>(w2);\n\t\t*dst_p++ = detail::endian_swap<Endian>(w3);\n\t}\n}\n\n} // namespace\n\n\nvoid packed_to_planar<packed_v210_be>::unpack(const void *src, void * const dst[4], unsigned left, unsigned right)\n{\n\tunpack_v210<big_endian_t>(src, dst, left, right);\n}\n\nvoid packed_to_planar<packed_v210_le>::unpack(const void *src, void * const dst[4], unsigned left, unsigned right)\n{\n\tunpack_v210<little_endian_t>(src, dst, left, right);\n}\n\nvoid planar_to_packed<packed_v210_be, false>::pack(const void * const src[4], void *dst, unsigned left, unsigned right)\n{\n\tpack_v210<big_endian_t>(src, dst, left, right);\n}\n\nvoid planar_to_packed<packed_v210_be, true>::pack(const void * const src[4], void *dst, unsigned left, unsigned right)\n{\n\tpack_v210<big_endian_t>(src, dst, left, right);\n}\n\nvoid planar_to_packed<packed_v210_le, false>::pack(const void * const src[4], void *dst, unsigned left, unsigned right)\n{\n\tpack_v210<little_endian_t>(src, dst, left, right);\n}\n\nvoid planar_to_packed<packed_v210_le, true>::pack(const void * const src[4], void *dst, unsigned left, unsigned right)\n{\n\tpack_v210<little_endian_t>(src, dst, left, right);\n}\n\n} // namespace p2p\n"
  },
  {
    "path": "common-src/log/log_styles_model.cpp",
    "content": "#include \"log_styles_model.h\"\n\n//==============================================================================\n\nLogStylesModel::LogStylesModel(QObject * a_pParent) :\n\tQAbstractItemModel(a_pParent)\n{\n}\n\n// END OF LogStylesModel::LogStylesModel(QObject * a_pParent)\n//==============================================================================\n\nLogStylesModel::~LogStylesModel()\n{\n}\n\n// END OF LogStylesModel::~LogStylesModel()\n//==============================================================================\n\nQModelIndex LogStylesModel::index(int a_row, int a_column,\n\tconst QModelIndex & a_parent) const\n{\n\t(void)a_parent;\n\treturn createIndex(a_row, a_column);\n}\n\n// END OF QModelIndex LogStylesModel::index(int a_row, int a_column,\n//\t\tconst QModelIndex & a_parent) const\n//==============================================================================\n\nQModelIndex LogStylesModel::parent(const QModelIndex & a_child) const\n{\n\t(void)a_child;\n\treturn QModelIndex();\n}\n\n// END OF QModelIndex LogStylesModel::parent(const QModelIndex & a_child)\n//\t\tconst\n//==============================================================================\n\nQt::ItemFlags LogStylesModel::flags(const QModelIndex & a_index) const\n{\n\tif (!a_index.isValid())\n\t{\n\t\treturn Qt::NoItemFlags;\n\t}\n\n\tQt::ItemFlags cellFlags = Qt::NoItemFlags\n\t\t| Qt::ItemIsEnabled\n\t\t| Qt::ItemIsSelectable\n\t\t| Qt::ItemIsUserCheckable\n\t;\n\n\treturn cellFlags;\n}\n\n// END OF Qt::ItemFlags LogStylesModel::flags(const QModelIndex & a_index)\n//\t\tconst\n//==============================================================================\n\nQVariant LogStylesModel::data(const QModelIndex & a_index, int a_role) const\n{\n\tif(!a_index.isValid())\n\t\treturn QVariant();\n\n\tint row = a_index.row();\n\tint column = a_index.column();\n\n\tif((row >= (int)m_styles.size()) || (column >= 1))\n\t\treturn QVariant();\n\n\tif((a_role == Qt::DisplayRole) || (a_role == Qt::ToolTipRole))\n\t\treturn m_styles[row].title;\n\telse if(a_role == Qt::UserRole)\n\t\treturn m_styles[row].name;\n\telse if(a_role == Qt::CheckStateRole)\n\t\treturn m_styles[row].isVisible ? Qt::Checked : Qt::Unchecked;\n\n\treturn QVariant();\n}\n\n// END OF QVariant LogStylesModel::data(const QModelIndex & a_index,\n//\t\tint a_role) const\n//==============================================================================\n\nint LogStylesModel::rowCount(const QModelIndex & a_parent) const\n{\n\t(void)a_parent;\n\treturn (int)m_styles.size();\n}\n\n// END OF int LogStylesModel::rowCount(const QModelIndex & a_parent) const\n//==============================================================================\n\nint LogStylesModel::columnCount(const QModelIndex & a_parent) const\n{\n\t(void)a_parent;\n\treturn 1;\n}\n\n// END OF int LogStylesModel::columnCount(const QModelIndex & a_parent)\n//\t\tconst\n//==============================================================================\n\nbool LogStylesModel::setData(const QModelIndex & a_index,\n\tconst QVariant & a_value, int a_role)\n{\n\tif(!a_index.isValid())\n\t\treturn false;\n\n\tint row = a_index.row();\n\tint column = a_index.column();\n\n\tif((row >= (int)m_styles.size()) || (column >= 1))\n\t\treturn false;\n\n\tif(a_role == Qt::CheckStateRole)\n\t{\n\t\tm_styles[row].isVisible = (a_value == Qt::Checked) ? true : false;\n\t\treturn true;\n\t}\n\n\treturn false;\n}\n\n// END OF bool LogStylesModel::setData(const QModelIndex & a_index,\n//\t\tconst QVariant & a_value, int a_role)\n//==============================================================================\n\nstd::vector<TextBlockStyle> LogStylesModel::styles() const\n{\n\treturn m_styles;\n}\n\n// END OF std::vector<TextBlockStyle> LogStylesModel::styles() const\n//==============================================================================\n\nvoid LogStylesModel::setStyles(const std::vector<TextBlockStyle> & a_styles)\n{\n\tbeginResetModel();\n\tm_styles = a_styles;\n\tendResetModel();\n}\n\n// END OF void LogStylesModel::setStyles(\n//\t\tconst std::vector<TextBlockStyle> & a_styles)\n//==============================================================================\n\nTextBlockStyle LogStylesModel::style(int a_index) const\n{\n\tQ_ASSERT(styleIndexValid(a_index));\n\treturn m_styles[a_index];\n}\n\n// END OF TextBlockStyle LogStylesModel::style(int a_index) const\n//==============================================================================\n\nTextBlockStyle LogStylesModel::style(const QModelIndex & a_index) const\n{\n\treturn style(a_index.row());\n}\n\n// END OF TextBlockStyle LogStylesModel::style(const QModelIndex & a_index)\n//\t\tconst\n//==============================================================================\n\nbool LogStylesModel::setStyleFont(int a_index, const QFont & a_font)\n{\n\tif(!styleIndexValid(a_index))\n\t\treturn false;\n\n\tm_styles[a_index].textFormat.setFont(a_font);\n\treturn true;\n}\n\n// END OF bool LogStylesModel::setStyleFont(int a_index, const QFont & a_font)\n//==============================================================================\n\nbool LogStylesModel::setStyleTextColor(int a_index, const QColor & a_color)\n{\n\tif(!styleIndexValid(a_index))\n\t\treturn false;\n\n\tm_styles[a_index].textFormat.setForeground(a_color);\n\treturn true;\n}\n\n// END OF bool LogStylesModel::setStyleTextColor(int a_index,\n//\t\tconst QColor & a_color)\n//==============================================================================\n\nbool LogStylesModel::setStyleBackgroundColor(int a_index,\n\tconst QColor & a_color)\n{\n\tif(!styleIndexValid(a_index))\n\t\treturn false;\n\n\tm_styles[a_index].textFormat.setBackground(a_color);\n\treturn true;\n}\n\n// END OF bool LogStylesModel::setStyleBackgroundColor(int a_index,\n//\t\tconst QColor & a_color)\n//==============================================================================\n\nbool LogStylesModel::styleIndexValid(int a_index) const\n{\n\treturn ((a_index >= 0) && (a_index < (int)m_styles.size()));\n}\n\n// END OF bool LogStylesModel::styleIndexValid(int a_index) const\n//==============================================================================\n"
  },
  {
    "path": "common-src/log/log_styles_model.h",
    "content": "#ifndef LOG_STYLES_MODEL_H_INCLUDED\n#define LOG_STYLES_MODEL_H_INCLUDED\n\n#include \"styled_log_view_structures.h\"\n\n#include <QAbstractItemModel>\n\nclass LogStylesModel : public QAbstractItemModel\n{\n\tQ_OBJECT\n\npublic:\n\n\tLogStylesModel(QObject * a_pParent = nullptr);\n\n\tvirtual ~LogStylesModel();\n\n\tvirtual QModelIndex index(int a_row, int a_column,\n\t\tconst QModelIndex & a_parent = QModelIndex()) const override;\n\n\tvirtual QModelIndex parent(const QModelIndex & a_child) const override;\n\n\tvirtual Qt::ItemFlags flags(const QModelIndex & a_index) const override;\n\n\tvirtual QVariant data(const QModelIndex & a_index,\n\t\tint a_role = Qt::DisplayRole) const override;\n\n\tvirtual int rowCount(const QModelIndex & a_parent = QModelIndex()) const\n\t\toverride;\n\n\tvirtual int columnCount(const QModelIndex & a_parent = QModelIndex()) const\n\t\toverride;\n\n\tvirtual bool setData(const QModelIndex & a_index, const QVariant & a_value,\n\t\tint a_role = Qt::EditRole) override;\n\n\tvirtual std::vector<TextBlockStyle> styles() const;\n\n\tvirtual void setStyles(const std::vector<TextBlockStyle> & a_styles);\n\n\tvirtual TextBlockStyle style(int a_index) const;\n\tvirtual TextBlockStyle style(const QModelIndex & a_index) const;\n\n\tvirtual bool setStyleFont(int a_index, const QFont & a_font);\n\tvirtual bool setStyleTextColor(int a_index, const QColor & a_color);\n\tvirtual bool setStyleBackgroundColor(int a_index, const QColor & a_color);\n\nprotected:\n\n\tvirtual bool styleIndexValid(int a_index) const;\n\n\tstd::vector<TextBlockStyle> m_styles;\n};\n\n#endif // LOG_STYLES_MODEL_H_INCLUDED\n"
  },
  {
    "path": "common-src/log/styled_log_view.cpp",
    "content": "#include \"styled_log_view.h\"\n\n#include \"styled_log_view_settings_dialog.h\"\n\n#include <QMenu>\n#include <QScrollBar>\n#include <QDir>\n#include <QFileDialog>\n#include <QFile>\n\n//==============================================================================\n\nconst size_t StyledLogView::DEFAULT_MAX_ENTRIES_TO_SHOW = 200;\n\n//==============================================================================\n\nStyledLogView::StyledLogView(QWidget * a_pParent) :\n\t  QTextEdit(a_pParent)\n\t, m_millisecondsToDivideBlocks(2000)\n\t, m_pContextMenu(nullptr)\n\t, m_pSettingsDialog(nullptr)\n\t, m_maxEntriesToShow(DEFAULT_MAX_ENTRIES_TO_SHOW)\n{\n\tsetReadOnly(true);\n\tsetContextMenuPolicy(Qt::CustomContextMenu);\n\taddStyle(TextBlockStyle(LOG_STYLE_DEFAULT));\n\tcreateActionsAndMenus();\n\n\tm_pSettingsDialog = new StyledLogViewSettingsDialog();\n\n\tconnect(this, SIGNAL(customContextMenuRequested(const QPoint &)),\n\t\tthis, SLOT(slotShowCustomMenu(const QPoint &)));\n\tconnect(m_pSettingsDialog, SIGNAL(signalSettingsChanged()),\n\t\tthis, SLOT(slotLogSettingsChanged()));\n}\n\n// END OF StyledLogView::StyledLogView(QWidget * a_pParent)\n//==============================================================================\n\nStyledLogView::~StyledLogView()\n{\n\tdelete m_pSettingsDialog;\n}\n\n// END OF StyledLogView::~StyledLogView()\n//==============================================================================\n\nTextBlockStyle StyledLogView::getStyle(const QString & a_styleName) const\n{\n\tTextBlockStyle style(a_styleName);\n\n\tQString styleName = a_styleName;\n\n\tQStringList foundAliasesList;\n\n\tstd::vector<TextBlockStyle>::const_iterator it = m_styles.end();\n\n\twhile(true)\n\t{\n\t\tit = std::find_if(m_styles.begin(), m_styles.end(),\n\t\t\t[&](const TextBlockStyle & a_style) -> bool\n\t\t\t{\n\t\t\t\treturn (a_style.name == styleName);\n\t\t\t});\n\n\t\tif(it == m_styles.end())\n\t\t\treturn style;\n\n\t\t// Alias retains its own visibility and title\n\t\tif(it->name == a_styleName)\n\t\t{\n\t\t\tstyle.isVisible = it->isVisible;\n\t\t\tstyle.title = it->title;\n\t\t}\n\n\t\tif(!it->isAlias)\n\t\t{\n\t\t\tstyle.textFormat = it->textFormat;\n\t\t\treturn style;\n\t\t}\n\n\t\tfoundAliasesList += it->name;\n\n\t\t// Check for aliasing loop\n\t\tif(foundAliasesList.contains(it->originalStyleName))\n\t\t\treturn style;\n\n\t\tstyleName = it->originalStyleName;\n\t}\n\n\treturn style;\n}\n\n// END OF TextBlockStyle StyledLogView::getStyle(\n//\t\tconst QString & a_styleName) const\n//==============================================================================\n\nvoid StyledLogView::addStyle(const TextBlockStyle & a_style,\n\tbool a_updateExisting)\n{\n\tTextBlockStyle newStyle(a_style);\n\n\t// Resolve original style for alias to prevent alias loop\n\tif(newStyle.isAlias)\n\t{\n\t\tTextBlockStyle originalStyle = getStyle(newStyle.originalStyleName);\n\t\tnewStyle.originalStyleName = originalStyle.name;\n\t}\n\n\tstd::vector<TextBlockStyle>::iterator it = std::find_if(m_styles.begin(),\n\t\tm_styles.end(), [&](const TextBlockStyle & la_style) -> bool\n\t\t{\n\t\t\treturn (la_style.name == newStyle.name);\n\t\t});\n\n\tif(it == m_styles.end())\n\t\tm_styles.push_back(newStyle);\n\telse if(a_updateExisting)\n\t\t*it = newStyle;\n}\n\n// END OF void StyledLogView::addStyle(const TextBlockStyle & a_style,\n//\t\tbool a_updateExisting)\n//==============================================================================\n\nvoid StyledLogView::addStyle(const QString & a_aliasName,\n\tconst QString & a_title, const QString & a_originalStyleName)\n{\n\t// no aliasing default style name\n\tif(a_aliasName == LOG_STYLE_DEFAULT)\n\t\treturn;\n\n\taddStyle(TextBlockStyle(a_aliasName, a_title, a_originalStyleName));\n}\n\n// END OF void StyledLogView::addStyle(const QString & a_aliasName,\n//\t\tconst QString & a_title, const QString & a_originalStyleName)\n//==============================================================================\n\nvoid StyledLogView::startNewBlock()\n{\n\tif(m_entries.empty())\n\t\treturn;\n\tif(m_entries.back().isDivider)\n\t\treturn;\n\tm_entries.push_back(LogEntry::divider());\n}\n\n// END OF void StyledLogView::startNewBlock()\n//==============================================================================\n\nqint64 StyledLogView::millisecondsToDivideBlocks() const\n{\n\treturn m_millisecondsToDivideBlocks;\n}\n\n// END OF qint64 StyledLogView::millisecondsToDivideBlocks() const\n//==============================================================================\n\nbool StyledLogView::setMillisecondsToDivideBlocks(qint64 a_value)\n{\n\tif(a_value < 0)\n\t\treturn false;\n\n\tm_millisecondsToDivideBlocks = a_value;\n\tupdateHtml();\n\treturn true;\n}\n\n// END OF bool StyledLogView::setMillisecondsToDivideBlocks(qint64 a_value)\n//==============================================================================\n\nQStringList StyledLogView::styles(bool a_excludeAliases) const\n{\n\tQStringList stylesList;\n\n\tfor(const TextBlockStyle & style : m_styles)\n\t\tif(!(a_excludeAliases && style.isAlias))\n\t\t\tstylesList += style.name;\n\n\treturn stylesList;\n}\n\n// END OF QStringList StyledLogView::styles(bool a_excludeAliases) const\n//==============================================================================\n\nbool StyledLogView::saveHtml(const QString & a_filePath,\n\tbool a_excludeFiltered)\n{\n\tif(a_filePath.isEmpty())\n\t\treturn false;\n\n\tQFile file(a_filePath);\n\n\tbool result = file.open(QIODevice::WriteOnly);\n\tif(!result)\n\t\treturn false;\n\n\tQByteArray htmlData = realHtml(a_excludeFiltered).toUtf8();\n\tqint64 bytesWritten = file.write(htmlData);\n\tfile.close();\n\n\tif(bytesWritten != htmlData.size())\n\t\treturn false;\n\n\treturn true;\n}\n\n// END OF bool StyledLogView::saveHtml(const QString & a_filePath,\n//\t\tbool a_excludeFiltered)\n//==============================================================================\n\nbool StyledLogView::saveHtml(bool a_excludeFiltered)\n{\n\tQString timeString =\n\t\tQDateTime::currentDateTime().toString(\"yyyy-MM-dd_hh-mm-ss-zzz\");\n\tQString fileName = tr(\"vapoursynth_editor_log_{time}.html\")\n\t\t.replace(\"{time}\", timeString);\n\n\tQString currentDir = QDir(\".\").absolutePath();\n\n\tQString filePath = currentDir + QString(\"/\") + fileName;\n\n\tfilePath = QFileDialog::getSaveFileName(this, tr(\"Save log\"),\n\t\tfilePath, tr(\"HTML files (*.html);;All files (*.*)\"));\n\n\treturn saveHtml(filePath, a_excludeFiltered);\n}\n\n// END OF bool StyledLogView::saveHtml(bool a_excludeFiltered)\n//==============================================================================\n\nvoid StyledLogView::addEntry(const QString & a_text, const QString & a_style)\n{\n\tm_entries.push_back(LogEntry(a_text, a_style));\n\tupdateHtml();\n}\n\n// END OF void StyledLogView::addEntry(const QString & a_text,\n//\t\tconst QString & a_style)\n//==============================================================================\n\nvoid StyledLogView::addEntry(const LogEntry & a_entry)\n{\n\tm_entries.push_back(a_entry);\n\tupdateHtml();\n}\n\n// END OF void void StyledLogView::addEntry(const LogEntry & a_entry)\n//==============================================================================\n\nvoid StyledLogView::clear()\n{\n\tm_entries.clear();\n\tQTextEdit::clear();\n}\n\n// END OF void StyledLogView::clear()\n//==============================================================================\n\nvoid StyledLogView::slotSaveHtml()\n{\n\tsaveHtml();\n}\n\n// END OF void StyledLogView::slotSaveHtml()\n//==============================================================================\n\nvoid StyledLogView::slotSaveHtmlFiltered()\n{\n\tsaveHtml(true);\n}\n\n// END OF void StyledLogView::slotSaveHtmlFiltered()\n//==============================================================================\n\nvoid StyledLogView::slotShowCustomMenu(const QPoint & a_position)\n{\n\tcreateActionsAndMenus();\n\tQPoint globalPosition = mapToGlobal(a_position);\n    m_pContextMenu->popup(globalPosition);\n}\n\n// END OF void StyledLogView::slotShowCustomMenu(const QPoint & a_position)\n//==============================================================================\n\nvoid StyledLogView::slotLogSettings()\n{\n\tQ_ASSERT(m_pSettingsDialog);\n\tm_pSettingsDialog->setStyles(m_styles);\n\tm_pSettingsDialog->show();\n}\n\n// END OF void StyledLogView::slotLogSettings()\n//==============================================================================\n\nvoid StyledLogView::slotLogSettingsChanged()\n{\n\tm_styles = m_pSettingsDialog->styles();\n\tupdateHtml();\n}\n\n// END OF void StyledLogView::slotLogSettingsChanged()\n//==============================================================================\n\nvoid StyledLogView::updateHtml()\n{\n\tif(m_entries.empty())\n\t{\n\t\tQTextEdit::clear();\n\t\treturn;\n\t}\n\n\tQString borderColor = palette().color(QPalette::Dark).name();\n\n\tQString html = QString(\n\t\t\"<body>\\n\"\n\t\t\"<style type=\\\"text/css\\\">\\n\"\n\t\t\"table {\"\n\t\t\t\"border-width: 1px;\"\n\t\t\t\"border-style: solid;\"\n\t\t\t\"border-color: {table-border-color};\"\n\t\t\"}\\n\"\n\t\t\"div {\"\n\t\t\t\"margin-left: 2px;\"\n\t\t\t\"margin-top: 2px;\"\n\t\t\t\"margin-right: 2px;\"\n\t\t\t\"margin-bottom: 2px;\"\n\t\t\"}\\n\"\n\t\t\"</style>\\n\"\n\t\t\"<table width=\\\"100%\\\" cellspacing=\\\"-1\\\">\\n\"\n\t\t).replace(\"{table-border-color}\", borderColor);\n\n\tbool openBlock = false;\n\tQDateTime lastTime;\n\tQString lastStyle;\n\n\tsize_t firstEntryToShow = 0;\n\n\tif(m_entries.size() > m_maxEntriesToShow)\n\t{\n\t\tfirstEntryToShow = m_entries.size() - m_maxEntriesToShow;\n\t\thtml += tr(\"<tr><td align=\\\"center\\\">%1 entries not shown. \"\n\t\t\t\"Save the log to read.</td></tr>\\n\").arg(firstEntryToShow);\n\t}\n\n\tfor(size_t i = firstEntryToShow; i < m_entries.size(); ++i)\n\t{\n\t\tconst LogEntry & entry = m_entries[i];\n\n\t\tTextBlockStyle style = getStyle(entry.style);\n\n\t\tif(!style.isVisible)\n\t\t\tcontinue;\n\n\t\tif(openBlock)\n\t\t{\n\t\t\tif(entry.isDivider ||\n\t\t\t\t(lastTime.msecsTo(entry.time) > m_millisecondsToDivideBlocks) ||\n\t\t\t\t(entry.style != lastStyle))\n\t\t\t{\n\t\t\t\thtml += QString(\"</td></tr>\\n\");\n\t\t\t\topenBlock = false;\n\t\t\t}\n\t\t}\n\n\t\tlastStyle = entry.style;\n\t\tlastTime = entry.time;\n\n\t\tif(entry.isDivider)\n\t\t\tcontinue;\n\n\t\tQTextCharFormat format = style.textFormat;\n\t\tQFont styleFont = format.font();\n\n\t\tif(!openBlock)\n\t\t{\n\t\t\thtml += QString(\"<tr bgcolor=\\\"%1\\\"><td>\")\n\t\t\t\t.arg(format.background().color().name());\n\t\t\tQString timeString = entry.time.toString(\"yyyy-MM-dd hh:mm:ss.zzz\");\n\t\t\thtml += QString(\"<div><font size=\\\"-2\\\" \"\n\t\t\t\t\"color=\\\"%1\\\">%2</font></div>\")\n\t\t\t\t.arg(format.foreground().color().name())\n\t\t\t\t.arg(timeString);\n\t\t\topenBlock = true;\n\t\t}\n\n\t\tQString entryHtml = entry.text;\n\t\tentryHtml.replace(\"\\n\", \"<br>\");\n\n\t\tif(styleFont.bold())\n\t\t\tentryHtml = QString(\"<b>%1</b>\").arg(entryHtml);\n\t\tif(styleFont.italic())\n\t\t\tentryHtml = QString(\"<i>%1</i>\").arg(entryHtml);\n\t\tif(styleFont.underline())\n\t\t\tentryHtml = QString(\"<u>%1</u>\").arg(entryHtml);\n\t\tif(styleFont.strikeOut())\n\t\t\tentryHtml = QString(\"<s>%1</s>\").arg(entryHtml);\n\n\t\thtml += QString(\"<div><font face=\\\"%1\\\" \"\n\t\t\t\"color=\\\"%2\\\">%3</font></div>\")\n\t\t\t.arg(styleFont.family())\n\t\t\t.arg(format.foreground().color().name())\n\t\t\t.arg(entryHtml);\n\t}\n\n\tif(openBlock)\n\t\thtml += QString(\"</td></tr>\\n\");\n\n\thtml += QString(\"</table>\\n</body>\");\n\n\tsetHtml(html);\n\n\tverticalScrollBar()->setValue(verticalScrollBar()->maximum());\n}\n\n// END OF void StyledLogView::updateHtml()\n//==============================================================================\n\nvoid StyledLogView::createActionsAndMenus()\n{\n\tif(m_pContextMenu)\n\t\tdelete m_pContextMenu;\n\n\tm_pContextMenu = createStandardContextMenu();\n\n\tstruct ActionToCreate\n\t{\n\t\tQString title;\n\t\tconst char * slotToConnect;\n\t\tbool isSeparator;\n\n\t\tActionToCreate(const QString & a_title, const char * a_slotToConnect) :\n\t\t\ttitle(a_title), slotToConnect(a_slotToConnect), isSeparator(false)\n\t\t{};\n\n\t\tActionToCreate() : title(), slotToConnect(nullptr), isSeparator(true)\n\t\t{};\n\t};\n\n\tconst ActionToCreate SEPARATOR;\n\n\tActionToCreate actionsToCreate[] = {\n\t\tSEPARATOR,\n\t\t{tr(\"Log settings\"), SLOT(slotLogSettings())},\n\t\tSEPARATOR,\n\t\t{tr(\"Save\"), SLOT(slotSaveHtml())},\n\t\t{tr(\"Save filtered\"), SLOT(slotSaveHtmlFiltered())},\n\t\t{tr(\"Clear\"), SLOT(clear())},\n\t};\n\n\tfor(const ActionToCreate & action : actionsToCreate)\n\t{\n\t\tif(action.isSeparator)\n\t\t\tm_pContextMenu->addSeparator();\n\t\telse\n\t\t\tm_pContextMenu->addAction(action.title, this, action.slotToConnect);\n\t}\n}\n\n// END OF void StyledLogView::createActionsAndMenus()\n//==============================================================================\n\nQString StyledLogView::realHtml(bool a_excludeFiltered) const\n{\n\tQString title = tr(\"VapourSynth Editor log \") +\n\t\tQDateTime::currentDateTime().toString(\"yyyy-MM-dd hh:mm:ss.zzz\");\n\n\tQString borderColor = palette().color(QPalette::Dark).name();\n\n\tQString styleText = QString(\n\t\t\"<style type=\\\"text/css\\\">\\n\"\n\t\t\"table, td {border: 1px solid {table-border-color};}\\n\"\n\t\t\"table {border-collapse: collapse; width: 100%;}\\n\"\n\t\t\"p {padding: 0; margin: 0;}\\n\"\n\t).replace(\"{table-border-color}\", borderColor);\n\n\tstyleText += \"</style>\\n\";\n\n\tQString html = QString(\n\t\t\"<!DOCTYPE HTML PUBLIC \\\"-//W3C//DTD HTML 4.01//EN\\\" \"\n\t\t\"\\\"http://www.w3.org/TR/html4/strict.dtd\\\">\\n\"\n\t\t\"<html>\\n\"\n\t\t\"<head>\\n\"\n\t\t\"<title>{title}</title>\\n\"\n\t\t\"{style}\"\n\t\t\"</head>\\n\"\n\t\t\"<body>\\n\"\n\t\t\"<table>\\n\"\n\t).replace(\"{title}\", title)\n\t\t.replace(\"{style}\", styleText);\n\n\tbool openBlock = false;\n\tQDateTime lastTime;\n\tQString lastStyle;\n\n\tfor(const LogEntry & entry : m_entries)\n\t{\n\t\tTextBlockStyle style = getStyle(entry.style);\n\n\t\tif(a_excludeFiltered && (!style.isVisible))\n\t\t\tcontinue;\n\n\t\tif(openBlock)\n\t\t{\n\t\t\tif(entry.isDivider ||\n\t\t\t\t(lastTime.msecsTo(entry.time) > m_millisecondsToDivideBlocks) ||\n\t\t\t\t(entry.style != lastStyle))\n\t\t\t{\n\t\t\t\thtml += QString(\"</td></tr>\\n\");\n\t\t\t\topenBlock = false;\n\t\t\t}\n\t\t}\n\n\t\tlastStyle = entry.style;\n\t\tlastTime = entry.time;\n\n\t\tif(entry.isDivider)\n\t\t\tcontinue;\n\n\t\tQTextCharFormat format = style.textFormat;\n\t\tQFont styleFont = format.font();\n\n\t\tif(!openBlock)\n\t\t{\n\t\t\thtml += QString(\"<tr bgcolor=\\\"%1\\\"><td>\\n\")\n\t\t\t\t.arg(format.background().color().name());\n\t\t\tQString timeString = entry.time.toString(\"yyyy-MM-dd hh:mm:ss.zzz\");\n\t\t\thtml += QString(\"<p style=\\\"font-size: 70%; \"\n\t\t\t\t\"color: %1;\\\">%2</p>\\n\")\n\t\t\t\t.arg(format.foreground().color().name())\n\t\t\t\t.arg(timeString);\n\t\t\topenBlock = true;\n\t\t}\n\n\t\tQString entryHtml = entry.text;\n\t\tentryHtml.replace(\"\\n\", \"<br>\\n\");\n\n\t\tif(styleFont.bold())\n\t\t\tentryHtml = QString(\"<b>%1</b>\").arg(entryHtml);\n\t\tif(styleFont.italic())\n\t\t\tentryHtml = QString(\"<i>%1</i>\").arg(entryHtml);\n\t\tif(styleFont.underline())\n\t\t\tentryHtml = QString(\"<u>%1</u>\").arg(entryHtml);\n\t\tif(styleFont.strikeOut())\n\t\t\tentryHtml = QString(\"<s>%1</s>\").arg(entryHtml);\n\n\t\thtml += QString(\"<p style=\\\"font-family: %1; color: %2;\\\">%3</p>\\n\")\n\t\t\t.arg(styleFont.family())\n\t\t\t.arg(format.foreground().color().name())\n\t\t\t.arg(entryHtml);\n\t}\n\n\tif(openBlock)\n\t\thtml += QString(\"</td>\\n</tr>\\n\");\n\n\thtml += \"</table>\\n</body>\\n</html>\\n\";\n\n\treturn html;\n}\n\n// END OF QString StyledLogView::realHtml(bool a_excludeFiltered) const\n//==============================================================================\n"
  },
  {
    "path": "common-src/log/styled_log_view.h",
    "content": "#ifndef STYLED_LOG_VIEW_H_INCLUDED\n#define STYLED_LOG_VIEW_H_INCLUDED\n\n#include \"styled_log_view_structures.h\"\n\n#include <QTextEdit>\n#include <vector>\n\nclass StyledLogViewSettingsDialog;\n\nclass StyledLogView : public QTextEdit\n{\n\tQ_OBJECT\n\npublic:\n\n\tstatic const size_t DEFAULT_MAX_ENTRIES_TO_SHOW;\n\n\tStyledLogView(QWidget * a_pParent = nullptr);\n\tvirtual ~StyledLogView();\n\n\tvirtual TextBlockStyle getStyle(const QString & a_styleName) const;\n\n\tvirtual void addStyle(const TextBlockStyle & a_style,\n\t\tbool a_updateExisting = true);\n\n\tvirtual void addStyle(const QString & a_aliasName,\n\t\tconst QString & a_title,\n\t\tconst QString & a_originalStyleName = LOG_STYLE_DEFAULT);\n\n\tvirtual void startNewBlock();\n\n\tvirtual qint64 millisecondsToDivideBlocks() const;\n\n\tvirtual bool setMillisecondsToDivideBlocks(qint64 a_value);\n\n\tvirtual QStringList styles(bool a_excludeAliases = false) const;\n\n\tvirtual bool saveHtml(const QString & a_filePath,\n\t\tbool a_excludeFiltered = false);\n\n\tvirtual bool saveHtml(bool a_excludeFiltered = false);\n\npublic slots:\n\n\tvirtual void addEntry(const QString & a_text,\n\t\tconst QString & a_style = LOG_STYLE_DEFAULT);\n\n\tvirtual void addEntry(const LogEntry & a_entry);\n\n\tvirtual void clear();\n\n\tvirtual void slotSaveHtml();\n\n\tvirtual void slotSaveHtmlFiltered();\n\nprotected slots:\n\n\tvirtual void slotShowCustomMenu(const QPoint & a_position);\n\n\tvirtual void slotLogSettings();\n\n\tvirtual void slotLogSettingsChanged();\n\nprotected:\n\n\tvirtual void updateHtml();\n\n\tvirtual void createActionsAndMenus();\n\n\tvirtual QString realHtml(bool a_excludeFiltered = false) const;\n\n\tstd::vector<TextBlockStyle> m_styles;\n\tstd::vector<LogEntry> m_entries;\n\n\tqint64 m_millisecondsToDivideBlocks;\n\n\tQMenu * m_pContextMenu;\n\n\tStyledLogViewSettingsDialog * m_pSettingsDialog;\n\n\tsize_t m_maxEntriesToShow;\n};\n\n#endif // STYLED_LOG_VIEW_H_INCLUDED\n"
  },
  {
    "path": "common-src/log/styled_log_view_core.cpp",
    "content": "#include \"styled_log_view_core.h\"\n\n#include <QVariant>\n\n//==============================================================================\n\nconst char LOG_STYLE_DEFAULT[] = \"info\";\nconst char LOG_STYLE_TITLE_DEFAULT[] = \"Info message\";\n\nconst char LE_IS_DIVIDER[] = \"isDivider\";\nconst char LE_TIME[] = \"time\";\nconst char LE_TEXT[] = \"text\";\nconst char LE_STYLE[] = \"style\";\n\n//==============================================================================\n\nLogEntry::LogEntry(bool a_isDivider, const QString & a_text,\n\tconst QString & a_style) :\n\t  isDivider(a_isDivider)\n\t, time(QDateTime::currentDateTime())\n\t, text(a_text)\n\t, style(a_style)\n{\n}\n\n// END OF LogEntry::LogEntry(bool a_isDivider, const QString & a_text,\n//\t\tconst QString & a_style)\n//==============================================================================\n\nLogEntry::LogEntry(const QString & a_text, const QString & a_style) :\n\t  isDivider(false)\n\t, time(QDateTime::currentDateTime())\n\t, text(a_text)\n\t, style(a_style)\n{\n}\n\n// END OF LogEntry::LogEntry(const QString & a_text, const QString & a_style)\n//==============================================================================\n\nLogEntry LogEntry::divider()\n{\n\treturn LogEntry(true, QString(), QString());\n}\n\n// END OF LogEntry LogEntry::divider()\n//==============================================================================\n\nQJsonObject LogEntry::toJson() const\n{\n\tQJsonObject jsLogEntry;\n\tjsLogEntry[LE_IS_DIVIDER] = isDivider;\n\tjsLogEntry[LE_TIME] = time.toMSecsSinceEpoch();\n\tif(isDivider)\n\t\treturn jsLogEntry;\n\tjsLogEntry[LE_TEXT] = text;\n\tjsLogEntry[LE_STYLE] = style;\n\treturn jsLogEntry;\n}\n\n// END OF QJsonObject LogEntry::toJson() const\n//==============================================================================\n\nLogEntry LogEntry::fromJson(const QJsonObject & a_object)\n{\n\tLogEntry entry;\n\tif(a_object.contains(LE_IS_DIVIDER))\n\t\tentry.isDivider = a_object[LE_IS_DIVIDER].toBool();\n\tif(a_object.contains(LE_TIME))\n\t\tentry.time = QDateTime::fromMSecsSinceEpoch(\n\t\t\ta_object[LE_TIME].toVariant().toLongLong());\n\tif(a_object.contains(LE_TEXT))\n\t\tentry.text = a_object[LE_TEXT].toString();\n\tif(a_object.contains(LE_STYLE))\n\t\tentry.style = a_object[LE_STYLE].toString();\n\treturn entry;\n}\n\n// END OF LogEntry LogEntry::fromJson(const QJsonObject & a_object)\n//==============================================================================\n"
  },
  {
    "path": "common-src/log/styled_log_view_core.h",
    "content": "#ifndef STYLED_LOG_VIEW_CORE_H_INCLUDED\n#define STYLED_LOG_VIEW_CORE_H_INCLUDED\n\n#include <QString>\n#include <QDateTime>\n#include <QJsonObject>\n\n//==============================================================================\n\nextern const char LOG_STYLE_DEFAULT[];\nextern const char LOG_STYLE_TITLE_DEFAULT[];\n\nextern const char LE_IS_DIVIDER[];\nextern const char LE_TIME[];\nextern const char LE_TEXT[];\nextern const char LE_STYLE[];\n\n//==============================================================================\n\nstruct LogEntry\n{\n\tbool isDivider;\n\tQDateTime time;\n\tQString text;\n\tQString style;\n\n\tLogEntry(bool a_isDivider = false, const QString & a_text = QString(),\n\t\tconst QString & a_style = LOG_STYLE_DEFAULT);\n\n\tLogEntry(const QString & a_text, const QString & a_style =\n\t\tLOG_STYLE_DEFAULT);\n\n\tstatic LogEntry divider();\n\n\tQJsonObject toJson() const;\n\tstatic LogEntry fromJson(const QJsonObject & a_object);\n};\n\n//==============================================================================\n\n#endif // STYLED_LOG_VIEW_CORE_H_INCLUDED\n"
  },
  {
    "path": "common-src/log/styled_log_view_settings_dialog.cpp",
    "content": "#include \"styled_log_view_settings_dialog.h\"\n\n#include \"log_styles_model.h\"\n\n#include <QGuiApplication>\n#include <QFontDialog>\n#include <QColorDialog>\n\n//==============================================================================\n\nStyledLogViewSettingsDialog::StyledLogViewSettingsDialog(QWidget * a_pParent):\n\t  QDialog(a_pParent, \n\t\t  Qt::Dialog\n\t\t| Qt::CustomizeWindowHint\n\t\t| Qt::WindowTitleHint\n\t\t| Qt::WindowCloseButtonHint)\n\t, m_pLogStylesModel(nullptr)\n{\n\tm_ui.setupUi(this);\n\n\tm_pLogStylesModel = new LogStylesModel(this);\n\tm_ui.stylesView->setModel(m_pLogStylesModel);\n\n\tconnect(m_ui.okButton, SIGNAL(clicked()), this, SLOT(slotOk()));\n\tconnect(m_ui.applyButton, SIGNAL(clicked()), this, SLOT(slotApply()));\n\tconnect(m_ui.cancelButton, SIGNAL(clicked()), this, SLOT(reject()));\n\n\tconnect(m_ui.stylesView, SIGNAL(clicked(const QModelIndex &)),\n\t\tthis, SLOT(slotStyleSelected(const QModelIndex &)));\n\n\tconnect(m_ui.fontButton, SIGNAL(clicked()),\n\t\tthis, SLOT(slotFontButtonClicked()));\n\tconnect(m_ui.textColorButton, SIGNAL(clicked()),\n\t\tthis, SLOT(slotTextColorButtonClicked()));\n\tconnect(m_ui.backgroundColorButton, SIGNAL(clicked()),\n\t\tthis, SLOT(slotBackgroundColorButtonClicked()));\n}\n\n// END OF StyledLogViewSettingsDialog::StyledLogViewSettingsDialog(\n//\t\tQWidget * a_pParent)\n//==============================================================================\n\nStyledLogViewSettingsDialog::~StyledLogViewSettingsDialog()\n{\n}\n\n// END OF StyledLogViewSettingsDialog::~StyledLogViewSettingsDialog()\n//==============================================================================\n\nstd::vector<TextBlockStyle> StyledLogViewSettingsDialog::styles() const\n{\n\tQ_ASSERT(m_pLogStylesModel);\n\treturn m_pLogStylesModel->styles();\n}\n\n// END OF std::vector<TextBlockStyle> StyledLogViewSettingsDialog::styles()\n//\t\tconst\n//==============================================================================\n\nvoid StyledLogViewSettingsDialog::setStyles(\n\tconst std::vector<TextBlockStyle> & a_styles)\n{\n\tQ_ASSERT(m_pLogStylesModel);\n\tm_pLogStylesModel->setStyles(a_styles);\n\tm_ui.stylesView->resizeRowsToContents();\n}\n\n// END OF void StyledLogViewSettingsDialog::setStyles(\n//\t\tconst std::vector<TextBlockStyle> & a_styles)\n//==============================================================================\n\nvoid StyledLogViewSettingsDialog::slotOk()\n{\n\tslotApply();\n\tclose();\n}\n\n// END OF void StyledLogViewSettingsDialog::slotOk()\n//==============================================================================\n\nvoid StyledLogViewSettingsDialog::slotApply()\n{\n\temit signalSettingsChanged();\n}\n\n// END OF void StyledLogViewSettingsDialog::slotApply()\n//==============================================================================\n\nvoid StyledLogViewSettingsDialog::slotStyleSelected(const QModelIndex & a_index)\n{\n\tTextBlockStyle style = m_pLogStylesModel->style(a_index);\n\tQTextCharFormat format = style.textFormat;\n\n\tenableStyleSettingsControls(!style.isAlias);\n\n\tQPalette palette = QGuiApplication::palette();\n\tQString textColorString = style.isAlias ?\n\t\tpalette.color(QPalette::Disabled, QPalette::WindowText).name() :\n\t\tformat.foreground().color().name();\n\tQString backgroundColorString = style.isAlias ?\n\t\tpalette.color(QPalette::Disabled, QPalette::Window).name() :\n\t\tformat.background().color().name();\n\tQString styleSheetString =\n\t\tQString(\"QLabel {background-color : \\\"%1\\\"; color : \\\"%2\\\";}\")\n\t\t.arg(backgroundColorString).arg(textColorString);\n\n\tm_ui.fontLabel->setStyleSheet(styleSheetString);\n\n\tif(style.isAlias)\n\t{\n\t\tm_ui.fontLabel->clear();\n\t}\n\telse\n\t{\n\t\tm_ui.fontLabel->setFont(format.font());\n\t\tm_ui.fontLabel->setText(format.font().family());\n\t}\n}\n\n// END OF void StyledLogViewSettingsDialog::slotStyleSelected(\n//\t\tconst QModelIndex & a_index)\n//==============================================================================\n\nvoid StyledLogViewSettingsDialog::slotFontButtonClicked()\n{\n\tQModelIndex index = m_ui.stylesView->currentIndex();\n\tif(!index.isValid())\n\t\treturn;\n\n\tTextBlockStyle style = m_pLogStylesModel->style(index);\n\n\tQFontDialog fontDialog;\n\tfontDialog.setCurrentFont(style.textFormat.font());\n\tint returnCode = fontDialog.exec();\n\tif(returnCode == QDialog::Rejected)\n\t\treturn;\n\n\tQFont newFont = fontDialog.selectedFont();\n\tm_pLogStylesModel->setStyleFont(index.row(), newFont);\n\tslotStyleSelected(index);\n}\n\n// END OF void StyledLogViewSettingsDialog::slotFontButtonClicked()\n//==============================================================================\n\nvoid StyledLogViewSettingsDialog::slotTextColorButtonClicked()\n{\n\tQModelIndex index = m_ui.stylesView->currentIndex();\n\tif(!index.isValid())\n\t\treturn;\n\n\tTextBlockStyle style = m_pLogStylesModel->style(index);\n\n\tQColorDialog colorDialog;\n\tcolorDialog.setCurrentColor(style.textFormat.foreground().color());\n\n\tint returnCode = colorDialog.exec();\n\tif(returnCode == QDialog::Rejected)\n\t\treturn;\n\n\tQColor newColor = colorDialog.selectedColor();\n\tm_pLogStylesModel->setStyleTextColor(index.row(), newColor);\n\tslotStyleSelected(index);\n}\n\n// END OF void StyledLogViewSettingsDialog::slotTextColorButtonClicked()\n//==============================================================================\n\nvoid StyledLogViewSettingsDialog::slotBackgroundColorButtonClicked()\n{\n\tQModelIndex index = m_ui.stylesView->currentIndex();\n\tif(!index.isValid())\n\t\treturn;\n\n\tTextBlockStyle style = m_pLogStylesModel->style(index);\n\n\tQColorDialog colorDialog;\n\tcolorDialog.setCurrentColor(style.textFormat.background().color());\n\n\tint returnCode = colorDialog.exec();\n\tif(returnCode == QDialog::Rejected)\n\t\treturn;\n\n\tQColor newColor = colorDialog.selectedColor();\n\tm_pLogStylesModel->setStyleBackgroundColor(index.row(), newColor);\n\tslotStyleSelected(index);\n}\n\n// END OF void StyledLogViewSettingsDialog::slotBackgroundColorButtonClicked()\n//==============================================================================\n\nvoid StyledLogViewSettingsDialog::enableStyleSettingsControls(bool a_enable)\n{\n\tQWidget * widgetsToEnable[] = {m_ui.fontButton, m_ui.textColorButton,\n\t\tm_ui.backgroundColorButton, m_ui.fontLabel};\n\n\tfor(QWidget * pWidget : widgetsToEnable)\n\t\tpWidget->setEnabled(a_enable);\n}\n\n// END OF void StyledLogViewSettingsDialog::enableStyleSettingsControls(\n//\t\tbool a_enable)\n//==============================================================================\n"
  },
  {
    "path": "common-src/log/styled_log_view_settings_dialog.h",
    "content": "#ifndef STYLED_LOG_VIEW_SETTINGS_DIALOG_H_INCLUDED\n#define STYLED_LOG_VIEW_SETTINGS_DIALOG_H_INCLUDED\n\n#include <ui_styled_log_view_settings_dialog.h>\n\n#include \"styled_log_view_structures.h\"\n\nclass LogStylesModel;\n\nclass StyledLogViewSettingsDialog : public QDialog\n{\n\tQ_OBJECT\n\npublic:\n\n\tStyledLogViewSettingsDialog(QWidget * a_pParent = nullptr);\n\n\tvirtual ~StyledLogViewSettingsDialog();\n\n\tvirtual std::vector<TextBlockStyle> styles() const;\n\n\tvirtual void setStyles(const std::vector<TextBlockStyle> & a_styles);\n\nsignals:\n\n\tvoid signalSettingsChanged();\n\nprotected slots:\n\n\tvirtual void slotOk();\n\n\tvirtual void slotApply();\n\n\tvirtual void slotStyleSelected(const QModelIndex & a_index);\n\n\tvirtual void slotFontButtonClicked();\n\n\tvirtual void slotTextColorButtonClicked();\n\n\tvirtual void slotBackgroundColorButtonClicked();\n\nprotected:\n\n\tvirtual void enableStyleSettingsControls(bool a_enable = true);\n\n\tUi::StyledLogViewSettingsDialog m_ui;\n\n\tLogStylesModel * m_pLogStylesModel;\n};\n\n#endif // STYLED_LOG_VIEW_SETTINGS_DIALOG_H_INCLUDED\n"
  },
  {
    "path": "common-src/log/styled_log_view_settings_dialog.ui",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<ui version=\"4.0\">\n <class>StyledLogViewSettingsDialog</class>\n <widget class=\"QDialog\" name=\"StyledLogViewSettingsDialog\">\n  <property name=\"geometry\">\n   <rect>\n    <x>0</x>\n    <y>0</y>\n    <width>306</width>\n    <height>497</height>\n   </rect>\n  </property>\n  <property name=\"windowTitle\">\n   <string>Log settings</string>\n  </property>\n  <layout class=\"QVBoxLayout\" name=\"verticalLayout\">\n   <property name=\"spacing\">\n    <number>4</number>\n   </property>\n   <property name=\"leftMargin\">\n    <number>2</number>\n   </property>\n   <property name=\"topMargin\">\n    <number>2</number>\n   </property>\n   <property name=\"rightMargin\">\n    <number>2</number>\n   </property>\n   <property name=\"bottomMargin\">\n    <number>2</number>\n   </property>\n   <item>\n    <widget class=\"QTableView\" name=\"stylesView\">\n     <property name=\"alternatingRowColors\">\n      <bool>true</bool>\n     </property>\n     <property name=\"selectionMode\">\n      <enum>QAbstractItemView::SingleSelection</enum>\n     </property>\n     <property name=\"selectionBehavior\">\n      <enum>QAbstractItemView::SelectRows</enum>\n     </property>\n     <attribute name=\"horizontalHeaderVisible\">\n      <bool>false</bool>\n     </attribute>\n     <attribute name=\"horizontalHeaderStretchLastSection\">\n      <bool>true</bool>\n     </attribute>\n     <attribute name=\"verticalHeaderVisible\">\n      <bool>false</bool>\n     </attribute>\n    </widget>\n   </item>\n   <item>\n    <widget class=\"QLabel\" name=\"fontLabel\">\n     <property name=\"sizePolicy\">\n      <sizepolicy hsizetype=\"Expanding\" vsizetype=\"Preferred\">\n       <horstretch>0</horstretch>\n       <verstretch>0</verstretch>\n      </sizepolicy>\n     </property>\n     <property name=\"frameShape\">\n      <enum>QFrame::Box</enum>\n     </property>\n     <property name=\"text\">\n      <string/>\n     </property>\n    </widget>\n   </item>\n   <item>\n    <layout class=\"QHBoxLayout\" name=\"horizontalLayout_2\">\n     <property name=\"spacing\">\n      <number>4</number>\n     </property>\n     <item>\n      <widget class=\"QPushButton\" name=\"fontButton\">\n       <property name=\"text\">\n        <string>Font</string>\n       </property>\n      </widget>\n     </item>\n     <item>\n      <widget class=\"QPushButton\" name=\"textColorButton\">\n       <property name=\"text\">\n        <string>Text color</string>\n       </property>\n      </widget>\n     </item>\n     <item>\n      <widget class=\"QPushButton\" name=\"backgroundColorButton\">\n       <property name=\"text\">\n        <string>Background color</string>\n       </property>\n      </widget>\n     </item>\n    </layout>\n   </item>\n   <item>\n    <layout class=\"QHBoxLayout\" name=\"horizontalLayout\">\n     <property name=\"spacing\">\n      <number>4</number>\n     </property>\n     <item>\n      <widget class=\"QPushButton\" name=\"okButton\">\n       <property name=\"text\">\n        <string>OK</string>\n       </property>\n      </widget>\n     </item>\n     <item>\n      <widget class=\"QPushButton\" name=\"applyButton\">\n       <property name=\"text\">\n        <string>Apply</string>\n       </property>\n      </widget>\n     </item>\n     <item>\n      <widget class=\"QPushButton\" name=\"cancelButton\">\n       <property name=\"text\">\n        <string>Cancel</string>\n       </property>\n       <property name=\"default\">\n        <bool>true</bool>\n       </property>\n      </widget>\n     </item>\n    </layout>\n   </item>\n  </layout>\n </widget>\n <resources/>\n <connections/>\n</ui>\n"
  },
  {
    "path": "common-src/log/styled_log_view_structures.cpp",
    "content": "#include \"styled_log_view_structures.h\"\n\n#include <QGuiApplication>\n#include <QPalette>\n\n//==============================================================================\n\nTextBlockStyle::TextBlockStyle(const QString & a_name, const QString & a_title):\n\t  name(a_name)\n\t, title(a_title)\n\t, isAlias(false)\n\t, isVisible(true)\n{\n\tQPalette palette = QGuiApplication::palette();\n\ttextFormat.setBackground(palette.color(QPalette::Active, QPalette::Base));\n\ttextFormat.setForeground(palette.color(QPalette::Active, QPalette::Text));\n}\n\n// END OFTextBlockStyle::TextBlockStyle(const QString & a_name,\n//\t\tconst QString & a_title)\n//==============================================================================\n\nTextBlockStyle::TextBlockStyle(const QString & a_name, const QString & a_title,\n\tconst QTextCharFormat & a_textFormat):\n\t  name(a_name)\n\t, title(a_title)\n\t, textFormat(a_textFormat)\n\t, isAlias(false)\n\t, isVisible(true)\n{\n}\n\n// END OF TextBlockStyle::TextBlockStyle(const QString & a_name,\n//\t\tconst QString & a_title, const QTextCharFormat & a_textFormat)\n//==============================================================================\n\nTextBlockStyle::TextBlockStyle(const QString & a_name, const QString & a_title,\n\tconst QColor & a_backgroundColor, const QColor & a_textColor):\n\t  name(a_name)\n\t, title(a_title)\n\t, isAlias(false)\n\t, isVisible(true)\n{\n\ttextFormat.setForeground(a_textColor);\n\ttextFormat.setBackground(a_backgroundColor);\n}\n\n// END OF TextBlockStyle::TextBlockStyle(const QString & a_name,\n//\t\tconst QString & a_title, const QColor & a_backgroundColor,\n//\t\tconst QColor & a_textColor)\n//==============================================================================\n\nTextBlockStyle::TextBlockStyle(const QString & a_aliasName,\n\tconst QString & a_title, const QString & a_originalStyleName):\n\t  name(a_aliasName)\n\t, title(a_title)\n\t, isAlias(true)\n\t, originalStyleName(a_originalStyleName)\n\t, isVisible(true)\n{\n}\n\n// END OF TextBlockStyle::TextBlockStyle(const QString & a_aliasName,\n//\t\tconst QString & a_title, const QString & a_originalStyleName)\n//==============================================================================\n"
  },
  {
    "path": "common-src/log/styled_log_view_structures.h",
    "content": "#ifndef STYLED_LOG_VIEW_STRUCTURES_H_INCLUDED\n#define STYLED_LOG_VIEW_STRUCTURES_H_INCLUDED\n\n#include \"styled_log_view_core.h\"\n\n#include <QColor>\n#include <QTextCharFormat>\n\n//==============================================================================\n\nstruct TextBlockStyle\n{\n\tQString name;\n\tQString title;\n\tQTextCharFormat textFormat;\n\tbool isAlias;\n\tQString originalStyleName;\n\tbool isVisible;\n\n\tTextBlockStyle(const QString & a_name = LOG_STYLE_DEFAULT,\n\t\tconst QString & a_title = LOG_STYLE_TITLE_DEFAULT);\n\tTextBlockStyle(const QString & a_name, const QString & a_title,\n\t\tconst QTextCharFormat & a_textFormat);\n\tTextBlockStyle(const QString & a_name, const QString & a_title,\n\t\tconst QColor & a_backgroundColor, const QColor & a_textColor);\n\tTextBlockStyle(const QString & a_aliasName, const QString & a_title,\n\t\tconst QString & a_originalStyleName);\n};\n\n//==============================================================================\n\n#endif // STYLED_LOG_VIEW_STRUCTURES_H_INCLUDED\n"
  },
  {
    "path": "common-src/log/vs_editor_log.cpp",
    "content": "#include \"vs_editor_log.h\"\n\n#include \"../settings/settings_manager.h\"\n\n//==============================================================================\n\nVSEditorLog::VSEditorLog(QWidget * a_pParent) :\n\t  StyledLogView(a_pParent)\n\t, m_pSettingsManager(nullptr)\n{\n\tinitializeStyles();\n}\n\n// END OF VSEditorLog::VSEditorLog(QWidget * a_pParent)\n//==============================================================================\n\nVSEditorLog::~VSEditorLog()\n{\n}\n\n// END OF VSEditorLog::~VSEditorLog()\n//==============================================================================\n\nQString VSEditorLog::name() const\n{\n\treturn m_name;\n}\n\n// END OF QString VSEditorLog::name() const\n//==============================================================================\n\nvoid VSEditorLog::setName(const QString & a_name)\n{\n\tm_name = a_name;\n}\n\n// END OF void VSEditorLog::setName(const QString & a_name)\n//==============================================================================\n\nvoid VSEditorLog::setSettingsManager(SettingsManager * a_pSettingsManager)\n{\n\tm_pSettingsManager = a_pSettingsManager;\n}\n\n// END OF void VSEditorLog::setSettingsManager(\n//\t\tSettingsManager * a_pSettingsManager)\n//==============================================================================\n\nbool VSEditorLog::loadSettings()\n{\n\tif(!m_pSettingsManager)\n\t\treturn false;\n\n\tif(m_name.isEmpty())\n\t\treturn false;\n\n\tconst std::vector<TextBlockStyle> styles =\n\t\tm_pSettingsManager->getLogStyles(m_name);\n\n\tfor(TextBlockStyle & style : m_styles)\n\t{\n\t\tstd::vector<TextBlockStyle>::const_iterator it =\n\t\t\tstd::find_if(styles.begin(), styles.end(),\n\t\t\t\t[&](const TextBlockStyle & a_style) -> bool\n\t\t\t\t{\n\t\t\t\t\treturn (a_style.name == style.name);\n\t\t\t\t});\n\n\t\tif(it != styles.end())\n\t\t\tstyle = *it;\n\t}\n\n\treturn true;\n}\n\n// END OF bool VSEditorLog::loadSettings()\n//==============================================================================\n\nbool VSEditorLog::saveSettings()\n{\n\tif(!m_pSettingsManager)\n\t\treturn false;\n\n\tif(m_name.isEmpty())\n\t\treturn false;\n\n\treturn m_pSettingsManager->setLogStyles(m_name, m_styles);\n}\n\n// END OF bool VSEditorLog::saveSettings()\n//==============================================================================\n\nvoid VSEditorLog::slotLogSettingsChanged()\n{\n\tStyledLogView::slotLogSettingsChanged();\n\tsaveSettings();\n}\n\n// END OF void VSEditorLog::slotLogSettingsChanged()\n//==============================================================================\n\nvoid VSEditorLog::initializeStyles()\n{\n\tTextBlockStyle stylesToCreate[] = {\n\t\t{LOG_STYLE_ERROR, tr(\"Error\"), QColor(\"#ffeeee\"), Qt::darkRed},\n\t\t{LOG_STYLE_DEBUG, tr(\"Debug message\"),\n\t\t\tpalette().color(QPalette::Active, QPalette::Base),\n\t\t\tpalette().color(QPalette::Active, QPalette::Dark)},\n\t\t{LOG_STYLE_WARNING, tr(\"Warning\"), QColor(\"#eeeeff\"), Qt::darkBlue},\n\t\t{LOG_STYLE_POSITIVE, tr(\"Positive message\"), QColor(\"#eeffee\"),\n\t\t\tQt::darkGreen},\n\n\t\t// Aliases\n\t\t{LOG_STYLE_VS_DEBUG, tr(\"VapourSynth debug message\"),\n\t\t\tLOG_STYLE_DEBUG},\n\t\t{LOG_STYLE_VS_WARNING, tr(\"VapourSynth warning\"),\n\t\t\tLOG_STYLE_WARNING},\n\t\t{LOG_STYLE_VS_CRITICAL, tr(\"VapourSynth error\"), LOG_STYLE_ERROR},\n\t\t{LOG_STYLE_VS_FATAL, tr(\"VapourSynth fatal error\"),\n\t\t\tLOG_STYLE_ERROR},\n\t\t{LOG_STYLE_QT_DEBUG, tr(\"Qt debug message\"), LOG_STYLE_DEBUG},\n\t\t{LOG_STYLE_QT_INFO, tr(\"Qt info\"), LOG_STYLE_DEFAULT},\n\t\t{LOG_STYLE_QT_WARNING, tr(\"Qt warning\"), LOG_STYLE_WARNING},\n\t\t{LOG_STYLE_QT_CRITICAL, tr(\"Qt critical error\"), LOG_STYLE_ERROR},\n\t\t{LOG_STYLE_QT_FATAL, tr(\"Qt fatal error\"), LOG_STYLE_ERROR},\n\t};\n\n\tfor(TextBlockStyle & styleToCreate : stylesToCreate)\n\t\taddStyle(styleToCreate);\n}\n\n// END OF void VSEditorLog::initializeStyles()\n//==============================================================================\n"
  },
  {
    "path": "common-src/log/vs_editor_log.h",
    "content": "#ifndef VS_EDITOR_LOG_H_INCLUDED\n#define VS_EDITOR_LOG_H_INCLUDED\n\n#include \"styled_log_view.h\"\n#include \"vs_editor_log_definitions.h\"\n\nclass SettingsManager;\n\nclass VSEditorLog : public StyledLogView\n{\n\tQ_OBJECT\n\npublic:\n\n\tVSEditorLog(QWidget * a_pParent = nullptr);\n\tvirtual ~VSEditorLog();\n\n\tvirtual QString name() const;\n\tvirtual void setName(const QString & a_name);\n\n\tvirtual void setSettingsManager(SettingsManager * a_pSettingsManager);\n\n\tvirtual bool loadSettings();\n\n\tvirtual bool saveSettings();\n\nprotected slots:\n\n\tvirtual void slotLogSettingsChanged() override;\n\nprotected:\n\n\tvirtual void initializeStyles();\n\n\tQString m_name;\n\n\tSettingsManager * m_pSettingsManager;\n};\n\n#endif // VS_EDITOR_LOG_H_INCLUDED\n"
  },
  {
    "path": "common-src/log/vs_editor_log_definitions.cpp",
    "content": "#include \"vs_editor_log_definitions.h\"\n\n#include \"styled_log_view_core.h\"\n\n#include <VapourSynth4.h>\n#include <map>\n#include <algorithm>\n\n//==============================================================================\n\nconst char LOG_STYLE_ERROR[] = \"error\";\nconst char LOG_STYLE_DEBUG[] = \"debug\";\nconst char LOG_STYLE_WARNING[] = \"warning\";\nconst char LOG_STYLE_POSITIVE[] = \"positive\";\n\nconst char LOG_STYLE_VS_DEBUG[] = \"vs_debug\";\nconst char LOG_STYLE_VS_INFO[] = \"vs_info\";\nconst char LOG_STYLE_VS_WARNING[] = \"vs_warning\";\nconst char LOG_STYLE_VS_CRITICAL[] = \"vs_critical\";\nconst char LOG_STYLE_VS_FATAL[] = \"vs_fatal\";\n\nconst char LOG_STYLE_QT_DEBUG[] = \"qt_debug\";\nconst char LOG_STYLE_QT_INFO[] = \"qt_info\";\nconst char LOG_STYLE_QT_WARNING[] = \"qt_warning\";\nconst char LOG_STYLE_QT_CRITICAL[] = \"qt_critical\";\nconst char LOG_STYLE_QT_FATAL[] = \"qt_fatal\";\n\n//==============================================================================\n\nQString vsMessageTypeToStyleName(int a_messageType)\n{\n\tQString style(LOG_STYLE_DEFAULT);\n\n\tstatic std::map<int, QString> vsTypeToStyleMap = {\n\t\t{mtDebug, LOG_STYLE_VS_DEBUG},\n\t\t{mtInformation, LOG_STYLE_VS_INFO},\n\t\t{mtWarning, LOG_STYLE_VS_WARNING},\n\t\t{mtCritical, LOG_STYLE_VS_CRITICAL},\n\t\t{mtFatal, LOG_STYLE_VS_FATAL},\n\t};\n\n\tstd::map<int, QString>::const_iterator it =\n\t\tvsTypeToStyleMap.find(a_messageType);\n\tif(it != vsTypeToStyleMap.end())\n\t\treturn it->second;\n\n\treturn style;\n}\n\n// END OF QString vsMessageTypeToStyleName(int a_messageType)\n//==============================================================================\n"
  },
  {
    "path": "common-src/log/vs_editor_log_definitions.h",
    "content": "#ifndef VS_EDITOR_LOG_DEFINITIONS_H_INCLUDED\n#define VS_EDITOR_LOG_DEFINITIONS_H_INCLUDED\n\n#include <QString>\n\nextern const char LOG_STYLE_ERROR[];\nextern const char LOG_STYLE_DEBUG[];\nextern const char LOG_STYLE_WARNING[];\nextern const char LOG_STYLE_POSITIVE[];\n\nextern const char LOG_STYLE_VS_DEBUG[];\nextern const char LOG_STYLE_VS_INFO[];\nextern const char LOG_STYLE_VS_WARNING[];\nextern const char LOG_STYLE_VS_CRITICAL[];\nextern const char LOG_STYLE_VS_FATAL[];\n\nextern const char LOG_STYLE_QT_DEBUG[];\nextern const char LOG_STYLE_QT_INFO[];\nextern const char LOG_STYLE_QT_WARNING[];\nextern const char LOG_STYLE_QT_CRITICAL[];\nextern const char LOG_STYLE_QT_FATAL[];\n\nQString vsMessageTypeToStyleName(int a_messageType);\n\n#endif // VS_EDITOR_LOG_DEFINITIONS_H_INCLUDED\n"
  },
  {
    "path": "common-src/settings/settings_definitions.cpp",
    "content": "#include \"settings_definitions.h\"\n\n//==============================================================================\n\nconst bool DEFAULT_MAIN_WINDOW_MAXIMIZED = false;\nconst bool DEFAULT_PREVIEW_DIALOG_MAXIMIZED = false;\nconst bool DEFAULT_JOBS_DIALOG_MAXIMIZED = false;\nconst bool DEFAULT_JOB_SERVER_WATCHER_MAXIMIZED = false;\nconst bool DEFAULT_AUTO_LOAD_LAST_SCRIPT = true;\nconst bool DEFAULT_ZOOM_PANEL_VISIBLE = true;\nconst ZoomMode DEFAULT_ZOOM_MODE = ZoomMode::NoZoom;\nconst double DEFAULT_ZOOM_RATIO = 2.0;\nconst Qt::TransformationMode DEFAULT_SCALE_MODE = Qt::FastTransformation;\nconst CropMode DEFAULT_CROP_MODE = CropMode::Relative;\nconst int DEFAULT_CROP_ZOOM_RATIO = 1;\nconst bool DEFAULT_PROMPT_TO_SAVE_CHANGES = true;\nconst unsigned int DEFAULT_MAX_RECENT_FILES_NUMBER = 10;\nconst int DEFAULT_CHARACTERS_TYPED_TO_START_COMPLETION = 2;\nconst double DEFAULT_TIME_STEP = 5.0;\nconst TimeLineSlider::DisplayMode DEFAULT_TIMELINE_MODE =\n\tTimeLineSlider::DisplayMode::Time;\nconst bool DEFAULT_COLOR_PICKER_VISIBLE = false;\nconst PlayFPSLimitMode DEFAULT_PLAY_FPS_LIMIT_MODE =\n\tPlayFPSLimitMode::FromVideo;\nconst double DEFAULT_PLAY_FPS_LIMIT = 23.976;\nconst bool DEFAULT_USE_SPACES_AS_TAB = true;\nconst int DEFAULT_SPACES_IN_TAB = 4;\nconst bool DEFAULT_REMEMBER_LAST_PREVIEW_FRAME = false;\nconst int DEFAULT_LAST_PREVIEW_FRAME = 0;\nconst qlonglong DEFAULT_LAST_PREVIEW_TIMESTAMP = 0;\nconst SyncOutputNodesMode DEFAULT_SYNC_OUTPUT_MODE =\n\tSyncOutputNodesMode::Frame;\nconst bool DEFAULT_HIGHLIGHT_SELECTION_MATCHES = true;\nconst int DEFAULT_HIGHLIGHT_SELECTION_MATCHES_MIN_LENGTH = 3;\nconst bool DEFAULT_TIMELINE_PANEL_VISIBLE = true;\nconst bool DEFAULT_ALWAYS_KEEP_CURRENT_FRAME = true;\nconst QString DEFAULT_LAST_SNAPSHOT_EXTENSION = \"png\";\nconst int DEFAULT_FPS_DISPLAY_PRECISION = 3;\nconst double DEFAULT_TIMELINE_LABELS_HEIGHT = 5.0;\nconst char DEFAULT_DROP_FILE_TEMPLATE[] = \"r\\'{f}\\'\";\nconst int DEFAULT_MAX_WATCHER_CONNECTION_ATTEMPTS = 5;\nconst int DEFAULT_PNG_COMPRESSION_LEVEL = 0;\nconst bool DEFAULT_RELOAD_FROM_DISK = false;\nconst bool DEFAULT_DEBUG_MESSAGES = false;\nconst bool DEFAULT_DARK_MODE = false;\nconst bool DEFAULT_SILENT_SNAPSHOT = false;\nconst QString DEFAULT_SNAPSHOT_TEMPLATE = \"{f}-{i}-{o}.png\";\n\n//==============================================================================\n\nconst char ACTION_ID_NEW_SCRIPT[] = \"new_script\";\nconst char ACTION_ID_OPEN_SCRIPT[] = \"open_script\";\nconst char ACTION_ID_SAVE_SCRIPT[] = \"save_script\";\nconst char ACTION_ID_SAVE_SCRIPT_AS[] = \"save_script_as\";\nconst char ACTION_ID_TEMPLATES[] = \"templates\";\nconst char ACTION_ID_SETTINGS[] = \"settings\";\nconst char ACTION_ID_PREVIEW[] = \"preview\";\nconst char ACTION_ID_CHECK_SCRIPT[] = \"check_script\";\nconst char ACTION_ID_BENCHMARK[] = \"benchmark\";\nconst char ACTION_ID_CLI_ENCODE[] = \"cli_encode\";\nconst char ACTION_ID_ENQUEUE_ENCODE_JOB[] = \"enqueue_encode_job\";\nconst char ACTION_ID_TOGGLE_CONSOLE[] = \"toggle_console\";\nconst char ACTION_ID_JOBS[] = \"jobs\";\nconst char ACTION_ID_EXIT[] = \"exit\";\nconst char ACTION_ID_ABOUT[] = \"about\";\nconst char ACTION_ID_AUTOCOMPLETE[] = \"autocomplete\";\nconst char ACTION_ID_SAVE_SNAPSHOT[] = \"save_snapshot\";\nconst char ACTION_ID_TOGGLE_ZOOM_PANEL[] = \"toggle_zoom_panel\";\nconst char ACTION_ID_SET_ZOOM_MODE_NO_ZOOM[] = \"set_zoom_mode_no_zoom\";\nconst char ACTION_ID_SET_ZOOM_MODE_FIXED_RATIO[] = \"set_zoom_mode_fixed_ratio\";\nconst char ACTION_ID_SET_ZOOM_MODE_FIT_TO_FRAME[] =\n\t\"set_zoom_mode_fit_to_frame\";\nconst char ACTION_ID_SET_ZOOM_SCALE_MODE_NEAREST[] =\n\t\"set_zoom_scale_mode_nearest\";\nconst char ACTION_ID_SET_ZOOM_SCALE_MODE_BILINEAR[] =\n\t\"set_zoom_scale_mode_bilinear\";\nconst char ACTION_ID_TOGGLE_CROP_PANEL[] = \"toggle_crop_panel\";\nconst char ACTION_ID_PASTE_CROP_SNIPPET_INTO_SCRIPT[] =\n\t\"paste_crop_snippet_into_script\";\nconst char ACTION_ID_FRAME_TO_CLIPBOARD[] = \"frame_to_clipboard\";\nconst char ACTION_ID_TOGGLE_TIMELINE_PANEL[] = \"toggle_timeline_panel\";\nconst char ACTION_ID_SET_TIMELINE_MODE_TIME[] = \"set_timeline_mode_time\";\nconst char ACTION_ID_SET_TIMELINE_MODE_FRAMES[] = \"set_timeline_mode_frames\";\nconst char ACTION_ID_TIME_STEP_FORWARD[] = \"time_step_forward\";\nconst char ACTION_ID_TIME_STEP_BACK[] = \"time_step_back\";\nconst char ACTION_ID_ADVANCED_PREVIEW_SETTINGS[] = \"advanced_preview_settings\";\nconst char ACTION_ID_TOGGLE_COLOR_PICKER[] = \"toggle_color_picker\";\nconst char ACTION_ID_PLAY[] = \"play\";\nconst char ACTION_ID_DUPLICATE_SELECTION[] = \"duplicate_selection\";\nconst char ACTION_ID_COMMENT_SELECTION[] = \"comment_selection\";\nconst char ACTION_ID_UNCOMMENT_SELECTION[] = \"uncomment_selection\";\nconst char ACTION_ID_REPLACE_TAB_WITH_SPACES[] = \"replace_tab_with_spaces\";\nconst char ACTION_ID_TIMELINE_LOAD_CHAPTERS[] = \"timeline_load_chapters\";\nconst char ACTION_ID_TIMELINE_CLEAR_BOOKMARKS[] = \"timeline_clear_bookmarks\";\nconst char ACTION_ID_TIMELINE_BOOKMARK_CURRENT_FRAME[] =\n\t\"timeline_bookmark_current_frame\";\nconst char ACTION_ID_TIMELINE_UNBOOKMARK_CURRENT_FRAME[] =\n\t\"timeline_unbookmark_current_frame\";\nconst char ACTION_ID_TIMELINE_GO_TO_PREVIOUS_BOOKMARK[] =\n\t\"timeline_go_to_previous_bookmark\";\nconst char ACTION_ID_TIMELINE_GO_TO_NEXT_BOOKMARK[] =\n\t\"timeline_go_to_next_bookmark\";\nconst char ACTION_ID_PASTE_SHOWN_FRAME_NUMBER_INTO_SCRIPT[] =\n\t\"paste_shown_frame_number_into_script\";\nconst char ACTION_ID_MOVE_TEXT_BLOCK_UP[] = \"move_text_block_up\";\nconst char ACTION_ID_MOVE_TEXT_BLOCK_DOWN[] = \"move_text_block_down\";\nconst char ACTION_ID_TOGGLE_COMMENT[] = \"toggle_comment\";\nconst char ACTION_ID_SHUTDOWN_SERVER_AND_EXIT[] = \"shutdown_server_and_exit\";\nconst char ACTION_ID_SET_TRUSTED_CLIENTS_ADDRESSES[] =\n\t\"set_trusted_clients_addresses\";\nconst char ACTION_ID_JUMP_TO_FRAME[] = \"jump_to_frame\";\nconst char ACTION_ID_TOGGLE_FRAME_PROPS[] = \"toggle_frame_props_panel\";\nconst char ACTION_ID_SET_OUTPUT_INDEX_0[] = \"switch_to_output_index_0\";\nconst char ACTION_ID_SET_OUTPUT_INDEX_1[] = \"switch_to_output_index_1\";\nconst char ACTION_ID_SET_OUTPUT_INDEX_2[] = \"switch_to_output_index_2\";\nconst char ACTION_ID_SET_OUTPUT_INDEX_3[] = \"switch_to_output_index_3\";\nconst char ACTION_ID_SET_OUTPUT_INDEX_4[] = \"switch_to_output_index_4\";\nconst char ACTION_ID_SET_OUTPUT_INDEX_5[] = \"switch_to_output_index_5\";\nconst char ACTION_ID_SET_OUTPUT_INDEX_6[] = \"switch_to_output_index_6\";\nconst char ACTION_ID_SET_OUTPUT_INDEX_7[] = \"switch_to_output_index_7\";\nconst char ACTION_ID_SET_OUTPUT_INDEX_8[] = \"switch_to_output_index_8\";\nconst char ACTION_ID_SET_OUTPUT_INDEX_9[] = \"switch_to_output_index_9\";\nconst char ACTION_ID_SET_OUTPUT_INDEX_10[] = \"switch_to_output_index_10\";\nconst char ACTION_ID_SET_OUTPUT_INDEX_11[] = \"switch_to_output_index_11\";\nconst char ACTION_ID_SET_OUTPUT_INDEX_12[] = \"switch_to_output_index_12\";\nconst char ACTION_ID_SET_OUTPUT_INDEX_13[] = \"switch_to_output_index_13\";\nconst char ACTION_ID_SET_OUTPUT_INDEX_14[] = \"switch_to_output_index_14\";\nconst char ACTION_ID_SET_OUTPUT_INDEX_15[] = \"switch_to_output_index_15\";\nconst char ACTION_ID_SET_OUTPUT_INDEX_16[] = \"switch_to_output_index_16\";\nconst char ACTION_ID_SET_OUTPUT_INDEX_17[] = \"switch_to_output_index_17\";\nconst char ACTION_ID_SET_OUTPUT_INDEX_18[] = \"switch_to_output_index_18\";\nconst char ACTION_ID_SET_OUTPUT_INDEX_19[] = \"switch_to_output_index_19\";\nconst char ACTION_ID_PREVIOUS_OUTPUT_INDEX[] = \"switch_to_previous_output_index\";\nconst char ACTION_ID_NEXT_OUTPUT_INDEX[] = \"switch_to_next_output_index\";\n\n//==============================================================================\n\nconst char TEXT_FORMAT_ID_COMMON_SCRIPT_TEXT[] = \"common_script_text\";\nconst char TEXT_FORMAT_ID_KEYWORD[] = \"keyword\";\nconst char TEXT_FORMAT_ID_OPERATOR[] = \"operator\";\nconst char TEXT_FORMAT_ID_STRING[] = \"string\";\nconst char TEXT_FORMAT_ID_NUMBER[] = \"number\";\nconst char TEXT_FORMAT_ID_COMMENT[] = \"comment\";\nconst char TEXT_FORMAT_ID_VS_CORE[] = \"vs_core\";\nconst char TEXT_FORMAT_ID_VS_NAMESPACE[] = \"vs_namespace\";\nconst char TEXT_FORMAT_ID_VS_FUNCTION[] = \"vs_function\";\nconst char TEXT_FORMAT_ID_VS_ARGUMENT[] = \"vs_argument\";\nconst char TEXT_FORMAT_ID_TIMELINE[] = \"timeline_text\";\n\nconst char COLOR_ID_TEXT_BACKGROUND[] = \"text_background_color\";\nconst char COLOR_ID_ACTIVE_LINE[] = \"active_line_color\";\nconst char COLOR_ID_SELECTION_MATCHES[] = \"selection_matches\";\nconst char COLOR_ID_TIMELINE_BOOKMARKS[] = \"timeline_bookmarks\";\n\n//==============================================================================\n\nbool StandardAction::operator==(const StandardAction & a_other) const\n{\n\treturn id == a_other.id;\n}\n\nbool StandardAction::operator<(const StandardAction & a_other) const\n{\n\treturn id < a_other.id;\n}\n\n//==============================================================================\n\nCodeSnippet::CodeSnippet(const QString & a_name, const QString & a_text) :\n\t  name(a_name)\n\t, text(a_text)\n{\n}\n\nbool CodeSnippet::operator==(const CodeSnippet & a_other) const\n{\n\treturn (name == a_other.name);\n}\n\nbool CodeSnippet::operator<(const CodeSnippet & a_other) const\n{\n\treturn (name < a_other.name);\n}\n\nbool CodeSnippet::isEmpty() const\n{\n\treturn (name.isEmpty() && text.isEmpty());\n}\n\n//==============================================================================\n"
  },
  {
    "path": "common-src/settings/settings_definitions.h",
    "content": "#ifndef SETTINGS_DEFINITIONS_H_INCLUDED\n#define SETTINGS_DEFINITIONS_H_INCLUDED\n\n#include \"../timeline_slider/timeline_slider.h\"\n#include \"../log/styled_log_view_structures.h\"\n\n#include <QString>\n#include <QIcon>\n#include <QKeySequence>\n#include <QStringList>\n#include <QDateTime>\n#include <vector>\n\n//==============================================================================\n\nenum class ZoomMode\n{\n\tNoZoom,\n\tFixedRatio,\n\tFitToFrame,\n};\n\nenum class CropMode\n{\n\tAbsolute,\n\tRelative,\n};\n\nenum class PlayFPSLimitMode\n{\n\tFromVideo,\n\tNoLimit,\n\tCustom,\n};\n\nenum class SyncOutputNodesMode\n{\n\tFrame,\n\tTime,\n\tFromTimeLine,\n};\n\nstruct StandardAction\n{\n\tQString id;\n\tQString title;\n\tQIcon icon;\n\tQKeySequence hotkey;\n\n\tbool operator==(const StandardAction & a_other) const;\n\tbool operator<(const StandardAction & a_other) const;\n};\n\nstruct CodeSnippet\n{\n\tQString name;\n\tQString text;\n\n\tCodeSnippet(const QString & a_name = QString(),\n\t\tconst QString & a_text = QString());\n\tbool operator==(const CodeSnippet & a_other) const;\n\tbool operator<(const CodeSnippet & a_other) const;\n\tbool isEmpty() const;\n};\n\nstruct DropFileCategory\n{\n\tQString name;\n\tQStringList maskList;\n\tQString sourceTemplate;\n};\n\n//==============================================================================\n\nextern const bool DEFAULT_MAIN_WINDOW_MAXIMIZED;\nextern const bool DEFAULT_PREVIEW_DIALOG_MAXIMIZED;\nextern const bool DEFAULT_JOBS_DIALOG_MAXIMIZED;\nextern const bool DEFAULT_JOB_SERVER_WATCHER_MAXIMIZED;\nextern const bool DEFAULT_AUTO_LOAD_LAST_SCRIPT;\nextern const bool DEFAULT_ZOOM_PANEL_VISIBLE;\nextern const ZoomMode DEFAULT_ZOOM_MODE;\nextern const double DEFAULT_ZOOM_RATIO;\nextern const Qt::TransformationMode DEFAULT_SCALE_MODE;\nextern const CropMode DEFAULT_CROP_MODE;\nextern const int DEFAULT_CROP_ZOOM_RATIO;\nextern const bool DEFAULT_PROMPT_TO_SAVE_CHANGES;\nextern const unsigned int DEFAULT_MAX_RECENT_FILES_NUMBER;\nextern const QStringList DEFAULT_DOCUMENTATION_PATHS;\nextern const int DEFAULT_CHARACTERS_TYPED_TO_START_COMPLETION;\nextern const double DEFAULT_TIME_STEP;\nextern const TimeLineSlider::DisplayMode DEFAULT_TIMELINE_MODE;\nextern const bool DEFAULT_COLOR_PICKER_VISIBLE;\nextern const PlayFPSLimitMode DEFAULT_PLAY_FPS_LIMIT_MODE;\nextern const double DEFAULT_PLAY_FPS_LIMIT;\nextern const bool DEFAULT_USE_SPACES_AS_TAB;\nextern const int DEFAULT_SPACES_IN_TAB;\nextern const bool DEFAULT_REMEMBER_LAST_PREVIEW_FRAME;\nextern const int DEFAULT_LAST_PREVIEW_FRAME;\nextern const qlonglong DEFAULT_LAST_PREVIEW_TIMESTAMP;\nextern const SyncOutputNodesMode DEFAULT_SYNC_OUTPUT_MODE;\nextern const bool DEFAULT_HIGHLIGHT_SELECTION_MATCHES;\nextern const int DEFAULT_HIGHLIGHT_SELECTION_MATCHES_MIN_LENGTH;\nextern const bool DEFAULT_TIMELINE_PANEL_VISIBLE;\nextern const bool DEFAULT_ALWAYS_KEEP_CURRENT_FRAME;\nextern const QString DEFAULT_LAST_SNAPSHOT_EXTENSION;\nextern const int DEFAULT_FPS_DISPLAY_PRECISION;\nextern const double DEFAULT_TIMELINE_LABELS_HEIGHT;\nextern const char DEFAULT_DROP_FILE_TEMPLATE[];\nextern const int DEFAULT_MAX_WATCHER_CONNECTION_ATTEMPTS;\nextern const int DEFAULT_PNG_COMPRESSION_LEVEL;\nextern const bool DEFAULT_RELOAD_FROM_DISK;\nextern const bool DEFAULT_DEBUG_MESSAGES;\nextern const bool DEFAULT_DARK_MODE;\nextern const bool DEFAULT_SILENT_SNAPSHOT;\nextern const QString DEFAULT_SNAPSHOT_TEMPLATE;\n\n//==============================================================================\n\nextern const char ACTION_ID_NEW_SCRIPT[];\nextern const char ACTION_ID_OPEN_SCRIPT[];\nextern const char ACTION_ID_SAVE_SCRIPT[];\nextern const char ACTION_ID_SAVE_SCRIPT_AS[];\nextern const char ACTION_ID_TEMPLATES[];\nextern const char ACTION_ID_SETTINGS[];\nextern const char ACTION_ID_PREVIEW[];\nextern const char ACTION_ID_CHECK_SCRIPT[];\nextern const char ACTION_ID_BENCHMARK[];\nextern const char ACTION_ID_CLI_ENCODE[];\nextern const char ACTION_ID_ENQUEUE_ENCODE_JOB[];\nextern const char ACTION_ID_TOGGLE_CONSOLE[];\nextern const char ACTION_ID_JOBS[];\nextern const char ACTION_ID_EXIT[];\nextern const char ACTION_ID_ABOUT[];\nextern const char ACTION_ID_AUTOCOMPLETE[];\nextern const char ACTION_ID_SAVE_SNAPSHOT[];\nextern const char ACTION_ID_TOGGLE_ZOOM_PANEL[];\nextern const char ACTION_ID_SET_ZOOM_MODE_NO_ZOOM[];\nextern const char ACTION_ID_SET_ZOOM_MODE_FIXED_RATIO[];\nextern const char ACTION_ID_SET_ZOOM_MODE_FIT_TO_FRAME[];\nextern const char ACTION_ID_SET_ZOOM_SCALE_MODE_NEAREST[];\nextern const char ACTION_ID_SET_ZOOM_SCALE_MODE_BILINEAR[];\nextern const char ACTION_ID_TOGGLE_CROP_PANEL[];\nextern const char ACTION_ID_PASTE_CROP_SNIPPET_INTO_SCRIPT[];\nextern const char ACTION_ID_FRAME_TO_CLIPBOARD[];\nextern const char ACTION_ID_TOGGLE_TIMELINE_PANEL[];\nextern const char ACTION_ID_SET_TIMELINE_MODE_TIME[];\nextern const char ACTION_ID_SET_TIMELINE_MODE_FRAMES[];\nextern const char ACTION_ID_TIME_STEP_FORWARD[];\nextern const char ACTION_ID_TIME_STEP_BACK[];\nextern const char ACTION_ID_ADVANCED_PREVIEW_SETTINGS[];\nextern const char ACTION_ID_TOGGLE_COLOR_PICKER[];\nextern const char ACTION_ID_PLAY[];\nextern const char ACTION_ID_DUPLICATE_SELECTION[];\nextern const char ACTION_ID_COMMENT_SELECTION[];\nextern const char ACTION_ID_UNCOMMENT_SELECTION[];\nextern const char ACTION_ID_REPLACE_TAB_WITH_SPACES[];\nextern const char ACTION_ID_TIMELINE_LOAD_CHAPTERS[];\nextern const char ACTION_ID_TIMELINE_CLEAR_BOOKMARKS[];\nextern const char ACTION_ID_TIMELINE_BOOKMARK_CURRENT_FRAME[];\nextern const char ACTION_ID_TIMELINE_UNBOOKMARK_CURRENT_FRAME[];\nextern const char ACTION_ID_TIMELINE_GO_TO_PREVIOUS_BOOKMARK[];\nextern const char ACTION_ID_TIMELINE_GO_TO_NEXT_BOOKMARK[];\nextern const char ACTION_ID_PASTE_SHOWN_FRAME_NUMBER_INTO_SCRIPT[];\nextern const char ACTION_ID_MOVE_TEXT_BLOCK_UP[];\nextern const char ACTION_ID_MOVE_TEXT_BLOCK_DOWN[];\nextern const char ACTION_ID_TOGGLE_COMMENT[];\nextern const char ACTION_ID_SHUTDOWN_SERVER_AND_EXIT[];\nextern const char ACTION_ID_SET_TRUSTED_CLIENTS_ADDRESSES[];\nextern const char ACTION_ID_JUMP_TO_FRAME[];\nextern const char ACTION_ID_TOGGLE_FRAME_PROPS[];\nextern const char ACTION_ID_SET_OUTPUT_INDEX_0[];\nextern const char ACTION_ID_SET_OUTPUT_INDEX_1[];\nextern const char ACTION_ID_SET_OUTPUT_INDEX_2[];\nextern const char ACTION_ID_SET_OUTPUT_INDEX_3[];\nextern const char ACTION_ID_SET_OUTPUT_INDEX_4[];\nextern const char ACTION_ID_SET_OUTPUT_INDEX_5[];\nextern const char ACTION_ID_SET_OUTPUT_INDEX_6[];\nextern const char ACTION_ID_SET_OUTPUT_INDEX_7[];\nextern const char ACTION_ID_SET_OUTPUT_INDEX_8[];\nextern const char ACTION_ID_SET_OUTPUT_INDEX_9[];\nextern const char ACTION_ID_SET_OUTPUT_INDEX_10[];\nextern const char ACTION_ID_SET_OUTPUT_INDEX_11[];\nextern const char ACTION_ID_SET_OUTPUT_INDEX_12[];\nextern const char ACTION_ID_SET_OUTPUT_INDEX_13[];\nextern const char ACTION_ID_SET_OUTPUT_INDEX_14[];\nextern const char ACTION_ID_SET_OUTPUT_INDEX_15[];\nextern const char ACTION_ID_SET_OUTPUT_INDEX_16[];\nextern const char ACTION_ID_SET_OUTPUT_INDEX_17[];\nextern const char ACTION_ID_SET_OUTPUT_INDEX_18[];\nextern const char ACTION_ID_SET_OUTPUT_INDEX_19[];\nextern const char ACTION_ID_PREVIOUS_OUTPUT_INDEX[];\nextern const char ACTION_ID_NEXT_OUTPUT_INDEX[];\n\n//==============================================================================\n\nextern const char TEXT_FORMAT_ID_COMMON_SCRIPT_TEXT[];\nextern const char TEXT_FORMAT_ID_KEYWORD[];\nextern const char TEXT_FORMAT_ID_OPERATOR[];\nextern const char TEXT_FORMAT_ID_STRING[];\nextern const char TEXT_FORMAT_ID_NUMBER[];\nextern const char TEXT_FORMAT_ID_COMMENT[];\nextern const char TEXT_FORMAT_ID_VS_CORE[];\nextern const char TEXT_FORMAT_ID_VS_NAMESPACE[];\nextern const char TEXT_FORMAT_ID_VS_FUNCTION[];\nextern const char TEXT_FORMAT_ID_VS_ARGUMENT[];\nextern const char TEXT_FORMAT_ID_TIMELINE[];\n\nextern const char COLOR_ID_TEXT_BACKGROUND[];\nextern const char COLOR_ID_ACTIVE_LINE[];\nextern const char COLOR_ID_SELECTION_MATCHES[];\nextern const char COLOR_ID_TIMELINE_BOOKMARKS[];\n\n//==============================================================================\n\n#endif // SETTINGS_DEFINITIONS_H_INCLUDED\n"
  },
  {
    "path": "common-src/settings/settings_definitions_core.cpp",
    "content": "#include \"settings_definitions_core.h\"\n\n#include <QObject>\n#include <QJsonArray>\n#include <QVariant>\n#include <map>\n\n//==============================================================================\n\nconst bool DEFAULT_PREFER_VS_LIBRARIES_FROM_LIST = false;\nconst ResamplingFilter DEFAULT_CHROMA_RESAMPLING_FILTER =\n\tResamplingFilter::Bicubic;\nconst YuvMatrixCoefficients DEFAULT_YUV_MATRIX_COEFFICIENTS =\n\tYuvMatrixCoefficients::m709;\nconst ChromaPlacement DEFAULT_CHROMA_PLACEMENT = ChromaPlacement::LEFT;\nconst double DEFAULT_BICUBIC_FILTER_PARAMETER_B = 0.0;\nconst double DEFAULT_BICUBIC_FILTER_PARAMETER_C = 0.5;\nconst int DEFAULT_LANCZOS_FILTER_TAPS = 3;\nconst DitherType DEFAULT_DITHER_TYPE = DitherType::ERROR_DIFFUSION;\nconst EncodingType DEFAULT_ENCODING_TYPE = EncodingType::CLI;\nconst EncodingHeaderType DEFAULT_ENCODING_HEADER_TYPE =\n\tEncodingHeaderType::NoHeader;\nconst JobType DEFAULT_JOB_TYPE = JobType::EncodeScriptCLI;\nconst JobState DEFAULT_JOB_STATE = JobState::Waiting;\nconst int DEFAULT_JOB_FIRST_FRAME = -1;\nconst int DEFAULT_JOB_LAST_FRAME = -1;\nconst int DEFAULT_JOB_FRAMES_PROCESSED = 0;\nconst double DEFAULT_JOB_FPS = 0.0;\nconst int DEFAULT_RECENT_JOB_SERVERS_NUMBER = 10;\nconst int DEFAULT_WINDOW_GEOMETRY_SAVE_DELAY = 2000;\n\n//==============================================================================\n\nconst std::vector<JobState> ACTIVE_JOB_STATES = {JobState::Running,\n\tJobState::Pausing, JobState::Paused, JobState::Aborting,\n\tJobState::FailedCleanUp, JobState::CompletedCleanUp};\n\nJobProperties::JobProperties():\n\t  id(QUuid::createUuid())\n\t, type(JobType::EncodeScriptCLI)\n\t, jobState(JobState::Waiting)\n\t, encodingType(EncodingType::CLI)\n\t, encodingHeaderType(EncodingHeaderType::NoHeader)\n\t, firstFrame(-1)\n\t, firstFrameReal(-1)\n\t, lastFrame(-1)\n\t, lastFrameReal(-1)\n\t, framesProcessed(0)\n\t, fps(0.0)\n{\n}\n\nQString JobProperties::typeName(JobType a_type)\n{\n\tstatic std::map<JobType, QString> typeNameMap =\n\t{\n\t\t{JobType::EncodeScriptCLI, QObject::tr(\"CLI encoding\")},\n\t\t{JobType::RunProcess, QObject::tr(\"Process run\")},\n\t\t{JobType::RunShellCommand, QObject::tr(\"Shell command\")},\n\t};\n\n\treturn typeNameMap[a_type];\n}\n\nQString JobProperties::stateName(JobState a_state)\n{\n\tstatic std::map<JobState, QString> stateNameMap =\n\t{\n\t\t{JobState::Waiting, QObject::tr(\"Waiting\")},\n\t\t{JobState::Running, QObject::tr(\"Running\")},\n\t\t{JobState::Paused, QObject::tr(\"Paused\")},\n\t\t{JobState::Pausing, QObject::tr(\"Pausing\")},\n\t\t{JobState::Aborted, QObject::tr(\"Aborted\")},\n\t\t{JobState::Aborting, QObject::tr(\"Aborting\")},\n\t\t{JobState::FailedCleanUp, QObject::tr(\"Failed. Cleaning up.\")},\n\t\t{JobState::Failed, QObject::tr(\"Failed\")},\n\t\t{JobState::DependencyNotMet, QObject::tr(\"Dependency not met\")},\n\t\t{JobState::CompletedCleanUp, QObject::tr(\"Completing\")},\n\t\t{JobState::Completed, QObject::tr(\"Completed\")},\n\t};\n\n\treturn stateNameMap[a_state];\n}\n\nQString JobProperties::subject() const\n{\n\tQString subjectString;\n\n\tif(type == JobType::EncodeScriptCLI)\n\t{\n\t\tsubjectString = QString(\"%sn%:\\n\\\"%ep%\\\" %arg%\");\n\t\tsubjectString = subjectString.replace(\"%sn%\", scriptName);\n\t\tsubjectString = subjectString.replace(\"%ep%\", executablePath);\n\t\tsubjectString = subjectString.replace(\"%arg%\", arguments);\n\t}\n\telse if(type == JobType::RunProcess)\n\t{\n\t\tsubjectString = QString(\"\\\"%ep%\\\" %arg%\");\n\t\tsubjectString = subjectString.replace(\"%ep%\", executablePath);\n\t\tsubjectString = subjectString.replace(\"%arg%\", arguments);\n\t}\n\telse if(type == JobType::RunShellCommand)\n\t\tsubjectString = shellCommand;\n\n\tsubjectString = subjectString.simplified();\n\n\treturn subjectString;\n}\n\nint JobProperties::framesTotal() const\n{\n\treturn lastFrameReal - firstFrameReal + 1;\n}\n\nconst char JP_ID[] = \"id\";\nconst char JP_TYPE[] = \"type\";\nconst char JP_JOB_STATE[] = \"jobState\";\nconst char JP_DEPENDS_ON_JOB_IDS[] = \"dependsOnJobIds\";\nconst char JP_TIME_STARTED[] = \"timeStarted\";\nconst char JP_TIME_ENDED[] = \"timeEnded\";\nconst char JP_SCRIPT_NAME[] = \"scriptName\";\nconst char JP_SCRIPT_TEXT[] = \"scriptText\";\nconst char JP_ENCODING_TYPE[] = \"encodingType\";\nconst char JP_ENCODING_HEADER_TYPE[] = \"encodingHeaderType\";\nconst char JP_EXECUTABLE_PATH[] = \"executablePath\";\nconst char JP_ARGUMENTS[] = \"arguments\";\nconst char JP_SHELL_COMMAND[] = \"shellCommand\";\nconst char JP_FIRST_FRAME[] = \"firstFrame\";\nconst char JP_FIRST_FRAME_REAL[] = \"firstFrameReal\";\nconst char JP_LAST_FRAME[] = \"lastFrame\";\nconst char JP_LAST_FRAME_REAL[] = \"lastFrameReal\";\nconst char JP_FRAMES_PROCESSED[] = \"framesProcessed\";\nconst char JP_FPS[] = \"fps\";\n\nQJsonObject JobProperties::toJson() const\n{\n\tQJsonObject jsJob;\n\tjsJob[JP_ID] = id.toString();\n\tjsJob[JP_TYPE] = (int)type;\n\tjsJob[JP_JOB_STATE] = (int)jobState;\n\n\tQJsonArray jsDependencies;\n\tfor(const QUuid & dependencyId : dependsOnJobIds)\n\t\tjsDependencies.push_back(QJsonValue(dependencyId.toString()));\n\tjsJob[JP_DEPENDS_ON_JOB_IDS] = jsDependencies;\n\n\tjsJob[JP_TIME_STARTED] = timeStarted.toMSecsSinceEpoch();\n\tjsJob[JP_TIME_ENDED] = timeEnded.toMSecsSinceEpoch();\n\tjsJob[JP_SCRIPT_NAME] = scriptName;\n\tjsJob[JP_SCRIPT_TEXT] = scriptText;\n\tjsJob[JP_ENCODING_TYPE] = (int)encodingType;\n\tjsJob[JP_ENCODING_HEADER_TYPE] = (int)encodingHeaderType;\n\tjsJob[JP_EXECUTABLE_PATH] = executablePath;\n\tjsJob[JP_ARGUMENTS] = arguments;\n\tjsJob[JP_SHELL_COMMAND] = shellCommand;\n\tjsJob[JP_FIRST_FRAME] = firstFrame;\n\tjsJob[JP_FIRST_FRAME_REAL] = firstFrameReal;\n\tjsJob[JP_LAST_FRAME] = lastFrame;\n\tjsJob[JP_LAST_FRAME_REAL] = lastFrameReal;\n\tjsJob[JP_FRAMES_PROCESSED] = framesProcessed;\n\tjsJob[JP_FPS] = fps;\n\treturn jsJob;\n}\n\nJobProperties JobProperties::fromJson(const QJsonObject & a_object)\n{\n\tJobProperties properties;\n\tif(a_object.contains(JP_ID))\n\t\tproperties.id = QUuid(a_object[JP_ID].toString());\n\tif(a_object.contains(JP_TYPE))\n\t\tproperties.type = (JobType)a_object[JP_TYPE].toInt();\n\tif(a_object.contains(JP_JOB_STATE))\n\t\tproperties.jobState = (JobState)a_object[JP_JOB_STATE].toInt();\n\tif(a_object.contains(JP_DEPENDS_ON_JOB_IDS))\n\t{\n\t\tif(a_object[JP_DEPENDS_ON_JOB_IDS].isArray())\n\t\t{\n\t\t\tfor(const QJsonValue & value :\n\t\t\t\ta_object[JP_DEPENDS_ON_JOB_IDS].toArray())\n\t\t\t\tproperties.dependsOnJobIds.push_back(QUuid(value.toString()));\n\t\t}\n\t}\n\tif(a_object.contains(JP_TIME_STARTED))\n\t\tproperties.timeStarted = QDateTime::fromMSecsSinceEpoch(\n\t\t\ta_object[JP_TIME_STARTED].toVariant().toLongLong());\n\tif(a_object.contains(JP_TIME_ENDED))\n\t\tproperties.timeEnded = QDateTime::fromMSecsSinceEpoch(\n\t\t\ta_object[JP_TIME_ENDED].toVariant().toLongLong());\n\tif(a_object.contains(JP_SCRIPT_NAME))\n\t\tproperties.scriptName = a_object[JP_SCRIPT_NAME].toString();\n\tif(a_object.contains(JP_SCRIPT_TEXT))\n\t\tproperties.scriptText = a_object[JP_SCRIPT_TEXT].toString();\n\tif(a_object.contains(JP_ENCODING_TYPE))\n\t\tproperties.encodingType =\n\t\t\t(EncodingType)a_object[JP_ENCODING_TYPE].toInt();\n\tif(a_object.contains(JP_ENCODING_HEADER_TYPE))\n\t\tproperties.encodingHeaderType =\n\t\t\t(EncodingHeaderType)a_object[JP_ENCODING_HEADER_TYPE].toInt();\n\tif(a_object.contains(JP_EXECUTABLE_PATH))\n\t\tproperties.executablePath = a_object[JP_EXECUTABLE_PATH].toString();\n\tif(a_object.contains(JP_ARGUMENTS))\n\t\tproperties.arguments = a_object[JP_ARGUMENTS].toString();\n\tif(a_object.contains(JP_SHELL_COMMAND))\n\t\tproperties.shellCommand = a_object[JP_SHELL_COMMAND].toString();\n\tif(a_object.contains(JP_FIRST_FRAME))\n\t\tproperties.firstFrame = a_object[JP_FIRST_FRAME].toInt();\n\tif(a_object.contains(JP_FIRST_FRAME_REAL))\n\t\tproperties.firstFrameReal = a_object[JP_FIRST_FRAME_REAL].toInt();\n\tif(a_object.contains(JP_LAST_FRAME))\n\t\tproperties.lastFrame = a_object[JP_LAST_FRAME].toInt();\n\tif(a_object.contains(JP_LAST_FRAME_REAL))\n\t\tproperties.lastFrameReal= a_object[JP_LAST_FRAME_REAL].toInt();\n\tif(a_object.contains(JP_FRAMES_PROCESSED))\n\t\tproperties.framesProcessed = a_object[JP_FRAMES_PROCESSED].toInt();\n\tif(a_object.contains(JP_FPS))\n\t\tproperties.fps = a_object[JP_FPS].toDouble();\n\treturn properties;\n}\n\n//==============================================================================\n\nEncodingPreset::EncodingPreset(const QString & a_name):\n\t  name(a_name)\n\t, type(DEFAULT_ENCODING_TYPE)\n\t, headerType(DEFAULT_ENCODING_HEADER_TYPE)\n{\n}\n\nbool EncodingPreset::operator==(const EncodingPreset & a_other) const\n{\n\treturn (name == a_other.name);\n}\n\nbool EncodingPreset::operator<(const EncodingPreset & a_other) const\n{\n\treturn (name < a_other.name);\n}\n\nbool EncodingPreset::isEmpty() const\n{\n\treturn name.isEmpty();\n}\n\n//==============================================================================\n"
  },
  {
    "path": "common-src/settings/settings_definitions_core.h",
    "content": "#ifndef SETTINGS_DEFINITIONS_CORE_H_INCLUDED\n#define SETTINGS_DEFINITIONS_CORE_H_INCLUDED\n\n#include <QString>\n#include <QDateTime>\n#include <QUuid>\n#include <QJsonObject>\n#include <vector>\n\n//==============================================================================\n\nenum class ResamplingFilter : int\n{\n\tPoint,\n\tBilinear,\n\tBicubic,\n\tSpline16,\n\tSpline36,\n\tSpline64,\n\tLanczos,\n};\n\nenum class YuvMatrixCoefficients : int\n{\n\tm709,\n\tm470BG,\n\tm170M,\n\tm2020_NCL,\n};\n\nenum class ChromaPlacement : int\n{\n\tLEFT,\n\tCENTER,\n\tTOP_LEFT,\n};\n\nenum class DitherType: int\n{\n\tNONE,\n\tORDERED,\n\tRANDOM,\n\tERROR_DIFFUSION,\n};\n\nenum class EncodingType\n{\n\tCLI,\n\tRaw,\n\tVfW,\n};\n\nenum class EncodingHeaderType\n{\n\tNoHeader,\n\tY4M,\n};\n\nenum class JobType\n{\n\tEncodeScriptCLI,\n\tRunProcess,\n\tRunShellCommand,\n};\n\nenum class JobState\n{\n\tWaiting,\n\tRunning,\n\tPausing,\n\tPaused,\n\tAborting,\n\tAborted,\n\tFailedCleanUp,\n\tFailed,\n\tDependencyNotMet,\n\tCompletedCleanUp,\n\tCompleted,\n};\n\nextern const std::vector<JobState> ACTIVE_JOB_STATES;\n\nextern const char JP_ID[];\nextern const char JP_TYPE[];\nextern const char JP_JOB_STATE[];\nextern const char JP_DEPENDS_ON_JOB_IDS[];\nextern const char JP_TIME_STARTED[];\nextern const char JP_TIME_ENDED[];\nextern const char JP_SCRIPT_NAME[];\nextern const char JP_ENCODING_TYPE[];\nextern const char JP_ENCODING_HEADER_TYPE[];\nextern const char JP_EXECUTABLE_PATH[];\nextern const char JP_ARGUMENTS[];\nextern const char JP_SHELL_COMMAND[];\nextern const char JP_FIRST_FRAME[];\nextern const char JP_FIRST_FRAME_REAL[];\nextern const char JP_LAST_FRAME[];\nextern const char JP_LAST_FRAME_REAL[];\nextern const char JP_FRAMES_PROCESSED[];\nextern const char JP_FPS[];\n\nstruct JobProperties\n{\n\tQUuid id;\n\tJobType type;\n\tJobState jobState;\n\tstd::vector<QUuid> dependsOnJobIds;\n\tQDateTime timeStarted;\n\tQDateTime timeEnded;\n\tQString scriptName;\n\tQString scriptText;\n\tEncodingType encodingType;\n\tEncodingHeaderType encodingHeaderType;\n\tQString executablePath;\n\tQString arguments;\n\tQString shellCommand;\n\tint firstFrame;\n\tint firstFrameReal;\n\tint lastFrame;\n\tint lastFrameReal;\n\tint framesProcessed;\n\tdouble fps;\n\n\tJobProperties();\n\tJobProperties(const JobProperties &) = default;\n\tJobProperties(JobProperties &&) = default;\n\tJobProperties & operator=(const JobProperties &) = default;\n\tJobProperties & operator=(JobProperties &&) = default;\n\n\tstatic QString typeName(JobType a_type);\n\tstatic QString stateName(JobState a_state);\n\n\tQString subject() const;\n\tint framesTotal() const;\n\n\tQJsonObject toJson() const;\n\tstatic JobProperties fromJson(const QJsonObject & a_object);\n};\n\nstruct EncodingPreset\n{\n\tQString name;\n\tEncodingType type;\n\tEncodingHeaderType headerType;\n\tQString executablePath;\n\tQString arguments;\n\n\tEncodingPreset(const QString & a_name = QString());\n\tbool operator==(const EncodingPreset & a_other) const;\n\tbool operator<(const EncodingPreset & a_other) const;\n\tbool isEmpty() const;\n};\n\n//==============================================================================\n\nextern const bool DEFAULT_PREFER_VS_LIBRARIES_FROM_LIST;\nextern const ResamplingFilter DEFAULT_CHROMA_RESAMPLING_FILTER;\nextern const YuvMatrixCoefficients DEFAULT_YUV_MATRIX_COEFFICIENTS;\nextern const ChromaPlacement DEFAULT_CHROMA_PLACEMENT;\nextern const double DEFAULT_BICUBIC_FILTER_PARAMETER_B;\nextern const double DEFAULT_BICUBIC_FILTER_PARAMETER_C;\nextern const int DEFAULT_LANCZOS_FILTER_TAPS;\nextern const DitherType DEFAULT_DITHER_TYPE;\nextern const EncodingType DEFAULT_ENCODING_TYPE;\nextern const EncodingHeaderType DEFAULT_ENCODING_HEADER_TYPE;\nextern const JobType DEFAULT_JOB_TYPE;\nextern const JobState DEFAULT_JOB_STATE;\nextern const int DEFAULT_JOB_FIRST_FRAME;\nextern const int DEFAULT_JOB_LAST_FRAME;\nextern const int DEFAULT_JOB_FRAMES_PROCESSED;\nextern const double DEFAULT_JOB_FPS;\nextern const int DEFAULT_RECENT_JOB_SERVERS_NUMBER;\nextern const int DEFAULT_WINDOW_GEOMETRY_SAVE_DELAY;\n\n//==============================================================================\n\n#endif // SETTINGS_DEFINITIONS_CORE_H_INCLUDED\n"
  },
  {
    "path": "common-src/settings/settings_manager.cpp",
    "content": "#include \"settings_manager.h\"\n\n#include \"../helpers.h\"\n\n#include <QSettings>\n#include <QFileInfo>\n#include <QPalette>\n#include <QFontMetricsF>\n#include <QRegularExpression>\n\n//==============================================================================\n\nconst char MAIN_WINDOW_GEOMETRY_KEY[] = \"main_window_geometry\";\nconst char PREVIEW_DIALOG_GEOMETRY_KEY[] = \"prewiew_dialog_geometry\";\nconst char LAST_PREVIEW_SCROLLBAR_POS_X[] = \"last_preview_scrollbar_position_x\";\nconst char LAST_PREVIEW_SCROLLBAR_POS_Y[] = \"last_preview_scrollbar_position_y\";\nconst char JOB_SERVER_WATCHER_GEOMETRY_KEY[] = \"job_server_watcher_geometry\";\nconst char MAIN_WINDOW_MAXIMIZED_KEY[] = \"main_window_maximized\";\nconst char PREVIEW_DIALOG_MAXIMIZED_KEY[] = \"preview_dialog_maximized\";\nconst char JOB_SERVER_WATCHER_MAXIMIZED_KEY[] = \"job_server_watcher_maximized\";\nconst char JOBS_HEADER_STATE_KEY[] = \"jobs_header_state\";\nconst char AUTO_LOAD_LAST_SCRIPT_KEY[] = \"auto_load_last_script\";\nconst char ZOOM_PANEL_VISIBLE_KEY[] = \"zoom_panel_visible\";\nconst char ZOOM_MODE_KEY[] = \"zoom_mode\";\nconst char ZOOM_RATIO_KEY[] = \"zoom_ratio\";\nconst char SCALE_MODE_KEY[] = \"scale_mode\";\nconst char CROP_MODE_KEY[] = \"crop_mode\";\nconst char CROP_ZOOM_RATIO_KEY[] = \"crop_zoom_ratio\";\nconst char RELOAD_FROM_DISK_KEY[] = \"period_reload_from_disk\";\nconst char PROMPT_TO_SAVE_CHANGES_KEY[] = \"prompt_to_save_changes\";\nconst char RECENT_FILES_LIST_KEY[] = \"recent_files_list\";\nconst char MAX_RECENT_FILES_NUMBER_KEY[] = \"max_recent_files_number\";\nconst char CHARACTERS_TYPED_TO_START_COMPLETION_KEY[] =\n\t\"characters_typed_to_start_completion\";\nconst char TIMELINE_MODE_KEY[] = \"timeline_mode\";\nconst char TIME_STEP_KEY[] = \"time_step_mode\";\nconst char COLOR_PICKER_VISIBLE_KEY[] = \"color_picker_visible\";\nconst char PLAY_FPS_LIMIT_MODE_KEY[] = \"play_fps_limit_mode\";\nconst char PLAY_FPS_LIMIT_KEY[] = \"play_fps_limit\";\nconst char USE_SPACES_AS_TAB_KEY[] = \"use_spaces_as_tab\";\nconst char SPACES_IN_TAB_KEY[] = \"spaces_in_tab\";\nconst char REMEMBER_LAST_PREVIEW_FRAME_KEY[] = \"remember_last_preview_frame\";\nconst char LAST_PREVIEW_FRAME_KEY[] = \"last_preview_frame\";\nconst char LAST_PREVIEW_TIMESTAMP_KEY[] = \"last_preview_timestamp\";\nconst char SYNC_OUTPUT_MODE_KEY[] = \"sync_output_node_mode\";\nconst char NEW_SCRIPT_TEMPLATE_KEY[] = \"new_script_template\";\nconst char HIGHLIGHT_SELECTION_MATCHES_KEY[] = \"highlight_selection_matches\";\nconst char HIGHLIGHT_SELECTION_MATCHES_MIN_LENGTH_KEY[] =\n\t\"highlight_selection_matches_min_length\";\nconst char TIMELINE_PANEL_VISIBLE_KEY[] = \"timeline_panel_visible\";\nconst char ALWAYS_KEEP_CURRENT_FRAME_KEY[] = \"always_keep_current_frame\";\nconst char LAST_SNAPSHOT_EXTENSION_KEY[] = \"last_snapshot_extension\";\nconst char PNG_COMPRESSION_LEVEL_KEY[] = \"png_compression_level\";\nconst char DEBUG_MESSAGES_KEY[] = \"show_debug_messages\";\nconst char DARK_MODE_KEY[] = \"dark_mode\";\nconst char SILENT_SNAPSHOT_KEY[] = \"silent_snapshot\";\nconst char SNAPSHOT_TEMPLATE_KEY[] = \"snapshot_template\";\n\n//==============================================================================\n\nconst char HOTKEYS_GROUP[] = \"hotkeys\";\n\n//==============================================================================\n\nconst char THEME_GROUP[] = \"theme\";\n\n//==============================================================================\n\nconst char DARK_THEME_GROUP[] = \"dark_theme\";\n\n//==============================================================================\n\nconst char PREVIEWER_GROUP[] = \"previewer\";\n\n//==============================================================================\n\nconst char CODE_SNIPPETS_GROUP[] = \"code_snippets\";\n\n//==============================================================================\n\nconst char DROP_FILE_TEMPLATES_GROUP[] = \"drop_file_templates\";\n\nconst char DROP_FILE_CATEGORY_MASK_LIST_KEY[] = \"mask_list\";\nconst char DROP_FILE_CATEGORY_SOURCE_TEMPLATE_KEY[] = \"template\";\n\n//==============================================================================\n\nconst char LOGS_GROUP[] = \"logs\";\nconst char LOG_STYLES_GROUP[] = \"styles\";\n\nconst char LOG_STYLE_TITLE_KEY[] = \"title\";\nconst char LOG_STYLE_TEXT_FORMAT_KEY[] = \"text_format\";\nconst char LOG_STYLE_IS_ALIAS_KEY[] = \"is_alias\";\nconst char LOG_STYLE_ORIGINAL_STYLE_NAME_KEY[] = \"original_style_name\";\nconst char LOG_STYLE_IS_VISIBLE_KEY[] = \"is_visible\";\n\n//==============================================================================\n\nSettingsManager::SettingsManager(QObject * a_pParent) :\n\tSettingsManagerCore(a_pParent)\n{\n\tinitializeStandardActions();\n\tm_bInDarkMode = getDarkMode();\n}\n\nSettingsManager::~SettingsManager()\n{\n\n}\n\n//==============================================================================\n\nvoid SettingsManager::initializeStandardActions()\n{\n\tm_standardActions =\n\t{\n\t\t{ACTION_ID_NEW_SCRIPT, tr(\"New script\"), QIcon(\":new.png\"),\n\t\t\tQKeySequence::New},\n\t\t{ACTION_ID_OPEN_SCRIPT, tr(\"Open script\"), QIcon(\":load.png\"),\n\t\t\tQKeySequence::Open},\n\t\t{ACTION_ID_SAVE_SCRIPT, tr(\"Save script\"), QIcon(\":save.png\"),\n\t\t\tQKeySequence::Save},\n\t\t{ACTION_ID_SAVE_SCRIPT_AS, tr(\"Save script as...\"),\n\t\t\tQIcon(\":save_as.png\"), QKeySequence::SaveAs},\n\t\t{ACTION_ID_EXIT, tr(\"Exit\"), QIcon(\":exit.png\"),\n\t\t\tQKeySequence::Quit},\n\t\t{ACTION_ID_DUPLICATE_SELECTION, tr(\"Duplicate selection or line\"),\n\t\t\tQIcon(), QKeySequence(Qt::CTRL | Qt::Key_D)},\n\t\t{ACTION_ID_COMMENT_SELECTION, tr(\"Comment lines\"), QIcon(),\n\t\t\tQKeySequence(Qt::CTRL | Qt::SHIFT | Qt::Key_C)},\n\t\t{ACTION_ID_UNCOMMENT_SELECTION, tr(\"Uncomment lines\"), QIcon(),\n\t\t\tQKeySequence(Qt::CTRL | Qt::SHIFT | Qt::Key_X)},\n\t\t{ACTION_ID_REPLACE_TAB_WITH_SPACES,\n\t\t\ttr(\"Replace Tab characters with spaces\"), QIcon(),\n\t\t\tQKeySequence()},\n\t\t{ACTION_ID_TEMPLATES, tr(\"Snippets and templates\"), QIcon(),\n\t\t\tQKeySequence()},\n\t\t{ACTION_ID_SETTINGS, tr(\"Settings\"), QIcon(\":settings.png\"),\n\t\t\tQKeySequence()},\n\t\t{ACTION_ID_PREVIEW, tr(\"Preview\"), QIcon(\":preview.png\"),\n\t\t\tQKeySequence(Qt::Key_F5)},\n\t\t{ACTION_ID_CHECK_SCRIPT, tr(\"Check script\"), QIcon(\":check.png\"),\n\t\t\tQKeySequence(Qt::Key_F6)},\n\t\t{ACTION_ID_BENCHMARK, tr(\"Benchmark\"), QIcon(\":benchmark.png\"),\n\t\t\tQKeySequence(Qt::Key_F7)},\n\t\t{ACTION_ID_CLI_ENCODE, tr(\"Encode video\"),\n\t\t\tQIcon(\":film_save.png\"), QKeySequence(Qt::Key_F8)},\n\t\t{ACTION_ID_ENQUEUE_ENCODE_JOB, tr(\"Enqueue encode job\"),\n\t\t\tQIcon(\":jobs.png\"), QKeySequence(Qt::Key_F9)},\n\t\t{ACTION_ID_JOBS, tr(\"Jobs\"),\n\t\t\tQIcon(\":jobs.png\"), QKeySequence(Qt::Key_F10)},\n#if defined(Q_OS_WIN)\n\t\t{ACTION_ID_TOGGLE_CONSOLE, tr(\"Toggle console\"),\n\t\t\tQIcon(), QKeySequence(Qt::CTRL | Qt::Key_T)},\n#endif\n\t\t{ACTION_ID_ABOUT, tr(\"About...\"), QIcon(), QKeySequence()},\n\t\t{ACTION_ID_AUTOCOMPLETE, tr(\"Autocomplete\"), QIcon(),\n\t\t\tQKeySequence(Qt::CTRL | Qt::Key_Space)},\n\t\t{ACTION_ID_FRAME_TO_CLIPBOARD, tr(\"Copy frame to clipboard\"),\n\t\t\tQIcon(\":image_to_clipboard.png\"), QKeySequence(Qt::Key_X)},\n\t\t{ACTION_ID_SAVE_SNAPSHOT, tr(\"Save snapshot\"),\n\t\t\tQIcon(\":snapshot.png\"), QKeySequence(Qt::Key_S)},\n\t\t{ACTION_ID_TOGGLE_ZOOM_PANEL, tr(\"Show zoom panel\"),\n\t\t\tQIcon(\":zoom.png\"), QKeySequence(Qt::Key_Z)},\n\t\t{ACTION_ID_SET_ZOOM_MODE_NO_ZOOM, tr(\"Zoom: No zoom\"),\n\t\t\tQIcon(\":zoom_no_zoom.png\"), QKeySequence(\n\t\t\tQt::ALT | Qt::Key_1)},\n\t\t{ACTION_ID_SET_ZOOM_MODE_FIXED_RATIO, tr(\"Zoom: Fixed ratio\"),\n\t\t\tQIcon(\":zoom_fixed_ratio.png\"), QKeySequence(\n\t\t\tQt::ALT | Qt::Key_2)},\n\t\t{ACTION_ID_SET_ZOOM_MODE_FIT_TO_FRAME, tr(\"Zoom: Fit to frame\"),\n\t\t\tQIcon(\":zoom_fit_to_frame.png\"), QKeySequence(\n\t\t\tQt::ALT | Qt::Key_3)},\n\t\t{ACTION_ID_SET_ZOOM_SCALE_MODE_NEAREST, tr(\"Scale: Nearest\"),\n\t\t\tQIcon(), QKeySequence()},\n\t\t{ACTION_ID_SET_ZOOM_SCALE_MODE_BILINEAR, tr(\"Scale: Bilinear\"),\n\t\t\tQIcon(), QKeySequence()},\n\t\t{ACTION_ID_TOGGLE_CROP_PANEL, tr(\"Crop assistant\"),\n\t\t\tQIcon(\":crop.png\"), QKeySequence(Qt::Key_C)},\n\t\t{ACTION_ID_PASTE_CROP_SNIPPET_INTO_SCRIPT,\n\t\t\ttr(\"Paste crop snippet into script\"), QIcon(\":paste.png\"),\n\t\t\tQKeySequence()},\n\t\t{ACTION_ID_TOGGLE_TIMELINE_PANEL, tr(\"Show timeline panel\"),\n\t\t\tQIcon(\":timeline.png\"), QKeySequence(Qt::Key_T)},\n\t\t{ACTION_ID_SET_TIMELINE_MODE_TIME, tr(\"Timeline mode: Time\"),\n\t\t\tQIcon(\":timeline.png\"), QKeySequence()},\n\t\t{ACTION_ID_SET_TIMELINE_MODE_FRAMES, tr(\"Timeline mode: Frames\"),\n\t\t\tQIcon(\":timeline_frames.png\"), QKeySequence()},\n\t\t{ACTION_ID_TIME_STEP_FORWARD, tr(\"Time: step forward\"),\n\t\t\tQIcon(\":time_forward.png\"),\n\t\t\tQKeySequence(Qt::CTRL | Qt::SHIFT | Qt::Key_Right)},\n\t\t{ACTION_ID_TIME_STEP_BACK, tr(\"Time: step back\"),\n\t\t\tQIcon(\":time_back.png\"),\n\t\t\tQKeySequence(Qt::CTRL | Qt::SHIFT | Qt::Key_Left)},\n\t\t{ACTION_ID_ADVANCED_PREVIEW_SETTINGS,\n\t\t\ttr(\"Preview advanced settings\"), QIcon(\":settings.png\"),\n\t\t\tQKeySequence()},\n\t\t{ACTION_ID_TOGGLE_COLOR_PICKER, tr(\"Color panel\"),\n\t\t\tQIcon(\":color_picker.png\"), QKeySequence()},\n\t\t{ACTION_ID_PLAY, tr(\"Play\"), QIcon(\":play.png\"), QKeySequence()},\n\t\t{ACTION_ID_TIMELINE_LOAD_CHAPTERS, tr(\"Load chapters\"),\n\t\t\tQIcon(\":load.png\"), QKeySequence()},\n\t\t{ACTION_ID_TIMELINE_CLEAR_BOOKMARKS, tr(\"Clear bookmarks\"),\n\t\t\tQIcon(\":timeline_bookmark.png\"), QKeySequence()},\n\t\t{ACTION_ID_TIMELINE_BOOKMARK_CURRENT_FRAME,\n\t\t\ttr(\"Bookmark current frame\"),\n\t\t\tQIcon(\":timeline_bookmark_add.png\"),\n\t\t\tQKeySequence(Qt::CTRL | Qt::Key_B)},\n\t\t{ACTION_ID_TIMELINE_UNBOOKMARK_CURRENT_FRAME,\n\t\t\ttr(\"Unbookmark current frame\"),\n\t\t\tQIcon(\":timeline_bookmark_remove.png\"),\n\t\t\tQKeySequence(Qt::CTRL | Qt::Key_U)},\n\t\t{ACTION_ID_TIMELINE_GO_TO_PREVIOUS_BOOKMARK,\n\t\t\ttr(\"Go to previous bookmark\"),\n\t\t\tQIcon(\":timeline_bookmark_previous.png\"),\n\t\t\tQKeySequence(Qt::CTRL | Qt::Key_Left)},\n\t\t{ACTION_ID_TIMELINE_GO_TO_NEXT_BOOKMARK,\n\t\t\ttr(\"Go to next bookmark\"),\n\t\t\tQIcon(\":timeline_bookmark_next.png\"),\n\t\t\tQKeySequence(Qt::CTRL | Qt::Key_Right)},\n\t\t{ACTION_ID_PASTE_SHOWN_FRAME_NUMBER_INTO_SCRIPT,\n\t\t\ttr(\"Paste shown frame number into script\"), QIcon(),\n\t\t\tQKeySequence()},\n\t\t{ACTION_ID_MOVE_TEXT_BLOCK_UP, tr(\"Move text block up\"), QIcon(),\n\t\t\tQKeySequence(Qt::CTRL | Qt::SHIFT | Qt::Key_Up)},\n\t\t{ACTION_ID_MOVE_TEXT_BLOCK_DOWN, tr(\"Move text block down\"),\n\t\t\tQIcon(), QKeySequence(Qt::CTRL | Qt::SHIFT | Qt::Key_Down)},\n\t\t{ACTION_ID_TOGGLE_COMMENT, tr(\"Toggle comment\"),\n\t\t\tQIcon(), QKeySequence(Qt::CTRL | Qt::Key_Slash)},\n\t\t{ACTION_ID_SHUTDOWN_SERVER_AND_EXIT, tr(\"Shutdown server and exit\"),\n\t\t\tQIcon(\":exit.png\"), QKeySequence()},\n\t\t{ACTION_ID_SET_TRUSTED_CLIENTS_ADDRESSES,\n\t\t\ttr(\"Set trusted clients addresses\"), QIcon(), QKeySequence()},\n\t\t{ACTION_ID_JUMP_TO_FRAME, tr(\"Jump to frame...\"),\n\t\t\tQIcon(), QKeySequence(Qt::Key_J)},\n\t\t{ACTION_ID_TOGGLE_FRAME_PROPS, tr(\"Toggle frame properties panel\"),\n\t\t\tQIcon(), QKeySequence(Qt::Key_P)},\n\t\t{ACTION_ID_SET_OUTPUT_INDEX_0, tr(\"Switch to output index 0\"),\n\t\t\tQIcon(), QKeySequence(Qt::Key_0)},\n\t\t{ACTION_ID_SET_OUTPUT_INDEX_1, tr(\"Switch to output index 1\"),\n\t\t\tQIcon(), QKeySequence(Qt::Key_1)},\n\t\t{ACTION_ID_SET_OUTPUT_INDEX_2, tr(\"Switch to output index 2\"),\n\t\t\tQIcon(), QKeySequence(Qt::Key_2)},\n\t\t{ACTION_ID_SET_OUTPUT_INDEX_3, tr(\"Switch to output index 3\"),\n\t\t\tQIcon(), QKeySequence(Qt::Key_3)},\n\t\t{ACTION_ID_SET_OUTPUT_INDEX_4, tr(\"Switch to output index 4\"),\n\t\t\tQIcon(), QKeySequence(Qt::Key_4)},\n\t\t{ACTION_ID_SET_OUTPUT_INDEX_5, tr(\"Switch to output index 5\"),\n\t\t\tQIcon(), QKeySequence(Qt::Key_5)},\n\t\t{ACTION_ID_SET_OUTPUT_INDEX_6, tr(\"Switch to output index 6\"),\n\t\t\tQIcon(), QKeySequence(Qt::Key_6)},\n\t\t{ACTION_ID_SET_OUTPUT_INDEX_7, tr(\"Switch to output index 7\"),\n\t\t\tQIcon(), QKeySequence(Qt::Key_7)},\n\t\t{ACTION_ID_SET_OUTPUT_INDEX_8, tr(\"Switch to output index 8\"),\n\t\t\tQIcon(), QKeySequence(Qt::Key_8)},\n\t\t{ACTION_ID_SET_OUTPUT_INDEX_9, tr(\"Switch to output index 9\"),\n\t\t\tQIcon(), QKeySequence(Qt::Key_9)},\n\t\t{ACTION_ID_SET_OUTPUT_INDEX_10, tr(\"Switch to output index 10\"),\n\t\t\tQIcon(), QKeySequence()},\n\t\t{ACTION_ID_SET_OUTPUT_INDEX_11, tr(\"Switch to output index 11\"),\n\t\t\tQIcon(), QKeySequence()},\n\t\t{ACTION_ID_SET_OUTPUT_INDEX_12, tr(\"Switch to output index 12\"),\n\t\t\tQIcon(), QKeySequence()},\n\t\t{ACTION_ID_SET_OUTPUT_INDEX_13, tr(\"Switch to output index 13\"),\n\t\t\tQIcon(), QKeySequence()},\n\t\t{ACTION_ID_SET_OUTPUT_INDEX_14, tr(\"Switch to output index 14\"),\n\t\t\tQIcon(), QKeySequence()},\n\t\t{ACTION_ID_SET_OUTPUT_INDEX_15, tr(\"Switch to output index 15\"),\n\t\t\tQIcon(), QKeySequence()},\n\t\t{ACTION_ID_SET_OUTPUT_INDEX_16, tr(\"Switch to output index 16\"),\n\t\t\tQIcon(), QKeySequence()},\n\t\t{ACTION_ID_SET_OUTPUT_INDEX_17, tr(\"Switch to output index 17\"),\n\t\t\tQIcon(), QKeySequence()},\n\t\t{ACTION_ID_SET_OUTPUT_INDEX_18, tr(\"Switch to output index 18\"),\n\t\t\tQIcon(), QKeySequence()},\n\t\t{ACTION_ID_SET_OUTPUT_INDEX_19, tr(\"Switch to output index 19\"),\n\t\t\tQIcon(), QKeySequence()},\n\t\t{ACTION_ID_PREVIOUS_OUTPUT_INDEX, \"Switch to previous output index\",\n\t\t\tQIcon(), QKeySequence()},\n\t\t{ACTION_ID_NEXT_OUTPUT_INDEX, \"Switch to next output index\",\n\t\t\tQIcon(), QKeySequence()},\n\t};\n}\n\nstd::vector<StandardAction> SettingsManager::getStandardActions() const\n{\n\treturn m_standardActions;\n}\n\nQAction * SettingsManager::createStandardAction(const QString & a_actionID,\n\tQObject * a_pParent)\n{\n\tStandardAction actionToFind;\n\tactionToFind.id = a_actionID;\n\n\tstd::vector<StandardAction>::const_iterator it = std::find(\n\t\tm_standardActions.begin(), m_standardActions.end(), actionToFind);\n\tif(it == m_standardActions.end())\n\t\treturn nullptr;\n\n\tQKeySequence hotkey = getHotkey(it->id);\n\n\tQAction * pAction = new QAction(it->icon, it->title, a_pParent);\n\tpAction->setData(it->id);\n\tpAction->setShortcut(hotkey);\n\n\tvsedit::disableFontKerning(pAction);\n\n\treturn pAction;\n}\n\nQKeySequence SettingsManager::getDefaultHotkey(const QString & a_actionID) const\n{\n\tStandardAction actionToFind;\n\tactionToFind.id = a_actionID;\n\n\tstd::vector<StandardAction>::const_iterator it = std::find(\n\t\tm_standardActions.begin(), m_standardActions.end(), actionToFind);\n\tif(it != m_standardActions.end())\n\t\treturn it->hotkey;\n\n\treturn QKeySequence();\n}\n\nQKeySequence SettingsManager::getHotkey(const QString & a_actionID) const\n{\n\tQSettings settings(m_settingsFilePath, QSettings::IniFormat);\n\tsettings.beginGroup(HOTKEYS_GROUP);\n\tif(!settings.contains(a_actionID))\n\t\treturn getDefaultHotkey(a_actionID);\n\n\tQKeySequence hotkey =\n\t\tsettings.value(a_actionID).value<QKeySequence>();\n\treturn hotkey;\n}\n\nbool SettingsManager::setHotkey(const QString & a_actionID,\n\tconst QKeySequence & a_hotkey)\n{\n\treturn setValueInGroup(HOTKEYS_GROUP, a_actionID, a_hotkey);\n}\n\n//==============================================================================\n\nQTextCharFormat SettingsManager::getDefaultTextFormat(\n\tconst QString & a_textFormatID) const\n{\n\t// Standard \"Icecream\" theme\n\n\tQTextCharFormat defaultFormat;\n\n\tif(a_textFormatID == TEXT_FORMAT_ID_COMMON_SCRIPT_TEXT)\n\t{\n\t\tQFont commonScriptFont = defaultFormat.font();\n#ifdef Q_OS_MACOS\n\t\tcommonScriptFont.setFamily(\"menlo\");\n#else\n\t\tcommonScriptFont.setFamily(\"monospace\");\n#endif\n\t\tcommonScriptFont.setStyleHint(QFont::Monospace);\n\t\tcommonScriptFont.setFixedPitch(true);\n\t\tcommonScriptFont.setKerning(false);\n\t\tcommonScriptFont.setPointSize(12);\n\t\tdefaultFormat.setFont(commonScriptFont);\n\n\t\tQColor defaultColor = getColor(COLOR_ID_TEXT_BACKGROUND);\n\t\tint refColor = 255 - (defaultColor.red() + defaultColor.green() +\n\t\t\tdefaultColor.blue() + 64) * 0.25;\n\t\tdefaultFormat.setForeground(QColor(refColor, refColor, refColor));\n\t}\n\telse if(a_textFormatID == TEXT_FORMAT_ID_KEYWORD)\n\t{\n\t\tdefaultFormat.setForeground(QColor(\"#0EAA95\"));\n\t\tdefaultFormat.setFontWeight(QFont::Bold);\n\t}\n\telse if(a_textFormatID == TEXT_FORMAT_ID_OPERATOR)\n\t{\n\t\tdefaultFormat.setForeground(QColor(\"#b9672a\"));\n\t}\n\telse if(a_textFormatID == TEXT_FORMAT_ID_STRING)\n\t{\n\t\tdefaultFormat.setForeground(QColor(\"#a500bc\"));\n\t}\n\telse if(a_textFormatID == TEXT_FORMAT_ID_NUMBER)\n\t{\n\t\tdefaultFormat.setForeground(QColor(\"#3f8300\"));\n\t}\n\telse if(a_textFormatID == TEXT_FORMAT_ID_COMMENT)\n\t{\n\t\tdefaultFormat.setForeground(QColor(\"#387000\"));\n\t}\n\telse if(a_textFormatID == TEXT_FORMAT_ID_VS_CORE)\n\t{\n\t\tdefaultFormat.setForeground(QColor(\"#0673E0\"));\n\t\tdefaultFormat.setFontWeight(QFont::Bold);\n\t}\n\telse if(a_textFormatID == TEXT_FORMAT_ID_VS_NAMESPACE)\n\t{\n\t\tdefaultFormat.setForeground(QColor(\"#0673E0\"));\n\t\tdefaultFormat.setFontWeight(QFont::Bold);\n\t}\n\telse if(a_textFormatID == TEXT_FORMAT_ID_VS_FUNCTION)\n\t{\n\t\tdefaultFormat.setForeground(QColor(\"#0673E0\"));\n\t\tdefaultFormat.setFontWeight(QFont::Bold);\n\t}\n\telse if(a_textFormatID == TEXT_FORMAT_ID_VS_ARGUMENT)\n\t{\n\t\tdefaultFormat.setForeground(QColor(\"#a500bc\"));\n\t}\n\telse if(a_textFormatID == TEXT_FORMAT_ID_TIMELINE)\n\t{\n\t\tQFont timelineLabelsFont = defaultFormat.font();\n\t\ttimelineLabelsFont.setFamily(QString(\"Digital Mini\"));\n\n\t\tQFontMetricsF metrics(timelineLabelsFont);\n\t\tqreal factor = (qreal)DEFAULT_TIMELINE_LABELS_HEIGHT /\n\t\t\tmetrics.tightBoundingRect(\"9\").height();\n\t\tqreal currentFontSize = timelineLabelsFont.pointSizeF();\n\t\ttimelineLabelsFont.setPointSizeF(currentFontSize * factor);\n\n\t\tdefaultFormat.setFont(timelineLabelsFont);\n\t}\n\n\treturn defaultFormat;\n}\n\nQTextCharFormat SettingsManager::getTextFormat(const QString & a_textFormatID)\n\tconst\n{\n\tQVariant textFormatValue = valueInGroup(inDarkMode() ? DARK_THEME_GROUP\n\t\t: THEME_GROUP, a_textFormatID);\n\tif(textFormatValue.isNull())\n\t\treturn getDefaultTextFormat(a_textFormatID);\n\treturn vsedit::fromByteArray<QTextCharFormat>(\n\t\ttextFormatValue.toByteArray());\n}\n\nbool SettingsManager::setTextFormat(const QString & a_textFormatID,\n\tconst QTextCharFormat & a_format)\n{\n\t// Only record to settings if it doesn't match the default\n\tQTextCharFormat defaultFmt = getTextFormat(a_textFormatID);\n\tif(defaultFmt == a_format) return true;\n\treturn setValueInGroup(inDarkMode() ? DARK_THEME_GROUP\n\t\t: THEME_GROUP, a_textFormatID, vsedit::toByteArray(a_format));\n}\n\n//==============================================================================\n\nQColor SettingsManager::getDefaultColor(const QString & a_colorID) const\n{\n\tQColor defaultColor;\n\n\tconst QPalette defaultPalette;\n\n\tif(a_colorID == COLOR_ID_TEXT_BACKGROUND)\n\t{\n\t\tif(inDarkMode())\n\t\t\treturn QColor(16, 16, 24);\n#ifdef Q_OS_WIN\n\t\tstatic bool inWindowsDarkMode =\n\t\t\tdefaultPalette.color(QPalette::WindowText).lightness()\n\t\t\t > defaultPalette.color(QPalette::Window).lightness();\n\t\tif(inWindowsDarkMode)\n\t\t\treturn QColor(16, 16, 24);\n\t\telse\n\t\t\treturn QColor(255, 255, 255);\n#else\n\t\treturn defaultPalette.color(QPalette::Active, QPalette::Base);\n#endif\n\t}\n\n\tif(a_colorID == COLOR_ID_ACTIVE_LINE)\n\t{\n\t\tdefaultColor = getColor(COLOR_ID_TEXT_BACKGROUND);\n\t\tint refColor = (defaultColor.red() + defaultColor.green() +\n\t\t\tdefaultColor.blue() + 128) * 0.25;\n\t\treturn QColor(refColor, refColor, refColor);\n\t}\n\n\tif(a_colorID == COLOR_ID_SELECTION_MATCHES)\n\t\treturn QColor(\"#FFCCFF\");\n\n\tif(a_colorID == COLOR_ID_TIMELINE_BOOKMARKS)\n\t\treturn Qt::magenta;\n\n\treturn defaultColor;\n}\n\nQColor SettingsManager::getColor(const QString & a_colorID) const\n{\n\tQVariant colorValue = valueInGroup(inDarkMode() ? DARK_THEME_GROUP\n\t\t: THEME_GROUP, a_colorID);\n\tif(colorValue.isNull())\n\t\treturn getDefaultColor(a_colorID);\n\treturn QColor(colorValue.toString());\n}\n\nbool SettingsManager::setColor(const QString & a_colorID,\n\tconst QColor & a_color)\n{\n\t// Only record to settings if it doesn't match the default\n\tQColor defaultColor = getDefaultColor(a_colorID);\n\tif(defaultColor == a_color) return true;\n\treturn setValueInGroup(inDarkMode() ? DARK_THEME_GROUP\n\t\t: THEME_GROUP, a_colorID, a_color.name());\n}\n\n//==============================================================================\n\nQString SettingsManager::getLastUsedPath() const\n{\n\tQStringList recentFilesList = getRecentFilesList();\n\tif(!recentFilesList.isEmpty())\n\t\treturn recentFilesList.first();\n\n\treturn QString();\n}\n\nbool SettingsManager::setLastUsedPath(const QString& a_lastUsedPath)\n{\n\treturn addToRecentFilesList(a_lastUsedPath);\n}\n\n//==============================================================================\n\nQByteArray SettingsManager::getMainWindowGeometry() const\n{\n\treturn value(MAIN_WINDOW_GEOMETRY_KEY).toByteArray();\n}\n\nbool SettingsManager::setMainWindowGeometry(\n\tconst QByteArray & a_mainWindowGeometry)\n{\n\treturn setValue(MAIN_WINDOW_GEOMETRY_KEY, a_mainWindowGeometry);\n}\n\n//==============================================================================\n\nbool SettingsManager::getMainWindowMaximized() const\n{\n\treturn value(MAIN_WINDOW_MAXIMIZED_KEY,\n\t\tDEFAULT_MAIN_WINDOW_MAXIMIZED).toBool();\n}\n\nbool SettingsManager::setMainWindowMaximized(bool a_mainWindowMaximized)\n{\n\treturn setValue(MAIN_WINDOW_MAXIMIZED_KEY, a_mainWindowMaximized);\n}\n\n//==============================================================================\n\nQByteArray SettingsManager::getPreviewDialogGeometry() const\n{\n\treturn value(PREVIEW_DIALOG_GEOMETRY_KEY).toByteArray();\n}\n\nbool SettingsManager::setPreviewDialogGeometry(\n\tconst QByteArray & a_previewDialogGeometry)\n{\n\treturn setValue(PREVIEW_DIALOG_GEOMETRY_KEY, a_previewDialogGeometry);\n}\n\n//==============================================================================\n\nbool SettingsManager::getPreviewDialogMaximized() const\n{\n\treturn value(PREVIEW_DIALOG_MAXIMIZED_KEY,\n\t\tDEFAULT_PREVIEW_DIALOG_MAXIMIZED).toBool();\n}\n\nbool SettingsManager::setPreviewDialogMaximized(bool a_previewDialogMaximized)\n{\n\treturn setValue(PREVIEW_DIALOG_MAXIMIZED_KEY, a_previewDialogMaximized);\n}\n\nQPoint SettingsManager::getLastPreviewScrollBarPositions() const\n{\n\tint x = valueInGroup(PREVIEWER_GROUP, LAST_PREVIEW_SCROLLBAR_POS_X, 0).toInt();\n\tint y = valueInGroup(PREVIEWER_GROUP, LAST_PREVIEW_SCROLLBAR_POS_Y, 0).toInt();\n\treturn QPoint(x, y);\n}\n\nbool SettingsManager::setLastPreviewScrollBarPositions(const QPoint &pos)\n{\n\tint x = pos.x();\n\tint y = pos.y();\n    return setValueInGroup(PREVIEWER_GROUP, LAST_PREVIEW_SCROLLBAR_POS_X, x)\n\t\t&& setValueInGroup(PREVIEWER_GROUP, LAST_PREVIEW_SCROLLBAR_POS_Y, y);\n}\n\n//==============================================================================\n\nQByteArray SettingsManager::getJobServerWatcherGeometry() const\n{\n\treturn value(JOB_SERVER_WATCHER_GEOMETRY_KEY).toByteArray();\n}\n\nbool SettingsManager::setJobServerWatcherGeometry(\n\tconst QByteArray & a_geometry)\n{\n\treturn setValue(JOB_SERVER_WATCHER_GEOMETRY_KEY, a_geometry);\n}\n\n//==============================================================================\n\nbool SettingsManager::getJobServerWatcherMaximized() const\n{\n\treturn value(JOB_SERVER_WATCHER_MAXIMIZED_KEY,\n\t\tDEFAULT_JOB_SERVER_WATCHER_MAXIMIZED).toBool();\n}\n\nbool SettingsManager::setJobServerWatcherMaximized(bool a_maximized)\n{\n\treturn setValue(JOB_SERVER_WATCHER_MAXIMIZED_KEY, a_maximized);\n}\n\n//==============================================================================\n\nQByteArray SettingsManager::getJobsHeaderState() const\n{\n\treturn value(JOBS_HEADER_STATE_KEY).toByteArray();\n}\n\nbool SettingsManager::setJobsHeaderState(const QByteArray & a_headerState)\n{\n\treturn setValue(JOBS_HEADER_STATE_KEY, a_headerState);\n}\n\n//==============================================================================\n\nbool SettingsManager::getAutoLoadLastScript() const\n{\n\treturn value(AUTO_LOAD_LAST_SCRIPT_KEY, DEFAULT_AUTO_LOAD_LAST_SCRIPT)\n\t\t.toBool();\n}\n\nbool SettingsManager::setAutoLoadLastScript(bool a_autoLoadLastScript)\n{\n\treturn setValue(AUTO_LOAD_LAST_SCRIPT_KEY, a_autoLoadLastScript);\n}\n\n//==============================================================================\n\nbool SettingsManager::getZoomPanelVisible() const\n{\n\treturn value(ZOOM_PANEL_VISIBLE_KEY, DEFAULT_ZOOM_PANEL_VISIBLE).toBool();\n}\n\nbool SettingsManager::setZoomPanelVisible(bool a_zoomPanelVisible)\n{\n\treturn setValue(ZOOM_PANEL_VISIBLE_KEY, a_zoomPanelVisible);\n}\n\n//==============================================================================\n\nZoomMode SettingsManager::getZoomMode() const\n{\n\treturn (ZoomMode)value(ZOOM_MODE_KEY, (int)DEFAULT_ZOOM_MODE).toInt();\n}\n\nbool SettingsManager::setZoomMode(ZoomMode a_zoomMode)\n{\n\treturn setValue(ZOOM_MODE_KEY, (int)a_zoomMode);\n}\n\n//==============================================================================\n\ndouble SettingsManager::getZoomRatio() const\n{\n\treturn value(ZOOM_RATIO_KEY, DEFAULT_ZOOM_RATIO).toDouble();\n}\n\nbool SettingsManager::setZoomRatio(double a_zoomRatio)\n{\n\treturn setValue(ZOOM_RATIO_KEY, a_zoomRatio);\n}\n\n//==============================================================================\n\nQt::TransformationMode SettingsManager::getScaleMode() const\n{\n\treturn (Qt::TransformationMode)value(SCALE_MODE_KEY,\n\t\t(int)DEFAULT_SCALE_MODE).toInt();\n}\n\nbool SettingsManager::setScaleMode(Qt::TransformationMode a_scaleMode)\n{\n\treturn setValue(SCALE_MODE_KEY, (int)a_scaleMode);\n}\n\n//==============================================================================\n\nCropMode SettingsManager::getCropMode() const\n{\n\treturn (CropMode)value(CROP_MODE_KEY, (int)DEFAULT_CROP_MODE).toInt();\n}\n\nbool SettingsManager::setCropMode(CropMode a_cropMode)\n{\n\treturn setValue(CROP_MODE_KEY, (int)a_cropMode);\n}\n\n//==============================================================================\n\nint SettingsManager::getCropZoomRatio() const\n{\n\treturn value(CROP_ZOOM_RATIO_KEY, DEFAULT_CROP_ZOOM_RATIO).toInt();\n}\n\nbool SettingsManager::setCropZoomRatio(int a_cropZoomRatio)\n{\n\treturn setValue(CROP_ZOOM_RATIO_KEY, a_cropZoomRatio);\n}\n\n//==============================================================================\n\nbool SettingsManager::getPromptToSaveChanges() const\n{\n\treturn value(PROMPT_TO_SAVE_CHANGES_KEY,\n\t\tDEFAULT_PROMPT_TO_SAVE_CHANGES).toBool();\n}\n\nbool SettingsManager::setPromptToSaveChanges(bool a_prompt)\n{\n\treturn setValue(PROMPT_TO_SAVE_CHANGES_KEY, a_prompt);\n}\n\n//==============================================================================\n\nQStringList SettingsManager::getRecentFilesList() const\n{\n\treturn value(RECENT_FILES_LIST_KEY).toStringList();\n}\n\nbool SettingsManager::addToRecentFilesList(const QString & a_filePath)\n{\n\tQFileInfo fileInfo(a_filePath);\n\tQString canonicalPath = fileInfo.canonicalFilePath();\n\tQStringList recentFilesList = getRecentFilesList();\n\trecentFilesList.removeAll(canonicalPath);\n\trecentFilesList.prepend(canonicalPath);\n\tunsigned int maxRecentFilesNumber = getMaxRecentFilesNumber();\n\twhile((unsigned int)recentFilesList.size() > maxRecentFilesNumber)\n\t\trecentFilesList.removeLast();\n\treturn setValue(RECENT_FILES_LIST_KEY, recentFilesList);\n}\n\n//==============================================================================\n\nunsigned int SettingsManager::getMaxRecentFilesNumber() const\n{\n\treturn value(MAX_RECENT_FILES_NUMBER_KEY,\n\t\tDEFAULT_MAX_RECENT_FILES_NUMBER).toUInt();\n}\n\nbool SettingsManager::setMaxRecentFilesNumber(\n\tunsigned int a_maxRecentFilesNumber)\n{\n\treturn setValue(MAX_RECENT_FILES_NUMBER_KEY, a_maxRecentFilesNumber);\n}\n\nbool SettingsManager::getReloadScriptFromDisk() const\n{\n\treturn value(RELOAD_FROM_DISK_KEY, DEFAULT_RELOAD_FROM_DISK).toBool();\n}\n\nbool SettingsManager::setReloadScriptFromDisk(bool a_reload)\n{\n\treturn setValue(RELOAD_FROM_DISK_KEY, a_reload);\n}\n\n//==============================================================================\n\nint SettingsManager::getCharactersTypedToStartCompletion() const\n{\n\treturn value(CHARACTERS_TYPED_TO_START_COMPLETION_KEY,\n\t\tDEFAULT_CHARACTERS_TYPED_TO_START_COMPLETION).toInt();\n}\n\nbool SettingsManager::setCharactersTypedToStartCompletion(\n\tint a_charactersNumber)\n{\n\treturn setValue(CHARACTERS_TYPED_TO_START_COMPLETION_KEY,\n\t\ta_charactersNumber);\n}\n\n//==============================================================================\n\nTimeLineSlider::DisplayMode SettingsManager::getTimeLineMode() const\n{\n\treturn (TimeLineSlider::DisplayMode)value(TIMELINE_MODE_KEY,\n\t\t(int)DEFAULT_TIMELINE_MODE).toInt();\n}\n\nbool SettingsManager::setTimeLineMode(\n\tTimeLineSlider::DisplayMode a_timeLineMode)\n{\n\treturn setValue(TIMELINE_MODE_KEY, (int)a_timeLineMode);\n}\n\n//==============================================================================\n\ndouble SettingsManager::getTimeStep() const\n{\n\treturn value(TIME_STEP_KEY, DEFAULT_TIME_STEP).toDouble();\n}\n\nbool SettingsManager::setTimeStep(double a_timeStep)\n{\n\treturn setValue(TIME_STEP_KEY, a_timeStep);\n}\n\n//==============================================================================\n\nbool SettingsManager::getColorPickerVisible() const\n{\n\treturn value(COLOR_PICKER_VISIBLE_KEY,\n\t\tDEFAULT_COLOR_PICKER_VISIBLE).toBool();\n}\n\nbool SettingsManager::setColorPickerVisible(bool a_colorPickerVisible)\n{\n\treturn setValue(COLOR_PICKER_VISIBLE_KEY, a_colorPickerVisible);\n}\n\n//==============================================================================\n\nPlayFPSLimitMode SettingsManager::getPlayFPSLimitMode() const\n{\n\treturn (PlayFPSLimitMode)value(PLAY_FPS_LIMIT_MODE_KEY,\n\t\t(int)DEFAULT_PLAY_FPS_LIMIT_MODE).toInt();\n}\n\nbool SettingsManager::setPlayFPSLimitMode(PlayFPSLimitMode a_mode)\n{\n\treturn setValue(PLAY_FPS_LIMIT_MODE_KEY, (int)a_mode);\n}\n\n//==============================================================================\n\ndouble SettingsManager::getPlayFPSLimit() const\n{\n\treturn value(PLAY_FPS_LIMIT_KEY, DEFAULT_PLAY_FPS_LIMIT).toDouble();\n}\n\nbool SettingsManager::setPlayFPSLimit(double a_limit)\n{\n\treturn setValue(PLAY_FPS_LIMIT_KEY, a_limit);\n}\n\n//==============================================================================\n\nbool SettingsManager::getUseSpacesAsTab() const\n{\n\treturn value(USE_SPACES_AS_TAB_KEY, DEFAULT_USE_SPACES_AS_TAB).toBool();\n}\n\nbool SettingsManager::setUseSpacesAsTab(bool a_value)\n{\n\treturn setValue(USE_SPACES_AS_TAB_KEY, a_value);\n}\n\n//==============================================================================\n\nint SettingsManager::getSpacesInTab() const\n{\n\treturn value(SPACES_IN_TAB_KEY, DEFAULT_SPACES_IN_TAB).toInt();\n}\n\nbool SettingsManager::setSpacesInTab(int a_spacesNumber)\n{\n\treturn setValue(SPACES_IN_TAB_KEY, a_spacesNumber);\n}\n\n//==============================================================================\n\nQString SettingsManager::getTabText() const\n{\n\tQString text = \"\\t\";\n\tbool useSpacesAsTab = getUseSpacesAsTab();\n\tif(useSpacesAsTab)\n\t{\n\t\tint spacesInTab = getSpacesInTab();\n\t\ttext.fill(' ', spacesInTab);\n\t}\n\treturn text;\n}\n\n//==============================================================================\n\nbool SettingsManager::getRememberLastPreviewFrame() const\n{\n\treturn value(REMEMBER_LAST_PREVIEW_FRAME_KEY,\n\t\tDEFAULT_REMEMBER_LAST_PREVIEW_FRAME).toBool();\n}\n\nbool SettingsManager::setRememberLastPreviewFrame(bool a_remember)\n{\n\treturn setValue(REMEMBER_LAST_PREVIEW_FRAME_KEY, a_remember);\n}\n\n//==============================================================================\n\nint SettingsManager::getLastPreviewFrame(bool a_inPreviewer) const\n{\n\tif(a_inPreviewer)\n\t{\n\t\treturn valueInGroup(PREVIEWER_GROUP, LAST_PREVIEW_FRAME_KEY,\n\t\t\tDEFAULT_LAST_PREVIEW_FRAME).toInt();\n\t}\n\treturn value(LAST_PREVIEW_FRAME_KEY, DEFAULT_LAST_PREVIEW_FRAME).toInt();\n}\n\nbool SettingsManager::setLastPreviewFrame(int a_frameNumber, bool a_inPreviewer)\n{\n\tif(a_inPreviewer)\n\t{\n\t\treturn setValueInGroup(PREVIEWER_GROUP,\n\t\t\tLAST_PREVIEW_FRAME_KEY, a_frameNumber);\n\t}\n\treturn setValue(LAST_PREVIEW_FRAME_KEY, a_frameNumber);\n}\n\nqlonglong SettingsManager::getLastPreviewTimestamp(bool a_inPreviewer) const\n{\n\tif(a_inPreviewer)\n\t\treturn valueInGroup(PREVIEWER_GROUP, LAST_PREVIEW_TIMESTAMP_KEY,\n\t\t\tDEFAULT_LAST_PREVIEW_TIMESTAMP).toLongLong();\n\treturn value(LAST_PREVIEW_TIMESTAMP_KEY,\n\t\t\tDEFAULT_LAST_PREVIEW_TIMESTAMP).toLongLong();\n}\n\nbool SettingsManager::setLastPreviewTimestamp(qlonglong a_ms, bool a_inPreviewer)\n{\n\tif(a_inPreviewer)\n\t\treturn setValueInGroup(PREVIEWER_GROUP, LAST_PREVIEW_TIMESTAMP_KEY, a_ms);\n\treturn setValue(LAST_PREVIEW_TIMESTAMP_KEY, a_ms);\n}\n\nSyncOutputNodesMode SettingsManager::getSyncOutputMode() const\n{\n\treturn (SyncOutputNodesMode)value(SYNC_OUTPUT_MODE_KEY,\n\t\t(int)DEFAULT_SYNC_OUTPUT_MODE).toInt();\n}\n\nbool SettingsManager::setSyncOutputMode(SyncOutputNodesMode a_mode)\n{\n\treturn setValue(SYNC_OUTPUT_MODE_KEY, (int)a_mode);\n}\n\n//==============================================================================\n\nQString SettingsManager::getDefaultNewScriptTemplate()\n{\n\treturn QString(\n\t\t\"import vapoursynth as vs\\n\"\n\t\t\"core = vs.core\\n\"\n\t);\n}\n\nQString SettingsManager::getNewScriptTemplate()\n{\n\treturn value(NEW_SCRIPT_TEMPLATE_KEY,\n\t\tgetDefaultNewScriptTemplate()).toString();\n}\n\nbool SettingsManager::setNewScriptTemplate(const QString & a_text)\n{\n\treturn setValue(NEW_SCRIPT_TEMPLATE_KEY, a_text);\n}\n\n//==============================================================================\n\nstd::vector<CodeSnippet> SettingsManager::getAllCodeSnippets() const\n{\n\tQSettings settings(m_settingsFilePath, QSettings::IniFormat);\n\tsettings.beginGroup(CODE_SNIPPETS_GROUP);\n\n\tstd::vector<CodeSnippet> snippets;\n\n\tQStringList snippetNames = settings.childKeys();\n\tfor(const QString & snippetName : snippetNames)\n\t{\n\t\tCodeSnippet snippet(snippetName);\n\t\tsnippet.text = settings.value(snippetName).toString();\n\t\tsnippets.push_back(snippet);\n\t}\n\n\treturn snippets;\n}\n\nCodeSnippet SettingsManager::getCodeSnippet(const QString & a_name) const\n{\n\tQSettings settings(m_settingsFilePath, QSettings::IniFormat);\n\tsettings.beginGroup(CODE_SNIPPETS_GROUP);\n\n\tCodeSnippet snippet;\n\n\tif(!settings.contains(a_name))\n\t\treturn snippet;\n\n\tsnippet.name = a_name;\n\tsnippet.text = valueInGroup(CODE_SNIPPETS_GROUP, a_name).toString();\n\n\treturn snippet;\n}\n\nbool SettingsManager::saveCodeSnippet(const CodeSnippet & a_snippet)\n{\n\treturn setValueInGroup(CODE_SNIPPETS_GROUP, a_snippet.name, a_snippet.text);\n}\n\nbool SettingsManager::deleteCodeSnippet(const QString & a_name)\n{\n\treturn deleteValueInGroup(CODE_SNIPPETS_GROUP, a_name);\n}\n\n//==============================================================================\n\nstd::vector<DropFileCategory> SettingsManager::getAllDropFileTemplates() const\n{\n\tQSettings settings(m_settingsFilePath, QSettings::IniFormat);\n\tsettings.beginGroup(DROP_FILE_TEMPLATES_GROUP);\n\n\tstd::vector<DropFileCategory> categories;\n\n\tQStringList categoryNames = settings.childGroups();\n\tfor(const QString & categoryName : categoryNames)\n\t{\n\t\tsettings.beginGroup(categoryName);\n\n\t\tDropFileCategory category;\n\t\tcategory.name = categoryName;\n\t\tcategory.maskList =\n\t\t\tsettings.value(DROP_FILE_CATEGORY_MASK_LIST_KEY).toStringList();\n\t\tcategory.sourceTemplate =\n\t\t\tsettings.value(DROP_FILE_CATEGORY_SOURCE_TEMPLATE_KEY).toString();\n\t\tcategories.push_back(category);\n\n\t\tsettings.endGroup();\n\t}\n\n\treturn categories;\n}\n\nbool SettingsManager::setDropFileTemplates(\n\tconst std::vector<DropFileCategory> & a_categories)\n{\n\tQSettings settings(m_settingsFilePath, QSettings::IniFormat);\n\n\tsettings.remove(DROP_FILE_TEMPLATES_GROUP);\n\tsettings.beginGroup(DROP_FILE_TEMPLATES_GROUP);\n\n\tfor(const DropFileCategory & category : a_categories)\n\t{\n\t\tsettings.beginGroup(category.name);\n\t\tsettings.setValue(DROP_FILE_CATEGORY_MASK_LIST_KEY, category.maskList);\n\t\tsettings.setValue(DROP_FILE_CATEGORY_SOURCE_TEMPLATE_KEY,\n\t\t\tcategory.sourceTemplate);\n\t\tsettings.endGroup();\n\t}\n\n\tsettings.sync();\n\tbool success = (QSettings::NoError == settings.status());\n\treturn success;\n}\n\nQString SettingsManager::getDropFileTemplate(const QString & a_filePath) const\n{\n\tQSettings settings(m_settingsFilePath, QSettings::IniFormat);\n\tsettings.beginGroup(DROP_FILE_TEMPLATES_GROUP);\n\n\tstd::vector<DropFileCategory> categories = getAllDropFileTemplates();\n\n\tfor(const DropFileCategory & category : categories)\n\t{\n\t\tfor(const QString & mask : category.maskList)\n\t\t{\n\t\t\tauto re = QRegularExpression::fromWildcard(mask,\n\t\t\t\tQt::CaseInsensitive,\n\t\t\t\tQRegularExpression::UnanchoredWildcardConversion);\n\t\t\tif(re.match(a_filePath).hasMatch())\n\t\t\t\treturn category.sourceTemplate;\n\t\t}\n\t}\n\n\treturn QString(DEFAULT_DROP_FILE_TEMPLATE);\n}\n\n//==============================================================================\n\nbool SettingsManager::getHighlightSelectionMatches() const\n{\n\treturn value(HIGHLIGHT_SELECTION_MATCHES_KEY,\n\t\tDEFAULT_HIGHLIGHT_SELECTION_MATCHES).toBool();\n}\n\nbool SettingsManager::setHighlightSelectionMatches(bool a_highlight)\n{\n\treturn setValue(HIGHLIGHT_SELECTION_MATCHES_KEY, a_highlight);\n}\n\n//==============================================================================\n\nint SettingsManager::getHighlightSelectionMatchesMinLength() const\n{\n\treturn value(HIGHLIGHT_SELECTION_MATCHES_MIN_LENGTH_KEY,\n\t\tDEFAULT_HIGHLIGHT_SELECTION_MATCHES_MIN_LENGTH).toInt();\n}\n\nbool SettingsManager::setHighlightSelectionMatchesMinLength(int a_length)\n{\n\treturn setValue(HIGHLIGHT_SELECTION_MATCHES_MIN_LENGTH_KEY, a_length);\n}\n\n//==============================================================================\n\nbool SettingsManager::getTimeLinePanelVisible() const\n{\n\treturn value(TIMELINE_PANEL_VISIBLE_KEY,\n\t\tDEFAULT_TIMELINE_PANEL_VISIBLE).toBool();\n}\n\nbool SettingsManager::setTimeLinePanelVisible(bool a_visible)\n{\n\treturn setValue(TIMELINE_PANEL_VISIBLE_KEY, a_visible);\n}\n\n//==============================================================================\n\nbool SettingsManager::getAlwaysKeepCurrentFrame() const\n{\n\treturn value(ALWAYS_KEEP_CURRENT_FRAME_KEY,\n\t\tDEFAULT_ALWAYS_KEEP_CURRENT_FRAME).toBool();\n}\n\nbool SettingsManager::setAlwaysKeepCurrentFrame(bool a_keep)\n{\n\treturn setValue(ALWAYS_KEEP_CURRENT_FRAME_KEY, a_keep);\n}\n\n//==============================================================================\n\nstd::vector<TextBlockStyle> SettingsManager::getLogStyles(\n\tconst QString & a_logName) const\n{\n\tstd::vector<TextBlockStyle> styles;\n\n\tif(a_logName.isEmpty())\n\t\treturn styles;\n\n\tQSettings settings(m_settingsFilePath, QSettings::IniFormat);\n\tsettings.beginGroup(LOGS_GROUP);\n\n\tQStringList logNames = settings.childGroups();\n\tif(!logNames.contains(a_logName))\n\t\treturn styles;\n\n\tsettings.beginGroup(a_logName);\n\tsettings.beginGroup(LOG_STYLES_GROUP);\n\n\tQStringList styleNames = settings.childGroups();\n\tfor(const QString & styleName : styleNames)\n\t{\n\t\tsettings.beginGroup(styleName);\n\n\t\tTextBlockStyle style;\n\t\tstyle.name = styleName;\n\t\tstyle.title = settings.value(LOG_STYLE_TITLE_KEY).toString();\n\t\tif(settings.contains(LOG_STYLE_TEXT_FORMAT_KEY))\n\t\t\tstyle.textFormat = qvariant_cast<QTextFormat>(\n\t\t\t\tsettings.value(LOG_STYLE_TEXT_FORMAT_KEY)).toCharFormat();\n\t\tstyle.isAlias = settings.value(LOG_STYLE_IS_ALIAS_KEY, false).toBool();\n\t\tstyle.originalStyleName =\n\t\t\tsettings.value(LOG_STYLE_ORIGINAL_STYLE_NAME_KEY).toString();\n\t\tstyle.isVisible =\n\t\t\tsettings.value(LOG_STYLE_IS_VISIBLE_KEY, true).toBool();\n\n\t\tstyles.push_back(style);\n\n\t\tsettings.endGroup();\n\t}\n\n\treturn styles;\n}\n\nbool SettingsManager::setLogStyles(const QString & a_logName,\n\tconst std::vector<TextBlockStyle> a_styles)\n{\n\tif(a_logName.isEmpty())\n\t\treturn false;\n\n\tif(a_styles.empty())\n\t\treturn false;\n\n\tQSettings settings(m_settingsFilePath, QSettings::IniFormat);\n\tsettings.beginGroup(LOGS_GROUP);\n\tsettings.beginGroup(a_logName);\n\tsettings.remove(LOG_STYLES_GROUP);\n\tsettings.beginGroup(LOG_STYLES_GROUP);\n\tfor(const TextBlockStyle & style : a_styles)\n\t{\n\t\tsettings.beginGroup(style.name);\n\t\tsettings.setValue(LOG_STYLE_TITLE_KEY, style.title);\n\t\tsettings.setValue(LOG_STYLE_TEXT_FORMAT_KEY, style.textFormat);\n\t\tsettings.setValue(LOG_STYLE_IS_ALIAS_KEY, style.isAlias);\n\t\tsettings.setValue(LOG_STYLE_ORIGINAL_STYLE_NAME_KEY,\n\t\t\tstyle.originalStyleName);\n\t\tsettings.setValue(LOG_STYLE_IS_VISIBLE_KEY, style.isVisible);\n\t\tsettings.endGroup();\n\t}\n\n\tsettings.sync();\n\tbool success = (QSettings::NoError == settings.status());\n\treturn success;\n}\n\n//==============================================================================\n\nQString SettingsManager::getLastSnapshotExtension() const\n{\n\treturn value(LAST_SNAPSHOT_EXTENSION_KEY,\n\t\tDEFAULT_LAST_SNAPSHOT_EXTENSION).toString();\n}\n\nbool SettingsManager::setLastSnapshotExtension(const QString & a_extension)\n{\n\treturn setValue(LAST_SNAPSHOT_EXTENSION_KEY, a_extension);\n}\n\nint SettingsManager::getPNGSnapshotCompressionLevel() const\n{\n\treturn value(PNG_COMPRESSION_LEVEL_KEY,\n\t\tDEFAULT_PNG_COMPRESSION_LEVEL).toInt();\n}\n\nbool SettingsManager::setPNGSnapshotCompressionLevel(int a_level)\n{\n\treturn setValue(PNG_COMPRESSION_LEVEL_KEY, a_level);\n}\n\nbool SettingsManager::getShowDebugMessages() const\n{\n    return value(DEBUG_MESSAGES_KEY, DEFAULT_DEBUG_MESSAGES).toBool();\n}\n\nbool SettingsManager::setShowDebugMessages(bool a_debug)\n{\n    return setValue(DEBUG_MESSAGES_KEY, a_debug);\n}\n\nbool SettingsManager::getDarkMode() const\n{\n\treturn value(DARK_MODE_KEY, DEFAULT_DARK_MODE).toBool();\n}\n\nbool SettingsManager::setDarkMode(bool a_dark)\n{\n\treturn setValue(DARK_MODE_KEY, a_dark);\n}\n\nbool SettingsManager::getSilentSnapshot() const\n{\n\treturn value(SILENT_SNAPSHOT_KEY, DEFAULT_SILENT_SNAPSHOT).toBool();\n}\n\nbool SettingsManager::setSilentSnapshot(bool a_set)\n{\n\treturn setValue(SILENT_SNAPSHOT_KEY, a_set);\n}\n\nQString SettingsManager::getSnapshotTemplate() const\n{\n\treturn value(SNAPSHOT_TEMPLATE_KEY, DEFAULT_SNAPSHOT_TEMPLATE).toString();\n}\n\nbool SettingsManager::setSnapshotTemplate(const QString & a_template)\n{\n\treturn setValue(SNAPSHOT_TEMPLATE_KEY, a_template);\n}\n\n//==============================================================================\n"
  },
  {
    "path": "common-src/settings/settings_manager.h",
    "content": "#ifndef SETTINGSMANAGER_H\n#define SETTINGSMANAGER_H\n\n#include \"settings_manager_core.h\"\n#include \"settings_definitions.h\"\n\n#include <QByteArray>\n#include <QTextCharFormat>\n#include <QColor>\n#include <QAction>\n\n//==============================================================================\n\nclass SettingsManager : public SettingsManagerCore\n{\npublic:\n\n\tSettingsManager(QObject * a_pParent);\n\tvirtual ~SettingsManager();\n\n\t//----------------------------------------------------------------------\n\n\tQAction * createStandardAction(const QString & a_actionID,\n\t\tQObject * a_pParent);\n\n\tstd::vector<StandardAction> getStandardActions() const;\n\n\tQKeySequence getDefaultHotkey(const QString & a_actionID) const;\n\n\tQKeySequence getHotkey(const QString & a_actionID) const;\n\n\tbool setHotkey(const QString & a_actionID,\n\t\tconst QKeySequence & a_hotkey);\n\n\t//----------------------------------------------------------------------\n\n\tQTextCharFormat getDefaultTextFormat(const QString & a_textFormatID)\n\t\tconst;\n\n\tQTextCharFormat getTextFormat(const QString & a_textFormatID) const;\n\n\tbool setTextFormat(const QString & a_textFormatID,\n\t\tconst QTextCharFormat & a_format);\n\n\t//----------------------------------------------------------------------\n\n\tQColor getDefaultColor(const QString & a_colorID) const;\n\n\tQColor getColor(const QString & a_colorID) const;\n\n\tbool setColor(const QString & a_colorID, const QColor & a_color);\n\n\t//----------------------------------------------------------------------\n\n\tQString getLastUsedPath() const;\n\n\tbool setLastUsedPath(const QString& a_lastUsedPath);\n\n\tQByteArray getMainWindowGeometry() const;\n\n\tbool setMainWindowGeometry(const QByteArray & a_mainWindowGeometry);\n\n\tbool getMainWindowMaximized() const;\n\n\tbool setMainWindowMaximized(bool a_mainWindowMaximized);\n\n\tQByteArray getPreviewDialogGeometry() const;\n\n\tbool setPreviewDialogGeometry(const QByteArray & a_previewDialogGeometry);\n\n\tbool getPreviewDialogMaximized() const;\n\n\tbool setPreviewDialogMaximized(bool a_previewDialogMaximized);\n\n\tQPoint getLastPreviewScrollBarPositions() const;\n\n\tbool setLastPreviewScrollBarPositions(const QPoint &pos);\n\n\tQByteArray getJobServerWatcherGeometry() const;\n\n\tbool setJobServerWatcherGeometry(const QByteArray & a_geometry);\n\n\tbool getJobServerWatcherMaximized() const;\n\n\tbool setJobServerWatcherMaximized(bool a_maximized);\n\n\tQByteArray getJobsHeaderState() const;\n\n\tbool setJobsHeaderState(const QByteArray & a_headerState);\n\n\tbool getAutoLoadLastScript() const;\n\n\tbool setAutoLoadLastScript(bool a_autoLoadLastScript);\n\n\tbool getZoomPanelVisible() const;\n\n\tbool setZoomPanelVisible(bool a_zoomPanelVisible);\n\n\tZoomMode getZoomMode() const;\n\n\tbool setZoomMode(ZoomMode a_zoomMode);\n\n\tdouble getZoomRatio() const;\n\n\tbool setZoomRatio(double a_zoomRatio);\n\n\tQt::TransformationMode getScaleMode() const;\n\n\tbool setScaleMode(Qt::TransformationMode a_scaleMode);\n\n\tCropMode getCropMode() const;\n\n\tbool setCropMode(CropMode a_cropMode);\n\n\tint getCropZoomRatio() const;\n\n\tbool setCropZoomRatio(int a_cropZoomRatio);\n\n\tbool getPromptToSaveChanges() const;\n\n\tbool setPromptToSaveChanges(bool a_prompt);\n\n\tQStringList getRecentFilesList() const;\n\n\tbool addToRecentFilesList(const QString & a_filePath);\n\n\tunsigned int getMaxRecentFilesNumber() const;\n\n\tbool setMaxRecentFilesNumber(unsigned int a_maxRecentFilesNumber);\n\n\tbool getReloadScriptFromDisk() const;\n\n\tbool setReloadScriptFromDisk(bool a_reload);\n\n\tint getCharactersTypedToStartCompletion() const;\n\n\tbool setCharactersTypedToStartCompletion(int a_charactersNumber);\n\n\tTimeLineSlider::DisplayMode getTimeLineMode() const;\n\n\tbool setTimeLineMode(TimeLineSlider::DisplayMode a_timeLineMode);\n\n\tdouble getTimeStep() const;\n\n\tbool setTimeStep(double a_timeStep);\n\n\tbool getColorPickerVisible() const;\n\n\tbool setColorPickerVisible(bool a_colorPickerVisible);\n\n\tPlayFPSLimitMode getPlayFPSLimitMode() const;\n\n\tbool setPlayFPSLimitMode(PlayFPSLimitMode a_mode);\n\n\tdouble getPlayFPSLimit() const;\n\n\tbool setPlayFPSLimit(double a_limit);\n\n\tbool getUseSpacesAsTab() const;\n\n\tbool setUseSpacesAsTab(bool a_value);\n\n\tint getSpacesInTab() const;\n\n\tbool setSpacesInTab(int a_spacesNumber);\n\n\tQString getTabText() const;\n\n\tbool getRememberLastPreviewFrame() const;\n\n\tbool setRememberLastPreviewFrame(bool a_remember);\n\n\tint getLastPreviewFrame(bool a_inPreviewer = false) const;\n\n\tbool setLastPreviewFrame(int a_frameNumber, bool a_inPreviewer = false);\n\n\t// timestamp in ms\n\tqlonglong getLastPreviewTimestamp(bool a_inPreviewer = false) const;\n\n\tbool setLastPreviewTimestamp(qlonglong a_ms, bool a_inPreviewer = false);\n\n\tSyncOutputNodesMode getSyncOutputMode() const;\n\n\tbool setSyncOutputMode(SyncOutputNodesMode a_mode);\n\n\tQString getDefaultNewScriptTemplate();\n\n\tQString getNewScriptTemplate();\n\n\tbool setNewScriptTemplate(const QString & a_text);\n\n\tstd::vector<CodeSnippet> getAllCodeSnippets() const;\n\n\tCodeSnippet getCodeSnippet(const QString & a_name) const;\n\n\tbool saveCodeSnippet(const CodeSnippet & a_snippet);\n\n\tbool deleteCodeSnippet(const QString & a_name);\n\n\tstd::vector<DropFileCategory> getAllDropFileTemplates() const;\n\n\tbool setDropFileTemplates(\n\t\tconst std::vector<DropFileCategory> & a_categories);\n\n\tQString getDropFileTemplate(const QString & a_filePath) const;\n\n\tbool getHighlightSelectionMatches() const;\n\n\tbool setHighlightSelectionMatches(bool a_highlight);\n\n\tint getHighlightSelectionMatchesMinLength() const;\n\n\tbool setHighlightSelectionMatchesMinLength(int a_length);\n\n\tbool getTimeLinePanelVisible() const;\n\n\tbool setTimeLinePanelVisible(bool a_visible);\n\n\tbool getAlwaysKeepCurrentFrame() const;\n\n\tbool setAlwaysKeepCurrentFrame(bool a_keep);\n\n\tstd::vector<TextBlockStyle> getLogStyles(const QString & a_logName) const;\n\n\tbool setLogStyles(const QString & a_logName,\n\t\tconst std::vector<TextBlockStyle> a_styles);\n\n\tQString getLastSnapshotExtension() const;\n\n\tbool setLastSnapshotExtension(const QString & a_extension);\n\n\tint getPNGSnapshotCompressionLevel() const;\n\n\tbool setPNGSnapshotCompressionLevel(int a_level);\n\n\tbool getShowDebugMessages() const;\n\n\tbool setShowDebugMessages(bool a_debug);\n\n\tbool getDarkMode() const;\n\n\tbool setDarkMode(bool a_dark);\n\n\tbool inDarkMode() const { return m_bInDarkMode; }\n\n\tbool getSilentSnapshot() const;\n\n\tbool setSilentSnapshot(bool a_set);\n\n\tQString getSnapshotTemplate() const;\n\n\tbool setSnapshotTemplate(const QString & a_template);\n\nprivate:\n\n\tvoid initializeStandardActions();\n\n\tstd::vector<StandardAction> m_standardActions;\n\n\tbool m_bInDarkMode;\n};\n\n//==============================================================================\n\n#endif // SETTINGSMANAGER_H\n"
  },
  {
    "path": "common-src/settings/settings_manager_core.cpp",
    "content": "#include \"settings_manager_core.h\"\n\n#include <QCoreApplication>\n#include <QFile>\n#include <QFileInfo>\n#include <QStandardPaths>\n#include <QSettings>\n\n//==============================================================================\n\nconst char SETTINGS_FILE_NAME[] = \"/vsedit.config\";\n\n//==============================================================================\n\nconst char COMMON_GROUP[] = \"common\";\n\nconst char VAPOURSYNTH_LIBRARY_PATHS_KEY[] = \"vapoursynth_library_paths\";\nconst char PREFER_VS_LIBRARIES_FROM_LIST_KEY[] = \"prefer_vs_libs_from_list\";\nconst char CHROMA_RESAMPLING_FILTER_KEY[] = \"chroma_resampling_filter\";\nconst char YUV_MATRIX_COEFFICIENTS_KEY[] = \"yuv_matrix_coefficients\";\nconst char CHROMA_PLACEMENT_KEY[] = \"chroma_placement\";\nconst char BICUBIC_FILTER_PARAMETER_B_KEY[] = \"bicubic_filter_parameter_b\";\nconst char BICUBIC_FILTER_PARAMETER_C_KEY[] = \"bicubic_filter_parameter_c\";\nconst char LANCZOS_FILTER_TAPS_KEY[] = \"lanczos_filter_taps\";\nconst char DITHER_TYPE_KEY[] = \"dither_type\";\nconst char RECENT_JOB_SERVERS_KEY[] = \"recent_job_servers\";\nconst char TRUSTED_CLIENTS_ADDRESSES_KEY[] = \"trusted_clients_addresses\";\n\n//==============================================================================\n\nconst char ENCODING_PRESETS_GROUP[] = \"encoding_presets\";\n\nconst char ENCODING_PRESET_ENCODING_TYPE_KEY[] = \"encoding_type\";\nconst char ENCODING_PRESET_HEADER_TYPE_KEY[] = \"header_type\";\nconst char ENCODING_PRESET_EXECUTABLE_PATH_KEY[] = \"executable_path\";\nconst char ENCODING_PRESET_ARGUMENTS_KEY[] = \"arguments\";\n\n//==============================================================================\n\nconst char JOBS_GROUP[] = \"jobs\";\n\nconst char JOB_ID_KEY[] = \"id\";\nconst char JOB_TYPE_KEY[] = \"type\";\nconst char JOB_STATE_KEY[] = \"state\";\nconst char JOB_DEPENDS_ON_JOBS_KEY[] = \"depends_on_jobs\";\nconst char JOB_TIME_STARTED_KEY[] = \"time_started\";\nconst char JOB_TIME_ENDED_KEY[] = \"time_ended\";\nconst char JOB_SCRIPT_NAME_KEY[] = \"script_name\";\nconst char JOB_SCRIPT_TEXT_KEY[] = \"script_text\";\nconst char JOB_ENCODING_TYPE_KEY[] = \"encoding_type\";\nconst char JOB_ENCODING_HEADER_TYPE_KEY[] = \"encoding_header_type\";\nconst char JOB_EXECUTABLE_PATH_KEY[] = \"executable_path\";\nconst char JOB_ARGUMENTS_KEY[] = \"arguments\";\nconst char JOB_SHELL_COMMAND_KEY[] = \"shell_command\";\nconst char JOB_FIRST_FRAME_KEY[] = \"first_frame\";\nconst char JOB_FIRST_FRAME_REAL_KEY[] = \"first_frame_real\";\nconst char JOB_LAST_FRAME_KEY[] = \"last_frame\";\nconst char JOB_LAST_FRAME_REAL_KEY[] = \"last_frame_real\";\nconst char JOB_FRAME_PROCESSED_KEY[] = \"frames_processed\";\nconst char JOB_FPS_KEY[] = \"fps\";\n\n//==============================================================================\n\nSettingsManagerCore::SettingsManagerCore(QObject * a_pParent) :\n\tQObject(a_pParent)\n{\n\tQString applicationDir = QCoreApplication::applicationDirPath();\n\n\tbool portableMode = getPortableMode();\n\tif(portableMode)\n\t\tm_settingsFilePath = applicationDir + SETTINGS_FILE_NAME;\n\telse\n\t{\n\t\tm_settingsFilePath = QStandardPaths::writableLocation(\n\t\t\tQStandardPaths::GenericConfigLocation) + SETTINGS_FILE_NAME;\n\t}\n}\n\nSettingsManagerCore::~SettingsManagerCore()\n{\n\n}\n\n//==============================================================================\n\nbool SettingsManagerCore::getPortableMode() const\n{\n\tQString applicationDir = QCoreApplication::applicationDirPath();\n\tQString settingsFilePath = applicationDir + SETTINGS_FILE_NAME;\n\tQFileInfo settingsFileInfo(settingsFilePath);\n\n\tbool portableMode = (settingsFileInfo.exists() &&\n\t\tsettingsFileInfo.isWritable());\n\treturn portableMode;\n}\n\nbool SettingsManagerCore::setPortableMode(bool a_portableMod)\n{\n\tQString applicationDir = QCoreApplication::applicationDirPath();\n\tQString settingsFilePath = applicationDir + SETTINGS_FILE_NAME;\n\tQFileInfo settingsFileInfo(settingsFilePath);\n\n\tbool portableExists = settingsFileInfo.exists();\n\tbool currentModePortable = portableExists && settingsFileInfo.isWritable();\n\n\tif(a_portableMod == currentModePortable)\n\t\treturn true;\n\n\t// In Windows, even if a dir is not writable, a file in it may still be\n\t// writable. Therefore, we should take a test by writing a file.\n\tbool portableWritable = false;\n\tif(a_portableMod && !portableExists)\n\t{\n\t\tQFile portableFile(applicationDir + SETTINGS_FILE_NAME);\n\t\tif((portableWritable = portableFile.open(QIODevice::WriteOnly)))\n\t\t\tportableFile.close();\n\t}\n\telse\n\t\tportableWritable = currentModePortable;\n\n\tif(a_portableMod && !portableWritable)\n\t\treturn false;\n\n\tQString genericConfigDir = QStandardPaths::writableLocation(\n\t\tQStandardPaths::GenericConfigLocation);\n\n\tQString newSettingsFilePath;\n\tif(a_portableMod)\n\t\tnewSettingsFilePath = applicationDir + SETTINGS_FILE_NAME;\n\telse\n\t\tnewSettingsFilePath = genericConfigDir + SETTINGS_FILE_NAME;\n\n\t// When copying portable settings to common folder - another settings\n\t// file may already exist there. Need to delete it first.\n\tif(QFile::exists(newSettingsFilePath))\n\t{\n\t\tbool settingsFileDeleted = QFile::remove(newSettingsFilePath);\n\t\tif(!settingsFileDeleted)\n\t\t\treturn false;\n\t}\n\n\tbool settingsFileCopied =\n\t\tQFile::copy(m_settingsFilePath, newSettingsFilePath);\n\tQString oldSettingsFilePath = m_settingsFilePath;\n\tm_settingsFilePath = newSettingsFilePath;\n\n\tif(a_portableMod)\n\t\treturn settingsFileCopied;\n\telse if(settingsFileCopied)\n\t{\n\t\tbool portableSettingsFileDeleted = QFile::remove(oldSettingsFilePath);\n\t\treturn portableSettingsFileDeleted;\n\t}\n\n\treturn false;\n}\n\nbool SettingsManagerCore::getPreferVSLibrariesFromList() const\n{\n\treturn value(PREFER_VS_LIBRARIES_FROM_LIST_KEY,\n\t\tDEFAULT_PREFER_VS_LIBRARIES_FROM_LIST).toBool();\n}\n\nbool SettingsManagerCore::setPreferVSLibrariesFromList(bool a_prior)\n{\n\treturn setValue(PREFER_VS_LIBRARIES_FROM_LIST_KEY, a_prior);\n}\n\n\n//==============================================================================\n\nQVariant SettingsManagerCore::valueInGroup(const QString & a_group,\n\tconst QString & a_key, const QVariant & a_defaultValue) const\n{\n\tQSettings settings(m_settingsFilePath, QSettings::IniFormat);\n\tsettings.beginGroup(a_group);\n\treturn settings.value(a_key, a_defaultValue);\n}\n\nbool SettingsManagerCore::setValueInGroup(const QString & a_group,\n\tconst QString & a_key, const QVariant & a_value)\n{\n\tQSettings settings(m_settingsFilePath, QSettings::IniFormat);\n\tsettings.beginGroup(a_group);\n\tsettings.setValue(a_key, a_value);\n\tsettings.sync();\n\tbool success = (QSettings::NoError == settings.status());\n\treturn success;\n}\n\nbool SettingsManagerCore::deleteValueInGroup(const QString & a_group,\n\tconst QString & a_key)\n{\n\tQSettings settings(m_settingsFilePath, QSettings::IniFormat);\n\tsettings.beginGroup(a_group);\n\tsettings.remove(a_key);\n\tsettings.sync();\n\tbool success = (QSettings::NoError == settings.status());\n\treturn success;\n}\n\n//==============================================================================\n\nQVariant SettingsManagerCore::value(const QString & a_key,\n\tconst QVariant & a_defaultValue) const\n{\n\treturn valueInGroup(COMMON_GROUP, a_key, a_defaultValue);\n}\n\nbool SettingsManagerCore::setValue(const QString & a_key,\n\tconst QVariant & a_value)\n{\n\treturn setValueInGroup(COMMON_GROUP, a_key, a_value);\n}\n\n//==============================================================================\n\nQStringList SettingsManagerCore::getVapourSynthLibraryPaths() const\n{\n\tQStringList paths = value(VAPOURSYNTH_LIBRARY_PATHS_KEY).toStringList();\n\tpaths.removeDuplicates();\n\treturn paths;\n}\n\nbool SettingsManagerCore::setVapourSynthLibraryPaths(\n\tconst QStringList & a_pathsList)\n{\n\treturn setValue(VAPOURSYNTH_LIBRARY_PATHS_KEY, a_pathsList);\n}\n\n//==============================================================================\n\nResamplingFilter SettingsManagerCore::getChromaResamplingFilter() const\n{\n\treturn (ResamplingFilter)value(CHROMA_RESAMPLING_FILTER_KEY,\n\t\t(int)DEFAULT_CHROMA_RESAMPLING_FILTER).toInt();\n}\n\nbool SettingsManagerCore::setChromaResamplingFilter(ResamplingFilter a_filter)\n{\n\treturn setValue(CHROMA_RESAMPLING_FILTER_KEY, (int)a_filter);\n}\n\n//==============================================================================\n\nYuvMatrixCoefficients SettingsManagerCore::getYuvMatrixCoefficients() const\n{\n\treturn (YuvMatrixCoefficients)value(YUV_MATRIX_COEFFICIENTS_KEY,\n\t\t(int)DEFAULT_YUV_MATRIX_COEFFICIENTS).toInt();\n}\n\nbool SettingsManagerCore::setYuvMatrixCoefficients(\n\tYuvMatrixCoefficients a_matrix)\n{\n\treturn setValue(YUV_MATRIX_COEFFICIENTS_KEY, (int)a_matrix);\n}\n\n//==============================================================================\n\nChromaPlacement SettingsManagerCore::getChromaPlacement() const\n{\n\treturn (ChromaPlacement)value(CHROMA_PLACEMENT_KEY,\n\t\t(int)DEFAULT_CHROMA_PLACEMENT).toInt();\n}\n\nbool SettingsManagerCore::setChromaPlacement(ChromaPlacement a_placement)\n{\n\treturn setValue(CHROMA_PLACEMENT_KEY, (int)a_placement);\n}\n\n//==============================================================================\n\ndouble SettingsManagerCore::getBicubicFilterParameterB() const\n{\n\treturn value(BICUBIC_FILTER_PARAMETER_B_KEY,\n\t\tDEFAULT_BICUBIC_FILTER_PARAMETER_B).toDouble();\n}\n\nbool SettingsManagerCore::setBicubicFilterParameterB(double a_parameterB)\n{\n\treturn setValue(BICUBIC_FILTER_PARAMETER_B_KEY, a_parameterB);\n}\n\n//==============================================================================\n\ndouble SettingsManagerCore::getBicubicFilterParameterC() const\n{\n\treturn value(BICUBIC_FILTER_PARAMETER_C_KEY,\n\t\tDEFAULT_BICUBIC_FILTER_PARAMETER_C).toDouble();\n}\n\nbool SettingsManagerCore::setBicubicFilterParameterC(double a_parameterC)\n{\n\treturn setValue(BICUBIC_FILTER_PARAMETER_C_KEY, a_parameterC);\n}\n\n//==============================================================================\n\nint SettingsManagerCore::getLanczosFilterTaps() const\n{\n\treturn value(LANCZOS_FILTER_TAPS_KEY, DEFAULT_LANCZOS_FILTER_TAPS).toInt();\n}\n\nbool SettingsManagerCore::setLanczosFilterTaps(int a_taps)\n{\n\treturn setValue(LANCZOS_FILTER_TAPS_KEY, a_taps);\n}\n\nDitherType SettingsManagerCore::getDitherType() const\n{\n    return (DitherType)value(DITHER_TYPE_KEY,\n\t\t(int)DEFAULT_DITHER_TYPE).toInt();\n}\n\nbool SettingsManagerCore::setDitherType(DitherType a_dither)\n{\n    return setValue(DITHER_TYPE_KEY, (int)a_dither);\n}\n\n//==============================================================================\n\nstd::vector<EncodingPreset> SettingsManagerCore::getAllEncodingPresets() const\n{\n\tQSettings settings(m_settingsFilePath, QSettings::IniFormat);\n\tsettings.beginGroup(ENCODING_PRESETS_GROUP);\n\n\tstd::vector<EncodingPreset> presets;\n\n\tQStringList presetNames = settings.childGroups();\n\tfor(const QString & presetName : presetNames)\n\t{\n\t\tsettings.beginGroup(presetName);\n\n\t\tEncodingPreset preset;\n\t\tpreset.name = presetName;\n\t\tpreset.type = (EncodingType)settings.value(\n\t\t\tENCODING_PRESET_ENCODING_TYPE_KEY, (int)DEFAULT_ENCODING_TYPE)\n\t\t\t.toInt();\n\t\tpreset.headerType = (EncodingHeaderType)settings.value(\n\t\t\tENCODING_PRESET_HEADER_TYPE_KEY, (int)DEFAULT_ENCODING_HEADER_TYPE)\n\t\t\t.toInt();\n\t\tpreset.executablePath = settings.value(\n\t\t\tENCODING_PRESET_EXECUTABLE_PATH_KEY).toString();\n\t\tpreset.arguments = settings.value(\n\t\t\tENCODING_PRESET_ARGUMENTS_KEY).toString();\n\t\tpresets.push_back(preset);\n\n\t\tsettings.endGroup();\n\t}\n\n\treturn presets;\n}\n\nEncodingPreset SettingsManagerCore::getEncodingPreset(const QString & a_name) const\n{\n\tQSettings settings(m_settingsFilePath, QSettings::IniFormat);\n\tsettings.beginGroup(ENCODING_PRESETS_GROUP);\n\n\tEncodingPreset preset;\n\n\tQStringList presetNames = settings.childGroups();\n\tif(!presetNames.contains(a_name))\n\t\treturn preset;\n\n\tpreset.name = a_name;\n\tsettings.beginGroup(a_name);\n\n\tpreset.type = (EncodingType)settings.value(\n\t\tENCODING_PRESET_ENCODING_TYPE_KEY, (int)DEFAULT_ENCODING_TYPE)\n\t\t.toInt();\n\tpreset.headerType = (EncodingHeaderType)settings.value(\n\t\tENCODING_PRESET_HEADER_TYPE_KEY, (int)DEFAULT_ENCODING_HEADER_TYPE)\n\t\t.toInt();\n\tpreset.executablePath = settings.value(\n\t\tENCODING_PRESET_EXECUTABLE_PATH_KEY).toString();\n\tpreset.arguments = settings.value(\n\t\tENCODING_PRESET_ARGUMENTS_KEY).toString();\n\n\treturn preset;\n}\n\nbool SettingsManagerCore::saveEncodingPreset(const EncodingPreset & a_preset)\n{\n\tQSettings settings(m_settingsFilePath, QSettings::IniFormat);\n\tsettings.beginGroup(ENCODING_PRESETS_GROUP);\n\tsettings.beginGroup(a_preset.name);\n\n\tsettings.setValue(ENCODING_PRESET_ENCODING_TYPE_KEY, (int)a_preset.type);\n\tsettings.setValue(ENCODING_PRESET_HEADER_TYPE_KEY,\n\t\t(int)a_preset.headerType);\n\tsettings.setValue(ENCODING_PRESET_EXECUTABLE_PATH_KEY,\n\t\ta_preset.executablePath);\n\tsettings.setValue(ENCODING_PRESET_ARGUMENTS_KEY, a_preset.arguments);\n\n\tsettings.sync();\n\tbool success = (QSettings::NoError == settings.status());\n\treturn success;\n}\n\nbool SettingsManagerCore::deleteEncodingPreset(const QString & a_name)\n{\n\tQSettings settings(m_settingsFilePath, QSettings::IniFormat);\n\tsettings.beginGroup(ENCODING_PRESETS_GROUP);\n\n\tQStringList subGroups = settings.childGroups();\n\tif(!subGroups.contains(a_name))\n\t\treturn false;\n\tsettings.remove(a_name);\n\n\tsettings.sync();\n\tbool success = (QSettings::NoError == settings.status());\n\treturn success;\n}\n\n//==============================================================================\n\nstd::vector<JobProperties> SettingsManagerCore::getJobs() const\n{\n\tQSettings settings(m_settingsFilePath, QSettings::IniFormat);\n\tsettings.beginGroup(JOBS_GROUP);\n\n\tstd::vector<JobProperties> jobs;\n\n\tQStringList numbers = settings.childGroups();\n\tfor(const QString & number : numbers)\n\t{\n\t\tsettings.beginGroup(number);\n\n\t\tJobProperties job;\n\n\t\tQString idString = settings.value(JOB_ID_KEY).toString();\n\t\tif(idString.isEmpty())\n\t\t\tjob.id = QUuid::createUuid();\n\t\telse\n\t\t\tjob.id = QUuid(idString);\n\n\t\tjob.type = (JobType)settings.value(JOB_TYPE_KEY,\n\t\t\t(int)DEFAULT_JOB_TYPE).toInt();\n\t\tjob.jobState = (JobState)settings.value(JOB_STATE_KEY,\n\t\t\t(int)DEFAULT_JOB_STATE).toInt();\n\n\t\tQStringList dependencyIdStrings =\n\t\t\tsettings.value(JOB_DEPENDS_ON_JOBS_KEY).toStringList();\n\t\tfor(const QString & dependencyIdString : dependencyIdStrings)\n\t\t{\n\t\t\tQUuid dependencyId(dependencyIdString);\n\t\t\tjob.dependsOnJobIds.push_back(dependencyId);\n\t\t}\n\n\t\tjob.timeStarted = settings.value(JOB_TIME_STARTED_KEY).toDateTime();\n\t\tjob.timeEnded = settings.value(JOB_TIME_ENDED_KEY).toDateTime();\n\t\tjob.scriptName = settings.value(JOB_SCRIPT_NAME_KEY).toString();\n\t\tjob.scriptText = settings.value(JOB_SCRIPT_TEXT_KEY).toString();\n\n\t\tjob.encodingType = (EncodingType)settings.value(JOB_ENCODING_TYPE_KEY,\n\t\t\t(int)DEFAULT_ENCODING_TYPE).toInt();\n\t\tjob.encodingHeaderType = (EncodingHeaderType)settings.value(\n\t\t\tJOB_ENCODING_HEADER_TYPE_KEY,\n\t\t\t(int)DEFAULT_ENCODING_HEADER_TYPE).toInt();\n\n\t\tjob.executablePath = settings.value(JOB_EXECUTABLE_PATH_KEY).toString();\n\t\tjob.arguments = settings.value(JOB_ARGUMENTS_KEY).toString();\n\t\tjob.shellCommand = settings.value(JOB_SHELL_COMMAND_KEY).toString();\n\n\t\tjob.firstFrame = settings.value(JOB_FIRST_FRAME_KEY,\n\t\t\tDEFAULT_JOB_FIRST_FRAME).toInt();\n\t\tjob.firstFrameReal = settings.value(JOB_FIRST_FRAME_REAL_KEY,\n\t\t\tjob.firstFrame).toInt();\n\t\tjob.lastFrame = settings.value(JOB_LAST_FRAME_KEY,\n\t\t\tDEFAULT_JOB_LAST_FRAME).toInt();\n\t\tjob.lastFrameReal = settings.value(JOB_LAST_FRAME_REAL_KEY,\n\t\t\tjob.lastFrame).toInt();\n\t\tjob.framesProcessed = settings.value(JOB_FRAME_PROCESSED_KEY,\n\t\t\tDEFAULT_JOB_FRAMES_PROCESSED).toInt();\n\t\tjob.fps = settings.value(JOB_FPS_KEY, DEFAULT_JOB_FPS).toDouble();\n\n\t\tjobs.push_back(job);\n\n\t\tsettings.endGroup();\n\t}\n\n\treturn jobs;\n}\n\nbool SettingsManagerCore::setJobs(const std::vector<JobProperties> & a_jobs)\n{\n\tQSettings settings(m_settingsFilePath, QSettings::IniFormat);\n\tsettings.remove(JOBS_GROUP);\n\tsettings.beginGroup(JOBS_GROUP);\n\n\tfor(size_t i = 0; i < a_jobs.size(); ++i)\n\t{\n\t\tconst JobProperties & job = a_jobs[i];\n\n\t\tsettings.beginGroup(QString(\"%1\").arg(i, 7, 10, QChar('0')));\n\n\t\tsettings.setValue(JOB_ID_KEY, job.id.toString());\n\t\tsettings.setValue(JOB_TYPE_KEY, (int)job.type);\n\t\tsettings.setValue(JOB_STATE_KEY, (int)job.jobState);\n\n\t\tQStringList dependencyIdStrings;\n\t\tfor(const QUuid & id : job.dependsOnJobIds)\n\t\t\tdependencyIdStrings << id.toString();\n\t\tsettings.setValue(JOB_DEPENDS_ON_JOBS_KEY, dependencyIdStrings);\n\n\t\tsettings.setValue(JOB_TIME_STARTED_KEY, job.timeStarted);\n\t\tsettings.setValue(JOB_TIME_ENDED_KEY, job.timeEnded);\n\t\tsettings.setValue(JOB_SCRIPT_NAME_KEY, job.scriptName);\n\t\tsettings.setValue(JOB_SCRIPT_TEXT_KEY, job.scriptText);\n\t\tsettings.setValue(JOB_ENCODING_TYPE_KEY, (int)job.encodingType);\n\t\tsettings.setValue(JOB_ENCODING_HEADER_TYPE_KEY,\n\t\t\t(int)job.encodingHeaderType);\n\t\tsettings.setValue(JOB_EXECUTABLE_PATH_KEY, job.executablePath);\n\t\tsettings.setValue(JOB_ARGUMENTS_KEY, job.arguments);\n\t\tsettings.setValue(JOB_SHELL_COMMAND_KEY, job.shellCommand);\n\t\tsettings.setValue(JOB_FIRST_FRAME_KEY, job.firstFrame);\n\t\tsettings.setValue(JOB_FIRST_FRAME_REAL_KEY, job.firstFrameReal);\n\t\tsettings.setValue(JOB_LAST_FRAME_KEY, job.lastFrame);\n\t\tsettings.setValue(JOB_LAST_FRAME_REAL_KEY, job.lastFrameReal);\n\t\tsettings.setValue(JOB_FRAME_PROCESSED_KEY, job.framesProcessed);\n\t\tsettings.setValue(JOB_FPS_KEY, job.fps);\n\n\t\tsettings.endGroup();\n\t}\n\n\tsettings.sync();\n\tbool success = (QSettings::NoError == settings.status());\n\treturn success;\n}\n\n//==============================================================================\n\nQStringList SettingsManagerCore::getRecentJobServers() const\n{\n\tQStringList recentServers = value(RECENT_JOB_SERVERS_KEY).toStringList();\n\trecentServers.removeDuplicates();\n\treturn recentServers.mid(0, DEFAULT_RECENT_JOB_SERVERS_NUMBER);\n}\n\nbool SettingsManagerCore::setRecentJobServers(const QStringList & a_servers)\n{\n\tQStringList recentServers = a_servers;\n\trecentServers.removeDuplicates();\n\trecentServers = recentServers.mid(0, DEFAULT_RECENT_JOB_SERVERS_NUMBER);\n\treturn setValue(RECENT_JOB_SERVERS_KEY, recentServers);\n}\n\n//==============================================================================\n\nQStringList SettingsManagerCore::getTrustedClientsAddresses() const\n{\n\tQStringList addresses = value(TRUSTED_CLIENTS_ADDRESSES_KEY).toStringList();\n\taddresses.removeDuplicates();\n\treturn addresses;\n}\n\nbool SettingsManagerCore::setTrustedClientsAddresses(\n\tconst QStringList & a_addresses)\n{\n\tQStringList addresses = a_addresses;\n\taddresses.removeDuplicates();\n\treturn setValue(TRUSTED_CLIENTS_ADDRESSES_KEY, addresses);\n}\n\n//==============================================================================\n"
  },
  {
    "path": "common-src/settings/settings_manager_core.h",
    "content": "#ifndef SETTINGS_MANAGER_CORE_H_INCLUDED\n#define SETTINGS_MANAGER_CORE_H_INCLUDED\n\n#include \"settings_definitions_core.h\"\n\n#include <QObject>\n#include <QVariant>\n#include <vector>\n\n/// Base class that manages non-GUI related settings\nclass SettingsManagerCore : public QObject\n{\npublic:\n\n\tSettingsManagerCore(QObject * a_pParent);\n\tvirtual ~SettingsManagerCore();\n\n\t//----------------------------------------------------------------------\n\n\tbool getPortableMode() const;\n\n\tbool setPortableMode(bool a_portableMod);\n\n\t//----------------------------------------------------------------------\n\n\tQStringList getVapourSynthLibraryPaths() const;\n\n\tbool setVapourSynthLibraryPaths(const QStringList & a_pathsList);\n\n\tbool getPreferVSLibrariesFromList() const;\n\n\tbool setPreferVSLibrariesFromList(bool a_prior);\n\n\tResamplingFilter getChromaResamplingFilter() const;\n\n\tbool setChromaResamplingFilter(ResamplingFilter a_filter);\n\n\tYuvMatrixCoefficients getYuvMatrixCoefficients() const;\n\n\tbool setYuvMatrixCoefficients(YuvMatrixCoefficients a_matrix);\n\n\tChromaPlacement getChromaPlacement() const;\n\n\tbool setChromaPlacement(ChromaPlacement a_placement);\n\n\tdouble getBicubicFilterParameterB() const;\n\n\tbool setBicubicFilterParameterB(double a_parameterB);\n\n\tdouble getBicubicFilterParameterC() const;\n\n\tbool setBicubicFilterParameterC(double a_parameterC);\n\n\tint getLanczosFilterTaps() const;\n\n\tbool setLanczosFilterTaps(int a_taps);\n\n\tDitherType getDitherType() const;\n\n\tbool setDitherType(DitherType a_dither);\n\n\tstd::vector<EncodingPreset> getAllEncodingPresets() const;\n\n\tEncodingPreset getEncodingPreset(const QString & a_name) const;\n\n\tbool saveEncodingPreset(const EncodingPreset & a_preset);\n\n\tbool deleteEncodingPreset(const QString & a_name);\n\n\tstd::vector<JobProperties> getJobs() const;\n\n\tbool setJobs(const std::vector<JobProperties> & a_jobs);\n\n\tQStringList getRecentJobServers() const;\n\n\tbool setRecentJobServers(const QStringList & a_servers);\n\n\tQStringList getTrustedClientsAddresses() const;\n\n\tbool setTrustedClientsAddresses(const QStringList & a_addresses);\n\nprotected:\n\n\tQVariant valueInGroup(const QString & a_group, const QString & a_key,\n\t\tconst QVariant & a_defaultValue = QVariant()) const;\n\n\tbool setValueInGroup(const QString & a_group, const QString & a_key,\n\t\tconst QVariant & a_value);\n\n\tbool deleteValueInGroup(const QString & a_group, const QString & a_key);\n\n\tQVariant value(const QString & a_key, const QVariant & a_defaultValue =\n\t\tQVariant()) const;\n\n\tbool setValue(const QString & a_key, const QVariant & a_value);\n\n\tQString m_settingsFilePath;\n};\n\n#endif // SETTINGS_MANAGER_CORE_H_INCLUDED\n"
  },
  {
    "path": "common-src/timeline_slider/timeline_slider.cpp",
    "content": "#include \"timeline_slider.h\"\n\n#include \"../helpers.h\"\n\n#include <QKeyEvent>\n#include <QMouseEvent>\n#include <QPaintEvent>\n#include <QWheelEvent>\n#include <QPoint>\n#include <QPainter>\n#include <QMargins>\n#include <QToolTip>\n#include <QFontMetricsF>\n#include <climits>\n#include <cmath>\n#include <cstdlib>\n#include <map>\n\n//==============================================================================\n\nTimeLineSlider::TimeLineSlider(QWidget * a_pParent) : QWidget(a_pParent)\n\t, m_maxFrame(999)\n\t, m_fps(0.0)\n\t, m_currentFrame(0)\n\t, m_pointerAtFrame(0)\n\t, m_displayMode(Time)\n\t, m_bigStep(10)\n\t, m_sideMargin(6)\n\t, m_bottomMargin(2)\n\t, m_slideLineHeight(12)\n\t, m_slideLineFrameWidth(1)\n\t, m_slideLineTicksSpacing(1)\n\t, m_shortTickHeight(2)\n\t, m_mediumTickHeight(3)\n\t, m_longTickHeight(4)\n\t, m_tickTextSpacing(1)\n\t, m_textHeight(6)\n\t, m_topMargin(2)\n\t, m_minimumTicksSpacing(4)\n\t, m_sliderPressed(false)\n\t, m_labelsFont(\"Digital Mini\")\n{\n\tQ_ASSERT(m_bigStep > 0);\n\n\tsetAutoFillBackground(true);\n\tsetFocusPolicy(Qt::StrongFocus);\n\tsetMouseTracking(true);\n\n\tQFontMetricsF metrics(m_labelsFont);\n\tqreal factor = (qreal)m_textHeight /\n\t\tmetrics.tightBoundingRect(\"9\").height();\n\tm_labelsFont.setPointSizeF(m_labelsFont.pointSizeF() * factor);\n\n\tm_slideLineColor = palette().color(QPalette::Base);\n\tm_activeFrameColor = palette().color(QPalette::Highlight);\n\tm_inactiveFrameColor = palette().color(QPalette::Dark);\n\tm_currentFramePointerColor = palette().color(QPalette::Dark);\n\tm_slidingPointerColor = palette().color(QPalette::Text);\n\tm_bookmarkColor = Qt::magenta;\n\n\tm_colorRoleMap = {\n\t\t{SlideLine, &m_slideLineColor},\n\t\t{ActiveFrame, &m_activeFrameColor},\n\t\t{InactiveFrame, &m_inactiveFrameColor},\n\t\t{CurrentFramePointer, &m_currentFramePointerColor},\n\t\t{SlidingPointer, &m_slidingPointerColor},\n\t\t{Bookmark, &m_bookmarkColor},\n\t};\n\n\tsetSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Minimum);\n\n\trecalculateMinimumSize();\n}\n\n// END OF TimeLineSlider::TimeLineSlider(QWidget * a_pParent)\n//==============================================================================\n\nTimeLineSlider::~TimeLineSlider()\n{\n\n}\n\n// END OF TimeLineSlider::~TimeLineSlider()\n//==============================================================================\n\nint TimeLineSlider::frame() const\n{\n\treturn m_currentFrame;\n}\n\n// END OF int TimeLineSlider::frame() const\n//==============================================================================\n\nvoid TimeLineSlider::setFrame(int a_frame, bool a_refreshCache)\n{\n\tint oldCurrentFrame = m_currentFrame;\n\tif(a_frame > m_maxFrame)\n\t\tm_currentFrame = m_maxFrame;\n\telse\n\t\tm_currentFrame = a_frame;\n\n\tif(m_currentFrame != m_pointerAtFrame)\n\t\tm_pointerAtFrame = m_currentFrame;\n\n\tif(m_currentFrame == oldCurrentFrame)\n\t\treturn;\n\n\trepaint();\n\temit signalFrameChanged(m_currentFrame, a_refreshCache);\n}\n\n// END OF void TimeLineSlider::setFrame(int a_frame, bool a_refreshCache)\n//==============================================================================\n\nvoid TimeLineSlider::setFramesNumber(int a_framesNumber, bool a_refreshCache)\n{\n\tm_maxFrame = a_framesNumber - 1;\n\tif(m_currentFrame > m_maxFrame)\n\t\tsetFrame(m_maxFrame, a_refreshCache);\n\trepaint();\n}\n\n// END OF void TimeLineSlider::setFramesNumber(int a_framesNumber,\n//\t\tbool a_refreshCache)\n//==============================================================================\n\nvoid TimeLineSlider::setFPS(double a_fps)\n{\n\tm_fps = a_fps;\n\trepaint();\n}\n\n// END OF void TimeLineSlider::setFPS(double a_fps)\n//==============================================================================\n\nTimeLineSlider::DisplayMode TimeLineSlider::displayMode() const\n{\n\treturn m_displayMode;\n}\n\n// END OF TimeLineSlider::DisplayMode TimeLineSlider::displayMode() const\n//==============================================================================\n\nvoid TimeLineSlider::setDisplayMode(DisplayMode a_displayMode)\n{\n\tm_displayMode = a_displayMode;\n\trepaint();\n}\n\n// END OF void TimeLineSlider::setDisplayMode(DisplayMode a_displayMode)\n//==============================================================================\n\n\nvoid TimeLineSlider::setBigStep(int a_bigStep)\n{\n\tm_bigStep = std::max(std::abs(a_bigStep), 1);\n}\n\n\n// END OF void TimeLineSlider::setBigStep(int a_bigStep)\n//==============================================================================\n\nvoid TimeLineSlider::setLabelsFont(const QFont & a_font)\n{\n\tm_labelsFont = a_font;\n\tQFontMetrics metrics(m_labelsFont);\n\tm_textHeight = metrics.tightBoundingRect(\"9\").height();\n\trecalculateMinimumSize();\n\tupdate();\n}\n\n// END OF void TimeLineSlider::setLabelsFont(const QFont & a_font)\n//==============================================================================\n\nvoid TimeLineSlider::setColor(ColorRole a_role, const QColor & a_color)\n{\n\tstd::map<ColorRole, QColor *>::iterator it = m_colorRoleMap.find(a_role);\n\tif(it == m_colorRoleMap.end())\n\t\treturn;\n\n\t*(it->second) = a_color;\n\tupdate();\n}\n\n// END OF void TimeLineSlider::setColor(ColorRole a_role,\n//\t\tconst QColor & a_color)\n//==============================================================================\n\nvoid TimeLineSlider::addBookmark(int a_bookmark)\n{\n\tif(a_bookmark < 0)\n\t\treturn;\n\n\tm_bookmarks.insert(a_bookmark);\n\tupdate();\n}\n\n// END OF void TimeLineSlider::addBookmark(int a_bookmark)\n//==============================================================================\n\nvoid TimeLineSlider::removeBookmark(int a_bookmark)\n{\n\tm_bookmarks.erase(a_bookmark);\n\tupdate();\n}\n\n// END OF void TimeLineSlider::removeBookmark(int a_bookmark)\n//==============================================================================\n\nstd::set<int> TimeLineSlider::bookmarks() const\n{\n\treturn m_bookmarks;\n}\n\n// END OF std::set<int> TimeLineSlider::bookmarks() const\n//==============================================================================\n\nvoid TimeLineSlider::setBookmarks(const std::set<int> & a_bookmarks)\n{\n\tstd::set<int>::iterator it = a_bookmarks.lower_bound(0);\n\tm_bookmarks = std::set<int>(it, a_bookmarks.end());\n\tupdate();\n}\n\n// END OF void TimeLineSlider::setBookmarks(const std::set<int> & a_bookmarks)\n//==============================================================================\n\nvoid TimeLineSlider::clearBookmarks()\n{\n\tm_bookmarks.clear();\n\tupdate();\n}\n\n// END OF void TimeLineSlider::clearBookmarks()\n//==============================================================================\n\nint TimeLineSlider::getClosestBookmark(int a_frame) const\n{\n\tif(m_bookmarks.size() == 0)\n\t\treturn a_frame;\n\n\tif(m_bookmarks.size() == 1)\n\t\treturn *m_bookmarks.begin();\n\n\tstd::set<int>::iterator next = m_bookmarks.upper_bound(a_frame);\n\n\tif(next == m_bookmarks.begin())\n\t\treturn *next;\n\n\tif(next == m_bookmarks.end())\n\t\treturn *m_bookmarks.rbegin();\n\n\tif(*next > m_maxFrame)\n\t{\n\t\tnext = m_bookmarks.upper_bound(m_maxFrame);\n\t\tnext--;\n\t\treturn *next;\n\t}\n\n\tstd::set<int>::iterator prev = next;\n\tprev--;\n\n\tint backDiff = a_frame - *prev;\n\tint forwardDiff = *next - a_frame;\n\n\tif(forwardDiff < backDiff)\n\t\treturn *next;\n\n\treturn *prev;\n}\n\n// END OF int TimeLineSlider::getClosestBookmark(int a_frame) const\n//==============================================================================\n\nvoid TimeLineSlider::slotStepUp()\n{\n\tif(m_currentFrame < m_maxFrame)\n\t\tsetFrame(m_currentFrame + 1, false);\n}\n\n// END OF void TimeLineSlider::slotStepUp()\n//==============================================================================\n\nvoid TimeLineSlider::slotStepDown()\n{\n\tif(m_currentFrame > 0)\n\t\tsetFrame(m_currentFrame - 1, false);\n}\n\n// END OF void TimeLineSlider::slotStepDown()\n//==============================================================================\n\nvoid TimeLineSlider::slotBigStepUp()\n{\n\tslotStepBy(m_bigStep);\n}\n\n// END OF void TimeLineSlider::slotBigStepUp()\n//==============================================================================\n\nvoid TimeLineSlider::slotBigStepDown()\n{\n\tslotStepBy(-m_bigStep);\n}\n\n// END OF void TimeLineSlider::slotBigStepDown()\n//==============================================================================\n\nvoid TimeLineSlider::slotStepBy(int a_step)\n{\n\tif(a_step < 0)\n\t{\n\t\tif(-a_step <= m_currentFrame)\n\t\t\tsetFrame(m_currentFrame + a_step, false);\n\t\telse\n\t\t\tsetFrame(0, false);\n\t}\n\telse\n\t{\n\t\tif(a_step <= (m_maxFrame - m_currentFrame))\n\t\t\tsetFrame(m_currentFrame + a_step, false);\n\t\telse\n\t\t\tsetFrame(m_maxFrame, false);\n\t}\n}\n\n// END OF void TimeLineSlider::slotStepBy(int a_step)\n//==============================================================================\n\nvoid TimeLineSlider::slotStepBySeconds(double a_seconds)\n{\n\tif(m_fps == 0.0)\n\t\treturn;\n\n    int framesStep = std::round(a_seconds * m_fps);\n    slotStepBy(framesStep);\n}\n\n// END OF void TimeLineSlider::slotStepBySeconds(double a_seconds)\n//==============================================================================\n\nvoid TimeLineSlider::slotBookmarkCurrentFrame()\n{\n\taddBookmark(m_currentFrame);\n}\n\n// END OF void TimeLineSlider::slotBookmarkCurrentFrame()\n//==============================================================================\n\nvoid TimeLineSlider::slotUnbookmarkCurrentFrame()\n{\n\tremoveBookmark(m_currentFrame);\n}\n\n// END OF void TimeLineSlider::slotUnbookmarkCurrentFrame()\n//==============================================================================\n\nvoid TimeLineSlider::slotGoToPreviousBookmark()\n{\n\tif(m_bookmarks.size() == 0)\n\t\treturn;\n\n\tif(m_currentFrame == 0)\n\t\treturn;\n\n\tstd::set<int>::iterator it = m_bookmarks.upper_bound(m_currentFrame - 1);\n\n\tif(it == m_bookmarks.end())\n\t{\n\t\tsetFrame(*m_bookmarks.rbegin(), false);\n\t\treturn;\n\t}\n\n\tif(it == m_bookmarks.begin())\n\t\treturn;\n\n\tit--;\n\n\tif(*it < 0)\n\t\treturn;\n\n\tsetFrame(*it, false);\n}\n\n// END OF void TimeLineSlider::slotGoToPreviousBookmark()\n//==============================================================================\n\nvoid TimeLineSlider::slotGoToNextBookmark()\n{\n\tif(m_bookmarks.size() == 0)\n\t\treturn;\n\n\tstd::set<int>::iterator it = m_bookmarks.upper_bound(m_currentFrame);\n\n\tif(it == m_bookmarks.end())\n\t\treturn;\n\n\tif(*it > m_maxFrame)\n\t\treturn;\n\n\tsetFrame(*it, false);\n}\n\n// END OF void TimeLineSlider::slotGoToNextBookmark()\n//==============================================================================\n\nvoid TimeLineSlider::keyPressEvent(QKeyEvent * a_pEvent)\n{\n\tif(a_pEvent->modifiers() != Qt::NoModifier)\n\t{\n\t\tQWidget::keyPressEvent(a_pEvent);\n\t\treturn;\n\t}\n\n\tint key = a_pEvent->key();\n\tif((key == Qt::Key_Left) || (key == Qt::Key_Down))\n\t{\n\t\tslotStepDown();\n\t\ta_pEvent->accept();\n\t\treturn;\n\t}\n\telse if((key == Qt::Key_Right) || (key == Qt::Key_Up))\n\t{\n\t\tslotStepUp();\n\t\ta_pEvent->accept();\n\t\treturn;\n\t}\n\telse if(key == Qt::Key_PageUp)\n\t{\n\t\tslotBigStepUp();\n\t\ta_pEvent->accept();\n\t\treturn;\n\t}\n\telse if(key == Qt::Key_PageDown)\n\t{\n\t\tslotBigStepDown();\n\t\ta_pEvent->accept();\n\t\treturn;\n\t}\n\telse if(key == Qt::Key_Home)\n\t{\n\t\tsetFrame(0, true);\n\t\ta_pEvent->accept();\n\t\treturn;\n\t}\n\telse if(key == Qt::Key_End)\n\t{\n\t\tsetFrame(m_maxFrame, true);\n\t\ta_pEvent->accept();\n\t\treturn;\n\t}\n\n\tQWidget::keyPressEvent(a_pEvent);\n}\n\n// END OF void TimeLineSlider::keyPressEvent(QKeyEvent * a_pEvent)\n//==============================================================================\n\nvoid TimeLineSlider::mouseMoveEvent(QMouseEvent * a_pEvent)\n{\n\tif(m_sliderPressed)\n\t{\n\t\tsetPointerAtFrame(a_pEvent);\n\t\trepaint();\n\t\temit signalSliderMoved(m_pointerAtFrame);\n\t}\n\n\t// Display tooltip\n\tif(m_sliderPressed || slideLineActiveRect().contains(a_pEvent->pos()))\n\t{\n\t\tint l_frame = m_sliderPressed ?\n\t\t\tm_pointerAtFrame : posToFrame(a_pEvent->pos().x());\n\t\tQString tipString = QString::number(l_frame);\n\t\tif(m_fps != 0.0)\n\t\t{\n\t\t\ttipString += \" - \";\n\t\t\ttipString += vsedit::timeToString(((double)l_frame) / m_fps);\n\t\t}\n\t\tQToolTip::showText(a_pEvent->globalPosition().toPoint(), tipString);\n\t}\n\n\tQWidget::mouseMoveEvent(a_pEvent);\n}\n\n// END OF void TimeLineSlider::mouseMoveEvent(QMouseEvent * a_pEvent)\n//==============================================================================\n\nvoid TimeLineSlider::mousePressEvent(QMouseEvent * a_pEvent)\n{\n\tif(slideLineActiveRect().contains(a_pEvent->pos()))\n\t{\n\t\tm_sliderPressed = true;\n\t\tsetPointerAtFrame(a_pEvent);\n\t\trepaint();\n\t\temit signalSliderPressed();\n\t}\n\n\tQWidget::mousePressEvent(a_pEvent);\n}\n\n// END OF void TimeLineSlider::mousePressEvent(QMouseEvent * a_pEvent)\n//==============================================================================\n\nvoid TimeLineSlider::mouseReleaseEvent(QMouseEvent * a_pEvent)\n{\n\tbool emitSignal = m_sliderPressed;\n\tm_sliderPressed = false;\n\tsetFrame(m_pointerAtFrame, true);\n\tif(emitSignal)\n\t\temit signalSliderReleased();\n\tQWidget::mouseReleaseEvent(a_pEvent);\n}\n\n// END OF void TimeLineSlider::mouseReleaseEvent(QMouseEvent * a_pEvent)\n//==============================================================================\n\nvoid TimeLineSlider::paintEvent(QPaintEvent * a_pEvent)\n{\n\tif(slideLineActiveRect().width() < 2)\n\t{\n\t\ta_pEvent->ignore();\n\t\treturn;\n\t}\n\n\tQPainter painter(this);\n\n\t// Slide line\n\tQRect l_slideLineRect = slideLineRect();\n\tpainter.setBrush(m_slideLineColor);\n\tQPen pen = painter.pen();\n\tQColor frameColor;\n\tif(hasFocus())\n\t\tframeColor = m_activeFrameColor;\n\telse\n\t\tframeColor = m_inactiveFrameColor;\n\tpen.setColor(frameColor);\n\tpen.setWidth(m_slideLineFrameWidth);\n\tpainter.setPen(pen);\n\tQMargins slideLineMargins(0, 0, m_slideLineFrameWidth,\n\t\tm_slideLineFrameWidth);\n\tpainter.drawRect(l_slideLineRect.marginsRemoved(slideLineMargins));\n\n\t// Bookmarks\n\tpen.setColor(m_bookmarkColor);\n\tpen.setWidth(1);\n\tpainter.setPen(pen);\n\tint pointerTop = l_slideLineRect.top() + m_slideLineFrameWidth;\n\tint pointerBottom = l_slideLineRect.bottom() - m_slideLineFrameWidth;\n\tfor(int i : m_bookmarks)\n\t{\n\t\tif(i > m_maxFrame)\n\t\t\tbreak;\n\t\tint pointerPos = frameToPos(i);\n\t\tpainter.drawLine(pointerPos, pointerTop, pointerPos, pointerBottom);\n\t}\n\n\t// Current frame pointer\n\tpainter.setPen(m_currentFramePointerColor);\n\tint pointerPos = frameToPos(m_currentFrame);\n\tpainter.drawLine(pointerPos, pointerTop, pointerPos, pointerBottom);\n\n\t// Sliding frame pointer\n\tpainter.setPen(m_slidingPointerColor);\n\tpointerPos = frameToPos(m_pointerAtFrame);\n\tpainter.drawLine(pointerPos, pointerTop, pointerPos, pointerBottom);\n\n\t// Ruler\n\tpainter.setPen(palette().color(QPalette::WindowText));\n\tDisplayMode l_displayMode = Time;\n\tif((m_displayMode == Frames) || (m_fps == 0.0))\n\t\tl_displayMode = Frames;\n\n\tdouble unitsInPixel = (double)m_maxFrame /\n\t\t(double)(slideLineInnerWidth() - 1);\n\tdouble maxUnits = (double)m_maxFrame;\n\n\tbool ticksAtExactFrames =\n\t\t(unitsInPixel < 1.0 / (double)m_minimumTicksSpacing);\n\n\tif(l_displayMode == Time)\n\t{\n\t\tunitsInPixel /= m_fps;\n\t\tmaxUnits /= m_fps;\n\t}\n\n\tpainter.setFont(m_labelsFont);\n\n\tint tickBottom = height() - m_bottomMargin - m_slideLineHeight -\n\t\tm_slideLineTicksSpacing - 1;\n\tint shortTickTop = tickBottom - m_shortTickHeight + 1;\n\tint mediumTickTop = tickBottom - m_mediumTickHeight + 1;\n\tint longTickTop = tickBottom - m_longTickHeight + 1;\n\tint startPos = m_sideMargin + m_slideLineFrameWidth;\n\n\tQPoint labelPos(0, longTickTop - m_tickTextSpacing);\n\tQFontMetricsF labelsFontMetrics(m_labelsFont);\n\n\tif(ticksAtExactFrames)\n\t{\n        for(int n = 0; n <= m_maxFrame; ++n)\n\t\t{\n\t\t\tint tickPos = frameToPos(n);\n\t\t\tif(n % 10 == 0)\n\t\t\t{\n\t\t\t\tpainter.drawLine(tickPos, longTickTop, tickPos, tickBottom);\n\n\t\t\t\tQString labelString;\n\t\t\t\tif(l_displayMode == Frames)\n\t\t\t\t\tlabelString = QString::number(n);\n\t\t\t\telse\n\t\t\t\t\tlabelString = vsedit::timeToString(((double)n) / m_fps);\n\t\t\t\tlabelPos.setX(tickPos - labelsFontMetrics.horizontalAdvance(\n\t\t\t\t\tlabelString) / 2 + 1);\n\t\t\t\tpainter.drawText(labelPos, labelString);\n\t\t\t}\n\t\t\telse if(n % 5 == 0)\n\t\t\t\tpainter.drawLine(tickPos, mediumTickTop, tickPos, tickBottom);\n\t\t\telse\n\t\t\t\tpainter.drawLine(tickPos, shortTickTop, tickPos, tickBottom);\n\t\t}\n\t}\n\telse\n\t{\n\t\tdouble minUnitsPerTick =\n\t\t\tunitsInPixel * (double)m_minimumTicksSpacing;\n\t\tdouble unitsPerTick =\n\t\t\tstd::pow(10.0, std::floor(std::log10((double)maxUnits)));\n\t\twhile(unitsPerTick > minUnitsPerTick)\n\t\t\tunitsPerTick /= 10.0;\n\n\t\t// Do sane division for seconds and minutes.\n\t\tif((l_displayMode == Time) && (minUnitsPerTick > 0.1))\n\t\t{\n\t\t\tunitsPerTick = 0.2; // 2 sec\n\t\t\tif(unitsPerTick < minUnitsPerTick)\n\t\t\t\tunitsPerTick *= 2.5; // 5 sec\n\t\t\tif(unitsPerTick < minUnitsPerTick)\n\t\t\t\tunitsPerTick *= 2.0; // 10 sec\n\t\t\tif(unitsPerTick < minUnitsPerTick)\n\t\t\t\tunitsPerTick *= 2.0; // 20 sec\n\t\t\tif(unitsPerTick < minUnitsPerTick)\n\t\t\t\tunitsPerTick *= 1.5; // 30 sec\n\t\t\tif(unitsPerTick < minUnitsPerTick)\n\t\t\t\tunitsPerTick *= 2.0; // 1 min\n\t\t\tif(unitsPerTick < minUnitsPerTick)\n\t\t\t\tunitsPerTick *= 2.0; // 2 min\n\t\t\tif(unitsPerTick < minUnitsPerTick)\n\t\t\t\tunitsPerTick *= 2.5; // 5 min\n\t\t\tif(unitsPerTick < minUnitsPerTick)\n\t\t\t\tunitsPerTick *= 2.0; // 10 min\n\t\t\tif(unitsPerTick < minUnitsPerTick)\n\t\t\t\tunitsPerTick *= 2.0; // 20 min\n\t\t\tif(unitsPerTick < minUnitsPerTick)\n\t\t\t\tunitsPerTick *= 1.5; // 30 min\n\t\t\tif(unitsPerTick < minUnitsPerTick)\n\t\t\t\tunitsPerTick *= 2.0; // 1 hour\n\t\t}\n\n\t\twhile(unitsPerTick < minUnitsPerTick)\n\t\t{\n\t\t\tunitsPerTick *= 2.0;\n\t\t\tif(unitsPerTick < minUnitsPerTick)\n\t\t\t\tunitsPerTick *= 1.25;\n\t\t\tif(unitsPerTick < minUnitsPerTick)\n\t\t\t\tunitsPerTick *= 2.0;\n\t\t\tif(unitsPerTick < minUnitsPerTick)\n\t\t\t\tunitsPerTick *= 2.0;\n\t\t}\n\n\t\tdouble units = 0.0;\n\t\tint n = 0;\n\t\twhile(units - maxUnits < 0.001)\n\t\t{\n\t\t\tint tickPos = startPos + (int)(units / unitsInPixel);\n\t\t\tif(n % 10 == 0)\n\t\t\t{\n\t\t\t\tpainter.drawLine(tickPos, longTickTop, tickPos, tickBottom);\n\n\t\t\t\tQString labelString;\n\t\t\t\tif(l_displayMode == Frames)\n\t\t\t\t\tlabelString = QString::number(units);\n\t\t\t\telse\n\t\t\t\t\tlabelString = vsedit::timeToString(units);\n\t\t\t\tlabelPos.setX(tickPos - labelsFontMetrics.horizontalAdvance(\n\t\t\t\t\tlabelString) / 2 + 1);\n\t\t\t\tpainter.drawText(labelPos, labelString);\n\t\t\t}\n\t\t\telse if(n % 5 == 0)\n\t\t\t\tpainter.drawLine(tickPos, mediumTickTop, tickPos, tickBottom);\n\t\t\telse\n\t\t\t\tpainter.drawLine(tickPos, shortTickTop, tickPos, tickBottom);\n\t\t\tn++;\n\t\t\tunits += unitsPerTick;\n\t\t}\n\t}\n\n\ta_pEvent->accept();\n}\n\n// END OF void TimeLineSlider::paintEvent(QPaintEvent * a_pEvent)\n//==============================================================================\n\nvoid TimeLineSlider::wheelEvent(QWheelEvent * a_pEvent)\n{\n\tif(a_pEvent->modifiers() != Qt::NoModifier)\n\t{\n\t\tQWidget::wheelEvent(a_pEvent);\n\t\treturn;\n\t}\n\n\tQPoint delta = a_pEvent->angleDelta();\n\tif(delta.x() == 0)\n\t{\n\t\tif(delta.y() < 0)\n\t\t\tslotStepDown();\n\t\telse\n\t\t\tslotStepUp();\n\t}\n\telse\n\t{\n\t\tif(delta.x() < 0)\n\t\t\tslotStepDown();\n\t\telse\n\t\t\tslotStepUp();\n\t}\n\ta_pEvent->accept();\n}\n\n// END OF void TimeLineSlider::wheelEvent(QWheelEvent * a_pEvent)\n//==============================================================================\n\nint TimeLineSlider::slideLineInnerWidth() const\n{\n\tint l_slideLineInnerWidth = width() - m_sideMargin * 2 -\n\t\tm_slideLineFrameWidth * 2;\n\treturn l_slideLineInnerWidth;\n}\n\n// END OF int TimeLineSlider::slideLineInnerWidth() const\n//==============================================================================\n\nint TimeLineSlider::frameToPos(int a_frame) const\n{\n\tif(a_frame > m_maxFrame)\n\t\ta_frame = m_maxFrame;\n\tint framePos = (int)((double)(slideLineInnerWidth() - 1) /\n\t\t(double)m_maxFrame * (double)a_frame);\n\tframePos += m_sideMargin + m_slideLineFrameWidth;\n\treturn framePos;\n}\n\n// END OF int TimeLineSlider::frameToPos(int a_frame) const\n//==============================================================================\n\nint TimeLineSlider::posToFrame(int a_pos) const\n{\n\tint start = m_sideMargin + m_slideLineFrameWidth;\n\tint last = width() - m_sideMargin - m_slideLineFrameWidth - 1;\n\tif(a_pos < start)\n\t\treturn 0;\n\telse if(a_pos > last)\n\t\treturn m_maxFrame;\n\n\tint l_frame = (int)std::round((double)m_maxFrame /\n\t\t(double)(slideLineInnerWidth() - 1) *\n\t\t(double)(a_pos - start));\n\treturn l_frame;\n}\n\n// END OF int TimeLineSlider::posToFrame(int a_pos) const\n//==============================================================================\n\nQRect TimeLineSlider::slideLineRect() const\n{\n\tQRect l_slideLineRect;\n\tl_slideLineRect.setLeft(m_sideMargin);\n\tint slideLineWidth = width() - m_sideMargin * 2;\n\tl_slideLineRect.setWidth(slideLineWidth);\n\tl_slideLineRect.setTop(height() - m_bottomMargin - m_slideLineHeight);\n\tl_slideLineRect.setHeight(m_slideLineHeight);\n\treturn l_slideLineRect;\n}\n\n// END OF QRect TimeLineSlider::slideLineRect() const\n//==============================================================================\n\nQRect TimeLineSlider::slideLineActiveRect() const\n{\n\tQMargins margins(m_slideLineFrameWidth, m_slideLineFrameWidth,\n\t\tm_slideLineFrameWidth, m_slideLineFrameWidth);\n\treturn slideLineRect().marginsRemoved(margins);\n}\n\n// END OF QRect TimeLineSlider::slideLineActiveRect() const\n//==============================================================================\n\nvoid TimeLineSlider::recalculateMinimumSize()\n{\n\tint widgetHeight = m_bottomMargin + m_slideLineHeight +\n\t\tm_slideLineTicksSpacing + m_longTickHeight + m_tickTextSpacing +\n\t\tm_textHeight + m_topMargin;\n\tsetMinimumSize(2 * m_sideMargin + 2 * m_slideLineFrameWidth + 2,\n\t\twidgetHeight);\n}\n\n// END OF void TimeLineSlider::recalculateMinimumSize()\n//===================================================================================\n\nvoid TimeLineSlider::setPointerAtFrame(const QMouseEvent * a_pEvent)\n{\n\tint frame = posToFrame(a_pEvent->pos().x());\n\tif(a_pEvent->modifiers() == Qt::ControlModifier)\n\t\tm_pointerAtFrame = getClosestBookmark(frame);\n\telse\n\t\tm_pointerAtFrame = frame;\n}\n\n// END OF void TimeLineSlider::setPointerAtFrame(const QMouseEvent * a_pEvent)\n//==============================================================================\n"
  },
  {
    "path": "common-src/timeline_slider/timeline_slider.h",
    "content": "#ifndef TIMELINESLIDER_H\n#define TIMELINESLIDER_H\n\n#include <QWidget>\n#include <set>\n\nclass QKeyEvent;\nclass QMouseEvent;\nclass QPaintEvent;\nclass QWheelEvent;\n\nclass TimeLineSlider : public QWidget\n{\n\tQ_OBJECT\n\npublic:\n\n\tTimeLineSlider(QWidget * a_pParent = nullptr);\n\n\tvirtual ~TimeLineSlider();\n\n\tenum DisplayMode\n\t{\n\t\tTime,\n\t\tFrames,\n\t};\n\n\tenum ColorRole\n\t{\n\t\tSlideLine,\n\t\tActiveFrame,\n\t\tInactiveFrame,\n\t\tCurrentFramePointer,\n\t\tSlidingPointer,\n\t\tBookmark,\n\t};\n\n\tint frame() const;\n\n\tvoid setFrame(int a_frame, bool a_refreshCache);\n\n\tvoid setFramesNumber(int a_framesNumber, bool a_refreshCache);\n\n\tvoid setFPS(double a_fps);\n\n\tDisplayMode displayMode() const;\n\n\tvoid setDisplayMode(DisplayMode a_displayMode);\n\n\tvoid setBigStep(int a_bigStep);\n\n\tvoid setLabelsFont(const QFont & a_font);\n\tvoid setColor(ColorRole a_role, const QColor & a_color);\n\n\tvoid addBookmark(int a_bookmark);\n\tvoid removeBookmark(int a_bookmark);\n\tstd::set<int> bookmarks() const;\n\tvoid setBookmarks(const std::set<int> & a_bookmarks);\n\tvoid clearBookmarks();\n\tint getClosestBookmark(int a_frame) const;\n\npublic slots:\n\n\tvoid slotStepUp();\n\tvoid slotStepDown();\n\tvoid slotBigStepUp();\n\tvoid slotBigStepDown();\n\tvoid slotStepBy(int a_step);\n\tvoid slotStepBySeconds(double a_seconds);\n\n\tvoid slotBookmarkCurrentFrame();\n\tvoid slotUnbookmarkCurrentFrame();\n\tvoid slotGoToPreviousBookmark();\n\tvoid slotGoToNextBookmark();\n\nsignals:\n\n\tvoid signalSliderMoved(int a_frame);\n\n\tvoid signalFrameChanged(int a_frame, bool a_refreshCache);\n\n\tvoid signalSliderPressed();\n\tvoid signalSliderReleased();\n\nprotected:\n\n\tvoid keyPressEvent(QKeyEvent * a_pEvent);\n\n\tvoid mouseMoveEvent(QMouseEvent * a_pEvent);\n\n\tvoid mousePressEvent(QMouseEvent * a_pEvent);\n\n\tvoid mouseReleaseEvent(QMouseEvent * a_pEvent);\n\n\tvoid paintEvent(QPaintEvent * a_pEvent);\n\n\tvoid wheelEvent(QWheelEvent * a_pEvent);\n\nprivate:\n\n\tint slideLineInnerWidth() const;\n\n\tint frameToPos(int a_frame) const;\n\n\tint posToFrame(int a_pos) const;\n\n\tQRect slideLineRect() const;\n\n\tQRect slideLineActiveRect() const;\n\n\tvoid recalculateMinimumSize();\n\n\tvoid setPointerAtFrame(const QMouseEvent * a_pEvent);\n\n\tint m_maxFrame;\n\tdouble m_fps;\n\n\tint m_currentFrame;\n\tint m_pointerAtFrame;\n\n\tDisplayMode m_displayMode;\n\n\tint m_bigStep;\n\n\tint m_sideMargin;\n\tint m_bottomMargin;\n\tint m_slideLineHeight;\n\tint m_slideLineFrameWidth;\n\tint m_slideLineTicksSpacing;\n\tint m_shortTickHeight;\n\tint m_mediumTickHeight;\n\tint m_longTickHeight;\n\tint m_tickTextSpacing;\n\tint m_textHeight;\n\tint m_topMargin;\n\tint m_minimumTicksSpacing;\n\n\tbool m_sliderPressed;\n\n\tQFont m_labelsFont;\n\tQColor m_slideLineColor;\n\tQColor m_activeFrameColor;\n\tQColor m_inactiveFrameColor;\n\tQColor m_currentFramePointerColor;\n\tQColor m_slidingPointerColor;\n\tQColor m_bookmarkColor;\n\n\tstd::map<ColorRole, QColor *> m_colorRoleMap;\n\n\tstd::set<int> m_bookmarks;\n};\n\n#endif // TIMELINESLIDER_H\n"
  },
  {
    "path": "common-src/vapoursynth/vapoursynth_script_processor.cpp",
    "content": "#include \"vapoursynth_script_processor.h\"\n\n#include \"../helpers.h\"\n#include \"vs_script_library.h\"\n#include \"vs_pack_rgb.h\"\n#include \"vs_set_matrix.h\"\n\n#include <VSHelper4.h>\n#include <VSConstants4.h>\n\n#include <vector>\n#include <cmath>\n#include <utility>\n#include <memory>\n#include <functional>\n#include <QPixmap>\n#include <QColormap>\n\n//==============================================================================\n\nvoid VS_CC frameReady(void * a_pUserData,\n\tconst VSFrame * a_cpFrame, int a_frameNumber,\n\tVSNode * a_pNode, const char * a_errorMessage)\n{\n\tVapourSynthScriptProcessor * pScriptProcessor =\n\t\tstatic_cast<VapourSynthScriptProcessor *>(a_pUserData);\n\tQ_ASSERT(pScriptProcessor);\n\tQString errorMessage(a_errorMessage);\n\tQMetaObject::invokeMethod(pScriptProcessor,\n\t\t\"slotReceiveFrameAndProcessQueue\",\n\t\tQt::QueuedConnection,\n\t\tQ_ARG(const VSFrame *, a_cpFrame),\n\t\tQ_ARG(int, a_frameNumber),\n\t\tQ_ARG(VSNode *, a_pNode),\n\t\tQ_ARG(QString, errorMessage));\n}\n\n// END OF void VS_CC frameReady(void * a_pUserData,\n//\tconst VSFrame * a_cpFrame, int a_frameNumber,\n//\tVSNode * a_pNode, const char * a_errorMessage)\n//==============================================================================\n\nVapourSynthScriptProcessor::VapourSynthScriptProcessor(\n\tSettingsManagerCore * a_pSettingsManager,\n\tVSScriptLibrary * a_pVSScriptLibrary,\n\tQObject * a_pParent):\n\tQObject(a_pParent)\n\t, m_pSettingsManager(a_pSettingsManager)\n\t, m_pVSScriptLibrary(a_pVSScriptLibrary)\n\t, m_script()\n\t, m_scriptName()\n\t, m_error()\n\t, m_initialized(false)\n\t, m_cpVSAPI(nullptr)\n\t, m_pVSScript(nullptr)\n\t, m_pCore(nullptr)\n\t, m_nodeInfo()\n\t, m_finalizing(false)\n{\n\tQ_ASSERT(m_pSettingsManager);\n\tQ_ASSERT(m_pVSScriptLibrary);\n\n\tslotResetSettings();\n}\n\n// END OF VapourSynthScriptProcessor::VapourSynthScriptProcessor(\n//\t\tSettingsManagerCore * a_pSettingsManager,\n//\t\tVSScriptLibrary * a_pVSScriptLibrary, QObject * a_pParent)\n//==============================================================================\n\nVapourSynthScriptProcessor::~VapourSynthScriptProcessor()\n{\n\tfinalize();\n}\n\n// END OF VapourSynthScriptProcessor::~VapourSynthScriptProcessor()\n//==============================================================================\n\nbool VapourSynthScriptProcessor::initialize(const QString& a_script,\n\tconst QString& a_scriptName, int a_outputIndex, ProcessReason a_reason)\n{\n\tif(m_initialized || m_finalizing)\n\t{\n\t\tm_error = tr(\"Script processor is already in use.\");\n\t\temit signalWriteLogMessage(mtCritical, m_error);\n\t\treturn false;\n\t}\n\n\tif(!m_pVSScript || !m_pCore)\n\t{\n\t\tm_pCore = m_pVSScriptLibrary->createCore();\n\t\tm_pVSScript = m_pVSScriptLibrary->createScript(m_pCore);\n\t}\n\tif(!m_pVSScript)\n\t{\n\t\tm_error = tr(\"Failed to create VSScript handle!\");\n\t\temit signalWriteLogMessage(mtCritical, m_error);\n\t\tfinalize();\n\t\treturn false;\n\t}\n\n\tm_cpVSAPI = m_pVSScriptLibrary->getVSAPI();\n\tif(!m_cpVSAPI)\n\t{\n\t\tfinalize();\n\t\treturn false;\n\t}\n\n\tm_cpVSAPI->getCoreInfo(m_pCore, &m_cpCoreInfo);\n\n\tint opresult = m_pVSScriptLibrary->evaluateScript(m_pVSScript,\n\t\ta_script.toUtf8().constData(), a_scriptName.toUtf8().constData());\n\n\tif(opresult)\n\t{\n\t\tm_error = tr(\"Failed to evaluate the script\");\n\t\tconst char * vsError = m_pVSScriptLibrary->getError(m_pVSScript);\n\t\tif(vsError)\n\t\t\tm_error += QString(\":\\n\") + vsError;\n\t\telse\n\t\t\tm_error += '.';\n\n\t\temit signalWriteLogMessage(mtCritical, m_error);\n\t\tfinalize();\n\t\treturn false;\n\t}\n\n\tVSNode * pOutputNode = m_pVSScriptLibrary->getOutput(\n\t\tm_pVSScript, a_outputIndex);\n\tif(!pOutputNode)\n\t{\n\t\tm_error = tr(\"Failed to get output node #%1.\")\n\t\t\t.arg(a_outputIndex);\n\t\temit signalWriteLogMessage(mtCritical, m_error);\n\t\tfinalize();\n\t\treturn false;\n\t}\n\n\tm_nodeInfo = VSNodeInfo(pOutputNode, m_cpVSAPI);\n\n#ifdef Q_OS_WIN // AUDIO\n\tif(a_reason == ProcessReason::Encode && m_nodeInfo.isAudio())\n#else\n\tif((a_reason == ProcessReason::Preview\n\t\t|| a_reason == ProcessReason::Encode) && m_nodeInfo.isAudio())\n#endif\n\t{\n\t\tm_cpVSAPI->freeNode(pOutputNode);\n\t\tm_error = tr(\"Output node #%1 is audio. \"\n#ifdef Q_OS_WIN // AUDIO\n\t\t\t\"Encoding audio are not supported.\")\n#else\n\t\t\t\"Previewing and encoding audio are not supported.\")\n#endif\n\t\t\t.arg(a_outputIndex);\n\t\temit signalWriteLogMessage(\n\t\t\ta_outputIndex == 0 ? mtCritical : mtWarning, m_error);\n\t\tfinalize();\n\t\treturn false;\n\t}\n\n\tif(m_nodeInfo.isVideo() &&\n\t\tm_nodeInfo.getAsVideo()->format.colorFamily == cfUndefined)\n\t{\n\t\temit signalWriteLogMessage(mtWarning,\n\t\t\ttr(\"Video output node #%1 has Undefined format.\")\n\t\t\t.arg(a_outputIndex));\n\t}\n\n\tm_cpVSAPI->freeNode(pOutputNode);\n\n\tm_script = a_script;\n\tm_scriptName = a_scriptName;\n\n\tm_error.clear();\n\tm_initialized = true;\n\n\tsendFrameQueueChangeSignal();\n\n\treturn true;\n}\n\n// END OF bool VapourSynthScriptProcessor::initialize(const QString& a_script,\n//\t\tconst QString& a_scriptName, int a_outputIndex, ProcessReason a_reason)\n//==============================================================================\n\nbool VapourSynthScriptProcessor::finalize()\n{\n\tm_finalizing = true;\n\tbool noFrameTicketsInProcess = flushFrameTicketsQueue();\n\tif(!noFrameTicketsInProcess)\n\t\treturn false;\n\n\tfor(std::pair<const int, NodePair> & mapItem : m_nodePairForOutputIndex)\n\t{\n\t\tNodePair & nodePair = mapItem.second;\n\t\tif(nodePair.pOutputNode)\n\t\t\tm_cpVSAPI->freeNode(nodePair.pOutputNode);\n\t\tif(nodePair.pPreviewNode)\n\t\t\tm_cpVSAPI->freeNode(nodePair.pPreviewNode);\n\t}\n\tm_nodePairForOutputIndex.clear();\n\n\tif(m_pVSScript)\n\t{\n\t\tm_pVSScriptLibrary->freeScript(m_pVSScript);\n\t\tm_pVSScript = nullptr;\n\t}\n\n\tm_cpVSAPI = nullptr;\n\n\tm_script.clear();\n\tm_scriptName.clear();\n\n\tm_initialized = false;\n\tm_finalizing = false;\n\n\temit signalFinalized();\n\n\treturn true;\n}\n\n// END OF bool VapourSynthScriptProcessor::finalize()\n//==============================================================================\n\nbool VapourSynthScriptProcessor::isInitialized() const\n{\n\treturn m_initialized;\n}\n\n// END OF bool VapourSynthScriptProcessor::isInitialized() const\n//==============================================================================\n\nQString VapourSynthScriptProcessor::error() const\n{\n\treturn m_error;\n}\n\n// END OF QString VapourSynthScriptProcessor::error() const\n//==============================================================================\n\nstd::vector<int> VapourSynthScriptProcessor::getOutputIndices() const\n{\n\tif(!isInitialized() || !m_pVSScript)\n    \treturn std::vector<int>();\n\n\treturn m_pVSScriptLibrary->getOutputIndices(m_pVSScript);\n}\n\nVSNodeInfo VapourSynthScriptProcessor::nodeInfo(int a_outputIndex)\n{\n\tif(!m_initialized)\n\t\treturn VSNodeInfo();\n\n\tQ_ASSERT(m_cpVSAPI);\n\tQ_ASSERT(m_pVSScript);\n\n\tVSNode * pNode =\n\t\tm_pVSScriptLibrary->getOutput(m_pVSScript, a_outputIndex);\n\tif(!pNode)\n\t{\n\t\tm_error = tr(\"Couldn't resolve output node #%1.\")\n\t\t\t.arg(a_outputIndex);\n\t\temit signalWriteLogMessage(\n\t\t\ta_outputIndex == 0 ? mtCritical : mtWarning, m_error);\n\t\treturn VSNodeInfo();\n\t}\n\n\tVSNodeInfo nodeInfo(pNode, m_cpVSAPI);\n\n\tm_cpVSAPI->freeNode(pNode);\n\n\treturn nodeInfo;\n}\n\n// END OF VSNodeInfo VapourSynthScriptProcessor::nodeInfo(int a_outputIndex)\n//==============================================================================\n\nbool VapourSynthScriptProcessor::requestFrameAsync(int a_frameNumber,\n\tint a_outputIndex, bool a_needPreview)\n{\n\tif(!m_initialized)\n\t\treturn false;\n\n\tif(a_frameNumber < 0)\n\t{\n\t\tm_error = tr(\"Requested frame number %1 is negative.\")\n\t\t\t.arg(a_frameNumber);\n\t\temit signalWriteLogMessage(mtCritical, m_error);\n\t\treturn false;\n\t}\n\n\tQ_ASSERT(m_cpVSAPI);\n\n\tNodePair & nodePair = getNodePair(a_outputIndex, a_needPreview);\n\tif(!nodePair.pOutputNode)\n\t\treturn false;\n\n\tint numFrames;\n\tint mediaType = m_cpVSAPI->getNodeType(nodePair.pOutputNode);\n\tif(mediaType == mtAudio)\n\t{\n\t\tauto *info = m_cpVSAPI->getAudioInfo(nodePair.pOutputNode);\n\t\tQ_ASSERT(info);\n\t\tnumFrames = info->numFrames;\n\t}\n\telse\n\t{\n\t\tauto *info = m_cpVSAPI->getVideoInfo(nodePair.pOutputNode);\n\t\tQ_ASSERT(info);\n\t\tnumFrames = info->numFrames;\n\t}\n\n\tif(a_frameNumber >= numFrames)\n\t{\n\t\tm_error = tr(\"Requested frame number %1 is outside the frame \"\n\t\t\t\"range.\").arg(a_outputIndex);\n\t\temit signalWriteLogMessage(mtCritical, m_error);\n\t\treturn false;\n\t}\n\n\tif(a_needPreview && (!nodePair.pPreviewNode))\n\t\treturn false;\n\n\tFrameTicket newFrameTicket(a_frameNumber, a_outputIndex,\n\t\tnodePair.pOutputNode, a_needPreview, nodePair.pPreviewNode);\n\n\tm_frameTicketsQueue.push_back(newFrameTicket);\n\tsendFrameQueueChangeSignal();\n\tprocessFrameTicketsQueue();\n\n\treturn true;\n}\n\n// END OF void VapourSynthScriptProcessor::requestFrameAsync(int a_frameNumber,\n//\t\tint a_outputIndex, bool a_needPreview)\n//==============================================================================\n\nbool VapourSynthScriptProcessor::flushFrameTicketsQueue()\n{\n\t// Check the processing queue.\n\tfor(FrameTicket & ticket : m_frameTicketsInProcess)\n\t\tticket.discard = true;\n\n\tsize_t queueSize = m_frameTicketsQueue.size();\n\tm_frameTicketsQueue.clear();\n\tif(queueSize)\n\t\tsendFrameQueueChangeSignal();\n\n\treturn m_frameTicketsInProcess.empty();\n}\n\n// END OF bool VapourSynthScriptProcessor::flushFrameTicketsQueue()\n//==============================================================================\n\nconst QString & VapourSynthScriptProcessor::script() const\n{\n\treturn m_script;\n}\n\n// END OF const QString & VapourSynthScriptProcessor::script() const\n//==============================================================================\n\nconst QString & VapourSynthScriptProcessor::scriptName() const\n{\n\treturn m_scriptName;\n}\n\n// END OF const QString & VapourSynthScriptProcessor::scriptName() const\n//==============================================================================\n\nvoid VapourSynthScriptProcessor::setScriptName(const QString & a_scriptName)\n{\n\tm_scriptName = a_scriptName;\n}\n\n// END OF void VapourSynthScriptProcessor::setScriptName(\n//\t\tconst QString & a_scriptName)\n//==============================================================================\n\nvoid VapourSynthScriptProcessor::slotReceiveFrameAndProcessQueue(\n\tconst VSFrame * a_cpFrame, int a_frameNumber, VSNode * a_pNode,\n\tQString a_errorMessage)\n{\n\treceiveFrame(a_cpFrame, a_frameNumber, a_pNode, a_errorMessage);\n\tprocessFrameTicketsQueue();\n}\n\n// END OF void VapourSynthScriptProcessor::slotReceiveFrameAndProcessQueue(\n//\t\tconst VSFrame * a_cpFrame, int a_frameNumber,\n//\t\tVSNode * a_pNode, QString a_errorMessage)\n//==============================================================================\n\nvoid VapourSynthScriptProcessor::slotResetSettings()\n{\n\tm_yuvMatrix = m_pSettingsManager->getYuvMatrixCoefficients();\n\n\tm_chromaResamplingFilter = m_pSettingsManager->getChromaResamplingFilter();\n\tm_resamplingFilterParameterA = NAN;\n\tm_resamplingFilterParameterB = NAN;\n\tif(m_chromaResamplingFilter == ResamplingFilter::Bicubic)\n\t{\n\t\tm_resamplingFilterParameterA =\n\t\t\tm_pSettingsManager->getBicubicFilterParameterB();\n\t\tm_resamplingFilterParameterB =\n\t\t\tm_pSettingsManager->getBicubicFilterParameterC();\n\t}\n\telse if(m_chromaResamplingFilter == ResamplingFilter::Lanczos)\n\t{\n\t\tm_resamplingFilterParameterA =\n\t\t\t(double)m_pSettingsManager->getLanczosFilterTaps();\n\t}\n\n\tm_chromaPlacement = m_pSettingsManager->getChromaPlacement();\n\n\tm_ditherType = m_pSettingsManager->getDitherType();\n\n\tfor(std::pair<const int, NodePair> & mapItem : m_nodePairForOutputIndex)\n\t{\n\t\tNodePair & nodePair = mapItem.second;\n\t\tif(nodePair.pPreviewNode)\n\t\t\trecreatePreviewNode(nodePair);\n\t}\n}\n\n// END OF void VapourSynthScriptProcessor::slotResetSettings()\n//==============================================================================\n\nvoid VapourSynthScriptProcessor::receiveFrame(\n\tconst VSFrame * a_cpFrame, int a_frameNumber,\n\tVSNode * a_pNode, const QString & a_errorMessage)\n{\n\tQ_ASSERT(m_cpVSAPI);\n\n\tif(!a_errorMessage.isEmpty())\n\t{\n\t\tm_error = tr(\"Error on frame %1 request:\\n%2\")\n\t\t\t.arg(a_frameNumber).arg(a_errorMessage);\n\t\temit signalWriteLogMessage(mtCritical, m_error);\n\t}\n\n\tFrameTicket ticket(a_frameNumber, -1, nullptr);\n\n\tstd::vector<FrameTicket>::iterator it = std::find_if(\n\t\tm_frameTicketsInProcess.begin(), m_frameTicketsInProcess.end(),\n\t\t[&](const FrameTicket & a_ticket)\n\t\t{\n\t\t\treturn ((a_ticket.frameNumber == a_frameNumber) &&\n\t\t\t\t((a_ticket.pOutputNode == a_pNode) ||\n\t\t\t\t(a_ticket.pPreviewNode == a_pNode)));\n\t\t});\n\n\tif(it != m_frameTicketsInProcess.end())\n\t{\n\t\t// Save frame references and free node references in ticket at once.\n\t\tif(it->pOutputNode == a_pNode)\n\t\t{\n\t\t\tit->cpOutputFrame = a_cpFrame;\n\t\t\tm_cpVSAPI->freeNode(it->pOutputNode);\n\t\t\tit->pOutputNode = nullptr;\n\n\t\t\tif(it->needPreview)\n\t\t\t{\n\t\t\t\tQ_ASSERT(it->pPreviewNode);\n\t\t\t\tif(a_cpFrame)\n\t\t\t\t{\n\t\t\t\t\tm_cpVSAPI->getFrameAsync(it->frameNumber, it->pPreviewNode,\n\t\t\t\t\t\tframeReady, this);\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tm_cpVSAPI->freeNode(it->pPreviewNode);\n\t\t\t\t\tit->pPreviewNode = nullptr;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\telse if(it->pPreviewNode == a_pNode)\n\t\t{\n\t\t\tit->cpPreviewFrame = a_cpFrame;\n\t\t\tm_cpVSAPI->freeNode(it->pPreviewNode);\n\t\t\tit->pPreviewNode = nullptr;\n\t\t}\n\n\t\t// Since we nullify the nodes in ticket - we can check if it can be\n\t\t// removed from the queue by checking the nodes.\n\t\tif((it->pOutputNode != nullptr) ||\n\t\t\t(it->needPreview && (it->pPreviewNode != nullptr)))\n\t\t\treturn;\n\n\t\tticket = *it;\n\t\tm_frameTicketsInProcess.erase(it);\n\t\tsendFrameQueueChangeSignal();\n\t}\n\telse\n\t{\n\t\tQString warning = tr(\"Warning: received frame not registered in \"\n\t\t\t\"processing. Frame number: %1; Node: %2\\n\")\n\t\t\t.arg(a_frameNumber).arg((intptr_t)a_pNode);\n\t\temit signalWriteLogMessage(mtCritical, warning);\n\t\tm_cpVSAPI->freeFrame(a_cpFrame);\n\t}\n\n\tif(!ticket.discard)\n\t{\n\t\tif(ticket.isComplete())\n\t\t{\n\t\t\temit signalDistributeFrame(ticket.frameNumber, ticket.outputIndex,\n\t\t\t\tticket.cpOutputFrame, ticket.cpPreviewFrame);\n\t\t}\n\t\telse\n\t\t{\n\t\t\temit signalFrameRequestDiscarded(ticket.frameNumber,\n\t\t\t\tticket.outputIndex, QString());\n\t\t}\n\t}\n\n\tfreeFrameTicket(ticket);\n}\n\n// END OF void VapourSynthScriptProcessor::receiveFrame(\n//\t\tconst VSFrame * a_cpFrame, int a_frameNumber,\n//\t\tVSNode * a_pNode, const QString & a_errorMessage)\n//==============================================================================\n\nvoid VapourSynthScriptProcessor::processFrameTicketsQueue()\n{\n\tQ_ASSERT(m_cpVSAPI);\n\n\tsize_t oldInQueue = m_frameTicketsQueue.size();\n\tsize_t oldInProcess = m_frameTicketsInProcess.size();\n\n\twhile(((int)m_frameTicketsInProcess.size() < m_cpCoreInfo.numThreads) &&\n\t\t(!m_frameTicketsQueue.empty()))\n\t{\n\t\tFrameTicket ticket = std::move(m_frameTicketsQueue.front());\n\t\tm_frameTicketsQueue.pop_front();\n\n\t\t// In case preview node was hot-swapped.\n\t\tNodePair & nodePair =\n\t\t\tgetNodePair(ticket.outputIndex, ticket.needPreview);\n\n\t\tbool validPair = (nodePair.pOutputNode != nullptr);\n\t\tif(ticket.needPreview)\n\t\t\tvalidPair = validPair && (nodePair.pPreviewNode != nullptr);\n\t\tif(!validPair)\n\t\t{\n\t\t\tQString reason = tr(\"No nodes to produce the frame \"\n\t\t\t\t\"%1 at output #%2.\").arg(ticket.frameNumber)\n\t\t\t\t.arg(ticket.outputIndex);\n\t\t\temit signalFrameRequestDiscarded(ticket.frameNumber,\n\t\t\t\tticket.outputIndex, reason);\n\t\t\tcontinue;\n\t\t}\n\n\t\tticket.pOutputNode = m_cpVSAPI->addNodeRef(nodePair.pOutputNode);\n\t\tif(ticket.needPreview)\n\t\t\tticket.pPreviewNode =\n\t\t\t\tm_cpVSAPI->addNodeRef(nodePair.pPreviewNode);\n\n\t\tm_cpVSAPI->getFrameAsync(ticket.frameNumber, ticket.pOutputNode,\n\t\t\tframeReady, this);\n\n\t\tm_frameTicketsInProcess.push_back(ticket);\n\t}\n\n\tsize_t inQueue = m_frameTicketsQueue.size();\n\tsize_t inProcess = m_frameTicketsInProcess.size();\n\tif((inQueue != oldInQueue) || (oldInProcess != inProcess))\n\t\tsendFrameQueueChangeSignal();\n\n\tif(m_finalizing)\n\t\tfinalize();\n}\n\n// END OF void VapourSynthScriptProcessor::processFrameTicketsQueue()\n//==============================================================================\n\nvoid VapourSynthScriptProcessor::sendFrameQueueChangeSignal()\n{\n\tsize_t inQueue = m_frameTicketsQueue.size();\n\tsize_t inProcess = m_frameTicketsInProcess.size();\n\n\tm_cpVSAPI->getCoreInfo(m_pCore, &m_cpCoreInfo);\n\n\tsize_t maxThreads = m_cpCoreInfo.numThreads;\n\tdouble usedCacheRatio = (double)m_cpCoreInfo.usedFramebufferSize\n\t\t/ (double)m_cpCoreInfo.maxFramebufferSize;\n\temit signalFrameQueueStateChanged(inQueue, inProcess, maxThreads,\n\t\tusedCacheRatio);\n}\n\n// END OF void VapourSynthScriptProcessor::sendFrameQueueChangeSignal()\n//==============================================================================\n\nbool VapourSynthScriptProcessor::recreatePreviewNode(NodePair & a_nodePair)\n{\n\tif(!a_nodePair.pOutputNode)\n\t\treturn false;\n\n\tif(!m_cpVSAPI)\n\t\treturn false;\n\n\tif(a_nodePair.pPreviewNode)\n\t{\n\t\tm_cpVSAPI->freeNode(a_nodePair.pPreviewNode);\n\t\ta_nodePair.pPreviewNode = nullptr;\n\t}\n\n\tint outputMediaType = m_cpVSAPI->getNodeType(a_nodePair.pOutputNode);\n\tif(outputMediaType == mtAudio)\n\t{\n#ifdef Q_OS_WIN // AUDIO\n\t\treturn recreateAudioPreviewNode(a_nodePair);\n#else\n\t\tm_error = tr(\"Audio playback is supported on Windows only.\");\n\t\temit signalWriteLogMessage(mtCritical, m_error);\n\t\treturn false;\n#endif\n\t}\n\n\tconst VSVideoInfo * cpVideoInfo =\n\t\tm_cpVSAPI->getVideoInfo(a_nodePair.pOutputNode);\n\tif(!cpVideoInfo)\n\t\treturn false;\n\tconst VSVideoFormat * cpFormat = &cpVideoInfo->format;\n\n\tbool to_10_bit = (QColormap::instance().depth() == 30);\n\n\tVSMap * pResultMap = nullptr;\n\n\tif(vsh::isSameVideoPresetFormat(pfRGB24, cpFormat, m_pCore, m_cpVSAPI))\n\t{\n\t\tto_10_bit = false;\n\t\tpResultMap = m_cpVSAPI->createMap();\n\t\tm_cpVSAPI->mapSetNode(pResultMap, \"clip\", a_nodePair.pOutputNode,\n\t\t\tmaReplace);\n\t}\n\telse if(to_10_bit &&\n\t\tvsh::isSameVideoPresetFormat(pfRGB30, cpFormat, m_pCore, m_cpVSAPI))\n\t{\n\t\tpResultMap = m_cpVSAPI->createMap();\n\t\tm_cpVSAPI->mapSetNode(pResultMap, \"clip\", a_nodePair.pOutputNode,\n\t\t\tmaReplace);\n\t}\n\telse\n\t{\n\t\tbool isVF = isVariableFormat(cpVideoInfo);\n\t\tbool isYUV = cpFormat->colorFamily == cfYUV;\n\n\t\tVSPlugin * pResizePlugin = m_cpVSAPI->getPluginByID(\n\t\t\t\"com.vapoursynth.resize\", m_pCore);\n\t\tconst char * resizeName = \"Point\";\n\n\t\tVSMap * pArgumentMap = m_cpVSAPI->createMap();\n\n\t\tVSCoreInfo coreInfo;\n\t\tm_cpVSAPI->getCoreInfo(m_pCore, &coreInfo);\n\t\tif(coreInfo.core < 58)\n\t\t\tm_cpVSAPI->mapSetInt(pArgumentMap, \"prefer_props\", 1, maReplace);\n\n\t\t// Set matrix and chromaloc\n\n\t\tint64_t matrixIn;\n\t\tswitch(m_yuvMatrix)\n\t\t{\n\t\tcase YuvMatrixCoefficients::m709:\n\t\t\tmatrixIn = VSC_MATRIX_BT709;\n\t\t\tbreak;\n\t\tcase YuvMatrixCoefficients::m470BG:\n\t\t\tmatrixIn = VSC_MATRIX_BT470_BG;\n\t\t\tbreak;\n\t\tcase YuvMatrixCoefficients::m170M:\n\t\t\tmatrixIn = VSC_MATRIX_ST170_M;\n\t\t\tbreak;\n\t\tcase YuvMatrixCoefficients::m2020_NCL:\n\t\t\tmatrixIn = VSC_MATRIX_BT2020_NCL;\n\t\t\tbreak;\n\t\tdefault:\n\t\t\tQ_ASSERT(false);\n\t\t}\n\n\t\tm_cpVSAPI->mapSetInt(pArgumentMap, \"matrix_in\", matrixIn, maReplace);\n\n\t\tint64_t chromaLoc;\n\t\tswitch(m_chromaPlacement)\n\t\t{\n\t\tcase ChromaPlacement::LEFT:\n\t\t\tchromaLoc = VSC_CHROMA_LEFT;\n\t\t\tbreak;\n\t\tcase ChromaPlacement::CENTER:\n\t\t\tchromaLoc = VSC_CHROMA_CENTER;\n\t\t\tbreak;\n\t\tcase ChromaPlacement::TOP_LEFT:\n\t\t\tchromaLoc = VSC_CHROMA_TOP_LEFT;\n\t\t\tbreak;\n\t\tdefault:\n\t\t\tQ_ASSERT(false);\n\t\t}\n\t\tm_cpVSAPI->mapSetInt(pArgumentMap, \"chromaloc_in\", chromaLoc, maReplace);\n\n\t\tQString ditherType;\n\t\tswitch (m_ditherType)\n\t\t{\n\t\tcase DitherType::NONE:\n\t\t\tditherType = \"none\";\n\t\t\tbreak;\n\t\tcase DitherType::ORDERED:\n\t\t\tditherType = \"ordered\";\n\t\t\tbreak;\n\t\tcase DitherType::RANDOM:\n\t\t\tditherType = \"random\";\n\t\t\tbreak;\n\t\tcase DitherType::ERROR_DIFFUSION:\n\t\t\tditherType = \"error_diffusion\";\n\t\t\tbreak;\n\t\tdefault:\n\t\t\tQ_ASSERT(false);\n\t\t}\n\t\tm_cpVSAPI->mapSetData(pArgumentMap, \"dither_type\",\n\t\t\tditherType.toStdString().c_str(), ditherType.size(),\n\t\t\tdtUtf8, maReplace);\n\n\t\tVSMap *pTempMap = m_cpVSAPI->createMap();\n\t\tm_cpVSAPI->copyMap(pArgumentMap, pTempMap);\n\t\tm_cpVSAPI->mapSetNode(pTempMap, \"clip\",\n\t\t\ta_nodePair.pOutputNode, maReplace);\n\t\tsetMatrixFilter(pTempMap, pArgumentMap, m_pCore, m_cpVSAPI);\n\t\tm_cpVSAPI->clearMap(pTempMap);\n\n\t\tm_cpVSAPI->mapSetInt(pArgumentMap, \"format\", (to_10_bit ?\n\t\t\tpfRGB30 : pfRGB24), maReplace);\n\n\t\tif(isYUV || isVF)\n\t\t{\n\t\t\tswitch(m_chromaResamplingFilter)\n\t\t\t{\n\t\t\tcase ResamplingFilter::Point:\n\t\t\t\tresizeName = \"Point\";\n\t\t\t\tbreak;\n\t\t\tcase ResamplingFilter::Bilinear:\n\t\t\t\tresizeName = \"Bilinear\";\n\t\t\t\tbreak;\n\t\t\tcase ResamplingFilter::Bicubic:\n\t\t\t\tresizeName = \"Bicubic\";\n\t\t\t\tm_cpVSAPI->mapSetFloat(pArgumentMap, \"filter_param_a_uv\",\n\t\t\t\t\tm_resamplingFilterParameterA, maReplace);\n\t\t\t\tm_cpVSAPI->mapSetFloat(pArgumentMap, \"filter_param_b_uv\",\n\t\t\t\t\tm_resamplingFilterParameterB, maReplace);\n\t\t\t\tbreak;\n\t\t\tcase ResamplingFilter::Lanczos:\n\t\t\t\tresizeName = \"Lanczos\";\n\t\t\t\tm_cpVSAPI->mapSetFloat(pArgumentMap, \"filter_param_a_uv\",\n\t\t\t\t\tm_resamplingFilterParameterA, maReplace);\n\t\t\t\tbreak;\n\t\t\tcase ResamplingFilter::Spline16:\n\t\t\t\tresizeName = \"Spline16\";\n\t\t\t\tbreak;\n\t\t\tcase ResamplingFilter::Spline36:\n\t\t\t\tresizeName = \"Spline36\";\n\t\t\t\tbreak;\n\t\t\tcase ResamplingFilter::Spline64:\n\t\t\t\tresizeName = \"Spline64\";\n\t\t\tdefault:\n\t\t\t\tQ_ASSERT(false);\n\t\t\t}\n\t\t}\n\n\t\tpResultMap = m_cpVSAPI->invoke(pResizePlugin, resizeName, pArgumentMap);\n\n\t\tm_cpVSAPI->freeMap(pArgumentMap);\n\n\t}\n\n\tconst char * cpResultError = m_cpVSAPI->mapGetError(pResultMap);\n\n\tif(cpResultError)\n\t{\n\t\tm_error = tr(\"Failed to convert to RGB:\\n\");\n\t\tm_error += cpResultError;\n\t\temit signalWriteLogMessage(mtCritical, m_error);\n\t\tm_cpVSAPI->freeMap(pResultMap);\n\t\treturn false;\n\t}\n\n\tVSNode * pRGBNode = m_cpVSAPI->mapGetNode(pResultMap, \"clip\", 0, nullptr);\n\tm_cpVSAPI->freeMap(pResultMap);\n\n\tVSNode * pPreviewNode = packRGBFilter(pRGBNode, a_nodePair.pOutputNode,\n\t\tto_10_bit, m_pCore, m_cpVSAPI);\n\n\tQ_ASSERT(pPreviewNode);\n\ta_nodePair.pPreviewNode = pPreviewNode;\n\n\treturn true;\n}\n\n// END OF bool VapourSynthScriptProcessor::recreatePreviewNode(\n//\t\tNodePair & a_nodePair)\n//==============================================================================\n\nbool VapourSynthScriptProcessor::recreateAudioPreviewNode(NodePair &a_nodePair)\n{\n\tQ_ASSERT(m_pCore);\n\n\tconst VSAudioInfo * cpAudioInfo =\n\t\tm_cpVSAPI->getAudioInfo(a_nodePair.pOutputNode);\n\n\tVSMap * map = m_cpVSAPI->createMap();\n\tVSPlugin *stdPlugin = m_cpVSAPI->getPluginByID(VSH_STD_PLUGIN_ID, m_pCore);\n\tm_cpVSAPI->mapSetInt(map, \"length\", cpAudioInfo->numFrames, maReplace);\n\tVSMap * blankMap = m_cpVSAPI->invoke(stdPlugin, \"BlankClip\", map);\n\tm_cpVSAPI->clearMap(map);\n\n\tQString props = vsedit::nodeInfoString(\n\t\tnodeInfo(a_nodePair.outputIndex), m_cpVSAPI);\n\tQString text = QString(\"Audio node #%1\\n\\n\").arg(a_nodePair.outputIndex)\n\t\t+ props.replace(\"| \", \"\\n\");\n    m_cpVSAPI->mapSetData(blankMap, \"text\", text.toStdString().c_str(),\n\t\ttext.size(), dtUtf8, maReplace);\n\tVSPlugin * textPlugin = m_cpVSAPI->getPluginByID(VSH_TEXT_PLUGIN_ID, m_pCore);\n    VSMap * textMap = m_cpVSAPI->invoke(textPlugin, \"Text\", blankMap);\n\tm_cpVSAPI->clearMap(blankMap);\n\n\tVSNode * textClip = m_cpVSAPI->mapGetNode(textMap, \"clip\", 0, nullptr);\n\tm_cpVSAPI->clearMap(textMap);\n\n\ta_nodePair.pPreviewNode = packRGBFilter(textClip, a_nodePair.pOutputNode,\n\t\tfalse, m_pCore, m_cpVSAPI);\n    return true;\n}\n\nvoid VapourSynthScriptProcessor::freeFrameTicket(FrameTicket & a_ticket)\n{\n\tQ_ASSERT(m_cpVSAPI);\n\n\ta_ticket.discard = true;\n\n\tif(a_ticket.cpOutputFrame)\n\t{\n\t\tm_cpVSAPI->freeFrame(a_ticket.cpOutputFrame);\n\t\ta_ticket.cpOutputFrame = nullptr;\n\t}\n\n\tif(a_ticket.cpPreviewFrame)\n\t{\n\t\tm_cpVSAPI->freeFrame(a_ticket.cpPreviewFrame);\n\t\ta_ticket.cpPreviewFrame = nullptr;\n\t}\n\n\tif(a_ticket.pOutputNode)\n\t{\n\t\tm_cpVSAPI->freeNode(a_ticket.pOutputNode);\n\t\ta_ticket.pOutputNode = nullptr;\n\t}\n\n\tif(a_ticket.pPreviewNode)\n\t{\n\n\t\tm_cpVSAPI->freeNode(a_ticket.pPreviewNode);\n\t\ta_ticket.pPreviewNode = nullptr;\n\t}\n}\n\n// END OF void VapourSynthScriptProcessor::freeFrameTicket(\n//\t\tFrameTicket & a_ticket)\n//==============================================================================\n\nNodePair & VapourSynthScriptProcessor::getNodePair(int a_outputIndex,\n\tbool a_needPreview)\n{\n\tNodePair & nodePair = m_nodePairForOutputIndex[a_outputIndex];\n\n\tnodePair.outputIndex = a_outputIndex;\n\n\tif(!nodePair.pOutputNode)\n\t{\n\t\tQ_ASSERT(!nodePair.pPreviewNode);\n\n\t\tnodePair.pOutputNode =\n\t\t\tm_pVSScriptLibrary->getOutput(m_pVSScript, a_outputIndex);\n\t\tif(!nodePair.pOutputNode)\n\t\t{\n\t\t\tm_error = tr(\"Couldn't resolve output node #%1.\")\n\t\t\t\t.arg(a_outputIndex);\n\t\t\temit signalWriteLogMessage(\n\t\t\t\ta_outputIndex == 0 ? mtCritical : mtWarning, m_error);\n\t\t\treturn nodePair;\n\t\t}\n\t}\n\n\tif(a_needPreview && (!nodePair.pPreviewNode))\n\t{\n\t\tbool previewNodeCreated = recreatePreviewNode(nodePair);\n\t\tif(!previewNodeCreated)\n\t\t{\n\t\t\tm_error = tr(\"Couldn't create preview node for output \"\n\t\t\t\t\"#%1.\").arg(a_outputIndex);\n\t\t\temit signalWriteLogMessage(mtCritical, m_error);\n\t\t\treturn nodePair;\n\t\t}\n\t}\n\n\treturn nodePair;\n}\n\n// END OF NodePair VapourSynthScriptProcessor::getNodePair(int a_outputIndex,\n//\t\tbool a_needPreview)\n//==============================================================================\n\nQString VapourSynthScriptProcessor::framePropsString(\n\tconst VSFrame * a_cpFrame) const\n{\n\tif(!a_cpFrame)\n\t\treturn tr(\"Null frame.\");\n\n\tQ_ASSERT(m_cpVSAPI);\n\n\tQString propsString;\n\tQStringList propsStringList;\n\n\tstatic std::map<VSPropertyType, QString> propTypeToString =\n\t{\n\t\t{ptUnset, \"<unset>\"},\n\t\t{ptInt, \"int\"},\n\t\t{ptFloat, \"float\"},\n\t\t{ptData, \"data\"},\n\t\t{ptFunction, \"function\"},\n\t\t{ptVideoNode, \"vnode\"},\n\t\t{ptVideoFrame, \"vframe\"},\n\t\t{ptAudioNode, \"anode\"},\n\t\t{ptAudioFrame, \"aframe\"}\n\t};\n\n\tstatic std::map<int64_t, QString> _ChromaLocationToString = \n\t{\n\t\t{VSC_CHROMA_LEFT, \"left\"},\n\t\t{VSC_CHROMA_CENTER, \"center\"},\n\t\t{VSC_CHROMA_TOP_LEFT, \"top left\"},\n\t\t{VSC_CHROMA_BOTTOM_LEFT, \"bottom left\"},\n\t\t{VSC_CHROMA_BOTTOM, \"bottom\"},\n\t};\n\n\tstatic std::map<int64_t, QString> _ColorRangeToString = \n\t{\n\t\t{VSC_RANGE_FULL, \"full\"},\n\t\t{VSC_RANGE_LIMITED, \"limited\"},\n\t};\n\n\tstatic std::map<int64_t, QString> _PrimariesToString = \n\t{\n\t\t{VSC_PRIMARIES_BT709, \"709\"},\n\t\t{VSC_PRIMARIES_UNSPECIFIED, \"unspec\"},\n\t\t{VSC_PRIMARIES_BT470_M, \"470m\"},\n\t\t{VSC_PRIMARIES_BT470_BG, \"470bg\"},\n\t\t{VSC_PRIMARIES_ST170_M, \"170m\"},\n\t\t{VSC_PRIMARIES_ST240_M, \"240m\"},\n\t\t{VSC_PRIMARIES_FILM, \"film\"},\n\t\t{VSC_PRIMARIES_BT2020, \"2020\"},\n\t\t{VSC_PRIMARIES_ST428, \"st428\"},\n\t\t{VSC_PRIMARIES_ST431_2, \"st431-2\"},\n\t\t{VSC_PRIMARIES_ST432_1, \"st432-1\"},\n\t\t{VSC_PRIMARIES_EBU3213_E, \"jedec-p22\"},\n\t};\n\n\tstatic std::map<int64_t, QString> _MatrixToString =\n\t{\n\t\t{VSC_MATRIX_RGB, \"rgb\"},\n\t\t{VSC_MATRIX_BT709, \"709\"},\n\t\t{VSC_MATRIX_UNSPECIFIED, \"unspec\"},\n\t\t{VSC_MATRIX_FCC, \"fcc\"},\n\t\t{VSC_MATRIX_BT470_BG, \"470bg\"},\n\t\t{VSC_MATRIX_ST170_M, \"170m\"},\n\t\t{VSC_MATRIX_ST240_M, \"240m\"},\n\t\t{VSC_MATRIX_YCGCO, \"ycgco\"},\n\t\t{VSC_MATRIX_BT2020_NCL, \"2020ncl\"},\n\t\t{VSC_MATRIX_BT2020_CL, \"2020cl\"},\n\t\t{VSC_MATRIX_CHROMATICITY_DERIVED_NCL, \"chromancl\"},\n\t\t{VSC_MATRIX_CHROMATICITY_DERIVED_CL, \"chromacl\"},\n\t\t{VSC_MATRIX_ICTCP, \"ictcp\"},\n\t};\n\n\tstatic std::map<int64_t, QString> _TransferToString =\n\t{\n\t\t{VSC_TRANSFER_BT709, \"709\"},\n\t\t{VSC_TRANSFER_UNSPECIFIED, \"unspec\"},\n\t\t{VSC_TRANSFER_BT470_M, \"470m\"},\n\t\t{VSC_TRANSFER_BT470_BG, \"470bg\"},\n\t\t{VSC_TRANSFER_BT601, \"601\"},\n\t\t{VSC_TRANSFER_ST240_M, \"240m\"},\n\t\t{VSC_TRANSFER_LINEAR, \"linear\"},\n\t\t{VSC_TRANSFER_LOG_100, \"log100\"},\n\t\t{VSC_TRANSFER_LOG_316, \"log316\"},\n\t\t{VSC_TRANSFER_IEC_61966_2_4, \"xvycc\"},\n\t\t{VSC_TRANSFER_IEC_61966_2_1, \"srgb\"},\n\t\t{VSC_TRANSFER_BT2020_10, \"2020_10\"},\n\t\t{VSC_TRANSFER_BT2020_12, \"2020_12\"},\n\t\t{VSC_TRANSFER_ST2084, \"st2084\"},\n\t\t//{VSC_TRANSFER_ST428, \"st428\"},\n\t\t{17, \"st428\"},\n\t\t{VSC_TRANSFER_ARIB_B67, \"std-b67\"},\n\t};\n\n\tstatic std::map<int64_t, QString> _FieldBasedToString =\n\t{\n\t\t{VSC_FIELD_PROGRESSIVE, \"progressive\"},\n\t\t{VSC_FIELD_BOTTOM, \"bottom field first\"},\n\t\t{VSC_FIELD_TOP, \"top field first\"},\n\t};\n\n\tstatic std::map<int64_t, QString> _FieldToString =\n\t{\n\t\t{0, \"from bottom field\"},\n\t\t{1, \"from top field\"},\n\t};\n\n\tstatic std::map<QString, std::map<int64_t, QString>> reservedPropToMap =\n\t{\n\t\t{\"_ChromaLocation\", _ChromaLocationToString},\n\t\t{\"_Range\", _ColorRangeToString},\n\t\t{\"_ColorRange\", _ColorRangeToString},\n\t\t{\"_Primaries\", _PrimariesToString},\n\t\t{\"_Matrix\", _MatrixToString},\n\t\t{\"_Transfer\", _TransferToString},\n\t\t{\"_FieldBased\", _FieldBasedToString},\n\t\t{\"_Field\", _FieldToString},\n\t};\n\n\tconst VSMap * cpProps = m_cpVSAPI->getFramePropertiesRO(a_cpFrame);\n\n\tint propsNumber = m_cpVSAPI->mapNumKeys(cpProps);\n\tfor(int i = 0; i < propsNumber; ++i)\n\t{\n\t\tconst char * propKey = m_cpVSAPI->mapGetKey(cpProps, i);\n\t\tif(!propKey)\n\t\t\tcontinue;\n\t\tQString currentPropString = QString(\"%1 : \").arg(propKey);\n\t\tauto propType = (VSPropertyType)m_cpVSAPI->mapGetType(cpProps, propKey);\n\t\tcurrentPropString += propTypeToString[propType];\n\t\tint elementsNumber = m_cpVSAPI->mapNumElements(cpProps, propKey);\n\t\tif(elementsNumber > 1)\n\t\t\tcurrentPropString += \"[]\";\n\t\tswitch(propType)\n\t\t{\n\t\tcase ptVideoFrame:\n\t\tcase ptVideoNode:\n\t\tcase ptAudioFrame:\n\t\tcase ptAudioNode:\n\t\tcase ptFunction:\n\t\t\tbreak;\n\t\tcase ptUnset:\n\t\t\tcurrentPropString += \": <unset>\";\n\t\t\tbreak;\n\t\tcase ptInt:\n\t\t{\n\t\t\tcurrentPropString += \" : \";\n\t\t\tQStringList elementStringList;\n\t\t\tfor(int j = 0; j < elementsNumber; ++j)\n\t\t\t{\n\t\t\t\tQString elementString;\n\t\t\t\tint error;\n\t\t\t\tint64_t element = m_cpVSAPI->mapGetInt(cpProps,\n\t\t\t\t\tpropKey, j, &error);\n\t\t\t\tif(error)\n\t\t\t\t\telementString = \"<error>\";\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tauto it = reservedPropToMap.find(QString(propKey));\n\t\t\t\t\tif(it == reservedPropToMap.end())\n\t\t\t\t\t\telementString = QString::number(element);\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tauto it2 = it->second.find(element);\n\t\t\t\t\t\tif(it2 == it->second.end())\n\t\t\t\t\t\t\telementString = QString::number(element);\n\t\t\t\t\t\telse\n\t\t\t\t\t\t\telementString = QString(\"%1 (%2)\")\n\t\t\t\t\t\t\t\t.arg(element).arg(it2->second);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\telementStringList += elementString;\n\t\t\t}\n\t\t\tcurrentPropString += elementStringList.join(\", \");\n\t\t\tbreak;\n\t\t}\n\t\tcase ptFloat:\n\t\t{\n\t\t\tcurrentPropString += \" : \";\n\t\t\tQStringList elementStringList;\n\t\t\tfor(int j = 0; j < elementsNumber; ++j)\n\t\t\t{\n\t\t\t\tQString elementString;\n\t\t\t\tint error;\n\t\t\t\tdouble element = m_cpVSAPI->mapGetFloat(cpProps,\n\t\t\t\t\tpropKey, j, &error);\n\t\t\t\tif(error)\n\t\t\t\t\telementString = \"<error>\";\n\t\t\t\telse\n\t\t\t\t\telementString = QString::number(element);\n\n\t\t\t\telementStringList += elementString;\n\t\t\t}\n\t\t\tcurrentPropString += elementStringList.join(\", \");\n\t\t\tbreak;\n\t\t}\n\t\tcase ptData:\n\t\t{\n\t\t\tcurrentPropString += \" : \";\n\t\t\tQStringList elementStringList;\n\t\t\tfor(int j = 0; j < elementsNumber; ++j)\n\t\t\t{\n\t\t\t\tQString elementString;\n\t\t\t\tint error;\n\t\t\t\tint hint = m_cpVSAPI->mapGetDataTypeHint(cpProps,\n\t\t\t\t\tpropKey, j, &error);\n\t\t\t\tif(error)\n\t\t\t\t\telementString = \"<error>\";\n\t\t\t\telse if(hint == dtUtf8)\n\t\t\t\t{\n\t\t\t\t\tconst char * element = m_cpVSAPI->mapGetData(cpProps,\n\t\t\t\t\t\tpropKey, j, &error);\n\t\t\t\t\tif(error)\n\t\t\t\t\t\telementString = \"<error>\";\n\t\t\t\t\telse\n\t\t\t\t\t\telementString = QString::fromUtf8(element);\n\t\t\t\t}\n\t\t\t\telse if(hint == dtBinary)\n\t\t\t\t{\n\t\t\t\t\tint len = m_cpVSAPI->mapGetDataSize(cpProps,\n\t\t\t\t\t\tpropKey, j, &error);\n\t\t\t\t\tif(error)\n\t\t\t\t\t\telementString = \"<error>\";\n\t\t\t\t\telse\n\t\t\t\t\t\telementString = QString(\"<binary with %1 bytes>\")\n\t\t\t\t\t\t\t.arg(len);\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tconst char * element = m_cpVSAPI->mapGetData(cpProps,\n\t\t\t\t\t\tpropKey, j, &error);\n\t\t\t\t\tif(error)\n\t\t\t\t\t\telementString = \"<error>\";\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\telementString = QString::fromUtf8(element);\n\t\t\t\t\t\tQByteArray elementAsUtf8 = elementString.toUtf8();\n\t\t\t\t\t\tint len = m_cpVSAPI->mapGetDataSize(cpProps,\n\t\t\t\t\t\t\tpropKey, j, &error);\n\t\t\t\t\t\tif(elementAsUtf8.length() != len ||\n\t\t\t\t\t\t\telementAsUtf8.toStdString() != element)\n\t\t\t\t\t\t\telementString = \"<unknown type>\";\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\telementStringList += elementString;\n\t\t\t}\n\t\t\tcurrentPropString += elementStringList.join(\", \");\n\t\t\tbreak;\n\t\t}\n\t\tdefault:\n\t\t\tQ_ASSERT(false);\n\t\t}\n\n\t\tpropsStringList += currentPropString;\n\t}\n\n\tpropsString = propsStringList.join(\" \\n\");\n\n\treturn propsString;\n}\n\n// END OF QString VapourSynthScriptProcessor::framePropsString(\n//\t\tconst VSFrame * a_cpFrame) const\n//==============================================================================\n\nbool VapourSynthScriptProcessor::clearCoreCaches()\n{\n\treturn m_pVSScriptLibrary->clearCoreCaches(m_pCore);\n}\n"
  },
  {
    "path": "common-src/vapoursynth/vapoursynth_script_processor.h",
    "content": "#ifndef VAPOURSYNTHSCRIPTPROCESSOR_H\n#define VAPOURSYNTHSCRIPTPROCESSOR_H\n\n#include \"vs_script_processor_structures.h\"\n#include \"../settings/settings_manager_core.h\"\n#include \"../helpers_vs.h\"\n\n#include <VSScript4.h>\n\n#include <QObject>\n#include <deque>\n#include <vector>\n#include <map>\n\nclass VSScriptLibrary;\n\n//==============================================================================\n\nclass VapourSynthScriptProcessor : public QObject\n{\n\tQ_OBJECT\n\npublic:\n\n\tVapourSynthScriptProcessor(SettingsManagerCore * a_pSettingsManager,\n\t\tVSScriptLibrary * a_pVSScriptLibrary, QObject * a_pParent = nullptr);\n\n\tvirtual ~VapourSynthScriptProcessor();\n\n\tbool initialize(const QString& a_script, const QString& a_scriptName,\n\t\tint a_outputIndex, ProcessReason a_reason);\n\n\tbool finalize();\n\n\tbool isInitialized() const;\n\n\tQString error() const;\n\n\tstd::vector<int> getOutputIndices() const;\n\n\tVSNodeInfo nodeInfo(int a_outputIndex = 0);\n\n\tbool requestFrameAsync(int a_frameNumber, int a_outputIndex = 0,\n\t\tbool a_needPreview = false);\n\n\tbool flushFrameTicketsQueue();\n\n\tconst QString & script() const;\n\n\tconst QString & scriptName() const;\n\n\tvoid setScriptName(const QString & a_scriptName);\n\n\tQString framePropsString(const VSFrame * a_cpFrame) const;\n\n\tbool clearCoreCaches();\n\npublic slots:\n\n\tvoid slotResetSettings();\n\nsignals:\n\n\tvoid signalWriteLogMessage(int a_messageType, const QString & a_message);\n\n\tvoid signalDistributeFrame(int a_frameNumber, int a_outputIndex,\n\t\tconst VSFrame * a_cpOutputFrame,\n\t\tconst VSFrame * a_cpPreviewFrame);\n\n\tvoid signalFrameRequestDiscarded(int a_frameNumber, int a_outputIndex,\n\t\tconst QString & a_reason);\n\n\tvoid signalFrameQueueStateChanged(size_t a_inQueue, size_t a_inProcess,\n\t\tsize_t a_maxThreads, double a_usedCacheRatio);\n\n\tvoid signalFinalized();\n\nprivate slots:\n\n\tvoid slotReceiveFrameAndProcessQueue(\n\t\tconst VSFrame * a_cpFrame, int a_frameNumber,\n\t\tVSNode * a_pNode, QString a_errorMessage);\n\nprivate:\n\n\tvoid receiveFrame(const VSFrame * a_cpFrame, int a_frameNumber,\n\t\tVSNode * a_pNode, const QString & a_errorMessage);\n\n\tvoid processFrameTicketsQueue();\n\n\tvoid sendFrameQueueChangeSignal();\n\n\tbool recreatePreviewNode(NodePair & a_nodePair);\n\n\tbool recreateAudioPreviewNode(NodePair & a_nodePair);\n\n\tvoid freeFrameTicket(FrameTicket & a_ticket);\n\n\tNodePair & getNodePair(int a_outputIndex, bool a_needPreview);\n\n\tSettingsManagerCore * m_pSettingsManager;\n\n\tVSScriptLibrary * m_pVSScriptLibrary;\n\n\tQString m_script;\n\n\tQString m_scriptName;\n\n\tQString m_error;\n\n\tbool m_initialized;\n\n\tconst VSAPI * m_cpVSAPI;\n\n\tVSScript * m_pVSScript;\n\tVSCore * m_pCore;\n\n\tVSNodeInfo m_nodeInfo;\n\tVSCoreInfo m_cpCoreInfo;\n\n\tstd::deque<FrameTicket> m_frameTicketsQueue;\n\tstd::vector<FrameTicket> m_frameTicketsInProcess;\n\tstd::map<int, NodePair> m_nodePairForOutputIndex;\n\n\tResamplingFilter m_chromaResamplingFilter;\n\tChromaPlacement m_chromaPlacement;\n\tdouble m_resamplingFilterParameterA;\n\tdouble m_resamplingFilterParameterB;\n\tYuvMatrixCoefficients m_yuvMatrix;\n\tDitherType m_ditherType;\n\n\tbool m_finalizing;\n};\n\n//==============================================================================\n\n#endif // VAPOURSYNTHSCRIPTPROCESSOR_H\n"
  },
  {
    "path": "common-src/vapoursynth/vs_pack_rgb.cpp",
    "content": "#include \"vs_pack_rgb.h\"\n#include \"../libp2p/p2p_api.h\"\n\n#include <VSHelper4.h>\n\n#include <vector>\n\nstruct PackData\n{\n    VSNode *rgbNode;\n    VSNode *outputNode;\n};\n\nvoid packFree(void *instanceData, [[maybe_unused]] VSCore *core, const VSAPI *vsapi)\n{\n    PackData *d = reinterpret_cast<PackData *>(instanceData);\n    vsapi->freeNode(d->rgbNode);\n    // The outputNode is freed somewhere else\n    // vsapi->freeNode(d->outputNode);\n    delete d;\n}\n\ntemplate <p2p_packing packing_fmt>\nconst VSFrame *packGetFrame(int n, int activationReason, void *instanceData, [[maybe_unused]] void **frameData, VSFrameContext *frameCtx, VSCore *core, const VSAPI *vsapi)\n{\n    PackData *d = reinterpret_cast<PackData *>(instanceData);\n    if (activationReason == arInitial)\n    {\n        vsapi->requestFrameFilter(n, d->outputNode, frameCtx);\n        vsapi->requestFrameFilter(n, d->rgbNode, frameCtx);\n    }\n    else if (activationReason == arAllFramesReady)\n    {\n        const VSFrame *srcFrame = vsapi->getFrameFilter(n, d->rgbNode, frameCtx);\n        VSVideoFormat frameFormat;\n        vsapi->getVideoFormatByID(&frameFormat, pfGray8, core);\n        int width = vsapi->getFrameWidth(srcFrame, 0);\n        int height = vsapi->getFrameHeight(srcFrame, 0);\n        VSFrame *dstFrame = vsapi->newVideoFrame(&frameFormat, width * 4, height, nullptr, core);\n\n        p2p_buffer_param p = {};\n        p.width = width;\n        p.height = height;\n        p.packing = packing_fmt;\n        for (int plane = 0; plane < 3; ++plane)\n        {\n            p.src[plane] = vsapi->getReadPtr(srcFrame, plane);\n            p.src_stride[plane] = vsapi->getStride(srcFrame, plane);\n        }\n        p.dst[0] = vsapi->getWritePtr(dstFrame, 0);\n        p.dst_stride[0] = vsapi->getStride(dstFrame, 0);\n        p2p_pack_frame(&p, P2P_ALPHA_SET_ONE);\n\n        VSMap *props = vsapi->getFramePropertiesRW(dstFrame);\n        vsapi->mapSetInt(props, \"PackingFormat\", static_cast<int64_t>(packing_fmt), maReplace);\n\n        const VSFrame *outputFrame = vsapi->getFrameFilter(n, d->outputNode, frameCtx);\n        vsapi->mapConsumeFrame(props, \"OutputFrame\", outputFrame, maReplace);\n        vsapi->freeFrame(srcFrame);\n        return dstFrame;\n    }\n    return nullptr;\n}\n\nVSNode *packRGBFilter(VSNode *rgbNode, VSNode *outputNode, bool use10bit, VSCore *core, const VSAPI *vsapi)\n{\n    VSVideoInfo vi = *vsapi->getVideoInfo(rgbNode);\n    vi.width *= 4;\n    vsapi->getVideoFormatByID(&vi.format, pfGray8, core);\n\n    PackData *d = new PackData{rgbNode, outputNode};\n\n    std::vector<VSFilterDependency> deps = {\n        {rgbNode, rpStrictSpatial},\n        {outputNode, rpStrictSpatial}};\n\n    if (use10bit)\n        return vsapi->createVideoFilter2(\"PackRGB30\", &vi, packGetFrame<p2p_rgb30>, packFree, fmParallel, deps.data(), deps.size(), d, core);\n    else\n        return vsapi->createVideoFilter2(\"PackRGB24\", &vi, packGetFrame<p2p_argb32>, packFree, fmParallel, deps.data(), deps.size(), d, core);\n}\n"
  },
  {
    "path": "common-src/vapoursynth/vs_pack_rgb.h",
    "content": "#ifndef VS_PACK_RGB_H_INCLUDED\n#define VS_PACK_RGB_H_INCLUDED\n\n#include <VapourSynth4.h>\n\nVSNode *packRGBFilter(VSNode *rgbNode, VSNode *outputNode, bool use10bit, VSCore *core, const VSAPI *vsapi);\n\n#endif\n"
  },
  {
    "path": "common-src/vapoursynth/vs_script_library.cpp",
    "content": "#include \"vs_script_library.h\"\n\n#include \"../settings/settings_manager_core.h\"\n#include \"../helpers.h\"\n\n#include <QSettings>\n#include <QProcess>\n#include <QProcessEnvironment>\n\n//==============================================================================\n\nvoid VS_CC vsMessageHandler(int a_msgType, const char * a_message,\n\tvoid * a_pUserData)\n{\n\tVSScriptLibrary * pVSScriptLibrary =\n\t\treinterpret_cast<VSScriptLibrary *>(a_pUserData);\n\tpVSScriptLibrary->handleVSMessage(a_msgType, a_message);\n}\n\n// END OF void VS_CC vsMessageHandler(int a_msgType, const char * a_message,\n//\t\tvoid * a_pUserData)\n//==============================================================================\n\nVSScriptLibrary::VSScriptLibrary(SettingsManagerCore * a_pSettingsManager,\n\tQObject * a_pParent):\n\tQObject(a_pParent)\n\t, m_pSettingsManager(a_pSettingsManager)\n\t, m_vsScriptLibrary(this)\n\t, m_initialized(false)\n\t, m_cpVSSAPI(nullptr)\n\t, m_cpVSAPI(nullptr)\n\t, m_VSAPIMajor(VSE_VS_API_VER_MAJOR)\n\t, m_VSAPIMinor(VSE_VS_API_VER_MINOR)\n\t, m_VSSAPIMajor(VSE_VSS_API_VER_MAJOR)\n\t, m_VSSAPIMinor(VSE_VSS_API_VER_MINOR)\n{\n\tQ_ASSERT(m_pSettingsManager);\n}\n\n// END OF VSScriptLibrary::VSScriptLibrary(\n//\t\tSettingsManagerCore * a_pSettingsManager, QObject * a_pParent)\n//==============================================================================\n\nVSScriptLibrary::~VSScriptLibrary()\n{\n\tm_VSCoreLogHandles.clear();\n\tfinalize();\n}\n\n// END OF VSScriptLibrary::~VSScriptLibrary()\n//==============================================================================\n\nbool VSScriptLibrary::initialize()\n{\n\tif(m_initialized)\n\t\treturn true;\n\n\tbool libraryInitialized = initLibrary2();\n\tif(!libraryInitialized)\n\t\treturn false;\n\n\tfor(; m_VSAPIMinor >= 0; --m_VSAPIMinor)\n\t{\n\t\tint apiVer = VS_MAKE_VERSION(m_VSAPIMajor, m_VSAPIMinor);\n\t\tm_cpVSAPI = m_cpVSSAPI->getVSAPI(apiVer);\n\t\tif(m_cpVSAPI)\n\t\t\tbreak;\n\t}\n\n\tif(!m_cpVSAPI)\n\t{\n\t\tQString errorString = tr(\"Failed to get VapourSynth API!\");\n\t\temit signalWriteLogMessage(mtCritical, errorString);\n\t\tfinalize();\n\t\treturn false;\n\t}\n\n\tm_initialized = true;\n\n\treturn true;\n}\n\n// END OF bool VSScriptLibrary::initialize()\n//==============================================================================\n\nbool VSScriptLibrary::finalize()\n{\n\tm_cpVSAPI = nullptr;\n\n\tfreeLibrary();\n\tm_initialized = false;\n\n\treturn true;\n}\n\n// END OF bool VSScriptLibrary::finalize()\n//==============================================================================\n\nbool VSScriptLibrary::isInitialized() const\n{\n\treturn m_initialized;\n}\n\n// END OF bool VSScriptLibrary::isInitialized() const\n//==============================================================================\n\nconst VSAPI * VSScriptLibrary::getVSAPI()\n{\n\tif(!initialize())\n\t\treturn nullptr;\n\n\treturn m_cpVSAPI;\n}\n\n// END OF const VSAPI * VSScriptLibrary::getVSAPI()\n//==============================================================================\n\nVSScript * VSScriptLibrary::createScript(VSCore * a_pCore)\n{\n\tif(!initialize())\n\t\treturn nullptr;\n\n\tVSScript * pScript = m_cpVSSAPI->createScript(a_pCore);\n\tif(pScript)\n\t\tm_cpVSSAPI->evalSetWorkingDir(pScript, 1);\n\n\treturn pScript;\n}\n\n// END OF VSScript * VSScriptLibrary::createScript()\n//==============================================================================\n\nint VSScriptLibrary::evaluateScript(VSScript * a_pScript,\n\tconst char * a_scriptText, const char * a_scriptFilename)\n{\n\n\tif(!initialize())\n\t\treturn 1;\n\n\treturn m_cpVSSAPI->evaluateBuffer(a_pScript, a_scriptText,\n\t\ta_scriptFilename);\n}\n\n// END OF int VSScriptLibrary::evaluateScript(VSScript * a_ppScript,\n//\t\tconst char * a_scriptText, const char * a_scriptFilename)\n//==============================================================================\n\nconst char * VSScriptLibrary::getError(VSScript * a_pScript)\n{\n\tif(!initialize())\n\t\treturn nullptr;\n\n\treturn m_cpVSSAPI->getError(a_pScript);\n}\n\n// END OF const char * VSScriptLibrary::getError(VSScript * a_pScript)\n//==============================================================================\n\nVSCore *VSScriptLibrary::createCore(int a_flag)\n{\n\tif(!initialize())\n\t\treturn nullptr;\n\n\tVSCore * pCore = m_cpVSAPI->createCore(a_flag);\n\tif(!pCore)\n\t{\n\t\tQString errorString = tr(\"Failed to get VapourSynth Core!\");\n\t\temit signalWriteLogMessage(mtCritical, errorString);\n\t\tfinalize();\n\t\treturn nullptr;\n\t}\n\n\tif(m_VSCoreLogHandles.find(pCore) == m_VSCoreLogHandles.end())\n\t\tm_VSCoreLogHandles[pCore] = m_cpVSAPI->addLogHandler(\n\t\t\tvsMessageHandler, nullptr, this, pCore);\n\n    return pCore;\n}\n\nstd::vector<int> VSScriptLibrary::getOutputIndices(VSScript *a_pScript) const\n{\n#if(VSSCRIPT_API_MAJOR == 4) && (VSSCRIPT_API_MINOR >= 2)\n\tif(m_initialized && a_pScript && vssVersionCompare(4, 2) >= 0)\n\t{\n\t\tint size = m_cpVSSAPI->getAvailableOutputNodes(a_pScript, 0, nullptr);\n\t\tif(size <= 0)\n\t\t\treturn std::vector<int>();\n\t\tstd::vector<int> idx(size);\n\t\tm_cpVSSAPI->getAvailableOutputNodes(a_pScript, size, idx.data());\n\t\treturn idx;\n\t}\n\telse\n\t\treturn std::vector<int>();\n#else\n\treturn std::vector<int>();\n#endif\n}\n\nVSNode * VSScriptLibrary::getOutput(VSScript * a_pScript, int a_index)\n{\n\tif(!initialize())\n\t\treturn nullptr;\n\n\treturn m_cpVSSAPI->getOutputNode(a_pScript, a_index);\n}\n\n// END OF VSNode * VSScriptLibrary::getOutput(VSScript * a_pScript,\n//\t\tint a_index)\n//==============================================================================\n\nbool VSScriptLibrary::freeScript(VSScript * a_pScript)\n{\n\tif(!initialize())\n\t\treturn false;\n\n\tm_cpVSSAPI->freeScript(a_pScript);\n\n\treturn true;\n}\n\nbool VSScriptLibrary::clearCoreCaches(VSCore * a_pCore)\n{\n#if(VAPOURSYNTH_API_MAJOR == 4) && (VAPOURSYNTH_API_MINOR >= 1)\n\tif(vsVersionCompare(4, 1) >= 0)\n\t{\n\t\tif(!m_initialized)\n\t\t\treturn false;\n\n\t\tm_cpVSAPI->clearCoreCaches(a_pCore);\n\t\treturn true;\n\t}\n#endif\n    return false;\n}\n\nQString VSScriptLibrary::VSAPIInfo()\n{\n\tif(!m_initialized)\n\t\treturn QString();\n    return QString(\"R%1.%2\").arg(m_VSAPIMajor).arg(m_VSAPIMinor);\n}\n\nQString VSScriptLibrary::VSSAPIInfo()\n{\n\tif(!m_initialized)\n\t\treturn QString();\n    return QString(\"R%1.%2\").arg(m_VSSAPIMajor).arg(m_VSSAPIMinor);\n}\n\n// END OF bool VSScriptLibrary::freeScript(VSScript * a_pScript)\n//==============================================================================\n\nbool VSScriptLibrary::initLibrary2()\n{\n\tif(m_vsScriptLibrary.isLoaded())\n\t{\n\t\tQ_ASSERT(vssGetAPI);\n\t\treturn true;\n\t}\n\n\tQString libraryName = \"vsscript\";\n\n#ifdef Q_OS_WIN\n\tQString libraryNameOld = \"vsscript\";\n\tQString libraryNameExt = \"vsscript.dll\";\n\tbool libraryName2CS = false;\n\tint libraryName2Chop = 4;\n#elif defined(Q_OS_MACOS)\n\tQString libraryNameOld = \"vapoursynth-script\";\n\tQString libraryNameExt = \"libvsscript.4.dylib\";\n\tbool libraryName2CS = true;\n\tint libraryName2Chop = 8;\n#else\n\tQString libraryNameOld = \"vapoursynth-script\";\n\tQString libraryNameExt = \"libvsscript.so.4\";\n\tbool libraryName2CS = true;\n\tint libraryName2Chop = 5;\n#endif\n\n\tQString libraryDir;\n\tQString libraryFullPath = QString();\n\tbool loaded = false;\n\n\tQString path = QString::fromLocal8Bit(qgetenv(\"PATH\"));\n\tQString path_backup = path;\n\n\tQFunctionPointer * ppGetAPI = (QFunctionPointer *)&vssGetAPI;\n\tQFunctionPointer * ppLastError = (QFunctionPointer *)&vssGetAPILastError;\n\n\tauto set_path = [&]()\n\t{\n#ifdef Q_OS_WIN\n\t\tpath = libraryDir + \";\" + path;\n\t\tqputenv(\"PATH\", path.toLocal8Bit());\n#endif\n\t};\n\n\tauto reset_path = [&]()\n\t{\n#ifdef Q_OS_WIN\n\t\tpath = path_backup;\n\t\tqputenv(\"PATH\", path.toLocal8Bit());\n#endif\n\t};\n\n\tauto load_vssapi = [&] (int max_minor_ver, int min_minor_ver)\n\t{\n\t\t*ppGetAPI = m_vsScriptLibrary.resolve(\"getVSScriptAPI\");\n\t\tif(!*ppGetAPI)\n\t\t\treturn;\n\t\tif(max_minor_ver >= 3)\n\t\t\t*ppLastError = m_vsScriptLibrary.resolve(\"getVSScriptAPILastError\");\n\t\tconst char * errVSSMsg = nullptr;\n\t\tfor(int vminor = max_minor_ver; vminor >= min_minor_ver; --vminor)\n\t\t{\n\t\t\tint apiVer = VS_MAKE_VERSION(m_VSSAPIMajor, vminor);\n\t\t\tm_cpVSSAPI = vssGetAPI(apiVer);\n\t\t\tif(m_cpVSSAPI)\n\t\t\t{\n\t\t\t\tm_VSSAPIMinor = vminor;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tif(vminor >= 3 && *ppLastError)\n\t\t\t{\n\t\t\t\tconst char * lastError = vssGetAPILastError();\n\t\t\t\tif(lastError && !errVSSMsg)\n\t\t\t\t\terrVSSMsg = lastError;\n\t\t\t}\n\t\t}\n\t\tif(m_cpVSSAPI)\n\t\t\treturn;\n\t\telse\n\t\t{\n\t\t\tQString errMsg = QString(\"Library found in %1\"\n\t\t\t\t\" but failed to get VSScript API!\").arg(libraryFullPath);\n\t\t\tif(errVSSMsg)\n\t\t\t\temit signalWriteLogMessage(mtWarning, QString(\"%1\\n%2\").arg(errMsg).arg(errVSSMsg));\n\t\t\telse\n\t\t\t\temit signalWriteLogMessage(mtWarning, errMsg);\n\t\t\treturn;\n\t\t}\n\t};\n\n\tauto load_from_list2 = [&] ()\n\t{\n\t\tQStringList librarySearchPaths =\n\t\t\tm_pSettingsManager->getVapourSynthLibraryPaths();\n\t\tfor(const QString & libPath : librarySearchPaths)\n\t\t{\n\t\t\tm_vsScriptLibrary.unload();\n\t\t\tlibraryDir = vsedit::resolvePathFromApplication(libPath);\n\t\t\tlibraryFullPath = libraryDir + QString(\"/\") + libraryName;\n\t\t\tm_vsScriptLibrary.setFileName(libraryFullPath);\n\t\t\tset_path();\n\t\t\tloaded = m_vsScriptLibrary.load();\n\t\t\treset_path();\n\t\t\tif(loaded)\n\t\t\t{\n\t\t\t\tload_vssapi(m_VSSAPIMinor, 3);\n\t\t\t\tloaded = m_cpVSSAPI != nullptr;\n\t\t\t}\n\t\t}\n\t};\n\n\tauto load_from_list = [&] ()\n\t{\n\t\tQStringList librarySearchPaths =\n\t\t\tm_pSettingsManager->getVapourSynthLibraryPaths();\n\t\tfor(const QString & libPath : librarySearchPaths)\n\t\t{\n\t\t\tm_vsScriptLibrary.unload();\n\t\t\tlibraryDir = vsedit::resolvePathFromApplication(libPath);\n\t\t\tlibraryFullPath = libraryDir + QString(\"/\") + libraryNameOld;\n\t\t\tm_vsScriptLibrary.setFileName(libraryFullPath);\n\t\t\tset_path();\n\t\t\tloaded = m_vsScriptLibrary.load();\n\t\t\treset_path();\n\t\t\tif(loaded)\n\t\t\t{\n\t\t\t\tload_vssapi(2, 0);\n\t\t\t\tloaded = m_cpVSSAPI != nullptr;\n\t\t\t}\n\t\t}\n\t};\n\n\tauto load_from_python = [&] ()\n\t{\n\t\tauto venv = qgetenv(\"VIRTUAL_ENV\");\n\t\tif(!venv.isEmpty())\n\t\t{\n\t\t\temit signalWriteLogMessage(mtInformation, QString(\n\t\t\t\t\"You are in a Python virtual environment with path %1\")\n\t\t\t\t.arg(QString::fromLocal8Bit(venv)));\n\t\t}\n\t\tQProcess vssProc;\n#ifdef Q_OS_WIN\n\t\tvssProc.startCommand(\"python -c \\\"import vapoursynth;\"\n#else\n\t\tvssProc.startCommand(\"/usr/bin/env python3 -c \\\"import vapoursynth;\"\n#endif\n\t\t\t\"print(vapoursynth.get_vsscript())\\\"\");\n\t\tif(vssProc.waitForFinished(3000))\n\t\t{\n\t\t\tQString ret = QString::fromLocal8Bit(\n\t\t\t\tvssProc.readAllStandardOutput()).trimmed();\n\t\t\tif(ret.count('\\n') == 0 && ret.endsWith(libraryNameExt,\n\t\t\t\tlibraryName2CS ? Qt::CaseSensitive : Qt::CaseInsensitive))\n\t\t\t{\n#ifdef Q_OS_WIN\n\t\t\t\tret.chop(libraryName2Chop);\n#endif\n\t\t\t\tlibraryFullPath = ret;\n\t\t\t}\n\t\t}\n\n\t\tif(libraryFullPath.isEmpty())\n\t\t\treturn;\n\n\t\tm_vsScriptLibrary.unload();\n\t\tm_vsScriptLibrary.setFileName(libraryFullPath);\n\t\tloaded = m_vsScriptLibrary.load();\n\n\t\tif(loaded)\n\t\t{\n\t\t\tload_vssapi(m_VSSAPIMinor, 3);\n\t\t\tloaded = m_cpVSSAPI != nullptr;\n\t\t}\n\t};\n\n\tauto load_from_env = [&] ()\n\t{\n\t\tauto envPath = qgetenv(\"VSSCRIPT_PATH\");\n\t\tif(!envPath.isEmpty())\n\t\t\tlibraryFullPath = QString::fromLocal8Bit(envPath);\n\n\t\tif(libraryFullPath.isEmpty())\n\t\t\treturn;\n\n\t\tm_vsScriptLibrary.unload();\n\t\tm_vsScriptLibrary.setFileName(libraryFullPath);\n\t\tloaded = m_vsScriptLibrary.load();\n\t\tif(loaded)\n\t\t{\n\t\t\tload_vssapi(m_VSSAPIMinor, 0);\n\t\t\tloaded = m_cpVSSAPI != nullptr;\n\t\t}\n\t};\n\n\tauto load_from_registry = [&] ()\n\t{\n#ifdef Q_OS_WIN\n\t\tQSettings settings(\"HKEY_LOCAL_MACHINE\\\\SOFTWARE\",\n\t\t\tQSettings::NativeFormat);\n\t\tlibraryFullPath =\n\t\t\tsettings.value(\"VapourSynth/VSScriptDLL\").toString();\n\n\t\tif(libraryFullPath.isEmpty())\n\t\t\treturn;\n\n\t\t\tm_vsScriptLibrary.unload();\n\t\tm_vsScriptLibrary.setFileName(libraryFullPath);\n\t\tloaded = m_vsScriptLibrary.load();\n\t\tif(loaded)\n\t\t{\n\t\t\tload_vssapi(m_VSSAPIMinor, 0);\n\t\t\tloaded = m_cpVSSAPI != nullptr;\n\t\t}\n#endif\n\t};\n\n\tauto load_from_path = [&]()\n\t{\n\t\tm_vsScriptLibrary.unload();\n\t\tm_vsScriptLibrary.setFileName(libraryNameOld);\n\t\tloaded = m_vsScriptLibrary.load();\n\t\tif(loaded)\n\t\t{\n\t\t\tload_vssapi(2, 0);\n\t\t\tloaded = m_cpVSSAPI != nullptr;\n\t\t}\n\t};\n\n\tif(m_pSettingsManager->getPreferVSLibrariesFromList())\n\t{\n\t\tif(!loaded) load_from_list2();\n\t\tif(!loaded) load_from_list();\n\t\tif(!loaded) load_from_python();\n\t\tif(!loaded) load_from_env();\n\t\tif(!loaded) load_from_registry();\n\t\tif(!loaded) load_from_path();\n\t}\n\telse\n\t{\n\t\tif(!loaded) load_from_python();\n\t\tif(!loaded) load_from_env();\n\t\tif(!loaded) load_from_list2();\n\t\tif(!loaded) load_from_list();\n\t\tif(!loaded) load_from_registry();\n\t\tif(!loaded) load_from_path();\n\t}\n\n\tif(!m_cpVSSAPI)\n\t{\n\t\tQString errorStr = QString(\"Failed to get VSScript API!\");\n\t\temit signalWriteLogMessage(mtCritical, errorStr);\n\t\tfreeLibrary();\n\t\treturn false;\n\t}\n\n\treturn true;\n}\n\n// END OF bool VSScriptLibrary::initLibrary2()\n//==============================================================================\n\nvoid VSScriptLibrary::freeLibrary()\n{\n\tvssGetAPI = nullptr;\n\n\tif(m_vsScriptLibrary.isLoaded())\n\t\tm_vsScriptLibrary.unload();\n}\n\n// END OF void VSScriptLibrary::freeLibrary()\n//==============================================================================\n\nvoid VSScriptLibrary::handleVSMessage(int a_messageType,\n\tconst QString & a_message)\n{\n\temit signalWriteLogMessage(a_messageType, a_message);\n}\n\n// END OF void VSScriptLibrary::handleVSMessage(int a_messageType,\n//\t\tconst QString & a_message)\n//==============================================================================\n"
  },
  {
    "path": "common-src/vapoursynth/vs_script_library.h",
    "content": "#ifndef VS_SCRIPT_LIBRARY_H_INCLUDED\n#define VS_SCRIPT_LIBRARY_H_INCLUDED\n\n#include \"../version_info.h\"\n#include <VSScript4.h>\n\n#include <QObject>\n#include <QLibrary>\n#include <map>\n#include <vector>\n\nclass SettingsManagerCore;\n\n//==============================================================================\n\ntypedef const VSSCRIPTAPI * (VS_CC * FNP_getVSSAPI)(int);\ntypedef const char * (VS_CC * FNP_getVSSAPILastError)();\n\n//==============================================================================\n\nclass VSScriptLibrary : public QObject\n{\n\tQ_OBJECT\n\npublic:\n\n\tVSScriptLibrary(SettingsManagerCore * a_pSettingsManager,\n\t\tQObject * a_pParent = nullptr);\n\n\tvirtual ~VSScriptLibrary();\n\n\tbool initialize();\n\n\tbool finalize();\n\n\tbool isInitialized() const;\n\n\tconst VSAPI * getVSAPI();\n\n\tVSScript * createScript(VSCore * a_pCore = nullptr);\n\n\tint evaluateScript(VSScript * a_pScript, const char * a_scriptText,\n\t\tconst char * a_scriptFilename);\n\n\tconst char * getError(VSScript * a_pScript);\n\n\tVSCore * createCore(int a_flag = 0);\n\n\t// Returns empty vector if not supported by API\n\tstd::vector<int> getOutputIndices(VSScript * a_pScript) const;\n\n\tVSNode * getOutput(VSScript * a_pScript, int a_index);\n\n\tbool freeScript(VSScript * a_pScript);\n\n\tbool clearCoreCaches(VSCore * a_pCore);\n\n\tQString VSAPIInfo();\n\tQString VSSAPIInfo();\n\nsignals:\n\n\tvoid signalWriteLogMessage(int a_messageType, const QString & a_message);\n\nprivate:\n\n\tbool initLibrary2(); // For VSScript API  4.3 and later\n\n\tvoid freeLibrary();\n\n\tvoid handleVSMessage(int a_messageType, const QString & a_message);\n\n\tfriend void VS_CC vsMessageHandler(int a_msgType,\n\t\tconst char * a_message, void * a_pUserData);\n\n\tSettingsManagerCore * m_pSettingsManager;\n\n\tQLibrary m_vsScriptLibrary;\n\n\tFNP_getVSSAPI vssGetAPI;\n\tFNP_getVSSAPILastError vssGetAPILastError;\n\n\tbool m_initialized;\n\n\tconst VSSCRIPTAPI * m_cpVSSAPI;\n\n\tconst VSAPI * m_cpVSAPI;\n\n\tstd::map<VSCore *, VSLogHandle *> m_VSCoreLogHandles;\n\n\tint m_VSAPIMajor;\n\tint m_VSAPIMinor;\n\tint m_VSSAPIMajor;\n\tint m_VSSAPIMinor;\n\n\tint vsVersionCompare(int a_major, int a_minor) const\n\t{\n\t\treturn version_compare(m_VSAPIMajor, m_VSAPIMinor, a_major, a_minor);\n\t}\n\n\tint vssVersionCompare(int a_major, int a_minor) const\n\t{\n\t\treturn version_compare(m_VSSAPIMajor, m_VSSAPIMinor, a_major, a_minor);\n\t}\n\n};\n\n//==============================================================================\n\n#endif // VS_SCRIPT_LIBRARY_H_INCLUDED\n"
  },
  {
    "path": "common-src/vapoursynth/vs_script_processor_structures.cpp",
    "content": "#include \"vs_script_processor_structures.h\"\n\n//==============================================================================\n\nFrame::Frame(int a_number, int a_outputIndex,\n\tconst VSFrame * a_cpOutputFrame,\n\tconst VSFrame * a_cpPreviewFrame):\n\t  number(a_number)\n\t, outputIndex(a_outputIndex)\n\t, cpOutputFrame(a_cpOutputFrame)\n\t, cpPreviewFrame(a_cpPreviewFrame)\n{\n}\n\nbool Frame::operator==(const Frame & a_other) const\n{\n\treturn ((number == a_other.number) && (outputIndex == a_other.outputIndex));\n}\n\n//==============================================================================\n\nFrameTicket::FrameTicket(int a_frameNumber, int a_outputIndex,\n\t\tVSNode * a_pOutputNode, bool a_needPreview,\n\t\tVSNode * a_pPreviewNode):\n\tframeNumber(a_frameNumber)\n\t, outputIndex(a_outputIndex)\n\t, pOutputNode(a_pOutputNode)\n\t, needPreview(a_needPreview)\n\t, pPreviewNode(a_pPreviewNode)\n\t, cpOutputFrame(nullptr)\n\t, cpPreviewFrame(nullptr)\n\t, discard(false)\n{\n}\n\n//==============================================================================\n\nbool FrameTicket::isComplete() const\n{\n\tbool complete = (cpOutputFrame != nullptr);\n\tif(needPreview)\n\t\tcomplete = complete && (cpPreviewFrame != nullptr);\n\treturn complete;\n}\n\n//==============================================================================\n\nNodePair::NodePair():\n\t  outputIndex(-1)\n\t, pOutputNode(nullptr)\n\t, pPreviewNode(nullptr)\n{\n}\n\n//==============================================================================\n\nNodePair::NodePair(int a_outputIndex, VSNode * a_pOutputNode,\n\tVSNode * a_pPreviewNode):\n\t  outputIndex(a_outputIndex)\n\t, pOutputNode(a_pOutputNode)\n\t, pPreviewNode(a_pPreviewNode)\n{\n}\n\n//==============================================================================\n\nbool NodePair::isNull() const\n{\n\treturn ((outputIndex == -1) && (pOutputNode == nullptr) &&\n\t\t(pPreviewNode == nullptr));\n}\n\n//==============================================================================\n\nbool NodePair::isValid() const\n{\n\treturn ((outputIndex >= 0) && (pOutputNode != nullptr) &&\n\t\t(pPreviewNode != nullptr));\n}\n\n//==============================================================================\n"
  },
  {
    "path": "common-src/vapoursynth/vs_script_processor_structures.h",
    "content": "#ifndef VS_SCRIPT_PROCESSOR_STRUCTURES_H_INCLUDED\n#define VS_SCRIPT_PROCESSOR_STRUCTURES_H_INCLUDED\n\n#include <VapourSynth4.h>\n\n//==============================================================================\n\nstruct Frame\n{\n\tint number;\n\tint outputIndex;\n\tconst VSFrame * cpOutputFrame;\n\tconst VSFrame * cpPreviewFrame;\n\n\tFrame(int a_number, int a_outputIndex,\n\t\tconst VSFrame * a_cpOutputFrame,\n\t\tconst VSFrame * a_cpPreviewFrame = nullptr);\n\tbool operator==(const Frame & a_other) const;\n};\n\n//==============================================================================\n\nstruct FrameTicket\n{\n\tint frameNumber;\n\tint outputIndex;\n\tVSNode * pOutputNode;\n\tbool needPreview;\n\tVSNode * pPreviewNode;\n\tconst VSFrame * cpOutputFrame;\n\tconst VSFrame * cpPreviewFrame;\n\tbool discard;\n\n\tFrameTicket(int a_frameNumber, int a_outputIndex,\n\t\tVSNode * a_pOutputNode, bool a_needPreview = false,\n\t\tVSNode * a_pPreviewNode = nullptr);\n\n\tbool isComplete() const;\n};\n\n//==============================================================================\n\nstruct NodePair\n{\n\tint outputIndex;\n\tVSNode * pOutputNode;\n\tVSNode * pPreviewNode;\n\n\tNodePair();\n\tNodePair(int a_outputIndex, VSNode * a_pOutputNode,\n\t\tVSNode * a_pPreviewNode);\n\n\tbool isNull() const;\n\tbool isValid() const;\n};\n\n//==============================================================================\n\n#endif // VS_SCRIPT_PROCESSOR_STRUCTURES_H_INCLUDED\n"
  },
  {
    "path": "common-src/vapoursynth/vs_set_matrix.cpp",
    "content": "#include \"vs_set_matrix.h\"\n\n#include <VSHelper4.h>\n#include <VSConstants4.h>\n\n#include <memory>\n#include <cstring>\n\nstruct setMatrixData\n{\n    VSNode *node;\n    VSVideoInfo vi;\n    int64_t matrix_in;\n};\n\nconst VSFrame * VS_CC setMatrixGetFrame(int n, int activationReason, void *instanceData, void **frameData, VSFrameContext *frameCtx, VSCore *core, const VSAPI *vsapi)\n{\n    setMatrixData *d = reinterpret_cast<setMatrixData *>(instanceData);\n    if (activationReason == arInitial)\n    {\n        vsapi->requestFrameFilter(n, d->node, frameCtx);\n    }\n    else if (activationReason == arAllFramesReady)\n    {\n        const VSFrame *src_frame = vsapi->getFrameFilter(n, d->node, frameCtx);\n\n        /* RGB: tag RGB matrix\n           YUV: if missing matrix, add it\n           GRAY: if having RGB matrix, drop it\n         */\n\n        const VSVideoFormat *vff = vsapi->getVideoFrameFormat(src_frame);\n\n        VSFrame *dst_frame = vsapi->copyFrame(src_frame, core);\n        vsapi->freeFrame(src_frame);\n        VSMap *props = vsapi->getFramePropertiesRW(dst_frame);\n\n        if (vff->colorFamily == cfRGB)\n        {\n            vsapi->mapSetInt(props, \"_Matrix\", VSC_MATRIX_RGB, maReplace);\n        }\n        else if (vff->colorFamily == cfYUV)\n        {\n            int err;\n\n            int64_t matrix = vsapi->mapGetInt(props, \"_Matrix\", 0, &err);\n            if (err)\n            {\n                vsapi->mapSetInt(props, \"_Matrix\", d->matrix_in, maReplace);\n            }\n        }\n        else\n        {\n            int err;\n\n            int64_t matrix = vsapi->mapGetInt(props, \"_Matrix\", 0, &err);\n            if (!err && matrix == 0)\n            {\n                vsapi->mapDeleteKey(props, \"_Matrix\");\n            }\n        }\n        return dst_frame;\n    }\n    return nullptr;\n}\n\nvoid VS_CC setMatrixFree(void *instanceData, VSCore *core, const VSAPI *vsapi)\n{\n    setMatrixData *d = reinterpret_cast<setMatrixData *>(instanceData);\n    vsapi->freeNode(d->node);\n    delete d;\n}\n\nvoid VS_CC setMatrixFilter(const VSMap *in, VSMap *out, VSCore *core, const VSAPI *vsapi)\n{\n    std::unique_ptr<setMatrixData> d(new setMatrixData());\n\n    d->node = vsapi->mapGetNode(in, \"clip\", 0, nullptr);\n    const VSVideoInfo *vi = vsapi->getVideoInfo(d->node);\n    d->vi = *vi;\n\n    int err;\n    d->matrix_in = vsapi->mapGetInt(in, \"matrix_in\", 0, &err);\n\n    VSFilterDependency deps[] = {{d->node, rpStrictSpatial}};\n\n    vsapi->createVideoFilter(out, \"SetMatrix\", &d->vi, setMatrixGetFrame, setMatrixFree, fmParallel, deps, 1, d.get(), core);\n\n    d.release();\n}\n"
  },
  {
    "path": "common-src/vapoursynth/vs_set_matrix.h",
    "content": "#ifndef VS_SET_MATRIX_H_INCLUDED\n#define VS_SET_MATRIX_H_INCLUDED\n\n#include <VapourSynth4.h>\n\nvoid VS_CC setMatrixFilter(const VSMap *in, VSMap *out, VSCore *core, const VSAPI *vsapi);\n\n#endif\n"
  },
  {
    "path": "common-src/version_info.cpp",
    "content": "#include \"version_info.h\"\n\n#include <iostream>\n\nvoid print_version()\n{\n\tstd::cerr << \"VapourSynth Editor \" << VSE_VERSION_STR << std::endl;\n}\n\nint version_compare(int major1, int minor1, int major2, int minor2)\n{\n\tif(major1 > major2)\n\t\treturn 1;\n\telse if(major1 < major2)\n\t\treturn -1;\n\telse if(minor1 > minor2)\n\t\treturn 1;\n\telse if(minor1 < minor2)\n\t\treturn -1;\n\telse\n\t\treturn 0;\n}\n"
  },
  {
    "path": "common-src/version_info.h",
    "content": "#ifndef VERSION_INFO_H_INCLUDED\n#define VERSION_INFO_H_INCLUDED\n\n#define VSE_VERSION_STR \"R19-mod-6.10\"\n\n#define VS_USE_LATEST_API\n#define VSE_VS_API_VER_MAJOR 4\n#define VSE_VS_API_VER_MINOR 2\n\n#define VSSCRIPT_USE_LATEST_API\n#define VSE_VSS_API_VER_MAJOR 4\n#define VSE_VSS_API_VER_MINOR 3\n\nvoid print_version();\n\nint version_compare(int major1, int minor1, int major2, int minor2);\n\n#endif\n"
  },
  {
    "path": "common-src/win32_console.cpp",
    "content": "#pragma comment (lib, \"kernel32.lib\")\n#pragma comment (lib, \"user32.lib\")\n#if defined(_WIN32)\n\n#include \"win32_console.h\"\n\nvoid AttachedConsole::init()\n{\n    if (console)\n        return;\n\n    if (!AllocConsole())\n        return;\n\n    console = GetConsoleWindow();\n    if (!console)\n        return;\n\n    freopen_s(&file, \"CONOUT$\", \"w\", stderr);\n    freopen_s(&file, \"CONOUT$\", \"w\", stdout);\n\n    HANDLE handle = GetStdHandle(STD_ERROR_HANDLE);\n    DWORD mode;\n    GetConsoleMode(handle, &mode);\n    mode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING;\n    mode |= DISABLE_NEWLINE_AUTO_RETURN;\n    SetConsoleMode(handle, mode);\n}\n\nAttachedConsole::AttachedConsole() : console(NULL), file(nullptr)\n{\n    init();\n    if (console)\n        ShowWindow(console, SW_HIDE);\n}\n\nbool AttachedConsole::visible()\n{\n    if (!console)\n        return false;\n\n    return IsWindowVisible(console);\n}\n\nvoid AttachedConsole::show()\n{\n    if (!console)\n    {\n        init();\n        if (!console)\n            return;\n    }\n\n    ShowWindow(console, SW_SHOWNOACTIVATE);\n}\n\nvoid AttachedConsole::hide()\n{\n    if (!console)\n        return;\n\n    clear();\n    ShowWindow(console, SW_HIDE);\n}\n\nvoid AttachedConsole::destroy()\n{\n    if (!console)\n        return;\n\n    clear();\n\n    FreeConsole();\n}\n\nvoid AttachedConsole::clear()\n{\n    std::wcerr.clear();\n    std::wcout.clear();\n    std::wclog.clear();\n    std::cerr.clear();\n    std::cout.clear();\n    std::clog.clear();\n\n    if (console)\n    {\n        SetConsoleTextAttribute(console, 0);\n    }\n}\n\n#endif\n"
  },
  {
    "path": "common-src/win32_console.h",
    "content": "#ifndef WIN32_CONSOLE_H_INCLUDED\n#define WIN32_CONSOLE_H_INCLUDED\n\n#if defined(_WIN32)\n#define NOMINMAX\n#define WIN32_LEAN_AND_MEAN\n#include \"Windows.h\"\n\n#include <iostream>\n\nclass AttachedConsole\n{\nprivate:\n    HWND console;\n    FILE *file;\n\n    void init();\n    void clear();\n\npublic:\n    AttachedConsole();\n\n    bool visible();\n    void show();\n    void hide();\n    void destroy();\n};\n\n#endif\n\n#endif\n"
  },
  {
    "path": "msvc/VapourSynthEditor.sln",
    "content": "﻿\nMicrosoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio Version 17\nVisualStudioVersion = 17.9.34728.123\nMinimumVisualStudioVersion = 10.0.40219.1\nProject(\"{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}\") = \"vsedit\", \"vsedit\\vsedit.vcxproj\", \"{CD54B5E3-31F8-49BC-9D02-E6E7B9D25FAD}\"\nEndProject\nProject(\"{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}\") = \"libp2p\", \"libp2p\\libp2p.vcxproj\", \"{DD503806-0462-4CFE-BC5D-6355CF100832}\"\nEndProject\nProject(\"{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}\") = \"vsedit-previewer\", \"vsedit-previewer\\vsedit-previewer.vcxproj\", \"{654CE67F-6EB3-4DBD-86F2-D3DB7081FA04}\"\nEndProject\nProject(\"{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}\") = \"vsedit-job-server\", \"vsedit-job-server\\vsedit-job-server.vcxproj\", \"{BF53C69D-89A2-40B4-977E-1C535B4C7EB8}\"\nEndProject\nProject(\"{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}\") = \"vsedit-job-server-watcher\", \"vsedit-job-server-watcher\\vsedit-job-server-watcher.vcxproj\", \"{1550A490-74AA-413F-97C4-AFFA1BB470C2}\"\nEndProject\nProject(\"{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}\") = \"vsedit-encode\", \"vsedit-encode\\vsedit-encode.vcxproj\", \"{FFEEADE6-3DBE-4371-B1BC-D67DC80FE0CF}\"\nEndProject\nGlobal\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n\t\tDebug|x64 = Debug|x64\n\t\tDebug|x86 = Debug|x86\n\t\tRelease|x64 = Release|x64\n\t\tRelease|x86 = Release|x86\n\tEndGlobalSection\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n\t\t{CD54B5E3-31F8-49BC-9D02-E6E7B9D25FAD}.Debug|x64.ActiveCfg = Debug|x64\n\t\t{CD54B5E3-31F8-49BC-9D02-E6E7B9D25FAD}.Debug|x64.Build.0 = Debug|x64\n\t\t{CD54B5E3-31F8-49BC-9D02-E6E7B9D25FAD}.Debug|x86.ActiveCfg = Debug|x64\n\t\t{CD54B5E3-31F8-49BC-9D02-E6E7B9D25FAD}.Debug|x86.Build.0 = Debug|x64\n\t\t{CD54B5E3-31F8-49BC-9D02-E6E7B9D25FAD}.Release|x64.ActiveCfg = Release|x64\n\t\t{CD54B5E3-31F8-49BC-9D02-E6E7B9D25FAD}.Release|x64.Build.0 = Release|x64\n\t\t{CD54B5E3-31F8-49BC-9D02-E6E7B9D25FAD}.Release|x86.ActiveCfg = Release|x64\n\t\t{CD54B5E3-31F8-49BC-9D02-E6E7B9D25FAD}.Release|x86.Build.0 = Release|x64\n\t\t{DD503806-0462-4CFE-BC5D-6355CF100832}.Debug|x64.ActiveCfg = Debug|x64\n\t\t{DD503806-0462-4CFE-BC5D-6355CF100832}.Debug|x64.Build.0 = Debug|x64\n\t\t{DD503806-0462-4CFE-BC5D-6355CF100832}.Debug|x86.ActiveCfg = Debug|Win32\n\t\t{DD503806-0462-4CFE-BC5D-6355CF100832}.Debug|x86.Build.0 = Debug|Win32\n\t\t{DD503806-0462-4CFE-BC5D-6355CF100832}.Release|x64.ActiveCfg = Release|x64\n\t\t{DD503806-0462-4CFE-BC5D-6355CF100832}.Release|x64.Build.0 = Release|x64\n\t\t{DD503806-0462-4CFE-BC5D-6355CF100832}.Release|x86.ActiveCfg = Release|Win32\n\t\t{DD503806-0462-4CFE-BC5D-6355CF100832}.Release|x86.Build.0 = Release|Win32\n\t\t{654CE67F-6EB3-4DBD-86F2-D3DB7081FA04}.Debug|x64.ActiveCfg = Debug|x64\n\t\t{654CE67F-6EB3-4DBD-86F2-D3DB7081FA04}.Debug|x64.Build.0 = Debug|x64\n\t\t{654CE67F-6EB3-4DBD-86F2-D3DB7081FA04}.Debug|x86.ActiveCfg = Debug|x64\n\t\t{654CE67F-6EB3-4DBD-86F2-D3DB7081FA04}.Debug|x86.Build.0 = Debug|x64\n\t\t{654CE67F-6EB3-4DBD-86F2-D3DB7081FA04}.Release|x64.ActiveCfg = Release|x64\n\t\t{654CE67F-6EB3-4DBD-86F2-D3DB7081FA04}.Release|x64.Build.0 = Release|x64\n\t\t{654CE67F-6EB3-4DBD-86F2-D3DB7081FA04}.Release|x86.ActiveCfg = Release|x64\n\t\t{654CE67F-6EB3-4DBD-86F2-D3DB7081FA04}.Release|x86.Build.0 = Release|x64\n\t\t{BF53C69D-89A2-40B4-977E-1C535B4C7EB8}.Debug|x64.ActiveCfg = Debug|x64\n\t\t{BF53C69D-89A2-40B4-977E-1C535B4C7EB8}.Debug|x64.Build.0 = Debug|x64\n\t\t{BF53C69D-89A2-40B4-977E-1C535B4C7EB8}.Debug|x86.ActiveCfg = Debug|x64\n\t\t{BF53C69D-89A2-40B4-977E-1C535B4C7EB8}.Debug|x86.Build.0 = Debug|x64\n\t\t{BF53C69D-89A2-40B4-977E-1C535B4C7EB8}.Release|x64.ActiveCfg = Release|x64\n\t\t{BF53C69D-89A2-40B4-977E-1C535B4C7EB8}.Release|x64.Build.0 = Release|x64\n\t\t{BF53C69D-89A2-40B4-977E-1C535B4C7EB8}.Release|x86.ActiveCfg = Release|x64\n\t\t{BF53C69D-89A2-40B4-977E-1C535B4C7EB8}.Release|x86.Build.0 = Release|x64\n\t\t{1550A490-74AA-413F-97C4-AFFA1BB470C2}.Debug|x64.ActiveCfg = Debug|x64\n\t\t{1550A490-74AA-413F-97C4-AFFA1BB470C2}.Debug|x64.Build.0 = Debug|x64\n\t\t{1550A490-74AA-413F-97C4-AFFA1BB470C2}.Debug|x86.ActiveCfg = Debug|x64\n\t\t{1550A490-74AA-413F-97C4-AFFA1BB470C2}.Debug|x86.Build.0 = Debug|x64\n\t\t{1550A490-74AA-413F-97C4-AFFA1BB470C2}.Release|x64.ActiveCfg = Release|x64\n\t\t{1550A490-74AA-413F-97C4-AFFA1BB470C2}.Release|x64.Build.0 = Release|x64\n\t\t{1550A490-74AA-413F-97C4-AFFA1BB470C2}.Release|x86.ActiveCfg = Release|x64\n\t\t{1550A490-74AA-413F-97C4-AFFA1BB470C2}.Release|x86.Build.0 = Release|x64\n\t\t{FFEEADE6-3DBE-4371-B1BC-D67DC80FE0CF}.Debug|x64.ActiveCfg = Debug|x64\n\t\t{FFEEADE6-3DBE-4371-B1BC-D67DC80FE0CF}.Debug|x64.Build.0 = Debug|x64\n\t\t{FFEEADE6-3DBE-4371-B1BC-D67DC80FE0CF}.Debug|x86.ActiveCfg = Debug|x64\n\t\t{FFEEADE6-3DBE-4371-B1BC-D67DC80FE0CF}.Debug|x86.Build.0 = Debug|x64\n\t\t{FFEEADE6-3DBE-4371-B1BC-D67DC80FE0CF}.Release|x64.ActiveCfg = Release|x64\n\t\t{FFEEADE6-3DBE-4371-B1BC-D67DC80FE0CF}.Release|x64.Build.0 = Release|x64\n\t\t{FFEEADE6-3DBE-4371-B1BC-D67DC80FE0CF}.Release|x86.ActiveCfg = Release|x64\n\t\t{FFEEADE6-3DBE-4371-B1BC-D67DC80FE0CF}.Release|x86.Build.0 = Release|x64\n\tEndGlobalSection\n\tGlobalSection(SolutionProperties) = preSolution\n\t\tHideSolutionNode = FALSE\n\tEndGlobalSection\n\tGlobalSection(ExtensibilityGlobals) = postSolution\n\t\tSolutionGuid = {B21A7A0A-C50F-4BF0-AD63-9DA782B23EEE}\n\tEndGlobalSection\nEndGlobal\n"
  },
  {
    "path": "msvc/VapourSynthEditor.vcxproj",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project DefaultTargets=\"Build\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <ItemGroup Label=\"ProjectConfigurations\">\n    <ProjectConfiguration Include=\"Debug|Win32\">\n      <Configuration>Debug</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Release|Win32\">\n      <Configuration>Release</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Debug|x64\">\n      <Configuration>Debug</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Release|x64\">\n      <Configuration>Release</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n\n  </ItemGroup>\n  <PropertyGroup Label=\"Globals\">\n    <VCProjectVersion>17.0</VCProjectVersion>\n    <Keyword>Win32Proj</Keyword>\n    <ProjectGuid>{0688c101-c065-46f9-a1ca-9e11280c2ace}</ProjectGuid>\n    <RootNamespace>VapourSynthEditor</RootNamespace>\n    <WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>\n  </PropertyGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.Default.props\" />\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\" Label=\"Configuration\">\n    <ConfigurationType>Application</ConfigurationType>\n    <UseDebugLibraries>true</UseDebugLibraries>\n    <PlatformToolset>v143</PlatformToolset>\n    <CharacterSet>Unicode</CharacterSet>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\" Label=\"Configuration\">\n    <ConfigurationType>Application</ConfigurationType>\n    <UseDebugLibraries>false</UseDebugLibraries>\n    <PlatformToolset>v143</PlatformToolset>\n    <WholeProgramOptimization>true</WholeProgramOptimization>\n    <CharacterSet>Unicode</CharacterSet>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\" Label=\"Configuration\">\n    <ConfigurationType>Application</ConfigurationType>\n    <UseDebugLibraries>true</UseDebugLibraries>\n    <PlatformToolset>v143</PlatformToolset>\n    <CharacterSet>Unicode</CharacterSet>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\" Label=\"Configuration\">\n    <ConfigurationType>Application</ConfigurationType>\n    <UseDebugLibraries>false</UseDebugLibraries>\n    <PlatformToolset>v143</PlatformToolset>\n    <WholeProgramOptimization>true</WholeProgramOptimization>\n    <CharacterSet>Unicode</CharacterSet>\n  </PropertyGroup>\n\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.props\" />\n  <ImportGroup Label=\"ExtensionSettings\">\n  </ImportGroup>\n  <ImportGroup Label=\"Shared\" >\n  </ImportGroup>\n    <ImportGroup Label=\"PropertySheets\" Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">\n      <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n    </ImportGroup>\n    <ImportGroup Label=\"PropertySheets\" Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">\n      <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n    </ImportGroup>\n    <ImportGroup Label=\"PropertySheets\" Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">\n      <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n    </ImportGroup>\n    <ImportGroup Label=\"PropertySheets\" Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">\n      <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n    </ImportGroup>\n\n  <PropertyGroup Label=\"UserMacros\" />\n\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">\n    <ClCompile>\n      <WarningLevel>Level3</WarningLevel>\n      <SDLCheck>true</SDLCheck>\n      <PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <ConformanceMode>true</ConformanceMode>\n    </ClCompile>\n    <Link>\n      <SubSystem>Console</SubSystem>\n      <GenerateDebugInformation>true</GenerateDebugInformation>\n    </Link>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">\n    <ClCompile>\n      <WarningLevel>Level3</WarningLevel>\n      <FunctionLevelLinking>true</FunctionLevelLinking>\n      <IntrinsicFunctions>true</IntrinsicFunctions>\n      <SDLCheck>true</SDLCheck>\n      <PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <ConformanceMode>true</ConformanceMode>\n    </ClCompile>\n    <Link>\n      <SubSystem>Console</SubSystem>\n      <EnableCOMDATFolding>true</EnableCOMDATFolding>\n      <OptimizeReferences>true</OptimizeReferences>\n      <GenerateDebugInformation>true</GenerateDebugInformation>\n    </Link>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">\n    <ClCompile>\n      <WarningLevel>Level3</WarningLevel>\n      <SDLCheck>true</SDLCheck>\n      <PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <ConformanceMode>true</ConformanceMode>\n    </ClCompile>\n    <Link>\n      <SubSystem>Console</SubSystem>\n      <GenerateDebugInformation>true</GenerateDebugInformation>\n    </Link>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">\n    <ClCompile>\n      <WarningLevel>Level3</WarningLevel>\n      <FunctionLevelLinking>true</FunctionLevelLinking>\n      <IntrinsicFunctions>true</IntrinsicFunctions>\n      <SDLCheck>true</SDLCheck>\n      <PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <ConformanceMode>true</ConformanceMode>\n    </ClCompile>\n    <Link>\n      <SubSystem>Console</SubSystem>\n      <EnableCOMDATFolding>true</EnableCOMDATFolding>\n      <OptimizeReferences>true</OptimizeReferences>\n      <GenerateDebugInformation>true</GenerateDebugInformation>\n    </Link>\n  </ItemDefinitionGroup>\n\n  <ItemGroup></ItemGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.targets\" />\n  <ImportGroup Label=\"ExtensionTargets\">\n  </ImportGroup>\n</Project>\n"
  },
  {
    "path": "msvc/VapourSynthEditor.vcxproj.filters",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project ToolsVersion=\"4.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <ItemGroup>\n    <Filter Include=\"Source Files\">\n      <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>\n      <Extensions>cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx</Extensions>\n    </Filter>\n    <Filter Include=\"Header Files\">\n      <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>\n      <Extensions>h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd</Extensions>\n    </Filter>\n    <Filter Include=\"Resource Files\">\n      <UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>\n      <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>\n    </Filter>\n  </ItemGroup>\n</Project>"
  },
  {
    "path": "msvc/libp2p/libp2p.vcxproj",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project DefaultTargets=\"Build\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <ItemGroup Label=\"ProjectConfigurations\">\n    <ProjectConfiguration Include=\"Debug|Win32\">\n      <Configuration>Debug</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Release|Win32\">\n      <Configuration>Release</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Debug|x64\">\n      <Configuration>Debug</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Release|x64\">\n      <Configuration>Release</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n  </ItemGroup>\n  <PropertyGroup Label=\"Globals\">\n    <VCProjectVersion>17.0</VCProjectVersion>\n    <Keyword>Win32Proj</Keyword>\n    <ProjectGuid>{dd503806-0462-4cfe-bc5d-6355cf100832}</ProjectGuid>\n    <RootNamespace>libp2p</RootNamespace>\n    <WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>\n  </PropertyGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.Default.props\" />\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\" Label=\"Configuration\">\n    <ConfigurationType>Application</ConfigurationType>\n    <UseDebugLibraries>true</UseDebugLibraries>\n    <PlatformToolset>v143</PlatformToolset>\n    <CharacterSet>Unicode</CharacterSet>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\" Label=\"Configuration\">\n    <ConfigurationType>Application</ConfigurationType>\n    <UseDebugLibraries>false</UseDebugLibraries>\n    <PlatformToolset>v143</PlatformToolset>\n    <WholeProgramOptimization>true</WholeProgramOptimization>\n    <CharacterSet>Unicode</CharacterSet>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\" Label=\"Configuration\">\n    <ConfigurationType>Application</ConfigurationType>\n    <UseDebugLibraries>true</UseDebugLibraries>\n    <PlatformToolset>v143</PlatformToolset>\n    <CharacterSet>Unicode</CharacterSet>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\" Label=\"Configuration\">\n    <ConfigurationType>StaticLibrary</ConfigurationType>\n    <UseDebugLibraries>false</UseDebugLibraries>\n    <PlatformToolset>v143</PlatformToolset>\n    <WholeProgramOptimization>true</WholeProgramOptimization>\n    <CharacterSet>Unicode</CharacterSet>\n  </PropertyGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.props\" />\n  <ImportGroup Label=\"ExtensionSettings\">\n  </ImportGroup>\n  <ImportGroup Label=\"Shared\">\n  </ImportGroup>\n  <ImportGroup Label=\"PropertySheets\" Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <ImportGroup Label=\"PropertySheets\" Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <ImportGroup Label=\"PropertySheets\" Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <ImportGroup Label=\"PropertySheets\" Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <PropertyGroup Label=\"UserMacros\" />\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">\n    <ClCompile>\n      <WarningLevel>Level3</WarningLevel>\n      <SDLCheck>true</SDLCheck>\n      <PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <ConformanceMode>true</ConformanceMode>\n    </ClCompile>\n    <Link>\n      <SubSystem>Console</SubSystem>\n      <GenerateDebugInformation>true</GenerateDebugInformation>\n    </Link>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">\n    <ClCompile>\n      <WarningLevel>Level3</WarningLevel>\n      <FunctionLevelLinking>true</FunctionLevelLinking>\n      <IntrinsicFunctions>true</IntrinsicFunctions>\n      <SDLCheck>true</SDLCheck>\n      <PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <ConformanceMode>true</ConformanceMode>\n    </ClCompile>\n    <Link>\n      <SubSystem>Console</SubSystem>\n      <EnableCOMDATFolding>true</EnableCOMDATFolding>\n      <OptimizeReferences>true</OptimizeReferences>\n      <GenerateDebugInformation>true</GenerateDebugInformation>\n    </Link>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">\n    <ClCompile>\n      <WarningLevel>Level3</WarningLevel>\n      <SDLCheck>true</SDLCheck>\n      <PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <ConformanceMode>true</ConformanceMode>\n    </ClCompile>\n    <Link>\n      <SubSystem>Console</SubSystem>\n      <GenerateDebugInformation>true</GenerateDebugInformation>\n    </Link>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">\n    <ClCompile>\n      <WarningLevel>Level3</WarningLevel>\n      <FunctionLevelLinking>true</FunctionLevelLinking>\n      <IntrinsicFunctions>true</IntrinsicFunctions>\n      <SDLCheck>true</SDLCheck>\n      <PreprocessorDefinitions>P2P_SIMD;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <ConformanceMode>true</ConformanceMode>\n    </ClCompile>\n    <Link>\n      <SubSystem>Console</SubSystem>\n      <EnableCOMDATFolding>true</EnableCOMDATFolding>\n      <OptimizeReferences>true</OptimizeReferences>\n      <GenerateDebugInformation>true</GenerateDebugInformation>\n    </Link>\n  </ItemDefinitionGroup>\n  <ItemGroup>\n    <ClInclude Include=\"..\\..\\common-src\\libp2p\\p2p.h\" />\n    <ClInclude Include=\"..\\..\\common-src\\libp2p\\p2p_api.h\" />\n    <ClInclude Include=\"..\\..\\common-src\\libp2p\\simd\\cpuinfo_x86.h\" />\n    <ClInclude Include=\"..\\..\\common-src\\libp2p\\simd\\p2p_simd.h\" />\n  </ItemGroup>\n  <ItemGroup>\n    <ClCompile Include=\"..\\..\\common-src\\libp2p\\p2p_api.cpp\" />\n    <ClCompile Include=\"..\\..\\common-src\\libp2p\\simd\\cpuinfo_x86.cpp\" />\n    <ClCompile Include=\"..\\..\\common-src\\libp2p\\simd\\p2p_simd.cpp\" />\n    <ClCompile Include=\"..\\..\\common-src\\libp2p\\simd\\p2p_sse41.cpp\" />\n    <ClCompile Include=\"..\\..\\common-src\\libp2p\\v210.cpp\" />\n  </ItemGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.targets\" />\n  <ImportGroup Label=\"ExtensionTargets\">\n  </ImportGroup>\n</Project>"
  },
  {
    "path": "msvc/libp2p/libp2p.vcxproj.filters",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project ToolsVersion=\"4.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <ItemGroup>\n    <Filter Include=\"Source Files\">\n      <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>\n      <Extensions>cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx</Extensions>\n    </Filter>\n    <Filter Include=\"Header Files\">\n      <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>\n      <Extensions>h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd</Extensions>\n    </Filter>\n    <Filter Include=\"Resource Files\">\n      <UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>\n      <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>\n    </Filter>\n  </ItemGroup>\n  <ItemGroup>\n    <ClInclude Include=\"..\\..\\common-src\\libp2p\\p2p.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\common-src\\libp2p\\p2p_api.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\common-src\\libp2p\\simd\\cpuinfo_x86.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\common-src\\libp2p\\simd\\p2p_simd.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n  </ItemGroup>\n  <ItemGroup>\n    <ClCompile Include=\"..\\..\\common-src\\libp2p\\p2p_api.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\common-src\\libp2p\\v210.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\common-src\\libp2p\\simd\\cpuinfo_x86.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\common-src\\libp2p\\simd\\p2p_simd.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\common-src\\libp2p\\simd\\p2p_sse41.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n  </ItemGroup>\n</Project>"
  },
  {
    "path": "msvc/vsedit/resource.h",
    "content": "//{{NO_DEPENDENCIES}}\n// Microsoft Visual C++ generated include file.\n// Used by vsedit.rc\n//\n#define IDI_ICON1                       101\n\n// Next default values for new objects\n// \n#ifdef APSTUDIO_INVOKED\n#ifndef APSTUDIO_READONLY_SYMBOLS\n#define _APS_NEXT_RESOURCE_VALUE        102\n#define _APS_NEXT_COMMAND_VALUE         40001\n#define _APS_NEXT_CONTROL_VALUE         1001\n#define _APS_NEXT_SYMED_VALUE           101\n#endif\n#endif\n"
  },
  {
    "path": "msvc/vsedit/vsedit.vcxproj",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project DefaultTargets=\"Build\" ToolsVersion=\"17.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <ItemGroup Label=\"ProjectConfigurations\">\n    <ProjectConfiguration Include=\"Debug|x64\">\n      <Configuration>Debug</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Release|x64\">\n      <Configuration>Release</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n  </ItemGroup>\n  <PropertyGroup Label=\"Globals\">\n    <ProjectGuid>{CD54B5E3-31F8-49BC-9D02-E6E7B9D25FAD}</ProjectGuid>\n    <Keyword>QtVS_v304</Keyword>\n    <WindowsTargetPlatformVersion Condition=\"'$(Configuration)|$(Platform)' == 'Debug|x64'\">10.0.22621.0</WindowsTargetPlatformVersion>\n    <WindowsTargetPlatformVersion Condition=\"'$(Configuration)|$(Platform)' == 'Release|x64'\">10.0</WindowsTargetPlatformVersion>\n    <QtMsBuild Condition=\"'$(QtMsBuild)'=='' OR !Exists('$(QtMsBuild)\\qt.targets')\">$(MSBuildProjectDirectory)\\QtMsBuild</QtMsBuild>\n  </PropertyGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.Default.props\" />\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)' == 'Debug|x64'\" Label=\"Configuration\">\n    <ConfigurationType>Application</ConfigurationType>\n    <PlatformToolset>v143</PlatformToolset>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)' == 'Release|x64'\" Label=\"Configuration\">\n    <ConfigurationType>Application</ConfigurationType>\n    <PlatformToolset>v143</PlatformToolset>\n    <WholeProgramOptimization>true</WholeProgramOptimization>\n  </PropertyGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.props\" />\n  <ImportGroup Condition=\"Exists('$(QtMsBuild)\\qt_defaults.props')\">\n    <Import Project=\"$(QtMsBuild)\\qt_defaults.props\" />\n  </ImportGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)' == 'Debug|x64'\" Label=\"QtSettings\">\n    <QtInstall>C:\\Qt\\6.7.2\\msvc2019_64</QtInstall>\n    <QtModules>\n    </QtModules>\n    <QtBuildConfig>debug</QtBuildConfig>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)' == 'Release|x64'\" Label=\"QtSettings\">\n    <QtInstall>C:\\Qt\\6.7.2\\msvc2019_64</QtInstall>\n    <QtModules>core;gui;multimedia;widgets</QtModules>\n    <QtBuildConfig>release</QtBuildConfig>\n    <QtDeploy>true</QtDeploy>\n  </PropertyGroup>\n  <Target Name=\"QtMsBuildNotFound\" BeforeTargets=\"CustomBuild;ClCompile\" Condition=\"!Exists('$(QtMsBuild)\\qt.targets') or !Exists('$(QtMsBuild)\\qt.props')\">\n    <Message Importance=\"High\" Text=\"QtMsBuild: could not locate qt.targets, qt.props; project may not build correctly.\" />\n  </Target>\n  <ImportGroup Label=\"ExtensionSettings\" />\n  <ImportGroup Label=\"Shared\" />\n  <ImportGroup Label=\"PropertySheets\" Condition=\"'$(Configuration)|$(Platform)' == 'Debug|x64'\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n    <Import Project=\"$(QtMsBuild)\\Qt.props\" />\n  </ImportGroup>\n  <ImportGroup Label=\"PropertySheets\" Condition=\"'$(Configuration)|$(Platform)' == 'Release|x64'\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n    <Import Project=\"$(QtMsBuild)\\Qt.props\" />\n  </ImportGroup>\n  <PropertyGroup Label=\"UserMacros\" />\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)' == 'Debug|x64'\">\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)' == 'Release|x64'\">\n    <IncludePath>C:\\Program Files\\VapourSynth\\sdk\\include;$(IncludePath)</IncludePath>\n  </PropertyGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">\n    <QtMoc>\n      <QtMocDir>..\\..\\vsedit\\generated\\moc</QtMocDir>\n    </QtMoc>\n    <QtRcc>\n      <QtRccDir>..\\..\\vsedit\\generated\\rcc</QtRccDir>\n    </QtRcc>\n    <QtUic>\n      <QtUicDir>..\\..\\vsedit\\generated\\ui</QtUicDir>\n    </QtUic>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)' == 'Debug|x64'\" Label=\"Configuration\">\n    <ClCompile>\n      <TreatWChar_tAsBuiltInType>true</TreatWChar_tAsBuiltInType>\n      <MultiProcessorCompilation>true</MultiProcessorCompilation>\n      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>\n      <Optimization>Disabled</Optimization>\n    </ClCompile>\n    <Link>\n      <SubSystem>Windows</SubSystem>\n      <GenerateDebugInformation>true</GenerateDebugInformation>\n    </Link>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)' == 'Release|x64'\" Label=\"Configuration\">\n    <ClCompile>\n      <TreatWChar_tAsBuiltInType>true</TreatWChar_tAsBuiltInType>\n      <MultiProcessorCompilation>true</MultiProcessorCompilation>\n      <DebugInformationFormat>None</DebugInformationFormat>\n      <Optimization>MaxSpeed</Optimization>\n    </ClCompile>\n    <Link>\n      <SubSystem>Windows</SubSystem>\n      <GenerateDebugInformation>false</GenerateDebugInformation>\n    </Link>\n  </ItemDefinitionGroup>\n  <ItemGroup>\n    <ProjectReference Include=\"..\\libp2p\\libp2p.vcxproj\">\n      <Project>{dd503806-0462-4cfe-bc5d-6355cf100832}</Project>\n    </ProjectReference>\n  </ItemGroup>\n  <ItemGroup>\n    <QtUic Include=\"..\\..\\common-src\\log\\styled_log_view_settings_dialog.ui\" />\n    <QtUic Include=\"..\\..\\vsedit\\src\\frame_consumers\\benchmark_dialog.ui\" />\n    <QtUic Include=\"..\\..\\vsedit\\src\\frame_consumers\\encode_dialog.ui\" />\n    <QtUic Include=\"..\\..\\vsedit\\src\\main_window.ui\" />\n    <QtUic Include=\"..\\..\\vsedit\\src\\preview\\preview_advanced_settings_dialog.ui\" />\n    <QtUic Include=\"..\\..\\vsedit\\src\\preview\\preview_dialog.ui\" />\n    <QtUic Include=\"..\\..\\vsedit\\src\\script_status_bar_widget\\script_status_bar_widget.ui\" />\n    <QtUic Include=\"..\\..\\vsedit\\src\\script_templates\\templates_dialog.ui\" />\n    <QtUic Include=\"..\\..\\vsedit\\src\\settings\\settings_dialog.ui\" />\n  </ItemGroup>\n  <ItemGroup>\n    <QtMoc Include=\"..\\..\\vsedit\\src\\vapoursynth\\vs_script_processor_dialog.h\" />\n  </ItemGroup>\n  <ItemGroup>\n    <QtMoc Include=\"..\\..\\vsedit\\src\\vapoursynth\\vapoursynth_plugins_manager.h\" />\n  </ItemGroup>\n  <ItemGroup>\n    <ClInclude Include=\"..\\..\\common-src\\chrono.h\" />\n    <ClInclude Include=\"..\\..\\common-src\\settings\\settings_definitions_core.h\" />\n    <ClInclude Include=\"resource.h\" />\n    <QtMoc Include=\"..\\..\\common-src\\frame_header_writers\\frame_header_writer_y4m.h\" />\n    <QtMoc Include=\"..\\..\\common-src\\frame_header_writers\\frame_header_writer_null.h\" />\n    <QtMoc Include=\"..\\..\\common-src\\frame_header_writers\\frame_header_writer.h\" />\n    <ClInclude Include=\"..\\..\\common-src\\helpers.h\" />\n    <ClInclude Include=\"..\\..\\common-src\\helpers_vs.h\" />\n    <ClInclude Include=\"..\\..\\common-src\\jobs\\job_variables.h\" />\n    <QtMoc Include=\"..\\..\\common-src\\jobs\\job.h\" />\n    <ClInclude Include=\"..\\..\\common-src\\log\\styled_log_view_core.h\" />\n    <ClInclude Include=\"..\\..\\common-src\\log\\styled_log_view_structures.h\" />\n    <ClInclude Include=\"..\\..\\common-src\\log\\vs_editor_log_definitions.h\" />\n    <QtMoc Include=\"..\\..\\common-src\\log\\vs_editor_log.h\" />\n    <QtMoc Include=\"..\\..\\common-src\\log\\styled_log_view_settings_dialog.h\" />\n    <QtMoc Include=\"..\\..\\common-src\\log\\styled_log_view.h\" />\n    <QtMoc Include=\"..\\..\\common-src\\log\\log_styles_model.h\" />\n    <ClInclude Include=\"..\\..\\common-src\\settings\\settings_definitions.h\" />\n    <ClInclude Include=\"..\\..\\common-src\\settings\\settings_manager.h\" />\n    <ClInclude Include=\"..\\..\\common-src\\settings\\settings_manager_core.h\" />\n    <QtMoc Include=\"..\\..\\common-src\\timeline_slider\\timeline_slider.h\" />\n    <ClInclude Include=\"..\\..\\common-src\\vapoursynth\\vs_pack_rgb.h\" />\n    <ClInclude Include=\"..\\..\\common-src\\vapoursynth\\vs_script_processor_structures.h\" />\n    <ClInclude Include=\"..\\..\\common-src\\vapoursynth\\vs_set_matrix.h\" />\n    <QtMoc Include=\"..\\..\\common-src\\vapoursynth\\vs_script_library.h\" />\n    <QtMoc Include=\"..\\..\\common-src\\vapoursynth\\vapoursynth_script_processor.h\" />\n    <ClInclude Include=\"..\\..\\common-src\\version_info.h\" />\n    <ClInclude Include=\"..\\..\\common-src\\win32_console.h\" />\n    <QtMoc Include=\"..\\..\\vsedit\\src\\frame_consumers\\benchmark_dialog.h\" />\n    <QtMoc Include=\"..\\..\\vsedit\\src\\frame_consumers\\encode_dialog.h\" />\n    <QtMoc Include=\"..\\..\\vsedit\\src\\job_server_watcher_socket.h\" />\n    <QtMoc Include=\"..\\..\\vsedit\\src\\main_window.h\" />\n    <QtMoc Include=\"..\\..\\vsedit\\src\\preview\\preview_advanced_settings_dialog.h\" />\n    <QtMoc Include=\"..\\..\\vsedit\\src\\preview\\preview_area.h\" />\n    <QtMoc Include=\"..\\..\\vsedit\\src\\preview\\preview_dialog.h\" />\n    <ClInclude Include=\"..\\..\\vsedit\\src\\preview\\scroll_navigator.h\" />\n    <ClInclude Include=\"..\\..\\vsedit\\src\\preview\\zoom_ratio_spinbox.h\" />\n    <ClInclude Include=\"..\\..\\vsedit\\src\\script_editor\\number_matcher.h\" />\n    <QtMoc Include=\"..\\..\\vsedit\\src\\script_editor\\script_completer_model.h\" />\n    <QtMoc Include=\"..\\..\\vsedit\\src\\script_editor\\script_completer.h\" />\n    <QtMoc Include=\"..\\..\\vsedit\\src\\script_editor\\syntax_highlighter.h\" />\n    <QtMoc Include=\"..\\..\\vsedit\\src\\script_editor\\script_editor.h\" />\n    <QtMoc Include=\"..\\..\\vsedit\\src\\script_status_bar_widget\\script_status_bar_widget.h\" />\n    <QtMoc Include=\"..\\..\\vsedit\\src\\script_templates\\templates_dialog.h\" />\n    <QtMoc Include=\"..\\..\\vsedit\\src\\script_templates\\drop_file_category_model.h\" />\n    <QtMoc Include=\"..\\..\\vsedit\\src\\settings\\item_delegate_for_hotkey.h\" />\n    <QtMoc Include=\"..\\..\\vsedit\\src\\settings\\clearable_key_sequence_editor.h\" />\n    <QtMoc Include=\"..\\..\\vsedit\\src\\settings\\actions_hotkey_edit_model.h\" />\n    <QtMoc Include=\"..\\..\\vsedit\\src\\settings\\settings_dialog.h\" />\n    <QtMoc Include=\"..\\..\\vsedit\\src\\settings\\theme_elements_model.h\" />\n    <ClInclude Include=\"..\\..\\vsedit\\src\\vapoursynth\\vs_plugin_data.h\" />\n  </ItemGroup>\n  <ItemGroup>\n    <ClCompile Include=\"..\\..\\common-src\\frame_header_writers\\frame_header_writer.cpp\" />\n    <ClCompile Include=\"..\\..\\common-src\\frame_header_writers\\frame_header_writer_null.cpp\" />\n    <ClCompile Include=\"..\\..\\common-src\\frame_header_writers\\frame_header_writer_y4m.cpp\" />\n    <ClCompile Include=\"..\\..\\common-src\\helpers.cpp\" />\n    <ClCompile Include=\"..\\..\\common-src\\jobs\\job.cpp\" />\n    <ClCompile Include=\"..\\..\\common-src\\jobs\\job_variables.cpp\" />\n    <ClCompile Include=\"..\\..\\common-src\\log\\log_styles_model.cpp\" />\n    <ClCompile Include=\"..\\..\\common-src\\log\\styled_log_view.cpp\" />\n    <ClCompile Include=\"..\\..\\common-src\\log\\styled_log_view_core.cpp\" />\n    <ClCompile Include=\"..\\..\\common-src\\log\\styled_log_view_settings_dialog.cpp\" />\n    <ClCompile Include=\"..\\..\\common-src\\log\\styled_log_view_structures.cpp\" />\n    <ClCompile Include=\"..\\..\\common-src\\log\\vs_editor_log.cpp\" />\n    <ClCompile Include=\"..\\..\\common-src\\log\\vs_editor_log_definitions.cpp\" />\n    <ClCompile Include=\"..\\..\\common-src\\settings\\settings_definitions.cpp\" />\n    <ClCompile Include=\"..\\..\\common-src\\settings\\settings_definitions_core.cpp\" />\n    <ClCompile Include=\"..\\..\\common-src\\settings\\settings_manager.cpp\" />\n    <ClCompile Include=\"..\\..\\common-src\\settings\\settings_manager_core.cpp\" />\n    <ClCompile Include=\"..\\..\\common-src\\timeline_slider\\timeline_slider.cpp\" />\n    <ClCompile Include=\"..\\..\\common-src\\vapoursynth\\vapoursynth_script_processor.cpp\" />\n    <ClCompile Include=\"..\\..\\common-src\\vapoursynth\\vs_pack_rgb.cpp\" />\n    <ClCompile Include=\"..\\..\\common-src\\vapoursynth\\vs_script_library.cpp\" />\n    <ClCompile Include=\"..\\..\\common-src\\vapoursynth\\vs_script_processor_structures.cpp\" />\n    <ClCompile Include=\"..\\..\\common-src\\vapoursynth\\vs_set_matrix.cpp\" />\n    <ClCompile Include=\"..\\..\\common-src\\version_info.cpp\" />\n    <ClCompile Include=\"..\\..\\common-src\\win32_console.cpp\" />\n    <ClCompile Include=\"..\\..\\vsedit\\src\\frame_consumers\\benchmark_dialog.cpp\" />\n    <ClCompile Include=\"..\\..\\vsedit\\src\\frame_consumers\\encode_dialog.cpp\" />\n    <ClCompile Include=\"..\\..\\vsedit\\src\\job_server_watcher_socket.cpp\" />\n    <ClCompile Include=\"..\\..\\vsedit\\src\\main.cpp\" />\n    <ClCompile Include=\"..\\..\\vsedit\\src\\main_window.cpp\" />\n    <ClCompile Include=\"..\\..\\vsedit\\src\\preview\\preview_advanced_settings_dialog.cpp\" />\n    <ClCompile Include=\"..\\..\\vsedit\\src\\preview\\preview_area.cpp\" />\n    <ClCompile Include=\"..\\..\\vsedit\\src\\preview\\preview_dialog.cpp\" />\n    <ClCompile Include=\"..\\..\\vsedit\\src\\preview\\scroll_navigator.cpp\" />\n    <ClCompile Include=\"..\\..\\vsedit\\src\\preview\\zoom_ratio_spinbox.cpp\" />\n    <ClCompile Include=\"..\\..\\vsedit\\src\\script_editor\\number_matcher.cpp\" />\n    <ClCompile Include=\"..\\..\\vsedit\\src\\script_editor\\script_completer.cpp\" />\n    <ClCompile Include=\"..\\..\\vsedit\\src\\script_editor\\script_completer_model.cpp\" />\n    <ClCompile Include=\"..\\..\\vsedit\\src\\script_editor\\script_editor.cpp\" />\n    <ClCompile Include=\"..\\..\\vsedit\\src\\script_editor\\syntax_highlighter.cpp\" />\n    <ClCompile Include=\"..\\..\\vsedit\\src\\script_status_bar_widget\\script_status_bar_widget.cpp\" />\n    <ClCompile Include=\"..\\..\\vsedit\\src\\script_templates\\drop_file_category_model.cpp\" />\n    <ClCompile Include=\"..\\..\\vsedit\\src\\script_templates\\templates_dialog.cpp\" />\n    <ClCompile Include=\"..\\..\\vsedit\\src\\settings\\actions_hotkey_edit_model.cpp\" />\n    <ClCompile Include=\"..\\..\\vsedit\\src\\settings\\clearable_key_sequence_editor.cpp\" />\n    <ClCompile Include=\"..\\..\\vsedit\\src\\settings\\item_delegate_for_hotkey.cpp\" />\n    <ClCompile Include=\"..\\..\\vsedit\\src\\settings\\settings_dialog.cpp\" />\n    <ClCompile Include=\"..\\..\\vsedit\\src\\settings\\theme_elements_model.cpp\" />\n    <ClCompile Include=\"..\\..\\vsedit\\src\\vapoursynth\\vapoursynth_plugins_manager.cpp\" />\n    <ClCompile Include=\"..\\..\\vsedit\\src\\vapoursynth\\vs_plugin_data.cpp\" />\n    <ClCompile Include=\"..\\..\\vsedit\\src\\vapoursynth\\vs_script_processor_dialog.cpp\" />\n  </ItemGroup>\n  <ItemGroup>\n    <QtRcc Include=\"..\\..\\resources\\dark\\style.qrc\" />\n    <QtRcc Include=\"..\\..\\resources\\vsedit.qrc\" />\n  </ItemGroup>\n  <ItemGroup>\n    <ResourceCompile Include=\"vsedit.rc\" />\n  </ItemGroup>\n  <ItemGroup>\n    <Image Include=\"..\\..\\resources\\vsedit.ico\" />\n  </ItemGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.targets\" />\n  <ImportGroup Condition=\"Exists('$(QtMsBuild)\\qt.targets')\">\n    <Import Project=\"$(QtMsBuild)\\qt.targets\" />\n  </ImportGroup>\n  <ImportGroup Label=\"ExtensionTargets\">\n  </ImportGroup>\n</Project>"
  },
  {
    "path": "msvc/vsedit/vsedit.vcxproj.filters",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project ToolsVersion=\"4.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <ItemGroup>\n    <Filter Include=\"Source Files\">\n      <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>\n      <Extensions>qml;cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>\n    </Filter>\n    <Filter Include=\"Header Files\">\n      <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>\n      <Extensions>h;hh;hpp;hxx;hm;inl;inc;xsd</Extensions>\n    </Filter>\n    <Filter Include=\"Resource Files\">\n      <UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>\n      <Extensions>qrc;rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>\n    </Filter>\n    <Filter Include=\"Form Files\">\n      <UniqueIdentifier>{99349809-55BA-4b9d-BF79-8FDBB0286EB3}</UniqueIdentifier>\n      <Extensions>ui</Extensions>\n    </Filter>\n    <Filter Include=\"Translation Files\">\n      <UniqueIdentifier>{639EADAA-A684-42e4-A9AD-28FC9BCB8F7C}</UniqueIdentifier>\n      <Extensions>ts</Extensions>\n    </Filter>\n  </ItemGroup>\n  <ItemGroup>\n    <QtUic Include=\"..\\..\\common-src\\log\\styled_log_view_settings_dialog.ui\">\n      <Filter>Form Files</Filter>\n    </QtUic>\n    <QtUic Include=\"..\\..\\vsedit\\src\\settings\\settings_dialog.ui\">\n      <Filter>Form Files</Filter>\n    </QtUic>\n    <QtUic Include=\"..\\..\\vsedit\\src\\script_status_bar_widget\\script_status_bar_widget.ui\">\n      <Filter>Form Files</Filter>\n    </QtUic>\n    <QtUic Include=\"..\\..\\vsedit\\src\\preview\\preview_advanced_settings_dialog.ui\">\n      <Filter>Form Files</Filter>\n    </QtUic>\n    <QtUic Include=\"..\\..\\vsedit\\src\\preview\\preview_dialog.ui\">\n      <Filter>Form Files</Filter>\n    </QtUic>\n    <QtUic Include=\"..\\..\\vsedit\\src\\script_templates\\templates_dialog.ui\">\n      <Filter>Form Files</Filter>\n    </QtUic>\n    <QtUic Include=\"..\\..\\vsedit\\src\\frame_consumers\\benchmark_dialog.ui\">\n      <Filter>Form Files</Filter>\n    </QtUic>\n    <QtUic Include=\"..\\..\\vsedit\\src\\frame_consumers\\encode_dialog.ui\">\n      <Filter>Form Files</Filter>\n    </QtUic>\n    <QtUic Include=\"..\\..\\vsedit\\src\\main_window.ui\">\n      <Filter>Form Files</Filter>\n    </QtUic>\n  </ItemGroup>\n  <ItemGroup>\n    <QtMoc Include=\"..\\..\\vsedit\\src\\vapoursynth\\vs_script_processor_dialog.h\">\n      <Filter>Header Files</Filter>\n    </QtMoc>\n    <QtMoc Include=\"..\\..\\vsedit\\src\\vapoursynth\\vapoursynth_plugins_manager.h\">\n      <Filter>Header Files</Filter>\n    </QtMoc>\n    <QtMoc Include=\"..\\..\\vsedit\\src\\settings\\theme_elements_model.h\">\n      <Filter>Header Files</Filter>\n    </QtMoc>\n    <QtMoc Include=\"..\\..\\vsedit\\src\\settings\\settings_dialog.h\">\n      <Filter>Header Files</Filter>\n    </QtMoc>\n    <QtMoc Include=\"..\\..\\vsedit\\src\\settings\\actions_hotkey_edit_model.h\">\n      <Filter>Header Files</Filter>\n    </QtMoc>\n    <QtMoc Include=\"..\\..\\vsedit\\src\\settings\\clearable_key_sequence_editor.h\">\n      <Filter>Header Files</Filter>\n    </QtMoc>\n    <QtMoc Include=\"..\\..\\vsedit\\src\\settings\\item_delegate_for_hotkey.h\">\n      <Filter>Header Files</Filter>\n    </QtMoc>\n    <QtMoc Include=\"..\\..\\vsedit\\src\\script_templates\\drop_file_category_model.h\">\n      <Filter>Header Files</Filter>\n    </QtMoc>\n    <QtMoc Include=\"..\\..\\vsedit\\src\\script_templates\\templates_dialog.h\">\n      <Filter>Header Files</Filter>\n    </QtMoc>\n    <QtMoc Include=\"..\\..\\vsedit\\src\\script_status_bar_widget\\script_status_bar_widget.h\">\n      <Filter>Header Files</Filter>\n    </QtMoc>\n    <QtMoc Include=\"..\\..\\vsedit\\src\\script_editor\\script_editor.h\">\n      <Filter>Header Files</Filter>\n    </QtMoc>\n    <QtMoc Include=\"..\\..\\vsedit\\src\\script_editor\\syntax_highlighter.h\">\n      <Filter>Header Files</Filter>\n    </QtMoc>\n    <QtMoc Include=\"..\\..\\vsedit\\src\\script_editor\\script_completer.h\">\n      <Filter>Header Files</Filter>\n    </QtMoc>\n    <QtMoc Include=\"..\\..\\vsedit\\src\\script_editor\\script_completer_model.h\">\n      <Filter>Header Files</Filter>\n    </QtMoc>\n    <QtMoc Include=\"..\\..\\vsedit\\src\\preview\\preview_dialog.h\">\n      <Filter>Header Files</Filter>\n    </QtMoc>\n    <QtMoc Include=\"..\\..\\vsedit\\src\\preview\\preview_area.h\">\n      <Filter>Header Files</Filter>\n    </QtMoc>\n    <QtMoc Include=\"..\\..\\vsedit\\src\\preview\\preview_advanced_settings_dialog.h\">\n      <Filter>Header Files</Filter>\n    </QtMoc>\n    <QtMoc Include=\"..\\..\\vsedit\\src\\main_window.h\">\n      <Filter>Header Files</Filter>\n    </QtMoc>\n    <QtMoc Include=\"..\\..\\vsedit\\src\\job_server_watcher_socket.h\">\n      <Filter>Header Files</Filter>\n    </QtMoc>\n    <QtMoc Include=\"..\\..\\vsedit\\src\\frame_consumers\\encode_dialog.h\">\n      <Filter>Header Files</Filter>\n    </QtMoc>\n    <QtMoc Include=\"..\\..\\vsedit\\src\\frame_consumers\\benchmark_dialog.h\">\n      <Filter>Header Files</Filter>\n    </QtMoc>\n    <QtMoc Include=\"..\\..\\common-src\\vapoursynth\\vapoursynth_script_processor.h\">\n      <Filter>Header Files</Filter>\n    </QtMoc>\n    <QtMoc Include=\"..\\..\\common-src\\vapoursynth\\vs_script_library.h\">\n      <Filter>Header Files</Filter>\n    </QtMoc>\n    <QtMoc Include=\"..\\..\\common-src\\timeline_slider\\timeline_slider.h\">\n      <Filter>Header Files</Filter>\n    </QtMoc>\n    <QtMoc Include=\"..\\..\\common-src\\log\\log_styles_model.h\">\n      <Filter>Header Files</Filter>\n    </QtMoc>\n    <QtMoc Include=\"..\\..\\common-src\\log\\styled_log_view.h\">\n      <Filter>Header Files</Filter>\n    </QtMoc>\n    <QtMoc Include=\"..\\..\\common-src\\log\\styled_log_view_settings_dialog.h\">\n      <Filter>Header Files</Filter>\n    </QtMoc>\n    <QtMoc Include=\"..\\..\\common-src\\log\\vs_editor_log.h\">\n      <Filter>Header Files</Filter>\n    </QtMoc>\n    <QtMoc Include=\"..\\..\\common-src\\jobs\\job.h\">\n      <Filter>Header Files</Filter>\n    </QtMoc>\n    <QtMoc Include=\"..\\..\\common-src\\frame_header_writers\\frame_header_writer.h\">\n      <Filter>Header Files</Filter>\n    </QtMoc>\n    <QtMoc Include=\"..\\..\\common-src\\frame_header_writers\\frame_header_writer_null.h\">\n      <Filter>Header Files</Filter>\n    </QtMoc>\n    <QtMoc Include=\"..\\..\\common-src\\frame_header_writers\\frame_header_writer_y4m.h\">\n      <Filter>Header Files</Filter>\n    </QtMoc>\n  </ItemGroup>\n  <ItemGroup>\n    <ClInclude Include=\"..\\..\\vsedit\\src\\vapoursynth\\vs_plugin_data.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\vsedit\\src\\script_editor\\number_matcher.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\vsedit\\src\\preview\\zoom_ratio_spinbox.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\vsedit\\src\\preview\\scroll_navigator.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\common-src\\helpers.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\common-src\\helpers_vs.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\common-src\\version_info.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\common-src\\win32_console.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\common-src\\chrono.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\common-src\\vapoursynth\\vs_pack_rgb.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\common-src\\vapoursynth\\vs_script_processor_structures.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\common-src\\vapoursynth\\vs_set_matrix.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\common-src\\settings\\settings_definitions.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\common-src\\settings\\settings_manager.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\common-src\\settings\\settings_manager_core.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\common-src\\log\\styled_log_view_core.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\common-src\\log\\styled_log_view_structures.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\common-src\\log\\vs_editor_log_definitions.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\common-src\\jobs\\job_variables.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\common-src\\settings\\settings_definitions_core.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"resource.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n  </ItemGroup>\n  <ItemGroup>\n    <ClCompile Include=\"..\\..\\vsedit\\src\\vapoursynth\\vs_script_processor_dialog.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\vsedit\\src\\vapoursynth\\vs_plugin_data.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\vsedit\\src\\vapoursynth\\vapoursynth_plugins_manager.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\vsedit\\src\\settings\\theme_elements_model.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\vsedit\\src\\settings\\settings_dialog.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\vsedit\\src\\settings\\actions_hotkey_edit_model.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\vsedit\\src\\settings\\clearable_key_sequence_editor.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\vsedit\\src\\settings\\item_delegate_for_hotkey.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\vsedit\\src\\script_templates\\templates_dialog.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\vsedit\\src\\script_templates\\drop_file_category_model.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\vsedit\\src\\script_status_bar_widget\\script_status_bar_widget.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\vsedit\\src\\script_editor\\script_editor.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\vsedit\\src\\script_editor\\syntax_highlighter.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\vsedit\\src\\script_editor\\number_matcher.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\vsedit\\src\\script_editor\\script_completer.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\vsedit\\src\\script_editor\\script_completer_model.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\vsedit\\src\\preview\\scroll_navigator.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\vsedit\\src\\preview\\zoom_ratio_spinbox.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\vsedit\\src\\preview\\preview_dialog.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\vsedit\\src\\preview\\preview_area.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\vsedit\\src\\preview\\preview_advanced_settings_dialog.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\vsedit\\src\\main_window.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\vsedit\\src\\main.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\vsedit\\src\\job_server_watcher_socket.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\vsedit\\src\\frame_consumers\\encode_dialog.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\vsedit\\src\\frame_consumers\\benchmark_dialog.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\common-src\\helpers.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\common-src\\version_info.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\common-src\\win32_console.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\common-src\\vapoursynth\\vs_set_matrix.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\common-src\\vapoursynth\\vapoursynth_script_processor.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\common-src\\vapoursynth\\vs_pack_rgb.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\common-src\\vapoursynth\\vs_script_library.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\common-src\\vapoursynth\\vs_script_processor_structures.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\common-src\\timeline_slider\\timeline_slider.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\common-src\\settings\\settings_manager_core.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\common-src\\settings\\settings_definitions.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\common-src\\settings\\settings_definitions_core.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\common-src\\settings\\settings_manager.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\common-src\\log\\log_styles_model.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\common-src\\log\\styled_log_view.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\common-src\\log\\styled_log_view_core.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\common-src\\log\\styled_log_view_settings_dialog.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\common-src\\log\\styled_log_view_structures.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\common-src\\log\\vs_editor_log.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\common-src\\log\\vs_editor_log_definitions.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\common-src\\jobs\\job.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\common-src\\jobs\\job_variables.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\common-src\\frame_header_writers\\frame_header_writer.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\common-src\\frame_header_writers\\frame_header_writer_null.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\common-src\\frame_header_writers\\frame_header_writer_y4m.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n  </ItemGroup>\n  <ItemGroup>\n    <QtRcc Include=\"..\\..\\resources\\vsedit.qrc\">\n      <Filter>Resource Files</Filter>\n    </QtRcc>\n    <QtRcc Include=\"..\\..\\resources\\dark\\style.qrc\">\n      <Filter>Resource Files</Filter>\n    </QtRcc>\n  </ItemGroup>\n  <ItemGroup>\n    <ResourceCompile Include=\"vsedit.rc\">\n      <Filter>Resource Files</Filter>\n    </ResourceCompile>\n  </ItemGroup>\n  <ItemGroup>\n    <Image Include=\"..\\..\\resources\\vsedit.ico\">\n      <Filter>Resource Files</Filter>\n    </Image>\n  </ItemGroup>\n</Project>"
  },
  {
    "path": "msvc/vsedit-encode/resource.h",
    "content": "//{{NO_DEPENDENCIES}}\n// Microsoft Visual C++ generated include file.\n// Used by vsedit.rc\n//\n#define IDI_ICON1                       101\n\n// Next default values for new objects\n// \n#ifdef APSTUDIO_INVOKED\n#ifndef APSTUDIO_READONLY_SYMBOLS\n#define _APS_NEXT_RESOURCE_VALUE        102\n#define _APS_NEXT_COMMAND_VALUE         40001\n#define _APS_NEXT_CONTROL_VALUE         1001\n#define _APS_NEXT_SYMED_VALUE           101\n#endif\n#endif\n"
  },
  {
    "path": "msvc/vsedit-encode/vsedit-encode.vcxproj",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project DefaultTargets=\"Build\" ToolsVersion=\"17.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <ItemGroup Label=\"ProjectConfigurations\">\n    <ProjectConfiguration Include=\"Debug|x64\">\n      <Configuration>Debug</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Release|x64\">\n      <Configuration>Release</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n  </ItemGroup>\n  <PropertyGroup Label=\"Globals\">\n    <ProjectGuid>{FFEEADE6-3DBE-4371-B1BC-D67DC80FE0CF}</ProjectGuid>\n    <Keyword>QtVS_v304</Keyword>\n    <WindowsTargetPlatformVersion Condition=\"'$(Configuration)|$(Platform)' == 'Debug|x64'\">10.0</WindowsTargetPlatformVersion>\n    <WindowsTargetPlatformVersion Condition=\"'$(Configuration)|$(Platform)' == 'Release|x64'\">10.0</WindowsTargetPlatformVersion>\n    <QtMsBuild Condition=\"'$(QtMsBuild)'=='' OR !Exists('$(QtMsBuild)\\qt.targets')\">$(MSBuildProjectDirectory)\\QtMsBuild</QtMsBuild>\n  </PropertyGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.Default.props\" />\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)' == 'Debug|x64'\" Label=\"Configuration\">\n    <ConfigurationType>Application</ConfigurationType>\n    <PlatformToolset>v143</PlatformToolset>\n    <UseDebugLibraries>true</UseDebugLibraries>\n    <CharacterSet>Unicode</CharacterSet>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)' == 'Release|x64'\" Label=\"Configuration\">\n    <ConfigurationType>Application</ConfigurationType>\n    <PlatformToolset>v143</PlatformToolset>\n    <UseDebugLibraries>false</UseDebugLibraries>\n    <WholeProgramOptimization>true</WholeProgramOptimization>\n    <CharacterSet>Unicode</CharacterSet>\n  </PropertyGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.props\" />\n  <ImportGroup Condition=\"Exists('$(QtMsBuild)\\qt_defaults.props')\">\n    <Import Project=\"$(QtMsBuild)\\qt_defaults.props\" />\n  </ImportGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)' == 'Debug|x64'\" Label=\"QtSettings\">\n    <QtInstall>6.7.2_msvc2019_64</QtInstall>\n    <QtModules>core</QtModules>\n    <QtBuildConfig>debug</QtBuildConfig>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)' == 'Release|x64'\" Label=\"QtSettings\">\n    <QtInstall>6.7.2_msvc2019_64</QtInstall>\n    <QtModules>core;gui;widgets</QtModules>\n    <QtBuildConfig>release</QtBuildConfig>\n    <QtDeploy>true</QtDeploy>\n  </PropertyGroup>\n  <Target Name=\"QtMsBuildNotFound\" BeforeTargets=\"CustomBuild;ClCompile\" Condition=\"!Exists('$(QtMsBuild)\\qt.targets') or !Exists('$(QtMsBuild)\\qt.props')\">\n    <Message Importance=\"High\" Text=\"QtMsBuild: could not locate qt.targets, qt.props; project may not build correctly.\" />\n  </Target>\n  <ImportGroup Label=\"ExtensionSettings\" />\n  <ImportGroup Label=\"Shared\" />\n  <ImportGroup Label=\"PropertySheets\" Condition=\"'$(Configuration)|$(Platform)' == 'Debug|x64'\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n    <Import Project=\"$(QtMsBuild)\\Qt.props\" />\n  </ImportGroup>\n  <ImportGroup Label=\"PropertySheets\" Condition=\"'$(Configuration)|$(Platform)' == 'Release|x64'\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n    <Import Project=\"$(QtMsBuild)\\Qt.props\" />\n  </ImportGroup>\n  <PropertyGroup Label=\"UserMacros\" />\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)' == 'Debug|x64'\">\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)' == 'Release|x64'\">\n    <IncludePath>C:\\Program Files\\VapourSynth\\sdk\\include;$(VC_IncludePath);$(WindowsSDK_IncludePath);</IncludePath>\n  </PropertyGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">\n    <QtMoc>\n      <QtMocDir>..\\..\\vsedit\\generated\\moc</QtMocDir>\n    </QtMoc>\n    <QtRcc>\n      <QtRccDir>..\\..\\vsedit\\generated\\rcc</QtRccDir>\n    </QtRcc>\n    <QtUic>\n      <QtUicDir>..\\..\\vsedit\\generated\\ui</QtUicDir>\n    </QtUic>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)' == 'Debug|x64'\" Label=\"Configuration\">\n    <ClCompile>\n      <MultiProcessorCompilation>true</MultiProcessorCompilation>\n      <WarningLevel>Level3</WarningLevel>\n      <SDLCheck>true</SDLCheck>\n      <ConformanceMode>true</ConformanceMode>\n    </ClCompile>\n    <Link>\n      <SubSystem>Console</SubSystem>\n      <GenerateDebugInformation>true</GenerateDebugInformation>\n    </Link>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)' == 'Release|x64'\" Label=\"Configuration\">\n    <ClCompile>\n      <MultiProcessorCompilation>true</MultiProcessorCompilation>\n      <WarningLevel>Level3</WarningLevel>\n      <SDLCheck>true</SDLCheck>\n      <ConformanceMode>true</ConformanceMode>\n      <FunctionLevelLinking>true</FunctionLevelLinking>\n      <IntrinsicFunctions>true</IntrinsicFunctions>\n    </ClCompile>\n    <Link>\n      <SubSystem>Console</SubSystem>\n      <GenerateDebugInformation>false</GenerateDebugInformation>\n      <EnableCOMDATFolding>true</EnableCOMDATFolding>\n      <OptimizeReferences>true</OptimizeReferences>\n    </Link>\n  </ItemDefinitionGroup>\n  <ItemGroup>\n    <ProjectReference Include=\"..\\libp2p\\libp2p.vcxproj\">\n      <Project>{dd503806-0462-4cfe-bc5d-6355cf100832}</Project>\n    </ProjectReference>\n  </ItemGroup>\n  <ItemGroup>\n    <QtUic Include=\"..\\..\\common-src\\log\\styled_log_view_settings_dialog.ui\" />\n    <QtUic Include=\"..\\..\\vsedit\\src\\frame_consumers\\encode_dialog.ui\" />\n    <QtUic Include=\"..\\..\\vsedit\\src\\script_status_bar_widget\\script_status_bar_widget.ui\" />\n  </ItemGroup>\n  <ItemGroup>\n    <ClCompile Include=\"..\\..\\common-src\\frame_header_writers\\frame_header_writer.cpp\" />\n    <ClCompile Include=\"..\\..\\common-src\\frame_header_writers\\frame_header_writer_null.cpp\" />\n    <ClCompile Include=\"..\\..\\common-src\\frame_header_writers\\frame_header_writer_y4m.cpp\" />\n    <ClCompile Include=\"..\\..\\common-src\\helpers.cpp\" />\n    <ClCompile Include=\"..\\..\\common-src\\jobs\\job.cpp\" />\n    <ClCompile Include=\"..\\..\\common-src\\jobs\\job_variables.cpp\" />\n    <ClCompile Include=\"..\\..\\common-src\\log\\log_styles_model.cpp\" />\n    <ClCompile Include=\"..\\..\\common-src\\log\\styled_log_view.cpp\" />\n    <ClCompile Include=\"..\\..\\common-src\\log\\styled_log_view_core.cpp\" />\n    <ClCompile Include=\"..\\..\\common-src\\log\\styled_log_view_settings_dialog.cpp\" />\n    <ClCompile Include=\"..\\..\\common-src\\log\\styled_log_view_structures.cpp\" />\n    <ClCompile Include=\"..\\..\\common-src\\log\\vs_editor_log.cpp\" />\n    <ClCompile Include=\"..\\..\\common-src\\log\\vs_editor_log_definitions.cpp\" />\n    <ClCompile Include=\"..\\..\\common-src\\settings\\settings_definitions.cpp\" />\n    <ClCompile Include=\"..\\..\\common-src\\settings\\settings_definitions_core.cpp\" />\n    <ClCompile Include=\"..\\..\\common-src\\settings\\settings_manager.cpp\" />\n    <ClCompile Include=\"..\\..\\common-src\\settings\\settings_manager_core.cpp\" />\n    <ClCompile Include=\"..\\..\\common-src\\vapoursynth\\vapoursynth_script_processor.cpp\" />\n    <ClCompile Include=\"..\\..\\common-src\\vapoursynth\\vs_pack_rgb.cpp\" />\n    <ClCompile Include=\"..\\..\\common-src\\vapoursynth\\vs_script_library.cpp\" />\n    <ClCompile Include=\"..\\..\\common-src\\vapoursynth\\vs_script_processor_structures.cpp\" />\n    <ClCompile Include=\"..\\..\\common-src\\vapoursynth\\vs_set_matrix.cpp\" />\n    <ClCompile Include=\"..\\..\\vsedit\\src\\frame_consumers\\encode_dialog.cpp\" />\n    <ClCompile Include=\"..\\..\\vsedit\\src\\script_status_bar_widget\\script_status_bar_widget.cpp\" />\n    <ClCompile Include=\"..\\..\\vsedit\\src\\settings\\actions_hotkey_edit_model.cpp\" />\n    <ClCompile Include=\"..\\..\\vsedit\\src\\settings\\clearable_key_sequence_editor.cpp\" />\n    <ClCompile Include=\"..\\..\\vsedit\\src\\settings\\item_delegate_for_hotkey.cpp\" />\n    <ClCompile Include=\"..\\..\\vsedit\\src\\settings\\theme_elements_model.cpp\" />\n    <ClCompile Include=\"..\\..\\vsedit\\src\\vsedit_encode_main.cpp\" />\n  </ItemGroup>\n  <ItemGroup>\n    <QtMoc Include=\"..\\..\\common-src\\log\\log_styles_model.h\" />\n  </ItemGroup>\n  <ItemGroup>\n    <QtMoc Include=\"..\\..\\common-src\\log\\styled_log_view.h\" />\n  </ItemGroup>\n  <ItemGroup>\n    <ClInclude Include=\"..\\..\\common-src\\chrono.h\" />\n    <ClInclude Include=\"resource.h\" />\n    <QtMoc Include=\"..\\..\\vsedit\\src\\script_status_bar_widget\\script_status_bar_widget.h\" />\n    <QtMoc Include=\"..\\..\\vsedit\\src\\frame_consumers\\encode_dialog.h\" />\n    <QtMoc Include=\"..\\..\\vsedit\\src\\settings\\theme_elements_model.h\" />\n    <QtMoc Include=\"..\\..\\vsedit\\src\\settings\\item_delegate_for_hotkey.h\" />\n    <QtMoc Include=\"..\\..\\vsedit\\src\\settings\\clearable_key_sequence_editor.h\" />\n    <QtMoc Include=\"..\\..\\vsedit\\src\\settings\\actions_hotkey_edit_model.h\" />\n    <QtMoc Include=\"..\\..\\common-src\\vapoursynth\\vapoursynth_script_processor.h\" />\n    <ClInclude Include=\"..\\..\\common-src\\vapoursynth\\vs_pack_rgb.h\" />\n    <QtMoc Include=\"..\\..\\common-src\\vapoursynth\\vs_script_library.h\" />\n    <ClInclude Include=\"..\\..\\common-src\\vapoursynth\\vs_script_processor_structures.h\" />\n    <ClInclude Include=\"..\\..\\common-src\\vapoursynth\\vs_set_matrix.h\" />\n    <QtMoc Include=\"..\\..\\common-src\\frame_header_writers\\frame_header_writer_y4m.h\" />\n    <QtMoc Include=\"..\\..\\common-src\\frame_header_writers\\frame_header_writer_null.h\" />\n    <QtMoc Include=\"..\\..\\common-src\\frame_header_writers\\frame_header_writer.h\" />\n    <ClInclude Include=\"..\\..\\common-src\\helpers.h\" />\n    <ClInclude Include=\"..\\..\\common-src\\helpers_vs.h\" />\n    <ClInclude Include=\"..\\..\\common-src\\jobs\\job_variables.h\" />\n    <QtMoc Include=\"..\\..\\common-src\\jobs\\job.h\" />\n    <ClInclude Include=\"..\\..\\common-src\\log\\styled_log_view_core.h\" />\n    <ClInclude Include=\"..\\..\\common-src\\log\\styled_log_view_structures.h\" />\n    <ClInclude Include=\"..\\..\\common-src\\log\\vs_editor_log_definitions.h\" />\n    <ClInclude Include=\"..\\..\\common-src\\settings\\settings_definitions.h\" />\n    <ClInclude Include=\"..\\..\\common-src\\settings\\settings_definitions_core.h\" />\n    <ClInclude Include=\"..\\..\\common-src\\settings\\settings_manager.h\" />\n    <ClInclude Include=\"..\\..\\common-src\\settings\\settings_manager_core.h\" />\n    <QtMoc Include=\"..\\..\\common-src\\log\\vs_editor_log.h\" />\n    <QtMoc Include=\"..\\..\\common-src\\log\\styled_log_view_settings_dialog.h\" />\n  </ItemGroup>\n  <ItemGroup>\n    <QtRcc Include=\"..\\..\\resources\\dark\\style.qrc\" />\n    <QtRcc Include=\"..\\..\\resources\\vsedit.qrc\" />\n  </ItemGroup>\n  <ItemGroup>\n    <Image Include=\"..\\..\\resources\\vsedit.ico\" />\n  </ItemGroup>\n  <ItemGroup>\n    <ResourceCompile Include=\"vsedit-encode.rc\" />\n  </ItemGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.targets\" />\n  <ImportGroup Condition=\"Exists('$(QtMsBuild)\\qt.targets')\">\n    <Import Project=\"$(QtMsBuild)\\qt.targets\" />\n  </ImportGroup>\n  <ImportGroup Label=\"ExtensionTargets\">\n  </ImportGroup>\n</Project>"
  },
  {
    "path": "msvc/vsedit-encode/vsedit-encode.vcxproj.filters",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project ToolsVersion=\"4.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <ItemGroup>\n    <Filter Include=\"Source Files\">\n      <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>\n      <Extensions>qml;cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>\n    </Filter>\n    <Filter Include=\"Header Files\">\n      <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>\n      <Extensions>h;hh;hpp;hxx;hm;inl;inc;xsd</Extensions>\n    </Filter>\n    <Filter Include=\"Resource Files\">\n      <UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>\n      <Extensions>qrc;rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>\n    </Filter>\n    <Filter Include=\"Form Files\">\n      <UniqueIdentifier>{99349809-55BA-4b9d-BF79-8FDBB0286EB3}</UniqueIdentifier>\n      <Extensions>ui</Extensions>\n    </Filter>\n    <Filter Include=\"Translation Files\">\n      <UniqueIdentifier>{639EADAA-A684-42e4-A9AD-28FC9BCB8F7C}</UniqueIdentifier>\n      <Extensions>ts</Extensions>\n    </Filter>\n  </ItemGroup>\n  <ItemGroup>\n    <QtUic Include=\"..\\..\\common-src\\log\\styled_log_view_settings_dialog.ui\">\n      <Filter>Form Files</Filter>\n    </QtUic>\n    <QtUic Include=\"..\\..\\vsedit\\src\\frame_consumers\\encode_dialog.ui\">\n      <Filter>Form Files</Filter>\n    </QtUic>\n    <QtUic Include=\"..\\..\\vsedit\\src\\script_status_bar_widget\\script_status_bar_widget.ui\">\n      <Filter>Form Files</Filter>\n    </QtUic>\n  </ItemGroup>\n  <ItemGroup>\n    <ClCompile Include=\"..\\..\\common-src\\log\\log_styles_model.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\common-src\\log\\styled_log_view.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\common-src\\log\\styled_log_view_core.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\common-src\\log\\styled_log_view_settings_dialog.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\common-src\\log\\styled_log_view_structures.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\common-src\\log\\vs_editor_log.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\common-src\\log\\vs_editor_log_definitions.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\common-src\\helpers.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\common-src\\settings\\settings_definitions.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\common-src\\settings\\settings_definitions_core.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\common-src\\settings\\settings_manager.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\common-src\\settings\\settings_manager_core.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\common-src\\jobs\\job.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\common-src\\jobs\\job_variables.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\common-src\\frame_header_writers\\frame_header_writer.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\common-src\\frame_header_writers\\frame_header_writer_null.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\common-src\\frame_header_writers\\frame_header_writer_y4m.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\common-src\\vapoursynth\\vs_set_matrix.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\common-src\\vapoursynth\\vs_script_processor_structures.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\common-src\\vapoursynth\\vs_script_library.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\common-src\\vapoursynth\\vs_pack_rgb.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\common-src\\vapoursynth\\vapoursynth_script_processor.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\vsedit\\src\\settings\\actions_hotkey_edit_model.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\vsedit\\src\\settings\\clearable_key_sequence_editor.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\vsedit\\src\\settings\\item_delegate_for_hotkey.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\vsedit\\src\\settings\\theme_elements_model.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\vsedit\\src\\frame_consumers\\encode_dialog.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\vsedit\\src\\script_status_bar_widget\\script_status_bar_widget.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\vsedit\\src\\vsedit_encode_main.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n  </ItemGroup>\n  <ItemGroup>\n    <QtMoc Include=\"..\\..\\common-src\\log\\log_styles_model.h\">\n      <Filter>Header Files</Filter>\n    </QtMoc>\n    <QtMoc Include=\"..\\..\\common-src\\log\\styled_log_view.h\">\n      <Filter>Header Files</Filter>\n    </QtMoc>\n    <QtMoc Include=\"..\\..\\common-src\\log\\styled_log_view_settings_dialog.h\">\n      <Filter>Header Files</Filter>\n    </QtMoc>\n    <QtMoc Include=\"..\\..\\common-src\\log\\vs_editor_log.h\">\n      <Filter>Header Files</Filter>\n    </QtMoc>\n    <QtMoc Include=\"..\\..\\common-src\\jobs\\job.h\">\n      <Filter>Header Files</Filter>\n    </QtMoc>\n    <QtMoc Include=\"..\\..\\common-src\\frame_header_writers\\frame_header_writer.h\">\n      <Filter>Header Files</Filter>\n    </QtMoc>\n    <QtMoc Include=\"..\\..\\common-src\\frame_header_writers\\frame_header_writer_null.h\">\n      <Filter>Header Files</Filter>\n    </QtMoc>\n    <QtMoc Include=\"..\\..\\common-src\\frame_header_writers\\frame_header_writer_y4m.h\">\n      <Filter>Header Files</Filter>\n    </QtMoc>\n    <QtMoc Include=\"..\\..\\common-src\\vapoursynth\\vs_script_library.h\">\n      <Filter>Header Files</Filter>\n    </QtMoc>\n    <QtMoc Include=\"..\\..\\common-src\\vapoursynth\\vapoursynth_script_processor.h\">\n      <Filter>Header Files</Filter>\n    </QtMoc>\n    <QtMoc Include=\"..\\..\\vsedit\\src\\settings\\actions_hotkey_edit_model.h\">\n      <Filter>Header Files</Filter>\n    </QtMoc>\n    <QtMoc Include=\"..\\..\\vsedit\\src\\settings\\clearable_key_sequence_editor.h\">\n      <Filter>Header Files</Filter>\n    </QtMoc>\n    <QtMoc Include=\"..\\..\\vsedit\\src\\settings\\item_delegate_for_hotkey.h\">\n      <Filter>Header Files</Filter>\n    </QtMoc>\n    <QtMoc Include=\"..\\..\\vsedit\\src\\settings\\theme_elements_model.h\">\n      <Filter>Header Files</Filter>\n    </QtMoc>\n    <QtMoc Include=\"..\\..\\vsedit\\src\\frame_consumers\\encode_dialog.h\">\n      <Filter>Header Files</Filter>\n    </QtMoc>\n    <QtMoc Include=\"..\\..\\vsedit\\src\\script_status_bar_widget\\script_status_bar_widget.h\">\n      <Filter>Header Files</Filter>\n    </QtMoc>\n  </ItemGroup>\n  <ItemGroup>\n    <ClInclude Include=\"..\\..\\common-src\\log\\styled_log_view_core.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\common-src\\log\\styled_log_view_structures.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\common-src\\log\\vs_editor_log_definitions.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\common-src\\chrono.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\common-src\\helpers.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\common-src\\helpers_vs.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\common-src\\settings\\settings_definitions.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\common-src\\settings\\settings_definitions_core.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\common-src\\settings\\settings_manager.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\common-src\\settings\\settings_manager_core.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\common-src\\jobs\\job_variables.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\common-src\\vapoursynth\\vs_set_matrix.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\common-src\\vapoursynth\\vs_script_processor_structures.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\common-src\\vapoursynth\\vs_pack_rgb.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"resource.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n  </ItemGroup>\n  <ItemGroup>\n    <QtRcc Include=\"..\\..\\resources\\dark\\style.qrc\">\n      <Filter>Resource Files</Filter>\n    </QtRcc>\n    <QtRcc Include=\"..\\..\\resources\\vsedit.qrc\">\n      <Filter>Resource Files</Filter>\n    </QtRcc>\n  </ItemGroup>\n  <ItemGroup>\n    <Image Include=\"..\\..\\resources\\vsedit.ico\">\n      <Filter>Resource Files</Filter>\n    </Image>\n  </ItemGroup>\n  <ItemGroup>\n    <ResourceCompile Include=\"vsedit-encode.rc\">\n      <Filter>Resource Files</Filter>\n    </ResourceCompile>\n  </ItemGroup>\n</Project>"
  },
  {
    "path": "msvc/vsedit-job-server/resource.h",
    "content": "//{{NO_DEPENDENCIES}}\n// Microsoft Visual C++ generated include file.\n// Used by vsedit.rc\n//\n#define IDI_ICON1                       101\n\n// Next default values for new objects\n// \n#ifdef APSTUDIO_INVOKED\n#ifndef APSTUDIO_READONLY_SYMBOLS\n#define _APS_NEXT_RESOURCE_VALUE        102\n#define _APS_NEXT_COMMAND_VALUE         40001\n#define _APS_NEXT_CONTROL_VALUE         1001\n#define _APS_NEXT_SYMED_VALUE           101\n#endif\n#endif\n"
  },
  {
    "path": "msvc/vsedit-job-server/vsedit-job-server.vcxproj",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project DefaultTargets=\"Build\" ToolsVersion=\"17.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <ItemGroup Label=\"ProjectConfigurations\">\n    <ProjectConfiguration Include=\"Debug|x64\">\n      <Configuration>Debug</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Release|x64\">\n      <Configuration>Release</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n  </ItemGroup>\n  <PropertyGroup Label=\"Globals\">\n    <ProjectGuid>{BF53C69D-89A2-40B4-977E-1C535B4C7EB8}</ProjectGuid>\n    <Keyword>QtVS_v304</Keyword>\n    <WindowsTargetPlatformVersion Condition=\"'$(Configuration)|$(Platform)' == 'Debug|x64'\">10.0.22621.0</WindowsTargetPlatformVersion>\n    <WindowsTargetPlatformVersion Condition=\"'$(Configuration)|$(Platform)' == 'Release|x64'\">10.0</WindowsTargetPlatformVersion>\n    <QtMsBuild Condition=\"'$(QtMsBuild)'=='' OR !Exists('$(QtMsBuild)\\qt.targets')\">$(MSBuildProjectDirectory)\\QtMsBuild</QtMsBuild>\n  </PropertyGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.Default.props\" />\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)' == 'Debug|x64'\" Label=\"Configuration\">\n    <ConfigurationType>Application</ConfigurationType>\n    <PlatformToolset>v143</PlatformToolset>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)' == 'Release|x64'\" Label=\"Configuration\">\n    <ConfigurationType>Application</ConfigurationType>\n    <PlatformToolset>v143</PlatformToolset>\n    <WholeProgramOptimization>true</WholeProgramOptimization>\n  </PropertyGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.props\" />\n  <ImportGroup Condition=\"Exists('$(QtMsBuild)\\qt_defaults.props')\">\n    <Import Project=\"$(QtMsBuild)\\qt_defaults.props\" />\n  </ImportGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)' == 'Debug|x64'\" Label=\"QtSettings\">\n    <QtInstall>C:\\Qt\\6.7.2\\msvc2019_64</QtInstall>\n    <QtModules>\n    </QtModules>\n    <QtBuildConfig>debug</QtBuildConfig>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)' == 'Release|x64'\" Label=\"QtSettings\">\n    <QtInstall>C:\\Qt\\6.7.2\\msvc2019_64</QtInstall>\n    <QtModules>core;;widgets;websockets</QtModules>\n    <QtBuildConfig>release</QtBuildConfig>\n    <QtDeploy>true</QtDeploy>\n  </PropertyGroup>\n  <Target Name=\"QtMsBuildNotFound\" BeforeTargets=\"CustomBuild;ClCompile\" Condition=\"!Exists('$(QtMsBuild)\\qt.targets') or !Exists('$(QtMsBuild)\\qt.props')\">\n    <Message Importance=\"High\" Text=\"QtMsBuild: could not locate qt.targets, qt.props; project may not build correctly.\" />\n  </Target>\n  <ImportGroup Label=\"ExtensionSettings\" />\n  <ImportGroup Label=\"Shared\" />\n  <ImportGroup Label=\"PropertySheets\" Condition=\"'$(Configuration)|$(Platform)' == 'Debug|x64'\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n    <Import Project=\"$(QtMsBuild)\\Qt.props\" />\n  </ImportGroup>\n  <ImportGroup Label=\"PropertySheets\" Condition=\"'$(Configuration)|$(Platform)' == 'Release|x64'\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n    <Import Project=\"$(QtMsBuild)\\Qt.props\" />\n  </ImportGroup>\n  <PropertyGroup Label=\"UserMacros\" />\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)' == 'Debug|x64'\">\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)' == 'Release|x64'\">\n    <IncludePath>C:\\Program Files\\VapourSynth\\sdk\\include;$(IncludePath)</IncludePath>\n  </PropertyGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">\n    <QtMoc>\n      <QtMocDir>..\\..\\vsedit-job-server\\generated\\moc</QtMocDir>\n    </QtMoc>\n    <QtRcc>\n      <QtRccDir>..\\..\\vsedit-job-server\\generated\\rcc</QtRccDir>\n    </QtRcc>\n    <QtUic>\n      <QtUicDir>..\\..\\vsedit-job-server\\generated\\ui</QtUicDir>\n    </QtUic>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)' == 'Debug|x64'\" Label=\"Configuration\">\n    <ClCompile>\n      <TreatWChar_tAsBuiltInType>true</TreatWChar_tAsBuiltInType>\n      <MultiProcessorCompilation>true</MultiProcessorCompilation>\n      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>\n      <Optimization>Disabled</Optimization>\n    </ClCompile>\n    <Link>\n      <SubSystem>Windows</SubSystem>\n      <GenerateDebugInformation>true</GenerateDebugInformation>\n    </Link>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)' == 'Release|x64'\" Label=\"Configuration\">\n    <ClCompile>\n      <TreatWChar_tAsBuiltInType>true</TreatWChar_tAsBuiltInType>\n      <MultiProcessorCompilation>true</MultiProcessorCompilation>\n      <DebugInformationFormat>None</DebugInformationFormat>\n      <Optimization>MaxSpeed</Optimization>\n    </ClCompile>\n    <Link>\n      <SubSystem>Console</SubSystem>\n      <GenerateDebugInformation>false</GenerateDebugInformation>\n    </Link>\n  </ItemDefinitionGroup>\n  <ItemGroup>\n    <ProjectReference Include=\"..\\libp2p\\libp2p.vcxproj\">\n      <Project>{dd503806-0462-4cfe-bc5d-6355cf100832}</Project>\n    </ProjectReference>\n  </ItemGroup>\n  <ItemGroup>\n    <ResourceCompile Include=\"vsedit-job-server.rc\" />\n  </ItemGroup>\n  <ItemGroup>\n    <ClInclude Include=\"..\\..\\common-src\\application_instance_file_guard\\application_instance_file_guard.h\" />\n    <ClInclude Include=\"..\\..\\common-src\\chrono.h\" />\n    <ClInclude Include=\"..\\..\\common-src\\ipc_defines.h\" />\n    <ClInclude Include=\"..\\..\\common-src\\jobs\\job_variables.h\" />\n    <ClInclude Include=\"..\\..\\common-src\\vapoursynth\\vs_pack_rgb.h\" />\n    <ClInclude Include=\"..\\..\\common-src\\vapoursynth\\vs_set_matrix.h\" />\n    <ClInclude Include=\"..\\..\\vsedit-job-server\\src\\jobs\\job_definitions.h\" />\n    <ClInclude Include=\"resource.h\" />\n    <QtMoc Include=\"..\\..\\vsedit-job-server\\src\\job_server.h\" />\n    <QtMoc Include=\"..\\..\\vsedit-job-server\\src\\jobs\\jobs_manager.h\" />\n    <QtMoc Include=\"..\\..\\common-src\\jobs\\job.h\" />\n    <QtMoc Include=\"..\\..\\common-src\\frame_header_writers\\frame_header_writer_y4m.h\" />\n    <QtMoc Include=\"..\\..\\common-src\\frame_header_writers\\frame_header_writer_null.h\" />\n    <QtMoc Include=\"..\\..\\common-src\\frame_header_writers\\frame_header_writer.h\" />\n    <ClInclude Include=\"..\\..\\common-src\\helpers.h\" />\n    <ClInclude Include=\"..\\..\\common-src\\helpers_vs.h\" />\n    <ClInclude Include=\"..\\..\\common-src\\log\\styled_log_view_core.h\" />\n    <ClInclude Include=\"..\\..\\common-src\\log\\vs_editor_log_definitions.h\" />\n    <ClInclude Include=\"..\\..\\common-src\\settings\\settings_definitions_core.h\" />\n    <ClInclude Include=\"..\\..\\common-src\\settings\\settings_manager_core.h\" />\n    <QtMoc Include=\"..\\..\\common-src\\vapoursynth\\vapoursynth_script_processor.h\" />\n    <QtMoc Include=\"..\\..\\common-src\\vapoursynth\\vs_script_library.h\" />\n    <ClInclude Include=\"..\\..\\common-src\\vapoursynth\\vs_script_processor_structures.h\" />\n    <ClInclude Include=\"..\\..\\common-src\\version_info.h\" />\n  </ItemGroup>\n  <ItemGroup>\n    <ClCompile Include=\"..\\..\\common-src\\application_instance_file_guard\\application_instance_file_guard.cpp\" />\n    <ClCompile Include=\"..\\..\\common-src\\frame_header_writers\\frame_header_writer.cpp\" />\n    <ClCompile Include=\"..\\..\\common-src\\frame_header_writers\\frame_header_writer_null.cpp\" />\n    <ClCompile Include=\"..\\..\\common-src\\frame_header_writers\\frame_header_writer_y4m.cpp\" />\n    <ClCompile Include=\"..\\..\\common-src\\helpers.cpp\" />\n    <ClCompile Include=\"..\\..\\common-src\\jobs\\job.cpp\" />\n    <ClCompile Include=\"..\\..\\common-src\\jobs\\job_variables.cpp\" />\n    <ClCompile Include=\"..\\..\\common-src\\log\\styled_log_view_core.cpp\" />\n    <ClCompile Include=\"..\\..\\common-src\\log\\vs_editor_log_definitions.cpp\" />\n    <ClCompile Include=\"..\\..\\common-src\\settings\\settings_definitions_core.cpp\" />\n    <ClCompile Include=\"..\\..\\common-src\\settings\\settings_manager_core.cpp\" />\n    <ClCompile Include=\"..\\..\\common-src\\vapoursynth\\vapoursynth_script_processor.cpp\" />\n    <ClCompile Include=\"..\\..\\common-src\\vapoursynth\\vs_pack_rgb.cpp\" />\n    <ClCompile Include=\"..\\..\\common-src\\vapoursynth\\vs_script_library.cpp\" />\n    <ClCompile Include=\"..\\..\\common-src\\vapoursynth\\vs_script_processor_structures.cpp\" />\n    <ClCompile Include=\"..\\..\\common-src\\vapoursynth\\vs_set_matrix.cpp\" />\n    <ClCompile Include=\"..\\..\\common-src\\version_info.cpp\" />\n    <ClCompile Include=\"..\\..\\vsedit-job-server\\src\\jobs\\jobs_manager.cpp\" />\n    <ClCompile Include=\"..\\..\\vsedit-job-server\\src\\job_server.cpp\" />\n    <ClCompile Include=\"..\\..\\vsedit-job-server\\src\\main.cpp\" />\n  </ItemGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.targets\" />\n  <ImportGroup Condition=\"Exists('$(QtMsBuild)\\qt.targets')\">\n    <Import Project=\"$(QtMsBuild)\\qt.targets\" />\n  </ImportGroup>\n  <ImportGroup Label=\"ExtensionTargets\">\n  </ImportGroup>\n</Project>"
  },
  {
    "path": "msvc/vsedit-job-server/vsedit-job-server.vcxproj.filters",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project ToolsVersion=\"4.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <ItemGroup>\n    <Filter Include=\"Source Files\">\n      <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>\n      <Extensions>qml;cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>\n    </Filter>\n    <Filter Include=\"Header Files\">\n      <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>\n      <Extensions>h;hh;hpp;hxx;hm;inl;inc;xsd</Extensions>\n    </Filter>\n    <Filter Include=\"Resource Files\">\n      <UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>\n      <Extensions>qrc;rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>\n    </Filter>\n    <Filter Include=\"Form Files\">\n      <UniqueIdentifier>{99349809-55BA-4b9d-BF79-8FDBB0286EB3}</UniqueIdentifier>\n      <Extensions>ui</Extensions>\n    </Filter>\n    <Filter Include=\"Translation Files\">\n      <UniqueIdentifier>{639EADAA-A684-42e4-A9AD-28FC9BCB8F7C}</UniqueIdentifier>\n      <Extensions>ts</Extensions>\n    </Filter>\n  </ItemGroup>\n  <ItemGroup>\n    <ResourceCompile Include=\"vsedit-job-server.rc\">\n      <Filter>Resource Files</Filter>\n    </ResourceCompile>\n  </ItemGroup>\n  <ItemGroup>\n    <ClInclude Include=\"..\\..\\common-src\\chrono.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\common-src\\helpers.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\common-src\\helpers_vs.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\common-src\\version_info.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\common-src\\settings\\settings_definitions_core.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\common-src\\settings\\settings_manager_core.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\common-src\\log\\styled_log_view_core.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\common-src\\log\\vs_editor_log_definitions.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\common-src\\vapoursynth\\vs_script_processor_structures.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\common-src\\jobs\\job_variables.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\common-src\\application_instance_file_guard\\application_instance_file_guard.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\common-src\\ipc_defines.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\vsedit-job-server\\src\\jobs\\job_definitions.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"resource.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\common-src\\vapoursynth\\vs_set_matrix.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\common-src\\vapoursynth\\vs_pack_rgb.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n  </ItemGroup>\n  <ItemGroup>\n    <ClCompile Include=\"..\\..\\common-src\\helpers.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\common-src\\version_info.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\common-src\\settings\\settings_definitions_core.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\common-src\\settings\\settings_manager_core.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\common-src\\log\\styled_log_view_core.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\common-src\\log\\vs_editor_log_definitions.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\common-src\\vapoursynth\\vs_script_processor_structures.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\common-src\\vapoursynth\\vs_script_library.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\common-src\\vapoursynth\\vapoursynth_script_processor.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\common-src\\frame_header_writers\\frame_header_writer.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\common-src\\frame_header_writers\\frame_header_writer_null.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\common-src\\frame_header_writers\\frame_header_writer_y4m.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\common-src\\jobs\\job.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\common-src\\jobs\\job_variables.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\common-src\\application_instance_file_guard\\application_instance_file_guard.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\vsedit-job-server\\src\\jobs\\jobs_manager.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\vsedit-job-server\\src\\job_server.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\vsedit-job-server\\src\\main.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\common-src\\vapoursynth\\vs_set_matrix.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\common-src\\vapoursynth\\vs_pack_rgb.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n  </ItemGroup>\n  <ItemGroup>\n    <QtMoc Include=\"..\\..\\common-src\\vapoursynth\\vs_script_library.h\">\n      <Filter>Header Files</Filter>\n    </QtMoc>\n    <QtMoc Include=\"..\\..\\common-src\\vapoursynth\\vapoursynth_script_processor.h\">\n      <Filter>Header Files</Filter>\n    </QtMoc>\n    <QtMoc Include=\"..\\..\\common-src\\frame_header_writers\\frame_header_writer.h\">\n      <Filter>Header Files</Filter>\n    </QtMoc>\n    <QtMoc Include=\"..\\..\\common-src\\frame_header_writers\\frame_header_writer_null.h\">\n      <Filter>Header Files</Filter>\n    </QtMoc>\n    <QtMoc Include=\"..\\..\\common-src\\frame_header_writers\\frame_header_writer_y4m.h\">\n      <Filter>Header Files</Filter>\n    </QtMoc>\n    <QtMoc Include=\"..\\..\\common-src\\jobs\\job.h\">\n      <Filter>Header Files</Filter>\n    </QtMoc>\n    <QtMoc Include=\"..\\..\\vsedit-job-server\\src\\jobs\\jobs_manager.h\">\n      <Filter>Header Files</Filter>\n    </QtMoc>\n    <QtMoc Include=\"..\\..\\vsedit-job-server\\src\\job_server.h\">\n      <Filter>Header Files</Filter>\n    </QtMoc>\n  </ItemGroup>\n</Project>"
  },
  {
    "path": "msvc/vsedit-job-server-watcher/resource.h",
    "content": "//{{NO_DEPENDENCIES}}\n// Microsoft Visual C++ generated include file.\n// Used by vsedit.rc\n//\n#define IDI_ICON1                       101\n\n// Next default values for new objects\n// \n#ifdef APSTUDIO_INVOKED\n#ifndef APSTUDIO_READONLY_SYMBOLS\n#define _APS_NEXT_RESOURCE_VALUE        102\n#define _APS_NEXT_COMMAND_VALUE         40001\n#define _APS_NEXT_CONTROL_VALUE         1001\n#define _APS_NEXT_SYMED_VALUE           101\n#endif\n#endif\n"
  },
  {
    "path": "msvc/vsedit-job-server-watcher/vsedit-job-server-watcher.vcxproj",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project DefaultTargets=\"Build\" ToolsVersion=\"17.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <ItemGroup Label=\"ProjectConfigurations\">\n    <ProjectConfiguration Include=\"Debug|x64\">\n      <Configuration>Debug</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Release|x64\">\n      <Configuration>Release</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n  </ItemGroup>\n  <PropertyGroup Label=\"Globals\">\n    <ProjectGuid>{1550A490-74AA-413F-97C4-AFFA1BB470C2}</ProjectGuid>\n    <Keyword>QtVS_v304</Keyword>\n    <WindowsTargetPlatformVersion Condition=\"'$(Configuration)|$(Platform)' == 'Debug|x64'\">10.0.22621.0</WindowsTargetPlatformVersion>\n    <WindowsTargetPlatformVersion Condition=\"'$(Configuration)|$(Platform)' == 'Release|x64'\">10.0</WindowsTargetPlatformVersion>\n    <QtMsBuild Condition=\"'$(QtMsBuild)'=='' OR !Exists('$(QtMsBuild)\\qt.targets')\">$(MSBuildProjectDirectory)\\QtMsBuild</QtMsBuild>\n  </PropertyGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.Default.props\" />\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)' == 'Debug|x64'\" Label=\"Configuration\">\n    <ConfigurationType>Application</ConfigurationType>\n    <PlatformToolset>v143</PlatformToolset>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)' == 'Release|x64'\" Label=\"Configuration\">\n    <ConfigurationType>Application</ConfigurationType>\n    <PlatformToolset>v143</PlatformToolset>\n    <WholeProgramOptimization>true</WholeProgramOptimization>\n  </PropertyGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.props\" />\n  <ImportGroup Condition=\"Exists('$(QtMsBuild)\\qt_defaults.props')\">\n    <Import Project=\"$(QtMsBuild)\\qt_defaults.props\" />\n  </ImportGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)' == 'Debug|x64'\" Label=\"QtSettings\">\n    <QtInstall>C:\\Qt\\6.7.2\\msvc2019_64</QtInstall>\n    <QtModules>\n    </QtModules>\n    <QtBuildConfig>debug</QtBuildConfig>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)' == 'Release|x64'\" Label=\"QtSettings\">\n    <QtInstall>C:\\Qt\\6.7.2\\msvc2019_64</QtInstall>\n    <QtModules>core;gui;widgets;websockets</QtModules>\n    <QtBuildConfig>release</QtBuildConfig>\n    <QtDeploy>true</QtDeploy>\n  </PropertyGroup>\n  <Target Name=\"QtMsBuildNotFound\" BeforeTargets=\"CustomBuild;ClCompile\" Condition=\"!Exists('$(QtMsBuild)\\qt.targets') or !Exists('$(QtMsBuild)\\qt.props')\">\n    <Message Importance=\"High\" Text=\"QtMsBuild: could not locate qt.targets, qt.props; project may not build correctly.\" />\n  </Target>\n  <ImportGroup Label=\"ExtensionSettings\" />\n  <ImportGroup Label=\"Shared\" />\n  <ImportGroup Label=\"PropertySheets\" Condition=\"'$(Configuration)|$(Platform)' == 'Debug|x64'\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n    <Import Project=\"$(QtMsBuild)\\Qt.props\" />\n  </ImportGroup>\n  <ImportGroup Label=\"PropertySheets\" Condition=\"'$(Configuration)|$(Platform)' == 'Release|x64'\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n    <Import Project=\"$(QtMsBuild)\\Qt.props\" />\n  </ImportGroup>\n  <PropertyGroup Label=\"UserMacros\" />\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)' == 'Debug|x64'\">\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)' == 'Release|x64'\">\n    <IncludePath>C:\\Program Files\\VapourSynth\\sdk\\include;$(IncludePath)</IncludePath>\n  </PropertyGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">\n    <QtMoc>\n      <QtMocDir>..\\..\\vsedit-job-server-watcher\\generated\\moc</QtMocDir>\n    </QtMoc>\n    <QtRcc>\n      <QtRccDir>..\\..\\vsedit-job-server-watcher\\generated\\rcc</QtRccDir>\n    </QtRcc>\n    <QtUic>\n      <QtUicDir>..\\..\\vsedit-job-server-watcher\\generated\\ui</QtUicDir>\n    </QtUic>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)' == 'Debug|x64'\" Label=\"Configuration\">\n    <ClCompile>\n      <TreatWChar_tAsBuiltInType>true</TreatWChar_tAsBuiltInType>\n      <MultiProcessorCompilation>true</MultiProcessorCompilation>\n      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>\n      <Optimization>Disabled</Optimization>\n    </ClCompile>\n    <Link>\n      <SubSystem>Windows</SubSystem>\n      <GenerateDebugInformation>true</GenerateDebugInformation>\n    </Link>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)' == 'Release|x64'\" Label=\"Configuration\">\n    <ClCompile>\n      <TreatWChar_tAsBuiltInType>true</TreatWChar_tAsBuiltInType>\n      <MultiProcessorCompilation>true</MultiProcessorCompilation>\n      <DebugInformationFormat>None</DebugInformationFormat>\n      <Optimization>MaxSpeed</Optimization>\n    </ClCompile>\n    <Link>\n      <SubSystem>Windows</SubSystem>\n      <GenerateDebugInformation>false</GenerateDebugInformation>\n    </Link>\n  </ItemDefinitionGroup>\n  <ItemGroup>\n    <ProjectReference Include=\"..\\libp2p\\libp2p.vcxproj\">\n      <Project>{dd503806-0462-4cfe-bc5d-6355cf100832}</Project>\n    </ProjectReference>\n  </ItemGroup>\n  <ItemGroup>\n    <QtRcc Include=\"..\\..\\resources\\dark\\style.qrc\" />\n    <QtRcc Include=\"..\\..\\resources\\vsedit-job-server-watcher.qrc\" />\n  </ItemGroup>\n  <ItemGroup>\n    <ResourceCompile Include=\"vsedit-job-server-watcher.rc\" />\n  </ItemGroup>\n  <ItemGroup>\n    <Image Include=\"..\\..\\resources\\vsedit.ico\" />\n  </ItemGroup>\n  <ItemGroup>\n    <ClInclude Include=\"..\\..\\common-src\\application_instance_file_guard\\application_instance_file_guard.h\" />\n    <QtMoc Include=\"..\\..\\common-src\\frame_header_writers\\frame_header_writer.h\" />\n    <QtMoc Include=\"..\\..\\common-src\\frame_header_writers\\frame_header_writer_y4m.h\" />\n    <QtMoc Include=\"..\\..\\common-src\\frame_header_writers\\frame_header_writer_null.h\" />\n    <ClInclude Include=\"..\\..\\common-src\\helpers.h\" />\n    <ClInclude Include=\"..\\..\\common-src\\helpers_vs.h\" />\n    <ClInclude Include=\"..\\..\\common-src\\ipc_defines.h\" />\n    <ClInclude Include=\"..\\..\\common-src\\jobs\\job_variables.h\" />\n    <ClInclude Include=\"..\\..\\common-src\\log\\styled_log_view_core.h\" />\n    <ClInclude Include=\"..\\..\\common-src\\log\\styled_log_view_structures.h\" />\n    <ClInclude Include=\"..\\..\\common-src\\log\\vs_editor_log_definitions.h\" />\n    <ClInclude Include=\"..\\..\\common-src\\settings\\settings_definitions.h\" />\n    <ClInclude Include=\"..\\..\\common-src\\settings\\settings_definitions_core.h\" />\n    <ClInclude Include=\"..\\..\\common-src\\settings\\settings_manager.h\" />\n    <ClInclude Include=\"..\\..\\common-src\\settings\\settings_manager_core.h\" />\n    <ClInclude Include=\"..\\..\\common-src\\vapoursynth\\vs_pack_rgb.h\" />\n    <ClInclude Include=\"..\\..\\common-src\\vapoursynth\\vs_script_processor_structures.h\" />\n    <ClInclude Include=\"..\\..\\common-src\\vapoursynth\\vs_set_matrix.h\" />\n    <ClInclude Include=\"..\\..\\common-src\\version_info.h\" />\n    <ClInclude Include=\"..\\..\\common-src\\win32_console.h\" />\n    <QtMoc Include=\"..\\..\\vsedit-job-server-watcher\\src\\trusted_clients_addresses_dialog.h\" />\n    <QtMoc Include=\"..\\..\\vsedit-job-server-watcher\\src\\main_window.h\" />\n    <QtMoc Include=\"..\\..\\vsedit-job-server-watcher\\src\\jobs\\job_state_delegate.h\" />\n    <QtMoc Include=\"..\\..\\vsedit-job-server-watcher\\src\\jobs\\job_edit_dialog.h\" />\n    <QtMoc Include=\"..\\..\\vsedit-job-server-watcher\\src\\jobs\\job_dependencies_delegate.h\" />\n    <QtMoc Include=\"..\\..\\vsedit-job-server-watcher\\src\\jobs\\jobs_model.h\" />\n    <QtMoc Include=\"..\\..\\vsedit-job-server-watcher\\src\\connect_to_server_dialog.h\" />\n    <QtMoc Include=\"..\\..\\common-src\\vapoursynth\\vs_script_library.h\" />\n    <QtMoc Include=\"..\\..\\common-src\\vapoursynth\\vapoursynth_script_processor.h\" />\n    <QtMoc Include=\"..\\..\\common-src\\timeline_slider\\timeline_slider.h\" />\n    <QtMoc Include=\"..\\..\\common-src\\log\\vs_editor_log.h\" />\n    <QtMoc Include=\"..\\..\\common-src\\log\\styled_log_view_settings_dialog.h\" />\n    <QtMoc Include=\"..\\..\\common-src\\log\\styled_log_view.h\" />\n    <QtMoc Include=\"..\\..\\common-src\\log\\log_styles_model.h\" />\n    <QtMoc Include=\"..\\..\\common-src\\jobs\\job.h\" />\n    <ClInclude Include=\"resource.h\" />\n  </ItemGroup>\n  <ItemGroup>\n    <ClCompile Include=\"..\\..\\common-src\\application_instance_file_guard\\application_instance_file_guard.cpp\" />\n    <ClCompile Include=\"..\\..\\common-src\\frame_header_writers\\frame_header_writer.cpp\" />\n    <ClCompile Include=\"..\\..\\common-src\\frame_header_writers\\frame_header_writer_null.cpp\" />\n    <ClCompile Include=\"..\\..\\common-src\\frame_header_writers\\frame_header_writer_y4m.cpp\" />\n    <ClCompile Include=\"..\\..\\common-src\\helpers.cpp\" />\n    <ClCompile Include=\"..\\..\\common-src\\jobs\\job.cpp\" />\n    <ClCompile Include=\"..\\..\\common-src\\jobs\\job_variables.cpp\" />\n    <ClCompile Include=\"..\\..\\common-src\\log\\log_styles_model.cpp\" />\n    <ClCompile Include=\"..\\..\\common-src\\log\\styled_log_view.cpp\" />\n    <ClCompile Include=\"..\\..\\common-src\\log\\styled_log_view_core.cpp\" />\n    <ClCompile Include=\"..\\..\\common-src\\log\\styled_log_view_settings_dialog.cpp\" />\n    <ClCompile Include=\"..\\..\\common-src\\log\\styled_log_view_structures.cpp\" />\n    <ClCompile Include=\"..\\..\\common-src\\log\\vs_editor_log.cpp\" />\n    <ClCompile Include=\"..\\..\\common-src\\log\\vs_editor_log_definitions.cpp\" />\n    <ClCompile Include=\"..\\..\\common-src\\settings\\settings_definitions.cpp\" />\n    <ClCompile Include=\"..\\..\\common-src\\settings\\settings_definitions_core.cpp\" />\n    <ClCompile Include=\"..\\..\\common-src\\settings\\settings_manager.cpp\" />\n    <ClCompile Include=\"..\\..\\common-src\\settings\\settings_manager_core.cpp\" />\n    <ClCompile Include=\"..\\..\\common-src\\timeline_slider\\timeline_slider.cpp\" />\n    <ClCompile Include=\"..\\..\\common-src\\vapoursynth\\vapoursynth_script_processor.cpp\" />\n    <ClCompile Include=\"..\\..\\common-src\\vapoursynth\\vs_pack_rgb.cpp\" />\n    <ClCompile Include=\"..\\..\\common-src\\vapoursynth\\vs_script_library.cpp\" />\n    <ClCompile Include=\"..\\..\\common-src\\vapoursynth\\vs_script_processor_structures.cpp\" />\n    <ClCompile Include=\"..\\..\\common-src\\vapoursynth\\vs_set_matrix.cpp\" />\n    <ClCompile Include=\"..\\..\\common-src\\version_info.cpp\" />\n    <ClCompile Include=\"..\\..\\vsedit-job-server-watcher\\src\\connect_to_server_dialog.cpp\" />\n    <ClCompile Include=\"..\\..\\vsedit-job-server-watcher\\src\\jobs\\jobs_model.cpp\" />\n    <ClCompile Include=\"..\\..\\vsedit-job-server-watcher\\src\\jobs\\job_dependencies_delegate.cpp\" />\n    <ClCompile Include=\"..\\..\\vsedit-job-server-watcher\\src\\jobs\\job_edit_dialog.cpp\" />\n    <ClCompile Include=\"..\\..\\vsedit-job-server-watcher\\src\\jobs\\job_state_delegate.cpp\" />\n    <ClCompile Include=\"..\\..\\vsedit-job-server-watcher\\src\\main.cpp\" />\n    <ClCompile Include=\"..\\..\\vsedit-job-server-watcher\\src\\main_window.cpp\" />\n    <ClCompile Include=\"..\\..\\vsedit-job-server-watcher\\src\\trusted_clients_addresses_dialog.cpp\" />\n  </ItemGroup>\n  <ItemGroup>\n    <QtUic Include=\"..\\..\\common-src\\log\\styled_log_view_settings_dialog.ui\" />\n    <QtUic Include=\"..\\..\\vsedit-job-server-watcher\\src\\connect_to_server_dialog.ui\" />\n    <QtUic Include=\"..\\..\\vsedit-job-server-watcher\\src\\jobs\\job_edit_dialog.ui\" />\n    <QtUic Include=\"..\\..\\vsedit-job-server-watcher\\src\\main_window.ui\" />\n    <QtUic Include=\"..\\..\\vsedit-job-server-watcher\\src\\trusted_clients_addresses_dialog.ui\" />\n  </ItemGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.targets\" />\n  <ImportGroup Condition=\"Exists('$(QtMsBuild)\\qt.targets')\">\n    <Import Project=\"$(QtMsBuild)\\qt.targets\" />\n  </ImportGroup>\n  <ImportGroup Label=\"ExtensionTargets\">\n  </ImportGroup>\n</Project>"
  },
  {
    "path": "msvc/vsedit-job-server-watcher/vsedit-job-server-watcher.vcxproj.filters",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project ToolsVersion=\"4.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <ItemGroup>\n    <Filter Include=\"Source Files\">\n      <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>\n      <Extensions>qml;cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>\n    </Filter>\n    <Filter Include=\"Header Files\">\n      <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>\n      <Extensions>h;hh;hpp;hxx;hm;inl;inc;xsd</Extensions>\n    </Filter>\n    <Filter Include=\"Resource Files\">\n      <UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>\n      <Extensions>qrc;rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>\n    </Filter>\n    <Filter Include=\"Form Files\">\n      <UniqueIdentifier>{99349809-55BA-4b9d-BF79-8FDBB0286EB3}</UniqueIdentifier>\n      <Extensions>ui</Extensions>\n    </Filter>\n    <Filter Include=\"Translation Files\">\n      <UniqueIdentifier>{639EADAA-A684-42e4-A9AD-28FC9BCB8F7C}</UniqueIdentifier>\n      <Extensions>ts</Extensions>\n    </Filter>\n  </ItemGroup>\n  <ItemGroup>\n    <QtRcc Include=\"..\\..\\resources\\dark\\style.qrc\">\n      <Filter>Resource Files</Filter>\n    </QtRcc>\n    <QtRcc Include=\"..\\..\\resources\\vsedit-job-server-watcher.qrc\">\n      <Filter>Resource Files</Filter>\n    </QtRcc>\n  </ItemGroup>\n  <ItemGroup>\n    <ResourceCompile Include=\"vsedit-job-server-watcher.rc\">\n      <Filter>Resource Files</Filter>\n    </ResourceCompile>\n  </ItemGroup>\n  <ItemGroup>\n    <Image Include=\"..\\..\\resources\\vsedit.ico\">\n      <Filter>Resource Files</Filter>\n    </Image>\n  </ItemGroup>\n  <ItemGroup>\n    <ClInclude Include=\"resource.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\common-src\\application_instance_file_guard\\application_instance_file_guard.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\common-src\\jobs\\job_variables.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\common-src\\log\\styled_log_view_core.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\common-src\\log\\styled_log_view_structures.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\common-src\\log\\vs_editor_log_definitions.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\common-src\\settings\\settings_definitions.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\common-src\\settings\\settings_definitions_core.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\common-src\\settings\\settings_manager.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\common-src\\settings\\settings_manager_core.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\common-src\\vapoursynth\\vs_pack_rgb.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\common-src\\vapoursynth\\vs_script_processor_structures.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\common-src\\vapoursynth\\vs_set_matrix.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\common-src\\helpers.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\common-src\\helpers_vs.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\common-src\\ipc_defines.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\common-src\\version_info.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\common-src\\win32_console.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n  </ItemGroup>\n  <ItemGroup>\n    <ClCompile Include=\"..\\..\\common-src\\application_instance_file_guard\\application_instance_file_guard.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\common-src\\jobs\\job.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\common-src\\jobs\\job_variables.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\common-src\\log\\log_styles_model.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\common-src\\log\\styled_log_view.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\common-src\\log\\styled_log_view_core.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\common-src\\log\\styled_log_view_settings_dialog.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\common-src\\log\\styled_log_view_structures.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\common-src\\log\\vs_editor_log.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\common-src\\log\\vs_editor_log_definitions.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\common-src\\settings\\settings_definitions.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\common-src\\settings\\settings_definitions_core.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\common-src\\settings\\settings_manager.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\common-src\\settings\\settings_manager_core.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\common-src\\timeline_slider\\timeline_slider.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\common-src\\vapoursynth\\vapoursynth_script_processor.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\common-src\\vapoursynth\\vs_pack_rgb.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\common-src\\vapoursynth\\vs_script_library.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\common-src\\vapoursynth\\vs_script_processor_structures.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\common-src\\vapoursynth\\vs_set_matrix.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\common-src\\helpers.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\common-src\\version_info.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\vsedit-job-server-watcher\\src\\connect_to_server_dialog.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\vsedit-job-server-watcher\\src\\jobs\\jobs_model.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\vsedit-job-server-watcher\\src\\jobs\\job_dependencies_delegate.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\vsedit-job-server-watcher\\src\\jobs\\job_edit_dialog.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\vsedit-job-server-watcher\\src\\jobs\\job_state_delegate.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\vsedit-job-server-watcher\\src\\main.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\vsedit-job-server-watcher\\src\\main_window.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\vsedit-job-server-watcher\\src\\trusted_clients_addresses_dialog.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\common-src\\frame_header_writers\\frame_header_writer_null.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\common-src\\frame_header_writers\\frame_header_writer_y4m.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\common-src\\frame_header_writers\\frame_header_writer.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n  </ItemGroup>\n  <ItemGroup>\n    <QtMoc Include=\"..\\..\\common-src\\jobs\\job.h\">\n      <Filter>Header Files</Filter>\n    </QtMoc>\n    <QtMoc Include=\"..\\..\\common-src\\log\\log_styles_model.h\">\n      <Filter>Header Files</Filter>\n    </QtMoc>\n    <QtMoc Include=\"..\\..\\common-src\\log\\styled_log_view.h\">\n      <Filter>Header Files</Filter>\n    </QtMoc>\n    <QtMoc Include=\"..\\..\\common-src\\log\\styled_log_view_settings_dialog.h\">\n      <Filter>Header Files</Filter>\n    </QtMoc>\n    <QtMoc Include=\"..\\..\\common-src\\log\\vs_editor_log.h\">\n      <Filter>Header Files</Filter>\n    </QtMoc>\n    <QtMoc Include=\"..\\..\\common-src\\timeline_slider\\timeline_slider.h\">\n      <Filter>Header Files</Filter>\n    </QtMoc>\n    <QtMoc Include=\"..\\..\\common-src\\vapoursynth\\vapoursynth_script_processor.h\">\n      <Filter>Header Files</Filter>\n    </QtMoc>\n    <QtMoc Include=\"..\\..\\common-src\\vapoursynth\\vs_script_library.h\">\n      <Filter>Header Files</Filter>\n    </QtMoc>\n    <QtMoc Include=\"..\\..\\vsedit-job-server-watcher\\src\\connect_to_server_dialog.h\">\n      <Filter>Header Files</Filter>\n    </QtMoc>\n    <QtMoc Include=\"..\\..\\vsedit-job-server-watcher\\src\\jobs\\jobs_model.h\">\n      <Filter>Header Files</Filter>\n    </QtMoc>\n    <QtMoc Include=\"..\\..\\vsedit-job-server-watcher\\src\\jobs\\job_dependencies_delegate.h\">\n      <Filter>Header Files</Filter>\n    </QtMoc>\n    <QtMoc Include=\"..\\..\\vsedit-job-server-watcher\\src\\jobs\\job_edit_dialog.h\">\n      <Filter>Header Files</Filter>\n    </QtMoc>\n    <QtMoc Include=\"..\\..\\vsedit-job-server-watcher\\src\\jobs\\job_state_delegate.h\">\n      <Filter>Header Files</Filter>\n    </QtMoc>\n    <QtMoc Include=\"..\\..\\vsedit-job-server-watcher\\src\\main_window.h\">\n      <Filter>Header Files</Filter>\n    </QtMoc>\n    <QtMoc Include=\"..\\..\\vsedit-job-server-watcher\\src\\trusted_clients_addresses_dialog.h\">\n      <Filter>Header Files</Filter>\n    </QtMoc>\n    <QtMoc Include=\"..\\..\\common-src\\frame_header_writers\\frame_header_writer_null.h\">\n      <Filter>Header Files</Filter>\n    </QtMoc>\n    <QtMoc Include=\"..\\..\\common-src\\frame_header_writers\\frame_header_writer_y4m.h\">\n      <Filter>Header Files</Filter>\n    </QtMoc>\n    <QtMoc Include=\"..\\..\\common-src\\frame_header_writers\\frame_header_writer.h\">\n      <Filter>Header Files</Filter>\n    </QtMoc>\n  </ItemGroup>\n  <ItemGroup>\n    <QtUic Include=\"..\\..\\common-src\\log\\styled_log_view_settings_dialog.ui\">\n      <Filter>Form Files</Filter>\n    </QtUic>\n    <QtUic Include=\"..\\..\\vsedit-job-server-watcher\\src\\connect_to_server_dialog.ui\">\n      <Filter>Form Files</Filter>\n    </QtUic>\n    <QtUic Include=\"..\\..\\vsedit-job-server-watcher\\src\\main_window.ui\">\n      <Filter>Form Files</Filter>\n    </QtUic>\n    <QtUic Include=\"..\\..\\vsedit-job-server-watcher\\src\\trusted_clients_addresses_dialog.ui\">\n      <Filter>Form Files</Filter>\n    </QtUic>\n    <QtUic Include=\"..\\..\\vsedit-job-server-watcher\\src\\jobs\\job_edit_dialog.ui\">\n      <Filter>Form Files</Filter>\n    </QtUic>\n  </ItemGroup>\n</Project>"
  },
  {
    "path": "msvc/vsedit-previewer/resource.h",
    "content": "//{{NO_DEPENDENCIES}}\n// Microsoft Visual C++ generated include file.\n// Used by vsedit.rc\n//\n#define IDI_ICON1                       101\n\n// Next default values for new objects\n// \n#ifdef APSTUDIO_INVOKED\n#ifndef APSTUDIO_READONLY_SYMBOLS\n#define _APS_NEXT_RESOURCE_VALUE        102\n#define _APS_NEXT_COMMAND_VALUE         40001\n#define _APS_NEXT_CONTROL_VALUE         1001\n#define _APS_NEXT_SYMED_VALUE           101\n#endif\n#endif\n"
  },
  {
    "path": "msvc/vsedit-previewer/vsedit-previewer.vcxproj",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project DefaultTargets=\"Build\" ToolsVersion=\"17.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <ItemGroup Label=\"ProjectConfigurations\">\n    <ProjectConfiguration Include=\"Debug|x64\">\n      <Configuration>Debug</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Release|x64\">\n      <Configuration>Release</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n  </ItemGroup>\n  <PropertyGroup Label=\"Globals\">\n    <ProjectGuid>{654CE67F-6EB3-4DBD-86F2-D3DB7081FA04}</ProjectGuid>\n    <Keyword>QtVS_v304</Keyword>\n    <WindowsTargetPlatformVersion Condition=\"'$(Configuration)|$(Platform)' == 'Debug|x64'\">10.0.22621.0</WindowsTargetPlatformVersion>\n    <WindowsTargetPlatformVersion Condition=\"'$(Configuration)|$(Platform)' == 'Release|x64'\">10.0</WindowsTargetPlatformVersion>\n    <QtMsBuild Condition=\"'$(QtMsBuild)'=='' OR !Exists('$(QtMsBuild)\\qt.targets')\">$(MSBuildProjectDirectory)\\QtMsBuild</QtMsBuild>\n  </PropertyGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.Default.props\" />\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)' == 'Debug|x64'\" Label=\"Configuration\">\n    <ConfigurationType>Application</ConfigurationType>\n    <PlatformToolset>v143</PlatformToolset>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)' == 'Release|x64'\" Label=\"Configuration\">\n    <ConfigurationType>Application</ConfigurationType>\n    <PlatformToolset>v143</PlatformToolset>\n    <WholeProgramOptimization>true</WholeProgramOptimization>\n  </PropertyGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.props\" />\n  <ImportGroup Condition=\"Exists('$(QtMsBuild)\\qt_defaults.props')\">\n    <Import Project=\"$(QtMsBuild)\\qt_defaults.props\" />\n  </ImportGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)' == 'Debug|x64'\" Label=\"QtSettings\">\n    <QtInstall>C:\\Qt\\6.7.2\\msvc2019_64</QtInstall>\n    <QtModules>\n    </QtModules>\n    <QtBuildConfig>debug</QtBuildConfig>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)' == 'Release|x64'\" Label=\"QtSettings\">\n    <QtInstall>C:\\Qt\\6.7.2\\msvc2019_64</QtInstall>\n    <QtModules>core;gui;multimedia;widgets</QtModules>\n    <QtBuildConfig>release</QtBuildConfig>\n    <QtDeploy>true</QtDeploy>\n  </PropertyGroup>\n  <Target Name=\"QtMsBuildNotFound\" BeforeTargets=\"CustomBuild;ClCompile\" Condition=\"!Exists('$(QtMsBuild)\\qt.targets') or !Exists('$(QtMsBuild)\\qt.props')\">\n    <Message Importance=\"High\" Text=\"QtMsBuild: could not locate qt.targets, qt.props; project may not build correctly.\" />\n  </Target>\n  <ImportGroup Label=\"ExtensionSettings\" />\n  <ImportGroup Label=\"Shared\" />\n  <ImportGroup Label=\"PropertySheets\" Condition=\"'$(Configuration)|$(Platform)' == 'Debug|x64'\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n    <Import Project=\"$(QtMsBuild)\\Qt.props\" />\n  </ImportGroup>\n  <ImportGroup Label=\"PropertySheets\" Condition=\"'$(Configuration)|$(Platform)' == 'Release|x64'\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n    <Import Project=\"$(QtMsBuild)\\Qt.props\" />\n  </ImportGroup>\n  <PropertyGroup Label=\"UserMacros\" />\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)' == 'Debug|x64'\">\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)' == 'Release|x64'\">\n    <IncludePath>C:\\Program Files\\VapourSynth\\sdk\\include;$(IncludePath)</IncludePath>\n  </PropertyGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">\n    <QtMoc>\n      <QtMocDir>..\\..\\vsedit\\generated\\moc</QtMocDir>\n    </QtMoc>\n    <QtRcc>\n      <QtRccDir>..\\..\\vsedit\\generated\\rcc</QtRccDir>\n    </QtRcc>\n    <QtUic>\n      <QtUicDir>..\\..\\vsedit\\generated\\ui</QtUicDir>\n    </QtUic>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)' == 'Debug|x64'\" Label=\"Configuration\">\n    <ClCompile>\n      <TreatWChar_tAsBuiltInType>true</TreatWChar_tAsBuiltInType>\n      <MultiProcessorCompilation>true</MultiProcessorCompilation>\n      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>\n      <Optimization>Disabled</Optimization>\n    </ClCompile>\n    <Link>\n      <SubSystem>Windows</SubSystem>\n      <GenerateDebugInformation>true</GenerateDebugInformation>\n    </Link>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)' == 'Release|x64'\" Label=\"Configuration\">\n    <ClCompile>\n      <TreatWChar_tAsBuiltInType>true</TreatWChar_tAsBuiltInType>\n      <MultiProcessorCompilation>true</MultiProcessorCompilation>\n      <DebugInformationFormat>None</DebugInformationFormat>\n      <Optimization>MaxSpeed</Optimization>\n    </ClCompile>\n    <Link>\n      <SubSystem>Console</SubSystem>\n      <GenerateDebugInformation>false</GenerateDebugInformation>\n    </Link>\n  </ItemDefinitionGroup>\n  <ItemGroup>\n    <ProjectReference Include=\"..\\libp2p\\libp2p.vcxproj\">\n      <Project>{dd503806-0462-4cfe-bc5d-6355cf100832}</Project>\n    </ProjectReference>\n  </ItemGroup>\n  <ItemGroup>\n    <QtUic Include=\"..\\..\\vsedit\\src\\preview\\preview_advanced_settings_dialog.ui\" />\n    <QtUic Include=\"..\\..\\vsedit\\src\\preview\\preview_dialog.ui\" />\n    <QtUic Include=\"..\\..\\vsedit\\src\\script_status_bar_widget\\script_status_bar_widget.ui\" />\n  </ItemGroup>\n  <ItemGroup>\n    <QtMoc Include=\"..\\..\\vsedit\\src\\vapoursynth\\vs_script_processor_dialog.h\" />\n  </ItemGroup>\n  <ItemGroup>\n    <ClInclude Include=\"..\\..\\common-src\\chrono.h\" />\n    <ClInclude Include=\"..\\..\\common-src\\settings\\settings_definitions_core.h\" />\n    <ClInclude Include=\"resource.h\" />\n    <ClInclude Include=\"..\\..\\common-src\\helpers.h\" />\n    <ClInclude Include=\"..\\..\\common-src\\helpers_vs.h\" />\n    <ClInclude Include=\"..\\..\\common-src\\log\\styled_log_view_core.h\" />\n    <ClInclude Include=\"..\\..\\common-src\\log\\styled_log_view_structures.h\" />\n    <ClInclude Include=\"..\\..\\common-src\\log\\vs_editor_log_definitions.h\" />\n    <QtMoc Include=\"..\\..\\common-src\\log\\log_styles_model.h\" />\n    <ClInclude Include=\"..\\..\\common-src\\settings\\settings_definitions.h\" />\n    <ClInclude Include=\"..\\..\\common-src\\settings\\settings_manager.h\" />\n    <ClInclude Include=\"..\\..\\common-src\\settings\\settings_manager_core.h\" />\n    <QtMoc Include=\"..\\..\\common-src\\timeline_slider\\timeline_slider.h\" />\n    <ClInclude Include=\"..\\..\\common-src\\vapoursynth\\vs_pack_rgb.h\" />\n    <ClInclude Include=\"..\\..\\common-src\\vapoursynth\\vs_script_processor_structures.h\" />\n    <ClInclude Include=\"..\\..\\common-src\\vapoursynth\\vs_set_matrix.h\" />\n    <QtMoc Include=\"..\\..\\common-src\\vapoursynth\\vs_script_library.h\" />\n    <QtMoc Include=\"..\\..\\common-src\\vapoursynth\\vapoursynth_script_processor.h\" />\n    <ClInclude Include=\"..\\..\\common-src\\version_info.h\" />\n    <QtMoc Include=\"..\\..\\vsedit\\src\\preview\\preview_advanced_settings_dialog.h\" />\n    <QtMoc Include=\"..\\..\\vsedit\\src\\preview\\preview_area.h\" />\n    <QtMoc Include=\"..\\..\\vsedit\\src\\preview\\preview_dialog.h\" />\n    <ClInclude Include=\"..\\..\\vsedit\\src\\preview\\scroll_navigator.h\" />\n    <ClInclude Include=\"..\\..\\vsedit\\src\\preview\\zoom_ratio_spinbox.h\" />\n    <QtMoc Include=\"..\\..\\vsedit\\src\\script_status_bar_widget\\script_status_bar_widget.h\" />\n    <QtMoc Include=\"..\\..\\vsedit\\src\\settings\\item_delegate_for_hotkey.h\" />\n    <QtMoc Include=\"..\\..\\vsedit\\src\\settings\\clearable_key_sequence_editor.h\" />\n    <QtMoc Include=\"..\\..\\vsedit\\src\\settings\\actions_hotkey_edit_model.h\" />\n    <QtMoc Include=\"..\\..\\vsedit\\src\\settings\\theme_elements_model.h\" />\n    <ClInclude Include=\"..\\..\\vsedit\\src\\vapoursynth\\vs_plugin_data.h\" />\n  </ItemGroup>\n  <ItemGroup>\n    <ClCompile Include=\"..\\..\\common-src\\helpers.cpp\" />\n    <ClCompile Include=\"..\\..\\common-src\\log\\log_styles_model.cpp\" />\n    <ClCompile Include=\"..\\..\\common-src\\log\\styled_log_view_core.cpp\" />\n    <ClCompile Include=\"..\\..\\common-src\\log\\styled_log_view_structures.cpp\" />\n    <ClCompile Include=\"..\\..\\common-src\\log\\vs_editor_log_definitions.cpp\" />\n    <ClCompile Include=\"..\\..\\common-src\\settings\\settings_definitions.cpp\" />\n    <ClCompile Include=\"..\\..\\common-src\\settings\\settings_definitions_core.cpp\" />\n    <ClCompile Include=\"..\\..\\common-src\\settings\\settings_manager.cpp\" />\n    <ClCompile Include=\"..\\..\\common-src\\settings\\settings_manager_core.cpp\" />\n    <ClCompile Include=\"..\\..\\common-src\\timeline_slider\\timeline_slider.cpp\" />\n    <ClCompile Include=\"..\\..\\common-src\\vapoursynth\\vapoursynth_script_processor.cpp\" />\n    <ClCompile Include=\"..\\..\\common-src\\vapoursynth\\vs_pack_rgb.cpp\" />\n    <ClCompile Include=\"..\\..\\common-src\\vapoursynth\\vs_script_library.cpp\" />\n    <ClCompile Include=\"..\\..\\common-src\\vapoursynth\\vs_script_processor_structures.cpp\" />\n    <ClCompile Include=\"..\\..\\common-src\\vapoursynth\\vs_set_matrix.cpp\" />\n    <ClCompile Include=\"..\\..\\common-src\\version_info.cpp\" />\n    <ClCompile Include=\"..\\..\\vsedit\\src\\preview\\preview_advanced_settings_dialog.cpp\" />\n    <ClCompile Include=\"..\\..\\vsedit\\src\\preview\\preview_area.cpp\" />\n    <ClCompile Include=\"..\\..\\vsedit\\src\\preview\\preview_dialog.cpp\" />\n    <ClCompile Include=\"..\\..\\vsedit\\src\\preview\\scroll_navigator.cpp\" />\n    <ClCompile Include=\"..\\..\\vsedit\\src\\preview\\zoom_ratio_spinbox.cpp\" />\n    <ClCompile Include=\"..\\..\\vsedit\\src\\script_status_bar_widget\\script_status_bar_widget.cpp\" />\n    <ClCompile Include=\"..\\..\\vsedit\\src\\settings\\actions_hotkey_edit_model.cpp\" />\n    <ClCompile Include=\"..\\..\\vsedit\\src\\settings\\clearable_key_sequence_editor.cpp\" />\n    <ClCompile Include=\"..\\..\\vsedit\\src\\settings\\item_delegate_for_hotkey.cpp\" />\n    <ClCompile Include=\"..\\..\\vsedit\\src\\settings\\theme_elements_model.cpp\" />\n    <ClCompile Include=\"..\\..\\vsedit\\src\\vapoursynth\\vs_script_processor_dialog.cpp\" />\n    <ClCompile Include=\"..\\..\\vsedit\\src\\vsedit_previewer_main.cpp\" />\n  </ItemGroup>\n  <ItemGroup>\n    <QtRcc Include=\"..\\..\\resources\\dark\\style.qrc\" />\n    <QtRcc Include=\"..\\..\\resources\\vsedit.qrc\" />\n  </ItemGroup>\n  <ItemGroup>\n    <ResourceCompile Include=\"vsedit-previewer.rc\" />\n  </ItemGroup>\n  <ItemGroup>\n    <Image Include=\"..\\..\\resources\\vsedit.ico\" />\n  </ItemGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.targets\" />\n  <ImportGroup Condition=\"Exists('$(QtMsBuild)\\qt.targets')\">\n    <Import Project=\"$(QtMsBuild)\\qt.targets\" />\n  </ImportGroup>\n  <ImportGroup Label=\"ExtensionTargets\">\n  </ImportGroup>\n</Project>"
  },
  {
    "path": "msvc/vsedit-previewer/vsedit-previewer.vcxproj.filters",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project ToolsVersion=\"4.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <ItemGroup>\n    <Filter Include=\"Source Files\">\n      <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>\n      <Extensions>qml;cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>\n    </Filter>\n    <Filter Include=\"Header Files\">\n      <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>\n      <Extensions>h;hh;hpp;hxx;hm;inl;inc;xsd</Extensions>\n    </Filter>\n    <Filter Include=\"Resource Files\">\n      <UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>\n      <Extensions>qrc;rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>\n    </Filter>\n    <Filter Include=\"Form Files\">\n      <UniqueIdentifier>{99349809-55BA-4b9d-BF79-8FDBB0286EB3}</UniqueIdentifier>\n      <Extensions>ui</Extensions>\n    </Filter>\n    <Filter Include=\"Translation Files\">\n      <UniqueIdentifier>{639EADAA-A684-42e4-A9AD-28FC9BCB8F7C}</UniqueIdentifier>\n      <Extensions>ts</Extensions>\n    </Filter>\n  </ItemGroup>\n  <ItemGroup>\n    <QtUic Include=\"..\\..\\vsedit\\src\\script_status_bar_widget\\script_status_bar_widget.ui\">\n      <Filter>Form Files</Filter>\n    </QtUic>\n    <QtUic Include=\"..\\..\\vsedit\\src\\preview\\preview_advanced_settings_dialog.ui\">\n      <Filter>Form Files</Filter>\n    </QtUic>\n    <QtUic Include=\"..\\..\\vsedit\\src\\preview\\preview_dialog.ui\">\n      <Filter>Form Files</Filter>\n    </QtUic>\n  </ItemGroup>\n  <ItemGroup>\n    <QtMoc Include=\"..\\..\\vsedit\\src\\vapoursynth\\vs_script_processor_dialog.h\">\n      <Filter>Header Files</Filter>\n    </QtMoc>\n    <QtMoc Include=\"..\\..\\vsedit\\src\\settings\\theme_elements_model.h\">\n      <Filter>Header Files</Filter>\n    </QtMoc>\n    <QtMoc Include=\"..\\..\\vsedit\\src\\settings\\actions_hotkey_edit_model.h\">\n      <Filter>Header Files</Filter>\n    </QtMoc>\n    <QtMoc Include=\"..\\..\\vsedit\\src\\settings\\clearable_key_sequence_editor.h\">\n      <Filter>Header Files</Filter>\n    </QtMoc>\n    <QtMoc Include=\"..\\..\\vsedit\\src\\settings\\item_delegate_for_hotkey.h\">\n      <Filter>Header Files</Filter>\n    </QtMoc>\n    <QtMoc Include=\"..\\..\\vsedit\\src\\script_status_bar_widget\\script_status_bar_widget.h\">\n      <Filter>Header Files</Filter>\n    </QtMoc>\n    <QtMoc Include=\"..\\..\\vsedit\\src\\preview\\preview_dialog.h\">\n      <Filter>Header Files</Filter>\n    </QtMoc>\n    <QtMoc Include=\"..\\..\\vsedit\\src\\preview\\preview_area.h\">\n      <Filter>Header Files</Filter>\n    </QtMoc>\n    <QtMoc Include=\"..\\..\\vsedit\\src\\preview\\preview_advanced_settings_dialog.h\">\n      <Filter>Header Files</Filter>\n    </QtMoc>\n    <QtMoc Include=\"..\\..\\common-src\\vapoursynth\\vapoursynth_script_processor.h\">\n      <Filter>Header Files</Filter>\n    </QtMoc>\n    <QtMoc Include=\"..\\..\\common-src\\vapoursynth\\vs_script_library.h\">\n      <Filter>Header Files</Filter>\n    </QtMoc>\n    <QtMoc Include=\"..\\..\\common-src\\timeline_slider\\timeline_slider.h\">\n      <Filter>Header Files</Filter>\n    </QtMoc>\n    <QtMoc Include=\"..\\..\\common-src\\log\\log_styles_model.h\">\n      <Filter>Header Files</Filter>\n    </QtMoc>\n  </ItemGroup>\n  <ItemGroup>\n    <ClInclude Include=\"..\\..\\vsedit\\src\\vapoursynth\\vs_plugin_data.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\vsedit\\src\\preview\\zoom_ratio_spinbox.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\vsedit\\src\\preview\\scroll_navigator.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\common-src\\helpers.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\common-src\\helpers_vs.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\common-src\\version_info.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\common-src\\chrono.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\common-src\\vapoursynth\\vs_pack_rgb.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\common-src\\vapoursynth\\vs_script_processor_structures.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\common-src\\vapoursynth\\vs_set_matrix.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\common-src\\settings\\settings_definitions.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\common-src\\settings\\settings_manager.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\common-src\\settings\\settings_manager_core.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\common-src\\log\\styled_log_view_core.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\common-src\\log\\styled_log_view_structures.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\common-src\\log\\vs_editor_log_definitions.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\common-src\\settings\\settings_definitions_core.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"resource.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n  </ItemGroup>\n  <ItemGroup>\n    <ClCompile Include=\"..\\..\\vsedit\\src\\vapoursynth\\vs_script_processor_dialog.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\vsedit\\src\\settings\\theme_elements_model.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\vsedit\\src\\settings\\actions_hotkey_edit_model.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\vsedit\\src\\settings\\clearable_key_sequence_editor.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\vsedit\\src\\settings\\item_delegate_for_hotkey.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\vsedit\\src\\script_status_bar_widget\\script_status_bar_widget.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\vsedit\\src\\preview\\scroll_navigator.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\vsedit\\src\\preview\\zoom_ratio_spinbox.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\vsedit\\src\\preview\\preview_dialog.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\vsedit\\src\\preview\\preview_area.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\vsedit\\src\\preview\\preview_advanced_settings_dialog.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\common-src\\helpers.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\common-src\\version_info.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\common-src\\vapoursynth\\vs_set_matrix.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\common-src\\vapoursynth\\vapoursynth_script_processor.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\common-src\\vapoursynth\\vs_pack_rgb.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\common-src\\vapoursynth\\vs_script_library.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\common-src\\vapoursynth\\vs_script_processor_structures.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\common-src\\timeline_slider\\timeline_slider.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\common-src\\settings\\settings_manager_core.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\common-src\\settings\\settings_definitions.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\common-src\\settings\\settings_definitions_core.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\common-src\\settings\\settings_manager.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\common-src\\log\\log_styles_model.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\common-src\\log\\styled_log_view_core.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\common-src\\log\\styled_log_view_structures.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\common-src\\log\\vs_editor_log_definitions.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\vsedit\\src\\vsedit_previewer_main.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n  </ItemGroup>\n  <ItemGroup>\n    <QtRcc Include=\"..\\..\\resources\\vsedit.qrc\">\n      <Filter>Resource Files</Filter>\n    </QtRcc>\n    <QtRcc Include=\"..\\..\\resources\\dark\\style.qrc\">\n      <Filter>Resource Files</Filter>\n    </QtRcc>\n  </ItemGroup>\n  <ItemGroup>\n    <ResourceCompile Include=\"vsedit-previewer.rc\">\n      <Filter>Resource Files</Filter>\n    </ResourceCompile>\n  </ItemGroup>\n  <ItemGroup>\n    <Image Include=\"..\\..\\resources\\vsedit.ico\">\n      <Filter>Resource Files</Filter>\n    </Image>\n  </ItemGroup>\n</Project>"
  },
  {
    "path": "pro/build-inno-setup.iss",
    "content": "; https://jrsoftware.org/ishelp/index.php\n\n#define AppName \"VapourSynth Editor\"\n#define ExeName \"vsedit\"\n#define Version \"r19-mod-6.10\"\n\n[Setup]\nAppId={#AppName}\nAppName={#AppName}\nAppPublisher=YomikoR\nAppPublisherURL=https://github.com/YomikoR/VapourSynth-Editor\nAppReadmeFile=https://github.com/YomikoR/VapourSynth-Editor/blob/vs-api4/README\nAppSupportURL=https://github.com/YomikoR/VapourSynth-Editor/issues\nAppUpdatesURL=https://github.com/YomikoR/VapourSynth-Editor/blob/vs-api4/CHANGELOG\nAppVerName={#AppName} {#Version}\nAppVersion={#Version}\nArchitecturesAllowed=x64\nArchitecturesInstallIn64BitMode=x64\nChangesAssociations=yes\nCompression=lzma2/max\nDefaultDirName={autopf}\\{#AppName}\nDefaultGroupName={#AppName}\nLicenseFile=..\\LICENSE\nOutputBaseFilename={#AppName}-{#Version}-setup\nOutputDir=dist\nOutputManifestFile={#AppName}-{#Version}-setup-manifest.txt\nPrivilegesRequired=lowest\nPrivilegesRequiredOverridesAllowed=dialog commandline\nSetupIconFile=..\\resources\\{#ExeName}.ico\nSolidCompression=yes\nVersionInfoVersion=1.0.0\nWizardStyle=modern dynamic\n\n[Languages]\nName: \"english\"; MessagesFile: \"compiler:Default.isl\"\n\n[Tasks]\nName: \"desktopicon\"; Description: \"{cm:CreateDesktopIcon}\"; GroupDescription: \"{cm:AdditionalIcons}\"; Flags: unchecked\n\n[Files]\nSource: ..\\build\\release-64bit-msvc\\vsedit.exe; DestDir: {app}; Flags: ignoreversion uninsrestartdelete restartreplace\nSource: ..\\build\\release-64bit-msvc\\vsedit-job-server.exe; DestDir: {app}; Flags: ignoreversion uninsrestartdelete restartreplace\nSource: ..\\build\\release-64bit-msvc\\vsedit-job-server-watcher.exe; DestDir: {app}; Flags: ignoreversion uninsrestartdelete restartreplace\nSource: ..\\build\\release-64bit-msvc\\vsedit-previewer.exe; DestDir: {app}; Flags: ignoreversion uninsrestartdelete restartreplace\nSource: ..\\build\\release-64bit-msvc\\vsedit-encode.exe; DestDir: {app}; Flags: ignoreversion uninsrestartdelete restartreplace\nSource: ..\\build\\release-64bit-msvc\\vsedit.ico; DestDir: {app}; Flags: ignoreversion uninsrestartdelete restartreplace\nSource: ..\\build\\release-64bit-msvc\\vsedit.svg; DestDir: {app}; Flags: ignoreversion uninsrestartdelete restartreplace\nSource: ..\\build\\release-64bit-msvc\\README; DestDir: {app}; Flags: ignoreversion uninsrestartdelete restartreplace\nSource: ..\\build\\release-64bit-msvc\\LICENSE; DestDir: {app}; Flags: ignoreversion uninsrestartdelete restartreplace\nSource: ..\\build\\release-64bit-msvc\\CHANGELOG; DestDir: {app}; Flags: ignoreversion uninsrestartdelete restartreplace\nSource: ..\\build\\release-64bit-msvc\\Qt6Core.dll; DestDir: {app}; Flags: ignoreversion uninsrestartdelete restartreplace\nSource: ..\\build\\release-64bit-msvc\\Qt6Gui.dll; DestDir: {app}; Flags: ignoreversion uninsrestartdelete restartreplace\nSource: ..\\build\\release-64bit-msvc\\Qt6Multimedia.dll; DestDir: {app}; Flags: ignoreversion uninsrestartdelete restartreplace\nSource: ..\\build\\release-64bit-msvc\\Qt6Network.dll; DestDir: {app}; Flags: ignoreversion uninsrestartdelete restartreplace\nSource: ..\\build\\release-64bit-msvc\\Qt6WebSockets.dll; DestDir: {app}; Flags: ignoreversion uninsrestartdelete restartreplace\nSource: ..\\build\\release-64bit-msvc\\Qt6Widgets.dll; DestDir: {app}; Flags: ignoreversion uninsrestartdelete restartreplace\nSource: ..\\build\\release-64bit-msvc\\imageformats\\qwebp.dll; DestDir: {app}\\imageformats; Flags: ignoreversion uninsrestartdelete restartreplace\nSource: ..\\build\\release-64bit-msvc\\platforms\\qwindows.dll; DestDir: {app}\\platforms; Flags: ignoreversion uninsrestartdelete restartreplace\nSource: ..\\build\\release-64bit-msvc\\multimedia\\windowsmediaplugin.dll; DestDir: {app}\\multimedia; Flags: ignoreversion uninsrestartdelete restartreplace\n\n[Icons]\nName: \"{group}\\{#AppName}\"; Filename: \"{app}\\{#ExeName}.exe\"\nName: \"{group}\\VapourSynth Jobs Server Watcher\"; Filename: \"{app}\\{#ExeName}-job-server-watcher.exe\"\nName: \"{autodesktop}\\{#AppName}\"; Filename: \"{app}\\{#ExeName}.exe\"; Tasks: desktopicon\n\n[Run]\nFilename: \"{app}\\{#ExeName}.exe\"; Description: \"{cm:LaunchProgram,{#StringChange(AppName, '&', '&&')}}\"; Flags: nowait postinstall skipifsilent\n"
  },
  {
    "path": "pro/build-msvc.bat",
    "content": "@ECHO THIS SCRIPT IS OUTDATED AND NO MORE MAINTAINED. USE IT AS A REFERENCE ONLY.\n@SET BRANCH=%1\n@IF \"%BRANCH%\"==\"\" (\nSET GIT_BRANCH=\nSET NAME_BRANCH=\n)\n@IF NOT \"%BRANCH%\"==\"\" (\nSET GIT_BRANCH=-b %BRANCH%\nSET NAME_BRANCH=_%BRANCH%\n)\n@SET BUILDROOT=vsedit-build\n\n@pushd \"%TEMP%\"\n@rd /q /s %BUILDROOT%\n@mkdir %BUILDROOT%\ngit clone %GIT_BRANCH% https://bitbucket.org/mystery_keeper/vapoursynth-editor.git vsedit-build\n@cd /d %BUILDROOT%\\pro\n\n@SET ORIGINAL_PATH=%PATH%\n\n:: MSVC 64 bit build\n@ECHO === SETTING UP ENVIRONMENT ===\n@call \"C:\\Program Files (x86)\\Microsoft Visual Studio\\2017\\Community\\VC\\Auxiliary\\Build\\vcvars64.bat\"\n@SET PATH=%PATH%;S:\\sdk\\qt\\5.12.0\\msvc2017_64\\bin\\\n@ECHO === RUNNING QMAKE === \nqmake.exe -nocache \"CONFIG+=release\" pro.pro\n@ECHO === BUILDING ===\nnmake.exe release -f Makefile\n@ECHO === ARCHIVING ===\n@cd /d ../build/release-64bit-msvc\n@del vc_redist.x64.exe\n@7z a -y -m0=LZMA -mx9 \"%~dp0/vsedit%NAME_BRANCH%.7z\" \"*\"\n@iscc build-inno-setup.iss\n\n:: Clean up the environment\n@SET PATH=%ORIGINAL_PATH%\n\n@popd"
  },
  {
    "path": "pro/common.pri",
    "content": "VER_MAJ = 19\nVERSION = $$VER_MAJ\n\nQMAKE_TARGET_COMPANY = 'Aleksey [Mystery Keeper] Lyashin'\nQMAKE_TARGET_COPYRIGHT = $$QMAKE_TARGET_COMPANY\n"
  },
  {
    "path": "pro/pro.pro",
    "content": "lessThan(QT_MAJOR_VERSION, 6) {\n\terror(You must build with Qt 6 or later)\n}\n\nTEMPLATE = subdirs\n\nSUBDIRS += vsedit\nSUBDIRS += vsedit-previewer\nSUBDIRS += vsedit-job-server\nSUBDIRS += vsedit-job-server-watcher\nSUBDIRS += vsedit-encode\n\nvsedit.file = ./vsedit/vsedit.pro\nvsedit-previewer.file = ./vsedit-previewer/vsedit-previewer.pro\nvsedit-job-server.file = ./vsedit-job-server/vsedit-job-server.pro\nvsedit-job-server-watcher.file = ./vsedit-job-server-watcher/vsedit-job-server-watcher.pro\nvsedit-encode.file = ./vsedit-encode/vsedit-encode.pro\n"
  },
  {
    "path": "pro/vsedit/vsedit.pro",
    "content": "CONFIG += qt\n\nQT += widgets\nQT += network\n\nwin32 {\n\tQT += multimedia\n}\n\n\nHOST_64_BIT = contains(QMAKE_HOST.arch, \"x86_64\")\nTARGET_64_BIT = contains(QMAKE_TARGET.arch, \"x86_64\")\nARCHITECTURE_64_BIT = $$HOST_64_BIT | $$TARGET_64_BIT\n\nPROJECT_DIRECTORY = ../../vsedit\nCOMMON_DIRECTORY = ../..\n\nINCLUDEPATH += $$(VS_INCLUDE_PATH)\n\nCONFIG(debug, debug|release) {\n\n\tcontains(QMAKE_COMPILER, gcc) {\n\t\tif($$ARCHITECTURE_64_BIT) {\n\t\t\tDESTDIR = $${COMMON_DIRECTORY}/build/debug-64bit-gcc\n\t\t\tTARGET = vsedit-debug-64bit-gcc\n\t\t\tOBJECTS_DIR = $${PROJECT_DIRECTORY}/generated/obj-debug-64bit-gcc\n\t\t} else {\n\t\t\tDESTDIR = $${COMMON_DIRECTORY}/build/debug-32bit-gcc\n\t\t\tTARGET = vsedit-debug-32bit-gcc\n\t\t\tOBJECTS_DIR = $${PROJECT_DIRECTORY}/generated/obj-debug-32bit-gcc\n\t\t}\n\n\t\tQMAKE_CXXFLAGS += -O0\n\t\tQMAKE_CXXFLAGS += -g\n\t\tQMAKE_CXXFLAGS += -ggdb3\n\t}\n\n\tcontains(QMAKE_COMPILER, msvc) {\n\t\tif($$ARCHITECTURE_64_BIT) {\n\t\t\tDESTDIR = $${COMMON_DIRECTORY}/build/debug-64bit-msvc\n\t\t\tTARGET = vsedit-debug-64bit-msvc\n\t\t\tOBJECTS_DIR = $${PROJECT_DIRECTORY}/generated/obj-debug-64bit-msvc\n\t\t} else {\n\t\t\tDESTDIR = $${COMMON_DIRECTORY}/build/debug-32bit-msvc\n\t\t\tTARGET = vsedit-debug-32bit-msvc\n\t\t\tOBJECTS_DIR = $${PROJECT_DIRECTORY}/generated/obj-debug-32bit-msvc\n\t\t}\n\t}\n\n} else {\n\n\tcontains(QMAKE_COMPILER, gcc) {\n\t\tif($$ARCHITECTURE_64_BIT) {\n\t\t\tDESTDIR = $${COMMON_DIRECTORY}/build/release-64bit-gcc\n\t\t\tTARGET = vsedit\n\t\t\tOBJECTS_DIR = $${PROJECT_DIRECTORY}/generated/obj-release-64bit-gcc\n\t\t} else {\n\t\t\tDESTDIR = $${COMMON_DIRECTORY}/build/release-32bit-gcc\n\t\t\tTARGET = vsedit-32bit\n\t\t\tOBJECTS_DIR = $${PROJECT_DIRECTORY}/generated/obj-release-32bit-gcc\n\t\t}\n\n\t\tQMAKE_CXXFLAGS += -O2\n\t\tQMAKE_CXXFLAGS += -fexpensive-optimizations\n\t\tQMAKE_CXXFLAGS += -funit-at-a-time\n\t}\n\n\tmacx {\n\t\tQMAKE_CXXFLAGS -= -fexpensive-optimizations\n\t}\n\n\tcontains(QMAKE_COMPILER, msvc) {\n\t\tif($$ARCHITECTURE_64_BIT) {\n\t\t\tDESTDIR = $${COMMON_DIRECTORY}/build/release-64bit-msvc\n\t\t\tTARGET = vsedit\n\t\t\tOBJECTS_DIR = $${PROJECT_DIRECTORY}/generated/obj-release-64bit-msvc\n\t\t} else {\n\t\t\tDESTDIR = $${COMMON_DIRECTORY}/build/release-32bit-msvc\n\t\t\tTARGET = vsedit-32bit\n\t\t\tOBJECTS_DIR = $${PROJECT_DIRECTORY}/generated/obj-release-32bit-msvc\n\t\t}\n\t}\n\n\tDEFINES += NDEBUG\n\n}\n\nS = $${DIR_SEPARATOR}\n\nD = $$DESTDIR\nD = $$replace(D, /, $$S)\n\nSC = $${COMMON_DIRECTORY}/\nSC = $$replace(SC, /, $$S)\n\nE = $$escape_expand(\\n\\t)\n\nQMAKE_POST_LINK += $${QMAKE_COPY} $${SC}$${S}resources$${S}vsedit.ico $${D}$${S}vsedit.ico $${E}\nQMAKE_POST_LINK += $${QMAKE_COPY} $${SC}$${S}resources$${S}vsedit.svg $${D}$${S}vsedit.svg $${E}\nQMAKE_POST_LINK += $${QMAKE_COPY} $${SC}$${S}README $${D}$${S}README $${E}\nQMAKE_POST_LINK += $${QMAKE_COPY} $${SC}$${S}LICENSE $${D}$${S}LICENSE $${E}\nQMAKE_POST_LINK += $${QMAKE_COPY} $${SC}$${S}CHANGELOG $${D}$${S}CHANGELOG $${E}\n\nmacx {\n\tINCLUDEPATH += /usr/local/include\n\tICON = $${COMMON_DIRECTORY}/resources/vsedit.icns\n}\n\nwin32 {\n\tQMAKE_LFLAGS += '/entry:mainCRTStartup'\n\n\tINCLUDEPATH += 'C:/Program Files/VapourSynth/sdk/include/vapoursynth'\n\n\tDEPLOY_COMMAND = windeployqt\n\tDEPLOY_TARGET = $$shell_quote($$shell_path($${D}/$${TARGET}.exe))\n\tQMAKE_POST_LINK += $${DEPLOY_COMMAND} --no-translations --no-svg --no-opengl-sw --no-system-d3d-compiler $${DEPLOY_TARGET} $${E}\n\n\tif($$ARCHITECTURE_64_BIT) {\n\t\tmessage(\"x86_64 build\")\n\t} else {\n\t\tmessage(\"x86 build\")\n\t\tcontains(QMAKE_COMPILER, gcc) {\n\t\t\tQMAKE_LFLAGS += -Wl,--large-address-aware\n\t\t}\n\t\tcontains(QMAKE_COMPILER, msvc) {\n\t\t\tQMAKE_LFLAGS += /LARGEADDRESSAWARE\n\t\t}\n\t}\n}\n\ncontains(QMAKE_COMPILER, clang) {\n\tQMAKE_CXXFLAGS += -stdlib=libc++\n}\n\ncontains(QMAKE_COMPILER, gcc) {\n\tQMAKE_CXXFLAGS += -std=c++17\n\tQMAKE_CXXFLAGS += -Wall\n\tQMAKE_CXXFLAGS += -Wextra\n\tQMAKE_CXXFLAGS += -Wredundant-decls\n\tQMAKE_CXXFLAGS += -Wshadow\n\t#QMAKE_CXXFLAGS += -Weffc++\n\tQMAKE_CXXFLAGS += -pedantic\n\n\tLIBS += -L$$[QT_INSTALL_LIBS]\n} else {\n\tCONFIG += c++17\n}\n\ninclude($${COMMON_DIRECTORY}/pro/common.pri)\n\nTEMPLATE = app\n\nRC_ICONS = $${COMMON_DIRECTORY}/resources/vsedit.ico\nQMAKE_TARGET_PRODUCT = 'VapourSynth Editor'\nQMAKE_TARGET_DESCRIPTION = 'VapourSynth Editor'\n\n#SUBDIRS\n\nMOC_DIR = $${PROJECT_DIRECTORY}/generated/moc\nUI_DIR = $${PROJECT_DIRECTORY}/generated/ui\nRCC_DIR = $${PROJECT_DIRECTORY}/generated/rcc\n\n#DEFINES\n\n#TRANSLATIONS\n\nRESOURCES = $${COMMON_DIRECTORY}/resources/vsedit.qrc\nRESOURCES += $${COMMON_DIRECTORY}/resources/dark/style.qrc\n\nFORMS += $${COMMON_DIRECTORY}/common-src/log/styled_log_view_settings_dialog.ui\n\nFORMS += $${PROJECT_DIRECTORY}/src/settings/settings_dialog.ui\nFORMS += $${PROJECT_DIRECTORY}/src/script_status_bar_widget/script_status_bar_widget.ui\nFORMS += $${PROJECT_DIRECTORY}/src/preview/preview_advanced_settings_dialog.ui\nFORMS += $${PROJECT_DIRECTORY}/src/preview/preview_dialog.ui\nFORMS += $${PROJECT_DIRECTORY}/src/frame_consumers/benchmark_dialog.ui\nFORMS += $${PROJECT_DIRECTORY}/src/frame_consumers/encode_dialog.ui\nFORMS += $${PROJECT_DIRECTORY}/src/script_templates/templates_dialog.ui\nFORMS += $${PROJECT_DIRECTORY}/src/main_window.ui\n\nHEADERS += $${COMMON_DIRECTORY}/common-src/helpers.h\nHEADERS += $${COMMON_DIRECTORY}/common-src/helpers_vs.h\nHEADERS += $${COMMON_DIRECTORY}/common-src/version_info.h\nHEADERS += $${COMMON_DIRECTORY}/common-src/win32_console.h\nHEADERS += $${COMMON_DIRECTORY}/common-src/chrono.h\nHEADERS += $${COMMON_DIRECTORY}/common-src/settings/settings_definitions_core.h\nHEADERS += $${COMMON_DIRECTORY}/common-src/settings/settings_definitions.h\nHEADERS += $${COMMON_DIRECTORY}/common-src/settings/settings_manager_core.h\nHEADERS += $${COMMON_DIRECTORY}/common-src/settings/settings_manager.h\nHEADERS += $${COMMON_DIRECTORY}/common-src/log/styled_log_view_core.h\nHEADERS += $${COMMON_DIRECTORY}/common-src/log/styled_log_view_structures.h\nHEADERS += $${COMMON_DIRECTORY}/common-src/log/log_styles_model.h\nHEADERS += $${COMMON_DIRECTORY}/common-src/log/styled_log_view_settings_dialog.h\nHEADERS += $${COMMON_DIRECTORY}/common-src/log/styled_log_view.h\nHEADERS += $${COMMON_DIRECTORY}/common-src/log/vs_editor_log_definitions.h\nHEADERS += $${COMMON_DIRECTORY}/common-src/log/vs_editor_log.h\nHEADERS += $${COMMON_DIRECTORY}/common-src/vapoursynth/vs_script_library.h\nHEADERS += $${COMMON_DIRECTORY}/common-src/vapoursynth/vs_script_processor_structures.h\nHEADERS += $${COMMON_DIRECTORY}/common-src/vapoursynth/vapoursynth_script_processor.h\nHEADERS += $${COMMON_DIRECTORY}/common-src/frame_header_writers/frame_header_writer.h\nHEADERS += $${COMMON_DIRECTORY}/common-src/frame_header_writers/frame_header_writer_null.h\nHEADERS += $${COMMON_DIRECTORY}/common-src/frame_header_writers/frame_header_writer_y4m.h\nHEADERS += $${COMMON_DIRECTORY}/common-src/jobs/job.h\nHEADERS += $${COMMON_DIRECTORY}/common-src/jobs/job_variables.h\nHEADERS += $${COMMON_DIRECTORY}/common-src/timeline_slider/timeline_slider.h\nHEADERS += $${COMMON_DIRECTORY}/common-src/libp2p/p2p.h\nHEADERS += $${COMMON_DIRECTORY}/common-src/libp2p/p2p_api.h\nHEADERS += $${COMMON_DIRECTORY}/common-src/libp2p/simd/cpuinfo_x86.h\nHEADERS += $${COMMON_DIRECTORY}/common-src/libp2p/simd/p2p_simd.h\nHEADERS += $${COMMON_DIRECTORY}/common-src/vapoursynth/vs_pack_rgb.h\nHEADERS += $${COMMON_DIRECTORY}/common-src/vapoursynth/vs_set_matrix.h\n\nHEADERS += $${PROJECT_DIRECTORY}/src/settings/actions_hotkey_edit_model.h\nHEADERS += $${PROJECT_DIRECTORY}/src/settings/clearable_key_sequence_editor.h\nHEADERS += $${PROJECT_DIRECTORY}/src/settings/item_delegate_for_hotkey.h\nHEADERS += $${PROJECT_DIRECTORY}/src/settings/theme_elements_model.h\nHEADERS += $${PROJECT_DIRECTORY}/src/settings/settings_dialog.h\nHEADERS += $${PROJECT_DIRECTORY}/src/script_status_bar_widget/script_status_bar_widget.h\nHEADERS += $${PROJECT_DIRECTORY}/src/preview/scroll_navigator.h\nHEADERS += $${PROJECT_DIRECTORY}/src/preview/preview_area.h\nHEADERS += $${PROJECT_DIRECTORY}/src/preview/preview_advanced_settings_dialog.h\nHEADERS += $${PROJECT_DIRECTORY}/src/preview/preview_dialog.h\nHEADERS += $${PROJECT_DIRECTORY}/src/preview/zoom_ratio_spinbox.h\nHEADERS += $${PROJECT_DIRECTORY}/src/script_editor/number_matcher.h\nHEADERS += $${PROJECT_DIRECTORY}/src/script_editor/syntax_highlighter.h\nHEADERS += $${PROJECT_DIRECTORY}/src/script_editor/script_completer_model.h\nHEADERS += $${PROJECT_DIRECTORY}/src/script_editor/script_completer.h\nHEADERS += $${PROJECT_DIRECTORY}/src/script_editor/script_editor.h\nHEADERS += $${PROJECT_DIRECTORY}/src/vapoursynth/vs_plugin_data.h\nHEADERS += $${PROJECT_DIRECTORY}/src/vapoursynth/vapoursynth_plugins_manager.h\nHEADERS += $${PROJECT_DIRECTORY}/src/vapoursynth/vs_script_processor_dialog.h\nHEADERS += $${PROJECT_DIRECTORY}/src/job_server_watcher_socket.h\nHEADERS += $${PROJECT_DIRECTORY}/src/frame_consumers/benchmark_dialog.h\nHEADERS += $${PROJECT_DIRECTORY}/src/frame_consumers/encode_dialog.h\nHEADERS += $${PROJECT_DIRECTORY}/src/script_templates/drop_file_category_model.h\nHEADERS += $${PROJECT_DIRECTORY}/src/script_templates/templates_dialog.h\nHEADERS += $${PROJECT_DIRECTORY}/src/main_window.h\n\nSOURCES += $${COMMON_DIRECTORY}/common-src/helpers.cpp\nSOURCES += $${COMMON_DIRECTORY}/common-src/version_info.cpp\nSOURCES += $${COMMON_DIRECTORY}/common-src/win32_console.cpp\nSOURCES += $${COMMON_DIRECTORY}/common-src/settings/settings_definitions_core.cpp\nSOURCES += $${COMMON_DIRECTORY}/common-src/settings/settings_definitions.cpp\nSOURCES += $${COMMON_DIRECTORY}/common-src/settings/settings_manager_core.cpp\nSOURCES += $${COMMON_DIRECTORY}/common-src/settings/settings_manager.cpp\nSOURCES += $${COMMON_DIRECTORY}/common-src/log/styled_log_view_core.cpp\nSOURCES += $${COMMON_DIRECTORY}/common-src/log/styled_log_view_structures.cpp\nSOURCES += $${COMMON_DIRECTORY}/common-src/log/log_styles_model.cpp\nSOURCES += $${COMMON_DIRECTORY}/common-src/log/styled_log_view_settings_dialog.cpp\nSOURCES += $${COMMON_DIRECTORY}/common-src/log/styled_log_view.cpp\nSOURCES += $${COMMON_DIRECTORY}/common-src/log/vs_editor_log_definitions.cpp\nSOURCES += $${COMMON_DIRECTORY}/common-src/log/vs_editor_log.cpp\nSOURCES += $${COMMON_DIRECTORY}/common-src/vapoursynth/vs_script_library.cpp\nSOURCES += $${COMMON_DIRECTORY}/common-src/vapoursynth/vs_script_processor_structures.cpp\nSOURCES += $${COMMON_DIRECTORY}/common-src/vapoursynth/vapoursynth_script_processor.cpp\nSOURCES += $${COMMON_DIRECTORY}/common-src/frame_header_writers/frame_header_writer.cpp\nSOURCES += $${COMMON_DIRECTORY}/common-src/frame_header_writers/frame_header_writer_null.cpp\nSOURCES += $${COMMON_DIRECTORY}/common-src/frame_header_writers/frame_header_writer_y4m.cpp\nSOURCES += $${COMMON_DIRECTORY}/common-src/jobs/job.cpp\nSOURCES += $${COMMON_DIRECTORY}/common-src/jobs/job_variables.cpp\nSOURCES += $${COMMON_DIRECTORY}/common-src/timeline_slider/timeline_slider.cpp\nSOURCES += $${COMMON_DIRECTORY}/common-src/vapoursynth/vs_pack_rgb.cpp\nSOURCES += $${COMMON_DIRECTORY}/common-src/vapoursynth/vs_set_matrix.cpp\n\nSOURCES += $${PROJECT_DIRECTORY}/src/settings/actions_hotkey_edit_model.cpp\nSOURCES += $${PROJECT_DIRECTORY}/src/settings/clearable_key_sequence_editor.cpp\nSOURCES += $${PROJECT_DIRECTORY}/src/settings/item_delegate_for_hotkey.cpp\nSOURCES += $${PROJECT_DIRECTORY}/src/settings/theme_elements_model.cpp\nSOURCES += $${PROJECT_DIRECTORY}/src/settings/settings_dialog.cpp\nSOURCES += $${PROJECT_DIRECTORY}/src/script_status_bar_widget/script_status_bar_widget.cpp\nSOURCES += $${PROJECT_DIRECTORY}/src/preview/scroll_navigator.cpp\nSOURCES += $${PROJECT_DIRECTORY}/src/preview/preview_area.cpp\nSOURCES += $${PROJECT_DIRECTORY}/src/preview/preview_advanced_settings_dialog.cpp\nSOURCES += $${PROJECT_DIRECTORY}/src/preview/preview_dialog.cpp\nSOURCES += $${PROJECT_DIRECTORY}/src/preview/zoom_ratio_spinbox.cpp\nSOURCES += $${PROJECT_DIRECTORY}/src/script_editor/number_matcher.cpp\nSOURCES += $${PROJECT_DIRECTORY}/src/script_editor/syntax_highlighter.cpp\nSOURCES += $${PROJECT_DIRECTORY}/src/script_editor/script_completer_model.cpp\nSOURCES += $${PROJECT_DIRECTORY}/src/script_editor/script_completer.cpp\nSOURCES += $${PROJECT_DIRECTORY}/src/script_editor/script_editor.cpp\nSOURCES += $${PROJECT_DIRECTORY}/src/vapoursynth/vs_plugin_data.cpp\nSOURCES += $${PROJECT_DIRECTORY}/src/vapoursynth/vapoursynth_plugins_manager.cpp\nSOURCES += $${PROJECT_DIRECTORY}/src/vapoursynth/vs_script_processor_dialog.cpp\nSOURCES += $${PROJECT_DIRECTORY}/src/job_server_watcher_socket.cpp\nSOURCES += $${PROJECT_DIRECTORY}/src/frame_consumers/benchmark_dialog.cpp\nSOURCES += $${PROJECT_DIRECTORY}/src/frame_consumers/encode_dialog.cpp\nSOURCES += $${PROJECT_DIRECTORY}/src/script_templates/drop_file_category_model.cpp\nSOURCES += $${PROJECT_DIRECTORY}/src/script_templates/templates_dialog.cpp\nSOURCES += $${PROJECT_DIRECTORY}/src/main_window.cpp\nSOURCES += $${PROJECT_DIRECTORY}/src/main.cpp\n\n# libp2p\nSOURCES_P2P += $${COMMON_DIRECTORY}/common-src/libp2p/p2p_api.cpp\nSOURCES_P2P += $${COMMON_DIRECTORY}/common-src/libp2p/v210.cpp\nSOURCES_P2P += $${COMMON_DIRECTORY}/common-src/libp2p/simd/cpuinfo_x86.cpp\nSOURCES_P2P += $${COMMON_DIRECTORY}/common-src/libp2p/simd/p2p_simd.cpp\nif($$ARCHITECTURE_64_BIT) {\n\tSOURCES_P2P_SSE41 += $${COMMON_DIRECTORY}/common-src/libp2p/simd/p2p_sse41.cpp\n}\n\np2p.name = p2p\np2p.input = SOURCES_P2P\np2p.dependency_type = TYPE_C\np2p.variable_out = OBJECTS\np2p.output = ${QMAKE_VAR_OBJECTS_DIR}${QMAKE_FILE_IN_BASE}$${first(QMAKE_EXT_OBJ)}\np2p.commands = $${QMAKE_CXX} $(CXXFLAGS) -DP2P_SIMD $(INCPATH) -c ${QMAKE_FILE_IN}\ncontains(QMAKE_COMPILER, msvc) {\n\tp2p.commands += -Fo${QMAKE_FILE_OUT}\n} else {\n\tp2p.commands += -o ${QMAKE_FILE_OUT}\n\tp2p.commands += -std=c++14\n\tp2p.commands += -Wno-missing-field-initializers\n}\nmacx {\n\tp2p.commands += -Wno-gnu\n}\nQMAKE_EXTRA_COMPILERS += p2p\n\nif($$ARCHITECTURE_64_BIT) {\n\tp2p_sse41.name = p2p_sse41\n\tp2p_sse41.input = SOURCES_P2P_SSE41\n\tp2p_sse41.dependency_type = TYPE_C\n\tp2p_sse41.variable_out = OBJECTS\n\tp2p_sse41.output = ${QMAKE_VAR_OBJECTS_DIR}${QMAKE_FILE_IN_BASE}$${first(QMAKE_EXT_OBJ)}\n\tp2p_sse41.commands = $${QMAKE_CXX} $(CXXFLAGS) -DP2P_SIMD $(INCPATH) -c ${QMAKE_FILE_IN}\n\tcontains(QMAKE_COMPILER, msvc) {\n\t\tp2p_sse41.commands += -Fo${QMAKE_FILE_OUT}\n\t} else {\n\t\tp2p_sse41.commands += -msse4.1\n\t\tp2p_sse41.commands += -o ${QMAKE_FILE_OUT}\n\t\tp2p_sse41.commands += -std=c++14\n\t\tp2p_sse41.commands += -Wno-missing-field-initializers\n\t}\n}\nmacx {\n\tp2p_sse41.commands += -Wno-gnu\n}\nif($$ARCHITECTURE_64_BIT) {\n\tQMAKE_EXTRA_COMPILERS += p2p_sse41\n}\n\ninclude($${COMMON_DIRECTORY}/pro/local_quirks.pri)\n"
  },
  {
    "path": "pro/vsedit-encode/vsedit-encode.pro",
    "content": "CONFIG += qt\n\nQT += widgets\n\nwin32 {\n\tCONFIG += console\n}\n\nHOST_64_BIT = contains(QMAKE_HOST.arch, \"x86_64\")\nTARGET_64_BIT = contains(QMAKE_TARGET.arch, \"x86_64\")\nARCHITECTURE_64_BIT = $$HOST_64_BIT | $$TARGET_64_BIT\n\nPROJECT_DIRECTORY = ../../vsedit\nCOMMON_DIRECTORY = ../..\n\nINCLUDEPATH += $$(VS_INCLUDE_PATH)\n\nCONFIG(debug, debug|release) {\n\n\tcontains(QMAKE_COMPILER, gcc) {\n\t\tif($$ARCHITECTURE_64_BIT) {\n\t\t\tDESTDIR = $${COMMON_DIRECTORY}/build/debug-64bit-gcc\n\t\t\tTARGET = vsedit-encode-debug-64bit-gcc\n\t\t\tOBJECTS_DIR = $${PROJECT_DIRECTORY}/generated/obj-debug-64bit-gcc\n\t\t} else {\n\t\t\tDESTDIR = $${COMMON_DIRECTORY}/build/debug-32bit-gcc\n\t\t\tTARGET = vsedit-encode-debug-32bit-gcc\n\t\t\tOBJECTS_DIR = $${PROJECT_DIRECTORY}/generated/obj-debug-32bit-gcc\n\t\t}\n\n\t\tQMAKE_CXXFLAGS += -O0\n\t\tQMAKE_CXXFLAGS += -g\n\t\tQMAKE_CXXFLAGS += -ggdb3\n\t}\n\n\tcontains(QMAKE_COMPILER, msvc) {\n\t\tif($$ARCHITECTURE_64_BIT) {\n\t\t\tDESTDIR = $${COMMON_DIRECTORY}/build/debug-64bit-msvc\n\t\t\tTARGET = vsedit-encode-debug-64bit-msvc\n\t\t\tOBJECTS_DIR = $${PROJECT_DIRECTORY}/generated/obj-debug-64bit-msvc\n\t\t} else {\n\t\t\tDESTDIR = $${COMMON_DIRECTORY}/build/debug-32bit-msvc\n\t\t\tTARGET = vsedit-encode-debug-32bit-msvc\n\t\t\tOBJECTS_DIR = $${PROJECT_DIRECTORY}/generated/obj-debug-32bit-msvc\n\t\t}\n\t}\n\n} else {\n\n\tcontains(QMAKE_COMPILER, gcc) {\n\t\tif($$ARCHITECTURE_64_BIT) {\n\t\t\tDESTDIR = $${COMMON_DIRECTORY}/build/release-64bit-gcc\n\t\t\tTARGET = vsedit-encode\n\t\t\tOBJECTS_DIR = $${PROJECT_DIRECTORY}/generated/obj-release-64bit-gcc\n\t\t} else {\n\t\t\tDESTDIR = $${COMMON_DIRECTORY}/build/release-32bit-gcc\n\t\t\tTARGET = vsedit-encode-32bit\n\t\t\tOBJECTS_DIR = $${PROJECT_DIRECTORY}/generated/obj-release-32bit-gcc\n\t\t}\n\n\t\tQMAKE_CXXFLAGS += -O2\n\t\tQMAKE_CXXFLAGS += -fexpensive-optimizations\n\t\tQMAKE_CXXFLAGS += -funit-at-a-time\n\t}\n\n\tmacx {\n\t\tQMAKE_CXXFLAGS -= -fexpensive-optimizations\n\t}\n\n\tcontains(QMAKE_COMPILER, msvc) {\n\t\tif($$ARCHITECTURE_64_BIT) {\n\t\t\tDESTDIR = $${COMMON_DIRECTORY}/build/release-64bit-msvc\n\t\t\tTARGET = vsedit-encode\n\t\t\tOBJECTS_DIR = $${PROJECT_DIRECTORY}/generated/obj-release-64bit-msvc\n\t\t} else {\n\t\t\tDESTDIR = $${COMMON_DIRECTORY}/build/release-32bit-msvc\n\t\t\tTARGET = vsedit-encode-32bit\n\t\t\tOBJECTS_DIR = $${PROJECT_DIRECTORY}/generated/obj-release-32bit-msvc\n\t\t}\n\t}\n\n\tDEFINES += NDEBUG\n\n}\n\nS = $${DIR_SEPARATOR}\n\nD = $$DESTDIR\nD = $$replace(D, /, $$S)\n\nSC = $${COMMON_DIRECTORY}/\nSC = $$replace(SC, /, $$S)\n\nE = $$escape_expand(\\n\\t)\n\nQMAKE_POST_LINK += $${QMAKE_COPY} $${SC}$${S}resources$${S}vsedit.ico $${D}$${S}vsedit.ico $${E}\nQMAKE_POST_LINK += $${QMAKE_COPY} $${SC}$${S}resources$${S}vsedit.svg $${D}$${S}vsedit.svg $${E}\nQMAKE_POST_LINK += $${QMAKE_COPY} $${SC}$${S}README $${D}$${S}README $${E}\nQMAKE_POST_LINK += $${QMAKE_COPY} $${SC}$${S}LICENSE $${D}$${S}LICENSE $${E}\nQMAKE_POST_LINK += $${QMAKE_COPY} $${SC}$${S}CHANGELOG $${D}$${S}CHANGELOG $${E}\n\nmacx {\n\tINCLUDEPATH += /usr/local/include\n\tICON = $${COMMON_DIRECTORY}/resources/vsedit.icns\n}\n\nwin32 {\n\tINCLUDEPATH += 'C:/Program Files/VapourSynth/sdk/include/vapoursynth'\n\n\tDEPLOY_COMMAND = windeployqt\n\tDEPLOY_TARGET = $$shell_quote($$shell_path($${D}/$${TARGET}.exe))\n\tQMAKE_POST_LINK += $${DEPLOY_COMMAND} --no-translations --no-svg --no-opengl-sw --no-system-d3d-compiler $${DEPLOY_TARGET} $${E}\n\n\tif($$ARCHITECTURE_64_BIT) {\n\t\tmessage(\"x86_64 build\")\n\t} else {\n\t\tmessage(\"x86 build\")\n\t\tcontains(QMAKE_COMPILER, gcc) {\n\t\t\tQMAKE_LFLAGS += -Wl,--large-address-aware\n\t\t}\n\t\tcontains(QMAKE_COMPILER, msvc) {\n\t\t\tQMAKE_LFLAGS += /LARGEADDRESSAWARE\n\t\t}\n\t}\n}\n\ncontains(QMAKE_COMPILER, clang) {\n\tQMAKE_CXXFLAGS += -stdlib=libc++\n}\n\ncontains(QMAKE_COMPILER, gcc) {\n\tQMAKE_CXXFLAGS += -std=c++17\n\tQMAKE_CXXFLAGS += -Wall\n\tQMAKE_CXXFLAGS += -Wextra\n\tQMAKE_CXXFLAGS += -Wredundant-decls\n\tQMAKE_CXXFLAGS += -Wshadow\n\t#QMAKE_CXXFLAGS += -Weffc++\n\tQMAKE_CXXFLAGS += -pedantic\n\n\tLIBS += -L$$[QT_INSTALL_LIBS]\n} else {\n\tCONFIG += c++17\n}\n\ninclude($${COMMON_DIRECTORY}/pro/common.pri)\n\nTEMPLATE = app\n\nRC_ICONS = $${COMMON_DIRECTORY}/resources/vsedit.ico\nQMAKE_TARGET_PRODUCT = 'VapourSynth Editor Encode Panel'\nQMAKE_TARGET_DESCRIPTION = 'VapourSynth Editor Encode Panel'\n\n#SUBDIRS\n\nMOC_DIR = $${PROJECT_DIRECTORY}/generated/moc\nUI_DIR = $${PROJECT_DIRECTORY}/generated/ui\nRCC_DIR = $${PROJECT_DIRECTORY}/generated/rcc\n\n#DEFINES\n\n#TRANSLATIONS\n\nRESOURCES = $${COMMON_DIRECTORY}/resources/vsedit.qrc\nRESOURCES += $${COMMON_DIRECTORY}/resources/dark/style.qrc\n\nFORMS += $${COMMON_DIRECTORY}/common-src/log/styled_log_view_settings_dialog.ui\nFORMS += $${PROJECT_DIRECTORY}/src/script_status_bar_widget/script_status_bar_widget.ui\nFORMS += $${PROJECT_DIRECTORY}/src/frame_consumers/encode_dialog.ui\n\nHEADERS += $${COMMON_DIRECTORY}/common-src/helpers.h\nHEADERS += $${COMMON_DIRECTORY}/common-src/helpers_vs.h\nHEADERS += $${COMMON_DIRECTORY}/common-src/version_info.h\nHEADERS += $${COMMON_DIRECTORY}/common-src/chrono.h\nHEADERS += $${COMMON_DIRECTORY}/common-src/settings/settings_definitions_core.h\nHEADERS += $${COMMON_DIRECTORY}/common-src/settings/settings_definitions.h\nHEADERS += $${COMMON_DIRECTORY}/common-src/settings/settings_manager_core.h\nHEADERS += $${COMMON_DIRECTORY}/common-src/settings/settings_manager.h\nHEADERS += $${COMMON_DIRECTORY}/common-src/log/styled_log_view.h\nHEADERS += $${COMMON_DIRECTORY}/common-src/log/styled_log_view_core.h\nHEADERS += $${COMMON_DIRECTORY}/common-src/log/styled_log_view_structures.h\nHEADERS += $${COMMON_DIRECTORY}/common-src/log/styled_log_view_settings_dialog.h\nHEADERS += $${COMMON_DIRECTORY}/common-src/log/log_styles_model.h\nHEADERS += $${COMMON_DIRECTORY}/common-src/log/vs_editor_log_definitions.h\nHEADERS += $${COMMON_DIRECTORY}/common-src/log/vs_editor_log.h\nHEADERS += $${COMMON_DIRECTORY}/common-src/vapoursynth/vs_script_library.h\nHEADERS += $${COMMON_DIRECTORY}/common-src/vapoursynth/vs_script_processor_structures.h\nHEADERS += $${COMMON_DIRECTORY}/common-src/vapoursynth/vapoursynth_script_processor.h\nHEADERS += $${COMMON_DIRECTORY}/common-src/frame_header_writers/frame_header_writer.h\nHEADERS += $${COMMON_DIRECTORY}/common-src/frame_header_writers/frame_header_writer_null.h\nHEADERS += $${COMMON_DIRECTORY}/common-src/frame_header_writers/frame_header_writer_y4m.h\nHEADERS += $${COMMON_DIRECTORY}/common-src/jobs/job.h\nHEADERS += $${COMMON_DIRECTORY}/common-src/jobs/job_variables.h\nHEADERS += $${COMMON_DIRECTORY}/common-src/libp2p/p2p.h\nHEADERS += $${COMMON_DIRECTORY}/common-src/libp2p/p2p_api.h\nHEADERS += $${COMMON_DIRECTORY}/common-src/libp2p/simd/cpuinfo_x86.h\nHEADERS += $${COMMON_DIRECTORY}/common-src/libp2p/simd/p2p_simd.h\nHEADERS += $${COMMON_DIRECTORY}/common-src/vapoursynth/vs_pack_rgb.h\nHEADERS += $${COMMON_DIRECTORY}/common-src/vapoursynth/vs_set_matrix.h\n\nHEADERS += $${PROJECT_DIRECTORY}/src/settings/actions_hotkey_edit_model.h\nHEADERS += $${PROJECT_DIRECTORY}/src/settings/clearable_key_sequence_editor.h\nHEADERS += $${PROJECT_DIRECTORY}/src/settings/item_delegate_for_hotkey.h\nHEADERS += $${PROJECT_DIRECTORY}/src/settings/theme_elements_model.h\nHEADERS += $${PROJECT_DIRECTORY}/src/script_status_bar_widget/script_status_bar_widget.h\nHEADERS += $${PROJECT_DIRECTORY}/src/vapoursynth/vs_script_processor_dialog.h\nHEADERS += $${PROJECT_DIRECTORY}/src/frame_consumers/encode_dialog.h\n\nSOURCES += $${COMMON_DIRECTORY}/common-src/helpers.cpp\nSOURCES += $${COMMON_DIRECTORY}/common-src/version_info.cpp\nSOURCES += $${COMMON_DIRECTORY}/common-src/settings/settings_definitions_core.cpp\nSOURCES += $${COMMON_DIRECTORY}/common-src/settings/settings_definitions.cpp\nSOURCES += $${COMMON_DIRECTORY}/common-src/settings/settings_manager_core.cpp\nSOURCES += $${COMMON_DIRECTORY}/common-src/settings/settings_manager.cpp\nSOURCES += $${COMMON_DIRECTORY}/common-src/log/styled_log_view.cpp\nSOURCES += $${COMMON_DIRECTORY}/common-src/log/styled_log_view_core.cpp\nSOURCES += $${COMMON_DIRECTORY}/common-src/log/styled_log_view_structures.cpp\nSOURCES += $${COMMON_DIRECTORY}/common-src/log/styled_log_view_settings_dialog.cpp\nSOURCES += $${COMMON_DIRECTORY}/common-src/log/log_styles_model.cpp\nSOURCES += $${COMMON_DIRECTORY}/common-src/log/vs_editor_log_definitions.cpp\nSOURCES += $${COMMON_DIRECTORY}/common-src/log/vs_editor_log.cpp\nSOURCES += $${COMMON_DIRECTORY}/common-src/vapoursynth/vs_script_library.cpp\nSOURCES += $${COMMON_DIRECTORY}/common-src/vapoursynth/vs_script_processor_structures.cpp\nSOURCES += $${COMMON_DIRECTORY}/common-src/vapoursynth/vapoursynth_script_processor.cpp\nSOURCES += $${COMMON_DIRECTORY}/common-src/frame_header_writers/frame_header_writer.cpp\nSOURCES += $${COMMON_DIRECTORY}/common-src/frame_header_writers/frame_header_writer_null.cpp\nSOURCES += $${COMMON_DIRECTORY}/common-src/frame_header_writers/frame_header_writer_y4m.cpp\nSOURCES += $${COMMON_DIRECTORY}/common-src/jobs/job.cpp\nSOURCES += $${COMMON_DIRECTORY}/common-src/jobs/job_variables.cpp\nSOURCES += $${COMMON_DIRECTORY}/common-src/vapoursynth/vs_pack_rgb.cpp\nSOURCES += $${COMMON_DIRECTORY}/common-src/vapoursynth/vs_set_matrix.cpp\n\nSOURCES += $${PROJECT_DIRECTORY}/src/settings/actions_hotkey_edit_model.cpp\nSOURCES += $${PROJECT_DIRECTORY}/src/settings/clearable_key_sequence_editor.cpp\nSOURCES += $${PROJECT_DIRECTORY}/src/settings/item_delegate_for_hotkey.cpp\nSOURCES += $${PROJECT_DIRECTORY}/src/settings/theme_elements_model.cpp\nSOURCES += $${PROJECT_DIRECTORY}/src/script_status_bar_widget/script_status_bar_widget.cpp\nSOURCES += $${PROJECT_DIRECTORY}/src/frame_consumers/encode_dialog.cpp\nSOURCES += $${PROJECT_DIRECTORY}/src/vapoursynth/vs_script_processor_dialog.cpp\nSOURCES += $${PROJECT_DIRECTORY}/src/vsedit_encode_main.cpp\n\n# libp2p\nSOURCES_P2P += $${COMMON_DIRECTORY}/common-src/libp2p/p2p_api.cpp\nSOURCES_P2P += $${COMMON_DIRECTORY}/common-src/libp2p/v210.cpp\nSOURCES_P2P += $${COMMON_DIRECTORY}/common-src/libp2p/simd/cpuinfo_x86.cpp\nSOURCES_P2P += $${COMMON_DIRECTORY}/common-src/libp2p/simd/p2p_simd.cpp\nif($$ARCHITECTURE_64_BIT) {\n\tSOURCES_P2P_SSE41 += $${COMMON_DIRECTORY}/common-src/libp2p/simd/p2p_sse41.cpp\n}\n\np2p.name = p2p\np2p.input = SOURCES_P2P\np2p.dependency_type = TYPE_C\np2p.variable_out = OBJECTS\np2p.output = ${QMAKE_VAR_OBJECTS_DIR}${QMAKE_FILE_IN_BASE}$${first(QMAKE_EXT_OBJ)}\np2p.commands = $${QMAKE_CXX} $(CXXFLAGS) -DP2P_SIMD $(INCPATH) -c ${QMAKE_FILE_IN}\ncontains(QMAKE_COMPILER, msvc) {\n\tp2p.commands += -Fo${QMAKE_FILE_OUT}\n} else {\n\tp2p.commands += -o ${QMAKE_FILE_OUT}\n\tp2p.commands += -std=c++14\n\tp2p.commands += -Wno-missing-field-initializers\n}\nmacx {\n\tp2p.commands += -Wno-gnu\n}\nQMAKE_EXTRA_COMPILERS += p2p\n\nif($$ARCHITECTURE_64_BIT) {\n\tp2p_sse41.name = p2p_sse41\n\tp2p_sse41.input = SOURCES_P2P_SSE41\n\tp2p_sse41.dependency_type = TYPE_C\n\tp2p_sse41.variable_out = OBJECTS\n\tp2p_sse41.output = ${QMAKE_VAR_OBJECTS_DIR}${QMAKE_FILE_IN_BASE}$${first(QMAKE_EXT_OBJ)}\n\tp2p_sse41.commands = $${QMAKE_CXX} $(CXXFLAGS) -DP2P_SIMD $(INCPATH) -c ${QMAKE_FILE_IN}\n\tcontains(QMAKE_COMPILER, msvc) {\n\t\tp2p_sse41.commands += -Fo${QMAKE_FILE_OUT}\n\t} else {\n\t\tp2p_sse41.commands += -msse4.1\n\t\tp2p_sse41.commands += -o ${QMAKE_FILE_OUT}\n\t\tp2p_sse41.commands += -std=c++14\n\t\tp2p_sse41.commands += -Wno-missing-field-initializers\n\t}\n}\nmacx {\n\tp2p_sse41.commands += -Wno-gnu\n}\nif($$ARCHITECTURE_64_BIT) {\n\tQMAKE_EXTRA_COMPILERS += p2p_sse41\n}\n\ninclude($${COMMON_DIRECTORY}/pro/local_quirks.pri)\n"
  },
  {
    "path": "pro/vsedit-job-server/vsedit-job-server.pro",
    "content": "CONFIG += qt\n\nQT += websockets\nQT += widgets\n\nwin32 {\n\tCONFIG += console\n}\n\nHOST_64_BIT = contains(QMAKE_HOST.arch, \"x86_64\")\nTARGET_64_BIT = contains(QMAKE_TARGET.arch, \"x86_64\")\nARCHITECTURE_64_BIT = $$HOST_64_BIT | $$TARGET_64_BIT\n\nPROJECT_DIRECTORY = ../../vsedit-job-server\nCOMMON_DIRECTORY = ../..\n\nINCLUDEPATH += $$(VS_INCLUDE_PATH)\n\nTARGET = vsedit-job-server\n\nCONFIG(debug, debug|release) {\n\n\tcontains(QMAKE_COMPILER, gcc) {\n\t\tif($$ARCHITECTURE_64_BIT) {\n\t\t\tDESTDIR = $${COMMON_DIRECTORY}/build/debug-64bit-gcc\n\t\t\tOBJECTS_DIR = $${PROJECT_DIRECTORY}/generated/obj-debug-64bit-gcc\n\t\t} else {\n\t\t\tDESTDIR = $${COMMON_DIRECTORY}/build/debug-32bit-gcc\n\t\t\tOBJECTS_DIR = $${PROJECT_DIRECTORY}/generated/obj-debug-32bit-gcc\n\t\t}\n\n\t\tQMAKE_CXXFLAGS += -O0\n\t\tQMAKE_CXXFLAGS += -g\n\t\tQMAKE_CXXFLAGS += -ggdb3\n\t}\n\n\tcontains(QMAKE_COMPILER, msvc) {\n\t\tif($$ARCHITECTURE_64_BIT) {\n\t\t\tDESTDIR = $${COMMON_DIRECTORY}/build/debug-64bit-msvc\n\t\t\tOBJECTS_DIR = $${PROJECT_DIRECTORY}/generated/obj-debug-64bit-msvc\n\t\t} else {\n\t\t\tDESTDIR = $${COMMON_DIRECTORY}/build/debug-32bit-msvc\n\t\t\tOBJECTS_DIR = $${PROJECT_DIRECTORY}/generated/obj-debug-32bit-msvc\n\t\t}\n\t}\n\n} else {\n\n\tcontains(QMAKE_COMPILER, gcc) {\n\t\tif($$ARCHITECTURE_64_BIT) {\n\t\t\tDESTDIR = $${COMMON_DIRECTORY}/build/release-64bit-gcc\n\t\t\tOBJECTS_DIR = $${PROJECT_DIRECTORY}/generated/obj-release-64bit-gcc\n\t\t} else {\n\t\t\tDESTDIR = $${COMMON_DIRECTORY}/build/release-32bit-gcc\n\t\t\tOBJECTS_DIR = $${PROJECT_DIRECTORY}/generated/obj-release-32bit-gcc\n\t\t}\n\n\t\tQMAKE_CXXFLAGS += -O2\n\t\tQMAKE_CXXFLAGS += -fexpensive-optimizations\n\t\tQMAKE_CXXFLAGS += -funit-at-a-time\n\t}\n\n\tmacx {\n\t\tQMAKE_CXXFLAGS -= -fexpensive-optimizations\n\t}\n\n\tcontains(QMAKE_COMPILER, msvc) {\n\t\tif($$ARCHITECTURE_64_BIT) {\n\t\t\tDESTDIR = $${COMMON_DIRECTORY}/build/release-64bit-msvc\n\t\t\tOBJECTS_DIR = $${PROJECT_DIRECTORY}/generated/obj-release-64bit-msvc\n\t\t} else {\n\t\t\tDESTDIR = $${COMMON_DIRECTORY}/build/release-32bit-msvc\n\t\t\tOBJECTS_DIR = $${PROJECT_DIRECTORY}/generated/obj-release-32bit-msvc\n\t\t}\n\t}\n\n\tDEFINES += NDEBUG\n\n}\n\nmacx {\n\tINCLUDEPATH += /usr/local/include\n}\n\nE = $$escape_expand(\\n\\t)\n\nwin32 {\n\tINCLUDEPATH += 'C:/Program Files/VapourSynth/sdk/include/vapoursynth'\n\n\tDEPLOY_COMMAND = windeployqt\n\tDEPLOY_TARGET = $$shell_quote($$shell_path($${DESTDIR}/$${TARGET}.exe))\n\tQMAKE_POST_LINK += $${DEPLOY_COMMAND} --no-translations --no-svg --no-opengl-sw --no-system-d3d-compiler $${DEPLOY_TARGET} $${E}\n\n\tif($$ARCHITECTURE_64_BIT) {\n\t\tmessage(\"x86_64 build\")\n\t} else {\n\t\tmessage(\"x86 build\")\n\t\tcontains(QMAKE_COMPILER, gcc) {\n\t\t\tQMAKE_LFLAGS += -Wl,--large-address-aware\n\t\t}\n\t\tcontains(QMAKE_COMPILER, msvc) {\n\t\t\tQMAKE_LFLAGS += /LARGEADDRESSAWARE\n\t\t}\n\t}\n}\n\ncontains(QMAKE_COMPILER, clang) {\n\tQMAKE_CXXFLAGS += -stdlib=libc++\n}\n\ncontains(QMAKE_COMPILER, gcc) {\n\tQMAKE_CXXFLAGS += -std=c++17\n\tQMAKE_CXXFLAGS += -Wall\n\tQMAKE_CXXFLAGS += -Wextra\n\tQMAKE_CXXFLAGS += -Wredundant-decls\n\tQMAKE_CXXFLAGS += -Wshadow\n\t#QMAKE_CXXFLAGS += -Weffc++\n\tQMAKE_CXXFLAGS += -pedantic\n\n\tLIBS += -L$$[QT_INSTALL_LIBS]\n} else {\n\tCONFIG += c++17\n}\n\nTEMPLATE = app\n\ninclude($${COMMON_DIRECTORY}/pro/common.pri)\n\nQMAKE_TARGET_PRODUCT = 'VapourSynth Editor Job Server'\nQMAKE_TARGET_DESCRIPTION = 'VapourSynth Editor Job Server'\n\n#SUBDIRS\n\nMOC_DIR = $${PROJECT_DIRECTORY}/generated/moc\nRCC_DIR = $${PROJECT_DIRECTORY}/generated/rcc\n\n#DEFINES\n\n#TRANSLATIONS\n\n#RESOURCES = $${COMMON_DIRECTORY}/resources/vsedit-job-server.qrc\n\nHEADERS += $${COMMON_DIRECTORY}/common-src/helpers.h\nHEADERS += $${COMMON_DIRECTORY}/common-src/helpers_vs.h\nHEADERS += $${COMMON_DIRECTORY}/common-src/version_info.h\nHEADERS += $${COMMON_DIRECTORY}/common-src/chrono.h\nHEADERS += $${COMMON_DIRECTORY}/common-src/settings/settings_definitions_core.h\nHEADERS += $${COMMON_DIRECTORY}/common-src/settings/settings_manager_core.h\nHEADERS += $${COMMON_DIRECTORY}/common-src/log/styled_log_view_core.h\nHEADERS += $${COMMON_DIRECTORY}/common-src/log/vs_editor_log_definitions.h\nHEADERS += $${COMMON_DIRECTORY}/common-src/vapoursynth/vs_script_library.h\nHEADERS += $${COMMON_DIRECTORY}/common-src/vapoursynth/vs_script_processor_structures.h\nHEADERS += $${COMMON_DIRECTORY}/common-src/vapoursynth/vapoursynth_script_processor.h\nHEADERS += $${COMMON_DIRECTORY}/common-src/frame_header_writers/frame_header_writer.h\nHEADERS += $${COMMON_DIRECTORY}/common-src/frame_header_writers/frame_header_writer_null.h\nHEADERS += $${COMMON_DIRECTORY}/common-src/frame_header_writers/frame_header_writer_y4m.h\nHEADERS += $${COMMON_DIRECTORY}/common-src/jobs/job.h\nHEADERS += $${COMMON_DIRECTORY}/common-src/jobs/job_variables.h\nHEADERS += $${COMMON_DIRECTORY}/common-src/application_instance_file_guard/application_instance_file_guard.h\nHEADERS += $${COMMON_DIRECTORY}/common-src/ipc_defines.h\nHEADERS += $${COMMON_DIRECTORY}/common-src/libp2p/p2p.h\nHEADERS += $${COMMON_DIRECTORY}/common-src/libp2p/p2p_api.h\nHEADERS += $${COMMON_DIRECTORY}/common-src/libp2p/simd/cpuinfo_x86.h\nHEADERS += $${COMMON_DIRECTORY}/common-src/libp2p/simd/p2p_simd.h\nHEADERS += $${COMMON_DIRECTORY}/common-src/vapoursynth/vs_pack_rgb.h\nHEADERS += $${COMMON_DIRECTORY}/common-src/vapoursynth/vs_set_matrix.h\n\nHEADERS += $${PROJECT_DIRECTORY}/src/jobs/job_definitions.h\nHEADERS += $${PROJECT_DIRECTORY}/src/jobs/jobs_manager.h\nHEADERS += $${PROJECT_DIRECTORY}/src/job_server.h\n\nSOURCES += $${COMMON_DIRECTORY}/common-src/helpers.cpp\nSOURCES += $${COMMON_DIRECTORY}/common-src/version_info.cpp\nSOURCES += $${COMMON_DIRECTORY}/common-src/settings/settings_definitions_core.cpp\nSOURCES += $${COMMON_DIRECTORY}/common-src/settings/settings_manager_core.cpp\nSOURCES += $${COMMON_DIRECTORY}/common-src/log/styled_log_view_core.cpp\nSOURCES += $${COMMON_DIRECTORY}/common-src/log/vs_editor_log_definitions.cpp\nSOURCES += $${COMMON_DIRECTORY}/common-src/vapoursynth/vs_script_library.cpp\nSOURCES += $${COMMON_DIRECTORY}/common-src/vapoursynth/vs_script_processor_structures.cpp\nSOURCES += $${COMMON_DIRECTORY}/common-src/vapoursynth/vapoursynth_script_processor.cpp\nSOURCES += $${COMMON_DIRECTORY}/common-src/frame_header_writers/frame_header_writer.cpp\nSOURCES += $${COMMON_DIRECTORY}/common-src/frame_header_writers/frame_header_writer_null.cpp\nSOURCES += $${COMMON_DIRECTORY}/common-src/frame_header_writers/frame_header_writer_y4m.cpp\nSOURCES += $${COMMON_DIRECTORY}/common-src/jobs/job.cpp\nSOURCES += $${COMMON_DIRECTORY}/common-src/jobs/job_variables.cpp\nSOURCES += $${COMMON_DIRECTORY}/common-src/application_instance_file_guard/application_instance_file_guard.cpp\nSOURCES += $${COMMON_DIRECTORY}/common-src/vapoursynth/vs_pack_rgb.cpp\nSOURCES += $${COMMON_DIRECTORY}/common-src/vapoursynth/vs_set_matrix.cpp\n\nSOURCES += $${PROJECT_DIRECTORY}/src/jobs/jobs_manager.cpp\nSOURCES += $${PROJECT_DIRECTORY}/src/job_server.cpp\nSOURCES += $${PROJECT_DIRECTORY}/src/main.cpp\n\n# libp2p\nSOURCES_P2P += $${COMMON_DIRECTORY}/common-src/libp2p/p2p_api.cpp\nSOURCES_P2P += $${COMMON_DIRECTORY}/common-src/libp2p/v210.cpp\nSOURCES_P2P += $${COMMON_DIRECTORY}/common-src/libp2p/simd/cpuinfo_x86.cpp\nSOURCES_P2P += $${COMMON_DIRECTORY}/common-src/libp2p/simd/p2p_simd.cpp\nif($$ARCHITECTURE_64_BIT) {\n\tSOURCES_P2P_SSE41 += $${COMMON_DIRECTORY}/common-src/libp2p/simd/p2p_sse41.cpp\n}\n\np2p.name = p2p\np2p.input = SOURCES_P2P\np2p.dependency_type = TYPE_C\np2p.variable_out = OBJECTS\np2p.output = ${QMAKE_VAR_OBJECTS_DIR}${QMAKE_FILE_IN_BASE}$${first(QMAKE_EXT_OBJ)}\np2p.commands = $${QMAKE_CXX} $(CXXFLAGS) -DP2P_SIMD $(INCPATH) -c ${QMAKE_FILE_IN}\ncontains(QMAKE_COMPILER, msvc) {\n\tp2p.commands += -Fo${QMAKE_FILE_OUT}\n} else {\n\tp2p.commands += -o ${QMAKE_FILE_OUT}\n\tp2p.commands += -std=c++14\n\tp2p.commands += -Wno-missing-field-initializers\n}\nmacx {\n\tp2p.commands += -Wno-gnu\n}\nQMAKE_EXTRA_COMPILERS += p2p\n\nif($$ARCHITECTURE_64_BIT) {\n\tp2p_sse41.name = p2p_sse41\n\tp2p_sse41.input = SOURCES_P2P_SSE41\n\tp2p_sse41.dependency_type = TYPE_C\n\tp2p_sse41.variable_out = OBJECTS\n\tp2p_sse41.output = ${QMAKE_VAR_OBJECTS_DIR}${QMAKE_FILE_IN_BASE}$${first(QMAKE_EXT_OBJ)}\n\tp2p_sse41.commands = $${QMAKE_CXX} $(CXXFLAGS) -DP2P_SIMD $(INCPATH) -c ${QMAKE_FILE_IN}\n\tcontains(QMAKE_COMPILER, msvc) {\n\t\tp2p_sse41.commands += -Fo${QMAKE_FILE_OUT}\n\t} else {\n\t\tp2p_sse41.commands += -msse4.1\n\t\tp2p_sse41.commands += -o ${QMAKE_FILE_OUT}\n\t\tp2p_sse41.commands += -std=c++14\n\t\tp2p_sse41.commands += -Wno-missing-field-initializers\n\t}\n}\nmacx {\n\tp2p_sse41.commands += -Wno-gnu\n}\nif($$ARCHITECTURE_64_BIT) {\n\tQMAKE_EXTRA_COMPILERS += p2p_sse41\n}\n\ninclude($${COMMON_DIRECTORY}/pro/local_quirks.pri)\n"
  },
  {
    "path": "pro/vsedit-job-server-watcher/vsedit-job-server-watcher.pro",
    "content": "CONFIG += qt\n\nQT += widgets\nQT += websockets\n\nHOST_64_BIT = contains(QMAKE_HOST.arch, \"x86_64\")\nTARGET_64_BIT = contains(QMAKE_TARGET.arch, \"x86_64\")\nARCHITECTURE_64_BIT = $$HOST_64_BIT | $$TARGET_64_BIT\n\nPROJECT_DIRECTORY = ../../vsedit-job-server-watcher\nCOMMON_DIRECTORY = ../..\n\nINCLUDEPATH += $$(VS_INCLUDE_PATH)\n\nTARGET = vsedit-job-server-watcher\n\nCONFIG(debug, debug|release) {\n\n\tcontains(QMAKE_COMPILER, gcc) {\n\t\tif($$ARCHITECTURE_64_BIT) {\n\t\t\tDESTDIR = $${COMMON_DIRECTORY}/build/debug-64bit-gcc\n\t\t\tOBJECTS_DIR = $${PROJECT_DIRECTORY}/generated/obj-debug-64bit-gcc\n\t\t} else {\n\t\t\tDESTDIR = $${COMMON_DIRECTORY}/build/debug-32bit-gcc\n\t\t\tOBJECTS_DIR = $${PROJECT_DIRECTORY}/generated/obj-debug-32bit-gcc\n\t\t}\n\n\t\tQMAKE_CXXFLAGS += -O0\n\t\tQMAKE_CXXFLAGS += -g\n\t\tQMAKE_CXXFLAGS += -ggdb3\n\t}\n\n\tcontains(QMAKE_COMPILER, msvc) {\n\t\tif($$ARCHITECTURE_64_BIT) {\n\t\t\tDESTDIR = $${COMMON_DIRECTORY}/build/debug-64bit-msvc\n\t\t\tOBJECTS_DIR = $${PROJECT_DIRECTORY}/generated/obj-debug-64bit-msvc\n\t\t} else {\n\t\t\tDESTDIR = $${COMMON_DIRECTORY}/build/debug-32bit-msvc\n\t\t\tOBJECTS_DIR = $${PROJECT_DIRECTORY}/generated/obj-debug-32bit-msvc\n\t\t}\n\t}\n\n} else {\n\n\tcontains(QMAKE_COMPILER, gcc) {\n\t\tif($$ARCHITECTURE_64_BIT) {\n\t\t\tDESTDIR = $${COMMON_DIRECTORY}/build/release-64bit-gcc\n\t\t\tOBJECTS_DIR = $${PROJECT_DIRECTORY}/generated/obj-release-64bit-gcc\n\t\t} else {\n\t\t\tDESTDIR = $${COMMON_DIRECTORY}/build/release-32bit-gcc\n\t\t\tOBJECTS_DIR = $${PROJECT_DIRECTORY}/generated/obj-release-32bit-gcc\n\t\t}\n\n\t\tQMAKE_CXXFLAGS += -O2\n\t\tQMAKE_CXXFLAGS += -fexpensive-optimizations\n\t\tQMAKE_CXXFLAGS += -funit-at-a-time\n\t}\n\n\tmacx {\n\t\tQMAKE_CXXFLAGS -= -fexpensive-optimizations\n\t}\n\n\tcontains(QMAKE_COMPILER, msvc) {\n\t\tif($$ARCHITECTURE_64_BIT) {\n\t\t\tDESTDIR = $${COMMON_DIRECTORY}/build/release-64bit-msvc\n\t\t\tOBJECTS_DIR = $${PROJECT_DIRECTORY}/generated/obj-release-64bit-msvc\n\t\t} else {\n\t\t\tDESTDIR = $${COMMON_DIRECTORY}/build/release-32bit-msvc\n\t\t\tOBJECTS_DIR = $${PROJECT_DIRECTORY}/generated/obj-release-32bit-msvc\n\t\t}\n\t}\n\n\tDEFINES += NDEBUG\n\n}\n\nE = $$escape_expand(\\n\\t)\n\nmacx {\n\tINCLUDEPATH += /usr/local/include\n\tICON = $${COMMON_DIRECTORY}/resources/vsedit.icns\n}\n\nwin32 {\n\tQMAKE_LFLAGS += '/entry:mainCRTStartup'\n\n\tINCLUDEPATH += 'C:/Program Files/VapourSynth/sdk/include/vapoursynth'\n\n\tDEPLOY_COMMAND = windeployqt\n\tDEPLOY_TARGET = $$shell_quote($$shell_path($${DESTDIR}/$${TARGET}.exe))\n\tQMAKE_POST_LINK += $${DEPLOY_COMMAND} --no-translations --no-svg --no-opengl-sw --no-system-d3d-compiler $${DEPLOY_TARGET} $${E}\n\n\tif($$ARCHITECTURE_64_BIT) {\n\t\tmessage(\"x86_64 build\")\n\t} else {\n\t\tmessage(\"x86 build\")\n\t\tcontains(QMAKE_COMPILER, gcc) {\n\t\t\tQMAKE_LFLAGS += -Wl,--large-address-aware\n\t\t}\n\t\tcontains(QMAKE_COMPILER, msvc) {\n\t\t\tQMAKE_LFLAGS += /LARGEADDRESSAWARE\n\t\t}\n\t}\n}\n\ncontains(QMAKE_COMPILER, clang) {\n\tQMAKE_CXXFLAGS += -stdlib=libc++\n}\n\ncontains(QMAKE_COMPILER, gcc) {\n\tQMAKE_CXXFLAGS += -std=c++17\n\tQMAKE_CXXFLAGS += -Wall\n\tQMAKE_CXXFLAGS += -Wextra\n\tQMAKE_CXXFLAGS += -Wredundant-decls\n\tQMAKE_CXXFLAGS += -Wshadow\n\t#QMAKE_CXXFLAGS += -Weffc++\n\tQMAKE_CXXFLAGS += -pedantic\n\n\tLIBS += -L$$[QT_INSTALL_LIBS]\n} else {\n\tCONFIG += c++17\n}\n\ninclude($${COMMON_DIRECTORY}/pro/common.pri)\n\nTEMPLATE = app\n\nRC_ICONS = $${COMMON_DIRECTORY}/resources/vsedit.ico\nQMAKE_TARGET_PRODUCT = 'VapourSynth Editor Job Server Watcher'\nQMAKE_TARGET_DESCRIPTION = 'VapourSynth Editor Job Server Watcher'\n\n#SUBDIRS\n\nMOC_DIR = $${PROJECT_DIRECTORY}/generated/moc\nUI_DIR = $${PROJECT_DIRECTORY}/generated/ui\nRCC_DIR = $${PROJECT_DIRECTORY}/generated/rcc\n\n#DEFINES\n\n#TRANSLATIONS\n\nRESOURCES = $${COMMON_DIRECTORY}/resources/vsedit-job-server-watcher.qrc\nRESOURCES += $${COMMON_DIRECTORY}/resources/dark/style.qrc\n\nFORMS += $${COMMON_DIRECTORY}/common-src/log/styled_log_view_settings_dialog.ui\nFORMS += $${PROJECT_DIRECTORY}/src/jobs/job_edit_dialog.ui\nFORMS += $${PROJECT_DIRECTORY}/src/connect_to_server_dialog.ui\nFORMS += $${PROJECT_DIRECTORY}/src/trusted_clients_addresses_dialog.ui\nFORMS += $${PROJECT_DIRECTORY}/src/main_window.ui\n\nHEADERS += $${COMMON_DIRECTORY}/common-src/application_instance_file_guard/application_instance_file_guard.h\nHEADERS += $${COMMON_DIRECTORY}/common-src/helpers.h\nHEADERS += $${COMMON_DIRECTORY}/common-src/helpers_vs.h\nHEADERS += $${COMMON_DIRECTORY}/common-src/version_info.h\nHEADERS += $${COMMON_DIRECTORY}/common-src/ipc_defines.h\nHEADERS += $${COMMON_DIRECTORY}/common-src/settings/settings_definitions_core.h\nHEADERS += $${COMMON_DIRECTORY}/common-src/settings/settings_definitions.h\nHEADERS += $${COMMON_DIRECTORY}/common-src/settings/settings_manager_core.h\nHEADERS += $${COMMON_DIRECTORY}/common-src/settings/settings_manager.h\nHEADERS += $${COMMON_DIRECTORY}/common-src/log/styled_log_view_core.h\nHEADERS += $${COMMON_DIRECTORY}/common-src/log/styled_log_view_structures.h\nHEADERS += $${COMMON_DIRECTORY}/common-src/log/log_styles_model.h\nHEADERS += $${COMMON_DIRECTORY}/common-src/log/styled_log_view_settings_dialog.h\nHEADERS += $${COMMON_DIRECTORY}/common-src/log/styled_log_view.h\nHEADERS += $${COMMON_DIRECTORY}/common-src/log/vs_editor_log_definitions.h\nHEADERS += $${COMMON_DIRECTORY}/common-src/log/vs_editor_log.h\nHEADERS += $${COMMON_DIRECTORY}/common-src/vapoursynth/vs_script_library.h\nHEADERS += $${COMMON_DIRECTORY}/common-src/vapoursynth/vs_script_processor_structures.h\nHEADERS += $${COMMON_DIRECTORY}/common-src/vapoursynth/vapoursynth_script_processor.h\nHEADERS += $${COMMON_DIRECTORY}/common-src/jobs/job_variables.h\nHEADERS += $${COMMON_DIRECTORY}/common-src/libp2p/p2p.h\nHEADERS += $${COMMON_DIRECTORY}/common-src/libp2p/p2p_api.h\nHEADERS += $${COMMON_DIRECTORY}/common-src/libp2p/simd/cpuinfo_x86.h\nHEADERS += $${COMMON_DIRECTORY}/common-src/libp2p/simd/p2p_simd.h\nHEADERS += $${COMMON_DIRECTORY}/common-src/vapoursynth/vs_pack_rgb.h\nHEADERS += $${COMMON_DIRECTORY}/common-src/vapoursynth/vs_set_matrix.h\nHEADERS += $${PROJECT_DIRECTORY}/src/jobs/jobs_model.h\nHEADERS += $${PROJECT_DIRECTORY}/src/jobs/job_edit_dialog.h\nHEADERS += $${PROJECT_DIRECTORY}/src/jobs/job_dependencies_delegate.h\nHEADERS += $${PROJECT_DIRECTORY}/src/jobs/job_state_delegate.h\nHEADERS += $${PROJECT_DIRECTORY}/src/connect_to_server_dialog.h\nHEADERS += $${PROJECT_DIRECTORY}/src/trusted_clients_addresses_dialog.h\nHEADERS += $${PROJECT_DIRECTORY}/src/main_window.h\n\nSOURCES += $${COMMON_DIRECTORY}/common-src/helpers.cpp\nSOURCES += $${COMMON_DIRECTORY}/common-src/version_info.cpp\nSOURCES += $${COMMON_DIRECTORY}/common-src/application_instance_file_guard/application_instance_file_guard.cpp\nSOURCES += $${COMMON_DIRECTORY}/common-src/settings/settings_definitions_core.cpp\nSOURCES += $${COMMON_DIRECTORY}/common-src/settings/settings_definitions.cpp\nSOURCES += $${COMMON_DIRECTORY}/common-src/settings/settings_manager_core.cpp\nSOURCES += $${COMMON_DIRECTORY}/common-src/settings/settings_manager.cpp\nSOURCES += $${COMMON_DIRECTORY}/common-src/log/styled_log_view_core.cpp\nSOURCES += $${COMMON_DIRECTORY}/common-src/log/styled_log_view_structures.cpp\nSOURCES += $${COMMON_DIRECTORY}/common-src/log/log_styles_model.cpp\nSOURCES += $${COMMON_DIRECTORY}/common-src/log/styled_log_view_settings_dialog.cpp\nSOURCES += $${COMMON_DIRECTORY}/common-src/log/styled_log_view.cpp\nSOURCES += $${COMMON_DIRECTORY}/common-src/log/vs_editor_log_definitions.cpp\nSOURCES += $${COMMON_DIRECTORY}/common-src/log/vs_editor_log.cpp\nSOURCES += $${COMMON_DIRECTORY}/common-src/vapoursynth/vs_script_library.cpp\nSOURCES += $${COMMON_DIRECTORY}/common-src/vapoursynth/vs_script_processor_structures.cpp\nSOURCES += $${COMMON_DIRECTORY}/common-src/vapoursynth/vapoursynth_script_processor.cpp\nSOURCES += $${COMMON_DIRECTORY}/common-src/jobs/job_variables.cpp\nSOURCES += $${COMMON_DIRECTORY}/common-src/vapoursynth/vs_pack_rgb.cpp\nSOURCES += $${COMMON_DIRECTORY}/common-src/vapoursynth/vs_set_matrix.cpp\nSOURCES += $${PROJECT_DIRECTORY}/src/jobs/jobs_model.cpp\nSOURCES += $${PROJECT_DIRECTORY}/src/jobs/job_edit_dialog.cpp\nSOURCES += $${PROJECT_DIRECTORY}/src/jobs/job_dependencies_delegate.cpp\nSOURCES += $${PROJECT_DIRECTORY}/src/jobs/job_state_delegate.cpp\nSOURCES += $${PROJECT_DIRECTORY}/src/connect_to_server_dialog.cpp\nSOURCES += $${PROJECT_DIRECTORY}/src/trusted_clients_addresses_dialog.cpp\nSOURCES += $${PROJECT_DIRECTORY}/src/main_window.cpp\nSOURCES += $${PROJECT_DIRECTORY}/src/main.cpp\n\n# libp2p\nSOURCES_P2P += $${COMMON_DIRECTORY}/common-src/libp2p/p2p_api.cpp\nSOURCES_P2P += $${COMMON_DIRECTORY}/common-src/libp2p/v210.cpp\nSOURCES_P2P += $${COMMON_DIRECTORY}/common-src/libp2p/simd/cpuinfo_x86.cpp\nSOURCES_P2P += $${COMMON_DIRECTORY}/common-src/libp2p/simd/p2p_simd.cpp\nif($$ARCHITECTURE_64_BIT) {\n\tSOURCES_P2P_SSE41 += $${COMMON_DIRECTORY}/common-src/libp2p/simd/p2p_sse41.cpp\n}\n\np2p.name = p2p\np2p.input = SOURCES_P2P\np2p.dependency_type = TYPE_C\np2p.variable_out = OBJECTS\np2p.output = ${QMAKE_VAR_OBJECTS_DIR}${QMAKE_FILE_IN_BASE}$${first(QMAKE_EXT_OBJ)}\np2p.commands = $${QMAKE_CXX} $(CXXFLAGS) -DP2P_SIMD $(INCPATH) -c ${QMAKE_FILE_IN}\ncontains(QMAKE_COMPILER, msvc) {\n\tp2p.commands += -Fo${QMAKE_FILE_OUT}\n} else {\n\tp2p.commands += -o ${QMAKE_FILE_OUT}\n\tp2p.commands += -std=c++14\n\tp2p.commands += -Wno-missing-field-initializers\n}\nmacx {\n\tp2p.commands += -Wno-gnu\n}\nQMAKE_EXTRA_COMPILERS += p2p\n\nif($$ARCHITECTURE_64_BIT) {\n\tp2p_sse41.name = p2p_sse41\n\tp2p_sse41.input = SOURCES_P2P_SSE41\n\tp2p_sse41.dependency_type = TYPE_C\n\tp2p_sse41.variable_out = OBJECTS\n\tp2p_sse41.output = ${QMAKE_VAR_OBJECTS_DIR}${QMAKE_FILE_IN_BASE}$${first(QMAKE_EXT_OBJ)}\n\tp2p_sse41.commands = $${QMAKE_CXX} $(CXXFLAGS) -DP2P_SIMD $(INCPATH) -c ${QMAKE_FILE_IN}\n\tcontains(QMAKE_COMPILER, msvc) {\n\t\tp2p_sse41.commands += -Fo${QMAKE_FILE_OUT}\n\t} else {\n\t\tp2p_sse41.commands += -msse4.1\n\t\tp2p_sse41.commands += -o ${QMAKE_FILE_OUT}\n\t\tp2p_sse41.commands += -std=c++14\n\t\tp2p_sse41.commands += -Wno-missing-field-initializers\n\t}\n}\nmacx {\n\tp2p_sse41.commands += -Wno-gnu\n}\nif($$ARCHITECTURE_64_BIT) {\n\tQMAKE_EXTRA_COMPILERS += p2p_sse41\n}\n\ninclude($${COMMON_DIRECTORY}/pro/local_quirks.pri)\n"
  },
  {
    "path": "pro/vsedit-previewer/vsedit-previewer.pro",
    "content": "CONFIG += qt\n\nQT += widgets\n\nwin32 {\n\tQT += multimedia\n\tCONFIG += console\n}\n\nHOST_64_BIT = contains(QMAKE_HOST.arch, \"x86_64\")\nTARGET_64_BIT = contains(QMAKE_TARGET.arch, \"x86_64\")\nARCHITECTURE_64_BIT = $$HOST_64_BIT | $$TARGET_64_BIT\n\nPROJECT_DIRECTORY = ../../vsedit\nCOMMON_DIRECTORY = ../..\n\nINCLUDEPATH += $$(VS_INCLUDE_PATH)\n\nCONFIG(debug, debug|release) {\n\n\tcontains(QMAKE_COMPILER, gcc) {\n\t\tif($$ARCHITECTURE_64_BIT) {\n\t\t\tDESTDIR = $${COMMON_DIRECTORY}/build/debug-64bit-gcc\n\t\t\tTARGET = vsedit-previewer-debug-64bit-gcc\n\t\t\tOBJECTS_DIR = $${PROJECT_DIRECTORY}/generated/obj-debug-64bit-gcc\n\t\t} else {\n\t\t\tDESTDIR = $${COMMON_DIRECTORY}/build/debug-32bit-gcc\n\t\t\tTARGET = vsedit-previewer-debug-32bit-gcc\n\t\t\tOBJECTS_DIR = $${PROJECT_DIRECTORY}/generated/obj-debug-32bit-gcc\n\t\t}\n\n\t\tQMAKE_CXXFLAGS += -O0\n\t\tQMAKE_CXXFLAGS += -g\n\t\tQMAKE_CXXFLAGS += -ggdb3\n\t}\n\n\tcontains(QMAKE_COMPILER, msvc) {\n\t\tif($$ARCHITECTURE_64_BIT) {\n\t\t\tDESTDIR = $${COMMON_DIRECTORY}/build/debug-64bit-msvc\n\t\t\tTARGET = vsedit-previewer-debug-64bit-msvc\n\t\t\tOBJECTS_DIR = $${PROJECT_DIRECTORY}/generated/obj-debug-64bit-msvc\n\t\t} else {\n\t\t\tDESTDIR = $${COMMON_DIRECTORY}/build/debug-32bit-msvc\n\t\t\tTARGET = vsedit-previewer-debug-32bit-msvc\n\t\t\tOBJECTS_DIR = $${PROJECT_DIRECTORY}/generated/obj-debug-32bit-msvc\n\t\t}\n\t}\n\n} else {\n\n\tcontains(QMAKE_COMPILER, gcc) {\n\t\tif($$ARCHITECTURE_64_BIT) {\n\t\t\tDESTDIR = $${COMMON_DIRECTORY}/build/release-64bit-gcc\n\t\t\tTARGET = vsedit-previewer\n\t\t\tOBJECTS_DIR = $${PROJECT_DIRECTORY}/generated/obj-release-64bit-gcc\n\t\t} else {\n\t\t\tDESTDIR = $${COMMON_DIRECTORY}/build/release-32bit-gcc\n\t\t\tTARGET = vsedit-previewer-32bit\n\t\t\tOBJECTS_DIR = $${PROJECT_DIRECTORY}/generated/obj-release-32bit-gcc\n\t\t}\n\n\t\tQMAKE_CXXFLAGS += -O2\n\t\tQMAKE_CXXFLAGS += -fexpensive-optimizations\n\t\tQMAKE_CXXFLAGS += -funit-at-a-time\n\t}\n\n\tmacx {\n\t\tQMAKE_CXXFLAGS -= -fexpensive-optimizations\n\t}\n\n\tcontains(QMAKE_COMPILER, msvc) {\n\t\tif($$ARCHITECTURE_64_BIT) {\n\t\t\tDESTDIR = $${COMMON_DIRECTORY}/build/release-64bit-msvc\n\t\t\tTARGET = vsedit-previewer\n\t\t\tOBJECTS_DIR = $${PROJECT_DIRECTORY}/generated/obj-release-64bit-msvc\n\t\t} else {\n\t\t\tDESTDIR = $${COMMON_DIRECTORY}/build/release-32bit-msvc\n\t\t\tTARGET = vsedit-previewer-32bit\n\t\t\tOBJECTS_DIR = $${PROJECT_DIRECTORY}/generated/obj-release-32bit-msvc\n\t\t}\n\t}\n\n\tDEFINES += NDEBUG\n\n}\n\nS = $${DIR_SEPARATOR}\n\nD = $$DESTDIR\nD = $$replace(D, /, $$S)\n\nSC = $${COMMON_DIRECTORY}/\nSC = $$replace(SC, /, $$S)\n\nE = $$escape_expand(\\n\\t)\n\nQMAKE_POST_LINK += $${QMAKE_COPY} $${SC}$${S}resources$${S}vsedit.ico $${D}$${S}vsedit.ico $${E}\nQMAKE_POST_LINK += $${QMAKE_COPY} $${SC}$${S}resources$${S}vsedit.svg $${D}$${S}vsedit.svg $${E}\nQMAKE_POST_LINK += $${QMAKE_COPY} $${SC}$${S}README $${D}$${S}README $${E}\nQMAKE_POST_LINK += $${QMAKE_COPY} $${SC}$${S}LICENSE $${D}$${S}LICENSE $${E}\nQMAKE_POST_LINK += $${QMAKE_COPY} $${SC}$${S}CHANGELOG $${D}$${S}CHANGELOG $${E}\n\nmacx {\n\tINCLUDEPATH += /usr/local/include\n\tICON = $${COMMON_DIRECTORY}/resources/vsedit.icns\n}\n\nwin32 {\n\tINCLUDEPATH += 'C:/Program Files/VapourSynth/sdk/include/vapoursynth'\n\n\tDEPLOY_COMMAND = windeployqt\n\tDEPLOY_TARGET = $$shell_quote($$shell_path($${D}/$${TARGET}.exe))\n\tQMAKE_POST_LINK += $${DEPLOY_COMMAND} --no-translations --no-svg --no-opengl-sw --no-system-d3d-compiler $${DEPLOY_TARGET} $${E}\n\n\tif($$ARCHITECTURE_64_BIT) {\n\t\tmessage(\"x86_64 build\")\n\t} else {\n\t\tmessage(\"x86 build\")\n\t\tcontains(QMAKE_COMPILER, gcc) {\n\t\t\tQMAKE_LFLAGS += -Wl,--large-address-aware\n\t\t}\n\t\tcontains(QMAKE_COMPILER, msvc) {\n\t\t\tQMAKE_LFLAGS += /LARGEADDRESSAWARE\n\t\t}\n\t}\n}\n\ncontains(QMAKE_COMPILER, clang) {\n\tQMAKE_CXXFLAGS += -stdlib=libc++\n}\n\ncontains(QMAKE_COMPILER, gcc) {\n\tQMAKE_CXXFLAGS += -std=c++17\n\tQMAKE_CXXFLAGS += -Wall\n\tQMAKE_CXXFLAGS += -Wextra\n\tQMAKE_CXXFLAGS += -Wredundant-decls\n\tQMAKE_CXXFLAGS += -Wshadow\n\t#QMAKE_CXXFLAGS += -Weffc++\n\tQMAKE_CXXFLAGS += -pedantic\n\n\tLIBS += -L$$[QT_INSTALL_LIBS]\n} else {\n\tCONFIG += c++17\n}\n\ninclude($${COMMON_DIRECTORY}/pro/common.pri)\n\nTEMPLATE = app\n\nRC_ICONS = $${COMMON_DIRECTORY}/resources/vsedit.ico\nQMAKE_TARGET_PRODUCT = 'VapourSynth Editor Previewer'\nQMAKE_TARGET_DESCRIPTION = 'VapourSynth Editor Previewer'\n\n#SUBDIRS\n\nMOC_DIR = $${PROJECT_DIRECTORY}/generated/moc\nUI_DIR = $${PROJECT_DIRECTORY}/generated/ui\nRCC_DIR = $${PROJECT_DIRECTORY}/generated/rcc\n\n#DEFINES\n\n#TRANSLATIONS\n\nRESOURCES = $${COMMON_DIRECTORY}/resources/vsedit.qrc\nRESOURCES += $${COMMON_DIRECTORY}/resources/dark/style.qrc\n\nFORMS += $${PROJECT_DIRECTORY}/src/settings/settings_dialog.ui\nFORMS += $${PROJECT_DIRECTORY}/src/script_status_bar_widget/script_status_bar_widget.ui\nFORMS += $${PROJECT_DIRECTORY}/src/preview/preview_advanced_settings_dialog.ui\nFORMS += $${PROJECT_DIRECTORY}/src/preview/preview_dialog.ui\n\nHEADERS += $${COMMON_DIRECTORY}/common-src/helpers.h\nHEADERS += $${COMMON_DIRECTORY}/common-src/helpers_vs.h\nHEADERS += $${COMMON_DIRECTORY}/common-src/version_info.h\nHEADERS += $${COMMON_DIRECTORY}/common-src/chrono.h\nHEADERS += $${COMMON_DIRECTORY}/common-src/settings/settings_definitions_core.h\nHEADERS += $${COMMON_DIRECTORY}/common-src/settings/settings_definitions.h\nHEADERS += $${COMMON_DIRECTORY}/common-src/settings/settings_manager_core.h\nHEADERS += $${COMMON_DIRECTORY}/common-src/settings/settings_manager.h\nHEADERS += $${COMMON_DIRECTORY}/common-src/log/styled_log_view_core.h\nHEADERS += $${COMMON_DIRECTORY}/common-src/log/styled_log_view_structures.h\nHEADERS += $${COMMON_DIRECTORY}/common-src/log/vs_editor_log_definitions.h\nHEADERS += $${COMMON_DIRECTORY}/common-src/vapoursynth/vs_script_library.h\nHEADERS += $${COMMON_DIRECTORY}/common-src/vapoursynth/vs_script_processor_structures.h\nHEADERS += $${COMMON_DIRECTORY}/common-src/vapoursynth/vapoursynth_script_processor.h\nHEADERS += $${COMMON_DIRECTORY}/common-src/timeline_slider/timeline_slider.h\nHEADERS += $${COMMON_DIRECTORY}/common-src/libp2p/p2p.h\nHEADERS += $${COMMON_DIRECTORY}/common-src/libp2p/p2p_api.h\nHEADERS += $${COMMON_DIRECTORY}/common-src/libp2p/simd/cpuinfo_x86.h\nHEADERS += $${COMMON_DIRECTORY}/common-src/libp2p/simd/p2p_simd.h\nHEADERS += $${COMMON_DIRECTORY}/common-src/vapoursynth/vs_pack_rgb.h\nHEADERS += $${COMMON_DIRECTORY}/common-src/vapoursynth/vs_set_matrix.h\n\nHEADERS += $${PROJECT_DIRECTORY}/src/settings/actions_hotkey_edit_model.h\nHEADERS += $${PROJECT_DIRECTORY}/src/settings/clearable_key_sequence_editor.h\nHEADERS += $${PROJECT_DIRECTORY}/src/settings/item_delegate_for_hotkey.h\nHEADERS += $${PROJECT_DIRECTORY}/src/settings/theme_elements_model.h\nHEADERS += $${PROJECT_DIRECTORY}/src/settings/settings_dialog.h\nHEADERS += $${PROJECT_DIRECTORY}/src/script_status_bar_widget/script_status_bar_widget.h\nHEADERS += $${PROJECT_DIRECTORY}/src/preview/scroll_navigator.h\nHEADERS += $${PROJECT_DIRECTORY}/src/preview/preview_area.h\nHEADERS += $${PROJECT_DIRECTORY}/src/preview/preview_advanced_settings_dialog.h\nHEADERS += $${PROJECT_DIRECTORY}/src/preview/preview_dialog.h\nHEADERS += $${PROJECT_DIRECTORY}/src/preview/zoom_ratio_spinbox.h\nHEADERS += $${PROJECT_DIRECTORY}/src/vapoursynth/vs_script_processor_dialog.h\n\nSOURCES += $${COMMON_DIRECTORY}/common-src/helpers.cpp\nSOURCES += $${COMMON_DIRECTORY}/common-src/version_info.cpp\nSOURCES += $${COMMON_DIRECTORY}/common-src/settings/settings_definitions_core.cpp\nSOURCES += $${COMMON_DIRECTORY}/common-src/settings/settings_definitions.cpp\nSOURCES += $${COMMON_DIRECTORY}/common-src/settings/settings_manager_core.cpp\nSOURCES += $${COMMON_DIRECTORY}/common-src/settings/settings_manager.cpp\nSOURCES += $${COMMON_DIRECTORY}/common-src/log/styled_log_view_core.cpp\nSOURCES += $${COMMON_DIRECTORY}/common-src/log/styled_log_view_structures.cpp\nSOURCES += $${COMMON_DIRECTORY}/common-src/log/vs_editor_log_definitions.cpp\nSOURCES += $${COMMON_DIRECTORY}/common-src/vapoursynth/vs_script_library.cpp\nSOURCES += $${COMMON_DIRECTORY}/common-src/vapoursynth/vs_script_processor_structures.cpp\nSOURCES += $${COMMON_DIRECTORY}/common-src/vapoursynth/vapoursynth_script_processor.cpp\nSOURCES += $${COMMON_DIRECTORY}/common-src/timeline_slider/timeline_slider.cpp\nSOURCES += $${COMMON_DIRECTORY}/common-src/vapoursynth/vs_pack_rgb.cpp\nSOURCES += $${COMMON_DIRECTORY}/common-src/vapoursynth/vs_set_matrix.cpp\n\nSOURCES += $${PROJECT_DIRECTORY}/src/settings/actions_hotkey_edit_model.cpp\nSOURCES += $${PROJECT_DIRECTORY}/src/settings/clearable_key_sequence_editor.cpp\nSOURCES += $${PROJECT_DIRECTORY}/src/settings/item_delegate_for_hotkey.cpp\nSOURCES += $${PROJECT_DIRECTORY}/src/settings/theme_elements_model.cpp\nSOURCES += $${PROJECT_DIRECTORY}/src/settings/settings_dialog.cpp\nSOURCES += $${PROJECT_DIRECTORY}/src/script_status_bar_widget/script_status_bar_widget.cpp\nSOURCES += $${PROJECT_DIRECTORY}/src/preview/scroll_navigator.cpp\nSOURCES += $${PROJECT_DIRECTORY}/src/preview/preview_area.cpp\nSOURCES += $${PROJECT_DIRECTORY}/src/preview/preview_advanced_settings_dialog.cpp\nSOURCES += $${PROJECT_DIRECTORY}/src/preview/preview_dialog.cpp\nSOURCES += $${PROJECT_DIRECTORY}/src/preview/zoom_ratio_spinbox.cpp\nSOURCES += $${PROJECT_DIRECTORY}/src/vapoursynth/vs_script_processor_dialog.cpp\nSOURCES += $${PROJECT_DIRECTORY}/src/vsedit_previewer_main.cpp\n\n# libp2p\nSOURCES_P2P += $${COMMON_DIRECTORY}/common-src/libp2p/p2p_api.cpp\nSOURCES_P2P += $${COMMON_DIRECTORY}/common-src/libp2p/v210.cpp\nSOURCES_P2P += $${COMMON_DIRECTORY}/common-src/libp2p/simd/cpuinfo_x86.cpp\nSOURCES_P2P += $${COMMON_DIRECTORY}/common-src/libp2p/simd/p2p_simd.cpp\nif($$ARCHITECTURE_64_BIT) {\n\tSOURCES_P2P_SSE41 += $${COMMON_DIRECTORY}/common-src/libp2p/simd/p2p_sse41.cpp\n}\n\np2p.name = p2p\np2p.input = SOURCES_P2P\np2p.dependency_type = TYPE_C\np2p.variable_out = OBJECTS\np2p.output = ${QMAKE_VAR_OBJECTS_DIR}${QMAKE_FILE_IN_BASE}$${first(QMAKE_EXT_OBJ)}\np2p.commands = $${QMAKE_CXX} $(CXXFLAGS) -DP2P_SIMD $(INCPATH) -c ${QMAKE_FILE_IN}\ncontains(QMAKE_COMPILER, msvc) {\n\tp2p.commands += -Fo${QMAKE_FILE_OUT}\n} else {\n\tp2p.commands += -o ${QMAKE_FILE_OUT}\n\tp2p.commands += -std=c++14\n\tp2p.commands += -Wno-missing-field-initializers\n}\nmacx {\n\tp2p.commands += -Wno-gnu\n}\nQMAKE_EXTRA_COMPILERS += p2p\n\nif($$ARCHITECTURE_64_BIT) {\n\tp2p_sse41.name = p2p_sse41\n\tp2p_sse41.input = SOURCES_P2P_SSE41\n\tp2p_sse41.dependency_type = TYPE_C\n\tp2p_sse41.variable_out = OBJECTS\n\tp2p_sse41.output = ${QMAKE_VAR_OBJECTS_DIR}${QMAKE_FILE_IN_BASE}$${first(QMAKE_EXT_OBJ)}\n\tp2p_sse41.commands = $${QMAKE_CXX} $(CXXFLAGS) -DP2P_SIMD $(INCPATH) -c ${QMAKE_FILE_IN}\n\tcontains(QMAKE_COMPILER, msvc) {\n\t\tp2p_sse41.commands += -Fo${QMAKE_FILE_OUT}\n\t} else {\n\t\tp2p_sse41.commands += -msse4.1\n\t\tp2p_sse41.commands += -o ${QMAKE_FILE_OUT}\n\t\tp2p_sse41.commands += -std=c++14\n\t\tp2p_sse41.commands += -Wno-missing-field-initializers\n\t}\n}\nmacx {\n\tp2p_sse41.commands += -Wno-gnu\n}\nif($$ARCHITECTURE_64_BIT) {\n\tQMAKE_EXTRA_COMPILERS += p2p_sse41\n}\n\ninclude($${COMMON_DIRECTORY}/pro/local_quirks.pri)\n"
  },
  {
    "path": "resources/dark/LICENSE.rst",
    "content": "License\n=======\n\nThe MIT License (MIT) - Code\n----------------------------\n\nCopyright (c) 2013-2019 Colin Duquesnoy\n\nPermission is hereby granted, free of charge, to any person obtaining a\ncopy of this software and associated documentation files (the\n\"Software\"), to deal in the Software without restriction, including\nwithout limitation the rights to use, copy, modify, merge, publish,\ndistribute, sublicense, and/or sell copies of the Software, and to\npermit persons to whom the Software is furnished to do so, subject to\nthe following conditions:\n\nThe above copyright notice and this permission notice shall be included\nin all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS\nOR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\nMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\nIN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\nCLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,\nTORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\nSOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\n\nCreative Commons Attribution International 4.0 - Images\n-------------------------------------------------------\n\nQDarkStyle (c) 2013-2019 Colin Duquesnoy\nQDarkStyle (c) 2019-2019 Daniel Cosmo Pizetta\n\nCreative Commons Corporation (“Creative Commons”) is not a law firm and\ndoes not provide legal services or legal advice. Distribution of\nCreative Commons public licenses does not create a lawyer-client or\nother relationship. Creative Commons makes its licenses and related\ninformation available on an “as-is” basis. Creative Commons gives no\nwarranties regarding its licenses, any material licensed under their\nterms and conditions, or any related information. Creative Commons\ndisclaims all liability for damages resulting from their use to the\nfullest extent possible.\n\nUsing Creative Commons Public Licenses\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nCreative Commons public licenses provide a standard set of terms and\nconditions that creators and other rights holders may use to share\noriginal works of authorship and other material subject to copyright and\ncertain other rights specified in the public license below. The\nfollowing considerations are for informational purposes only, are not\nexhaustive, and do not form part of our licenses.\n\n-  **Considerations for licensors:** Our public licenses are intended\n   for use by those authorized to give the public permission to use\n   material in ways otherwise restricted by copyright and certain other\n   rights. Our licenses are irrevocable. Licensors should read and\n   understand the terms and conditions of the license they choose before\n   applying it. Licensors should also secure all rights necessary before\n   applying our licenses so that the public can reuse the material as\n   expected. Licensors should clearly mark any material not subject to\n   the license. This includes other CC-licensed material, or material\n   used under an exception or limitation to copyright. `More\n   considerations for\n   licensors <http://wiki.creativecommons.org/Considerations_for_licensors_and_licensees#Considerations_for_licensors>`__.\n\n-  **Considerations for the public:** By using one of our public\n   licenses, a licensor grants the public permission to use the licensed\n   material under specified terms and conditions. If the licensor’s\n   permission is not necessary for any reason–for example, because of\n   any applicable exception or limitation to copyright–then that use is\n   not regulated by the license. Our licenses grant only permissions\n   under copyright and certain other rights that a licensor has\n   authority to grant. Use of the licensed material may still be\n   restricted for other reasons, including because others have copyright\n   or other rights in the material. A licensor may make special\n   requests, such as asking that all changes be marked or described.\n   Although not required by our licenses, you are encouraged to respect\n   those requests where reasonable. `More considerations for the\n   public <http://wiki.creativecommons.org/Considerations_for_licensors_and_licensees#Considerations_for_licensees>`__.\n\n\nCreative Commons Attribution 4.0 International Public License\n-------------------------------------------------------------\n\nBy exercising the Licensed Rights (defined below), You accept and agree\nto be bound by the terms and conditions of this Creative Commons\nAttribution 4.0 International Public License (\"Public License\"). To the\nextent this Public License may be interpreted as a contract, You are\ngranted the Licensed Rights in consideration of Your acceptance of these\nterms and conditions, and the Licensor grants You such rights in\nconsideration of benefits the Licensor receives from making the Licensed\nMaterial available under these terms and conditions.\n\nSection 1 – Definitions\n~~~~~~~~~~~~~~~~~~~~~~~\n\na. **Adapted Material** means material subject to Copyright and Similar\n   Rights that is derived from or based upon the Licensed Material and\n   in which the Licensed Material is translated, altered, arranged,\n   transformed, or otherwise modified in a manner requiring permission\n   under the Copyright and Similar Rights held by the Licensor. For\n   purposes of this Public License, where the Licensed Material is a\n   musical work, performance, or sound recording, Adapted Material is\n   always produced where the Licensed Material is synched in timed\n   relation with a moving image.\n\nb. **Adapter's License** means the license You apply to Your Copyright\n   and Similar Rights in Your contributions to Adapted Material in\n   accordance with the terms and conditions of this Public License.\n\nc. **Copyright and Similar Rights** means copyright and/or similar\n   rights closely related to copyright including, without limitation,\n   performance, broadcast, sound recording, and Sui Generis Database\n   Rights, without regard to how the rights are labeled or categorized.\n   For purposes of this Public License, the rights specified in Section\n   2(b)(1)-(2) are not Copyright and Similar Rights.\n\nd. **Effective Technological Measures** means those measures that, in\n   the absence of proper authority, may not be circumvented under laws\n   fulfilling obligations under Article 11 of the WIPO Copyright Treaty\n   adopted on December 20, 1996, and/or similar international\n   agreements.\n\ne. **Exceptions and Limitations** means fair use, fair dealing, and/or\n   any other exception or limitation to Copyright and Similar Rights\n   that applies to Your use of the Licensed Material.\n\nf. **Licensed Material** means the artistic or literary work, database,\n   or other material to which the Licensor applied this Public License.\n\ng. **Licensed Rights** means the rights granted to You subject to the\n   terms and conditions of this Public License, which are limited to all\n   Copyright and Similar Rights that apply to Your use of the Licensed\n   Material and that the Licensor has authority to license.\n\nh. **Licensor** means the individual(s) or entity(ies) granting rights\n   under this Public License.\n\ni. **Share** means to provide material to the public by any means or\n   process that requires permission under the Licensed Rights, such as\n   reproduction, public display, public performance, distribution,\n   dissemination, communication, or importation, and to make material\n   available to the public including in ways that members of the public\n   may access the material from a place and at a time individually\n   chosen by them.\n\nj. **Sui Generis Database Rights** means rights other than copyright\n   resulting from Directive 96/9/EC of the European Parliament and of\n   the Council of 11 March 1996 on the legal protection of databases, as\n   amended and/or succeeded, as well as other essentially equivalent\n   rights anywhere in the world.\n\nk. **You** means the individual or entity exercising the Licensed Rights\n   under this Public License. Your has a corresponding meaning.\n\nSection 2 – Scope\n~~~~~~~~~~~~~~~~~\n\na. **License grant.**\n\n1. Subject to the terms and conditions of this Public License, the\n   Licensor hereby grants You a worldwide, royalty-free,\n   non-sublicensable, non-exclusive, irrevocable license to exercise the\n   Licensed Rights in the Licensed Material to:\n\n   A. reproduce and Share the Licensed Material, in whole or in part;\n   and\n\n   B. produce, reproduce, and Share Adapted Material.\n\n2. **Exceptions and Limitations.** For the avoidance of doubt, where\n   Exceptions and Limitations apply to Your use, this Public License\n   does not apply, and You do not need to comply with its terms and\n   conditions.\n\n3. **Term.** The term of this Public License is specified in Section\n   6(a).\n\n4. **Media and formats; technical modifications allowed.** The Licensor\n   authorizes You to exercise the Licensed Rights in all media and\n   formats whether now known or hereafter created, and to make technical\n   modifications necessary to do so. The Licensor waives and/or agrees\n   not to assert any right or authority to forbid You from making\n   technical modifications necessary to exercise the Licensed Rights,\n   including technical modifications necessary to circumvent Effective\n   Technological Measures. For purposes of this Public License, simply\n   making modifications authorized by this Section 2(a)(4) never\n   produces Adapted Material.\n\n5. **Downstream recipients.**\n\n   A. **Offer from the Licensor – Licensed Material.** Every recipient\n   of the Licensed Material automatically receives an offer from the\n   Licensor to exercise the Licensed Rights under the terms and\n   conditions of this Public License.\n\n   B. **No downstream restrictions.** You may not offer or impose any\n   additional or different terms or conditions on, or apply any\n   Effective Technological Measures to, the Licensed Material if doing\n   so restricts exercise of the Licensed Rights by any recipient of the\n   Licensed Material.\n\n6. **No endorsement.** Nothing in this Public License constitutes or may\n   be construed as permission to assert or imply that You are, or that\n   Your use of the Licensed Material is, connected with, or sponsored,\n   endorsed, or granted official status by, the Licensor or others\n   designated to receive attribution as provided in Section\n   3(a)(1)(A)(i).\n\nb. **Other rights.**\n\n1. Moral rights, such as the right of integrity, are not licensed under\n   this Public License, nor are publicity, privacy, and/or other similar\n   personality rights; however, to the extent possible, the Licensor\n   waives and/or agrees not to assert any such rights held by the\n   Licensor to the limited extent necessary to allow You to exercise the\n   Licensed Rights, but not otherwise.\n\n2. Patent and trademark rights are not licensed under this Public\n   License.\n\n3. To the extent possible, the Licensor waives any right to collect\n   royalties from You for the exercise of the Licensed Rights, whether\n   directly or through a collecting society under any voluntary or\n   waivable statutory or compulsory licensing scheme. In all other cases\n   the Licensor expressly reserves any right to collect such royalties.\n\nSection 3 – License Conditions\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nYour exercise of the Licensed Rights is expressly made subject to the\nfollowing conditions.\n\na. **Attribution.**\n\n1. If You Share the Licensed Material (including in modified form), You\n   must:\n\n   A. retain the following if it is supplied by the Licensor with the\n   Licensed Material:\n\n        i. identification of the creator(s) of the Licensed Material and any\n           others designated to receive attribution, in any reasonable manner\n           requested by the Licensor (including by pseudonym if designated);\n\n        ii. a copyright notice;\n\n        iii. a notice that refers to this Public License;\n\n        iv. a notice that refers to the disclaimer of warranties;\n\n        v. a URI or hyperlink to the Licensed Material to the extent reasonably practicable;\n\n   B. indicate if You modified the Licensed Material and retain an\n   indication of any previous modifications; and\n\n   C. indicate the Licensed Material is licensed under this Public\n   License, and include the text of, or the URI or hyperlink to, this\n   Public License.\n\n2. You may satisfy the conditions in Section 3(a)(1) in any reasonable\n   manner based on the medium, means, and context in which You Share the\n   Licensed Material. For example, it may be reasonable to satisfy the\n   conditions by providing a URI or hyperlink to a resource that\n   includes the required information.\n\n3. If requested by the Licensor, You must remove any of the information\n   required by Section 3(a)(1)(A) to the extent reasonably practicable.\n\n4. If You Share Adapted Material You produce, the Adapter's License You\n   apply must not prevent recipients of the Adapted Material from\n   complying with this Public License.\n\nSection 4 – Sui Generis Database Rights\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nWhere the Licensed Rights include Sui Generis Database Rights that apply\nto Your use of the Licensed Material:\n\na. for the avoidance of doubt, Section 2(a)(1) grants You the right to\n   extract, reuse, reproduce, and Share all or a substantial portion of\n   the contents of the database;\n\nb. if You include all or a substantial portion of the database contents\n   in a database in which You have Sui Generis Database Rights, then the\n   database in which You have Sui Generis Database Rights (but not its\n   individual contents) is Adapted Material; and\n\nc. You must comply with the conditions in Section 3(a) if You Share all\n   or a substantial portion of the contents of the database.\n\nFor the avoidance of doubt, this Section 4 supplements and does not\nreplace Your obligations under this Public License where the Licensed\nRights include other Copyright and Similar Rights.\n\nSection 5 – Disclaimer of Warranties and Limitation of Liability\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\na. Unless otherwise separately undertaken by the Licensor, to the\n   extent possible, the Licensor offers the Licensed Material as-is and\n   as-available, and makes no representations or warranties of any kind\n   concerning the Licensed Material, whether express, implied,\n   statutory, or other. This includes, without limitation, warranties of\n   title, merchantability, fitness for a particular purpose,\n   non-infringement, absence of latent or other defects, accuracy, or\n   the presence or absence of errors, whether or not known or\n   discoverable. Where disclaimers of warranties are not allowed in full\n   or in part, this disclaimer may not apply to You.\n\nb. To the extent possible, in no event will the Licensor be liable to\n   You on any legal theory (including, without limitation, negligence)\n   or otherwise for any direct, special, indirect, incidental,\n   consequential, punitive, exemplary, or other losses, costs, expenses,\n   or damages arising out of this Public License or use of the Licensed\n   Material, even if the Licensor has been advised of the possibility of\n   such losses, costs, expenses, or damages. Where a limitation of\n   liability is not allowed in full or in part, this limitation may not\n   apply to You.\n\nc. The disclaimer of warranties and limitation of liability provided\n   above shall be interpreted in a manner that, to the extent possible,\n   most closely approximates an absolute disclaimer and waiver of all\n   liability.\n\nSection 6 – Term and Termination\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\na. This Public License applies for the term of the Copyright and Similar\n   Rights licensed here. However, if You fail to comply with this Public\n   License, then Your rights under this Public License terminate\n   automatically.\n\nb. Where Your right to use the Licensed Material has terminated under\n   Section 6(a), it reinstates:\n\n1. automatically as of the date the violation is cured, provided it is\n   cured within 30 days of Your discovery of the violation; or\n\n2. upon express reinstatement by the Licensor.\n\nFor the avoidance of doubt, this Section 6(b) does not affect any right\nthe Licensor may have to seek remedies for Your violations of this\nPublic License.\n\nc. For the avoidance of doubt, the Licensor may also offer the Licensed\n   Material under separate terms or conditions or stop distributing the\n   Licensed Material at any time; however, doing so will not terminate\n   this Public License.\n\nd. Sections 1, 5, 6, 7, and 8 survive termination of this Public\n   License.\n\nSection 7 – Other Terms and Conditions\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\na. The Licensor shall not be bound by any additional or different terms\n   or conditions communicated by You unless expressly agreed.\n\nb. Any arrangements, understandings, or agreements regarding the\n   Licensed Material not stated herein are separate from and independent\n   of the terms and conditions of this Public License.\n\nSection 8 – Interpretation\n~~~~~~~~~~~~~~~~~~~~~~~~~~\n\na. For the avoidance of doubt, this Public License does not, and shall\n   not be interpreted to, reduce, limit, restrict, or impose conditions\n   on any use of the Licensed Material that could lawfully be made\n   without permission under this Public License.\n\nb. To the extent possible, if any provision of this Public License is\n   deemed unenforceable, it shall be automatically reformed to the\n   minimum extent necessary to make it enforceable. If the provision\n   cannot be reformed, it shall be severed from this Public License\n   without affecting the enforceability of the remaining terms and\n   conditions.\n\nc. No term or condition of this Public License will be waived and no\n   failure to comply consented to unless expressly agreed to by the\n   Licensor.\n\nd. Nothing in this Public License constitutes or may be interpreted as a\n   limitation upon, or waiver of, any privileges and immunities that\n   apply to the Licensor or You, including from the legal processes of\n   any jurisdiction or authority.\n\n    Creative Commons is not a party to its public licenses.\n    Notwithstanding, Creative Commons may elect to apply one of its\n    public licenses to material it publishes and in those instances will\n    be considered the “Licensor.” Except for the limited purpose of\n    indicating that material is shared under a Creative Commons public\n    license or as otherwise permitted by the Creative Commons policies\n    published at\n    `creativecommons.org/policies <http://creativecommons.org/policies>`__,\n    Creative Commons does not authorize the use of the trademark\n    “Creative Commons” or any other trademark or logo of Creative\n    Commons without its prior written consent including, without\n    limitation, in connection with any unauthorized modifications to any\n    of its public licenses or any other arrangements, understandings, or\n    agreements concerning use of licensed material. For the avoidance of\n    doubt, this paragraph does not form part of the public licenses.\n\n    Creative Commons may be contacted at creativecommons.org\n"
  },
  {
    "path": "resources/dark/rc/.keep",
    "content": " \n"
  },
  {
    "path": "resources/dark/style.qrc",
    "content": "\n<RCC warning=\"WARNING! File created programmatically. All changes made in this file will be lost!\">\n  <qresource prefix=\"dark\">\n    <file>rc/.keep</file>\n    <file>rc/arrow_down.png</file>\n    <file>rc/arrow_down@2x.png</file>\n    <file>rc/arrow_down_disabled.png</file>\n    <file>rc/arrow_down_disabled@2x.png</file>\n    <file>rc/arrow_down_focus.png</file>\n    <file>rc/arrow_down_focus@2x.png</file>\n    <file>rc/arrow_down_pressed.png</file>\n    <file>rc/arrow_down_pressed@2x.png</file>\n    <file>rc/arrow_left.png</file>\n    <file>rc/arrow_left@2x.png</file>\n    <file>rc/arrow_left_disabled.png</file>\n    <file>rc/arrow_left_disabled@2x.png</file>\n    <file>rc/arrow_left_focus.png</file>\n    <file>rc/arrow_left_focus@2x.png</file>\n    <file>rc/arrow_left_pressed.png</file>\n    <file>rc/arrow_left_pressed@2x.png</file>\n    <file>rc/arrow_right.png</file>\n    <file>rc/arrow_right@2x.png</file>\n    <file>rc/arrow_right_disabled.png</file>\n    <file>rc/arrow_right_disabled@2x.png</file>\n    <file>rc/arrow_right_focus.png</file>\n    <file>rc/arrow_right_focus@2x.png</file>\n    <file>rc/arrow_right_pressed.png</file>\n    <file>rc/arrow_right_pressed@2x.png</file>\n    <file>rc/arrow_up.png</file>\n    <file>rc/arrow_up@2x.png</file>\n    <file>rc/arrow_up_disabled.png</file>\n    <file>rc/arrow_up_disabled@2x.png</file>\n    <file>rc/arrow_up_focus.png</file>\n    <file>rc/arrow_up_focus@2x.png</file>\n    <file>rc/arrow_up_pressed.png</file>\n    <file>rc/arrow_up_pressed@2x.png</file>\n    <file>rc/base_icon.png</file>\n    <file>rc/base_icon@2x.png</file>\n    <file>rc/base_icon_disabled.png</file>\n    <file>rc/base_icon_disabled@2x.png</file>\n    <file>rc/base_icon_focus.png</file>\n    <file>rc/base_icon_focus@2x.png</file>\n    <file>rc/base_icon_pressed.png</file>\n    <file>rc/base_icon_pressed@2x.png</file>\n    <file>rc/branch_closed.png</file>\n    <file>rc/branch_closed@2x.png</file>\n    <file>rc/branch_closed_disabled.png</file>\n    <file>rc/branch_closed_disabled@2x.png</file>\n    <file>rc/branch_closed_focus.png</file>\n    <file>rc/branch_closed_focus@2x.png</file>\n    <file>rc/branch_closed_pressed.png</file>\n    <file>rc/branch_closed_pressed@2x.png</file>\n    <file>rc/branch_end.png</file>\n    <file>rc/branch_end@2x.png</file>\n    <file>rc/branch_end_disabled.png</file>\n    <file>rc/branch_end_disabled@2x.png</file>\n    <file>rc/branch_end_focus.png</file>\n    <file>rc/branch_end_focus@2x.png</file>\n    <file>rc/branch_end_pressed.png</file>\n    <file>rc/branch_end_pressed@2x.png</file>\n    <file>rc/branch_line.png</file>\n    <file>rc/branch_line@2x.png</file>\n    <file>rc/branch_line_disabled.png</file>\n    <file>rc/branch_line_disabled@2x.png</file>\n    <file>rc/branch_line_focus.png</file>\n    <file>rc/branch_line_focus@2x.png</file>\n    <file>rc/branch_line_pressed.png</file>\n    <file>rc/branch_line_pressed@2x.png</file>\n    <file>rc/branch_more.png</file>\n    <file>rc/branch_more@2x.png</file>\n    <file>rc/branch_more_disabled.png</file>\n    <file>rc/branch_more_disabled@2x.png</file>\n    <file>rc/branch_more_focus.png</file>\n    <file>rc/branch_more_focus@2x.png</file>\n    <file>rc/branch_more_pressed.png</file>\n    <file>rc/branch_more_pressed@2x.png</file>\n    <file>rc/branch_open.png</file>\n    <file>rc/branch_open@2x.png</file>\n    <file>rc/branch_open_disabled.png</file>\n    <file>rc/branch_open_disabled@2x.png</file>\n    <file>rc/branch_open_focus.png</file>\n    <file>rc/branch_open_focus@2x.png</file>\n    <file>rc/branch_open_pressed.png</file>\n    <file>rc/branch_open_pressed@2x.png</file>\n    <file>rc/checkbox_checked.png</file>\n    <file>rc/checkbox_checked@2x.png</file>\n    <file>rc/checkbox_checked_disabled.png</file>\n    <file>rc/checkbox_checked_disabled@2x.png</file>\n    <file>rc/checkbox_checked_focus.png</file>\n    <file>rc/checkbox_checked_focus@2x.png</file>\n    <file>rc/checkbox_checked_pressed.png</file>\n    <file>rc/checkbox_checked_pressed@2x.png</file>\n    <file>rc/checkbox_indeterminate.png</file>\n    <file>rc/checkbox_indeterminate@2x.png</file>\n    <file>rc/checkbox_indeterminate_disabled.png</file>\n    <file>rc/checkbox_indeterminate_disabled@2x.png</file>\n    <file>rc/checkbox_indeterminate_focus.png</file>\n    <file>rc/checkbox_indeterminate_focus@2x.png</file>\n    <file>rc/checkbox_indeterminate_pressed.png</file>\n    <file>rc/checkbox_indeterminate_pressed@2x.png</file>\n    <file>rc/checkbox_unchecked.png</file>\n    <file>rc/checkbox_unchecked@2x.png</file>\n    <file>rc/checkbox_unchecked_disabled.png</file>\n    <file>rc/checkbox_unchecked_disabled@2x.png</file>\n    <file>rc/checkbox_unchecked_focus.png</file>\n    <file>rc/checkbox_unchecked_focus@2x.png</file>\n    <file>rc/checkbox_unchecked_pressed.png</file>\n    <file>rc/checkbox_unchecked_pressed@2x.png</file>\n    <file>rc/line_horizontal.png</file>\n    <file>rc/line_horizontal@2x.png</file>\n    <file>rc/line_horizontal_disabled.png</file>\n    <file>rc/line_horizontal_disabled@2x.png</file>\n    <file>rc/line_horizontal_focus.png</file>\n    <file>rc/line_horizontal_focus@2x.png</file>\n    <file>rc/line_horizontal_pressed.png</file>\n    <file>rc/line_horizontal_pressed@2x.png</file>\n    <file>rc/line_vertical.png</file>\n    <file>rc/line_vertical@2x.png</file>\n    <file>rc/line_vertical_disabled.png</file>\n    <file>rc/line_vertical_disabled@2x.png</file>\n    <file>rc/line_vertical_focus.png</file>\n    <file>rc/line_vertical_focus@2x.png</file>\n    <file>rc/line_vertical_pressed.png</file>\n    <file>rc/line_vertical_pressed@2x.png</file>\n    <file>rc/radio_checked.png</file>\n    <file>rc/radio_checked@2x.png</file>\n    <file>rc/radio_checked_disabled.png</file>\n    <file>rc/radio_checked_disabled@2x.png</file>\n    <file>rc/radio_checked_focus.png</file>\n    <file>rc/radio_checked_focus@2x.png</file>\n    <file>rc/radio_checked_pressed.png</file>\n    <file>rc/radio_checked_pressed@2x.png</file>\n    <file>rc/radio_unchecked.png</file>\n    <file>rc/radio_unchecked@2x.png</file>\n    <file>rc/radio_unchecked_disabled.png</file>\n    <file>rc/radio_unchecked_disabled@2x.png</file>\n    <file>rc/radio_unchecked_focus.png</file>\n    <file>rc/radio_unchecked_focus@2x.png</file>\n    <file>rc/radio_unchecked_pressed.png</file>\n    <file>rc/radio_unchecked_pressed@2x.png</file>\n    <file>rc/toolbar_move_horizontal.png</file>\n    <file>rc/toolbar_move_horizontal@2x.png</file>\n    <file>rc/toolbar_move_horizontal_disabled.png</file>\n    <file>rc/toolbar_move_horizontal_disabled@2x.png</file>\n    <file>rc/toolbar_move_horizontal_focus.png</file>\n    <file>rc/toolbar_move_horizontal_focus@2x.png</file>\n    <file>rc/toolbar_move_horizontal_pressed.png</file>\n    <file>rc/toolbar_move_horizontal_pressed@2x.png</file>\n    <file>rc/toolbar_move_vertical.png</file>\n    <file>rc/toolbar_move_vertical@2x.png</file>\n    <file>rc/toolbar_move_vertical_disabled.png</file>\n    <file>rc/toolbar_move_vertical_disabled@2x.png</file>\n    <file>rc/toolbar_move_vertical_focus.png</file>\n    <file>rc/toolbar_move_vertical_focus@2x.png</file>\n    <file>rc/toolbar_move_vertical_pressed.png</file>\n    <file>rc/toolbar_move_vertical_pressed@2x.png</file>\n    <file>rc/toolbar_separator_horizontal.png</file>\n    <file>rc/toolbar_separator_horizontal@2x.png</file>\n    <file>rc/toolbar_separator_horizontal_disabled.png</file>\n    <file>rc/toolbar_separator_horizontal_disabled@2x.png</file>\n    <file>rc/toolbar_separator_horizontal_focus.png</file>\n    <file>rc/toolbar_separator_horizontal_focus@2x.png</file>\n    <file>rc/toolbar_separator_horizontal_pressed.png</file>\n    <file>rc/toolbar_separator_horizontal_pressed@2x.png</file>\n    <file>rc/toolbar_separator_vertical.png</file>\n    <file>rc/toolbar_separator_vertical@2x.png</file>\n    <file>rc/toolbar_separator_vertical_disabled.png</file>\n    <file>rc/toolbar_separator_vertical_disabled@2x.png</file>\n    <file>rc/toolbar_separator_vertical_focus.png</file>\n    <file>rc/toolbar_separator_vertical_focus@2x.png</file>\n    <file>rc/toolbar_separator_vertical_pressed.png</file>\n    <file>rc/toolbar_separator_vertical_pressed@2x.png</file>\n    <file>rc/transparent.png</file>\n    <file>rc/transparent@2x.png</file>\n    <file>rc/transparent_disabled.png</file>\n    <file>rc/transparent_disabled@2x.png</file>\n    <file>rc/transparent_focus.png</file>\n    <file>rc/transparent_focus@2x.png</file>\n    <file>rc/transparent_pressed.png</file>\n    <file>rc/transparent_pressed@2x.png</file>\n    <file>rc/window_close.png</file>\n    <file>rc/window_close@2x.png</file>\n    <file>rc/window_close_disabled.png</file>\n    <file>rc/window_close_disabled@2x.png</file>\n    <file>rc/window_close_focus.png</file>\n    <file>rc/window_close_focus@2x.png</file>\n    <file>rc/window_close_pressed.png</file>\n    <file>rc/window_close_pressed@2x.png</file>\n    <file>rc/window_grip.png</file>\n    <file>rc/window_grip@2x.png</file>\n    <file>rc/window_grip_disabled.png</file>\n    <file>rc/window_grip_disabled@2x.png</file>\n    <file>rc/window_grip_focus.png</file>\n    <file>rc/window_grip_focus@2x.png</file>\n    <file>rc/window_grip_pressed.png</file>\n    <file>rc/window_grip_pressed@2x.png</file>\n    <file>rc/window_minimize.png</file>\n    <file>rc/window_minimize@2x.png</file>\n    <file>rc/window_minimize_disabled.png</file>\n    <file>rc/window_minimize_disabled@2x.png</file>\n    <file>rc/window_minimize_focus.png</file>\n    <file>rc/window_minimize_focus@2x.png</file>\n    <file>rc/window_minimize_pressed.png</file>\n    <file>rc/window_minimize_pressed@2x.png</file>\n    <file>rc/window_undock.png</file>\n    <file>rc/window_undock@2x.png</file>\n    <file>rc/window_undock_disabled.png</file>\n    <file>rc/window_undock_disabled@2x.png</file>\n    <file>rc/window_undock_focus.png</file>\n    <file>rc/window_undock_focus@2x.png</file>\n    <file>rc/window_undock_pressed.png</file>\n    <file>rc/window_undock_pressed@2x.png</file>\n  </qresource>\n  <qresource prefix=\"dark\">\n      <file>style.qss</file>\n  </qresource>\n</RCC>\n"
  },
  {
    "path": "resources/dark/style.qss",
    "content": "/* Modified for VapourSynth Editor */\n\n/* ---------------------------------------------------------------------------\n\n    WARNING! File created programmatically. All changes made in this file will be lost!\n\n    Created by the qtsass compiler v0.3.0\n\n    The definitions are in the \"qdarkstyle.qss._styles.scss\" module\n\n--------------------------------------------------------------------------- */\n/* Light Style - QDarkStyleSheet ------------------------------------------ */\n/*\n\nSee Qt documentation:\n\n  - https://doc.qt.io/qt-5/stylesheet.html\n  - https://doc.qt.io/qt-5/stylesheet-reference.html\n  - https://doc.qt.io/qt-5/stylesheet-examples.html\n\n--------------------------------------------------------------------------- */\n/* Reset elements ------------------------------------------------------------\n\nResetting everything helps to unify styles across different operating systems\n\n--------------------------------------------------------------------------- */\n* {\n  padding: 0px;\n  margin: 0px;\n  border: 0px;\n  border-style: none;\n  border-image: none;\n  outline: 0;\n}\n\n/* specific reset for elements inside QToolBar */\nQToolBar * {\n  margin: 0px;\n  padding: 0px;\n}\n\n/* QWidget ----------------------------------------------------------------\n\n--------------------------------------------------------------------------- */\nQWidget {\n  background-color: #19232D;\n  border: 0px solid #455364;\n  padding: 0px;\n  color: #E0E1E3;\n  selection-background-color: #346792;\n  selection-color: #E0E1E3;\n}\n\nQWidget:disabled {\n  background-color: #19232D;\n  color: #9DA9B5;\n  selection-background-color: #26486B;\n  selection-color: #9DA9B5;\n}\n\nQWidget::item:selected {\n  background-color: #346792;\n}\n\nQWidget::item:hover:!selected {\n  background-color: #1A72BB;\n}\n\n/* QMainWindow ------------------------------------------------------------\n\nThis adjusts the splitter in the dock widget, not qsplitter\nhttps://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qmainwindow\n\n--------------------------------------------------------------------------- */\nQMainWindow::separator {\n  background-color: #455364;\n  border: 0px solid #19232D;\n  spacing: 0px;\n  padding: 2px;\n}\n\nQMainWindow::separator:hover {\n  background-color: #60798B;\n  border: 0px solid #1A72BB;\n}\n\nQMainWindow::separator:horizontal {\n  width: 5px;\n  margin-top: 2px;\n  margin-bottom: 2px;\n  image: url(\":/dark/rc/toolbar_separator_vertical.png\");\n}\n\nQMainWindow::separator:vertical {\n  height: 5px;\n  margin-left: 2px;\n  margin-right: 2px;\n  image: url(\":/dark/rc/toolbar_separator_horizontal.png\");\n}\n\n/* QToolTip ---------------------------------------------------------------\n\nhttps://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qtooltip\n\n--------------------------------------------------------------------------- */\nQToolTip {\n  background-color: #346792;\n  color: #E0E1E3;\n  /* If you remove the border property, background stops working on Windows */\n  border: none;\n  /* Remove padding, for fix combo box tooltip */\n  padding: 0px;\n  /* Remove opacity, fix #174 - may need to use RGBA */\n  font-kerning: none;\n}\n\n/* QStatusBar -------------------------------------------------------------\n\nhttps://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qstatusbar\n\n--------------------------------------------------------------------------- */\nQStatusBar {\n  border: 1px solid #455364;\n  /* Fixes Spyder #9120, #9121 */\n  background: #455364;\n  /* Fixes #205, white vertical borders separating items */\n}\n\nQStatusBar::item {\n  border: none;\n}\n\nQStatusBar QToolTip {\n  background-color: #1A72BB;\n  border: 1px solid #19232D;\n  color: #19232D;\n  /* Remove padding, for fix combo box tooltip */\n  padding: 0px;\n  /* Reducing transparency to read better */\n  opacity: 230;\n}\n\nQStatusBar QLabel {\n  /* Fixes Spyder #9120, #9121 */\n  background: transparent;\n}\n\n/* QCheckBox --------------------------------------------------------------\n\nhttps://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qcheckbox\n\n--------------------------------------------------------------------------- */\nQCheckBox {\n  background-color: #19232D;\n  color: #E0E1E3;\n  spacing: 4px;\n  outline: none;\n  padding-top: 4px;\n  padding-bottom: 4px;\n}\n\nQCheckBox:focus {\n  border: none;\n}\n\nQCheckBox QWidget:disabled {\n  background-color: #19232D;\n  color: #9DA9B5;\n}\n\nQCheckBox::indicator {\n  margin-left: 2px;\n  height: 14px;\n  width: 14px;\n}\n\nQCheckBox::indicator:unchecked {\n  image: url(\":/dark/rc/checkbox_unchecked.png\");\n}\n\nQCheckBox::indicator:unchecked:hover, QCheckBox::indicator:unchecked:focus, QCheckBox::indicator:unchecked:pressed {\n  border: none;\n  image: url(\":/dark/rc/checkbox_unchecked_focus.png\");\n}\n\nQCheckBox::indicator:unchecked:disabled {\n  image: url(\":/dark/rc/checkbox_unchecked_disabled.png\");\n}\n\nQCheckBox::indicator:checked {\n  image: url(\":/dark/rc/checkbox_checked.png\");\n}\n\nQCheckBox::indicator:checked:hover, QCheckBox::indicator:checked:focus, QCheckBox::indicator:checked:pressed {\n  border: none;\n  image: url(\":/dark/rc/checkbox_checked_focus.png\");\n}\n\nQCheckBox::indicator:checked:disabled {\n  image: url(\":/dark/rc/checkbox_checked_disabled.png\");\n}\n\nQCheckBox::indicator:indeterminate {\n  image: url(\":/dark/rc/checkbox_indeterminate.png\");\n}\n\nQCheckBox::indicator:indeterminate:disabled {\n  image: url(\":/dark/rc/checkbox_indeterminate_disabled.png\");\n}\n\nQCheckBox::indicator:indeterminate:focus, QCheckBox::indicator:indeterminate:hover, QCheckBox::indicator:indeterminate:pressed {\n  image: url(\":/dark/rc/checkbox_indeterminate_focus.png\");\n}\n\n/* QGroupBox --------------------------------------------------------------\n\nhttps://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qgroupbox\n\n--------------------------------------------------------------------------- */\nQGroupBox {\n  font-weight: bold;\n  border: 1px solid #455364;\n  border-radius: 4px;\n  padding: 2px;\n  margin-top: 16px; /* was 6px */\n  margin-bottom: 4px;\n}\n\nQGroupBox::title {\n  subcontrol-origin: margin;\n  subcontrol-position: top left;\n  left: 4px;\n  top: 2px; /* was not specified */\n  bottom: 2px; /* was not specified */\n  padding-left: 2px;\n  padding-right: 4px;\n  padding-top: -4px;\n}\n\nQGroupBox::indicator {\n  margin-left: 2px;\n  margin-top: 2px;\n  padding: 0;\n  height: 14px;\n  width: 14px;\n}\n\nQGroupBox::indicator:unchecked {\n  border: none;\n  image: url(\":/dark/rc/checkbox_unchecked.png\");\n}\n\nQGroupBox::indicator:unchecked:hover, QGroupBox::indicator:unchecked:focus, QGroupBox::indicator:unchecked:pressed {\n  border: none;\n  image: url(\":/dark/rc/checkbox_unchecked_focus.png\");\n}\n\nQGroupBox::indicator:unchecked:disabled {\n  image: url(\":/dark/rc/checkbox_unchecked_disabled.png\");\n}\n\nQGroupBox::indicator:checked {\n  border: none;\n  image: url(\":/dark/rc/checkbox_checked.png\");\n}\n\nQGroupBox::indicator:checked:hover, QGroupBox::indicator:checked:focus, QGroupBox::indicator:checked:pressed {\n  border: none;\n  image: url(\":/dark/rc/checkbox_checked_focus.png\");\n}\n\nQGroupBox::indicator:checked:disabled {\n  image: url(\":/dark/rc/checkbox_checked_disabled.png\");\n}\n\n/* QRadioButton -----------------------------------------------------------\n\nhttps://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qradiobutton\n\n--------------------------------------------------------------------------- */\nQRadioButton {\n  background-color: #19232D;\n  color: #E0E1E3;\n  spacing: 4px;\n  padding-top: 4px;\n  padding-bottom: 4px;\n  border: none;\n  outline: none;\n}\n\nQRadioButton:focus {\n  border: none;\n}\n\nQRadioButton:disabled {\n  background-color: #19232D;\n  color: #9DA9B5;\n  border: none;\n  outline: none;\n}\n\nQRadioButton QWidget {\n  background-color: #19232D;\n  color: #E0E1E3;\n  spacing: 0px;\n  padding: 0px;\n  outline: none;\n  border: none;\n}\n\nQRadioButton::indicator {\n  border: none;\n  outline: none;\n  margin-left: 2px;\n  height: 14px;\n  width: 14px;\n}\n\nQRadioButton::indicator:unchecked {\n  image: url(\":/dark/rc/radio_unchecked.png\");\n}\n\nQRadioButton::indicator:unchecked:hover, QRadioButton::indicator:unchecked:focus, QRadioButton::indicator:unchecked:pressed {\n  border: none;\n  outline: none;\n  image: url(\":/dark/rc/radio_unchecked_focus.png\");\n}\n\nQRadioButton::indicator:unchecked:disabled {\n  image: url(\":/dark/rc/radio_unchecked_disabled.png\");\n}\n\nQRadioButton::indicator:checked {\n  border: none;\n  outline: none;\n  image: url(\":/dark/rc/radio_checked.png\");\n}\n\nQRadioButton::indicator:checked:hover, QRadioButton::indicator:checked:focus, QRadioButton::indicator:checked:pressed {\n  border: none;\n  outline: none;\n  image: url(\":/dark/rc/radio_checked_focus.png\");\n}\n\nQRadioButton::indicator:checked:disabled {\n  outline: none;\n  image: url(\":/dark/rc/radio_checked_disabled.png\");\n}\n\n/* QMenuBar ---------------------------------------------------------------\n\nhttps://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qmenubar\n\n--------------------------------------------------------------------------- */\nQMenuBar {\n  background-color: #455364;\n  padding: 2px;\n  border: 1px solid #19232D;\n  color: #E0E1E3;\n  selection-background-color: #1A72BB;\n}\n\nQMenuBar:focus {\n  border: 1px solid #346792;\n}\n\nQMenuBar::item {\n  background: transparent;\n  padding: 4px;\n}\n\nQMenuBar::item:selected {\n  padding: 4px;\n  background: transparent;\n  border: 0px solid #455364;\n  background-color: #1A72BB;\n}\n\nQMenuBar::item:pressed {\n  padding: 4px;\n  border: 0px solid #455364;\n  background-color: #1A72BB;\n  color: #E0E1E3;\n  margin-bottom: 0px;\n  padding-bottom: 0px;\n}\n\n/* QMenu ------------------------------------------------------------------\n\nhttps://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qmenu\n\n--------------------------------------------------------------------------- */\nQMenu {\n  border: 0px solid #455364;\n  color: #E0E1E3;\n  margin: 0px;\n  background-color: #37414F;\n  selection-background-color: #1A72BB;\n}\n\nQMenu::separator {\n  height: 1px;\n  background-color: #60798B;\n  color: #E0E1E3;\n}\n\nQMenu::item {\n  background-color: #37414F;\n  padding: 4px 24px 4px 28px;\n  /* Reserve space for selection border */\n  border: 1px transparent #455364;\n}\n\nQMenu::item:selected {\n  color: #E0E1E3;\n  background-color: #1A72BB;\n}\n\nQMenu::item:pressed {\n  background-color: #1A72BB;\n}\n\nQMenu::icon {\n  padding-left: 10px;\n  width: 14px;\n  height: 14px;\n}\n\nQMenu::indicator {\n  padding-left: 8px;\n  width: 12px;\n  height: 12px;\n  /* non-exclusive indicator = check box style indicator (see QActionGroup::setExclusive) */\n  /* exclusive indicator = radio button style indicator (see QActionGroup::setExclusive) */\n}\n\nQMenu::indicator:non-exclusive:unchecked {\n  image: url(\":/dark/rc/checkbox_unchecked.png\");\n}\n\nQMenu::indicator:non-exclusive:unchecked:hover, QMenu::indicator:non-exclusive:unchecked:focus, QMenu::indicator:non-exclusive:unchecked:pressed {\n  border: none;\n  image: url(\":/dark/rc/checkbox_unchecked_focus.png\");\n}\n\nQMenu::indicator:non-exclusive:unchecked:disabled {\n  image: url(\":/dark/rc/checkbox_unchecked_disabled.png\");\n}\n\nQMenu::indicator:non-exclusive:checked {\n  image: url(\":/dark/rc/checkbox_checked.png\");\n}\n\nQMenu::indicator:non-exclusive:checked:hover, QMenu::indicator:non-exclusive:checked:focus, QMenu::indicator:non-exclusive:checked:pressed {\n  border: none;\n  image: url(\":/dark/rc/checkbox_checked_focus.png\");\n}\n\nQMenu::indicator:non-exclusive:checked:disabled {\n  image: url(\":/dark/rc/checkbox_checked_disabled.png\");\n}\n\nQMenu::indicator:non-exclusive:indeterminate {\n  image: url(\":/dark/rc/checkbox_indeterminate.png\");\n}\n\nQMenu::indicator:non-exclusive:indeterminate:disabled {\n  image: url(\":/dark/rc/checkbox_indeterminate_disabled.png\");\n}\n\nQMenu::indicator:non-exclusive:indeterminate:focus, QMenu::indicator:non-exclusive:indeterminate:hover, QMenu::indicator:non-exclusive:indeterminate:pressed {\n  image: url(\":/dark/rc/checkbox_indeterminate_focus.png\");\n}\n\nQMenu::indicator:exclusive:unchecked {\n  image: url(\":/dark/rc/radio_unchecked.png\");\n}\n\nQMenu::indicator:exclusive:unchecked:hover, QMenu::indicator:exclusive:unchecked:focus, QMenu::indicator:exclusive:unchecked:pressed {\n  border: none;\n  outline: none;\n  image: url(\":/dark/rc/radio_unchecked_focus.png\");\n}\n\nQMenu::indicator:exclusive:unchecked:disabled {\n  image: url(\":/dark/rc/radio_unchecked_disabled.png\");\n}\n\nQMenu::indicator:exclusive:checked {\n  border: none;\n  outline: none;\n  image: url(\":/dark/rc/radio_checked.png\");\n}\n\nQMenu::indicator:exclusive:checked:hover, QMenu::indicator:exclusive:checked:focus, QMenu::indicator:exclusive:checked:pressed {\n  border: none;\n  outline: none;\n  image: url(\":/dark/rc/radio_checked_focus.png\");\n}\n\nQMenu::indicator:exclusive:checked:disabled {\n  outline: none;\n  image: url(\":/dark/rc/radio_checked_disabled.png\");\n}\n\nQMenu::right-arrow {\n  margin: 5px;\n  padding-left: 12px;\n  image: url(\":/dark/rc/arrow_right.png\");\n  height: 12px;\n  width: 12px;\n}\n\n/* QAbstractItemView ------------------------------------------------------\n\nhttps://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qcombobox\n\n--------------------------------------------------------------------------- */\nQAbstractItemView {\n  alternate-background-color: #19232D;\n  color: #E0E1E3;\n  border: 1px solid #455364;\n  border-radius: 4px;\n}\n\nQAbstractItemView QLineEdit {\n  padding: 2px;\n}\n\n/* QAbstractScrollArea ----------------------------------------------------\n\nhttps://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qabstractscrollarea\n\n--------------------------------------------------------------------------- */\nQAbstractScrollArea {\n  background-color: #19232D;\n  border: 1px solid #455364;\n  border-radius: 4px;\n  /* fix #159 */\n  padding: 0px;\n  /* remove min-height to fix #244 */\n  color: #E0E1E3;\n}\n\nQAbstractScrollArea:disabled {\n  color: #9DA9B5;\n}\n\n/* QScrollArea ------------------------------------------------------------\n\n--------------------------------------------------------------------------- */\nQScrollArea QWidget QWidget:disabled {\n  background-color: #19232D;\n}\n\n/* QScrollBar -------------------------------------------------------------\n\nhttps://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qscrollbar\n\n--------------------------------------------------------------------------- */\nQScrollBar:horizontal {\n  height: 16px;\n  margin: 2px 16px 2px 16px;\n  border: 1px solid #455364;\n  border-radius: 4px;\n  background-color: #19232D;\n}\n\nQScrollBar:vertical {\n  background-color: #19232D;\n  width: 16px;\n  margin: 16px 2px 16px 2px;\n  border: 1px solid #455364;\n  border-radius: 4px;\n}\n\nQScrollBar::handle:horizontal {\n  background-color: #60798B;\n  border: 1px solid #455364;\n  border-radius: 4px;\n  min-width: 8px;\n}\n\nQScrollBar::handle:horizontal:hover {\n  background-color: #346792;\n  border: #346792;\n  border-radius: 4px;\n  min-width: 8px;\n}\n\nQScrollBar::handle:horizontal:focus {\n  border: 1px solid #1A72BB;\n}\n\nQScrollBar::handle:vertical {\n  background-color: #60798B;\n  border: 1px solid #455364;\n  min-height: 8px;\n  border-radius: 4px;\n}\n\nQScrollBar::handle:vertical:hover {\n  background-color: #346792;\n  border: #346792;\n  border-radius: 4px;\n  min-height: 8px;\n}\n\nQScrollBar::handle:vertical:focus {\n  border: 1px solid #1A72BB;\n}\n\nQScrollBar::add-line:horizontal {\n  margin: 0px 0px 0px 0px;\n  border-image: url(\":/dark/rc/arrow_right_disabled.png\");\n  height: 12px;\n  width: 12px;\n  subcontrol-position: right;\n  subcontrol-origin: margin;\n}\n\nQScrollBar::add-line:horizontal:hover, QScrollBar::add-line:horizontal:on {\n  border-image: url(\":/dark/rc/arrow_right.png\");\n  height: 12px;\n  width: 12px;\n  subcontrol-position: right;\n  subcontrol-origin: margin;\n}\n\nQScrollBar::add-line:vertical {\n  margin: 3px 0px 3px 0px;\n  border-image: url(\":/dark/rc/arrow_down_disabled.png\");\n  height: 12px;\n  width: 12px;\n  subcontrol-position: bottom;\n  subcontrol-origin: margin;\n}\n\nQScrollBar::add-line:vertical:hover, QScrollBar::add-line:vertical:on {\n  border-image: url(\":/dark/rc/arrow_down.png\");\n  height: 12px;\n  width: 12px;\n  subcontrol-position: bottom;\n  subcontrol-origin: margin;\n}\n\nQScrollBar::sub-line:horizontal {\n  margin: 0px 3px 0px 3px;\n  border-image: url(\":/dark/rc/arrow_left_disabled.png\");\n  height: 12px;\n  width: 12px;\n  subcontrol-position: left;\n  subcontrol-origin: margin;\n}\n\nQScrollBar::sub-line:horizontal:hover, QScrollBar::sub-line:horizontal:on {\n  border-image: url(\":/dark/rc/arrow_left.png\");\n  height: 12px;\n  width: 12px;\n  subcontrol-position: left;\n  subcontrol-origin: margin;\n}\n\nQScrollBar::sub-line:vertical {\n  margin: 3px 0px 3px 0px;\n  border-image: url(\":/dark/rc/arrow_up_disabled.png\");\n  height: 12px;\n  width: 12px;\n  subcontrol-position: top;\n  subcontrol-origin: margin;\n}\n\nQScrollBar::sub-line:vertical:hover, QScrollBar::sub-line:vertical:on {\n  border-image: url(\":/dark/rc/arrow_up.png\");\n  height: 12px;\n  width: 12px;\n  subcontrol-position: top;\n  subcontrol-origin: margin;\n}\n\nQScrollBar::up-arrow:horizontal, QScrollBar::down-arrow:horizontal {\n  background: none;\n}\n\nQScrollBar::up-arrow:vertical, QScrollBar::down-arrow:vertical {\n  background: none;\n}\n\nQScrollBar::add-page:horizontal, QScrollBar::sub-page:horizontal {\n  background: none;\n}\n\nQScrollBar::add-page:vertical, QScrollBar::sub-page:vertical {\n  background: none;\n}\n\n/* QTextEdit --------------------------------------------------------------\n\nhttps://doc.qt.io/qt-5/stylesheet-examples.html#customizing-specific-widgets\n\n--------------------------------------------------------------------------- */\nQTextEdit {\n  background-color: #19232D;\n  color: #E0E1E3;\n  border-radius: 4px;\n  border: 1px solid #455364;\n}\n\nQTextEdit:focus {\n  border: 1px solid #1A72BB;\n}\n\nQTextEdit:selected {\n  background: #346792;\n  color: #455364;\n}\n\n/* QPlainTextEdit ---------------------------------------------------------\n\n--------------------------------------------------------------------------- */\nQPlainTextEdit {\n  background-color: #19232D;\n  color: #E0E1E3;\n  border-radius: 4px;\n  border: 1px solid #455364;\n}\n\nQPlainTextEdit:focus {\n  border: 1px solid #1A72BB;\n}\n\nQPlainTextEdit:selected {\n  background: #346792;\n  color: #455364;\n}\n\n/* QSizeGrip --------------------------------------------------------------\n\nhttps://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qsizegrip\n\n--------------------------------------------------------------------------- */\nQSizeGrip {\n  background: transparent;\n  width: 12px;\n  height: 12px;\n  image: url(\":/dark/rc/window_grip.png\");\n}\n\n/* QStackedWidget ---------------------------------------------------------\n\n--------------------------------------------------------------------------- */\nQStackedWidget {\n  padding: 2px;\n  border: 1px solid #455364;\n  border: 1px solid #19232D;\n}\n\n/* QToolBar ---------------------------------------------------------------\n\nhttps://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qtoolbar\n\n--------------------------------------------------------------------------- */\nQToolBar {\n  background-color: #455364;\n  border-bottom: 1px solid #19232D;\n  padding: 1px;\n  font-weight: bold;\n  spacing: 2px;\n}\n\nQToolBar:disabled {\n  /* Fixes #272 */\n  background-color: #455364;\n}\n\nQToolBar::handle:horizontal {\n  width: 16px;\n  image: url(\":/dark/rc/toolbar_move_horizontal.png\");\n}\n\nQToolBar::handle:vertical {\n  height: 16px;\n  image: url(\":/dark/rc/toolbar_move_vertical.png\");\n}\n\nQToolBar::separator:horizontal {\n  width: 16px;\n  image: url(\":/dark/rc/toolbar_separator_horizontal.png\");\n}\n\nQToolBar::separator:vertical {\n  height: 16px;\n  image: url(\":/dark/rc/toolbar_separator_vertical.png\");\n}\n\nQToolButton#qt_toolbar_ext_button {\n  background: #455364;\n  border: 0px;\n  color: #E0E1E3;\n  image: url(\":/dark/rc/arrow_right.png\");\n}\n\n/* QAbstractSpinBox -------------------------------------------------------\n\n--------------------------------------------------------------------------- */\nQAbstractSpinBox {\n  background-color: #19232D;\n  border: 1px solid #455364;\n  color: #E0E1E3;\n  /* This fixes 103, 111 */\n  padding-top: 2px;\n  /* This fixes 103, 111 */\n  padding-bottom: 2px;\n  padding-left: 4px;\n  padding-right: 4px;\n  border-radius: 4px;\n  /* min-width: 5px; removed to fix 109 */\n}\n\nQAbstractSpinBox:up-button {\n  background-color: transparent #19232D;\n  subcontrol-origin: border;\n  subcontrol-position: top right;\n  border-left: 1px solid #455364;\n  border-bottom: 1px solid #455364;\n  border-top-left-radius: 0;\n  border-bottom-left-radius: 0;\n  margin: 1px;\n  width: 12px;\n  margin-bottom: -1px;\n}\n\nQAbstractSpinBox::up-arrow, QAbstractSpinBox::up-arrow:disabled, QAbstractSpinBox::up-arrow:off {\n  image: url(\":/dark/rc/arrow_up_disabled.png\");\n  height: 8px;\n  width: 8px;\n}\n\nQAbstractSpinBox::up-arrow:hover {\n  image: url(\":/dark/rc/arrow_up.png\");\n}\n\nQAbstractSpinBox:down-button {\n  background-color: transparent #19232D;\n  subcontrol-origin: border;\n  subcontrol-position: bottom right;\n  border-left: 1px solid #455364;\n  border-top: 1px solid #455364;\n  border-top-left-radius: 0;\n  border-bottom-left-radius: 0;\n  margin: 1px;\n  width: 12px;\n  margin-top: -1px;\n}\n\nQAbstractSpinBox::down-arrow, QAbstractSpinBox::down-arrow:disabled, QAbstractSpinBox::down-arrow:off {\n  image: url(\":/dark/rc/arrow_down_disabled.png\");\n  height: 8px;\n  width: 8px;\n}\n\nQAbstractSpinBox::down-arrow:hover {\n  image: url(\":/dark/rc/arrow_down.png\");\n}\n\nQAbstractSpinBox:hover {\n  border: 1px solid #346792;\n  color: #E0E1E3;\n}\n\nQAbstractSpinBox:focus {\n  border: 1px solid #1A72BB;\n}\n\nQAbstractSpinBox:selected {\n  background: #346792;\n  color: #455364;\n}\n\n/* ------------------------------------------------------------------------ */\n/* DISPLAYS --------------------------------------------------------------- */\n/* ------------------------------------------------------------------------ */\n/* QLabel -----------------------------------------------------------------\n\nhttps://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qframe\n\n--------------------------------------------------------------------------- */\nQLabel {\n  background-color: #19232D;\n  border: 0px solid #455364;\n  padding: 0px;\n  margin: 0px;\n  color: #E0E1E3;\n}\n\nQLabel:disabled {\n  background-color: #19232D;\n  border: 0px solid #455364;\n  color: #9DA9B5;\n}\n\n/* QTextBrowser -----------------------------------------------------------\n\nhttps://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qabstractscrollarea\n\n--------------------------------------------------------------------------- */\nQTextBrowser {\n  background-color: #19232D;\n  border: 1px solid #455364;\n  color: #E0E1E3;\n  border-radius: 4px;\n}\n\nQTextBrowser:disabled {\n  background-color: #19232D;\n  border: 1px solid #455364;\n  color: #9DA9B5;\n  border-radius: 4px;\n}\n\nQTextBrowser:hover, QTextBrowser:!hover, QTextBrowser:selected, QTextBrowser:pressed {\n  border: 1px solid #455364;\n}\n\n/* QGraphicsView ----------------------------------------------------------\n\n--------------------------------------------------------------------------- */\nQGraphicsView {\n  background-color: #19232D;\n  border: 1px solid #455364;\n  color: #E0E1E3;\n  border-radius: 4px;\n}\n\nQGraphicsView:disabled {\n  background-color: #19232D;\n  border: 1px solid #455364;\n  color: #9DA9B5;\n  border-radius: 4px;\n}\n\nQGraphicsView:hover, QGraphicsView:!hover, QGraphicsView:selected, QGraphicsView:pressed {\n  border: 1px solid #455364;\n}\n\n/* QCalendarWidget --------------------------------------------------------\n\n--------------------------------------------------------------------------- */\nQCalendarWidget {\n  border: 1px solid #455364;\n  border-radius: 4px;\n}\n\nQCalendarWidget:disabled {\n  background-color: #19232D;\n  color: #9DA9B5;\n}\n\n/* QLCDNumber -------------------------------------------------------------\n\n--------------------------------------------------------------------------- */\nQLCDNumber {\n  background-color: #19232D;\n  color: #E0E1E3;\n}\n\nQLCDNumber:disabled {\n  background-color: #19232D;\n  color: #9DA9B5;\n}\n\n/* QProgressBar -----------------------------------------------------------\n\nhttps://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qprogressbar\n\n--------------------------------------------------------------------------- */\nQProgressBar {\n  background-color: #19232D;\n  border: 1px solid #455364;\n  color: #E0E1E3;\n  border-radius: 4px;\n  text-align: center;\n}\n\nQProgressBar:disabled {\n  background-color: #19232D;\n  border: 1px solid #455364;\n  color: #9DA9B5;\n  border-radius: 4px;\n  text-align: center;\n}\n\nQProgressBar::chunk {\n  background-color: #346792;\n  color: #19232D;\n  border-radius: 4px;\n}\n\nQProgressBar::chunk:disabled {\n  background-color: #26486B;\n  color: #9DA9B5;\n  border-radius: 4px;\n}\n\n/* ------------------------------------------------------------------------ */\n/* BUTTONS ---------------------------------------------------------------- */\n/* ------------------------------------------------------------------------ */\n/* QPushButton ------------------------------------------------------------\n\nhttps://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qpushbutton\n\n--------------------------------------------------------------------------- */\nQPushButton {\n  background-color: #455364;\n  color: #E0E1E3;\n  border-radius: 4px;\n  padding: 2px;\n  outline: none;\n  border: none;\n}\n\nQPushButton:disabled {\n  background-color: #455364;\n  color: #9DA9B5;\n  border-radius: 4px;\n  padding: 2px;\n}\n\nQPushButton:checked {\n  background-color: #60798B;\n  border-radius: 4px;\n  padding: 2px;\n  outline: none;\n}\n\nQPushButton:checked:disabled {\n  background-color: #60798B;\n  color: #9DA9B5;\n  border-radius: 4px;\n  padding: 2px;\n  outline: none;\n}\n\nQPushButton:checked:selected {\n  background: #60798B;\n}\n\nQPushButton:hover {\n  background-color: #54687A;\n  color: #E0E1E3;\n}\n\nQPushButton:pressed {\n  background-color: #60798B;\n}\n\nQPushButton:selected {\n  background: #60798B;\n  color: #E0E1E3;\n}\n\nQPushButton::menu-indicator {\n  subcontrol-origin: padding;\n  subcontrol-position: bottom right;\n  bottom: 4px;\n}\n\nQDialogButtonBox QPushButton {\n  /* Issue #194 #248 - Special case of QPushButton inside dialogs, for better UI */\n  min-width: 80px;\n}\n\n/* QToolButton ------------------------------------------------------------\n\nhttps://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qtoolbutton\n\n--------------------------------------------------------------------------- */\nQToolButton {\n  background-color: #455364;\n  color: #E0E1E3;\n  border-radius: 4px;\n  padding: 2px;\n  outline: none;\n  border: none;\n  /* The subcontrols below are used only in the DelayedPopup mode */\n  /* The subcontrols below are used only in the MenuButtonPopup mode */\n  /* The subcontrol below is used only in the InstantPopup or DelayedPopup mode */\n}\n\nQToolButton:disabled {\n  background-color: #455364;\n  color: #9DA9B5;\n  border-radius: 4px;\n  padding: 2px;\n}\n\nQToolButton:checked {\n  background-color: #60798B;\n  border-radius: 4px;\n  padding: 2px;\n  outline: none;\n}\n\nQToolButton:checked:disabled {\n  background-color: #60798B;\n  color: #9DA9B5;\n  border-radius: 4px;\n  padding: 2px;\n  outline: none;\n}\n\nQToolButton:checked:hover {\n  background-color: #54687A;\n  color: #E0E1E3;\n}\n\nQToolButton:checked:pressed {\n  background-color: #60798B;\n}\n\nQToolButton:checked:selected {\n  background: #60798B;\n  color: #E0E1E3;\n}\n\nQToolButton:hover {\n  background-color: #54687A;\n  color: #E0E1E3;\n}\n\nQToolButton:pressed {\n  background-color: #60798B;\n}\n\nQToolButton:selected {\n  background: #60798B;\n  color: #E0E1E3;\n}\n\nQToolButton[popupMode=\"0\"] {\n  /* Only for DelayedPopup */\n  padding-right: 2px;\n}\n\nQToolButton[popupMode=\"1\"] {\n  /* Only for MenuButtonPopup */\n  padding-right: 20px;\n}\n\nQToolButton[popupMode=\"1\"]::menu-button {\n  border: none;\n}\n\nQToolButton[popupMode=\"1\"]::menu-button:hover {\n  border: none;\n  border-left: 1px solid #455364;\n  border-radius: 0;\n}\n\nQToolButton[popupMode=\"2\"] {\n  /* Only for InstantPopup */\n  padding-right: 2px;\n}\n\nQToolButton::menu-button {\n  padding: 2px;\n  border-radius: 4px;\n  width: 12px;\n  border: none;\n  outline: none;\n}\n\nQToolButton::menu-button:hover {\n  border: 1px solid #346792;\n}\n\nQToolButton::menu-button:checked:hover {\n  border: 1px solid #346792;\n}\n\nQToolButton::menu-indicator {\n  image: url(\":/dark/rc/arrow_down.png\");\n  height: 8px;\n  width: 8px;\n  top: 0;\n  /* Exclude a shift for better image */\n  left: -2px;\n  /* Shift it a bit */\n}\n\nQToolButton::menu-arrow {\n  image: url(\":/dark/rc/arrow_down.png\");\n  height: 8px;\n  width: 8px;\n}\n\nQToolButton::menu-arrow:hover {\n  image: url(\":/dark/rc/arrow_down_focus.png\");\n}\n\n/* QCommandLinkButton -----------------------------------------------------\n\n--------------------------------------------------------------------------- */\nQCommandLinkButton {\n  background-color: transparent;\n  border: 1px solid #455364;\n  color: #E0E1E3;\n  border-radius: 4px;\n  padding: 0px;\n  margin: 0px;\n}\n\nQCommandLinkButton:disabled {\n  background-color: transparent;\n  color: #9DA9B5;\n}\n\n/* ------------------------------------------------------------------------ */\n/* INPUTS - NO FIELDS ----------------------------------------------------- */\n/* ------------------------------------------------------------------------ */\n/* QComboBox --------------------------------------------------------------\n\nhttps://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qcombobox\n\n--------------------------------------------------------------------------- */\nQComboBox {\n  border: 1px solid #455364;\n  border-radius: 4px;\n  selection-background-color: #346792;\n  padding-left: 4px;\n  padding-right: 4px;\n  /* padding-right = 36; 4 + 16*2 See scrollbar size */\n  /* changed to 4px to fix #239 */\n  /* Fixes #103, #111 */\n  min-height: 1.5em;\n  /* padding-top: 2px;     removed to fix #132 */\n  /* padding-bottom: 2px;  removed to fix #132 */\n  /* min-width: 75px;      removed to fix #109 */\n  /* Needed to remove indicator - fix #132 */\n}\n\nQComboBox QAbstractItemView {\n  border: 1px solid #455364;\n  border-radius: 0;\n  background-color: #19232D;\n  selection-background-color: #346792;\n}\n\nQComboBox QAbstractItemView:hover {\n  background-color: #19232D;\n  color: #E0E1E3;\n}\n\nQComboBox QAbstractItemView:selected {\n  background: #346792;\n  color: #455364;\n}\n\nQComboBox QAbstractItemView:alternate {\n  background: #19232D;\n}\n\nQComboBox:disabled {\n  background-color: #19232D;\n  color: #9DA9B5;\n}\n\nQComboBox:hover {\n  border: 1px solid #346792;\n}\n\nQComboBox:focus {\n  border: 1px solid #1A72BB;\n}\n\nQComboBox:on {\n  selection-background-color: #346792;\n}\n\nQComboBox::indicator {\n  border: none;\n  border-radius: 0;\n  background-color: transparent;\n  selection-background-color: transparent;\n  color: transparent;\n  selection-color: transparent;\n  /* Needed to remove indicator - fix #132 */\n}\n\nQComboBox::indicator:alternate {\n  background: #19232D;\n}\n\nQComboBox::item {\n  /* Remove to fix #282, #285 and MR #288*/\n  /*&:checked {\n            font-weight: bold;\n        }\n\n        &:selected {\n            border: 0px solid transparent;\n        }\n        */\n}\n\nQComboBox::item:alternate {\n  background: #19232D;\n}\n\nQComboBox::drop-down {\n  subcontrol-origin: padding;\n  subcontrol-position: top right;\n  width: 12px;\n  border-left: 1px solid #455364;\n}\n\nQComboBox::down-arrow {\n  image: url(\":/dark/rc/arrow_down_disabled.png\");\n  height: 8px;\n  width: 8px;\n}\n\nQComboBox::down-arrow:on, QComboBox::down-arrow:hover, QComboBox::down-arrow:focus {\n  image: url(\":/dark/rc/arrow_down.png\");\n}\n\n/* QSlider ----------------------------------------------------------------\n\nhttps://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qslider\n\n--------------------------------------------------------------------------- */\nQSlider:disabled {\n  background: #19232D;\n}\n\nQSlider:focus {\n  border: none;\n}\n\nQSlider::groove:horizontal {\n  background: #455364;\n  border: 1px solid #455364;\n  height: 4px;\n  margin: 0px;\n  border-radius: 4px;\n}\n\nQSlider::groove:vertical {\n  background: #455364;\n  border: 1px solid #455364;\n  width: 4px;\n  margin: 0px;\n  border-radius: 4px;\n}\n\nQSlider::add-page:vertical {\n  background: #346792;\n  border: 1px solid #455364;\n  width: 4px;\n  margin: 0px;\n  border-radius: 4px;\n}\n\nQSlider::add-page:vertical :disabled {\n  background: #26486B;\n}\n\nQSlider::sub-page:horizontal {\n  background: #346792;\n  border: 1px solid #455364;\n  height: 4px;\n  margin: 0px;\n  border-radius: 4px;\n}\n\nQSlider::sub-page:horizontal:disabled {\n  background: #26486B;\n}\n\nQSlider::handle:horizontal {\n  background: #9DA9B5;\n  border: 1px solid #455364;\n  width: 8px;\n  height: 8px;\n  margin: -8px 0px;\n  border-radius: 4px;\n}\n\nQSlider::handle:horizontal:hover {\n  background: #346792;\n  border: 1px solid #346792;\n}\n\nQSlider::handle:horizontal:focus {\n  border: 1px solid #1A72BB;\n}\n\nQSlider::handle:vertical {\n  background: #9DA9B5;\n  border: 1px solid #455364;\n  width: 8px;\n  height: 8px;\n  margin: 0 -8px;\n  border-radius: 4px;\n}\n\nQSlider::handle:vertical:hover {\n  background: #346792;\n  border: 1px solid #346792;\n}\n\nQSlider::handle:vertical:focus {\n  border: 1px solid #1A72BB;\n}\n\n/* QLineEdit --------------------------------------------------------------\n\nhttps://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qlineedit\n\n--------------------------------------------------------------------------- */\nQLineEdit {\n  background-color: #19232D;\n  padding-top: 2px;\n  /* This QLineEdit fix  103, 111 */\n  padding-bottom: 2px;\n  /* This QLineEdit fix  103, 111 */\n  padding-left: 4px;\n  padding-right: 4px;\n  border-style: solid;\n  border: 1px solid #455364;\n  border-radius: 4px;\n  color: #E0E1E3;\n}\n\nQLineEdit:disabled {\n  background-color: #19232D;\n  color: #9DA9B5;\n}\n\nQLineEdit:hover {\n  border: 1px solid #346792;\n  color: #E0E1E3;\n}\n\nQLineEdit:focus {\n  border: 1px solid #1A72BB;\n}\n\nQLineEdit:selected {\n  background-color: #346792;\n  color: #455364;\n}\n\n/* QTabWiget --------------------------------------------------------------\n\nhttps://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qtabwidget-and-qtabbar\n\n--------------------------------------------------------------------------- */\nQTabWidget {\n  padding: 2px;\n  selection-background-color: #455364;\n}\n\nQTabWidget QWidget {\n  /* Fixes #189 */\n  border-radius: 4px;\n}\n\nQTabWidget::pane {\n  border: 1px solid #455364;\n  border-radius: 4px;\n  margin: 0px;\n  /* Fixes double border inside pane with pyqt5 */\n  padding: 0px;\n}\n\nQTabWidget::pane:selected {\n  background-color: #455364;\n  border: 1px solid #346792;\n}\n\n/* QTabBar ----------------------------------------------------------------\n\nhttps://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qtabwidget-and-qtabbar\n\n--------------------------------------------------------------------------- */\nQTabBar, QDockWidget QTabBar {\n  qproperty-drawBase: 0;\n  border-radius: 4px;\n  margin: 0px;\n  padding: 2px;\n  border: 0;\n  /* left: 5px; move to the right by 5px - removed for fix */\n}\n\nQTabBar::close-button, QDockWidget QTabBar::close-button {\n  border: 0;\n  margin: 0;\n  padding: 4px;\n  image: url(\":/dark/rc/window_close.png\");\n}\n\nQTabBar::close-button:hover, QDockWidget QTabBar::close-button:hover {\n  image: url(\":/dark/rc/window_close_focus.png\");\n}\n\nQTabBar::close-button:pressed, QDockWidget QTabBar::close-button:pressed {\n  image: url(\":/dark/rc/window_close_pressed.png\");\n}\n\nQTabBar::tab, QDockWidget QTabBar::tab {\n  /* !selected and disabled ----------------------------------------- */\n  /* selected ------------------------------------------------------- */\n}\n\nQTabBar::tab:top:selected:disabled, QDockWidget QTabBar::tab:top:selected:disabled {\n  border-bottom: 3px solid #26486B;\n  color: #9DA9B5;\n  background-color: #455364;\n}\n\nQTabBar::tab:bottom:selected:disabled, QDockWidget QTabBar::tab:bottom:selected:disabled {\n  border-top: 3px solid #26486B;\n  color: #9DA9B5;\n  background-color: #455364;\n}\n\nQTabBar::tab:left:selected:disabled, QDockWidget QTabBar::tab:left:selected:disabled {\n  border-right: 3px solid #26486B;\n  color: #9DA9B5;\n  background-color: #455364;\n}\n\nQTabBar::tab:right:selected:disabled, QDockWidget QTabBar::tab:right:selected:disabled {\n  border-left: 3px solid #26486B;\n  color: #9DA9B5;\n  background-color: #455364;\n}\n\nQTabBar::tab:top:!selected:disabled, QDockWidget QTabBar::tab:top:!selected:disabled {\n  border-bottom: 3px solid #19232D;\n  color: #9DA9B5;\n  background-color: #19232D;\n}\n\nQTabBar::tab:bottom:!selected:disabled, QDockWidget QTabBar::tab:bottom:!selected:disabled {\n  border-top: 3px solid #19232D;\n  color: #9DA9B5;\n  background-color: #19232D;\n}\n\nQTabBar::tab:left:!selected:disabled, QDockWidget QTabBar::tab:left:!selected:disabled {\n  border-right: 3px solid #19232D;\n  color: #9DA9B5;\n  background-color: #19232D;\n}\n\nQTabBar::tab:right:!selected:disabled, QDockWidget QTabBar::tab:right:!selected:disabled {\n  border-left: 3px solid #19232D;\n  color: #9DA9B5;\n  background-color: #19232D;\n}\n\nQTabBar::tab:top:!selected, QDockWidget QTabBar::tab:top:!selected {\n  border-bottom: 2px solid #19232D;\n  margin-top: 2px;\n}\n\nQTabBar::tab:bottom:!selected, QDockWidget QTabBar::tab:bottom:!selected {\n  border-top: 2px solid #19232D;\n  margin-bottom: 2px;\n}\n\nQTabBar::tab:left:!selected, QDockWidget QTabBar::tab:left:!selected {\n  border-left: 2px solid #19232D;\n  margin-right: 2px;\n}\n\nQTabBar::tab:right:!selected, QDockWidget QTabBar::tab:right:!selected {\n  border-right: 2px solid #19232D;\n  margin-left: 2px;\n}\n\nQTabBar::tab:top, QDockWidget QTabBar::tab:top {\n  background-color: #455364;\n  margin-left: 2px;\n  padding-left: 4px;\n  padding-right: 4px;\n  padding-top: 2px;\n  padding-bottom: 2px;\n  min-width: 5px;\n  border-bottom: 3px solid #455364;\n  border-top-left-radius: 4px;\n  border-top-right-radius: 4px;\n}\n\nQTabBar::tab:top:selected, QDockWidget QTabBar::tab:top:selected {\n  background-color: #54687A;\n  border-bottom: 3px solid #259AE9;\n  border-top-left-radius: 4px;\n  border-top-right-radius: 4px;\n}\n\nQTabBar::tab:top:!selected:hover, QDockWidget QTabBar::tab:top:!selected:hover {\n  border: 1px solid #1A72BB;\n  border-bottom: 3px solid #1A72BB;\n  /* Fixes spyder-ide/spyder#9766 and #243 */\n  padding-left: 3px;\n  padding-right: 3px;\n}\n\nQTabBar::tab:bottom, QDockWidget QTabBar::tab:bottom {\n  border-top: 3px solid #455364;\n  background-color: #455364;\n  margin-left: 2px;\n  padding-left: 4px;\n  padding-right: 4px;\n  padding-top: 2px;\n  padding-bottom: 2px;\n  border-bottom-left-radius: 4px;\n  border-bottom-right-radius: 4px;\n  min-width: 5px;\n}\n\nQTabBar::tab:bottom:selected, QDockWidget QTabBar::tab:bottom:selected {\n  background-color: #54687A;\n  border-top: 3px solid #259AE9;\n  border-bottom-left-radius: 4px;\n  border-bottom-right-radius: 4px;\n}\n\nQTabBar::tab:bottom:!selected:hover, QDockWidget QTabBar::tab:bottom:!selected:hover {\n  border: 1px solid #1A72BB;\n  border-top: 3px solid #1A72BB;\n  /* Fixes spyder-ide/spyder#9766 and #243 */\n  padding-left: 3px;\n  padding-right: 3px;\n}\n\nQTabBar::tab:left, QDockWidget QTabBar::tab:left {\n  background-color: #455364;\n  margin-top: 2px;\n  padding-left: 2px;\n  padding-right: 2px;\n  padding-top: 4px;\n  padding-bottom: 4px;\n  border-top-left-radius: 4px;\n  border-bottom-left-radius: 4px;\n  min-height: 5px;\n}\n\nQTabBar::tab:left:selected, QDockWidget QTabBar::tab:left:selected {\n  background-color: #54687A;\n  border-right: 3px solid #259AE9;\n}\n\nQTabBar::tab:left:!selected:hover, QDockWidget QTabBar::tab:left:!selected:hover {\n  border: 1px solid #1A72BB;\n  border-right: 3px solid #1A72BB;\n  /* Fixes different behavior #271 */\n  margin-right: 0px;\n  padding-right: -1px;\n}\n\nQTabBar::tab:right, QDockWidget QTabBar::tab:right {\n  background-color: #455364;\n  margin-top: 2px;\n  padding-left: 2px;\n  padding-right: 2px;\n  padding-top: 4px;\n  padding-bottom: 4px;\n  border-top-right-radius: 4px;\n  border-bottom-right-radius: 4px;\n  min-height: 5px;\n}\n\nQTabBar::tab:right:selected, QDockWidget QTabBar::tab:right:selected {\n  background-color: #54687A;\n  border-left: 3px solid #259AE9;\n}\n\nQTabBar::tab:right:!selected:hover, QDockWidget QTabBar::tab:right:!selected:hover {\n  border: 1px solid #1A72BB;\n  border-left: 3px solid #1A72BB;\n  /* Fixes different behavior #271 */\n  margin-left: 0px;\n  padding-left: 0px;\n}\n\nQTabBar QToolButton, QDockWidget QTabBar QToolButton {\n  /* Fixes #136 */\n  background-color: #455364;\n  height: 12px;\n  width: 12px;\n}\n\nQTabBar QToolButton:pressed, QDockWidget QTabBar QToolButton:pressed {\n  background-color: #455364;\n}\n\nQTabBar QToolButton:pressed:hover, QDockWidget QTabBar QToolButton:pressed:hover {\n  border: 1px solid #346792;\n}\n\nQTabBar QToolButton::left-arrow:enabled, QDockWidget QTabBar QToolButton::left-arrow:enabled {\n  image: url(\":/dark/rc/arrow_left.png\");\n}\n\nQTabBar QToolButton::left-arrow:disabled, QDockWidget QTabBar QToolButton::left-arrow:disabled {\n  image: url(\":/dark/rc/arrow_left_disabled.png\");\n}\n\nQTabBar QToolButton::right-arrow:enabled, QDockWidget QTabBar QToolButton::right-arrow:enabled {\n  image: url(\":/dark/rc/arrow_right.png\");\n}\n\nQTabBar QToolButton::right-arrow:disabled, QDockWidget QTabBar QToolButton::right-arrow:disabled {\n  image: url(\":/dark/rc/arrow_right_disabled.png\");\n}\n\n/* QDockWiget -------------------------------------------------------------\n\n--------------------------------------------------------------------------- */\nQDockWidget {\n  outline: 1px solid #455364;\n  background-color: #19232D;\n  border: 1px solid #455364;\n  border-radius: 4px;\n  titlebar-close-icon: url(\":/dark/rc/transparent.png\");\n  titlebar-normal-icon: url(\":/dark/rc/transparent.png\");\n}\n\nQDockWidget::title {\n  /* Better size for title bar */\n  padding: 3px;\n  padding-bottom: -3px; /* was not specified */\n  spacing: 4px;\n  border: none;\n  background-color: #455364;\n}\n\nQDockWidget::close-button {\n  icon-size: 12px;\n  border: none;\n  background: transparent;\n  background-image: transparent;\n  border: 0;\n  margin: 0;\n  padding: 0;\n  image: url(\":/dark/rc/window_close.png\");\n}\n\nQDockWidget::close-button:hover {\n  image: url(\":/dark/rc/window_close_focus.png\");\n}\n\nQDockWidget::close-button:pressed {\n  image: url(\":/dark/rc/window_close_pressed.png\");\n}\n\nQDockWidget::float-button {\n  icon-size: 12px;\n  border: none;\n  background: transparent;\n  background-image: transparent;\n  border: 0;\n  margin: 0;\n  padding: 0;\n  image: url(\":/dark/rc/window_undock.png\");\n}\n\nQDockWidget::float-button:hover {\n  image: url(\":/dark/rc/window_undock_focus.png\");\n}\n\nQDockWidget::float-button:pressed {\n  image: url(\":/dark/rc/window_undock_pressed.png\");\n}\n\n/* QTreeView QListView QTableView -----------------------------------------\n\nhttps://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qtreeview\nhttps://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qlistview\nhttps://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qtableview\n\n--------------------------------------------------------------------------- */\nQTreeView:branch:selected, QTreeView:branch:hover {\n  background: url(\":/dark/rc/transparent.png\");\n}\n\nQTreeView:branch:has-siblings:!adjoins-item {\n  border-image: url(\":/dark/rc/branch_line.png\") 0;\n}\n\nQTreeView:branch:has-siblings:adjoins-item {\n  border-image: url(\":/dark/rc/branch_more.png\") 0;\n}\n\nQTreeView:branch:!has-children:!has-siblings:adjoins-item {\n  border-image: url(\":/dark/rc/branch_end.png\") 0;\n}\n\nQTreeView:branch:has-children:!has-siblings:closed, QTreeView:branch:closed:has-children:has-siblings {\n  border-image: none;\n  image: url(\":/dark/rc/branch_closed.png\");\n}\n\nQTreeView:branch:open:has-children:!has-siblings, QTreeView:branch:open:has-children:has-siblings {\n  border-image: none;\n  image: url(\":/dark/rc/branch_open.png\");\n}\n\nQTreeView:branch:has-children:!has-siblings:closed:hover, QTreeView:branch:closed:has-children:has-siblings:hover {\n  image: url(\":/dark/rc/branch_closed_focus.png\");\n}\n\nQTreeView:branch:open:has-children:!has-siblings:hover, QTreeView:branch:open:has-children:has-siblings:hover {\n  image: url(\":/dark/rc/branch_open_focus.png\");\n}\n\nQTreeView::indicator:checked,\nQListView::indicator:checked,\nQTableView::indicator:checked,\nQColumnView::indicator:checked {\n  image: url(\":/dark/rc/checkbox_checked.png\");\n}\n\nQTreeView::indicator:checked:hover, QTreeView::indicator:checked:focus, QTreeView::indicator:checked:pressed,\nQListView::indicator:checked:hover,\nQListView::indicator:checked:focus,\nQListView::indicator:checked:pressed,\nQTableView::indicator:checked:hover,\nQTableView::indicator:checked:focus,\nQTableView::indicator:checked:pressed,\nQColumnView::indicator:checked:hover,\nQColumnView::indicator:checked:focus,\nQColumnView::indicator:checked:pressed {\n  image: url(\":/dark/rc/checkbox_checked_focus.png\");\n}\n\nQTreeView::indicator:unchecked,\nQListView::indicator:unchecked,\nQTableView::indicator:unchecked,\nQColumnView::indicator:unchecked {\n  image: url(\":/dark/rc/checkbox_unchecked.png\");\n}\n\nQTreeView::indicator:unchecked:hover, QTreeView::indicator:unchecked:focus, QTreeView::indicator:unchecked:pressed,\nQListView::indicator:unchecked:hover,\nQListView::indicator:unchecked:focus,\nQListView::indicator:unchecked:pressed,\nQTableView::indicator:unchecked:hover,\nQTableView::indicator:unchecked:focus,\nQTableView::indicator:unchecked:pressed,\nQColumnView::indicator:unchecked:hover,\nQColumnView::indicator:unchecked:focus,\nQColumnView::indicator:unchecked:pressed {\n  image: url(\":/dark/rc/checkbox_unchecked_focus.png\");\n}\n\nQTreeView::indicator:indeterminate,\nQListView::indicator:indeterminate,\nQTableView::indicator:indeterminate,\nQColumnView::indicator:indeterminate {\n  image: url(\":/dark/rc/checkbox_indeterminate.png\");\n}\n\nQTreeView::indicator:indeterminate:hover, QTreeView::indicator:indeterminate:focus, QTreeView::indicator:indeterminate:pressed,\nQListView::indicator:indeterminate:hover,\nQListView::indicator:indeterminate:focus,\nQListView::indicator:indeterminate:pressed,\nQTableView::indicator:indeterminate:hover,\nQTableView::indicator:indeterminate:focus,\nQTableView::indicator:indeterminate:pressed,\nQColumnView::indicator:indeterminate:hover,\nQColumnView::indicator:indeterminate:focus,\nQColumnView::indicator:indeterminate:pressed {\n  image: url(\":/dark/rc/checkbox_indeterminate_focus.png\");\n}\n\nQTreeView,\nQListView,\nQTableView,\nQColumnView {\n  background-color: #19232D;\n  border: 1px solid #455364;\n  color: #E0E1E3;\n  gridline-color: #455364;\n  border-radius: 4px;\n}\n\nQTreeView:disabled,\nQListView:disabled,\nQTableView:disabled,\nQColumnView:disabled {\n  background-color: #19232D;\n  color: #9DA9B5;\n}\n\nQTreeView:selected,\nQListView:selected,\nQTableView:selected,\nQColumnView:selected {\n  background-color: #346792;\n  color: #455364;\n}\n\nQTreeView:focus,\nQListView:focus,\nQTableView:focus,\nQColumnView:focus {\n  border: 1px solid #1A72BB;\n}\n\nQTreeView::item:pressed,\nQListView::item:pressed,\nQTableView::item:pressed,\nQColumnView::item:pressed {\n  background-color: #346792;\n}\n\nQTreeView::item:selected:active,\nQListView::item:selected:active,\nQTableView::item:selected:active,\nQColumnView::item:selected:active {\n  background-color: #346792;\n}\n\nQTreeView::item:selected:!active,\nQListView::item:selected:!active,\nQTableView::item:selected:!active,\nQColumnView::item:selected:!active {\n  color: #E0E1E3;\n  background-color: #37414F;\n}\n\nQTreeView::item:!selected:hover,\nQListView::item:!selected:hover,\nQTableView::item:!selected:hover,\nQColumnView::item:!selected:hover {\n  outline: 0;\n  color: #E0E1E3;\n  background-color: #37414F;\n}\n\nQTableCornerButton::section {\n  background-color: #19232D;\n  border: 1px transparent #455364;\n  border-radius: 0px;\n}\n\n/* QHeaderView ------------------------------------------------------------\n\nhttps://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qheaderview\n\n--------------------------------------------------------------------------- */\nQHeaderView {\n  background-color: #455364;\n  border: 0px transparent #455364;\n  padding: 0;\n  margin: 0;\n  border-radius: 0;\n}\n\nQHeaderView:disabled {\n  background-color: #455364;\n  border: 1px transparent #455364;\n}\n\nQHeaderView::section {\n  background-color: #455364;\n  color: #E0E1E3;\n  border-radius: 0;\n  text-align: left;\n  font-size: 13px;\n}\n\nQHeaderView::section::horizontal {\n  padding-top: 0;\n  padding-bottom: 0;\n  padding-left: 4px;\n  padding-right: 4px;\n  border-left: 1px solid #19232D;\n}\n\nQHeaderView::section::horizontal::first, QHeaderView::section::horizontal::only-one {\n  border-left: 1px solid #455364;\n}\n\nQHeaderView::section::horizontal:disabled {\n  color: #9DA9B5;\n}\n\nQHeaderView::section::vertical {\n  padding-top: 0;\n  padding-bottom: 0;\n  padding-left: 4px;\n  padding-right: 4px;\n  border-top: 1px solid #19232D;\n}\n\nQHeaderView::section::vertical::first, QHeaderView::section::vertical::only-one {\n  border-top: 1px solid #455364;\n}\n\nQHeaderView::section::vertical:disabled {\n  color: #9DA9B5;\n}\n\nQHeaderView::down-arrow {\n  /* Those settings (border/width/height/background-color) solve bug */\n  /* transparent arrow background and size */\n  background-color: #455364;\n  border: none;\n  height: 12px;\n  width: 12px;\n  padding-left: 2px;\n  padding-right: 2px;\n  image: url(\":/dark/rc/arrow_down.png\");\n}\n\nQHeaderView::up-arrow {\n  background-color: #455364;\n  border: none;\n  height: 12px;\n  width: 12px;\n  padding-left: 2px;\n  padding-right: 2px;\n  image: url(\":/dark/rc/arrow_up.png\");\n}\n\n/* QToolBox --------------------------------------------------------------\n\nhttps://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qtoolbox\n\n--------------------------------------------------------------------------- */\nQToolBox {\n  padding: 0px;\n  border: 0px;\n  border: 1px solid #455364;\n}\n\nQToolBox:selected {\n  padding: 0px;\n  border: 2px solid #346792;\n}\n\nQToolBox::tab {\n  background-color: #19232D;\n  border: 1px solid #455364;\n  color: #E0E1E3;\n  border-top-left-radius: 4px;\n  border-top-right-radius: 4px;\n}\n\nQToolBox::tab:disabled {\n  color: #9DA9B5;\n}\n\nQToolBox::tab:selected {\n  background-color: #60798B;\n  border-bottom: 2px solid #346792;\n}\n\nQToolBox::tab:selected:disabled {\n  background-color: #455364;\n  border-bottom: 2px solid #26486B;\n}\n\nQToolBox::tab:!selected {\n  background-color: #455364;\n  border-bottom: 2px solid #455364;\n}\n\nQToolBox::tab:!selected:disabled {\n  background-color: #19232D;\n}\n\nQToolBox::tab:hover {\n  border-color: #1A72BB;\n  border-bottom: 2px solid #1A72BB;\n}\n\nQToolBox QScrollArea QWidget QWidget {\n  padding: 0px;\n  border: 0px;\n  background-color: #19232D;\n}\n\n/* QFrame -----------------------------------------------------------------\n\nhttps://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qframe\nhttps://doc.qt.io/qt-5/qframe.html#-prop\nhttps://doc.qt.io/qt-5/qframe.html#details\nhttps://stackoverflow.com/questions/14581498/qt-stylesheet-for-hline-vline-color\n\n--------------------------------------------------------------------------- */\n/* (dot) .QFrame  fix #141, #126, #123 */\n.QFrame {\n  border-radius: 4px;\n  border: 1px solid #455364;\n  /* No frame */\n  /* HLine */\n  /* HLine */\n}\n\n.QFrame[frameShape=\"0\"] {\n  border-radius: 4px;\n  border: 1px transparent #455364;\n}\n\n.QFrame[frameShape=\"4\"] {\n  max-height: 2px;\n  border: none;\n  background-color: #455364;\n}\n\n.QFrame[frameShape=\"5\"] {\n  max-width: 2px;\n  border: none;\n  background-color: #455364;\n}\n\n/* QSplitter --------------------------------------------------------------\n\nhttps://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qsplitter\n\n--------------------------------------------------------------------------- */\nQSplitter {\n  background-color: #455364;\n  spacing: 0px;\n  padding: 0px;\n  margin: 0px;\n}\n\nQSplitter::handle {\n  background-color: #455364;\n  border: 0px solid #19232D;\n  spacing: 0px;\n  padding: 1px;\n  margin: 0px;\n}\n\nQSplitter::handle:hover {\n  background-color: #9DA9B5;\n}\n\nQSplitter::handle:horizontal {\n  width: 5px;\n  image: url(\":/dark/rc/line_vertical.png\");\n}\n\nQSplitter::handle:vertical {\n  height: 5px;\n  image: url(\":/dark/rc/line_horizontal.png\");\n}\n\n/* QDateEdit, QDateTimeEdit -----------------------------------------------\n\n--------------------------------------------------------------------------- */\nQDateEdit, QDateTimeEdit {\n  selection-background-color: #346792;\n  border-style: solid;\n  border: 1px solid #455364;\n  border-radius: 4px;\n  /* This fixes 103, 111 */\n  padding-top: 2px;\n  /* This fixes 103, 111 */\n  padding-bottom: 2px;\n  padding-left: 4px;\n  padding-right: 4px;\n  min-width: 10px;\n}\n\nQDateEdit:on, QDateTimeEdit:on {\n  selection-background-color: #346792;\n}\n\nQDateEdit::drop-down, QDateTimeEdit::drop-down {\n  subcontrol-origin: padding;\n  subcontrol-position: top right;\n  width: 12px;\n  border-left: 1px solid #455364;\n}\n\nQDateEdit::down-arrow, QDateTimeEdit::down-arrow {\n  image: url(\":/dark/rc/arrow_down_disabled.png\");\n  height: 8px;\n  width: 8px;\n}\n\nQDateEdit::down-arrow:on, QDateEdit::down-arrow:hover, QDateEdit::down-arrow:focus, QDateTimeEdit::down-arrow:on, QDateTimeEdit::down-arrow:hover, QDateTimeEdit::down-arrow:focus {\n  image: url(\":/dark/rc/arrow_down.png\");\n}\n\nQDateEdit QAbstractItemView, QDateTimeEdit QAbstractItemView {\n  background-color: #19232D;\n  border-radius: 4px;\n  border: 1px solid #455364;\n  selection-background-color: #346792;\n}\n\n/* QAbstractView ----------------------------------------------------------\n\n--------------------------------------------------------------------------- */\nQAbstractView:hover {\n  border: 1px solid #346792;\n  color: #E0E1E3;\n}\n\nQAbstractView:selected {\n  background: #346792;\n  color: #455364;\n}\n\n/* PlotWidget -------------------------------------------------------------\n\n--------------------------------------------------------------------------- */\nPlotWidget {\n  /* Fix cut labels in plots #134 */\n  padding: 0px;\n}\n"
  },
  {
    "path": "resources/vsedit-job-server-watcher.qrc",
    "content": "<!DOCTYPE RCC><RCC version=\"1.0\">\n\t<qresource>\n\t\t<file alias=\"watcher.ico\">vsedit-job-server-watcher.ico</file>\n\t\t<file alias=\"exit.png\">door_in.png</file>\n\t\t<file alias=\"settings.png\">cog.png</file>\n\t\t<file alias=\"folder.png\">folder.png</file>\n\t\t<file alias=\"information.png\">information.png</file>\n\t\t<file alias=\"jobs.png\">sheduled_task.png</file>\n\t\t<file alias=\"link.png\">link.png</file>\n\t\t<file alias=\"add.png\">add.png</file>\n\t\t<file alias=\"delete.png\">delete.png</file>\n\t</qresource>\n</RCC>\n"
  },
  {
    "path": "resources/vsedit.qrc",
    "content": "<!DOCTYPE RCC><RCC version=\"1.0\">\n\t<qresource>\n\t\t<file alias=\"new.png\">page_white_text.png</file>\n\t\t<file alias=\"save.png\">disk.png</file>\n\t\t<file alias=\"save_as.png\">disk_edit.png</file>\n\t\t<file alias=\"load.png\">folder_page_white.png</file>\n\t\t<file alias=\"preview.png\">film.png</file>\n\t\t<file alias=\"check.png\">tick_light_blue.png</file>\n\t\t<file alias=\"exit.png\">door_in.png</file>\n\t\t<file alias=\"snapshot.png\">picture_save.png</file>\n\t\t<file alias=\"zoom.png\">zoom.png</file>\n\t\t<file alias=\"zoom_no_zoom.png\">zoom_actual.png</file>\n\t\t<file alias=\"zoom_fixed_ratio.png\">zoom_in.png</file>\n\t\t<file alias=\"zoom_fit_to_frame.png\">zoom_fit.png</file>\n\t\t<file alias=\"crop.png\">transform_crop.png</file>\n\t\t<file alias=\"paste.png\">paste_plain.png</file>\n\t\t<file alias=\"vsedit.ico\">vsedit.ico</file>\n\t\t<file alias=\"settings.png\">cog.png</file>\n\t\t<file alias=\"folder.png\">folder.png</file>\n\t\t<file alias=\"folder_add.png\">folder_add.png</file>\n\t\t<file alias=\"folder_remove.png\">folder_delete.png</file>\n\t\t<file alias=\"erase.png\">erase.png</file>\n\t\t<file alias=\"image_to_clipboard.png\">image_to_clipboard.png</file>\n\t\t<file alias=\"timeline.png\">timeline.png</file>\n\t\t<file alias=\"timeline_frames.png\">timeline_frames.png</file>\n\t\t<file alias=\"time_back.png\">time_back.png</file>\n\t\t<file alias=\"time_forward.png\">time_forward.png</file>\n\t\t<file alias=\"color_swatch.png\">color_swatch.png</file>\n\t\t<file alias=\"font.png\">font.png</file>\n\t\t<file alias=\"color_picker.png\">color_picker.png</file>\n\t\t<file alias=\"play.png\">play_green.png</file>\n\t\t<file alias=\"pause.png\">pause_green.png</file>\n\t\t<file alias=\"tick.png\">tick.png</file>\n\t\t<file alias=\"benchmark.png\">benchmark.png</file>\n\t\t<file alias=\"film_save.png\">film_save.png</file>\n\t\t<file alias=\"information.png\">information.png</file>\n\t\t<file alias=\"busy.png\">hourglass.png</file>\n\t\t<file alias=\"cross.png\">cross.png</file>\n\t\t<file alias=\"timeline_bookmark.png\">timeline_marker.png</file>\n\t\t<file alias=\"timeline_bookmark_add.png\">timeline_marker_add.png</file>\n\t\t<file alias=\"timeline_bookmark_remove.png\">timeline_marker_remove.png</file>\n\t\t<file alias=\"timeline_bookmark_previous.png\">timeline_marker_previous.png</file>\n\t\t<file alias=\"timeline_bookmark_next.png\">timeline_marker_next.png</file>\n\t\t<file alias=\"jobs.png\">sheduled_task.png</file>\n\n\t\t<file alias=\"readme\">../README</file>\n\n\t\t<file alias=\"fonts/DigitalMini.ttf\">fonts/DigitalMini.ttf</file>\n\t</qresource>\n</RCC>\n"
  },
  {
    "path": "vsedit/src/frame_consumers/benchmark_dialog.cpp",
    "content": "#include \"benchmark_dialog.h\"\n\n#include \"../../../common-src/helpers.h\"\n#include \"../../../common-src/vapoursynth/vapoursynth_script_processor.h\"\n#include \"../../../common-src/settings/settings_manager.h\"\n\n#include <VapourSynth4.h>\n\n//==============================================================================\n\nScriptBenchmarkDialog::ScriptBenchmarkDialog(\n\tSettingsManager * a_pSettingsManager, VSScriptLibrary * a_pVSScriptLibrary,\n\tQWidget * a_pParent):\n\tVSScriptProcessorDialog(a_pSettingsManager, a_pVSScriptLibrary, a_pParent,\n\t      Qt::Window\n\t\t| Qt::CustomizeWindowHint\n\t\t| Qt::WindowMinimizeButtonHint\n\t\t| Qt::WindowCloseButtonHint\n\t\t)\n\t, m_processing(false)\n\t, m_framesTotal(0)\n\t, m_framesProcessed(0)\n\t, m_framesFailed(0)\n\t, m_lastFromFrame(-1)\n\t, m_lastToFrame(-1)\n{\n\tvsedit::disableFontKerning(this);\n\tm_ui.setupUi(this);\n\tsetWindowIcon(QIcon(\":benchmark.png\"));\n\n\tcreateStatusBar();\n\n\tm_ui.feedbackTextEdit->setName(\"benchmark_log\");\n\tm_ui.feedbackTextEdit->setSettingsManager(m_pSettingsManager);\n\tm_ui.feedbackTextEdit->loadSettings();\n\n\tconnect(m_ui.wholeVideoButton, SIGNAL(clicked()),\n\t\tthis, SLOT(slotWholeVideoButtonPressed()));\n\tconnect(m_ui.startStopBenchmarkButton, SIGNAL(clicked()),\n\t\tthis, SLOT(slotStartStopBenchmarkButtonPressed()));\n}\n\n// END OF ScriptBenchmarkDialog::ScriptBenchmarkDialog(\n//\t\tSettingsManager * a_pSettingsManager,\n//\t\tVSScriptLibrary * a_pVSScriptLibrary, QWidget * a_pParent\n//==============================================================================\n\nScriptBenchmarkDialog::~ScriptBenchmarkDialog()\n{\n}\n\n// END OF ScriptBenchmarkDialog::~ScriptBenchmarkDialog()\n//==============================================================================\n\nbool ScriptBenchmarkDialog::initialize(const QString & a_script,\n\tconst QString & a_scriptName, ProcessReason a_reason)\n{\n\tbool initialized = VSScriptProcessorDialog::initialize(a_script,\n\t\ta_scriptName, a_reason);\n\tif(!initialized)\n\t\temit signalWriteLogMessage(mtCritical,\n\t\t\tm_pVapourSynthScriptProcessor->error());\n\treturn initialized;\n}\n\n// END OF bool ScriptBenchmarkDialog::initialize(const QString & a_script,\n//\t\tconst QString & a_scriptName)\n//==============================================================================\n\nvoid ScriptBenchmarkDialog::resetSavedRange()\n{\n\tm_lastFromFrame = -1;\n\tm_lastToFrame = -1;\n}\n\n// END OF void ScriptBenchmarkDialog::resetSavedRange()\n//==============================================================================\n\nvoid ScriptBenchmarkDialog::call()\n{\n\tif(m_processing)\n\t{\n\t\tshow();\n\t\treturn;\n\t}\n\n\tif((!m_pVapourSynthScriptProcessor->isInitialized()) || m_wantToFinalize)\n\t\treturn;\n\n\tQ_ASSERT(!m_nodeInfo[0].isInvalid());\n\n\tm_ui.feedbackTextEdit->clear();\n\tsetWindowTitle(tr(\"Benchmark: %1\").arg(scriptName()));\n\tQString text = tr(\"Ready to benchmark script %1\").arg(scriptName());\n\tm_ui.feedbackTextEdit->addEntry(text);\n\tm_ui.metricsEdit->clear();\n\tint firstFrame = 0;\n\tint lastFrame = m_nodeInfo[0].numFrames() - 1;\n\tm_ui.fromFrameSpinBox->setMaximum(lastFrame);\n\tm_ui.toFrameSpinBox->setMaximum(lastFrame);\n\tm_ui.processingProgressBar->setMaximum(m_nodeInfo[0].numFrames());\n\tm_ui.processingProgressBar->setValue(0);\n\n\tif(m_lastFromFrame >= 0)\n\t\tfirstFrame = std::min(m_lastFromFrame, lastFrame);\n\tm_ui.fromFrameSpinBox->setValue(firstFrame);\n\n\tif(m_lastToFrame >= 0)\n\t\tlastFrame = std::min(m_lastToFrame, lastFrame);\n\tm_ui.toFrameSpinBox->setValue(lastFrame);\n\n\tshow();\n}\n\n// END OF void ScriptBenchmarkDialog::call()\n//==============================================================================\n\nvoid ScriptBenchmarkDialog::stopAndCleanUp()\n{\n\tstopProcessing();\n\tm_ui.metricsEdit->clear();\n\tm_ui.processingProgressBar->setValue(0);\n}\n\n// END OF void ScriptBenchmarkDialog::stopAndCleanUp()\n//==============================================================================\n\nvoid ScriptBenchmarkDialog::slotWriteLogMessage(int a_messageType,\n\tconst QString & a_message)\n{\n\tQString style = vsMessageTypeToStyleName(a_messageType);\n\n\tQString debugTypes[] = {\n\t\tLOG_STYLE_DEBUG,\n\t\tLOG_STYLE_QT_DEBUG,\n\t\tLOG_STYLE_VS_DEBUG,\n\t};\n\tif(m_pSettingsManager->getShowDebugMessages() ||\n\t\t!vsedit::contains(debugTypes, style))\n\t{\n\t\tm_ui.feedbackTextEdit->addEntry(a_message, style);\n\t}\n}\n\n// END OF void ScriptBenchmarkDialog::slotWriteLogMessage(int a_messageType,\n//\t\tconst QString & a_message)\n//==============================================================================\n\nvoid ScriptBenchmarkDialog::slotWholeVideoButtonPressed()\n{\n\tQ_ASSERT(!m_nodeInfo[0].isInvalid());\n\tint lastFrame = m_nodeInfo[0].numFrames() - 1;\n\tm_ui.fromFrameSpinBox->setValue(0);\n\tm_ui.toFrameSpinBox->setValue(lastFrame);\n}\n\n// END OF void ScriptBenchmarkDialog::slotWholeVideoButtonPressed()\n//==============================================================================\n\nvoid ScriptBenchmarkDialog::slotStartStopBenchmarkButtonPressed()\n{\n\tif(m_processing)\n\t{\n\t\tstopProcessing();\n\t\treturn;\n\t}\n\n\tm_framesProcessed = 0;\n\tm_framesFailed = 0;\n\tint firstFrame = m_ui.fromFrameSpinBox->value();\n\tint lastFrame = m_ui.toFrameSpinBox->value();\n\n\tif(firstFrame > lastFrame)\n\t{\n\t\tm_ui.feedbackTextEdit->addEntry(tr(\n\t\t\t\"First frame number is larger than the last frame number.\"),\n\t\t\tLOG_STYLE_WARNING);\n\t\t\treturn;\n\t}\n\n\tm_framesTotal = lastFrame - firstFrame + 1;\n\tm_ui.processingProgressBar->setMaximum(m_framesTotal);\n\tm_ui.startStopBenchmarkButton->setText(tr(\"Stop\"));\n\tsetWindowTitle(tr(\"0% Benchmark: %1\").arg(scriptName()));\n\n\tm_lastFromFrame = firstFrame;\n\tm_lastToFrame = lastFrame;\n\n\tm_processing = true;\n\tm_benchmarkStartTime = hr_clock::now();\n\n\tfor(int i = firstFrame; i <= lastFrame; ++i)\n\t\tm_pVapourSynthScriptProcessor->requestFrameAsync(i);\n}\n\n// END OF void ScriptBenchmarkDialog::slotStartStopBenchmarkButtonPressed()\n//==============================================================================\n\nvoid ScriptBenchmarkDialog::slotReceiveFrame(int a_frameNumber,\n\tint a_outputIndex, const VSFrame * a_cpOutputFrame,\n\tconst VSFrame * a_cpPreviewFrame)\n{\n\t(void)a_frameNumber;\n\t(void)a_outputIndex;\n\t(void)a_cpOutputFrame;\n\t(void)a_cpPreviewFrame;\n\n\tif(!m_processing)\n\t\treturn;\n\n\tm_framesProcessed++;\n\tupdateMetrics();\n}\n\n// END OF void ScriptBenchmarkDialog::slotReceiveFrame(int a_frameNumber,\n//\t\tint a_outputIndex, const VSFrame * a_cpOutputFrame,\n//\t\tconst VSFrame * a_cpPreviewFrame)\n//==============================================================================\n\nvoid ScriptBenchmarkDialog::slotFrameRequestDiscarded(int a_frameNumber,\n\tint a_outputIndex, const QString & a_reason)\n{\n\t(void)a_frameNumber;\n\t(void)a_outputIndex;\n\t(void)a_reason;\n\n\tif(!m_processing)\n\t\treturn;\n\n\tm_framesProcessed++;\n\tm_framesFailed++;\n\tupdateMetrics();\n}\n\n// END OF void ScriptBenchmarkDialog::slotFrameRequestDiscarded(\n//\t\tint a_frameNumber, int a_outputIndex, const QString & a_reason)\n//==============================================================================\n\nvoid ScriptBenchmarkDialog::stopProcessing()\n{\n\tif(!m_processing)\n\t\treturn;\n\n\tm_processing = false;\n\tm_pVapourSynthScriptProcessor->flushFrameTicketsQueue();\n\tm_ui.startStopBenchmarkButton->setText(tr(\"Start\"));\n}\n\n// END OF void ScriptBenchmarkDialog::stopProcessing()\n//==============================================================================\n\nvoid ScriptBenchmarkDialog::updateMetrics()\n{\n\thr_time_point now = hr_clock::now();\n\tm_ui.processingProgressBar->setValue(m_framesProcessed);\n\tdouble passed = duration_to_double(now - m_benchmarkStartTime);\n\tQString passedString = vsedit::timeToString(passed);\n\tdouble fps = (double)m_framesProcessed / passed;\n\tQString text = tr(\"Time elapsed: %1 - %2 FPS\")\n\t\t.arg(passedString).arg(QString::number(fps, 'f', 20));\n\n\tif(m_framesFailed > 0)\n\t\ttext += tr(\"; %1 frames failed\").arg(m_framesFailed);\n\n\tif(m_framesProcessed < m_framesTotal)\n\t{\n\t\tdouble estimated = (m_framesTotal - m_framesProcessed) / fps;\n\t\tQString estimatedString = vsedit::timeToString(estimated);\n\t\ttext += tr(\"; estimated time to finish: %1\").arg(estimatedString);\n\t}\n\n\tm_ui.metricsEdit->setText(text);\n\n\tint percentage = (int)((double)m_framesProcessed * 100.0 /\n\t\t(double)m_framesTotal);\n\tsetWindowTitle(tr(\"%1% Benchmark: %2\")\n\t\t.arg(percentage).arg(scriptName()));\n\n\tif(m_framesProcessed == m_framesTotal)\n\t\tstopProcessing();\n}\n\n// END OF void ScriptBenchmarkDialog::updateMetrics()\n//==============================================================================\n\nvoid ScriptBenchmarkDialog::keyPressEvent(QKeyEvent * a_pEvent)\n{\n\tQt::KeyboardModifiers modifiers = a_pEvent->modifiers();\n\n\tif(modifiers != Qt::NoModifier)\n\t{\n\t\tQDialog::keyPressEvent(a_pEvent);\n\t\treturn;\n\t}\n\n\tif(a_pEvent->key() == Qt::Key_Escape)\n\t\tclose();\n\telse\n\t\tQDialog::keyPressEvent(a_pEvent);\n}\n\n// END OF void ScriptBenchmarkDialog::keyPressEvent(QKeyEvent * a_pEvent)\n//==============================================================================\n"
  },
  {
    "path": "vsedit/src/frame_consumers/benchmark_dialog.h",
    "content": "#ifndef BENCHMARK_DIALOG_H_INCLUDED\n#define BENCHMARK_DIALOG_H_INCLUDED\n\n#include <ui_benchmark_dialog.h>\n\n#include \"../vapoursynth/vs_script_processor_dialog.h\"\n#include \"../../../common-src/chrono.h\"\n\n#include <QKeyEvent>\n\nclass ScriptBenchmarkDialog : public VSScriptProcessorDialog\n{\n\tQ_OBJECT\n\npublic:\n\n\tScriptBenchmarkDialog(SettingsManager * a_pSettingsManager,\n\t\tVSScriptLibrary * a_pVSScriptLibrary,\n\t\tQWidget * a_pParent = nullptr);\n\tvirtual ~ScriptBenchmarkDialog();\n\n\tvirtual bool initialize(const QString & a_script,\n\t\tconst QString & a_scriptName,\n\t\tProcessReason a_reason = ProcessReason::Benchmark) override;\n\n\tvoid resetSavedRange();\n\npublic slots:\n\n\tvoid call();\n\nprotected slots:\n\n\tvirtual void slotWriteLogMessage(int a_messageType,\n\t\tconst QString & a_message) override;\n\n\tvirtual void slotReceiveFrame(int a_frameNumber, int a_outputIndex,\n\t\tconst VSFrame * a_cpOutputFrame,\n\t\tconst VSFrame * a_cpPreviewFrame) override;\n\n\tvirtual void slotFrameRequestDiscarded(int a_frameNumber,\n\tint a_outputIndex, const QString & a_reason) override;\n\n\tvoid slotWholeVideoButtonPressed();\n\n\tvoid slotStartStopBenchmarkButtonPressed();\n\nprotected:\n\n\tvirtual void stopAndCleanUp() override;\n\n\tvoid stopProcessing();\n\n\tvoid updateMetrics();\n\n\tvoid keyPressEvent(QKeyEvent * a_pEvent);\n\n\tUi::ScriptBenchmarkDialog m_ui;\n\n\tbool m_processing;\n\n\tint m_framesTotal;\n\tint m_framesProcessed;\n\tint m_framesFailed;\n\n\thr_time_point m_benchmarkStartTime;\n\n\tint m_lastFromFrame;\n\tint m_lastToFrame;\n\n};\n\n#endif // BENCHMARK_DIALOG_H_INCLUDED\n"
  },
  {
    "path": "vsedit/src/frame_consumers/benchmark_dialog.ui",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<ui version=\"4.0\">\n <class>ScriptBenchmarkDialog</class>\n <widget class=\"QDialog\" name=\"ScriptBenchmarkDialog\">\n  <property name=\"geometry\">\n   <rect>\n    <x>0</x>\n    <y>0</y>\n    <width>400</width>\n    <height>191</height>\n   </rect>\n  </property>\n  <property name=\"windowTitle\">\n   <string>Script benchmark</string>\n  </property>\n  <layout class=\"QVBoxLayout\" name=\"verticalLayout\">\n   <property name=\"spacing\">\n    <number>4</number>\n   </property>\n   <property name=\"leftMargin\">\n    <number>4</number>\n   </property>\n   <property name=\"topMargin\">\n    <number>4</number>\n   </property>\n   <property name=\"rightMargin\">\n    <number>4</number>\n   </property>\n   <property name=\"bottomMargin\">\n    <number>4</number>\n   </property>\n   <item>\n    <widget class=\"VSEditorLog\" name=\"feedbackTextEdit\">\n     <property name=\"readOnly\">\n      <bool>true</bool>\n     </property>\n     <property name=\"textInteractionFlags\">\n      <set>Qt::LinksAccessibleByKeyboard|Qt::LinksAccessibleByMouse|Qt::TextBrowserInteraction|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set>\n     </property>\n    </widget>\n   </item>\n   <item>\n    <widget class=\"QLineEdit\" name=\"metricsEdit\">\n     <property name=\"readOnly\">\n      <bool>true</bool>\n     </property>\n    </widget>\n   </item>\n   <item>\n    <widget class=\"QProgressBar\" name=\"processingProgressBar\">\n     <property name=\"alignment\">\n      <set>Qt::AlignCenter</set>\n     </property>\n     <property name=\"format\">\n      <string>%v / %m</string>\n     </property>\n    </widget>\n   </item>\n   <item>\n    <layout class=\"QHBoxLayout\" name=\"horizontalLayout\">\n     <property name=\"spacing\">\n      <number>4</number>\n     </property>\n     <item>\n      <widget class=\"QLabel\" name=\"framesLabel\">\n       <property name=\"text\">\n        <string>Frames:</string>\n       </property>\n      </widget>\n     </item>\n     <item>\n      <widget class=\"QSpinBox\" name=\"fromFrameSpinBox\"/>\n     </item>\n     <item>\n      <widget class=\"QLabel\" name=\"toLabel\">\n       <property name=\"text\">\n        <string>to</string>\n       </property>\n      </widget>\n     </item>\n     <item>\n      <widget class=\"QSpinBox\" name=\"toFrameSpinBox\"/>\n     </item>\n     <item>\n      <widget class=\"QPushButton\" name=\"wholeVideoButton\">\n       <property name=\"text\">\n        <string>Full length</string>\n       </property>\n      </widget>\n     </item>\n     <item>\n      <spacer name=\"horizontalSpacer\">\n       <property name=\"orientation\">\n        <enum>Qt::Horizontal</enum>\n       </property>\n       <property name=\"sizeHint\" stdset=\"0\">\n        <size>\n         <width>13</width>\n         <height>20</height>\n        </size>\n       </property>\n      </spacer>\n     </item>\n     <item>\n      <widget class=\"QPushButton\" name=\"startStopBenchmarkButton\">\n       <property name=\"text\">\n        <string>Start</string>\n       </property>\n       <property name=\"default\">\n        <bool>true</bool>\n       </property>\n      </widget>\n     </item>\n    </layout>\n   </item>\n  </layout>\n </widget>\n <customwidgets>\n  <customwidget>\n   <class>VSEditorLog</class>\n   <extends>QTextEdit</extends>\n   <header>../../../common-src/log/vs_editor_log.h</header>\n  </customwidget>\n </customwidgets>\n <resources/>\n <connections/>\n</ui>\n"
  },
  {
    "path": "vsedit/src/frame_consumers/encode_dialog.cpp",
    "content": "#include \"encode_dialog.h\"\n\n#include \"../../../common-src/helpers.h\"\n#include \"../../../common-src/settings/settings_manager.h\"\n\n#include <VapourSynth4.h>\n#include <VSHelper4.h>\n\n#include <QMessageBox>\n#include <QFileDialog>\n#include <algorithm>\n\n//==============================================================================\n\nEncodeDialog::EncodeDialog(SettingsManager * a_pSettingsManager,\n\tVSScriptLibrary * a_pVSScriptLibrary, QWidget * a_pParent) :\n\tQDialog(a_pParent,\n\t\t  Qt::Window\n\t\t| Qt::CustomizeWindowHint\n\t\t| Qt::WindowMinimizeButtonHint\n\t\t| Qt::WindowCloseButtonHint\n\t\t)\n\t, m_pSettingsManager(a_pSettingsManager)\n\t, m_pJob(nullptr)\n{\n\tvsedit::disableFontKerning(this);\n\tm_ui.setupUi(this);\n\n\tm_pJob = new vsedit::Job(JobProperties(), a_pSettingsManager,\n\t\ta_pVSScriptLibrary, this);\n\n\tsetUpEncodingPresets();\n\n\tm_ui.feedbackTextEdit->setName(\"encode_log\");\n\tm_ui.feedbackTextEdit->setSettingsManager(m_pSettingsManager);\n\tm_ui.feedbackTextEdit->loadSettings();\n\n\tconnect(m_ui.wholeVideoButton, SIGNAL(clicked()),\n\t\tthis, SLOT(slotWholeVideoButtonPressed()));\n\tconnect(m_ui.startEncodeButton, SIGNAL(clicked()),\n\t\tthis, SLOT(slotStartEncodeButtonPressed()));\n\tconnect(m_ui.pauseEncodeButton, SIGNAL(clicked()),\n\t\tm_pJob, SLOT(pause()));\n\tconnect(m_ui.abortEncodeButton, SIGNAL(clicked()),\n\t\tm_pJob, SLOT(abort()));\n\tconnect(m_ui.executableBrowseButton, SIGNAL(clicked()),\n\t\tthis, SLOT(slotExecutableBrowseButtonPressed()));\n\tconnect(m_ui.argumentsHelpButton, SIGNAL(clicked()),\n\t\tthis, SLOT(slotArgumentsHelpButtonPressed()));\n\n\tconnect(m_pJob, &vsedit::Job::signalStateChanged,\n\t\tthis, &EncodeDialog::slotJobStateChanged);\n\tconnect(m_pJob, &vsedit::Job::signalProgressChanged,\n\t\tthis, &EncodeDialog::slotJobProgressChanged);\n\tconnect(m_pJob, &vsedit::Job::signalPropertiesChanged,\n\t\tthis, &EncodeDialog::slotJobPropertiesChanged);\n\tconnect(m_pJob, SIGNAL(signalLogMessage(const QString &, const QString &)),\n\t\tthis, SLOT(slotWriteLogMessage(const QString &, const QString &)));\n}\n\n// END OF EncodeDialog::EncodeDialog(SettingsManager * a_pSettingsManager,\n//\t\tVSScriptLibrary * a_pVSScriptLibrary, QWidget * a_pParent)\n//==============================================================================\n\nEncodeDialog::~EncodeDialog()\n{\n}\n\n// END OF EncodeDialog::~EncodeDialog()\n//==============================================================================\n\nbool EncodeDialog::initialize(const QString & a_script,\n\tconst QString & a_scriptName)\n{\n\tif(m_pJob->isActive())\n\t\treturn false;\n\n\tJobProperties properties;\n\tproperties.scriptName = a_scriptName;\n\tproperties.scriptText = a_script;\n\tm_pJob->setProperties(properties);\n\tbool initialized = m_pJob->initialize();\n\tif(!initialized)\n\t\treturn false;\n\n\tproperties = m_pJob->properties();\n\tconst VSVideoInfo * cpVideoInfo = m_pJob->videoInfo();\n\tQ_ASSERT(cpVideoInfo);\n\n\tm_ui.feedbackTextEdit->clear();\n\tsetWindowTitle(tr(\"Encode: %1\").arg(a_scriptName));\n\tQString text = tr(\"Ready to encode script %1\").arg(a_scriptName);\n\tm_ui.feedbackTextEdit->addEntry(text);\n\tm_ui.metricsEdit->clear();\n\tint lastFrame = cpVideoInfo->numFrames - 1;\n\tm_ui.fromFrameSpinBox->setMaximum(lastFrame);\n\tm_ui.toFrameSpinBox->setMaximum(lastFrame);\n\tm_ui.fromFrameSpinBox->setValue(properties.firstFrameReal);\n\tm_ui.toFrameSpinBox->setValue(properties.lastFrameReal);\n\tm_ui.processingProgressBar->setMaximum(lastFrame);\n\tm_ui.processingProgressBar->setValue(0);\n\n\tsetUiEnabled();\n\n\treturn true;\n}\n\n// END OF bool EncodeDialog::initialize(const QString & a_script,\n//\t\tconst QString & a_scriptName)\n//==============================================================================\n\nbool EncodeDialog::busy() const\n{\n\treturn m_pJob->isActive();\n}\n\n// END OF bool EncodeDialog::busy() const\n//==============================================================================\n\nvoid EncodeDialog::showActive()\n{\n\tif(isMinimized())\n\t\tshowNormal();\n\telse\n\t\tshow();\n\tactivateWindow();\n}\n\n// END OF void EncodeDialog::showActive()\n//==============================================================================\n\nvoid EncodeDialog::showEvent(QShowEvent * a_pEvent)\n{\n\tQDialog::showEvent(a_pEvent);\n}\n\n// END OF void EncodeDialog::showEvent(QShowEvent * a_pEvent)\n//==============================================================================\n\nvoid EncodeDialog::closeEvent(QCloseEvent * a_pEvent)\n{\n\tif(m_pJob->isActive())\n\t{\n\t\ta_pEvent->ignore();\n\t\treturn;\n\t}\n\n\tm_pJob->cleanUpEncoding();\n\n\tQDialog::closeEvent(a_pEvent);\n}\n\n// END OF void EncodeDialog::closeEvent(QCloseEvent * a_pEvent)\n//==============================================================================\n\nvoid EncodeDialog::slotWholeVideoButtonPressed()\n{\n\tconst VSVideoInfo * cpVideoInfo = m_pJob->videoInfo();\n\tQ_ASSERT(cpVideoInfo);\n\tint lastFrame = cpVideoInfo->numFrames - 1;\n\tm_ui.fromFrameSpinBox->setValue(0);\n\tm_ui.toFrameSpinBox->setValue(lastFrame);\n}\n\n// END OF void EncodeDialog::slotWholeVideoButtonPressed()\n//==============================================================================\n\nvoid EncodeDialog::slotStartEncodeButtonPressed()\n{\n\tif(m_pJob->state() == JobState::Paused)\n\t{\n\t\tm_pJob->start();\n\t\treturn;\n\t}\n\n\tif(m_pJob->isActive())\n\t\treturn;\n\n\tint firstFrame = m_ui.fromFrameSpinBox->value();\n\tint lastFrame = m_ui.toFrameSpinBox->value();\n\n\tif(firstFrame > lastFrame)\n\t{\n\t\tm_ui.feedbackTextEdit->addEntry(tr(\"First frame number is \"\n\t\t\t\"larger than the last frame number.\"), LOG_STYLE_WARNING);\n\t\treturn;\n\t}\n\n\tm_pJob->setFirstFrame(firstFrame);\n\tm_pJob->setLastFrame(lastFrame);\n\tm_pJob->setExecutablePath(vsedit::resolvePathFromApplication(\n\t\tm_ui.executablePathEdit->text()));\n\tm_pJob->setArguments(m_ui.argumentsTextEdit->toPlainText());\n\tm_pJob->setEncodingHeaderType((EncodingHeaderType)\n\t\tm_ui.headerTypeComboBox->currentData().toInt());\n\tm_pJob->start();\n}\n\n// END OF void EncodeDialog::slotStartEncodeButtonPressed()\n//==============================================================================\n\nvoid EncodeDialog::slotExecutableBrowseButtonPressed()\n{\n\tQString applicationPath = QCoreApplication::applicationDirPath();\n\tQFileDialog fileDialog;\n\tfileDialog.setWindowTitle(tr(\"Choose encoder executable\"));\n\tfileDialog.setDirectory(applicationPath);\n\n\tif(!fileDialog.exec())\n\t\treturn;\n\n\tQStringList filesList = fileDialog.selectedFiles();\n\tm_ui.executablePathEdit->setText(filesList[0]);\n}\n\n// END OF void EncodeDialog::slotExecutableBrowseButtonPressed()\n//==============================================================================\n\nvoid EncodeDialog::slotArgumentsHelpButtonPressed()\n{\n\tJobVariables variables;\n\tQString argumentsHelpString = tr(\"Use following placeholders:\");\n\tfor(const vsedit::VariableToken & variable : variables.variables())\n\t{\n\t\targumentsHelpString += QString(\"\\n%1 - %2\")\n\t\t\t.arg(variable.token).arg(variable.description);\n\t}\n\tQString title = tr(\"Encoder arguments\");\n\tQMessageBox msgBox(this);\n\tmsgBox.setWindowTitle(title);\n\tmsgBox.setText(argumentsHelpString);\n\tvsedit::disableFontKerning(&msgBox);\n\tmsgBox.exec();\n}\n\n// END OF void EncodeDialog::slotArgumentsHelpButtonPressed()\n//==============================================================================\n\nvoid EncodeDialog::slotEncodingPresetSaveButtonPressed()\n{\n\tEncodingPreset preset(m_ui.encodingPresetComboBox->currentText());\n\tif(preset.name.isEmpty())\n\t{\n\t\tm_ui.feedbackTextEdit->addEntry(\n\t\t\ttr(\"Preset name must not be empty.\"), LOG_STYLE_WARNING);\n\t\treturn;\n\t}\n\n\tif(preset.type == EncodingType::CLI)\n\t{\n\t\tpreset.executablePath = m_ui.executablePathEdit->text();\n\t\tif(preset.executablePath.isEmpty())\n\t\t{\n\t\t\tm_ui.feedbackTextEdit->addEntry(\n\t\t\t\ttr(\"Executable path must not be empty.\"),\n\t\t\t\tLOG_STYLE_WARNING);\n\t\t\treturn;\n\t\t}\n\n\t\tpreset.arguments = m_ui.argumentsTextEdit->toPlainText();\n\t}\n\n\tpreset.headerType = (EncodingHeaderType)\n\t\tm_ui.headerTypeComboBox->currentData().toInt();\n\n\tbool success = m_pSettingsManager->saveEncodingPreset(preset);\n\tif(!success)\n\t{\n\t\tm_ui.feedbackTextEdit->addEntry(tr(\"Error saving preset.\"),\n\t\t\tLOG_STYLE_ERROR);\n\t\treturn;\n\t}\n\n\tstd::vector<EncodingPreset>::iterator it = std::find(\n\t\tm_encodingPresets.begin(), m_encodingPresets.end(), preset);\n\tif(it == m_encodingPresets.end())\n\t{\n\t\tQ_ASSERT(m_ui.encodingPresetComboBox->findText(preset.name) == -1);\n\t\tm_encodingPresets.push_back(preset);\n\t\tm_ui.encodingPresetComboBox->addItem(preset.name);\n\t\tm_ui.encodingPresetComboBox->model()->sort(0);\n\t}\n\telse\n\t{\n\t\tQ_ASSERT(m_ui.encodingPresetComboBox->findText(preset.name) != -1);\n\t\t*it = preset;\n\t}\n\n\tm_ui.feedbackTextEdit->addEntry(tr(\"Preset \\'%1\\' saved.\")\n\t\t.arg(preset.name), LOG_STYLE_POSITIVE);\n}\n\n// END OF void EncodeDialog::slotEncodingPresetSaveButtonPressed()\n//==============================================================================\n\nvoid EncodeDialog::slotEncodingPresetDeleteButtonPressed()\n{\n\tEncodingPreset preset(m_ui.encodingPresetComboBox->currentText());\n\tif(preset.name.isEmpty())\n\t\treturn;\n\n\tQMessageBox quesBox(this);\n\tvsedit::disableFontKerning(&quesBox);\n\tquesBox.setWindowTitle(tr(\"Delete preset\"));\n\tquesBox.setText(tr(\"Do you really want to delete \"\n\t\t\"preset \\'%1\\'?\").arg(preset.name));\n\tquesBox.setStandardButtons(QMessageBox::Yes | QMessageBox::No);\n\tquesBox.setDefaultButton(QMessageBox::No);\n\tint result = quesBox.exec();\n\tif(result == QMessageBox::No)\n\t\treturn;\n\n\tstd::vector<EncodingPreset>::iterator it = std::find(\n\t\tm_encodingPresets.begin(), m_encodingPresets.end(), preset);\n\tif(it == m_encodingPresets.end())\n\t{\n\t\tQ_ASSERT(m_ui.encodingPresetComboBox->findText(preset.name) == -1);\n\t\tm_ui.feedbackTextEdit->addEntry(tr(\"Error deleting preset. \"\n\t\t\t\"Preset was never saved.\"), LOG_STYLE_ERROR);\n\t\treturn;\n\t}\n\n\tint index = m_ui.encodingPresetComboBox->findText(preset.name);\n\tQ_ASSERT(index != -1);\n\tm_ui.encodingPresetComboBox->removeItem(index);\n\tm_encodingPresets.erase(it);\n\tm_ui.encodingPresetComboBox->setCurrentIndex(0);\n\tslotEncodingPresetComboBoxActivated(\n\t\tm_ui.encodingPresetComboBox->currentText());\n\n\tbool success = m_pSettingsManager->deleteEncodingPreset(preset.name);\n\tif(!success)\n\t{\n\t\tm_ui.feedbackTextEdit->addEntry(tr(\"Error deleting \"\n\t\t\t\"preset \\'%1\\'.\").arg(preset.name), LOG_STYLE_ERROR);\n\t\treturn;\n\t}\n\n\tm_ui.feedbackTextEdit->addEntry(tr(\"Preset \\'%1\\' deleted.\")\n\t\t.arg(preset.name), LOG_STYLE_POSITIVE);\n}\n\n// END OF void EncodeDialog::slotEncodingPresetDeleteButtonPressed()\n//==============================================================================\n\nvoid EncodeDialog::slotEncodingPresetComboBoxActivated(const QString & a_text)\n{\n\tif(a_text.isEmpty())\n\t{\n\t\tm_ui.executablePathEdit->clear();\n\t\tm_ui.argumentsTextEdit->clear();\n\t\treturn;\n\t}\n\n\tEncodingPreset preset(a_text);\n\n\tstd::vector<EncodingPreset>::iterator it = std::find(\n\t\tm_encodingPresets.begin(), m_encodingPresets.end(), preset);\n\tif(it == m_encodingPresets.end())\n\t{\n\t\tm_ui.feedbackTextEdit->addEntry(tr(\"Error. There is no preset \"\n\t\t\t\"named \\'%1\\'.\").arg(preset.name), LOG_STYLE_ERROR);\n\t\treturn;\n\t}\n\n\tpreset = *it;\n\n\tm_ui.executablePathEdit->setText(preset.executablePath);\n\tm_ui.argumentsTextEdit->setPlainText(preset.arguments);\n\n\tint headerTypeIndex =\n\t\tm_ui.headerTypeComboBox->findData((int)preset.headerType);\n\tif(headerTypeIndex < 0)\n\t{\n\t\tm_ui.feedbackTextEdit->addEntry(tr(\"Error. Preset \\'%1\\' \"\n\t\t\t\"has unknown header type.\").arg(preset.name), LOG_STYLE_ERROR);\n\t\theaderTypeIndex = 0;\n\t}\n\tm_ui.headerTypeComboBox->setCurrentIndex(headerTypeIndex);\n}\n\n// END OF void EncodeDialog::slotEncodingPresetComboBoxActivated(\n//\t\tconst QString & a_text)\n//==============================================================================\n\nvoid EncodeDialog::slotJobStateChanged(JobState a_newState, JobState a_oldState)\n{\n\tsetUiEnabled();\n\n\tJobProperties properties = m_pJob->properties();\n\n\tJobState pauseStates[] = {JobState::Pausing, JobState::Paused};\n\n\tJobState failStates[] = {JobState::FailedCleanUp, JobState::Failed,\n\t\tJobState::Aborted, JobState::Aborting};\n\n\tif(a_newState == JobState::Running)\n\t{\n\t\tJobState idleStates[] = {JobState::Waiting, JobState::Failed,\n\t\t\tJobState::Aborted, JobState::Completed};\n\t\tif(!vsedit::contains(idleStates, a_oldState))\n\t\t\treturn;\n\n\t\tsetWindowTitle(tr(\"0% Encode: %1\").arg(properties.scriptName));\n\n\t\tm_ui.processingProgressBar->setMaximum(properties.framesTotal());\n\t\tm_ui.processingProgressBar->setValue(0);\n\t}\n}\n\n// END OF void EncodeDialog::slotJobStateChanged(JobState a_newState,\n//\t\tJobState a_oldState)\n//==============================================================================\n\nvoid EncodeDialog::slotJobProgressChanged()\n{\n\tJobProperties properties = m_pJob->properties();\n\n\tm_ui.processingProgressBar->setValue(properties.framesProcessed);\n\n\tQDateTime now = QDateTime::currentDateTimeUtc();\n\tdouble passed = ((double)properties.timeStarted.msecsTo(now)) / 1000.0;\n\tQString passedString = vsedit::timeToString(passed);\n\n\tQString text = tr(\"Time elapsed: %1 - %2 FPS\")\n\t\t.arg(passedString).arg(QString::number(properties.fps, 'f', 20));\n\n\tif((properties.framesProcessed > 0) &&\n\t\t(properties.framesProcessed < properties.framesTotal()))\n\t{\n\t\tQ_ASSERT(properties.fps > 0.0);\n\t\tdouble estimated = (properties.framesTotal() -\n\t\t\tproperties.framesProcessed) / properties.fps;\n\t\tQString estimatedString = vsedit::timeToString(estimated);\n\t\ttext += tr(\"; estimated time to finish: %1\")\n\t\t\t.arg(estimatedString);\n\t}\n\n\tm_ui.metricsEdit->setText(text);\n\n\tint percentage = (int)((double)properties.framesProcessed * 100.0 /\n\t\t(double)properties.framesTotal());\n\tsetWindowTitle(tr(\"%1% Encode: %2\")\n\t\t.arg(percentage).arg(properties.scriptName));\n}\n\n// END OF void EncodeDialog::slotJobProgressChanged()\n//==============================================================================\n\nvoid EncodeDialog::slotJobPropertiesChanged()\n{\n\tJobProperties properties = m_pJob->properties();\n\tm_ui.processingProgressBar->setMaximum(properties.framesTotal());\n}\n\n// END OF void EncodeDialog::slotJobPropertiesChanged()\n//==============================================================================\n\nvoid EncodeDialog::slotWriteLogMessage(const QString & a_message,\n\tconst QString & a_style)\n{\n\tif(!isVisible())\n\t\temit signalWriteLogMessage(a_message, a_style);\n\telse\n\t{\n\t\tQString debugTypes[] = {\n\t\t\tLOG_STYLE_DEBUG,\n\t\t\tLOG_STYLE_QT_DEBUG,\n\t\t\tLOG_STYLE_VS_DEBUG,\n\t\t};\n\t\tif(m_pSettingsManager->getShowDebugMessages() ||\n\t\t\t!vsedit::contains(debugTypes, a_style))\n\t\t{\n\t\t\tm_ui.feedbackTextEdit->addEntry(a_message, a_style);\n\t\t}\n\t}\n}\n\n// END OF void EncodeDialog::slotWriteLogMessage(const QString & a_message,\n//\t\tconst QString & a_style)\n//==============================================================================\n\nvoid EncodeDialog::setUpEncodingPresets()\n{\n\tm_encodingPresets = m_pSettingsManager->getAllEncodingPresets();\n\tfor(const EncodingPreset & preset : m_encodingPresets)\n\t\tm_ui.encodingPresetComboBox->addItem(preset.name);\n\n\tm_ui.headerTypeComboBox->addItem(tr(\"No header\"),\n\t\t(int)EncodingHeaderType::NoHeader);\n\tm_ui.headerTypeComboBox->addItem(tr(\"Y4M\"),\n\t\t(int)EncodingHeaderType::Y4M);\n\n\tconnect(m_ui.encodingPresetSaveButton, SIGNAL(clicked()),\n\t\tthis, SLOT(slotEncodingPresetSaveButtonPressed()));\n\tconnect(m_ui.encodingPresetDeleteButton, SIGNAL(clicked()),\n\t\tthis, SLOT(slotEncodingPresetDeleteButtonPressed()));\n\tconnect(m_ui.encodingPresetComboBox, SIGNAL(textActivated(const QString &)),\n\t\tthis, SLOT(slotEncodingPresetComboBoxActivated(const QString &)));\n\n\tm_ui.encodingPresetComboBox->setCurrentIndex(0);\n\tslotEncodingPresetComboBoxActivated(\n\t\tm_ui.encodingPresetComboBox->currentText());\n}\n\n// END OF void EncodeDialog::setUpEncodingPresets()\n//==============================================================================\n\nvoid EncodeDialog::setUiEnabled()\n{\n}\n\n// END OF void EncodeDialog::setUiEnabled()\n//==============================================================================\n"
  },
  {
    "path": "vsedit/src/frame_consumers/encode_dialog.h",
    "content": "#ifndef ENCODE_DIALOG_H_INCLUDED\n#define ENCODE_DIALOG_H_INCLUDED\n\n#include <ui_encode_dialog.h>\n\n#include \"../../../common-src/jobs/job.h\"\n\nclass SettingsManager;\nclass VSScriptLibrary;\n\nclass EncodeDialog : public QDialog\n{\n\tQ_OBJECT\n\npublic:\n\n\tEncodeDialog(SettingsManager * a_pSettingsManager,\n\t\tVSScriptLibrary * a_pVSScriptLibrary,\n\t\tQWidget * a_pParent = nullptr);\n\tvirtual ~EncodeDialog();\n\n\tbool initialize(const QString & a_script, const QString & a_scriptName);\n\n\tbool busy() const;\n\npublic slots:\n\n\tvoid showActive();\n\nsignals:\n\n\tvoid signalWriteLogMessage(const QString & a_style,\n\t\tconst QString & a_message);\n\nprotected:\n\n\tvirtual void showEvent(QShowEvent * a_pEvent) override;\n\tvirtual void closeEvent(QCloseEvent * a_pEvent) override;\n\nprivate slots:\n\n\tvoid slotWholeVideoButtonPressed();\n\n\tvoid slotStartEncodeButtonPressed();\n\n\tvoid slotExecutableBrowseButtonPressed();\n\n\tvoid slotArgumentsHelpButtonPressed();\n\n\tvoid slotEncodingPresetSaveButtonPressed();\n\tvoid slotEncodingPresetDeleteButtonPressed();\n\tvoid slotEncodingPresetComboBoxActivated(const QString & a_text);\n\n\tvoid slotJobStateChanged(JobState a_newState, JobState a_oldState);\n\tvoid slotJobProgressChanged();\n\tvoid slotJobPropertiesChanged();\n\n\tvoid slotWriteLogMessage(const QString & a_message,\n\t\tconst QString & a_style);\n\nprivate:\n\n\tvoid setUpEncodingPresets();\n\n\tvoid setUiEnabled();\n\n\tUi::EncodeDialog m_ui;\n\n\tSettingsManager * m_pSettingsManager;\n\n\tvsedit::Job * m_pJob;\n\n\tstd::vector<EncodingPreset> m_encodingPresets;\n\n};\n\n#endif // ENCODE_DIALOG_H_INCLUDED\n"
  },
  {
    "path": "vsedit/src/frame_consumers/encode_dialog.ui",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<ui version=\"4.0\">\n <class>EncodeDialog</class>\n <widget class=\"QDialog\" name=\"EncodeDialog\">\n  <property name=\"geometry\">\n   <rect>\n    <x>0</x>\n    <y>0</y>\n    <width>677</width>\n    <height>648</height>\n   </rect>\n  </property>\n  <property name=\"windowTitle\">\n   <string>Encode video</string>\n  </property>\n  <property name=\"windowIcon\">\n   <iconset resource=\"../../../resources/vsedit.qrc\">\n    <normaloff>:/film_save.png</normaloff>:/film_save.png</iconset>\n  </property>\n  <layout class=\"QVBoxLayout\" name=\"verticalLayout\">\n   <property name=\"spacing\">\n    <number>4</number>\n   </property>\n   <property name=\"leftMargin\">\n    <number>4</number>\n   </property>\n   <property name=\"topMargin\">\n    <number>4</number>\n   </property>\n   <property name=\"rightMargin\">\n    <number>4</number>\n   </property>\n   <property name=\"bottomMargin\">\n    <number>4</number>\n   </property>\n   <item>\n    <widget class=\"VSEditorLog\" name=\"feedbackTextEdit\">\n     <property name=\"readOnly\">\n      <bool>true</bool>\n     </property>\n     <property name=\"textInteractionFlags\">\n      <set>Qt::LinksAccessibleByKeyboard|Qt::LinksAccessibleByMouse|Qt::TextBrowserInteraction|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set>\n     </property>\n    </widget>\n   </item>\n   <item>\n    <layout class=\"QHBoxLayout\" name=\"horizontalLayout_4\">\n     <property name=\"spacing\">\n      <number>4</number>\n     </property>\n     <item>\n      <widget class=\"QLabel\" name=\"encodingPresetLabel\">\n       <property name=\"text\">\n        <string>Preset:</string>\n       </property>\n      </widget>\n     </item>\n     <item>\n      <widget class=\"QComboBox\" name=\"encodingPresetComboBox\">\n       <property name=\"sizePolicy\">\n        <sizepolicy hsizetype=\"Expanding\" vsizetype=\"Fixed\">\n         <horstretch>0</horstretch>\n         <verstretch>0</verstretch>\n        </sizepolicy>\n       </property>\n       <property name=\"editable\">\n        <bool>true</bool>\n       </property>\n       <property name=\"insertPolicy\">\n        <enum>QComboBox::NoInsert</enum>\n       </property>\n      </widget>\n     </item>\n     <item>\n      <widget class=\"QPushButton\" name=\"encodingPresetSaveButton\">\n       <property name=\"text\">\n        <string>Save</string>\n       </property>\n      </widget>\n     </item>\n     <item>\n      <widget class=\"QPushButton\" name=\"encodingPresetDeleteButton\">\n       <property name=\"text\">\n        <string>Delete</string>\n       </property>\n      </widget>\n     </item>\n    </layout>\n   </item>\n   <item>\n    <layout class=\"QHBoxLayout\" name=\"horizontalLayout_2\">\n     <property name=\"spacing\">\n      <number>4</number>\n     </property>\n     <item>\n      <widget class=\"QLabel\" name=\"label_3\">\n       <property name=\"text\">\n        <string>Header:</string>\n       </property>\n      </widget>\n     </item>\n     <item>\n      <widget class=\"QComboBox\" name=\"headerTypeComboBox\">\n       <property name=\"sizeAdjustPolicy\">\n        <enum>QComboBox::AdjustToContents</enum>\n       </property>\n      </widget>\n     </item>\n     <item>\n      <widget class=\"QLabel\" name=\"label\">\n       <property name=\"text\">\n        <string>Executable:</string>\n       </property>\n      </widget>\n     </item>\n     <item>\n      <widget class=\"QLineEdit\" name=\"executablePathEdit\">\n       <property name=\"text\">\n        <string/>\n       </property>\n      </widget>\n     </item>\n     <item>\n      <widget class=\"QToolButton\" name=\"executableBrowseButton\">\n       <property name=\"text\">\n        <string/>\n       </property>\n       <property name=\"icon\">\n        <iconset resource=\"../../../resources/vsedit.qrc\">\n         <normaloff>:/folder.png</normaloff>:/folder.png</iconset>\n       </property>\n      </widget>\n     </item>\n    </layout>\n   </item>\n   <item>\n    <layout class=\"QHBoxLayout\" name=\"horizontalLayout_3\">\n     <item>\n      <widget class=\"QLabel\" name=\"label_2\">\n       <property name=\"text\">\n        <string>Arguments (newlines will be replaced with spaces):</string>\n       </property>\n      </widget>\n     </item>\n     <item>\n      <widget class=\"QToolButton\" name=\"argumentsHelpButton\">\n       <property name=\"text\">\n        <string/>\n       </property>\n       <property name=\"icon\">\n        <iconset resource=\"../../../resources/vsedit.qrc\">\n         <normaloff>:/information.png</normaloff>:/information.png</iconset>\n       </property>\n      </widget>\n     </item>\n     <item>\n      <spacer name=\"horizontalSpacer_2\">\n       <property name=\"orientation\">\n        <enum>Qt::Horizontal</enum>\n       </property>\n       <property name=\"sizeHint\" stdset=\"0\">\n        <size>\n         <width>40</width>\n         <height>20</height>\n        </size>\n       </property>\n      </spacer>\n     </item>\n    </layout>\n   </item>\n   <item>\n    <widget class=\"QPlainTextEdit\" name=\"argumentsTextEdit\">\n     <property name=\"plainText\">\n      <string/>\n     </property>\n    </widget>\n   </item>\n   <item>\n    <widget class=\"QLineEdit\" name=\"metricsEdit\">\n     <property name=\"readOnly\">\n      <bool>true</bool>\n     </property>\n    </widget>\n   </item>\n   <item>\n    <widget class=\"QProgressBar\" name=\"processingProgressBar\">\n     <property name=\"alignment\">\n      <set>Qt::AlignCenter</set>\n     </property>\n     <property name=\"format\">\n      <string>%v / %m</string>\n     </property>\n    </widget>\n   </item>\n   <item>\n    <layout class=\"QHBoxLayout\" name=\"horizontalLayout\">\n     <property name=\"spacing\">\n      <number>4</number>\n     </property>\n     <item>\n      <widget class=\"QLabel\" name=\"framesLabel\">\n       <property name=\"text\">\n        <string>Frames:</string>\n       </property>\n      </widget>\n     </item>\n     <item>\n      <widget class=\"QSpinBox\" name=\"fromFrameSpinBox\"/>\n     </item>\n     <item>\n      <widget class=\"QLabel\" name=\"toLabel\">\n       <property name=\"text\">\n        <string>to</string>\n       </property>\n      </widget>\n     </item>\n     <item>\n      <widget class=\"QSpinBox\" name=\"toFrameSpinBox\"/>\n     </item>\n     <item>\n      <widget class=\"QPushButton\" name=\"wholeVideoButton\">\n       <property name=\"text\">\n        <string>Whole video</string>\n       </property>\n      </widget>\n     </item>\n     <item>\n      <spacer name=\"horizontalSpacer\">\n       <property name=\"orientation\">\n        <enum>Qt::Horizontal</enum>\n       </property>\n       <property name=\"sizeHint\" stdset=\"0\">\n        <size>\n         <width>13</width>\n         <height>20</height>\n        </size>\n       </property>\n      </spacer>\n     </item>\n     <item>\n      <widget class=\"QPushButton\" name=\"startEncodeButton\">\n       <property name=\"text\">\n        <string>Start</string>\n       </property>\n       <property name=\"default\">\n        <bool>true</bool>\n       </property>\n      </widget>\n     </item>\n     <item>\n      <widget class=\"QPushButton\" name=\"pauseEncodeButton\">\n       <property name=\"text\">\n        <string>Pause</string>\n       </property>\n      </widget>\n     </item>\n     <item>\n      <widget class=\"QPushButton\" name=\"abortEncodeButton\">\n       <property name=\"text\">\n        <string>Abort</string>\n       </property>\n      </widget>\n     </item>\n    </layout>\n   </item>\n  </layout>\n </widget>\n <customwidgets>\n  <customwidget>\n   <class>VSEditorLog</class>\n   <extends>QTextEdit</extends>\n   <header>../../../common-src/log/vs_editor_log.h</header>\n  </customwidget>\n </customwidgets>\n <resources>\n  <include location=\"../../../resources/vsedit.qrc\"/>\n </resources>\n <connections/>\n</ui>\n"
  },
  {
    "path": "vsedit/src/job_server_watcher_socket.cpp",
    "content": "#include \"job_server_watcher_socket.h\"\n\n#include \"../../common-src/helpers.h\"\n#include \"../../common-src/ipc_defines.h\"\n#include \"../../common-src/log/vs_editor_log_definitions.h\"\n\n#include <QProcess>\n\n//==============================================================================\n\nJobServerWatcherSocket::JobServerWatcherSocket(QObject * a_pParent):\n\t  QObject(a_pParent)\n\t, m_pSocket(nullptr)\n{\n}\n\n// END OF JobServerWatcherSocket::JobServerWatcherSocket(QObject * a_pParent)\n//==============================================================================\n\nJobServerWatcherSocket::~JobServerWatcherSocket()\n{\n}\n\n// END OF JobServerWatcherSocket::~JobServerWatcherSocket()\n//==============================================================================\n\nbool JobServerWatcherSocket::sendMessage(const QByteArray & a_data)\n{\n\tbool connected = connectToJobServerWatcher();\n\tif(!connected)\n\t\treturn false;\n\n\tm_pSocket->write(a_data);\n\treturn true;\n}\n\n// END OF bool JobServerWatcherSocket::sendMessage(const QByteArray & a_data)\n//==============================================================================\n\nbool JobServerWatcherSocket::connectToJobServerWatcher()\n{\n\t// In Linux QLocalSocket wouldn't reconnect once disconnected.\n\t// So we recreate it before each connection attempt.\n\tresetSocket();\n\n\t// Must connect in Read/Write mode, or named pipe won't disconnect.\n\tconst QIODevice::OpenMode openMode = QIODevice::ReadWrite;\n\n\tm_pSocket->connectToServer(openMode);\n\tbool connected = m_pSocket->waitForConnected(1000);\n\tif(connected)\n\t\treturn true;\n\n\tQString watcherPath = vsedit::resolvePathFromApplication(\n\t\t\"./vsedit-job-server-watcher\");\n\tQString thisDir = vsedit::resolvePathFromApplication(\".\");\n\tQProcess watcherProcess;\n\n\tbool started = watcherProcess.startDetached(watcherPath, QStringList(),\n\t\tthisDir);\n\tif(!started)\n\t{\n\t\temit signalWriteLogMessage(tr(\"Could not start \"\n\t\t\t\"job server watcher.\"), LOG_STYLE_ERROR);\n\t\treturn false;\n\t}\n\n\tfor(int i = 0; i < 10; ++i)\n\t{\n\t\tresetSocket();\n\t\tm_pSocket->connectToServer(openMode);\n\t\tconnected = m_pSocket->waitForConnected(1000);\n\t\tif(connected)\n\t\t\tbreak;\n\t\tvsedit::wait(1000);\n\t}\n\n\tif(!connected)\n\t{\n\t\temit signalWriteLogMessage(tr(\"Started job server watcher, \"\n\t\t\t\"but could not connect.\"), LOG_STYLE_ERROR);\n\t\treturn false;\n\t}\n\n\treturn true;\n}\n\n// END OF bool JobServerWatcherSocket::connectToJobServerWatcher()\n//==============================================================================\n\nvoid JobServerWatcherSocket::resetSocket()\n{\n\tif(m_pSocket)\n\t\tdelete m_pSocket;\n\n\tm_pSocket = new QLocalSocket(this);\n\tm_pSocket->setServerName(JOB_SERVER_WATCHER_LOCAL_SERVER_NAME);\n}\n\n// END OF void JobServerWatcherSocket::resetSocket()\n//==============================================================================\n"
  },
  {
    "path": "vsedit/src/job_server_watcher_socket.h",
    "content": "#ifndef JOB_SERVER_WATCHER_SOCKET_H_INCLUDED\n#define JOB_SERVER_WATCHER_SOCKET_H_INCLUDED\n\n#include <QLocalSocket>\n\nclass JobServerWatcherSocket : public QObject\n{\n\tQ_OBJECT\n\npublic:\n\n\tJobServerWatcherSocket(QObject * a_pParent = nullptr);\n\tvirtual ~JobServerWatcherSocket();\n\n\tbool sendMessage(const QByteArray & a_data);\n\nsignals:\n\n\tvoid signalWriteLogMessage(const QString & a_message,\n\t\tconst QString & a_style);\n\nprivate:\n\n\tbool connectToJobServerWatcher();\n\tvoid resetSocket();\n\n\tQLocalSocket * m_pSocket;\n};\n\n#endif // JOB_SERVER_WATCHER_SOCKET_H_INCLUDED\n"
  },
  {
    "path": "vsedit/src/main.cpp",
    "content": "#include \"main_window.h\"\n\n#include \"../../common-src/log/vs_editor_log.h\"\n#include \"../../common-src/settings/settings_manager.h\"\n#include \"../../common-src/version_info.h\"\n#include \"../../common-src/win32_console.h\"\n\n#include <QApplication>\n\n#include <iostream>\n\nQ_DECLARE_OPAQUE_POINTER(const VSFrame *)\nQ_DECLARE_OPAQUE_POINTER(VSNode *)\n\nMainWindow * pMainWindow = nullptr;\n\n#if defined(Q_OS_WIN)\nAttachedConsole * pConsole = nullptr;\n\nvoid toggleAttachedConsole()\n{\n\tif(pConsole->visible())\n\t\tpConsole->hide();\n\telse\n\t\tpConsole->show();\n}\n#endif\n\nvoid handleQtMessage(QtMsgType a_type, const QMessageLogContext & a_context,\n\tconst QString & a_message)\n{\n\tQString prefix = \"Qt debug\";\n\tQString style = LOG_STYLE_DEFAULT;\n\n\tswitch(a_type)\n\t{\n\tcase QtDebugMsg:\n\t\tprefix = \"Qt debug\";\n\t\tstyle = LOG_STYLE_QT_DEBUG;\n\t\tbreak;\n\tcase QtInfoMsg:\n\t\tprefix = \"Qt info\";\n\t\tstyle = LOG_STYLE_QT_INFO;\n\t\tbreak;\n\tcase QtWarningMsg:\n\t\tprefix = \"Qt warning\";\n\t\tstyle = LOG_STYLE_QT_WARNING;\n\t\tbreak;\n\tcase QtCriticalMsg:\n\t\tprefix = \"Qt critical\";\n\t\tstyle = LOG_STYLE_QT_CRITICAL;\n\t\tbreak;\n\tcase QtFatalMsg:\n\t\tprefix = \"Qt fatal\";\n\t\tstyle = LOG_STYLE_QT_FATAL;\n\t\tbreak;\n\tdefault:\n\t\tQ_ASSERT(false);\n\t}\n\n\tQString fullMessage = QString(\"%1: %2\").arg(prefix).arg(a_message);\n\n\tQString fileString(a_context.file);\n\tQString lineString = QString::number(a_context.line);\n\tQString functionString(a_context.function);\n\n\tQString lineInfo = QString(\"\\n(%1:%2\").arg(fileString).arg(lineString);\n\tif(!functionString.isEmpty())\n\t\tlineInfo += QString(\", %1\").arg(functionString);\n\tlineInfo += QString(\")\");\n\tif(!fileString.isEmpty())\n\t\tfullMessage += lineInfo;\n\n\tpMainWindow->slotWriteLogMessage(fullMessage, style);\n\n\tif(a_type == QtFatalMsg)\n\t\tabort();\n}\n\nint main(int argc, char *argv[])\n{\n\tif(argc > 1)\n\t{\n\t\tif(strcmp(argv[1], \"-v\") == 0 ||\n\t\t\tstrcmp(argv[1], \"--version\") == 0)\n\t\t{\n\t\t\tprint_version();\n\t\t\treturn 0;\n\t\t}\n\t}\n\n#if defined(Q_OS_WIN)\n\tpConsole = new AttachedConsole();\n\tprint_version();\n\tstd::cerr << \"Do not close this window unless you are ready to quit!\" << std::endl;\n#endif\n\n\tQApplication::setAttribute(Qt::AA_DontUseNativeMenuBar);\n\tQGuiApplication::setHighDpiScaleFactorRoundingPolicy(\n\t\tQt::HighDpiScaleFactorRoundingPolicy::Floor);\n\tQApplication application(argc, argv);\n\n\tSettingsManager *settings = new SettingsManager(qApp);\n\n\tvsedit::disableFontKerning(qApp);\n\n\t// Make text in message box selectable\n\tapplication.setStyleSheet(\n\t\t\"QToolTip { font-kerning: none; }\"\n\t\t\"QMessageBox { messagebox-text-interaction-flags: 5; }\"\n\t\t\"QLabel { padding: 0px; }\");\n\n\tqRegisterMetaType<const VSFrame *>(\"const VSFrame *\");\n\tqRegisterMetaType<VSNode *>(\"VSNode *\");\n\n\tpMainWindow = new MainWindow(settings);\n\tqInstallMessageHandler(handleQtMessage);\n#if defined(Q_OS_WIN)\n\tQObject::connect(pMainWindow, &MainWindow::signalToggleAttachedConsole,\n\t\ttoggleAttachedConsole);\n#endif\n\tpMainWindow->show();\n\tint exitCode = application.exec();\n\tdelete pMainWindow;\n\tdelete settings;\n#if defined(Q_OS_WIN)\n\tif(pConsole)\n\t{\n\t\tpConsole->destroy();\n\t\tdelete pConsole;\n\t}\n#endif\n\treturn exitCode;\n}\n"
  },
  {
    "path": "vsedit/src/main_window.cpp",
    "content": "#include \"main_window.h\"\n\n#include \"../../common-src/settings/settings_manager.h\"\n#include \"../../common-src/vapoursynth/vs_script_library.h\"\n#include \"../../common-src/vapoursynth/vapoursynth_script_processor.h\"\n#include \"../../common-src/helpers.h\"\n#include \"../../common-src/ipc_defines.h\"\n\n#include \"vapoursynth/vapoursynth_plugins_manager.h\"\n#include \"preview/preview_dialog.h\"\n#include \"settings/settings_dialog.h\"\n#include \"frame_consumers/benchmark_dialog.h\"\n#include \"frame_consumers/encode_dialog.h\"\n#include \"script_templates/templates_dialog.h\"\n#include \"job_server_watcher_socket.h\"\n\n#include <QCoreApplication>\n#include <QSettings>\n#include <QByteArray>\n#include <QMenu>\n#include <QAction>\n#include <QCloseEvent>\n#include <QMoveEvent>\n#include <QResizeEvent>\n#include <QSocketNotifier>\n#include <QToolTip>\n#include <QMessageBox>\n#include <QFileDialog>\n#include <QFile>\n#include <QStandardPaths>\n#include <QStringList>\n#include <QFileInfo>\n#include <QDir>\n#include <QFontDatabase>\n#include <QResource>\n#include <QDesktopServices>\n#include <QUrl>\n#include <QDateTime>\n#include <QTimer>\n\n//==============================================================================\n\nMainWindow::MainWindow(SettingsManager *settings) : QMainWindow()\n\t, m_pSettingsManager(settings)\n\t, m_pVapourSynthPluginsManager(nullptr)\n\t, m_pVSScriptLibrary(nullptr)\n\t, m_pActionNewScript(nullptr)\n\t, m_pActionOpenScript(nullptr)\n\t, m_pActionSaveScript(nullptr)\n\t, m_pActionSaveScriptAs(nullptr)\n\t, m_pActionTemplates(nullptr)\n\t, m_pActionSettings(nullptr)\n\t, m_pActionPreview(nullptr)\n\t, m_pActionCheckScript(nullptr)\n\t, m_pActionBenchmark(nullptr)\n\t, m_pActionEncode(nullptr)\n\t, m_pActionEnqueueEncodeJob(nullptr)\n\t, m_pActionJobs(nullptr)\n\t, m_pActionConsole(nullptr)\n\t, m_pActionExit(nullptr)\n\t, m_pActionAbout(nullptr)\n\t, m_settableActionsList()\n\t, m_pMenuRecentScripts(nullptr)\n\t, m_pPreviewDialog(nullptr)\n\t, m_pSettingsDialog(nullptr)\n\t, m_pBenchmarkDialog(nullptr)\n\t, m_pEncodeDialog(nullptr)\n\t, m_pTemplatesDialog(nullptr)\n\t, m_scriptFilePath()\n\t, m_lastSavedText()\n\t, m_pJobServerWatcherSocket(nullptr)\n\t, m_pGeometrySaveTimer(nullptr)\n\t, m_pReloadTextTimer(nullptr)\n{\n\tloadFonts();\n\tvsedit::disableFontKerning(this);\n\n\tm_ui.setupUi(this);\n\n\tsetWindowIcon(QIcon(\":vsedit.ico\"));\n\n\tif(m_pSettingsManager->inDarkMode())\n\t{\n\t\t// Load qDarkStyle colors\n\t\tQFile styleSheetDark(\":/dark/style.qss\");\n\t\tif(!styleSheetDark.open(QFile::ReadOnly | QFile::Text))\n\t\t{\n\t\t\tQMessageBox::critical(this,\n\t\t\t\tQString::fromUtf8(\"File open error\"),\n\t\t\t\tQString::fromUtf8(\"Failed to open stylesheet file \")\n\t\t\t\t\t+ styleSheetDark.errorString());\n\t\t}\n\t\tqApp->setStyleSheet(styleSheetDark.readAll());\n\t\t// With the current impl of the timeline slider\n\t\t// we have to relaunch anyway\n\t\tQPalette newPal(qApp->palette());\n\t\tnewPal.setColor(QPalette::Base, QColor(0, 0, 0));\n\t\tnewPal.setColor(QPalette::Highlight, QColor(128, 128, 128));\n\t\tnewPal.setColor(QPalette::Dark, QColor(192, 192, 192));\n\t\tnewPal.setColor(QPalette::Text, QColor(64, 192, 0));\n\t\tqApp->setPalette(newPal);\n\t}\n#ifdef Q_OS_WIN\n\telse\n\t\tqApp->setStyle(\"fusion\");\n#endif\n\tm_pSettingsDialog = new SettingsDialog(m_pSettingsManager, nullptr);\n\n\tconnect(m_pSettingsDialog, SIGNAL(signalSettingsChanged()),\n\t\tthis, SLOT(slotSettingsChanged()));\n\n\tm_pVSScriptLibrary = new VSScriptLibrary(m_pSettingsManager, this);\n\n\tconnect(m_pVSScriptLibrary,\n\t\tSIGNAL(signalWriteLogMessage(int, const QString &)),\n\t\tthis, SLOT(slotWriteLogMessage(int, const QString &)));\n\n\tm_pVapourSynthPluginsManager = new VapourSynthPluginsManager(\n\t\tm_pSettingsManager, m_pVSScriptLibrary->getVSAPI(), this);\n\tVSPluginsList vsPluginsList = m_pVapourSynthPluginsManager->pluginsList();\n\n\tm_ui.scriptEdit->setPluginsList(vsPluginsList);\n\tm_ui.scriptEdit->setSettingsManager(m_pSettingsManager);\n\n\tconnect(m_ui.scriptEdit, SIGNAL(textChanged()),\n\t\tthis, SLOT(slotEditorTextChanged()));\n\tconnect(m_ui.scriptEdit, SIGNAL(modificationChanged(bool)),\n\t\tthis, SLOT(slotChangeWindowTitle()));\n\tconnect(m_ui.scriptEdit,\n\t\tSIGNAL(signalScriptFileDropped(const QString &, bool *)),\n\t\tthis, SLOT(slotScriptFileDropped(const QString &, bool *)));\n\n\tm_ui.logView->setName(\"main_log\");\n\tm_ui.logView->setSettingsManager(m_pSettingsManager);\n\tm_ui.logView->loadSettings();\n\n\tm_pPreviewDialog =\n\t\tnew PreviewDialog(m_pSettingsManager, m_pVSScriptLibrary);\n\n\tconnect(m_pPreviewDialog,\n\t\tSIGNAL(signalWriteLogMessage(int, const QString &)),\n\t\tthis, SLOT(slotWriteLogMessage(int, const QString &)));\n\tconnect(m_pPreviewDialog,\n\t\tSIGNAL(signalPasteIntoScriptAtNewLine(const QString &)),\n\t\tthis, SLOT(slotInsertTextIntoScriptAtNewLine(const QString &)));\n\tconnect(m_pPreviewDialog,\n\t\tSIGNAL(signalPasteIntoScriptAtCursor(const QString &)),\n\t\tthis, SLOT(slotInsertTextIntoScriptAtCursor(const QString &)));\n\tconnect(m_pSettingsDialog, SIGNAL(signalSettingsChanged()),\n\t\tm_pPreviewDialog, SLOT(slotSettingsChanged()));\n\n\tconnect(m_ui.scriptEdit, &QPlainTextEdit::textChanged,\n\t\tm_pPreviewDialog, &PreviewDialog::slotScriptTextChanged);\n\n\tm_pBenchmarkDialog =\n\t\tnew ScriptBenchmarkDialog(m_pSettingsManager, m_pVSScriptLibrary);\n\tconnect(m_pBenchmarkDialog,\n\t\tSIGNAL(signalWriteLogMessage(int, const QString &)),\n\t\tthis, SLOT(slotWriteLogMessage(int, const QString &)));\n\n\tm_pEncodeDialog = new EncodeDialog(m_pSettingsManager, m_pVSScriptLibrary);\n\tconnect(m_pEncodeDialog,\n\t\tSIGNAL(signalWriteLogMessage(const QString &, const QString &)),\n\t\tthis, SLOT(slotWriteLogMessage(const QString &, const QString &)));\n\n\tm_pTemplatesDialog = new TemplatesDialog(m_pSettingsManager);\n\tm_pTemplatesDialog->setPluginsList(vsPluginsList);\n\n\tconnect(m_pTemplatesDialog, SIGNAL(signalPasteCodeSnippet(const QString &)),\n\t\tthis, SLOT(slotInsertTextIntoScriptAtNewLine(const QString &)));\n\n\tm_orphanQObjects =\n\t{\n\t\t(QObject **)&m_pPreviewDialog,\n\t\t(QObject **)&m_pSettingsDialog,\n\t\t(QObject **)&m_pBenchmarkDialog,\n\t\t(QObject **)&m_pEncodeDialog,\n\t\t(QObject **)&m_pTemplatesDialog\n\t};\n\n\tm_pJobServerWatcherSocket = new JobServerWatcherSocket(this);\n\tconnect(m_pJobServerWatcherSocket,\n\t\tSIGNAL(signalWriteLogMessage(const QString &, const QString &)),\n\t\tthis, SLOT(slotWriteLogMessage(const QString &, const QString &)));\n\n\tm_pGeometrySaveTimer = new QTimer(this);\n\tm_pGeometrySaveTimer->setInterval(DEFAULT_WINDOW_GEOMETRY_SAVE_DELAY);\n\tconnect(m_pGeometrySaveTimer, &QTimer::timeout,\n\t\tthis, &MainWindow::slotSaveGeometry);\n\n\tm_pReloadTextTimer = new QTimer(this);\n\tm_pReloadTextTimer->setInterval(500);\n\tconnect(m_pReloadTextTimer, &QTimer::timeout,\n\t\tthis, &MainWindow::slotReloadTextFromDisk);\n\n\tcreateActionsAndMenus();\n\n\tslotChangeWindowTitle();\n\n\tm_windowGeometry = m_pSettingsManager->getMainWindowGeometry();\n\tif(!m_windowGeometry.isEmpty())\n\t\trestoreGeometry(m_windowGeometry);\n\n\tif(m_pSettingsManager->getMainWindowMaximized())\n\t\tshowMaximized();\n\n\tloadStartUpScript();\n\n\tif(m_pSettingsManager->getReloadScriptFromDisk())\n\t\tm_pReloadTextTimer->start();\n}\n\n// END OF MainWindow::MainWindow()\n//==============================================================================\n\nMainWindow::~MainWindow()\n{\n\tif(m_pGeometrySaveTimer->isActive())\n\t{\n\t\tm_pGeometrySaveTimer->stop();\n\t\tslotSaveGeometry();\n\t}\n\n\tif(m_pReloadTextTimer->isActive())\n\t\tm_pReloadTextTimer->stop();\n\n\tqInstallMessageHandler(0);\n\tdestroyOrphanQObjects();\n}\n\n// END OF MainWindow::~MainWindow()\n//==============================================================================\n\nvoid MainWindow::slotWriteLogMessage(int a_messageType,\n\tconst QString & a_message)\n{\n\tQString style = vsMessageTypeToStyleName(a_messageType);\n\tslotWriteLogMessage(a_message, style);\n}\n\n// END OF void MainWindow::slotWriteLogMessage(int a_messageType,\n//\t\tconst QString & a_message)\n//==============================================================================\n\nvoid MainWindow::slotWriteLogMessage(const QString & a_message,\n\tconst QString & a_style)\n{\n\tQString debugTypes[] = {\n\t\tLOG_STYLE_DEBUG,\n\t\tLOG_STYLE_QT_DEBUG,\n\t\tLOG_STYLE_VS_DEBUG,\n\t};\n\tif(m_pSettingsManager->getShowDebugMessages() ||\n\t\t!vsedit::contains(debugTypes, a_style))\n\t{\n\t\tm_ui.logView->addEntry(a_message, a_style);\n\t}\n\n\tQString fatalTypes[] = {LOG_STYLE_VS_FATAL, LOG_STYLE_QT_FATAL};\n\tif(!vsedit::contains(fatalTypes, a_style))\n\t\treturn;\n\n\tQDateTime now = QDateTime::currentDateTime();\n\tQString timeString = now.toString(\"hh:mm:ss.zzz\");\n\tQString dateString = now.toString(\"yyyy-MM-dd\");\n\tQString caption = QObject::tr(\"VapourSynth Editor fatal error!\");\n\tQString fullMessage = dateString + QString(\" \") + timeString +\n\t\tQString(\"\\n\") + caption + QString(\"\\n\") + a_message;\n\n    QString tempPath =\n\t\tQStandardPaths::writableLocation(QStandardPaths::TempLocation);\n\tif(tempPath.isEmpty())\n\t{\n\t\tQMessageBox::critical(nullptr, caption, fullMessage);\n\t\treturn;\n\t}\n\n\tQString filePath = tempPath + QString(\"/\") +\n\t\tQString(\"VapourSynth-Editor-crashlog-\") + dateString + QString(\"-\") +\n\t\ttimeString.replace(':', '-') + QString(\".html\");\n\n\tbool saved = m_ui.logView->saveHtml(filePath);\n\tif(!saved)\n\t{\n\t\tQMessageBox::critical(nullptr, caption, fullMessage);\n\t\treturn;\n\t}\n\n\tQUrl fileUrl = QUrl::fromLocalFile(filePath);\n\tQDesktopServices::openUrl(fileUrl);\n}\n\n// END OF void MainWindow::slotWriteLogMessage(const QString & a_message,\n//\t\tconst QString & a_style);\n//==============================================================================\n\nvoid MainWindow::slotInsertTextIntoScriptAtNewLine(const QString & a_text)\n{\n\tm_ui.scriptEdit->slotInsertTextAtNewLine(a_text);\n}\n\n// END OF void MainWindow::slotInsertTextIntoScriptAtNewLine(\n//\t\tconst QString & a_text)\n//==============================================================================\n\nvoid MainWindow::slotInsertTextIntoScriptAtCursor(const QString & a_text)\n{\n\tm_ui.scriptEdit->insertPlainText(a_text);\n}\n\n// END OF void MainWindow::slotInsertTextIntoScriptAtCursor(\n//\t\tconst QString & a_text)\n//==============================================================================\n\nvoid MainWindow::closeEvent(QCloseEvent * a_pEvent)\n{\n\tif(!safeToCloseFile())\n\t{\n\t\ta_pEvent->ignore();\n\t\treturn;\n\t}\n\n\tdestroyOrphanQObjects();\n\n\tQMainWindow::closeEvent(a_pEvent);\n}\n\n// END OF void MainWindow::closeEvent(QCloseEvent * a_pEvent)\n//==============================================================================\n\nvoid MainWindow::moveEvent(QMoveEvent * a_pEvent)\n{\n\tQMainWindow::moveEvent(a_pEvent);\n\tsaveGeometryDelayed();\n}\n\n// END OF void MainWindow::moveEvent(QMoveEvent * a_pEvent)\n//==============================================================================\n\nvoid MainWindow::resizeEvent(QResizeEvent * a_pEvent)\n{\n\tQMainWindow::resizeEvent(a_pEvent);\n\tsaveGeometryDelayed();\n}\n\n// END OF void MainWindow::resizeEvent(QResizeEvent * a_pEvent)\n//==============================================================================\n\nvoid MainWindow::changeEvent(QEvent * a_pEvent)\n{\n\tif(a_pEvent->type() == QEvent::WindowStateChange)\n\t{\n\t\tif(isMaximized())\n\t\t\tm_pSettingsManager->setMainWindowMaximized(true);\n\t\telse\n\t\t\tm_pSettingsManager->setMainWindowMaximized(false);\n\t}\n\tQMainWindow::changeEvent(a_pEvent);\n}\n\n// END OF void MainWindow::changeEvent(QEvent * a_pEvent)\n//==============================================================================\n\nvoid MainWindow::slotNewScript()\n{\n\tif(!safeToCloseFile())\n\t\treturn;\n\n\tQString newScriptTemplate = m_pSettingsManager->getNewScriptTemplate();\n\n\tm_scriptFilePath.clear();\n\tm_lastSavedText = newScriptTemplate;\n\tm_ui.scriptEdit->setPlainText(newScriptTemplate);\n\tm_ui.scriptEdit->moveCursor(QTextCursor::End);\n\tm_ui.scriptEdit->setModified(true);\n\n\tm_pBenchmarkDialog->resetSavedRange();\n}\n\n// END OF void MainWindow::slotNewScript()\n//==============================================================================\n\nbool MainWindow::slotSaveScript()\n{\n\tif(!m_ui.scriptEdit->isModified())\n\t\treturn false;\n\n\tif(m_scriptFilePath.isEmpty())\n\t{\n\t\tslotSaveScriptAs();\n\t\treturn false;\n\t}\n\n\treturn saveScriptToFile(m_scriptFilePath);\n}\n\n// END OF bool MainWindow::slotSaveScript()\n//==============================================================================\n\nbool MainWindow::slotSaveScriptAs()\n{\n\tQString offeredFilePath = m_scriptFilePath;\n\tif(offeredFilePath.isEmpty())\n\t{\n\t\tQFileInfo fileInfo(m_pSettingsManager->getLastUsedPath());\n\t\tofferedFilePath = fileInfo.absoluteDir().path() +\n\t\t\ttr(\"/Untitled.vpy\");\n\t}\n\n\tQString filePath = QFileDialog::getSaveFileName(this,\n\t\ttr(\"Save VapourSynth script\"), offeredFilePath,\n\t\ttr(\"VapourSynth script (*.vpy);;All files (*)\"));\n\n\tif(!filePath.isEmpty())\n\t{\n\t\tbool success = saveScriptToFile(filePath);\n\n\t\t// Copy bookmarks\n\t\tif((!success) || offeredFilePath.isEmpty())\n\t\t\treturn success;\n\t\tQFile::copy(offeredFilePath + TIMELINE_BOOKMARKS_FILE_SUFFIX,\n\t\t\tfilePath + TIMELINE_BOOKMARKS_FILE_SUFFIX);\n\t}\n\n\treturn false;\n}\n\n// END OF bool MainWindow::slotSaveScriptAs()\n//==============================================================================\n\nbool MainWindow::slotOpenScript()\n{\n\tif(!safeToCloseFile())\n\t\treturn false;\n\n\tQFileInfo fileInfo(m_pSettingsManager->getLastUsedPath());\n\tQString offeredPath = fileInfo.absoluteDir().path();\n\n\tQString filePath = QFileDialog::getOpenFileName(this,\n\t\ttr(\"Open VapourSynth script\"), offeredPath,\n\t\ttr(\"VapourSynth script (*.vpy);;All files (*)\"));\n\n\treturn loadScriptFromFile(filePath);\n}\n\n// END OF bool MainWindow::slotOpenScript()\n//==============================================================================\n\nvoid MainWindow::slotTemplates()\n{\n\tm_pTemplatesDialog->call();\n}\n\n// END OF void MainWindow::slotTemplates()\n//==============================================================================\n\nvoid MainWindow::slotPreview()\n{\n\tif(m_pPreviewDialog->busy())\n\t{\n\t\tQString message = tr(\"Preview dialog appears busy processing \"\n\t\t\t\"frames. Please stop any active actions in the dialog and wait \"\n\t\t\t\"for script processor to finish processing.\");\n\t\tm_ui.logView->addEntry(message, LOG_STYLE_WARNING);\n\t\treturn;\n\t}\n\n\tm_pPreviewDialog->previewScript(m_ui.scriptEdit->text(), m_scriptFilePath);\n}\n\n// END OF void MainWindow::slotPreview()\n//==============================================================================\n\nvoid MainWindow::slotCheckScript()\n{\n\tVapourSynthScriptProcessor tempProcessor(m_pSettingsManager,\n\t\tm_pVSScriptLibrary, this);\n\n\tconst VSAPI * cpVSAPI = m_pVSScriptLibrary->getVSAPI();\n\n\tconnect(&tempProcessor, SIGNAL(signalWriteLogMessage(int, const QString &)),\n\t\tthis, SLOT(slotWriteLogMessage(int, const QString &)));\n\n\tbool correct = tempProcessor.initialize(m_ui.scriptEdit->text(),\n\t\tm_scriptFilePath, 0, ProcessReason::Check);\n\tif(correct)\n\t{\n\t\tVSNodeInfo info = tempProcessor.nodeInfo();\n\t\tQString message = tr(\"Script was successfully evaluated. \"\n\t\t\t\"Output %1 info:\\n\").arg(info.isAudio() ? \"audio\" : \"video\");\n\t\tmessage += vsedit::nodeInfoString(info, cpVSAPI);\n\t\tm_ui.logView->addEntry(message, LOG_STYLE_POSITIVE);\n\t}\n}\n\n// END OF void MainWindow::slotCheckScript()\n//==============================================================================\n\nvoid MainWindow::slotBenchmark()\n{\n\tif(m_pBenchmarkDialog->busy())\n\t{\n\t\tQString message = tr(\"Benchmark dialog appears busy processing \"\n\t\t\t\"frames. Please stop any active actions in the dialog and wait \"\n\t\t\t\"for script processor to finish processing.\");\n\t\tm_ui.logView->addEntry(message, LOG_STYLE_WARNING);\n\t\treturn;\n\t}\n\n\tm_pBenchmarkDialog->initialize(m_ui.scriptEdit->text(), m_scriptFilePath);\n\tm_pBenchmarkDialog->call();\n}\n\n// END OF void MainWindow::slotBenchmark()\n//==============================================================================\n\nvoid MainWindow::slotEncode()\n{\n\tif(m_pEncodeDialog->busy())\n\t{\n\t\tm_pEncodeDialog->showActive();\n\t\treturn;\n\t}\n\n\tbool initialized = m_pEncodeDialog->initialize(\n\t\tm_ui.scriptEdit->text(), m_scriptFilePath);\n\tif(initialized)\n\t\tm_pEncodeDialog->showActive();\n}\n\n// END OF void MainWindow::slotEncode()\n//==============================================================================\n\nvoid MainWindow::slotEnqueueEncodeJob()\n{\n\tif(m_scriptFilePath.isEmpty())\n\t\treturn;\n\n\tJobProperties properties;\n\tproperties.type = JobType::EncodeScriptCLI;\n\tproperties.scriptName = m_scriptFilePath;\n\n\tQByteArray message = vsedit::jsonMessage(WMSG_CLI_ENCODE_JOB,\n\t\tproperties.toJson());\n\tm_pJobServerWatcherSocket->sendMessage(message);\n}\n\n// END OF void MainWindow::slotEnqueueEncodeJob()\n//==============================================================================\n\nvoid MainWindow::slotJobs()\n{\n\tm_pJobServerWatcherSocket->sendMessage(WMSG_SHOW_WINDOW);\n}\n\n// END OF void MainWindow::slotJobs()\n//==============================================================================\n\nvoid MainWindow::slotToggleConsole()\n{\n#if defined(Q_OS_WIN)\n\temit signalToggleAttachedConsole();\n#endif\n}\n\nvoid MainWindow::slotAbout()\n{\n\tQResource aboutResource(\":readme\");\n\tQByteArray aboutData((const char *)aboutResource.data(),\n\t\taboutResource.size());\n\tQString aboutString = QString::fromUtf8(aboutData);\n\taboutString.append(QString(\"\\n\\nBuilt with Qt %1\").arg(QT_VERSION_STR));\n\tQString VSAPIInfo = m_pVSScriptLibrary->VSAPIInfo();\n\tif(VSAPIInfo.isEmpty())\n\t{\n\t\taboutString.append(QString(\"\\nVapourSynth not well configured.\"));\n\t}\n\telse\n\t{\n\t\taboutString.append(QString(\"\\nVapourSynth API Version: \" + VSAPIInfo));\n\t\tQString VSSAPIInfo = m_pVSScriptLibrary->VSSAPIInfo();\n\t\taboutString.append(QString(\"\\nVSScript API Version: \" + VSSAPIInfo));\n\t}\n\tQMessageBox msgBox(this);\n\tmsgBox.setText(aboutString);\n\tmsgBox.setWindowTitle(\"About VapourSynth Editor\");\n\tvsedit::disableFontKerning(&msgBox);\n\tmsgBox.exec();\n}\n\n// END OF void MainWindow::slotAbout()\n//==============================================================================\n\nvoid MainWindow::slotChangeWindowTitle()\n{\n\tQString windowTitleText = QString::fromUtf8(\"VapourSynth Editor - \");\n\n\tif(m_scriptFilePath.isEmpty())\n\t\twindowTitleText += QString::fromUtf8(\"(Untitled)\");\n\telse\n\t\twindowTitleText += m_scriptFilePath;\n\n\tif(m_ui.scriptEdit->isModified())\n\t\twindowTitleText += \"*\";\n\n\tsetWindowTitle(windowTitleText);\n}\n\n// END OF void MainWindow::slotChangeWindowTitle()\n//==============================================================================\n\nvoid MainWindow::slotEditorTextChanged()\n{\n\tbool textMatchesSaved = (m_lastSavedText == m_ui.scriptEdit->text());\n\tm_ui.scriptEdit->setModified(!textMatchesSaved);\n\tslotChangeWindowTitle();\n}\n\n// END OF void MainWindow::slotEditorTextChanged()\n//==============================================================================\n\nvoid MainWindow::slotOpenRecentScriptActionTriggered()\n{\n\tQAction * pAction = qobject_cast<QAction *>(sender());\n\tif(pAction == nullptr)\n\t\treturn;\n\tif(!safeToCloseFile())\n\t\treturn;\n\tloadScriptFromFile(pAction->data().toString());\n}\n\n// END OF bool MainWindow::safeToCloseFile()\n//==============================================================================\n\nvoid MainWindow::slotSettingsChanged()\n{\n\tQKeySequence hotkey;\n\tfor(QAction * pAction : m_settableActionsList)\n\t{\n\t\thotkey = m_pSettingsManager->getHotkey(pAction->data().toString());\n\t\tpAction->setShortcut(hotkey);\n\t}\n\n\tm_pVapourSynthPluginsManager->slotRefill(m_pVSScriptLibrary->getVSAPI());\n\tVSPluginsList vsPluginsList = m_pVapourSynthPluginsManager->pluginsList();\n\tm_ui.scriptEdit->setPluginsList(vsPluginsList);\n\tm_ui.scriptEdit->slotLoadSettings();\n\tm_pTemplatesDialog->setPluginsList(vsPluginsList);\n\tm_pTemplatesDialog->slotLoadSettings();\n\n\tif(m_pSettingsManager->getReloadScriptFromDisk())\n\t\tm_pReloadTextTimer->start(500);\n\telse\n\t\tm_pReloadTextTimer->stop();\n}\n\n// END OF void MainWindow::slotSettingsChanged()\n//==============================================================================\n\nvoid MainWindow::slotScriptFileDropped(const QString & a_filePath,\n\tbool * a_pHandled)\n{\n\t*a_pHandled = true;\n\n\tif(!safeToCloseFile())\n\t\treturn;\n\n\tloadScriptFromFile(a_filePath);\n}\n\n// END OF void MainWindow::slotScriptFileDropped(const QString & a_filePath,\n//\t\tbool * a_pHandled)\n//==============================================================================\n\nvoid MainWindow::slotReloadTextFromDisk()\n{\n\tif(m_ui.scriptEdit->isModified())\n\t\treturn;\n\n\tif(m_scriptFilePath.isEmpty())\n\t\treturn;\n\n\tQFile scriptFile(m_scriptFilePath);\n\tbool loadSuccess = scriptFile.open(QIODevice::ReadOnly | QIODevice::Text);\n\tif(!loadSuccess)\n\t\treturn;\n\n\tQByteArray utf8Script = scriptFile.readAll();\n\tQString scriptText = QString::fromUtf8(utf8Script);\n\tif(scriptText.isEmpty()) // To prevent an occasional bug?\n\t\treturn;\n\tif(scriptText == m_ui.scriptEdit->text())\n\t\treturn;\n\n\tQPoint pos = m_ui.scriptEdit->cursorPosition();\n\tm_ui.scriptEdit->setPlainText(scriptText);\n\tm_ui.scriptEdit->setCursorPosition(pos);\n\tm_ui.scriptEdit->setModified(false);\n\n\tm_pBenchmarkDialog->resetSavedRange();\n}\n\nvoid MainWindow::slotSaveGeometry()\n{\n\tm_pGeometrySaveTimer->stop();\n\tm_pSettingsManager->setMainWindowGeometry(m_windowGeometry);\n}\n\n// END OF void MainWindow::slotSaveGeometry()\n//==============================================================================\n\nvoid MainWindow::createActionsAndMenus()\n{\n\tstruct ActionToCreate\n\t{\n\t\tQAction ** ppAction;\n\t\tconst char * id;\n\t\tQObject * pObjectToConnect;\n\t\tconst char * slotToConnect;\n\t};\n\n\tActionToCreate actionsToCreate[] =\n\t{\n\t\t{&m_pActionNewScript, ACTION_ID_NEW_SCRIPT,\n\t\t\tthis, SLOT(slotNewScript())},\n\t\t{&m_pActionOpenScript, ACTION_ID_OPEN_SCRIPT,\n\t\t\tthis, SLOT(slotOpenScript())},\n\t\t{&m_pActionSaveScript, ACTION_ID_SAVE_SCRIPT,\n\t\t\tthis, SLOT(slotSaveScript())},\n\t\t{&m_pActionSaveScriptAs, ACTION_ID_SAVE_SCRIPT_AS,\n\t\t\tthis, SLOT(slotSaveScriptAs())},\n\t\t{&m_pActionExit, ACTION_ID_EXIT,\n\t\t\tthis, SLOT(close())},\n\t\t{&m_pActionTemplates, ACTION_ID_TEMPLATES,\n\t\t\tthis, SLOT(slotTemplates())},\n\t\t{&m_pActionSettings, ACTION_ID_SETTINGS,\n\t\t\tm_pSettingsDialog, SLOT(slotCall())},\n\t\t{&m_pActionPreview, ACTION_ID_PREVIEW,\n\t\t\tthis, SLOT(slotPreview())},\n\t\t{&m_pActionCheckScript, ACTION_ID_CHECK_SCRIPT,\n\t\t\tthis, SLOT(slotCheckScript())},\n\t\t{&m_pActionBenchmark, ACTION_ID_BENCHMARK,\n\t\t\tthis, SLOT(slotBenchmark())},\n\t\t{&m_pActionEncode, ACTION_ID_CLI_ENCODE,\n\t\t\tthis, SLOT(slotEncode())},\n\t\t{&m_pActionEnqueueEncodeJob, ACTION_ID_ENQUEUE_ENCODE_JOB,\n\t\t\tthis, SLOT(slotEnqueueEncodeJob())},\n\t\t{&m_pActionJobs, ACTION_ID_JOBS,\n\t\t\tthis, SLOT(slotJobs())},\n#if defined(Q_OS_WIN)\n\t\t{&m_pActionConsole, ACTION_ID_TOGGLE_CONSOLE,\n\t\t\tthis, SLOT(slotToggleConsole())},\n#endif\n\t\t{&m_pActionAbout, ACTION_ID_ABOUT,\n\t\t\tthis, SLOT(slotAbout())},\n\t};\n\n\tfor(ActionToCreate & item : actionsToCreate)\n\t{\n\t\tQAction * pAction = m_pSettingsManager->createStandardAction(\n\t\t\titem.id, this);\n\t\t*item.ppAction = pAction;\n\t\tm_settableActionsList.push_back(pAction);\n\t\tconnect(pAction, SIGNAL(triggered()),\n\t\t\titem.pObjectToConnect, item.slotToConnect);\n\t}\n\n//------------------------------------------------------------------------------\n\n\tQMenu * pFileMenu = m_ui.menuBar->addMenu(tr(\"File\"));\n\tvsedit::disableFontKerning(pFileMenu);\n\tpFileMenu->addAction(m_pActionNewScript);\n\tpFileMenu->addAction(m_pActionOpenScript);\n\tpFileMenu->addAction(m_pActionSaveScript);\n\tpFileMenu->addAction(m_pActionSaveScriptAs);\n\tpFileMenu->addSeparator();\n\n\tm_pMenuRecentScripts = new QMenu(tr(\"Recent scripts\"), this);\n\tvsedit::disableFontKerning(m_pMenuRecentScripts);\n\tpFileMenu->addMenu(m_pMenuRecentScripts);\n\tfillRecentScriptsMenu();\n\n\tpFileMenu->addSeparator();\n\tpFileMenu->addAction(m_pActionExit);\n\n//------------------------------------------------------------------------------\n\n\tQMenu * pEditMenu = m_ui.menuBar->addMenu(tr(\"Edit\"));\n\tvsedit::disableFontKerning(pEditMenu);\n\n\tstd::vector<QAction *> editorActions = m_ui.scriptEdit->actionsForMenu();\n\tfor(QAction * pAction : editorActions)\n\t\tpEditMenu->addAction(pAction);\n\n\tpEditMenu->addSeparator();\n\tpEditMenu->addAction(m_pActionTemplates);\n\tpEditMenu->addAction(m_pActionSettings);\n\n//------------------------------------------------------------------------------\n\n\tQMenu * pScriptMenu = m_ui.menuBar->addMenu(tr(\"Script\"));\n\tvsedit::disableFontKerning(pScriptMenu);\n\tpScriptMenu->addAction(m_pActionPreview);\n\tpScriptMenu->addAction(m_pActionCheckScript);\n\tpScriptMenu->addAction(m_pActionBenchmark);\n\tpScriptMenu->addAction(m_pActionEncode);\n\tpScriptMenu->addAction(m_pActionEnqueueEncodeJob);\n\tpScriptMenu->addAction(m_pActionJobs);\n#if defined(Q_OS_WIN)\n\tpScriptMenu->addSeparator();\n\tpScriptMenu->addAction(m_pActionConsole);\n#endif\n\n//------------------------------------------------------------------------------\n\n\tQMenu * pHelpMenu = m_ui.menuBar->addMenu(tr(\"Help\"));\n\tvsedit::disableFontKerning(pHelpMenu);\n\tpHelpMenu->addAction(m_pActionAbout);\n}\n\n// END OF void MainWindow::createActionsAndMenus()\n//==============================================================================\n\nvoid MainWindow::fillRecentScriptsMenu()\n{\n\tm_pMenuRecentScripts->clear();\n\tQStringList recentSciptsList = m_pSettingsManager->getRecentFilesList();\n\tfor(const QString & filePath : recentSciptsList)\n\t{\n\t\tQAction * pAction = new QAction(m_pMenuRecentScripts);\n\t\tpAction->setIconText(filePath);\n\t\tpAction->setData(filePath);\n\t\tm_pMenuRecentScripts->addAction(pAction);\n\n\t\tconnect(pAction, SIGNAL(triggered()),\n\t\t\tthis, SLOT(slotOpenRecentScriptActionTriggered()));\n\t}\n}\n\n// END OF void MainWindow::fillRecentScriptsMenu()\n//==============================================================================\n\nbool MainWindow::saveScriptToFile(const QString& a_filePath)\n{\n\tif(a_filePath.isEmpty())\n\t\treturn false;\n\n\tQFile scriptFile(a_filePath);\n\tbool openSuccess = scriptFile.open(QIODevice::WriteOnly | QIODevice::Text);\n\tif(!openSuccess)\n\t{\n\t\tQMessageBox::critical(this,\n\t\t\tQString::fromUtf8(\"File open error\"),\n\t\t\tQString::fromUtf8(\"Failed to open the file \") + a_filePath +\n\t\t\tQString::fromUtf8(\"for writing!\"));\n\t\treturn false;\n\t}\n\n\tQByteArray utf8Script = m_ui.scriptEdit->text().toUtf8();\n\tqint64 writtenBytes = scriptFile.write(utf8Script);\n\n\tif(writtenBytes != utf8Script.size())\n\t{\n\t\tQMessageBox::critical(this,\n\t\t\tQString::fromUtf8(\"File write error\"),\n\t\t\tQString::fromUtf8(\"Error while writing to the file \") + a_filePath);\n\t\treturn false;\n\t}\n\n\tsetCurrentScriptFilePath(a_filePath);\n\tm_lastSavedText = m_ui.scriptEdit->text();\n\tm_ui.scriptEdit->setModified(false);\n\n\treturn true;\n}\n\n// END OF bool MainWindow::saveScriptToFile(const QString& a_filePath)\n//==============================================================================\n\nbool MainWindow::loadScriptFromFile(const QString& a_filePath)\n{\n\tif(a_filePath.isEmpty())\n\t\treturn false;\n\n\tQFile scriptFile(a_filePath);\n\tbool loadSuccess = scriptFile.open(QIODevice::ReadOnly | QIODevice::Text);\n\tif(!loadSuccess)\n\t{\n\t\tQMessageBox::critical(this,\n\t\t\tQString::fromUtf8(\"File open error\"),\n\t\t\tQString::fromUtf8(\"Failed to open the file %1.\").arg(a_filePath));\n\t\treturn false;\n\t}\n\n\tsetCurrentScriptFilePath(a_filePath);\n\tQByteArray utf8Script = scriptFile.readAll();\n\tQString scriptText = QString::fromUtf8(utf8Script);\n\tm_lastSavedText = scriptText;\n\tm_ui.scriptEdit->setPlainText(scriptText);\n\n\tm_pBenchmarkDialog->resetSavedRange();\n\n\treturn true;\n}\n\n// END OF bool MainWindow::loadScriptFromFile(const QString& a_filePath)\n//==============================================================================\n\nbool MainWindow::safeToCloseFile()\n{\n\tbool needPrompt = (m_pSettingsManager->getPromptToSaveChanges() &&\n\t\tm_ui.scriptEdit->isModified());\n\n\tif(!needPrompt)\n\t\treturn true;\n\n\tQMessageBox quesBox(this);\n\tvsedit::disableFontKerning(&quesBox);\n\tquesBox.setWindowTitle(tr(\"Save script?\"));\n\tif(m_scriptFilePath.isEmpty())\n\t{\n\t\tquesBox.setText(\n\t\t\ttr(\"Would you like to save your script before closing?\"));\n\t}\n\telse\n\t{\n\t\tquesBox.setText(\n\t\t\ttr(\"Would you like to save script \\\"%1\\\" before closing?\")\n\t\t\t.arg(m_scriptFilePath));\n\t}\n\tquesBox.setStandardButtons(\n\t\t  QMessageBox::Yes\n\t\t| QMessageBox::No\n\t\t| QMessageBox::Cancel);\n\tint ret = quesBox.exec();\n\tswitch(ret)\n\t{\n\tcase QMessageBox::Yes:\n\t\treturn slotSaveScript();\n\tcase QMessageBox::Cancel:\n\t\treturn false;\t\n\tdefault:\n\t\treturn true;\n\t}\n}\n\n// END OF bool MainWindow::safeToCloseFile()\n//==============================================================================\n\nvoid MainWindow::setCurrentScriptFilePath(const QString & a_filePath)\n{\n\tif(m_scriptFilePath == a_filePath)\n\t\treturn;\n\n\tm_scriptFilePath = a_filePath;\n\tm_pSettingsManager->setLastUsedPath(a_filePath);\n\tslotChangeWindowTitle();\n\tfillRecentScriptsMenu();\n}\n\n// END OF void MainWindow::setCurrentScriptFilePath(const QString & a_filePath)\n//==============================================================================\n\nvoid MainWindow::loadStartUpScript()\n{\n\tslotNewScript();\n\n\tQStringList argumentsList = QCoreApplication::arguments();\n    if(argumentsList.size() > 1)\n\t\tloadScriptFromFile(argumentsList.at(1));\n\telse if(m_pSettingsManager->getAutoLoadLastScript())\n\t{\n\t\tQString lastUsedPath = m_pSettingsManager->getLastUsedPath();\n\t\tif(!lastUsedPath.isEmpty())\n\t\t\tloadScriptFromFile(lastUsedPath);\n\t}\n}\n\n// END OF void MainWindow::loadStartUpScript()\n//==============================================================================\n\nvoid MainWindow::loadFonts()\n{\n\tQResource digitalMiniFontResource(\":/fonts/DigitalMini.ttf\");\n\tQByteArray digitalMiniFontData((const char *)digitalMiniFontResource.data(),\n\t\tdigitalMiniFontResource.size());\n\tQFontDatabase::addApplicationFontFromData(digitalMiniFontData);\n}\n\n// END OF void MainWindow::loadFonts()\n//==============================================================================\n\nvoid MainWindow::destroyOrphanQObjects()\n{\n\tfor(QObject ** ppObject : m_orphanQObjects)\n\t{\n\t\tif(!ppObject)\n\t\t\tcontinue;\n\t\tif(!*ppObject)\n\t\t\tcontinue;\n\t\tdelete *ppObject;\n\t\t*ppObject = nullptr;\n\t}\n}\n\n// END OF void MainWindow::destroyOrphanQObjects()\n//==============================================================================\n\nvoid MainWindow::saveGeometryDelayed()\n{\n\tQApplication::processEvents();\n\tif(!isMaximized())\n\t{\n\t\tm_windowGeometry = saveGeometry();\n\t\tm_pGeometrySaveTimer->start();\n\t}\n}\n\n// END OF void MainWindow::saveGeometryDelayed()\n//==============================================================================\n\nvoid MainWindow::reloadTexts()\n{\n\tQPoint pos = m_ui.scriptEdit->cursorPosition();\n\tif(!loadScriptFromFile(m_scriptFilePath))\n\t\tm_ui.scriptEdit->setModified(true);\n\tm_ui.scriptEdit->setCursorPosition(pos);\n}\n\n// END OF void MainWindow::reloadTexts()\n//==============================================================================\n"
  },
  {
    "path": "vsedit/src/main_window.h",
    "content": "#ifndef MAINWINDOW_H\n#define MAINWINDOW_H\n\n#include <ui_main_window.h>\n\n#include <vector>\n#include <mutex>\n\nclass SettingsManager;\nclass VapourSynthPluginsManager;\nclass VSScriptLibrary;\nclass PreviewDialog;\nclass SettingsDialog;\nclass ScriptBenchmarkDialog;\nclass EncodeDialog;\nclass TemplatesDialog;\nclass JobServerWatcherSocket;\nclass QTimer;\n\nclass MainWindow : public QMainWindow\n{\n\tQ_OBJECT\n\npublic:\n\n\tMainWindow(SettingsManager *settings);\n\n\tvirtual ~MainWindow();\n\npublic slots:\n\n\tvoid slotWriteLogMessage(int a_messageType, const QString & a_message);\n\tvoid slotWriteLogMessage(const QString & a_message,\n\t\tconst QString & a_style = LOG_STYLE_DEFAULT);\n\n\tvoid slotInsertTextIntoScriptAtNewLine(const QString & a_text);\n\tvoid slotInsertTextIntoScriptAtCursor(const QString & a_text);\n\nsignals:\n\n\tvoid signalToggleAttachedConsole();\n\nprotected:\n\n\tvoid closeEvent(QCloseEvent * a_pEvent) override;\n\n\tvoid moveEvent(QMoveEvent * a_pEvent) override;\n\n\tvoid resizeEvent(QResizeEvent * a_pEvent) override;\n\n\tvoid changeEvent(QEvent * a_pEvent) override;\n\nprivate slots:\n\n\tvoid slotNewScript();\n\tbool slotSaveScript();\n\tbool slotSaveScriptAs();\n\tbool slotOpenScript();\n\n\tvoid slotTemplates();\n\n\tvoid slotPreview();\n\tvoid slotCheckScript();\n\tvoid slotBenchmark();\n\tvoid slotEncode();\n\tvoid slotEnqueueEncodeJob();\n\tvoid slotJobs();\n\tvoid slotToggleConsole();\n\n\tvoid slotAbout();\n\n\tvoid slotChangeWindowTitle();\n\n\tvoid slotEditorTextChanged();\n\n\tvoid slotOpenRecentScriptActionTriggered();\n\n\tvoid slotSettingsChanged();\n\n\tvoid slotScriptFileDropped(const QString & a_filePath, bool * a_pHandled);\n\n\tvoid slotSaveGeometry();\n\n\tvoid slotReloadTextFromDisk();\n\nprivate:\n\n\tvoid createActionsAndMenus();\n\n\tvoid fillRecentScriptsMenu();\n\n\tbool saveScriptToFile(const QString& a_filePath);\n\n\tbool loadScriptFromFile(const QString& a_filePath);\n\n\tbool safeToCloseFile();\n\n\tvoid setCurrentScriptFilePath(const QString & a_filePath);\n\n\tvoid loadStartUpScript();\n\n\tvoid loadFonts();\n\n\tvoid destroyOrphanQObjects();\n\n\tvoid saveGeometryDelayed();\n\n\tvoid reloadTexts();\n\n\tUi::MainWindow m_ui;\n\n\tSettingsManager * m_pSettingsManager;\n\tVapourSynthPluginsManager * m_pVapourSynthPluginsManager;\n\tVSScriptLibrary * m_pVSScriptLibrary;\n\n\tQAction * m_pActionNewScript;\n\tQAction * m_pActionOpenScript;\n\tQAction * m_pActionSaveScript;\n\tQAction * m_pActionSaveScriptAs;\n\tQAction * m_pActionTemplates;\n\tQAction * m_pActionSettings;\n\tQAction * m_pActionPreview;\n\tQAction * m_pActionCheckScript;\n\tQAction * m_pActionBenchmark;\n\tQAction * m_pActionEncode;\n\tQAction * m_pActionEnqueueEncodeJob;\n\tQAction * m_pActionJobs;\n\tQAction * m_pActionConsole;\n\tQAction * m_pActionExit;\n\tQAction * m_pActionAbout;\n\n\tstd::vector<QAction *> m_settableActionsList;\n\n\tQMenu * m_pMenuRecentScripts;\n\n\tPreviewDialog * m_pPreviewDialog;\n\tSettingsDialog * m_pSettingsDialog;\n\tScriptBenchmarkDialog * m_pBenchmarkDialog;\n\tEncodeDialog * m_pEncodeDialog;\n\tTemplatesDialog * m_pTemplatesDialog;\n\n\tQString m_scriptFilePath;\n\tQString m_lastSavedText;\n\n\tstd::vector<QObject **> m_orphanQObjects;\n\n\tJobServerWatcherSocket * m_pJobServerWatcherSocket;\n\n\tQTimer * m_pGeometrySaveTimer;\n\tQByteArray m_windowGeometry;\n\n\tQTimer * m_pReloadTextTimer;\n};\n\n#endif // MAINWINDOW_H\n"
  },
  {
    "path": "vsedit/src/main_window.ui",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<ui version=\"4.0\">\n <class>MainWindow</class>\n <widget class=\"QMainWindow\" name=\"MainWindow\">\n  <property name=\"geometry\">\n   <rect>\n    <x>0</x>\n    <y>0</y>\n    <width>847</width>\n    <height>721</height>\n   </rect>\n  </property>\n  <property name=\"windowTitle\">\n   <string>VapourSynth Editor</string>\n  </property>\n  <widget class=\"QWidget\" name=\"centralWidget\">\n   <layout class=\"QVBoxLayout\" name=\"verticalLayout\">\n    <property name=\"spacing\">\n     <number>0</number>\n    </property>\n    <property name=\"leftMargin\">\n     <number>0</number>\n    </property>\n    <property name=\"topMargin\">\n     <number>0</number>\n    </property>\n    <property name=\"rightMargin\">\n     <number>0</number>\n    </property>\n    <property name=\"bottomMargin\">\n     <number>0</number>\n    </property>\n    <item>\n     <widget class=\"ScriptEditor\" name=\"scriptEdit\"/>\n    </item>\n   </layout>\n  </widget>\n  <widget class=\"QMenuBar\" name=\"menuBar\">\n   <property name=\"geometry\">\n    <rect>\n     <x>0</x>\n     <y>0</y>\n     <width>847</width>\n     <height>21</height>\n    </rect>\n   </property>\n  </widget>\n  <widget class=\"QStatusBar\" name=\"statusBar\"/>\n  <widget class=\"QDockWidget\" name=\"dockWidget\">\n   <property name=\"features\">\n    <set>QDockWidget::NoDockWidgetFeatures</set>\n   </property>\n   <property name=\"allowedAreas\">\n    <set>Qt::BottomDockWidgetArea</set>\n   </property>\n   <property name=\"windowTitle\">\n    <string>Log</string>\n   </property>\n   <attribute name=\"dockWidgetArea\">\n    <number>8</number>\n   </attribute>\n   <widget class=\"QWidget\" name=\"dockWidgetContents\">\n    <layout class=\"QGridLayout\" name=\"gridLayout\">\n     <property name=\"leftMargin\">\n      <number>0</number>\n     </property>\n     <property name=\"topMargin\">\n      <number>0</number>\n     </property>\n     <property name=\"rightMargin\">\n      <number>0</number>\n     </property>\n     <property name=\"bottomMargin\">\n      <number>0</number>\n     </property>\n     <property name=\"spacing\">\n      <number>0</number>\n     </property>\n     <item row=\"0\" column=\"0\">\n      <widget class=\"VSEditorLog\" name=\"logView\">\n       <property name=\"textInteractionFlags\">\n        <set>Qt::LinksAccessibleByKeyboard|Qt::LinksAccessibleByMouse|Qt::TextBrowserInteraction|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set>\n       </property>\n      </widget>\n     </item>\n    </layout>\n   </widget>\n  </widget>\n </widget>\n <customwidgets>\n  <customwidget>\n   <class>ScriptEditor</class>\n   <extends>QPlainTextEdit</extends>\n   <header>../../src/script_editor/script_editor.h</header>\n  </customwidget>\n  <customwidget>\n   <class>VSEditorLog</class>\n   <extends>QTextEdit</extends>\n   <header>../../common-src/log/vs_editor_log.h</header>\n  </customwidget>\n </customwidgets>\n <resources/>\n <connections/>\n</ui>\n"
  },
  {
    "path": "vsedit/src/preview/preview_advanced_settings_dialog.cpp",
    "content": "#include \"preview_advanced_settings_dialog.h\"\n\n#include \"../../../common-src/settings/settings_manager.h\"\n#include \"../../../common-src/helpers.h\"\n\n#include <QMessageBox>\n\n//==============================================================================\n\nPreviewAdvancedSettingsDialog::PreviewAdvancedSettingsDialog(\n\tSettingsManager * a_pSettingsManager, QWidget * a_pParent) :\n\tQDialog(a_pParent, \n\t\t  Qt::Dialog\n\t\t| Qt::CustomizeWindowHint\n\t\t| Qt::WindowTitleHint\n\t\t| Qt::WindowCloseButtonHint)\n\t, m_pSettingsManager(a_pSettingsManager)\n{\n\tvsedit::disableFontKerning(this);\n\tm_ui.setupUi(this);\n\tsetWindowIcon(QIcon(\":settings.png\"));\n\n\tm_ui.yuvMatrixCoefficientsComboBox->addItem(\n\t\ttr(\"709\"), (int)YuvMatrixCoefficients::m709);\n\tm_ui.yuvMatrixCoefficientsComboBox->addItem(\n\t\ttr(\"470BG\"), (int)YuvMatrixCoefficients::m470BG);\n\tm_ui.yuvMatrixCoefficientsComboBox->addItem(\n\t\ttr(\"170M\"), (int)YuvMatrixCoefficients::m170M);\n\tm_ui.yuvMatrixCoefficientsComboBox->addItem(\n\t\ttr(\"2020 NCL\"), (int)YuvMatrixCoefficients::m2020_NCL);\n\n\tm_ui.chromaResamplingFilterComboBox->addItem(tr(\"Point\"),\n\t\t(int)ResamplingFilter::Point);\n\tm_ui.chromaResamplingFilterComboBox->addItem(tr(\"Bilinear\"),\n\t\t(int)ResamplingFilter::Bilinear);\n\tm_ui.chromaResamplingFilterComboBox->addItem(tr(\"Bicubic\"),\n\t\t(int)ResamplingFilter::Bicubic);\n\tm_ui.chromaResamplingFilterComboBox->addItem(tr(\"Spline16\"),\n\t\t(int)ResamplingFilter::Spline16);\n\tm_ui.chromaResamplingFilterComboBox->addItem(tr(\"Spline36\"),\n\t\t(int)ResamplingFilter::Spline36);\n\tm_ui.chromaResamplingFilterComboBox->addItem(tr(\"Spline64\"),\n\t\t(int)ResamplingFilter::Spline64);\n\tm_ui.chromaResamplingFilterComboBox->addItem(tr(\"Lanczos\"),\n\t\t(int)ResamplingFilter::Lanczos);\n\n\tm_ui.chromaPlacementComboBox->addItem(tr(\"Left / MPEG2\"),\n\t\t(int)ChromaPlacement::LEFT);\n\tm_ui.chromaPlacementComboBox->addItem(tr(\"Center / MPEG1 / JPEG\"),\n\t\t(int)ChromaPlacement::CENTER);\n\tm_ui.chromaPlacementComboBox->addItem(tr(\"Top-left\"),\n\t\t(int)ChromaPlacement::TOP_LEFT);\n\n\tm_ui.ditherTypeComboBox->addItem(\"Error Diffusion\",\n\t\t(int)DitherType::ERROR_DIFFUSION);\n\tm_ui.ditherTypeComboBox->addItem(\"None\", (int)DitherType::NONE);\n\tm_ui.ditherTypeComboBox->addItem(\"Ordered\", (int)DitherType::ORDERED);\n\tm_ui.ditherTypeComboBox->addItem(\"Random\", (int)DitherType::RANDOM);\n\n\tm_ui.syncOutputComboBox->addItem(\"Frame\", (int)SyncOutputNodesMode::Frame);\n\tm_ui.syncOutputComboBox->addItem(\"Timestamp\",\n\t\t(int)SyncOutputNodesMode::Time);\n\tm_ui.syncOutputComboBox->addItem(\"From Timeline\",\n\t\t(int)SyncOutputNodesMode::FromTimeLine);\n\n\tconnect(m_ui.okButton, SIGNAL(clicked()), this, SLOT(slotOk()));\n\tconnect(m_ui.applyButton, SIGNAL(clicked()), this, SLOT(slotApply()));\n\tconnect(m_ui.resetToDefaultButton, SIGNAL(clicked()),\n\t\tthis, SLOT(slotResetToDefault()));\n\tconnect(m_ui.cancelButton, SIGNAL(clicked()), this, SLOT(reject()));\n\tconnect(m_ui.silentSnapshotCheckBox, SIGNAL(clicked()),\n\t\tthis, SLOT(slotSilentSnapshotChanged()));\n\tconnect(m_ui.argumentsHelpButton, SIGNAL(clicked()),\n\t\tthis, SLOT(slotArgumentsHelpButtonPressed()));\n}\n\n// END OF PreviewAdvancedSettingsDialog::PreviewAdvancedSettingsDialog(\n//\t\tSettingsManager * a_pSettingsManager, QWidget * a_pParent)\n//==============================================================================\n\nPreviewAdvancedSettingsDialog::~PreviewAdvancedSettingsDialog()\n{\n}\n\n// END OF PreviewAdvancedSettingsDialog::~PreviewAdvancedSettingsDialog()\n//==============================================================================\n\nvoid PreviewAdvancedSettingsDialog::slotCall()\n{\n\tYuvMatrixCoefficients matrix =\n\t\tm_pSettingsManager->getYuvMatrixCoefficients();\n\tint comboIndex =\n\t\tm_ui.yuvMatrixCoefficientsComboBox->findData((int)matrix);\n\tif(comboIndex != -1)\n\t\tm_ui.yuvMatrixCoefficientsComboBox->setCurrentIndex(comboIndex);\n\n\tResamplingFilter filter = m_pSettingsManager->getChromaResamplingFilter();\n\tcomboIndex = m_ui.chromaResamplingFilterComboBox->findData((int)filter);\n\tif(comboIndex != -1)\n\t\tm_ui.chromaResamplingFilterComboBox->setCurrentIndex(comboIndex);\n\n\tChromaPlacement chromaPlacement = m_pSettingsManager->getChromaPlacement();\n\tcomboIndex = m_ui.chromaPlacementComboBox->findData((int)chromaPlacement);\n\tif(comboIndex != -1)\n\t\tm_ui.chromaPlacementComboBox->setCurrentIndex(comboIndex);\n\n\tDitherType ditherType = m_pSettingsManager->getDitherType();\n\tcomboIndex = m_ui.ditherTypeComboBox->findData((int)ditherType);\n\tif(comboIndex != -1)\n\t\tm_ui.ditherTypeComboBox->setCurrentIndex(comboIndex);\n\n\tm_ui.bicubicFilterParameterBSpinBox->setValue(\n\t\tm_pSettingsManager->getBicubicFilterParameterB());\n\tm_ui.bicubicFilterParameterCSpinBox->setValue(\n\t\tm_pSettingsManager->getBicubicFilterParameterC());\n\tm_ui.lanczosFilterTapsSpinBox->setValue(\n\t\tm_pSettingsManager->getLanczosFilterTaps());\n\n\tbool silentSnapshotEnabled = m_pSettingsManager->getSilentSnapshot();\n\tm_ui.silentSnapshotCheckBox->setChecked(silentSnapshotEnabled);\n\tm_ui.saveSnapshotTemplateLineEdit->setText(\n\t\tm_pSettingsManager->getSnapshotTemplate());\n\tm_ui.saveSnapshotTemplateLineEdit->setEnabled(silentSnapshotEnabled);\n\n\tSyncOutputNodesMode syncOutputMode = m_pSettingsManager->getSyncOutputMode();\n\tcomboIndex = m_ui.syncOutputComboBox->findData((int)syncOutputMode);\n\tif(comboIndex != -1)\n\t\tm_ui.syncOutputComboBox->setCurrentIndex(comboIndex);\n\n\tshow();\n}\n\n// END OF void PreviewAdvancedSettingsDialog::slotCall()\n//==============================================================================\n\nvoid PreviewAdvancedSettingsDialog::slotOk()\n{\n\tslotApply();\n\taccept();\n}\n\n// END OF void PreviewAdvancedSettingsDialog::slotOk()\n//==============================================================================\n\nvoid PreviewAdvancedSettingsDialog::slotApply()\n{\n\tm_pSettingsManager->setChromaResamplingFilter((ResamplingFilter)\n\t\tm_ui.chromaResamplingFilterComboBox->currentData().toInt());\n\tm_pSettingsManager->setYuvMatrixCoefficients((YuvMatrixCoefficients)\n\t\tm_ui.yuvMatrixCoefficientsComboBox->currentData().toInt());\n\tm_pSettingsManager->setChromaPlacement((ChromaPlacement)\n\t\tm_ui.chromaPlacementComboBox->currentData().toInt());\n\tm_pSettingsManager->setBicubicFilterParameterB(\n\t\tm_ui.bicubicFilterParameterBSpinBox->value());\n\tm_pSettingsManager->setBicubicFilterParameterC(\n\t\tm_ui.bicubicFilterParameterCSpinBox->value());\n\tm_pSettingsManager->setLanczosFilterTaps(\n\t\tm_ui.lanczosFilterTapsSpinBox->value());\n\tm_pSettingsManager->setDitherType((DitherType)\n\t\tm_ui.ditherTypeComboBox->currentData().toInt());\n\tm_pSettingsManager->setSilentSnapshot(\n\t\tm_ui.silentSnapshotCheckBox->isChecked());\n\tm_pSettingsManager->setSnapshotTemplate(\n\t\tm_ui.saveSnapshotTemplateLineEdit->text());\n\tm_pSettingsManager->setSyncOutputMode((SyncOutputNodesMode)\n\t\tm_ui.syncOutputComboBox->currentData().toInt());\n\n\temit signalSettingsChanged();\n}\n\n// END OF void PreviewAdvancedSettingsDialog::slotApply()\n//==============================================================================\n\nvoid PreviewAdvancedSettingsDialog::slotResetToDefault()\n{\n\tYuvMatrixCoefficients matrix = DEFAULT_YUV_MATRIX_COEFFICIENTS;\n\tint comboIndex = m_ui.yuvMatrixCoefficientsComboBox->findData((int)matrix);\n\tif(comboIndex != -1)\n\t\tm_ui.yuvMatrixCoefficientsComboBox->setCurrentIndex(comboIndex);\n\n\tResamplingFilter filter = DEFAULT_CHROMA_RESAMPLING_FILTER;\n\tcomboIndex = m_ui.chromaResamplingFilterComboBox->findData((int)filter);\n\tif(comboIndex != -1)\n\t\tm_ui.chromaResamplingFilterComboBox->setCurrentIndex(comboIndex);\n\n\tChromaPlacement chromaPlacement = DEFAULT_CHROMA_PLACEMENT;\n\tcomboIndex = m_ui.chromaPlacementComboBox->findData((int)chromaPlacement);\n\tif(comboIndex != -1)\n\t\tm_ui.chromaPlacementComboBox->setCurrentIndex(comboIndex);\n\n\tm_ui.bicubicFilterParameterBSpinBox->setValue(\n\t\tDEFAULT_BICUBIC_FILTER_PARAMETER_B);\n\tm_ui.bicubicFilterParameterCSpinBox->setValue(\n\t\tDEFAULT_BICUBIC_FILTER_PARAMETER_C);\n\tm_ui.lanczosFilterTapsSpinBox->setValue(\n\t\tDEFAULT_LANCZOS_FILTER_TAPS);\n\t\n\tDitherType ditherType = DEFAULT_DITHER_TYPE;\n\tcomboIndex = m_ui.ditherTypeComboBox->findData((int)ditherType);\n\tif(comboIndex != -1)\n\t\tm_ui.ditherTypeComboBox->setCurrentIndex(comboIndex);\n\n\tSyncOutputNodesMode syncOutputMode = DEFAULT_SYNC_OUTPUT_MODE;\n\tcomboIndex = m_ui.syncOutputComboBox->findData((int)syncOutputMode);\n\tif(comboIndex != -1)\n\t\tm_ui.syncOutputComboBox->setCurrentIndex(comboIndex);\n\n\tm_ui.silentSnapshotCheckBox->setChecked(DEFAULT_SILENT_SNAPSHOT);\n\tm_ui.saveSnapshotTemplateLineEdit->setText(DEFAULT_SNAPSHOT_TEMPLATE);\n\tm_ui.saveSnapshotTemplateLineEdit->setEnabled(false);\n}\n\n// END OF void PreviewAdvancedSettingsDialog::slotResetToDefault()\n//==============================================================================\n\nvoid PreviewAdvancedSettingsDialog::slotSilentSnapshotChanged()\n{\n\tbool silentSnapshotEnabled = m_ui.silentSnapshotCheckBox->isChecked();\n\tm_ui.saveSnapshotTemplateLineEdit->setEnabled(silentSnapshotEnabled);\n\n\temit signalSilentSnapshotChanged();\n}\n\nvoid PreviewAdvancedSettingsDialog::slotArgumentsHelpButtonPressed()\n{\n\tQString argumentsHelpString = tr(\"Use the following placeholders:\");\n\targumentsHelpString += QString(\"\\n%1 - %2\")\n\t\t.arg(tr(\"{f}\")).arg(tr(\"script file path\"));\n\targumentsHelpString += QString(\"\\n%1 - %2\")\n\t\t.arg(tr(\"{d}\")).arg(tr(\"script file directory\"));\n\targumentsHelpString += QString(\"\\n%1 - %2\")\n\t\t.arg(tr(\"{n}\")).arg(tr(\"script file name\"));\n\targumentsHelpString += QString(\"\\n%1 - %2\")\n\t\t.arg(tr(\"{o}\")).arg(tr(\"output index\"));\n\targumentsHelpString += QString(\"\\n%1 - %2\")\n\t\t.arg(tr(\"{i}\")).arg(tr(\"frame number\"));\n\targumentsHelpString += QString(\"\\n%1 - %2\")\n\t\t.arg(tr(\"{t}\")).arg(tr(\"timestamp\"));\n\targumentsHelpString += QString(\"\\n%1 - %2\")\n\t\t.arg(tr(\"{nm}\")).arg(tr(\"clip name\"));\n\targumentsHelpString += QString(\"\\n%1 - %2\")\n\t\t.arg(tr(\"{sc}\")).arg(tr(\"scene name\"));\n\tQString title = tr(\"Snapshot template arguments\");\n\tQMessageBox msgBox(this);\n\tmsgBox.setWindowTitle(title);\n\tmsgBox.setText(argumentsHelpString);\n\tvsedit::disableFontKerning(&msgBox);\n\tmsgBox.exec();\n}\n"
  },
  {
    "path": "vsedit/src/preview/preview_advanced_settings_dialog.h",
    "content": "#ifndef PREVIEW_ADVANCED_SETTINGS_DIALOG_H_INCLUDED\n#define PREVIEW_ADVANCED_SETTINGS_DIALOG_H_INCLUDED\n\n#include <ui_preview_advanced_settings_dialog.h>\n\nclass SettingsManager;\n\nclass PreviewAdvancedSettingsDialog : public QDialog\n{\n\tQ_OBJECT\n\npublic:\n\n\tPreviewAdvancedSettingsDialog(SettingsManager * a_pSettingsManager,\n\t\tQWidget * a_pParent = nullptr);\n\n\tvirtual ~PreviewAdvancedSettingsDialog();\n\npublic slots:\n\n\tvoid slotCall();\n\nsignals:\n\n\tvoid signalSettingsChanged();\n\n\tvoid signalSilentSnapshotChanged();\n\nprivate slots:\n\n\tvoid slotOk();\n\n\tvoid slotApply();\n\n\tvoid slotResetToDefault();\n\n\tvoid slotSilentSnapshotChanged();\n\n\tvoid slotArgumentsHelpButtonPressed();\n\nprivate:\n\n\tUi::PreviewAdvancedSettingsDialog m_ui;\n\n\tSettingsManager * m_pSettingsManager;\n};\n\n#endif // PREVIEW_ADVANCED_SETTINGS_DIALOG_H_INCLUDED\n"
  },
  {
    "path": "vsedit/src/preview/preview_advanced_settings_dialog.ui",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<ui version=\"4.0\">\n <class>PreviewAdvancedSettingsDialog</class>\n <widget class=\"QDialog\" name=\"PreviewAdvancedSettingsDialog\">\n  <property name=\"geometry\">\n   <rect>\n    <x>0</x>\n    <y>0</y>\n    <width>364</width>\n    <height>181</height>\n   </rect>\n  </property>\n  <property name=\"windowTitle\">\n   <string>Preview Advanced Settings</string>\n  </property>\n  <layout class=\"QGridLayout\" name=\"gridLayout\">\n   <property name=\"leftMargin\">\n    <number>6</number>\n   </property>\n   <property name=\"topMargin\">\n    <number>6</number>\n   </property>\n   <property name=\"rightMargin\">\n    <number>6</number>\n   </property>\n   <property name=\"bottomMargin\">\n    <number>6</number>\n   </property>\n   <property name=\"spacing\">\n    <number>4</number>\n   </property>\n   <item row=\"0\">\n    <widget class=\"QLabel\" name=\"label_text\">\n     <property name=\"text\">\n      <string>Settings below may be overriden by frame properties.</string>\n     </property>\n    </widget>\n   </item>\n   <item row=\"4\" column=\"0\">\n    <widget class=\"QLabel\" name=\"label_4\">\n     <property name=\"text\">\n      <string>Bicubic filter parameter b:</string>\n     </property>\n    </widget>\n   </item>\n   <item row=\"1\" column=\"1\">\n    <widget class=\"QComboBox\" name=\"yuvMatrixCoefficientsComboBox\"/>\n   </item>\n   <item row=\"3\" column=\"1\">\n    <widget class=\"QComboBox\" name=\"chromaPlacementComboBox\"/>\n   </item>\n   <item row=\"2\" column=\"1\">\n    <widget class=\"QComboBox\" name=\"chromaResamplingFilterComboBox\"/>\n   </item>\n   <item row=\"2\" column=\"0\">\n    <widget class=\"QLabel\" name=\"label_2\">\n     <property name=\"text\">\n      <string>Chroma resampling filter:</string>\n     </property>\n    </widget>\n   </item>\n   <item row=\"1\" column=\"0\">\n    <widget class=\"QLabel\" name=\"label\">\n     <property name=\"text\">\n      <string>Y'CbCr / Y'UV matrix coefficients:</string>\n     </property>\n    </widget>\n   </item>\n   <item row=\"3\" column=\"0\">\n    <widget class=\"QLabel\" name=\"label_3\">\n     <property name=\"text\">\n      <string>Chroma placement:</string>\n     </property>\n    </widget>\n   </item>\n   <item row=\"6\" column=\"0\">\n    <widget class=\"QLabel\" name=\"label_6\">\n     <property name=\"text\">\n      <string>Lanczos filter taps:</string>\n     </property>\n    </widget>\n   </item>\n   <item row=\"5\" column=\"0\">\n    <widget class=\"QLabel\" name=\"label_5\">\n     <property name=\"text\">\n      <string>Bicubic filter parameter c:</string>\n     </property>\n    </widget>\n   </item>\n   <item row=\"5\" column=\"1\">\n    <widget class=\"QDoubleSpinBox\" name=\"bicubicFilterParameterCSpinBox\">\n     <property name=\"decimals\">\n      <number>6</number>\n     </property>\n     <property name=\"minimum\">\n      <double>-100000.000000000000000</double>\n     </property>\n     <property name=\"maximum\">\n      <double>100000.000000000000000</double>\n     </property>\n     <property name=\"singleStep\">\n      <double>0.000001000000000</double>\n     </property>\n     <property name=\"value\">\n      <double>0.333333000000000</double>\n     </property>\n    </widget>\n   </item>\n   <item row=\"4\" column=\"1\">\n    <widget class=\"QDoubleSpinBox\" name=\"bicubicFilterParameterBSpinBox\">\n     <property name=\"decimals\">\n      <number>6</number>\n     </property>\n     <property name=\"minimum\">\n      <double>-100000.000000000000000</double>\n     </property>\n     <property name=\"maximum\">\n      <double>100000.000000000000000</double>\n     </property>\n     <property name=\"singleStep\">\n      <double>0.000001000000000</double>\n     </property>\n     <property name=\"value\">\n      <double>0.333333000000000</double>\n     </property>\n    </widget>\n   </item>\n   <item row=\"10\" column=\"0\">\n    <widget class=\"QLabel\" name=\"label_sync\">\n     <property name=\"text\">\n      <string>Sync output nodes with:</string>\n     </property>\n    </widget>\n   </item>\n   <item row=\"10\" column=\"1\">\n    <widget class=\"QComboBox\" name=\"syncOutputComboBox\"/>\n   </item>\n   <item row=\"11\" column=\"0\" colspan=\"2\">\n    <layout class=\"QHBoxLayout\" name=\"horizontalLayout\">\n     <item>\n      <widget class=\"QPushButton\" name=\"okButton\">\n       <property name=\"text\">\n        <string>OK</string>\n       </property>\n       <property name=\"autoDefault\">\n        <bool>true</bool>\n       </property>\n      </widget>\n     </item>\n     <item>\n      <widget class=\"QPushButton\" name=\"applyButton\">\n       <property name=\"text\">\n        <string>Apply</string>\n       </property>\n      </widget>\n     </item>\n     <item>\n      <widget class=\"QPushButton\" name=\"resetToDefaultButton\">\n       <property name=\"text\">\n        <string>Reset to default</string>\n       </property>\n      </widget>\n     </item>\n     <item>\n      <widget class=\"QPushButton\" name=\"cancelButton\">\n       <property name=\"text\">\n        <string>Cancel</string>\n       </property>\n      </widget>\n     </item>\n    </layout>\n   </item>\n   <item row=\"7\" column=\"0\">\n    <widget class=\"QLabel\" name=\"label_dither\">\n     <property name=\"text\">\n      <string>Dither type:</string>\n     </property>\n    </widget>\n   </item>\n   <item row=\"7\" column=\"1\">\n    <widget class=\"QComboBox\" name=\"ditherTypeComboBox\"/>\n   </item>\n   <item row=\"6\" column=\"1\">\n    <widget class=\"QSpinBox\" name=\"lanczosFilterTapsSpinBox\">\n     <property name=\"minimum\">\n      <number>2</number>\n     </property>\n     <property name=\"maximum\">\n      <number>4096</number>\n     </property>\n     <property name=\"value\">\n      <number>3</number>\n     </property>\n    </widget>\n   </item>\n   <item row=\"8\" column=\"0\">\n    <widget class=\"QCheckBox\" name=\"silentSnapshotCheckBox\">\n     <property name=\"text\">\n      <string>Silently save snapshots with template:</string>\n     </property>\n    </widget>\n   </item>\n   <item row=\"8\" column=\"1\">\n    <widget class=\"QToolButton\" name=\"argumentsHelpButton\">\n     <property name=\"text\">\n     </property>\n     <property name=\"icon\">\n      <iconset resource=\"../../../resources/vsedit.qrc\">\n      <normaloff>:/information.png</normaloff>:/information.png</iconset>\n     </property>\n    </widget>\n   </item>\n   <item row=\"9\" column=\"0\" colspan=\"2\">\n    <widget class=\"QLineEdit\" name=\"saveSnapshotTemplateLineEdit\">\n    </widget>\n   </item>\n  </layout>\n </widget>\n <resources/>\n <connections/>\n</ui>\n"
  },
  {
    "path": "vsedit/src/preview/preview_area.cpp",
    "content": "#include \"preview_area.h\"\n\n#include \"scroll_navigator.h\"\n\n#include <QLabel>\n#include <QKeyEvent>\n#include <QWheelEvent>\n#include <QMouseEvent>\n#include <QEnterEvent>\n#include <QScrollBar>\n#include <QCoreApplication>\n#include <QTimer>\n\n//==============================================================================\n\nPreviewArea::PreviewArea(QWidget * a_pParent) : QScrollArea(a_pParent)\n\t, m_pPreviewLabel(nullptr)\n\t, m_pScrollNavigator(nullptr)\n\t, m_draggingPreview(false)\n\t, m_lastCursorPos(0, 0)\n\t, m_lastPreviewLabelPos(0, 0)\n\t, m_lastScenePos(0.0, 0.0)\n\t, m_newToPreviewer(false)\n{\n\tm_pPreviewLabel = new QLabel(this);\n\tm_pPreviewLabel->setPixmap(QPixmap());\n\tm_pPreviewLabel->setAlignment(Qt::AlignTop | Qt::AlignLeft);\n\tm_pPreviewLabel->move(0, 0);\n\tQScrollArea::setWidget(m_pPreviewLabel);\n\tsetWidgetResizable(true);\n\n\tm_pScrollNavigator = new ScrollNavigator(this);\n\tint scrollFrameWidth = frameWidth();\n\tm_pScrollNavigator->move(pos() +\n\t\tQPoint(scrollFrameWidth, scrollFrameWidth));\n\tm_pScrollNavigator->setVisible(false);\n\n\tsetAttribute(Qt::WA_Hover, true);\n\tsetMouseTracking(true);\n\tm_pPreviewLabel->setMouseTracking(true);\n}\n\n// END OF PreviewArea::PreviewArea(QWidget * a_pParent)\n//==============================================================================\n\nPreviewArea::~PreviewArea()\n{\n\n}\n\n// END OF PreviewArea::~PreviewArea()\n//==============================================================================\n\nvoid PreviewArea::setPixmap(const QPixmap & a_pixmap, bool a_isVideoFrame)\n{\n\tm_pPreviewLabel->setPixmap(a_pixmap);\n\tm_pixmapWidth = a_pixmap.width();\n\tm_pixmapHeight = a_pixmap.height();\n\tif(a_isVideoFrame && m_newToPreviewer)\n\t{\n\t\tm_newToPreviewer = false;\n\t\tQCoreApplication::processEvents();\n\t\tQTimer::singleShot(0, this, SLOT(slotSetScrollBarPositions()));\n\t}\n}\n\n// END OF void PreviewArea::setPixmap(const QPixmap & a_pixmap)\n//==============================================================================\n\nvoid PreviewArea::checkMouseOverPreview(const QPointF & a_pixelPos) \n{\n        if(!m_pPreviewLabel->underMouse())\n\t\treturn;\n\n\tdouble pX = a_pixelPos.x();\n\tdouble pY = a_pixelPos.y();\n\tif(pX < 0 || pY < 0 ||\n\t\tpX >= pixmapWidth() || pY >= pixmapHeight())\n\t\treturn;\n\n\temit signalMouseOverPoint(pX, pY);\n}\n\n// END OF void PreviewArea::checkMouseOverPreview(\n//\t\tconst QPoint & a_globalMousePos)\n//==============================================================================\n\nvoid PreviewArea::slotScrollLeft()\n{\n\thorizontalScrollBar()->setValue(0);\n}\n\n// END OF void PreviewArea::slotScrollLeft()\n//==============================================================================\n\nvoid PreviewArea::slotScrollRight()\n{\n\tQCoreApplication::processEvents();\n\tQScrollBar * pHorizontalScrollbar = horizontalScrollBar();\n\tpHorizontalScrollbar->setValue(pHorizontalScrollbar->maximum());\n}\n\n// END OF void PreviewArea::slotScrollRight()\n//==============================================================================\n\nvoid PreviewArea::slotScrollTop()\n{\n\tverticalScrollBar()->setValue(0);\n}\n\n// END OF void PreviewArea::slotScrollTop()\n//==============================================================================\n\nvoid PreviewArea::slotScrollBottom()\n{\n\tQCoreApplication::processEvents();\n\tQScrollBar * pVerticalScrollbar = verticalScrollBar();\n\tpVerticalScrollbar->setValue(pVerticalScrollbar->maximum());\n}\n\n// END OF void PreviewArea::slotScrollBottom()\n//==============================================================================\n\nvoid PreviewArea::resizeEvent(QResizeEvent * a_pEvent)\n{\n\tQScrollArea::resizeEvent(a_pEvent);\n\temit signalSizeChanged();\n}\n\n// END OF void PreviewArea::resizeEvent(QResizeEvent * a_pEvent)\n//==============================================================================\n\nvoid PreviewArea::keyPressEvent(QKeyEvent * a_pEvent)\n{\n\tif(a_pEvent->modifiers() != Qt::NoModifier)\n\t{\n\t\tQScrollArea::keyPressEvent(a_pEvent);\n\t\treturn;\n\t}\n\n\tint key = a_pEvent->key();\n\tint wantedKeys[] = {Qt::Key_Left, Qt::Key_Right, Qt::Key_Up, Qt::Key_Down,\n\t\tQt::Key_PageUp, Qt::Key_PageDown, Qt::Key_Home, Qt::Key_End};\n\tint * pKeysEnd = wantedKeys + sizeof(wantedKeys) / sizeof(*wantedKeys);\n\tif(pKeysEnd != std::find(wantedKeys, pKeysEnd, key))\n\t{\n\t\ta_pEvent->ignore();\n\t\treturn;\n\t}\n\n\tQScrollArea::keyPressEvent(a_pEvent);\n}\n\n// END OF void PreviewArea::keyPressEvent(QKeyEvent * a_pEvent)\n//==============================================================================\n\nvoid PreviewArea::wheelEvent(QWheelEvent * a_pEvent)\n{\n\tif(a_pEvent->modifiers() == Qt::ControlModifier)\n\t{\n\t\temit signalCtrlWheel(a_pEvent->angleDelta());\n\t\ta_pEvent->ignore();\n\t\treturn;\n\t}\n\n\tQScrollArea::wheelEvent(a_pEvent);\n}\n\n// END OF void PreviewArea::wheelEvent(QWheelEvent * a_pEvent)\n//==============================================================================\n\nvoid PreviewArea::mousePressEvent(QMouseEvent * a_pEvent)\n{\n\tif(a_pEvent->buttons() == Qt::LeftButton)\n\t{\n\t\tm_draggingPreview = true;\n\t\tm_lastCursorPos = a_pEvent->globalPosition().toPoint();\n\t\tm_lastPreviewLabelPos = m_pPreviewLabel->pos();\n\t\tm_pScrollNavigator->setVisible(true);\n\t\tdrawScrollNavigator();\n\t\ta_pEvent->accept();\n\t\treturn;\n\t}\n\n\tQScrollArea::mousePressEvent(a_pEvent);\n}\n\n// END OF void PreviewArea::mousePressEvent(QMouseEvent * a_pEvent)\n//==============================================================================\n\nvoid PreviewArea::mouseMoveEvent(QMouseEvent * a_pEvent)\n{\n\tif((a_pEvent->buttons() & Qt::LeftButton) && m_draggingPreview)\n\t{\n\t\tQPoint newCursorPos = a_pEvent->globalPosition().toPoint();\n\t\tQPoint posDifference = newCursorPos - m_lastCursorPos;\n\t\tQPoint newPreviewLabelPos = m_lastPreviewLabelPos +\n\t\t\tposDifference;\n\n\t\thorizontalScrollBar()->setValue(-newPreviewLabelPos.x());\n\t\tverticalScrollBar()->setValue(-newPreviewLabelPos.y());\n\n\t\tdrawScrollNavigator();\n\t\ta_pEvent->accept();\n\t\treturn;\n\t}\n\tm_lastScenePos = a_pEvent->scenePosition();\n\tcheckMouseOverPreview(pixelPosition());\n\n\tQScrollArea::mouseMoveEvent(a_pEvent);\n}\n\n// END OF void PreviewArea::mouseMoveEvent(QMouseEvent * a_pEvent)\n//==============================================================================\n\nvoid PreviewArea::mouseReleaseEvent(QMouseEvent * a_pEvent)\n{\n\tQt::MouseButton releasedButton = a_pEvent->button();\n\tif(releasedButton == Qt::LeftButton)\n\t{\n\t\tm_draggingPreview = false;\n\t\tm_pScrollNavigator->setVisible(false);\n\t\ta_pEvent->accept();\n\t\treturn;\n\t}\n\telse if(releasedButton == Qt::MiddleButton)\n\t\temit signalMouseMiddleButtonReleased();\n\telse if(releasedButton == Qt::RightButton)\n\t\temit signalMouseRightButtonReleased();\n\n\tQScrollArea::mouseReleaseEvent(a_pEvent);\n}\n\nvoid PreviewArea::enterEvent(QEnterEvent *a_pEvent)\n{\n\tm_lastScenePos = a_pEvent->scenePosition();\n\tcheckMouseOverPreview(pixelPosition());\n\tQScrollArea::enterEvent(a_pEvent);\n\tsetAttribute(Qt::WA_Hover, false);\n}\n\n// END OF void PreviewArea::mouseReleaseEvent(QMouseEvent * a_pEvent)\n//==============================================================================\n\nvoid PreviewArea::drawScrollNavigator()\n{\n\tint contentsWidth = this->pixmapWidth();\n\tint contentsHeight = this->pixmapHeight();\n\tint viewportX = -m_pPreviewLabel->x();\n\tint viewportY = -m_pPreviewLabel->y();\n\tint viewportWidth = viewport()->width();\n\tint viewportHeight = viewport()->height();\n\n\tm_pScrollNavigator->draw(contentsWidth, contentsHeight, viewportX,\n\t\tviewportY, viewportWidth, viewportHeight);\n}\n\n// END OF void PreviewArea::drawScrollNavigator()\n//==============================================================================\n\nQPointF PreviewArea::pixelPosition() const\n{\n\tQPoint lPos = m_pPreviewLabel->geometry().topLeft();\n\tQMargins lMargin = contentsMargins();\n\tQPoint mOffset = QPoint(lMargin.left(), lMargin.top());\n\treturn m_lastScenePos - lPos - mOffset;\n}\n\nQPoint PreviewArea::getScrollBarPositions() const\n{\n\tint x = horizontalScrollBar()->value();\n\tint y = verticalScrollBar()->value();\n\treturn QPoint(x, y);\n}\n\nvoid PreviewArea::slotSetScrollBarPositions()\n{\n\thorizontalScrollBar()->setValue(m_lastScrollBarPos.x());\n\tverticalScrollBar()->setValue(m_lastScrollBarPos.y());\n}\n\nvoid PreviewArea::getScrollBarPositionsFromPreviewer(const QPoint & pos)\n{\n\tm_newToPreviewer = true;\n\tm_lastScrollBarPos = pos;\n}\n"
  },
  {
    "path": "vsedit/src/preview/preview_area.h",
    "content": "#ifndef PREVIEWAREA_H\n#define PREVIEWAREA_H\n\n#include <QScrollArea>\n#include <QPixmap>\n#include <QPoint>\n\nclass QLabel;\nclass ScrollNavigator;\nclass QKeyEvent;\nclass QWheelEvent;\nclass QMouseEvent;\nclass QEnterEvent;\n\nclass PreviewArea : public QScrollArea\n{\n\tQ_OBJECT\n\npublic:\n\n\tPreviewArea(QWidget * a_pParent = nullptr);\n\n\tvirtual ~PreviewArea();\n\n\tvoid setWidget(QWidget * a_pWidget) = delete;\n\n\tint pixmapWidth() const { return m_pixmapWidth; }\n\n\tint pixmapHeight() const { return m_pixmapHeight; }\n\n\tvoid setPixmap(const QPixmap & a_pixmap, bool a_isVideoFrame = false);\n\n\tvoid checkMouseOverPreview(const QPointF & a_pixelPos);\n\n\tQPointF pixelPosition() const;\n\n\tQPoint getScrollBarPositions() const;\n\n\tvoid getScrollBarPositionsFromPreviewer(const QPoint & pos);\n\npublic slots:\n\n\tvoid slotScrollLeft();\n\tvoid slotScrollRight();\n\tvoid slotScrollTop();\n\tvoid slotScrollBottom();\n\tvoid slotSetScrollBarPositions();\n\n\nprotected:\n\n\tvoid resizeEvent(QResizeEvent * a_pEvent) override;\n\tvoid keyPressEvent(QKeyEvent * a_pEvent) override;\n\tvoid wheelEvent(QWheelEvent * a_pEvent) override;\n\tvoid mousePressEvent(QMouseEvent * a_pEvent) override;\n\tvoid mouseMoveEvent(QMouseEvent * a_pEvent) override;\n\tvoid mouseReleaseEvent(QMouseEvent * a_pEvent) override;\n\tvoid enterEvent(QEnterEvent * a_pEvent) override;\n\nsignals:\n\n\tvoid signalSizeChanged();\n\tvoid signalCtrlWheel(QPoint a_angleDelta);\n\tvoid signalMouseMiddleButtonReleased();\n\tvoid signalMouseRightButtonReleased();\n\tvoid signalMouseOverPoint(double a_normX, double a_normY);\n\nprivate:\n\n\tvoid drawScrollNavigator();\n\n\tQLabel * m_pPreviewLabel;\n\n\tScrollNavigator * m_pScrollNavigator;\n\n\tbool m_draggingPreview;\n\tQPoint m_lastCursorPos;\n\tQPoint m_lastPreviewLabelPos;\n\tQPointF m_lastScenePos;\n\n\tint m_pixmapWidth = 0;\n\tint m_pixmapHeight = 0;\n\n\tbool m_newToPreviewer;\n\tQPoint m_lastScrollBarPos;\n};\n\n#endif // PREVIEWAREA_H\n"
  },
  {
    "path": "vsedit/src/preview/preview_dialog.cpp",
    "content": "#include \"preview_dialog.h\"\n\n#include \"../../../common-src/helpers.h\"\n#include \"../../../common-src/libp2p/p2p_api.h\"\n#include \"../../../common-src/vapoursynth/vapoursynth_script_processor.h\"\n#include \"../../../common-src/settings/settings_manager.h\"\n#include \"scroll_navigator.h\"\n#include \"../../../common-src/timeline_slider/timeline_slider.h\"\n#include \"preview_advanced_settings_dialog.h\"\n#include \"zoom_ratio_spinbox.h\"\n\n#include <VapourSynth4.h>\n#include <VSHelper4.h>\n\n#include <QEvent>\n#include <QCloseEvent>\n#include <QMoveEvent>\n#include <QResizeEvent>\n#include <QKeyEvent>\n#include <QCursor>\n#include <QStandardPaths>\n#include <QFileDialog>\n#include <QMessageBox>\n#include <QPoint>\n#include <QMenu>\n#include <QActionGroup>\n#include <QAction>\n#include <QByteArray>\n#include <QClipboard>\n#include <QTimer>\n#include <QImageWriter>\n#include <QFileInfo>\n#include <QInputDialog>\n#include <QRegularExpression>\n#include <algorithm>\n#include <cmath>\n\n#ifdef Q_OS_WIN // AUDIO\n#include <QMediaDevices>\n#include <random>\n\n// Random numbers\nstd::random_device rd;\nstd::mt19937_64 gen(rd());\nstd::uniform_int_distribution<int64_t> unif16(-32768, 32768);\n\nstatic inline uint16_t dither32to16(uint32_t a)\n{\n\tint64_t perturbed = VSMAX(VSMIN((int64_t)a + unif16(gen) + unif16(gen) + 32768, 0xFFFFFFFF), 0);\n\tuint16_t base = perturbed >> 16;\n\treturn base;\n}\n\nstatic inline int16_t dither32Fto16(float a)\n{\n\tstatic double den = 65536 * 32767;\n\tfloat perturbed = VSMAX(VSMIN(a + 1.0f + (float)((unif16(gen) + unif16(gen)) / den), 2.0f), 0.0f);\n\treturn int(perturbed * 32767.0f) - 32767;\n}\n\nPreviewDialog::AudioFrame::AudioFrame() : number(-1), outputIndex(-1), data(QByteArray())\n{\n}\n\nPreviewDialog::AudioFrame::AudioFrame(int a_number, int a_outputIndex, QByteArray a_data) : number(a_number), outputIndex(a_outputIndex), data(a_data)\n{\n\tdata.detach();\n}\n\nbool PreviewDialog::AudioFrame::operator==(const AudioFrame &a_other) const\n{\n    return ((number == a_other.number) && (outputIndex == a_other.outputIndex));\n}\n#endif\n\n//==============================================================================\n\n#define BEGIN_CROP_VALUES_CHANGE \\\n\tif(m_changingCropValues) \\\n\t\treturn; \\\n\tm_changingCropValues = true;\n\n#define END_CROP_VALUES_CHANGE \\\n\tm_changingCropValues = false;\n\n//==============================================================================\n\nconst char TIMELINE_BOOKMARKS_FILE_SUFFIX[] = \".bookmarks\";\n\n//==============================================================================\n\nPreviewDialog::PreviewDialog(SettingsManager * a_pSettingsManager,\n\tVSScriptLibrary * a_pVSScriptLibrary, bool a_inPreviewer, QWidget * a_pParent) :\n\tVSScriptProcessorDialog(a_pSettingsManager, a_pVSScriptLibrary, a_pParent)\n\t, m_pAdvancedSettingsDialog(nullptr)\n\t, m_frameExpected(0)\n\t, m_frameTimestampExpected(0)\n\t, m_frameShown(-1)\n\t, m_lastFrameRequestedForPlay(-1)\n\t, m_bigFrameStep(10)\n\t, m_cpFrame(nullptr)\n\t, m_cpPreviewFrame(nullptr)\n\t, m_changingCropValues(false)\n\t, m_pPreviewContextMenu(nullptr)\n\t, m_pActionFrameToClipboard(nullptr)\n\t, m_pActionSaveSnapshot(nullptr)\n\t, m_pActionToggleZoomPanel(nullptr)\n\t, m_pMenuZoomModes(nullptr)\n\t, m_pActionGroupZoomModes(nullptr)\n\t, m_pActionSetZoomModeNoZoom(nullptr)\n\t, m_pActionSetZoomModeFixedRatio(nullptr)\n\t, m_pActionSetZoomModeFitToFrame(nullptr)\n\t, m_pMenuZoomScaleModes(nullptr)\n\t, m_pActionGroupZoomScaleModes(nullptr)\n\t, m_pActionSetZoomScaleModeNearest(nullptr)\n\t, m_pActionSetZoomScaleModeBilinear(nullptr)\n\t, m_pActionToggleCropPanel(nullptr)\n\t, m_pActionToggleTimeLinePanel(nullptr)\n\t, m_pMenuTimeLineModes(nullptr)\n\t, m_pActionGroupTimeLineModes(nullptr)\n\t, m_pActionSetTimeLineModeTime(nullptr)\n\t, m_pActionSetTimeLineModeFrames(nullptr)\n\t, m_pActionTimeStepForward(nullptr)\n\t, m_pActionTimeStepBack(nullptr)\n\t, m_pActionPasteCropSnippetIntoScript(nullptr)\n\t, m_pActionAdvancedSettingsDialog(nullptr)\n\t, m_pActionToggleColorPicker(nullptr)\n\t, m_pActionPlay(nullptr)\n\t, m_pActionLoadChapters(nullptr)\n\t, m_pActionClearBookmarks(nullptr)\n\t, m_pActionBookmarkCurrentFrame(nullptr)\n\t, m_pActionUnbookmarkCurrentFrame(nullptr)\n\t, m_pActionGoToPreviousBookmark(nullptr)\n\t, m_pActionGoToNextBookmark(nullptr)\n\t, m_pActionPasteShownFrameNumberIntoScript(nullptr)\n\t, m_pActionJumpToFrame(nullptr)\n\t, m_pActionToggleFramePropsPanel(nullptr)\n\t, m_pActionSwitchToOutputIndex0(nullptr)\n\t, m_pActionSwitchToOutputIndex1(nullptr)\n\t, m_pActionSwitchToOutputIndex2(nullptr)\n\t, m_pActionSwitchToOutputIndex3(nullptr)\n\t, m_pActionSwitchToOutputIndex4(nullptr)\n\t, m_pActionSwitchToOutputIndex5(nullptr)\n\t, m_pActionSwitchToOutputIndex6(nullptr)\n\t, m_pActionSwitchToOutputIndex7(nullptr)\n\t, m_pActionSwitchToOutputIndex8(nullptr)\n\t, m_pActionSwitchToOutputIndex9(nullptr)\n\t, m_pActionSwitchToOutputIndex10(nullptr)\n\t, m_pActionSwitchToOutputIndex11(nullptr)\n\t, m_pActionSwitchToOutputIndex12(nullptr)\n\t, m_pActionSwitchToOutputIndex13(nullptr)\n\t, m_pActionSwitchToOutputIndex14(nullptr)\n\t, m_pActionSwitchToOutputIndex15(nullptr)\n\t, m_pActionSwitchToOutputIndex16(nullptr)\n\t, m_pActionSwitchToOutputIndex17(nullptr)\n\t, m_pActionSwitchToOutputIndex18(nullptr)\n\t, m_pActionSwitchToOutputIndex19(nullptr)\n\t, m_pActionSwitchToPreviousOutputIndex(nullptr)\n\t, m_pActionSwitchToNextOutputIndex(nullptr)\n\t, m_playing(false)\n\t, m_processingPlayQueue(false)\n\t, m_nativePlaybackRate(false)\n\t, m_secondsBetweenFrames(0)\n\t, m_pPlayTimer(nullptr)\n\t, m_alwaysKeepCurrentFrame(DEFAULT_ALWAYS_KEEP_CURRENT_FRAME)\n\t, m_pGeometrySaveTimer(nullptr)\n\t, m_devicePixelRatio(-1)\n\t, m_pFramePropsPanel(nullptr)\n\t, m_toChangeTitle(false)\n\t, m_inPreviewer(a_inPreviewer)\n{\n\tvsedit::disableFontKerning(this);\n\tm_ui.setupUi(this);\n\tsetWindowIcon(QIcon(\":preview.png\"));\n\n\tm_iconPlay = QIcon(\":play.png\");\n\tm_iconPause = QIcon(\":pause.png\");\n\n\tm_pAdvancedSettingsDialog = new PreviewAdvancedSettingsDialog(\n\t\tm_pSettingsManager, this);\n\n\tm_pPlayTimer = new QTimer(this);\n\tm_pPlayTimer->setTimerType(Qt::PreciseTimer);\n\tm_pPlayTimer->setSingleShot(true);\n\n\tm_pFramePropsPanel = new FramePropsPanel(a_pSettingsManager, this);\n\n\tcreateActionsAndMenus();\n\n\tcreateStatusBar();\n\tm_pStatusBarWidget->setColorPickerVisible(\n\t\tm_pSettingsManager->getColorPickerVisible());\n\n\tm_ui.frameNumberSlider->setBigStep(m_bigFrameStep);\n\tm_ui.frameNumberSlider->setDisplayMode(\n\t\tm_pSettingsManager->getTimeLineMode());\n\n\tm_ui.frameToClipboardButton->setDefaultAction(m_pActionFrameToClipboard);\n\tm_ui.saveSnapshotButton->setDefaultAction(m_pActionSaveSnapshot);\n\tm_ui.advancedSettingsButton->setDefaultAction(\n\t\tm_pActionAdvancedSettingsDialog);\n\n\tsetUpZoomPanel();\n\tsetUpCropPanel();\n\tsetUpTimeLinePanel();\n\n\tm_ui.colorPickerButton->setDefaultAction(m_pActionToggleColorPicker);\n\n\tm_pGeometrySaveTimer = new QTimer(this);\n\tm_pGeometrySaveTimer->setInterval(DEFAULT_WINDOW_GEOMETRY_SAVE_DELAY);\n\tconnect(m_pGeometrySaveTimer, &QTimer::timeout,\n\t\tthis, &PreviewDialog::slotSaveGeometry);\n\n\tm_windowGeometry = m_pSettingsManager->getPreviewDialogGeometry();\n\tif(!m_windowGeometry.isEmpty())\n\t\trestoreGeometry(m_windowGeometry);\n\n\tconnect(m_pAdvancedSettingsDialog, SIGNAL(signalSettingsChanged()),\n\t\tthis, SLOT(slotAdvancedSettingsChanged()));\n\tconnect(m_ui.frameNumberSlider, SIGNAL(signalFrameChanged(int, bool)),\n\t\tthis, SLOT(slotShowFrame(int, bool)));\n\tconnect(m_ui.frameNumberSpinBox, SIGNAL(valueChanged(int)),\n\t\tthis, SLOT(slotShowFrame(int)));\n\tconnect(m_ui.previewArea, SIGNAL(signalSizeChanged()),\n\t\tthis, SLOT(slotPreviewAreaSizeChanged()));\n\tconnect(m_ui.previewArea, SIGNAL(signalCtrlWheel(QPoint)),\n\t\tthis, SLOT(slotPreviewAreaCtrlWheel(QPoint)));\n\tconnect(m_ui.previewArea, SIGNAL(signalMouseMiddleButtonReleased()),\n\t\tthis, SLOT(slotPreviewAreaMouseMiddleButtonReleased()));\n\tconnect(m_ui.previewArea, SIGNAL(signalMouseRightButtonReleased()),\n\t\tthis, SLOT(slotPreviewAreaMouseRightButtonReleased()));\n\tconnect(m_ui.previewArea, SIGNAL(signalMouseOverPoint(double, double)),\n\t\tthis, SLOT(slotPreviewAreaMouseOverPoint(double, double)));\n\tconnect(m_pPlayTimer, SIGNAL(timeout()),\n\t\tthis, SLOT(slotProcessPlayQueue()));\n\tconnect(this, SIGNAL(signalProcessorIdle(bool)),\n\t\tthis, SLOT(slotEnableSwitchOutputIndex(bool)));\n\n#ifdef Q_OS_WIN // AUDIO\n\tqputenv(\"QT_MEDIA_BACKEND\", QString(\"windows\").toLocal8Bit());\n\n\tm_pAudioPlayTimer = new QTimer(this);\n\tm_pAudioPlayTimer->setTimerType(Qt::PreciseTimer);\n\tm_pAudioPlayTimer->setSingleShot(true);\n\n\tconnect(m_pAudioPlayTimer, &QTimer::timeout,\n\t\tthis, &PreviewDialog::slotProcessAudioPlayQueue);\n#endif\n\n\tslotSettingsChanged();\n\n\tif(m_inPreviewer)\n\t{\n\t\tm_frameExpected = m_pSettingsManager->getLastPreviewFrame(true);\n\t\tm_frameTimestampExpected = m_pSettingsManager->getLastPreviewTimestamp(true);\n\t\tQPoint scrollBarPos = loadLastScrollBarPositions();\n\t\tm_ui.previewArea->getScrollBarPositionsFromPreviewer(scrollBarPos);\n\t}\n\telse if (m_pSettingsManager->getRememberLastPreviewFrame())\n\t{\n\t\tm_frameExpected = m_pSettingsManager->getLastPreviewFrame();\n\t\tm_frameTimestampExpected = m_pSettingsManager->getLastPreviewTimestamp();\n\t\tsetScriptName(m_pSettingsManager->getLastUsedPath());\n\t}\n}\n\n// END OF PreviewDialog::PreviewDialog(SettingsManager * a_pSettingsManager,\n//\t\tVSScriptLibrary * a_pVSScriptLibrary, QWidget * a_pParent)\n//==============================================================================\n\nPreviewDialog::~PreviewDialog()\n{\n\tif(m_pGeometrySaveTimer->isActive())\n\t{\n\t\tm_pGeometrySaveTimer->stop();\n\t\tslotSaveGeometry();\n\t}\n\tdelete m_pFramePropsPanel;\n}\n\n// END OF PreviewDialog::~PreviewDialog()\n//==============================================================================\n\nvoid PreviewDialog::setScriptName(const QString & a_scriptName)\n{\n\tVSScriptProcessorDialog::setScriptName(a_scriptName);\n\tsetTitle();\n}\n\n// END OF void PreviewDialog::setScriptName(const QString & a_scriptName)\n//==============================================================================\n\nvoid PreviewDialog::previewScript(const QString& a_script,\n\tconst QString& a_scriptName)\n{\n\tQString previousScript = script();\n\tQString previousScriptName = scriptName();\n\tm_scriptTextChanged = false;\n\n\tif(!m_inPreviewer)\n\t\tstopAndCleanUp();\n\n\tbool initialized = initialize(a_script, a_scriptName,\n\t\tProcessReason::Preview);\n\tif(!initialized)\n\t\treturn;\n\n\tm_outputIndices = m_pVapourSynthScriptProcessor->getOutputIndices();\n\tif(m_outputIndices.size() > 0)\n\t{\n\t\tm_ui.outputIndexComboBox->setSizeAdjustPolicy(QComboBox::AdjustToContents);\n\t\tm_ui.outputIndexComboBox->clear();\n\t\tfor(auto i : m_outputIndices)\n\t\t\tm_ui.outputIndexComboBox->addItem(QString::number(i));\n\t\tm_ui.outputIndexComboBox->setCurrentText(QString::number(m_outputIndex));\n\t}\n\telse\n\t{\n\t\t// Use old layout\n\t\tm_ui.outputIndexLabel->hide();\n\t\tm_ui.outputIndexComboBox->hide();\n\t\tm_ui.frameLabel->hide();\n\t}\n\n\tint lastFrameNumber;\n\n\tauto mt = m_nodeInfo[m_outputIndex].mediaType();\n#ifdef Q_OS_WIN // AUDIO\n\tif(mt == mtVideo)\n\t{\n\t\tm_currentIsAudio = false;\n\t\tconst VSVideoInfo * vi = m_nodeInfo[m_outputIndex].getAsVideo();\n\t\tif(!vi)\n\t\t\treturn;\n\n\t\tlastFrameNumber = vi->numFrames - 1;\n\t\tm_ui.frameNumberSpinBox->setMaximum(lastFrameNumber);\n\t\tm_ui.frameNumberSlider->setFramesNumber(vi->numFrames, false);\n\t\tauto fpsPair = m_nodeInfo[m_outputIndex].fpsPair();\n\t\tm_fpsNum = fpsPair.first;\n\t\tm_fpsDen = fpsPair.second;\n\t\tm_ui.frameNumberSlider->setFPS(m_fpsDen == 0 ?\n\t\t\t0.0 : (double)m_fpsNum / (double)m_fpsDen);\n\t}\n\telse\n\t{\n\t\tm_currentIsAudio = true;\n\t\tconst VSAudioInfo * ai = m_nodeInfo[m_outputIndex].getAsAudio();\n\t\tif(!ai)\n\t\t\treturn;\n\n\t\tlastFrameNumber = ai->numFrames - 1;\n\t\tm_ui.frameNumberSpinBox->setMaximum(lastFrameNumber);\n\t\tm_ui.frameNumberSlider->setFramesNumber(ai->numFrames, false);\n\t\tauto fpsPair = m_nodeInfo[m_outputIndex].fpsPair();\n\t\tm_fpsNum = fpsPair.first;\n\t\tm_fpsDen = fpsPair.second;\n\t\tm_ui.frameNumberSlider->setFPS((double)m_fpsNum / (double)m_fpsDen);\n\n\t\tif(m_ui.cropCheckButton->isChecked())\n\t\t\tm_ui.cropCheckButton->click();\n\t\tm_ui.cropCheckButton->setEnabled(false);\n\t\tm_pActionToggleCropPanel->setEnabled(false);\n\t\tm_ui.saveSnapshotButton->setEnabled(false);\n\t\tm_pActionSaveSnapshot->setEnabled(false);\n\t\tm_pStatusBarWidget->setColorPickerString(\"\");\n\t\tm_ui.playFpsLimitSpinBox->setEnabled(false);\n\t\tm_ui.playFpsLimitModeComboBox->setEnabled(false);\n\t\tint comboIndex = m_ui.playFpsLimitModeComboBox->findData(\n\t\t\t(int)PlayFPSLimitMode::FromVideo);\n\t\tif(comboIndex != -1)\n\t\t\tm_ui.playFpsLimitModeComboBox->setCurrentIndex(comboIndex);\n\n\t\tsetAudioOutput();\n\t}\n#else\n\tconst VSVideoInfo * vi = m_nodeInfo[m_outputIndex].getAsVideo();\n\tif(!vi)\n\t\treturn;\n\n\tlastFrameNumber = vi->numFrames - 1;\n\tm_ui.frameNumberSpinBox->setMaximum(lastFrameNumber);\n\tm_ui.frameNumberSlider->setFramesNumber(vi->numFrames, false);\n\tauto fpsPair = m_nodeInfo[m_outputIndex].fpsPair();\n\tm_fpsNum = fpsPair.first;\n\tm_fpsDen = fpsPair.second;\n\tm_ui.frameNumberSlider->setFPS(m_fpsDen == 0 ?\n\t\t0.0 : (double)m_fpsNum / (double)m_fpsDen);\n#endif\n\n\tbool scriptChanged = ((previousScript != a_script) &&\n\t\t(previousScriptName != a_scriptName));\n\n\tif(scriptChanged && (!m_alwaysKeepCurrentFrame))\n\t{\n\t\tm_frameExpected = 0;\n\t\tm_ui.previewArea->setPixmap(QPixmap());\n\t}\n\n\tif(m_frameExpected > lastFrameNumber)\n\t\tm_frameExpected = lastFrameNumber;\n\n\tresetCropSpinBoxes();\n\n\tslotSetPlayFPSLimit();\n\n\tsetScriptName(a_scriptName);\n\n\tloadTimelineBookmarks();\n\n\tif(m_pSettingsManager->getPreviewDialogMaximized())\n\t\tshowMaximized();\n\telse\n\t\tshowNormal();\n\n\tauto timelineMode = m_pSettingsManager->getTimeLineMode();\n\tif(timelineMode == TimeLineSlider::DisplayMode::Frames)\n\t\tm_frameTimestampExpected = frameToTimestamp(m_frameExpected);\n\telse\n\t\tm_frameExpected = timestampToFrame(m_frameTimestampExpected);\n\n\tif(m_frameExpected > lastFrameNumber)\n\t\tsetExpectedFrame(lastFrameNumber);\n\telse if(m_frameExpected < 0)\n\t\tsetExpectedFrame(0);\n\n\tslotShowFrame(m_frameExpected, false);\n\n\tif(m_outputIndices.size() > 0)\n\t{\n\t\tm_ui.outputIndexComboBox->disconnect(m_outputIndexComboBoxConnection);\n\n\t\tm_outputIndexComboBoxConnection = connect(m_ui.outputIndexComboBox,\n\t\t\t&QComboBox::currentTextChanged,\n\t\t\t[this]()\n\t\t\t{\n\t\t\t\tint idx = m_ui.outputIndexComboBox->currentText().toInt();\n\t\t\t\tslotSwitchOutputIndex(idx);\n\t\t\t});\n\t}\n\n\tsetTitle();\n}\n\n// END OF void PreviewDialog::previewScript(const QString& a_script,\n//\t\tconst QString& a_scriptName)\n//==============================================================================\n\nvoid PreviewDialog::stopAndCleanUp()\n{\n\tslotPlay(false);\n\n\tif(m_ui.cropCheckButton->isChecked())\n\t\tm_ui.cropCheckButton->click();\n\n\tbool rememberLastPreviewFrame = m_inPreviewer ||\n\t\tm_pSettingsManager->getRememberLastPreviewFrame();\n\tif(rememberLastPreviewFrame && (!scriptName().isEmpty()) &&\n\t\t(m_frameExpected > -1))\n\t{\n\t\tm_pSettingsManager->setLastPreviewFrame(m_frameExpected, m_inPreviewer);\n\t\tm_pSettingsManager->setLastPreviewTimestamp(m_frameTimestampExpected, m_inPreviewer);\n\t}\n\tm_frameShown = -1;\n\tm_framePixmap = QPixmap();\n\t// Replace shown image with a blank one of the same dimension:\n\t// -helps to keep the scrolling position when refreshing the script;\n\t// -leaves the image blank on sudden error;\n\t// -creates a blinking effect indicating the script is being refreshed.\n\tint pixmapWidth = m_ui.previewArea->pixmapWidth();\n\tint pixmapHeight = m_ui.previewArea->pixmapHeight();\n\tQPixmap blackPixmap(pixmapWidth, pixmapHeight);\n\tblackPixmap.fill(Qt::black);\n\tm_ui.previewArea->setPixmap(blackPixmap);\n\n\tif(m_cpFrame)\n\t{\n\t\tQ_ASSERT(m_cpVSAPI);\n\t\tm_cpVSAPI->freeFrame(m_cpFrame);\n\t\tm_cpFrame = nullptr;\n\t}\n\n\tif(m_cpPreviewFrame)\n\t{\n\t\tQ_ASSERT(m_cpVSAPI);\n\t\tm_cpVSAPI->freeFrame(m_cpPreviewFrame);\n\t\tm_cpPreviewFrame = nullptr;\n\t}\n\n\tVSScriptProcessorDialog::stopAndCleanUp();\n#ifdef Q_OS_WIN // AUDIO\n\tm_audioCache.clear();\n#endif\n}\n\n// END OF void PreviewDialog::stopAndCleanUp()\n//==============================================================================\n\nvoid PreviewDialog::moveEvent(QMoveEvent * a_pEvent)\n{\n\tQDialog::moveEvent(a_pEvent);\n\tsaveGeometryDelayed();\n}\n\n// END OF void PreviewDialog::moveEvent(QMoveEvent * a_pEvent)\n//==============================================================================\n\nvoid PreviewDialog::resizeEvent(QResizeEvent * a_pEvent)\n{\n\tQDialog::resizeEvent(a_pEvent);\n\tsaveGeometryDelayed();\n}\n\n// END OF void PreviewDialog::resizeEvent(QResizeEvent * a_pEvent)\n//==============================================================================\n\nvoid PreviewDialog::changeEvent(QEvent * a_pEvent)\n{\n\tQDialog::changeEvent(a_pEvent);\n\tif(a_pEvent->type() == QEvent::WindowStateChange)\n\t{\n\t\tif(isMaximized())\n\t\t\tm_pSettingsManager->setPreviewDialogMaximized(true);\n\t\telse\n\t\t\tm_pSettingsManager->setPreviewDialogMaximized(false);\n\t}\n}\n\n// END OF void PreviewDialog::changeEvent(QEvent * a_pEvent)\n//==============================================================================\n\nvoid PreviewDialog::closeEvent(QCloseEvent *a_pEvent)\n{\n\tm_pFramePropsPanel->setVisible(false);\n\tif(m_inPreviewer)\n\t{\n\t\tslotSaveGeometry();\n\t\tbool rememberLastPreviewFrame = m_inPreviewer ||\n\t\t\tm_pSettingsManager->getRememberLastPreviewFrame();\n\t\tif(rememberLastPreviewFrame && (m_frameExpected > -1))\n\t\t{\n\t\t\tm_pSettingsManager->setLastPreviewFrame(m_frameExpected, m_inPreviewer);\n\t\t\tm_pSettingsManager->setLastPreviewTimestamp(m_frameTimestampExpected, m_inPreviewer);\n\t\t}\n\t\tsaveLastScrollBarPositions();\n\n\t\treject();\n\t}\n\tVSScriptProcessorDialog::closeEvent(a_pEvent);\n}\n\n// END OF void PreviewDialog::closeEvent(QCloseEvent * a_pEvent)\n//==============================================================================\n\nvoid PreviewDialog::keyPressEvent(QKeyEvent * a_pEvent)\n{\n\tQt::KeyboardModifiers modifiers = a_pEvent->modifiers();\n\n\tif(modifiers != Qt::NoModifier)\n\t{\n\t\tQDialog::keyPressEvent(a_pEvent);\n\t\treturn;\n\t}\n\n\tif(!m_pVapourSynthScriptProcessor->isInitialized())\n\t{\n\t\tQDialog::keyPressEvent(a_pEvent);\n\t\treturn;\n\t}\n#ifdef Q_OS_WIN // AUDIO\n#else\n\tif(!m_nodeInfo[m_outputIndex].isVideo())\n\t\treturn;\n#endif\n\n\tint key = a_pEvent->key();\n\n\tif(((key == Qt::Key_Left) || (key == Qt::Key_Down)) &&\n\t\t(m_frameExpected > 0))\n\t\tslotShowFrame(m_frameExpected - 1, false);\n\telse if(((key == Qt::Key_Right) || (key == Qt::Key_Up)) &&\n\t\t(m_frameExpected < (m_nodeInfo[m_outputIndex].numFrames() - 1)))\n\t\tslotShowFrame(m_frameExpected + 1, false);\n\telse if((key == Qt::Key_PageDown) && (m_frameExpected > 0))\n\t\tslotShowFrame(std::max(0, m_frameExpected - m_bigFrameStep), true);\n\telse if((key == Qt::Key_PageUp) &&\n\t\t(m_frameExpected < (m_nodeInfo[m_outputIndex].numFrames() - 1)))\n\t{\n\t\tslotShowFrame(std::min(m_nodeInfo[m_outputIndex].numFrames() - 1,\n\t\t\tm_frameExpected + m_bigFrameStep), true);\n\t}\n\telse if(key == Qt::Key_Home)\n\t\tslotShowFrame(0, true);\n\telse if(key == Qt::Key_End)\n\t\tslotShowFrame(m_nodeInfo[m_outputIndex].numFrames() - 1, true);\n\telse if(key == Qt::Key_Escape)\n\t\tclose();\n\telse\n\t\tQDialog::keyPressEvent(a_pEvent);\n}\n\n// END OF void PreviewDialog::keyPressEvent(QKeyEvent * a_pEvent)\n//==============================================================================\n\nvoid PreviewDialog::slotScriptTextChanged()\n{\n\tm_scriptTextChanged = true;\n\tsetTitle();\n}\n\nvoid PreviewDialog::slotReceiveFrame(int a_frameNumber, int a_outputIndex,\n                                     const VSFrame * a_cpOutputFrame,\n                                     const VSFrame * a_cpPreviewFrame)\n{\n\tif(!a_cpOutputFrame)\n\t\treturn;\n\n\tQ_ASSERT(m_cpVSAPI);\n\tconst VSFrame * cpOutputFrame =\n\t\tm_cpVSAPI->addFrameRef(a_cpOutputFrame);\n\tconst VSFrame * cpPreviewFrame =\n\t\tm_cpVSAPI->addFrameRef(a_cpPreviewFrame);\n\n\tif(m_playing)\n\t{\n\t\tFrame newFrame(a_frameNumber, a_outputIndex,\n\t\t\tcpOutputFrame, cpPreviewFrame);\n\t\tm_framesCache[m_outputIndex].push_back(newFrame);\n#ifdef Q_OS_WIN // AUDIO\n\t\tif(m_currentIsAudio && m_pAudioSink)\n\t\t{\n\t\t\tQByteArray audioData = readAudioFrame(a_cpOutputFrame);\n\t\t\tAudioFrame newAudioFrame(a_frameNumber, a_outputIndex, audioData);\n\t\t\tm_audioCache[a_frameNumber] = newAudioFrame;\n\t\t\tslotProcessAudioPlayQueue();\n\t\t}\n\t\telse\n\t\t\tslotProcessPlayQueue();\n#else\n\t\tslotProcessPlayQueue();\n#endif\n\t}\n\telse\n\t{\n\t\tsetCurrentFrame(cpOutputFrame, cpPreviewFrame);\n\t\tm_frameShown = a_frameNumber;\n\t\tif(m_frameShown == m_frameExpected)\n\t\t\tm_ui.frameStatusLabel->setPixmap(m_readyPixmap);\n\t}\n}\n\n// END OF void PreviewDialog::slotReceiveFrame(int a_frameNumber,\n//\t\tint a_outputIndex, const VSFrame * a_cpOutputFrame,\n//\t\tconst VSFrame * a_cpPreviewFrame)\n//==============================================================================\n\nvoid PreviewDialog::slotFrameRequestDiscarded(int a_frameNumber,\n\tint a_outputIndex, const QString & a_reason)\n{\n\t(void)a_outputIndex;\n\t(void)a_reason;\n\n\tif(m_playing)\n\t{\n\t\tslotPlay(false);\n\t}\n\telse\n\t{\n\t\tif(a_frameNumber != m_frameExpected)\n\t\t\treturn;\n\n\t\tif(m_frameShown == -1)\n\t\t{\n\t\t\tif(m_frameExpected == 0)\n\t\t\t{\n\t\t\t\t// Nowhere to roll back\n\t\t\t\tm_ui.frameNumberSlider->setFrame(0, false);\n\t\t\t\tm_ui.frameNumberSpinBox->setValue(0);\n\t\t\t\tm_ui.frameStatusLabel->setPixmap(m_errorPixmap);\n\t\t\t}\n\t\t\telse\n\t\t\t\tslotShowFrame(0, false);\n\t\t\treturn;\n\t\t}\n\n\t\tsetExpectedFrame(m_frameShown);\n\t\tm_ui.frameNumberSlider->setFrame(m_frameShown, false);\n\t\tm_ui.frameNumberSpinBox->setValue(m_frameShown);\n\t\tm_ui.frameStatusLabel->setPixmap(m_readyPixmap);\n\t}\n}\n\n// END OF void PreviewDialog::slotFrameRequestDiscarded(int a_frameNumber,\n//\t\tint a_outputIndex, const QString & a_reason)\n//==============================================================================\n\nvoid PreviewDialog::slotShowFrame(int a_frameNumber, bool a_refreshCache)\n{\n\tif((m_frameShown == a_frameNumber) && (!m_framePixmap.isNull()))\n\t\treturn;\n\n\tif(m_playing)\n\t\treturn;\n\n\tstatic bool requestingFrame = false;\n\tif(requestingFrame)\n\t\treturn;\n\trequestingFrame = true;\n\n\tif(a_refreshCache)\n\t{\n\t\tint frameDiff = m_frameShown - a_frameNumber;\n\t\tif(frameDiff < 0)\n\t\t\tframeDiff = -frameDiff;\n\t\tif(frameDiff > 10 && m_usedCacheRatio > 0.75)\n\t\t{\n\t\t\tm_pVapourSynthScriptProcessor->clearCoreCaches();\n\t\t}\n\t}\n\n\tm_ui.frameNumberSpinBox->setValue(a_frameNumber);\n\tm_ui.frameNumberSlider->setFrame(a_frameNumber, a_refreshCache);\n\n\tbool requested = requestShowFrame(a_frameNumber);\n\tif(requested)\n\t{\n\t\tsetExpectedFrame(a_frameNumber);\n\t\tm_ui.frameStatusLabel->setPixmap(m_busyPixmap);\n\t}\n\telse\n\t{\n\t\tm_ui.frameNumberSpinBox->setValue(m_frameExpected);\n\t\tm_ui.frameNumberSlider->setFrame(m_frameExpected, a_refreshCache);\n\t}\n\n\trequestingFrame = false;\n}\n// END OF void PreviewDialog::slotShowFrame(int a_frameNumber, bool a_refreshCache)\n//==============================================================================\n\nvoid PreviewDialog::slotSaveSnapshot()\n{\n\tif((m_frameShown < 0) || m_framePixmap.isNull())\n\t\treturn;\n\n\tif(!m_nodeInfo[m_outputIndex].isVideo())\n\t\treturn;\n\n\tstatic std::map<QString, QString> extensionToFilterMap =\n\t{\n\t\t{\"png\", tr(\"PNG image (*.png)\")},\n\t};\n\n\tQString fileExtension = m_pSettingsManager->getLastSnapshotExtension();\n\n\tQList<QByteArray> supportedFormats = QImageWriter::supportedImageFormats();\n\tbool webpSupported = (supportedFormats.indexOf(\"webp\") > -1);\n\n\tif(webpSupported)\n\t\textensionToFilterMap[\"webp\"] = tr(\"WebP image (*.webp)\");\n\n\tQString currScriptName = scriptName();\n\tbool currScriptNotSaved = currScriptName.isEmpty();\n\n\t// Parse the template\n\tQString snapshotTemplate = m_pSettingsManager->getSnapshotTemplate();\n\tif(!currScriptNotSaved)\n\t{\n\t\tstd::vector<vsedit::VariableToken> variables =\n\t\t{\n\t\t\t{\"{f}\", tr(\"script file path\"),\n\t\t\t\t[&]()\n\t\t\t\t{\n\t\t\t\t\treturn currScriptName;\n\t\t\t\t}\n\t\t\t},\n\n\t\t\t{\"{d}\", tr(\"script file directory\"),\n\t\t\t\t[&]()\n\t\t\t\t{\n\t\t\t\t\tQFileInfo file(currScriptName);\n\t\t\t\t\treturn QDir::toNativeSeparators(file.path());\n\t\t\t\t}\n\t\t\t},\n\n\t\t\t{\"{n}\", tr(\"script file name\"),\n\t\t\t\t[&]()\n\t\t\t\t{\n\t\t\t\t\tQFileInfo file(currScriptName);\n\t\t\t\t\treturn file.completeBaseName();\n\t\t\t\t}\n\t\t\t},\n\n\t\t\t{\"{o}\", tr(\"output index\"),\n\t\t\t\t[&]()\n\t\t\t\t{\n\t\t\t\t\treturn QString::number(m_outputIndex);\n\t\t\t\t}\n\t\t\t},\n\n\t\t\t{\"{i}\", tr(\"frame number\"),\n\t\t\t\t[&]()\n\t\t\t\t{\n\t\t\t\t\treturn QString::number(m_frameShown);\n\t\t\t\t}\n\t\t\t},\n\n\t\t\t{\"{t}\", tr(\"timestamp\"),\n\t\t\t\t[&]()\n\t\t\t\t{\n\t\t\t\t\tif(m_fpsDen == 0 || m_fpsNum == 0)\n\t\t\t\t\t\treturn QString();\n\t\t\t\t\tQString timeStr = vsedit::timeToString(\n\t\t\t\t\t\t(double)m_frameShown / m_fpsNum * m_fpsDen, true)\n\t\t\t\t\t\t.replace(\":\", \".\");\n\t\t\t\t\treturn timeStr;\n\t\t\t\t}\n\t\t\t},\n\n\t\t\t{\"{nm}\", tr(\"clip name\"),\n\t\t\t\t[&]()\n\t\t\t\t{\n\t\t\t\t\treturn m_clipName;\n\t\t\t\t}\n\t\t\t},\n\n\t\t\t{\"{sc}\", tr(\"scene name\"),\n\t\t\t\t[&]()\n\t\t\t\t{\n\t\t\t\t\treturn m_sceneName;\n\t\t\t\t}\n\t\t\t},\n\t\t};\n\n\t\tfor(const vsedit::VariableToken & var : variables)\n\t\t{\n\t\t\tsnapshotTemplate = snapshotTemplate.replace(\n\t\t\t\tvar.token, var.evaluate());\n\t\t}\n\t}\n\n\tbool silentSnapshot = m_pSettingsManager->getSilentSnapshot();\n\n\tQString snapshotFilePath = snapshotTemplate;\n\tif(snapshotFilePath.isEmpty()) silentSnapshot = false;\n\tif(currScriptNotSaved || snapshotFilePath.isEmpty())\n\t{\n\t\tsnapshotFilePath =\n\t\t\tQStandardPaths::writableLocation(QStandardPaths::PicturesLocation);\n\t\tsnapshotFilePath += QString(\"/%1-%2\").arg(\n\t\t\tQString::number(m_frameShown), QString::number(m_outputIndex));\n\t\tsnapshotFilePath += fileExtension;\n\t}\n\n\tQStringList saveFormatsList;\n\tfor(const std::pair<const QString, QString> & pair : extensionToFilterMap)\n\t\tsaveFormatsList << pair.second;\n\n\tQString selectedFilter = extensionToFilterMap[fileExtension];\n\n\tif(currScriptNotSaved || !silentSnapshot)\n\t{\n\t\tsnapshotFilePath = QFileDialog::getSaveFileName(this,\n\t\t\ttr(\"Save frame as image\"), snapshotFilePath,\n\t\t\tsaveFormatsList.join(\";;\"), &selectedFilter);\n\t}\n\n\tQFileInfo fileInfo(snapshotFilePath);\n\tQString suffix = fileInfo.suffix().toLower();\n\n\tQByteArray format(\"png\");\n\tif((suffix == \"webp\") && webpSupported)\n\t\tformat = \"webp\";\n\telse if(silentSnapshot && suffix != \"png\")\n\t\tsnapshotFilePath += \".png\";\n\tif(!snapshotFilePath.isEmpty())\n\t{\n\t\tbool success = m_framePixmap.save(snapshotFilePath, format,\n\t\t\tformat == \"webp\" ? 100 :\n\t\t\tm_pSettingsManager->getPNGSnapshotCompressionLevel());\n\t\tif(success)\n\t\t\tm_pSettingsManager->setLastSnapshotExtension(suffix);\n\t\telse\n\t\t{\n\t\t\tQMessageBox::critical(this, tr(\"Image save error\"),\n\t\t\t\ttr(\"Error while saving image \") + snapshotFilePath);\n\t\t}\n\t}\n}\n\n// END OF void PreviewDialog::slotSaveSnapshot()\n//==============================================================================\n\nvoid PreviewDialog::slotToggleZoomPanelVisible(bool a_zoomPanelVisible)\n{\n\tm_ui.zoomPanel->setVisible(a_zoomPanelVisible);\n\tm_pSettingsManager->setZoomPanelVisible(a_zoomPanelVisible);\n}\n\n// END OF void PreviewDialog::slotToggleZoomPanelVisible(\n//\t\tbool a_zoomPanelVisible)\n//==============================================================================\n\nvoid PreviewDialog::slotZoomModeChanged()\n{\n\tstatic bool changingZoomMode = false;\n\tif(changingZoomMode)\n\t\treturn;\n\tchangingZoomMode = true;\n\n\tZoomMode zoomMode = (ZoomMode)m_ui.zoomModeComboBox->currentData().toInt();\n\n\tQObject * pSender = sender();\n\tif(pSender == m_ui.zoomModeComboBox)\n\t{\n\n\t\tfor(QAction * pAction : m_pActionGroupZoomModes->actions())\n\t\t{\n\t\t\tZoomMode actionZoomMode =\n\t\t\t\tm_actionIDToZoomModeMap[pAction->data().toString()];\n\t\t\tif(actionZoomMode == zoomMode)\n\t\t\t{\n\t\t\t\tpAction->setChecked(true);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t}\n\telse\n\t{\n\t\t// If signal wasn't sent by combo box - presume it was sent by action.\n\t\tQAction * pSenderAction = qobject_cast<QAction *>(pSender);\n\t\tzoomMode = m_actionIDToZoomModeMap[pSenderAction->data().toString()];\n\t\tint zoomModeIndex = m_ui.zoomModeComboBox->findData((int)zoomMode);\n\t\tm_ui.zoomModeComboBox->setCurrentIndex(zoomModeIndex);\n\t}\n\n\tsetPreviewPixmap();\n\tbool fixedRatio(zoomMode == ZoomMode::FixedRatio);\n\tm_ui.zoomRatioSpinBox->setEnabled(fixedRatio);\n\tbool noZoom = (zoomMode == ZoomMode::NoZoom);\n\tm_ui.scaleModeComboBox->setEnabled(!noZoom);\n\tm_pMenuZoomScaleModes->setEnabled(!noZoom);\n\tm_pSettingsManager->setZoomMode(zoomMode);\n\n\tchangingZoomMode = false;\n}\n\n// END OF void PreviewDialog::slotZoomModeChanged()\n//==============================================================================\n\nvoid PreviewDialog::slotZoomRatioChanged(double a_zoomRatio)\n{\n\tsetPreviewPixmap();\n\tm_pSettingsManager->setZoomRatio(a_zoomRatio);\n}\n\n// END OF void PreviewDialog::slotZoomRatioChanged(double a_zoomRatio)\n//==============================================================================\n\nvoid PreviewDialog::slotScaleModeChanged()\n{\n\tstatic bool changingScaleMode = false;\n\tif(changingScaleMode)\n\t\treturn;\n\tchangingScaleMode = true;\n\n\tQt::TransformationMode scaleMode = (Qt::TransformationMode)\n\t\tm_ui.scaleModeComboBox->currentData().toInt();\n\n\tQObject * pSender = sender();\n\tif(pSender == m_ui.scaleModeComboBox)\n\t{\n\t\tfor(QAction * pAction : m_pActionGroupZoomScaleModes->actions())\n\t\t{\n\t\t\tQt::TransformationMode actionScaleMode =\n\t\t\t\tm_actionIDToZoomScaleModeMap[pAction->data().toString()];\n\t\t\tif(actionScaleMode == scaleMode)\n\t\t\t{\n\t\t\t\tpAction->setChecked(true);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t}\n\telse\n\t{\n\t\t// If signal wasn't sent by combo box - presume it was sent by action.\n\t\tQAction * pSenderAction = qobject_cast<QAction *>(pSender);\n\t\tscaleMode =\n\t\t\tm_actionIDToZoomScaleModeMap[pSenderAction->data().toString()];\n\t\tint scaleModeIndex = m_ui.scaleModeComboBox->findData((int)scaleMode);\n\t\tm_ui.scaleModeComboBox->setCurrentIndex(scaleModeIndex);\n\t}\n\n\tm_ui.zoomRatioSpinBox->setScaleMode(scaleMode);\n\tsetPreviewPixmap();\n\tm_pSettingsManager->setScaleMode(scaleMode);\n\n\tchangingScaleMode = false;\n}\n\n// END OF void PreviewDialog::slotScaleModeChanged()\n//==============================================================================\n\nvoid PreviewDialog::slotToggleCropPanelVisible(bool a_cropPanelVisible)\n{\n\tm_ui.cropPanel->setVisible(a_cropPanelVisible);\n\tsetPreviewPixmap();\n}\n\n// END OF void PreviewDialog::slotToggleCropPanelVisible(\n//\t\tbool a_cropPanelVisible)\n//==============================================================================\n\nvoid PreviewDialog::slotCropModeChanged()\n{\n\tCropMode cropMode = (CropMode)m_ui.cropModeComboBox->currentData().toInt();\n\tif(cropMode == CropMode::Absolute)\n\t{\n\t\tm_ui.cropWidthSpinBox->setEnabled(true);\n\t\tm_ui.cropHeightSpinBox->setEnabled(true);\n\t\tm_ui.cropRightSpinBox->setEnabled(false);\n\t\tm_ui.cropBottomSpinBox->setEnabled(false);\n\t}\n\telse\n\t{\n\t\tm_ui.cropWidthSpinBox->setEnabled(false);\n\t\tm_ui.cropHeightSpinBox->setEnabled(false);\n\t\tm_ui.cropRightSpinBox->setEnabled(true);\n\t\tm_ui.cropBottomSpinBox->setEnabled(true);\n\t}\n\n\tm_pSettingsManager->setCropMode(cropMode);\n}\n\n// END OF void PreviewDialog::slotCropModeChanged()\n//==============================================================================\n\nvoid PreviewDialog::slotCropLeftValueChanged(int a_value)\n{\n\tBEGIN_CROP_VALUES_CHANGE\n\n\tconst VSVideoInfo * vi = m_nodeInfo[m_outputIndex].getAsVideo();\n\tif(!vi)\n\t{\n\t\tEND_CROP_VALUES_CHANGE\n\t\treturn;\n\t}\n\n\tint remainder = vi->width - a_value;\n\tm_ui.cropWidthSpinBox->setMaximum(remainder);\n\tm_ui.cropRightSpinBox->setMaximum(remainder - 1);\n\n\tCropMode cropMode = (CropMode)m_ui.cropModeComboBox->currentData().toInt();\n\tif(cropMode == CropMode::Absolute)\n\t{\n\t\tif(m_ui.cropWidthSpinBox->value() > remainder)\n\t\t\tm_ui.cropWidthSpinBox->setValue(remainder);\n\t\tm_ui.cropRightSpinBox->setValue(remainder -\n\t\t\tm_ui.cropWidthSpinBox->value());\n\t}\n\telse\n\t{\n\t\tif(m_ui.cropRightSpinBox->value() > remainder - 1)\n\t\t\tm_ui.cropRightSpinBox->setValue(remainder - 1);\n\t\tm_ui.cropWidthSpinBox->setValue(remainder -\n\t\t\tm_ui.cropRightSpinBox->value());\n\t}\n\n\trecalculateCropMods();\n\n\tsetPreviewPixmap();\n\n\tm_ui.previewArea->slotScrollLeft();\n\n\tEND_CROP_VALUES_CHANGE\n}\n\n// END OF void PreviewDialog::slotCropLeftValueChanged(int a_value)\n//==============================================================================\n\nvoid PreviewDialog::slotCropTopValueChanged(int a_value)\n{\n\tBEGIN_CROP_VALUES_CHANGE\n\n\tconst VSVideoInfo * vi = m_nodeInfo[m_outputIndex].getAsVideo();\n\tif(!vi)\n\t{\n\t\tEND_CROP_VALUES_CHANGE\n\t\treturn;\n\t}\n\n\tint remainder = vi->height - a_value;\n\tm_ui.cropHeightSpinBox->setMaximum(remainder);\n\tm_ui.cropBottomSpinBox->setMaximum(remainder - 1);\n\n\tCropMode cropMode = (CropMode)m_ui.cropModeComboBox->currentData().toInt();\n\tif(cropMode == CropMode::Absolute)\n\t{\n\t\tif(m_ui.cropHeightSpinBox->value() > remainder)\n\t\t\tm_ui.cropHeightSpinBox->setValue(remainder);\n\t\tm_ui.cropBottomSpinBox->setValue(remainder -\n\t\t\tm_ui.cropHeightSpinBox->value());\n\t}\n\telse\n\t{\n\t\tif(m_ui.cropBottomSpinBox->value() > remainder - 1)\n\t\t\tm_ui.cropBottomSpinBox->setValue(remainder - 1);\n\t\tm_ui.cropHeightSpinBox->setValue(remainder -\n\t\t\tm_ui.cropBottomSpinBox->value());\n\t}\n\n\trecalculateCropMods();\n\n\tsetPreviewPixmap();\n\n\tm_ui.previewArea->slotScrollTop();\n\n\tEND_CROP_VALUES_CHANGE\n}\n\n// END OF void PreviewDialog::slotCropTopValueChanged(int a_value)\n//==============================================================================\n\nvoid PreviewDialog::slotCropWidthValueChanged(int a_value)\n{\n\tBEGIN_CROP_VALUES_CHANGE\n\n\tconst VSVideoInfo * vi = m_nodeInfo[m_outputIndex].getAsVideo();\n\tif(!vi)\n\t{\n\t\tEND_CROP_VALUES_CHANGE\n\t\treturn;\n\t}\n\n\tm_ui.cropRightSpinBox->setValue(vi->width -\n\t\tm_ui.cropLeftSpinBox->value() - a_value);\n\n\trecalculateCropMods();\n\n\tsetPreviewPixmap();\n\n\tm_ui.previewArea->slotScrollRight();\n\n\tEND_CROP_VALUES_CHANGE\n}\n\n// END OF void PreviewDialog::slotCropWidthValueChanged(int a_value)\n//==============================================================================\n\nvoid PreviewDialog::slotCropHeightValueChanged(int a_value)\n{\n\tBEGIN_CROP_VALUES_CHANGE\n\n\tconst VSVideoInfo * vi = m_nodeInfo[m_outputIndex].getAsVideo();\n\tif(!vi)\n\t{\n\t\tEND_CROP_VALUES_CHANGE\n\t\treturn;\n\t}\n\n\tm_ui.cropBottomSpinBox->setValue(vi->height -\n\t\tm_ui.cropTopSpinBox->value() - a_value);\n\n\trecalculateCropMods();\n\n\tsetPreviewPixmap();\n\n\tm_ui.previewArea->slotScrollBottom();\n\n\tEND_CROP_VALUES_CHANGE\n}\n\n// END OF void PreviewDialog::slotCropHeightValueChanged(int a_value)\n//==============================================================================\n\nvoid PreviewDialog::slotCropRightValueChanged(int a_value)\n{\n\tBEGIN_CROP_VALUES_CHANGE\n\n\tconst VSVideoInfo * vi = m_nodeInfo[m_outputIndex].getAsVideo();\n\tif(!vi)\n\t{\n\t\tEND_CROP_VALUES_CHANGE\n\t\treturn;\n\t}\n\n\tm_ui.cropWidthSpinBox->setValue(vi->width -\n\t\tm_ui.cropLeftSpinBox->value() - a_value);\n\n\trecalculateCropMods();\n\n\tsetPreviewPixmap();\n\n\tm_ui.previewArea->slotScrollRight();\n\n\tEND_CROP_VALUES_CHANGE\n}\n\n// END OF void PreviewDialog::slotCropRightValueChanged(int a_value)\n//==============================================================================\n\nvoid PreviewDialog::slotCropBottomValueChanged(int a_value)\n{\n\tBEGIN_CROP_VALUES_CHANGE\n\n\tconst VSVideoInfo * vi = m_nodeInfo[m_outputIndex].getAsVideo();\n\tif(!vi)\n\t{\n\t\tEND_CROP_VALUES_CHANGE\n\t\treturn;\n\t}\n\n\tm_ui.cropHeightSpinBox->setValue(vi->height -\n\t\tm_ui.cropTopSpinBox->value() - a_value);\n\n\trecalculateCropMods();\n\n\tsetPreviewPixmap();\n\n\tm_ui.previewArea->slotScrollBottom();\n\n\tEND_CROP_VALUES_CHANGE\n}\n\n// END OF void PreviewDialog::slotCropBottomValueChanged(int a_value)\n//==============================================================================\n\nvoid PreviewDialog::slotCropZoomRatioValueChanged(int a_cropZoomRatio)\n{\n\tm_pSettingsManager->setCropZoomRatio(a_cropZoomRatio);\n\tsetPreviewPixmap();\n}\n\n// END OF void PreviewDialog::slotCropZoomRatioValueChanged(int a_cropZoomRatio)\n//==============================================================================\n\nvoid PreviewDialog::slotPasteCropSnippetIntoScript()\n{\n\tif(m_inPreviewer)\n\t\treturn;\n\tif(!m_ui.cropPanel->isVisible())\n\t\treturn;\n\n\tCropMode cropMode = (CropMode)m_ui.cropModeComboBox->currentData().toInt();\n\tQString cropString;\n\n\tif(cropMode == CropMode::Absolute)\n\t{\n\t\tcropString = QString(\"***CLIP*** = core.std.CropAbs\"\n\t\t\t\"(***CLIP***, x=%1, y=%2, width=%3, height=%4)\")\n\t\t\t.arg(m_ui.cropLeftSpinBox->value())\n\t\t\t.arg(m_ui.cropTopSpinBox->value())\n\t\t\t.arg(m_ui.cropWidthSpinBox->value())\n\t\t\t.arg(m_ui.cropHeightSpinBox->value());\n\t}\n\telse\n\t{\n\t\tcropString = QString(\"***CLIP*** = core.std.CropRel\"\n\t\t\t\"(***CLIP***, left=%1, top=%2, right=%3, bottom=%4)\")\n\t\t\t.arg(m_ui.cropLeftSpinBox->value())\n\t\t\t.arg(m_ui.cropTopSpinBox->value())\n\t\t\t.arg(m_ui.cropRightSpinBox->value())\n\t\t\t.arg(m_ui.cropBottomSpinBox->value());\n\t}\n\n\temit signalPasteIntoScriptAtNewLine(cropString);\n}\n\n// END OF void PreviewDialog::slotPasteCropSnippetIntoScript()\n//==============================================================================\n\nvoid PreviewDialog::slotCallAdvancedSettingsDialog()\n{\n\tm_pAdvancedSettingsDialog->slotCall();\n}\n\n// END OF void PreviewDialog::slotCallAdvancedSettingsDialog()\n//==============================================================================\n\nvoid PreviewDialog::slotToggleTimeLinePanelVisible(bool a_timeLinePanelVisible)\n{\n\tm_ui.timeLinePanel->setVisible(a_timeLinePanelVisible);\n\tm_pSettingsManager->setTimeLinePanelVisible(a_timeLinePanelVisible);\n}\n\n// END OF void PreviewDialog::slotToggleTimeLinePanelVisible(\n//\t\tbool a_timeLinePanelVisible)\n//==============================================================================\n\nvoid PreviewDialog::slotTimeLineModeChanged()\n{\n\tstatic bool changingTimeLineMode = false;\n\tif(changingTimeLineMode)\n\t\treturn;\n\tchangingTimeLineMode = true;\n\n\tTimeLineSlider::DisplayMode timeLineMode = (TimeLineSlider::DisplayMode)\n\t\tm_ui.timeLineModeComboBox->currentData().toInt();\n\n\tQObject * pSender = sender();\n\tif(pSender == m_ui.timeLineModeComboBox)\n\t{\n\t\tfor(QAction * pAction : m_pActionGroupTimeLineModes->actions())\n\t\t{\n\t\t\tTimeLineSlider::DisplayMode actionTimeLineMode =\n\t\t\t\tm_actionIDToTimeLineModeMap[pAction->data().toString()];\n\t\t\tif(actionTimeLineMode == timeLineMode)\n\t\t\t{\n\t\t\t\tpAction->setChecked(true);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t}\n\telse\n\t{\n\t\t// If signal wasn't sent by combo box - presume it was sent by action.\n\t\tQAction * pSenderAction = qobject_cast<QAction *>(pSender);\n\t\ttimeLineMode =\n\t\t\tm_actionIDToTimeLineModeMap[pSenderAction->data().toString()];\n\t\tint timeLineModeIndex = m_ui.timeLineModeComboBox->findData(\n\t\t\t(int)timeLineMode);\n\t\tm_ui.timeLineModeComboBox->setCurrentIndex(timeLineModeIndex);\n\t}\n\n\tm_ui.frameNumberSlider->setDisplayMode(timeLineMode);\n\tm_pSettingsManager->setTimeLineMode(timeLineMode);\n\n\tchangingTimeLineMode = false;\n}\n\n// END OF void PreviewDialog::slotTimeLineModeChanged()\n//==============================================================================\n\nvoid PreviewDialog::slotTimeStepChanged(const QTime & a_time)\n{\n\tm_pSettingsManager->setTimeStep(vsedit::qtimeToSeconds(a_time));\n}\n\n// END OF void PreviewDialog::slotTimeStepChanged(const QTime & a_time)\n//==============================================================================\n\nvoid PreviewDialog::slotTimeStepForward()\n{\n\tdouble step = vsedit::qtimeToSeconds(m_ui.timeStepEdit->time());\n\tm_ui.frameNumberSlider->slotStepBySeconds(step);\n}\n\n// END OF void PreviewDialog::slotTimeStepForward()\n//==============================================================================\n\nvoid PreviewDialog::slotTimeStepBack()\n{\n\tdouble step = vsedit::qtimeToSeconds(m_ui.timeStepEdit->time());\n\tm_ui.frameNumberSlider->slotStepBySeconds(-step);\n}\n\n// END OF void PreviewDialog::slotTimeStepBack()\n//==============================================================================\n\nvoid PreviewDialog::slotSettingsChanged()\n{\n\tQKeySequence hotkey;\n\tfor(QAction * pAction : m_settableActionsList)\n\t{\n\t\thotkey = m_pSettingsManager->getHotkey(pAction->data().toString());\n\t\tpAction->setShortcut(hotkey);\n\t}\n\n\tm_alwaysKeepCurrentFrame = m_pSettingsManager->getAlwaysKeepCurrentFrame();\n\n\tm_ui.frameNumberSlider->setUpdatesEnabled(false);\n\n\tQFont sliderLabelsFont =\n\t\tm_pSettingsManager->getTextFormat(TEXT_FORMAT_ID_TIMELINE).font();\n\tm_ui.frameNumberSlider->setLabelsFont(sliderLabelsFont);\n\n\tQColor bookmarksColor =\n\t\tm_pSettingsManager->getColor(COLOR_ID_TIMELINE_BOOKMARKS);\n\tm_ui.frameNumberSlider->setColor(TimeLineSlider::Bookmark, bookmarksColor);\n\n\tm_ui.frameNumberSlider->setUpdatesEnabled(true);\n}\n\n// END OF void PreviewDialog::slotSettingsChanged()\n//==============================================================================\n\nvoid PreviewDialog::slotPreviewAreaSizeChanged()\n{\n\tZoomMode zoomMode = (ZoomMode)m_ui.zoomModeComboBox->currentData().toInt();\n\tif(zoomMode == ZoomMode::FitToFrame)\n\t\tsetPreviewPixmap();\n}\n\n// END OF void PreviewDialog::slotPreviewAreaSizeChanged()\n//==============================================================================\n\nvoid PreviewDialog::slotPreviewAreaCtrlWheel(QPoint a_angleDelta)\n{\n#ifdef Q_OS_WIN // AUDIO\n\tif(m_currentIsAudio && m_pAudioSink)\n\t{\n\t\tint deltaY = a_angleDelta.y();\n\t\tm_audioVolume = m_pAudioSink->volume();\n\t\tif(deltaY > 0)\n\t\t{\n\t\t\tm_audioVolume += 0.1;\n\t\t\tm_pAudioSink->setVolume(m_audioVolume);\n\t\t}\n\t\telse if(deltaY < 0)\n\t\t{\n\t\t\tm_audioVolume -= 0.1;\n\t\t\tm_pAudioSink->setVolume(m_audioVolume);\n\t\t}\n\t\treturn;\n\t}\n#endif\n\tZoomMode zoomMode = (ZoomMode)m_ui.zoomModeComboBox->currentData().toInt();\n\tint deltaY = a_angleDelta.y();\n\n\tif(m_ui.cropCheckButton->isChecked())\n\t{\n\t\tif(deltaY > 0)\n\t\t\tm_ui.cropZoomRatioSpinBox->stepBy(1);\n\t\telse if(deltaY < 0)\n\t\t\tm_ui.cropZoomRatioSpinBox->stepBy(-1);\n\t}\n\telse if(zoomMode == ZoomMode::FixedRatio)\n\t{\n\t\tif(deltaY > 0)\n\t\t\tm_ui.zoomRatioSpinBox->stepBy(1);\n\t\telse if(deltaY < 0)\n\t\t\tm_ui.zoomRatioSpinBox->stepBy(-1);\n\t}\n}\n\n// END OF void PreviewDialog::slotPreviewAreaCtrlWheel(QPoint a_angleDelta)\n//==============================================================================\n\nvoid PreviewDialog::slotPreviewAreaMouseMiddleButtonReleased()\n{\n\tif(m_ui.cropCheckButton->isChecked())\n\t\treturn;\n\n\tint zoomModeIndex = m_ui.zoomModeComboBox->currentIndex();\n\tzoomModeIndex++;\n\tif(zoomModeIndex >= m_ui.zoomModeComboBox->count())\n\t\tzoomModeIndex = 0;\n\tm_ui.zoomModeComboBox->setCurrentIndex(zoomModeIndex);\n}\n\n// END OF void PreviewDialog::slotPreviewAreaMouseMiddleButtonReleased()\n//==============================================================================\n\nvoid PreviewDialog::slotPreviewAreaMouseRightButtonReleased()\n{\n\tm_pPreviewContextMenu->popup(QCursor::pos());\n}\n\n// END OF void PreviewDialog::slotPreviewAreaMouseRightButtonReleased()\n//==============================================================================\n\nvoid PreviewDialog::slotPreviewAreaMouseOverPoint(double a_pX, double a_pY)\n{\n\tif(!m_cpFrame)\n\t\treturn;\n\n\tif(m_cpVSAPI->getFrameType(m_cpFrame) == mtAudio)\n\t\treturn;\n\n\tif(!m_pStatusBarWidget->colorPickerVisible())\n\t\treturn;\n\n\tdouble value1 = 0.0;\n\tdouble value2 = 0.0;\n\tdouble value3 = 0.0;\n\tint preview_values[3] = {0, 0, 0};\n\n\tsize_t frameX = 0;\n\tsize_t frameY = 0;\n\n\tdouble zoomRatio;\n\n\tint width = m_cpVSAPI->getFrameWidth(m_cpFrame, 0);\n\tint height = m_cpVSAPI->getFrameHeight(m_cpFrame, 0);\n\tconst VSVideoFormat * cpFormat = m_cpVSAPI->getVideoFrameFormat(m_cpFrame);\n\n\tif(m_ui.cropPanel->isVisible())\n\t{\n\t\tzoomRatio = m_ui.cropZoomRatioSpinBox->value();\n\t\tint cropLeft = m_ui.cropLeftSpinBox->value();\n\t\tint cropTop = m_ui.cropTopSpinBox->value();\n\t\tint cropWidth = m_ui.cropWidthSpinBox->value();\n\t\tint cropHeight = m_ui.cropHeightSpinBox->value();\n\t\tframeX = (size_t)(a_pX * m_devicePixelRatio / zoomRatio + cropLeft);\n\t\tframeY = (size_t)(a_pY * m_devicePixelRatio / zoomRatio + cropTop);\n\t\tif(frameX >= (size_t)(cropLeft + cropWidth) ||\n\t\t\tframeY >= (size_t)(cropTop + cropHeight))\n\t\t\treturn;\n\t}\n\telse\n\t{\n\t\tZoomMode zoomMode = (ZoomMode)m_ui.zoomModeComboBox->currentData().toInt();\n\t\tif(zoomMode == ZoomMode::NoZoom)\n\t\t{\n\t\t\tzoomRatio = 1.0;\n\t\t}\n\t\telse if(zoomMode == ZoomMode::FixedRatio)\n\t\t{\n\t\t\tzoomRatio = m_ui.zoomRatioSpinBox->value();\n\t\t}\n\t\telse\n\t\t{\n\t\t\tif(m_framePixmap.isNull())\n\t\t\t{\n\t\t\t\tm_pStatusBarWidget->setColorPickerString(QString());\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tQRect previewRect = m_ui.previewArea->geometry();\n\t\t\tint cropSize = m_ui.previewArea->frameWidth() * 2;\n\t\t\tint frameWidth = previewRect.width() * m_devicePixelRatio - cropSize;\n\t\t\tint frameHeight = previewRect.height() * m_devicePixelRatio - cropSize;\n\t\t\tdouble scaleW = (double)frameWidth / m_framePixmap.width();\n\t\t\tdouble scaleH = (double)frameHeight / m_framePixmap.height();\n\t\t\tzoomRatio = scaleW < scaleH ? scaleW : scaleH;\n\t\t}\n\t\tif(zoomRatio <= 0)\n\t\t\treturn;\n\t\tframeX = (size_t)(a_pX * m_devicePixelRatio / zoomRatio);\n\t\tframeY = (size_t)(a_pY * m_devicePixelRatio / zoomRatio);\n\t\tif((frameX >= (size_t)width) || (frameY >= (size_t)height))\n\t\t\treturn;\n\t}\n\n\tvalue1 = valueAtPoint(frameX, frameY, 0);\n\tif(cpFormat->numPlanes > 1)\n\t\tvalue2 = valueAtPoint(frameX, frameY, 1);\n\tif(cpFormat->numPlanes > 2)\n\t\tvalue3 = valueAtPoint(frameX, frameY, 2);\n\n\tpreviewValueAtPoint(frameX, frameY, preview_values);\n\n\tQString l1(\"1\");\n\tQString l2(\"2\");\n\tQString l3(\"3\");\n\n\tint colorFamily = m_nodeInfo[m_outputIndex].getAsVideo()->\n\t\tformat.colorFamily;\n\n\tif(colorFamily == cfYUV)\n\t{\n\t\tl1 = \"Y\";\n\t\tl2 = \"U\";\n\t\tl3 = \"V\";\n\t}\n\telse if(colorFamily == cfRGB)\n\t{\n\t\tl1 = \"R\";\n\t\tl2 = \"G\";\n\t\tl3 = \"B\";\n\t}\n\n\tQString colorString;\n\n\tif(colorFamily == cfGray)\n\t\tcolorString = QString(\"Video: G:%1\").arg(value1);\n\telse\n\t{\n\t\tcolorString = QString(\"Video: %1:%2|%3:%4|%5:%6\")\n\t\t\t.arg(l1).arg(value1).arg(l2).arg(value2).arg(l3).arg(value3);\n\t}\n\n\tQString coordString = QString(\"    Position: X:%1|Y:%2\")\n\t\t.arg(frameX).arg(frameY);\n\n\tQString dispString = QString(\"    Display: R:%1|G:%2|B:%3\")\n\t\t.arg(preview_values[0]).arg(preview_values[1]).arg(preview_values[2]);\n\n\tm_pStatusBarWidget->setColorPickerString(colorString + coordString + \n\t\tdispString);\n}\n\n// END OF void PreviewDialog::slotPreviewAreaMouseOverPoint(float a_normX,\n//\t\tfloat a_normY)\n//==============================================================================\n\nvoid PreviewDialog::slotFrameToClipboard()\n{\n\tif(m_framePixmap.isNull())\n\t\treturn;\n\n\tQClipboard * pClipboard = QApplication::clipboard();\n\tpClipboard->setPixmap(m_framePixmap);\n}\n\n// END OF void PreviewDialog::slotFrameToClipboard()\n//==============================================================================\n\nvoid PreviewDialog::slotAdvancedSettingsChanged()\n{\n\tm_pVapourSynthScriptProcessor->slotResetSettings();\n\tif(!m_playing)\n\t\trequestShowFrame(m_frameExpected);\n}\n\n// END OF void PreviewDialog::slotAdvancedSettingsChanged()\n//==============================================================================\n\nvoid PreviewDialog::slotToggleColorPicker(bool a_colorPickerVisible)\n{\n\tm_pStatusBarWidget->setColorPickerVisible(a_colorPickerVisible);\n\tm_pSettingsManager->setColorPickerVisible(a_colorPickerVisible);\n}\n\n// END OF void PreviewDialog::slotToggleColorPicker(bool a_colorPickerVisible)\n//==============================================================================\n\nvoid PreviewDialog::slotSetPlayFPSLimit()\n{\n\tdouble limit = m_ui.playFpsLimitSpinBox->value();\n\tif(limit < 1e-3)\n\t\tlimit = 1e-3;\n\tm_nativePlaybackRate = false;\n#ifdef Q_OS_WIN // AUDIO\n\tPlayFPSLimitMode mode = m_currentIsAudio ? PlayFPSLimitMode::FromVideo :\n#else\n\tPlayFPSLimitMode mode =\n#endif\n\t\t(PlayFPSLimitMode)m_ui.playFpsLimitModeComboBox->currentData().toInt();\n\tif(mode == PlayFPSLimitMode::NoLimit)\n\t\tm_secondsBetweenFrames = 0.0;\n\telse if(mode == PlayFPSLimitMode::Custom)\n\t\tm_secondsBetweenFrames = 1.0 / limit;\n\telse if(mode == PlayFPSLimitMode::FromVideo)\n\t{\n\t\tif(m_fpsDen == 0 || m_fpsNum == 0)\n\t\t{\n\t\t\tm_nativePlaybackRate = true;\n\t\t\tm_secondsBetweenFrames = 0.0;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tm_secondsBetweenFrames = 1.0 / m_fpsNum * m_fpsDen;\n\t\t}\n\t}\n\telse\n\t\tQ_ASSERT(false);\n\n#ifdef Q_OS_WIN // AUDIO\n\tif(m_currentIsAudio)\n\t\treturn;\n#endif\n\tm_pSettingsManager->setPlayFPSLimitMode(mode);\n\tm_pSettingsManager->setPlayFPSLimit(limit);\n}\n\n// END OF void PreviewDialog::void slotSetPlayFPSLimit()\n//==============================================================================\n\nvoid PreviewDialog::slotPlay(bool a_play)\n{\n\tif(m_playing == a_play)\n\t\treturn;\n\n\tm_playing = a_play;\n\tm_pActionPlay->setChecked(m_playing);\n\n\tif(m_playing)\n\t{\n\t\tm_ui.outputIndexComboBox->setEnabled(false);\n\t\tm_pActionPlay->setIcon(m_iconPause);\n\t\tm_lastFrameRequestedForPlay = m_frameShown;\n#ifdef Q_OS_WIN // AUDIO\n\t\tif(m_currentIsAudio && m_pAudioSink)\n\t\t\tslotProcessAudioPlayQueue();\n\t\telse\n\t\t\tslotProcessPlayQueue();\n#else\n\t\tslotProcessPlayQueue();\n#endif\n\t}\n\telse\n\t{\n\t\tclearFramesCache();\n#ifdef Q_OS_WIN // AUDIO\n\t\tm_audioCache.clear();\n#endif\n\t\tm_pVapourSynthScriptProcessor->flushFrameTicketsQueue();\n\t\tm_ui.outputIndexComboBox->setEnabled(true);\n\t\tm_pActionPlay->setIcon(m_iconPlay);\n\t\tsetTitle();\n\t}\n}\n\n// END OF void PreviewDialog::slotPlay(bool a_play)\n//==============================================================================\n\nvoid PreviewDialog::slotProcessPlayQueue()\n{\n\tif(!m_playing)\n\t\treturn;\n\n\tif(m_processingPlayQueue)\n\t\treturn;\n\tm_processingPlayQueue = true;\n\n\tconst VSVideoInfo * vi = m_nodeInfo[m_outputIndex].getAsVideo();\n\tif(!vi)\n\t\treturn;\n\n\tint nextFrame = (m_frameShown + 1) % vi->numFrames;\n\tFrame referenceFrame(nextFrame, m_outputIndex, nullptr);\n\n\twhile(!m_framesCache[m_outputIndex].empty())\n\t{\n\t\tstd::list<Frame>::const_iterator it =\n\t\t\tstd::find(m_framesCache[m_outputIndex].begin(),\n\t\t\tm_framesCache[m_outputIndex].end(), referenceFrame);\n\n\t\tif(it == m_framesCache[m_outputIndex].end())\n\t\t\tbreak;\n\n\t\tif(m_nativePlaybackRate)\n\t\t{\n\t\t\tQ_ASSERT(m_cpVSAPI);\n\t\t\tconst VSMap * frameProps = m_cpVSAPI->getFramePropertiesRO(\n\t\t\t\tit->cpOutputFrame);\n\t\t\tint err_num, err_den;\n\t\t\tint64_t durNum = m_cpVSAPI->mapGetInt(frameProps, \"_DurationNum\", 0, &err_num);\n\t\t\tint64_t durDen = m_cpVSAPI->mapGetInt(frameProps, \"_DurationDen\", 0, &err_den);\n\t\t\tif(err_num || err_den || durNum <= 0 || durDen <= 0)\n\t\t\t{\n\t\t\t\t// Fallback to custom\n\t\t\t\tdouble limit = m_ui.playFpsLimitSpinBox->value();\n\t\t\t\tif(limit < 1e-3)\n\t\t\t\t\tlimit = 1e-3;\n\t\t\t\tm_secondsBetweenFrames = 1.0 / limit;\n\t\t\t}\n\t\t\telse\n\t\t\t\tm_secondsBetweenFrames = (double)durNum / (double)durDen;\n\t\t}\n\t\thr_time_point now = hr_clock::now();\n\t\tdouble passed = duration_to_double(now - m_lastFrameShowTime);\n\t\tdouble secondsToNextFrame = m_secondsBetweenFrames - passed;\n\t\tif(secondsToNextFrame > 0)\n\t\t{\n\t\t\tint millisecondsToNextFrame = std::ceil(secondsToNextFrame * 1000);\n\t\t\tm_pPlayTimer->start(millisecondsToNextFrame);\n\t\t\tbreak;\n\t\t}\n\n\t\tsetCurrentFrame(it->cpOutputFrame, it->cpPreviewFrame);\n\t\tm_lastFrameShowTime = hr_clock::now();\n\n\t\tm_frameShown = nextFrame;\n\t\tsetExpectedFrame(m_frameShown);\n\t\tm_ui.frameNumberSpinBox->setValue(m_frameExpected);\n\t\tm_ui.frameNumberSlider->setFrame(m_frameExpected, false);\n\t\tm_framesCache[m_outputIndex].erase(it);\n\t\tnextFrame = (m_frameShown + 1) % vi->numFrames;\n\t\treferenceFrame.number = nextFrame;\n\t}\n\n\tnextFrame = (m_lastFrameRequestedForPlay + 1) % vi->numFrames;\n\n\twhile(((m_framesInQueue[m_outputIndex] + m_framesInProcess[m_outputIndex]) <\n\t\tm_maxThreads) &&\n\t\t(m_framesCache[m_outputIndex].size() <= m_cachedFramesLimit))\n\t{\n\t\tm_pVapourSynthScriptProcessor->requestFrameAsync(nextFrame,\n\t\t\tm_outputIndex, true);\n\t\tm_lastFrameRequestedForPlay = nextFrame;\n\t\tnextFrame = (nextFrame + 1) % vi->numFrames;\n\t}\n\n\tm_processingPlayQueue = false;\n}\n\n// END OF void PreviewDialog::slotProcessPlayQueue()\n//==============================================================================\n\n#ifdef Q_OS_WIN // AUDIO\nvoid PreviewDialog::slotProcessAudioPlayQueue()\n{\n\tif(!m_playing)\n\t\treturn;\n\n\tif(m_processingPlayQueue)\n\t\treturn;\n\tm_processingPlayQueue = true;\n\n\tint numFrames = m_nodeInfo[m_outputIndex].numFrames();\n\tint nextFrame = (m_frameShown + 1) % numFrames;\n\n\tstatic double delay_estimate = 0.0;\n\n\twhile(!m_framesCache[m_outputIndex].empty())\n\t{\n\t\tauto ait = m_audioCache.find(nextFrame);\n\t\tif(ait == m_audioCache.end())\n\t\t\tbreak;\n\t\tauto af = m_audioCache[nextFrame];\n\n\t\tdouble ms_offset = 0.0;\n\t\thr_time_point now = hr_clock::now();\n\t\tdouble passed = duration_to_double(now - m_lastFrameShowTime);\n\t\tdouble secondsToNextFrame = m_secondsBetweenFrames - passed - delay_estimate;\n\t\tif(secondsToNextFrame > 0)\n\t\t{\n\t\t\tint millisecondsToNextFrame = std::round(secondsToNextFrame * 1000);\n\t\t\tms_offset = secondsToNextFrame - millisecondsToNextFrame / 1000.0;\n\t\t\tm_pAudioPlayTimer->start(millisecondsToNextFrame);\n\t\t\tbreak;\n\t\t}\n\n\t\tm_lastFrameShowTime = hr_clock::now();\n\t\tm_pAudioIODevice->write(af.data);\n\t\tauto time_post = hr_clock::now();\n\t\tdelay_estimate = duration_to_double(time_post - m_lastFrameShowTime) - ms_offset;\n\t\tm_audioCache.erase(nextFrame);\n\n\t\tFrame referenceFrame(nextFrame, m_outputIndex, nullptr);\n\t\tstd::list<Frame>::const_iterator it =\n\t\t\tstd::find(m_framesCache[m_outputIndex].begin(),\n\t\t\tm_framesCache[m_outputIndex].end(), referenceFrame);\n\n\t\t// caches are synced so this won't happen...\n\t\tif(it == m_framesCache[m_outputIndex].end())\n\t\t\tbreak;\n\n\t\tsetCurrentFrame(it->cpOutputFrame, it->cpPreviewFrame);\n\t\tm_frameShown = nextFrame;\n\t\tsetExpectedFrame(m_frameShown);\n\t\tm_ui.frameNumberSpinBox->setValue(m_frameExpected);\n\t\tm_ui.frameNumberSlider->setFrame(m_frameExpected, false);\n\t\tm_framesCache[m_outputIndex].erase(it);\n\t\tnextFrame = (m_frameShown + 1) % numFrames;\n\t\treferenceFrame.number = nextFrame;\n\t}\n\n\tnextFrame = (m_lastFrameRequestedForPlay + 1) % numFrames;\n\n\twhile(((m_framesInQueue[m_outputIndex] + m_framesInProcess[m_outputIndex]) <\n\t\tm_maxThreads) &&\n\t\t(m_framesCache[m_outputIndex].size() <= m_cachedFramesLimit))\n\t{\n\t\tm_pVapourSynthScriptProcessor->requestFrameAsync(nextFrame,\n\t\t\tm_outputIndex, true);\n\t\tm_lastFrameRequestedForPlay = nextFrame;\n\t\tnextFrame = (nextFrame + 1) % numFrames;\n\t}\n\n\tif(m_framesCache[m_outputIndex].empty())\n\t\tm_audioCache.clear();\n\n\tm_processingPlayQueue = false;\n}\n#endif\n\nvoid PreviewDialog::slotLoadChapters()\n{\n\tif(m_playing)\n\t\treturn;\n\n\tif (m_fpsDen == 0)\n\t{\n\t\tQString infoString = tr(\n\t\t\t\"Warning: Load chapters requires clip having constant frame rate. Skipped\");\n\t\temit signalWriteLogMessage(mtWarning, infoString);\n\t\treturn;\n\t}\n\n\tconst QString lastUsedPath = m_pSettingsManager->getLastUsedPath();\n\tconst QString filePath = QFileDialog::getOpenFileName(this,\n\t\ttr(\"Load chapters\"), lastUsedPath,\n\t\ttr(\"Chapters file (*.txt;*.xml);;All files (*)\"));\n\tQFile chaptersFile(filePath);\n\tif(!chaptersFile.open(QIODevice::ReadOnly | QIODevice::Text))\n\t\treturn;\n\n\tstatic QRegularExpression re = QRegularExpression(\n\t\tR\"((\\d{1,3}):(\\d{2}):(\\d{2})[\\.:](\\d{3})?)\");\n\twhile(!chaptersFile.atEnd())\n\t{\n\t\tconst QByteArray line = chaptersFile.readLine();\n\t\tauto match = re.match(line);\n\t\tif(!match.hasMatch())\n\t\t\tcontinue;\n\n\t\tdouble timecode = match.captured(1).toDouble() * 3600 +\n\t\t\tmatch.captured(2).toDouble() * 60 + match.captured(3).toDouble() +\n\t\t\tmatch.captured(4).toDouble() / 1000;\n\t\tconst int frameIndex = round(timecode * m_fpsNum / m_fpsDen);\n\t\tm_ui.frameNumberSlider->addBookmark(frameIndex);\n\t}\n\n\tsaveTimelineBookmarks();\n}\n\n// END OF void PreviewDialog::slotLoadBookmarks()\n//==============================================================================\n\nvoid PreviewDialog::slotClearBookmarks()\n{\n\tif(m_playing)\n\t\treturn;\n\n\tQMessageBox quesBox(this);\n\tvsedit::disableFontKerning(&quesBox);\n\tquesBox.setWindowTitle(tr(\"Clear Bookmarks\"));\n\tquesBox.setText(tr(\"Do you really want to clear timeline bookmarks?\"));\n\tquesBox.setStandardButtons(QMessageBox::Yes | QMessageBox::No);\n\tquesBox.setDefaultButton(QMessageBox::No);\n\tint result = quesBox.exec();\n\tif(result == QMessageBox::No)\n\t\treturn;\n\n\tm_ui.frameNumberSlider->clearBookmarks();\n\tsaveTimelineBookmarks();\n}\n\n// END OF void PreviewDialog::slotClearBookmarks()\n//==============================================================================\n\nvoid PreviewDialog::slotBookmarkCurrentFrame()\n{\n\tif(m_playing)\n\t\treturn;\n\n\tm_ui.frameNumberSlider->slotBookmarkCurrentFrame();\n\tsaveTimelineBookmarks();\n}\n\n// END OF void PreviewDialog::slotBookmarkCurrentFrame()\n//==============================================================================\n\nvoid PreviewDialog::slotUnbookmarkCurrentFrame()\n{\n\tif(m_playing)\n\t\treturn;\n\n\tm_ui.frameNumberSlider->slotUnbookmarkCurrentFrame();\n\tsaveTimelineBookmarks();\n}\n\n// END OF void PreviewDialog::slotUnbookmarkCurrentFrame()\n//==============================================================================\n\nvoid PreviewDialog::slotGoToPreviousBookmark()\n{\n\tif(m_playing)\n\t\treturn;\n\n\tm_ui.frameNumberSlider->slotGoToPreviousBookmark();\n}\n\n// END OF void PreviewDialog::slotGoToPreviousBookmark()\n//==============================================================================\n\nvoid PreviewDialog::slotGoToNextBookmark()\n{\n\tif(m_playing)\n\t\treturn;\n\n\tm_ui.frameNumberSlider->slotGoToNextBookmark();\n}\n\n// END OF void PreviewDialog::slotGoToNextBookmark()\n//==============================================================================\n\nvoid PreviewDialog::slotPasteShownFrameNumberIntoScript()\n{\n\temit signalPasteIntoScriptAtCursor(QString::number(m_frameShown));\n}\n\n// END OF void PreviewDialog::slotPasteShownFrameNumberIntoScript()\n//==============================================================================\n\nvoid PreviewDialog::slotSaveGeometry()\n{\n\tm_pGeometrySaveTimer->stop();\n\tm_pSettingsManager->setPreviewDialogGeometry(m_windowGeometry);\n}\n\nvoid PreviewDialog::slotJumpToFrame()\n{\n\tif(m_playing)\n\t\treturn;\n\n\tif(busy())\n\t\treturn;\n\n\tint currFrameNumber = m_frameExpected;\n\tint lastFrameNumber = m_nodeInfo[m_outputIndex].numFrames() - 1;\n\tint frame = QInputDialog::getInt(this, \"Jump to...\",\n\t\t\"Jump to frame...\", currFrameNumber);\n\tif(frame < 0) // Allowing -1, for example\n\t\tframe = lastFrameNumber + frame + 1;\n\tif(frame < 0)\n\t\tframe = 0;\n\tif(frame > lastFrameNumber)\n\t\tframe = lastFrameNumber;\n\tif(frame != currFrameNumber)\n\t{\n\t\tslotShowFrame(frame, true);\n\t}\n}\n\nQPoint PreviewDialog::loadLastScrollBarPositions() const\n{\n\treturn m_pSettingsManager->getLastPreviewScrollBarPositions();\n}\n\nvoid PreviewDialog::saveLastScrollBarPositions()\n{\n\tQPoint pos = m_ui.previewArea->getScrollBarPositions();\n\tm_pSettingsManager->setLastPreviewScrollBarPositions(pos);\n}\n\n// END OF void PreviewDialog::slotSaveGeometry()\n//==============================================================================\n\n#ifdef Q_OS_WIN // AUDIO\nvoid PreviewDialog::setAudioOutput()\n{\n\tconst VSAudioInfo * pAI = m_nodeInfo[m_outputIndex].getAsAudio();\n\tQAudioFormat af;\n\tint numChannels = pAI->format.numChannels;\n\tint bytesPerSample = pAI->format.bytesPerSample;\n\taf.setChannelCount(numChannels);\n\taf.setSampleRate(pAI->sampleRate);\n\n\t// Always convert to int16\n\tbytesPerSample = 2;\n\taf.setSampleFormat(QAudioFormat::Int16);\n\n\tstopAudioOutput();\n\tQAudioDevice device = QMediaDevices::defaultAudioOutput();\n\tif(numChannels <= 2 && device.isFormatSupported(af))\n\t{\n\t\tm_pAudioSink = new QAudioSink(device, af);\n\t\tm_pAudioSink->setVolume(m_audioVolume);\n\t\tm_pAudioSink->setBufferSize(numChannels * bytesPerSample * VS_AUDIO_FRAME_SAMPLES * 3);\n\t\tm_pAudioIODevice = m_pAudioSink->start();\n\t}\n\telse\n\t{\n\t\tqWarning() << QString(\"Audio format of node #%1 is not yet supported for playback.\")\n\t\t\t.arg(m_outputIndex).toStdString().c_str();\n\t}\n}\n\nvoid PreviewDialog::stopAudioOutput()\n{\n\tif(m_pAudioSink)\n\t{\n\t\tif(m_pAudioIODevice)\n\t\t\tm_pAudioIODevice->close();\n\t\tm_pAudioSink->stop();\n\t\tdelete m_pAudioSink;\n\t\tm_pAudioSink = nullptr;\n\t\tm_pAudioIODevice = nullptr;\n\t}\n\tm_audioCache.clear();\n}\n\nvoid PreviewDialog::playAudioFrame()\n{\n\tQByteArray frameData = readAudioFrame(m_cpFrame);\n\tif(frameData.size() > 0 && m_pAudioSink)\n\t{\n\t\tm_pAudioIODevice->write(frameData);\n\t}\n}\n\nQByteArray PreviewDialog::readAudioFrame(const VSFrame *a_cpFrame)\n{\n\tif(!a_cpFrame)\n\t    return QByteArray();\n\tif(m_cpVSAPI->getFrameType(a_cpFrame) != mtAudio)\n\t\treturn QByteArray();\n\tif(!m_pAudioSink)\n\t\treturn QByteArray();\n\n\tint numChannels = m_nodeInfo[m_outputIndex].getAsAudio()->format.numChannels;\n\tint bytesPerSample = m_nodeInfo[m_outputIndex].getAsAudio()->format.bytesPerSample;\n\tauto sampleType = m_nodeInfo[m_outputIndex].getAsAudio()->format.sampleType;\n\tif(numChannels == 1)\n\t{\n\t\tif(bytesPerSample == 2)\n\t\t\treturn QByteArray::fromRawData(reinterpret_cast<const char *>(\n\t\t\t\tm_cpVSAPI->getReadPtr(a_cpFrame, 0)), bytesPerSample * VS_AUDIO_FRAME_SAMPLES);\n\t\telse if(sampleType == stFloat)\n\t\t{\n\t\t\tstd::vector<int16_t> cache;\n\t\t\tcache.reserve(numChannels * VS_AUDIO_FRAME_SAMPLES);\n\t\t\tauto ptr0 = reinterpret_cast<const float *>(m_cpVSAPI->getReadPtr(a_cpFrame, 0));\n\t\t\tauto stride = m_cpVSAPI->getStride(a_cpFrame, 0) / bytesPerSample;\n\t\t\tfor (ptrdiff_t i = 0; i < stride; ++i)\n\t\t\t\tcache[i] = dither32Fto16(ptr0[i]);\n\t\t\treturn QByteArray::fromRawData(reinterpret_cast<const char *>(cache.data()),\n\t\t\t\tnumChannels * 2 * VS_AUDIO_FRAME_SAMPLES);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tstd::vector<uint16_t> cache;\n\t\t\tcache.reserve(numChannels * VS_AUDIO_FRAME_SAMPLES);\n\t\t\tauto ptr0 = reinterpret_cast<const uint32_t *>(m_cpVSAPI->getReadPtr(a_cpFrame, 0));\n\t\t\tauto stride = m_cpVSAPI->getStride(a_cpFrame, 0) / bytesPerSample;\n\t\t\tfor (ptrdiff_t i = 0; i < stride; ++i)\n\t\t\t\tcache[i] = dither32to16(ptr0[i]);\n\t\t\treturn QByteArray::fromRawData(reinterpret_cast<const char *>(cache.data()),\n\t\t\t\tnumChannels * 2 * VS_AUDIO_FRAME_SAMPLES);\n\t\t}\n\t}\n\telse\n\t{\n\t\tif(sampleType == stFloat)\n\t\t{\n\t\t\tstd::vector<int16_t> cache;\n\t\t\tcache.reserve(numChannels * VS_AUDIO_FRAME_SAMPLES);\n\t\t\tauto ptr0 = reinterpret_cast<const float *>(m_cpVSAPI->getReadPtr(a_cpFrame, 0));\n\t\t\tauto ptr1 = reinterpret_cast<const float *>(m_cpVSAPI->getReadPtr(a_cpFrame, 1));\n\t\t\tauto stride = m_cpVSAPI->getStride(a_cpFrame, 0) / bytesPerSample;\n\t\t\tfor (ptrdiff_t i = 0; i < stride; ++i)\n\t\t\t{\n\t\t\t\tcache[2 * i] = dither32Fto16(ptr0[i]);\n\t\t\t\tcache[2 * i + 1] = dither32Fto16(ptr1[i]);\n\t\t\t}\n\t\t\treturn QByteArray::fromRawData(reinterpret_cast<const char *>(cache.data()),\n\t\t\t\tnumChannels * 2 * VS_AUDIO_FRAME_SAMPLES);\n\t\t}\n\t\telse if(bytesPerSample == 2)\n\t\t{\n\t\t\tstd::vector<uint16_t> cache;\n\t\t\tcache.reserve(numChannels * VS_AUDIO_FRAME_SAMPLES);\n\t\t\tauto ptr0 = reinterpret_cast<const uint16_t *>(m_cpVSAPI->getReadPtr(a_cpFrame, 0));\n\t\t\tauto ptr1 = reinterpret_cast<const uint16_t *>(m_cpVSAPI->getReadPtr(a_cpFrame, 1));\n\t\t\tauto stride = m_cpVSAPI->getStride(a_cpFrame, 0) / bytesPerSample;\n\t\t\tfor (ptrdiff_t i = 0; i < stride; ++i)\n\t\t\t{\n\t\t\t\tcache[2 * i] = ptr0[i];\n\t\t\t\tcache[2 * i + 1] = ptr1[i];\n\t\t\t}\n\t\t\treturn QByteArray::fromRawData(reinterpret_cast<const char *>(cache.data()),\n\t\t\t\tnumChannels * 2 * VS_AUDIO_FRAME_SAMPLES);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tstd::vector<uint16_t> cache;\n\t\t\tcache.reserve(numChannels * VS_AUDIO_FRAME_SAMPLES);\n\t\t\tauto ptr0 = reinterpret_cast<const uint32_t *>(m_cpVSAPI->getReadPtr(a_cpFrame, 0));\n\t\t\tauto ptr1 = reinterpret_cast<const uint32_t *>(m_cpVSAPI->getReadPtr(a_cpFrame, 1));\n\t\t\tauto stride = m_cpVSAPI->getStride(a_cpFrame, 0) / bytesPerSample;\n\t\t\tfor (ptrdiff_t i = 0; i < stride; ++i)\n\t\t\t{\n\t\t\t\tcache[2 * i] = dither32to16(ptr0[i]);\n\t\t\t\tcache[2 * i + 1] = dither32to16(ptr1[i]);\n\t\t\t}\n\t\t\treturn QByteArray::fromRawData(reinterpret_cast<const char *>(cache.data()),\n\t\t\t\tnumChannels * 2 * VS_AUDIO_FRAME_SAMPLES);\n\t\t}\n\t}\n}\n#endif\n\nvoid PreviewDialog::slotToggleFrameProps()\n{\n\tif(m_pFramePropsPanel->isVisible())\n\t{\n\t\tm_pFramePropsPanel->setVisible(false);\n\t}\n\telse\n\t{\n\t\tupdateFrameProps(true);\n\t\tm_pFramePropsPanel->setVisible(true);\n\t}\n}\n// END OF void PreviewDialog::slotToggleFrameProps()\n//==============================================================================\n\nvoid PreviewDialog::slotSwitchOutputIndex(int a_outputIndex)\n{\n\t// Assuming there's a change\n\tif(a_outputIndex == m_outputIndex)\n\t\treturn;\n\n\t// Assuming already initialized\n\tif(!m_pVapourSynthScriptProcessor->isInitialized())\n\t\treturn;\n\n\t// Don't switch when playing (avoiding big troubles ahead)\n\tif(m_playing)\n\t\treturn;\n\n\t// Don't switch when busy processing the current frame\n\tif(busy())\n\t\treturn;\n\n\t// Check if output index is available\n\tVSNodeInfo ni = m_pVapourSynthScriptProcessor->nodeInfo(a_outputIndex);\n\tif(ni.isInvalid())\n\t\treturn;\n#ifdef Q_OS_WIN // AUDIO\n\tstopAudioOutput();\n\tm_currentIsAudio = ni.mediaType() == mtAudio;\n#else\n\tif(ni.isAudio())\n\t{\n\t\tQString errorString = tr(\"Output node #%1 is audio. \"\n\t\t\t\"Previewing and encoding audio are not supported.\")\n\t\t\t.arg(a_outputIndex);\n\t\temit signalWriteLogMessage(\n\t\t\ta_outputIndex == 0 ? mtCritical : mtWarning, errorString);\n\t\treturn;\n\t}\n#endif\n\tm_outputIndex = a_outputIndex;\n\n\t// Update stuff\n\tm_clipName = \"\";\n\tm_sceneName = \"\";\n\tm_toChangeTitle = true;\n\n\tm_nodeInfo[m_outputIndex] = ni;\n\tint lastFrameNumber = m_nodeInfo[m_outputIndex].numFrames() - 1;\n\tm_ui.frameNumberSpinBox->setMaximum(lastFrameNumber);\n\tm_ui.frameNumberSlider->setFramesNumber(\n\t\tm_nodeInfo[m_outputIndex].numFrames(), false);\n\t\tauto fpsPair = m_nodeInfo[m_outputIndex].fpsPair();\n\tm_fpsNum = fpsPair.first;\n\tm_fpsDen = fpsPair.second;\n\tm_ui.frameNumberSlider->setFPS(m_fpsDen == 0 ?\n\t\t0.0 : (double)m_fpsNum / (double)m_fpsDen);\n\n\tm_pStatusBarWidget->setNodeInfo(m_nodeInfo[m_outputIndex], m_cpVSAPI);\n\n\tbool setFrameFromTimestamps = false;\n\tSyncOutputNodesMode syncMode = m_pSettingsManager->getSyncOutputMode();\n\tif(syncMode == SyncOutputNodesMode::Time)\n\t\tsetFrameFromTimestamps = true;\n\telse if(syncMode == SyncOutputNodesMode::FromTimeLine)\n\t{\n\t\tTimeLineSlider::DisplayMode timeLineMode = (TimeLineSlider::DisplayMode)\n\t\t\tm_ui.timeLineModeComboBox->currentData().toInt();\n\t\tif(timeLineMode == TimeLineSlider::DisplayMode::Time)\n\t\t\tsetFrameFromTimestamps = true;\n\t}\n\tif(setFrameFromTimestamps)\n\t\tm_frameExpected = timestampToFrame(m_frameTimestampExpected);\n\n\tif(m_frameExpected > lastFrameNumber)\n\t\tsetExpectedFrame(lastFrameNumber);\n\telse if(m_frameExpected < 0)\n\t\tsetExpectedFrame(0);\n\n#ifdef Q_OS_WIN // AUDIO\n\tif(m_currentIsAudio)\n\t{\n\t\tif(m_ui.cropCheckButton->isChecked())\n\t\t\tm_ui.cropCheckButton->click();\n\t\tm_ui.cropCheckButton->setEnabled(false);\n\t\tm_pActionToggleCropPanel->setEnabled(false);\n\t\tm_ui.saveSnapshotButton->setEnabled(false);\n\t\tm_pActionSaveSnapshot->setEnabled(false);\n\t\tm_pStatusBarWidget->setColorPickerString(\"\");\n\t\tm_ui.playFpsLimitSpinBox->setEnabled(false);\n\t\tm_ui.playFpsLimitModeComboBox->setEnabled(false);\n\t\tint comboIndex = m_ui.playFpsLimitModeComboBox->findData(\n\t\t\t(int)PlayFPSLimitMode::FromVideo);\n\t\tif(comboIndex != -1)\n\t\t\tm_ui.playFpsLimitModeComboBox->setCurrentIndex(comboIndex);\n\n\t\tsetAudioOutput();\n\t}\n\telse\n\t{\n\t\tresetCropSpinBoxes();\n\t\tm_ui.cropCheckButton->setEnabled(true);\n\t\tm_pActionToggleCropPanel->setEnabled(true);\n\t\tm_ui.saveSnapshotButton->setEnabled(true);\n\t\tm_pActionSaveSnapshot->setEnabled(true);\n\t\tm_ui.playFpsLimitSpinBox->setEnabled(true);\n\t\tm_ui.playFpsLimitModeComboBox->setEnabled(true);\n\t}\n#else\n\tresetCropSpinBoxes();\n#endif\n\tslotSetPlayFPSLimit();\n\n\tresetCropSpinBoxes();\n\n\tm_pVapourSynthScriptProcessor->requestFrameAsync(m_frameExpected,\n\t\tm_outputIndex, true);\n\n\tslotShowFrame(m_frameExpected, false);\n}\n\n// END OF void PreviewDialog::slotSwitchOutputIndex(int a_outputIndex)\n//==============================================================================\n\nvoid PreviewDialog::slotEnableSwitchOutputIndex(bool a_idle)\n{\n\tif(m_playing)\n\t{\n\t\tm_ui.outputIndexComboBox->setEnabled(false);\n\t\treturn;\n\t}\n\tm_ui.outputIndexComboBox->setEnabled(a_idle);\n}\n\nvoid PreviewDialog::setOutputIndex(int a_index)\n{\n\tif(!m_ui.outputIndexComboBox->isEnabled())\n\t\treturn;\n\n\tif(m_playing)\n\t\treturn;\n\n\tif(a_index == m_outputIndex)\n\t\treturn;\n\n\tif(m_outputIndices.size() == 0)\n\t\treturn slotSwitchOutputIndex(a_index);\n\n\tif(vsedit::contains(m_outputIndices, a_index))\n\t{\n\t\tm_ui.outputIndexComboBox->setCurrentText(QString::number(a_index));\n\t}\n\telse\n\t{\n\t\temit signalWriteLogMessage(mtWarning,\n\t\t\tQString(\"Couldn't resolve output node #%1.\").arg(a_index));\n\t}\n}\n\nvoid PreviewDialog::slotSwitchToPreviousOutputIndex()\n{\n\tsize_t num = m_outputIndices.size();\n\tif(num <= 1)\n\t\treturn;\n\n\tif(m_outputIndex == m_outputIndices[0])\n\t\treturn setOutputIndex(m_outputIndices[num - 1]);\n\n\tauto idx = std::upper_bound(m_outputIndices.begin(),\n\t\tm_outputIndices.end(), m_outputIndex - 1);\n\tif(idx == m_outputIndices.end())\n\t\treturn setOutputIndex(m_outputIndices[num - 1]);\n\telse\n\t\treturn setOutputIndex(*(idx-1));\n}\n\nvoid PreviewDialog::slotSwitchToNextOutputIndex()\n{\n\tsize_t num = m_outputIndices.size();\n\tif(num <= 1)\n\t\treturn;\n\n\tif(m_outputIndex == m_outputIndices[num - 1])\n\t\treturn setOutputIndex(m_outputIndices[0]);\n\n\tauto idx = std::lower_bound(m_outputIndices.begin(),\n\t\tm_outputIndices.end(), m_outputIndex + 1);\n\tif(idx == m_outputIndices.end())\n\t\treturn setOutputIndex(m_outputIndices[0]);\n\telse\n\t\treturn setOutputIndex(*idx);\n}\n\nvoid PreviewDialog::createActionsAndMenus()\n{\n\tstruct ActionToCreate\n\t{\n\t\tQAction ** ppAction;\n\t\tconst char * id;\n\t\tbool checkable;\n\t\tconst char * slotToConnect;\n\t};\n\n\tActionToCreate actionsToCreate[] =\n\t{\n\t\t{&m_pActionFrameToClipboard, ACTION_ID_FRAME_TO_CLIPBOARD,\n\t\t\tfalse, SLOT(slotFrameToClipboard())},\n\t\t{&m_pActionSaveSnapshot, ACTION_ID_SAVE_SNAPSHOT,\n\t\t\tfalse, SLOT(slotSaveSnapshot())},\n\t\t{&m_pActionToggleZoomPanel, ACTION_ID_TOGGLE_ZOOM_PANEL,\n\t\t\ttrue, SLOT(slotToggleZoomPanelVisible(bool))},\n\t\t{&m_pActionSetZoomModeNoZoom, ACTION_ID_SET_ZOOM_MODE_NO_ZOOM,\n\t\t\ttrue, SLOT(slotZoomModeChanged())},\n\t\t{&m_pActionSetZoomModeFixedRatio, ACTION_ID_SET_ZOOM_MODE_FIXED_RATIO,\n\t\t\ttrue, SLOT(slotZoomModeChanged())},\n\t\t{&m_pActionSetZoomModeFitToFrame, ACTION_ID_SET_ZOOM_MODE_FIT_TO_FRAME,\n\t\t\ttrue, SLOT(slotZoomModeChanged())},\n\t\t{&m_pActionSetZoomScaleModeNearest,\n\t\t\tACTION_ID_SET_ZOOM_SCALE_MODE_NEAREST,\n\t\t\ttrue, SLOT(slotScaleModeChanged())},\n\t\t{&m_pActionSetZoomScaleModeBilinear,\n\t\t\tACTION_ID_SET_ZOOM_SCALE_MODE_BILINEAR,\n\t\t\ttrue, SLOT(slotScaleModeChanged())},\n\t\t{&m_pActionToggleCropPanel, ACTION_ID_TOGGLE_CROP_PANEL,\n\t\t\ttrue, SLOT(slotToggleCropPanelVisible(bool))},\n\t\t{&m_pActionToggleTimeLinePanel, ACTION_ID_TOGGLE_TIMELINE_PANEL,\n\t\t\ttrue, SLOT(slotToggleTimeLinePanelVisible(bool))},\n\t\t{&m_pActionSetTimeLineModeTime, ACTION_ID_SET_TIMELINE_MODE_TIME,\n\t\t\ttrue, SLOT(slotTimeLineModeChanged())},\n\t\t{&m_pActionSetTimeLineModeFrames, ACTION_ID_SET_TIMELINE_MODE_FRAMES,\n\t\t\ttrue, SLOT(slotTimeLineModeChanged())},\n\t\t{&m_pActionTimeStepForward, ACTION_ID_TIME_STEP_FORWARD,\n\t\t\tfalse, SLOT(slotTimeStepForward())},\n\t\t{&m_pActionTimeStepBack, ACTION_ID_TIME_STEP_BACK,\n\t\t\tfalse, SLOT(slotTimeStepBack())},\n\t\t{&m_pActionPasteCropSnippetIntoScript,\n\t\t\tACTION_ID_PASTE_CROP_SNIPPET_INTO_SCRIPT,\n\t\t\tfalse, SLOT(slotPasteCropSnippetIntoScript())},\n\t\t{&m_pActionAdvancedSettingsDialog, ACTION_ID_ADVANCED_PREVIEW_SETTINGS,\n\t\t\tfalse, SLOT(slotCallAdvancedSettingsDialog())},\n\t\t{&m_pActionToggleColorPicker, ACTION_ID_TOGGLE_COLOR_PICKER,\n\t\t\ttrue, SLOT(slotToggleColorPicker(bool))},\n\t\t{&m_pActionPlay, ACTION_ID_PLAY,\n\t\t\ttrue, SLOT(slotPlay(bool))},\n\t\t{&m_pActionLoadChapters, ACTION_ID_TIMELINE_LOAD_CHAPTERS,\n\t\t\tfalse, SLOT(slotLoadChapters())},\n\t\t{&m_pActionClearBookmarks, ACTION_ID_TIMELINE_CLEAR_BOOKMARKS,\n\t\t\tfalse, SLOT(slotClearBookmarks())},\n\t\t{&m_pActionBookmarkCurrentFrame,\n\t\t\tACTION_ID_TIMELINE_BOOKMARK_CURRENT_FRAME,\n\t\t\tfalse, SLOT(slotBookmarkCurrentFrame())},\n\t\t{&m_pActionUnbookmarkCurrentFrame,\n\t\t\tACTION_ID_TIMELINE_UNBOOKMARK_CURRENT_FRAME,\n\t\t\tfalse, SLOT(slotUnbookmarkCurrentFrame())},\n\t\t{&m_pActionGoToPreviousBookmark,\n\t\t\tACTION_ID_TIMELINE_GO_TO_PREVIOUS_BOOKMARK,\n\t\t\tfalse, SLOT(slotGoToPreviousBookmark())},\n\t\t{&m_pActionGoToNextBookmark, ACTION_ID_TIMELINE_GO_TO_NEXT_BOOKMARK,\n\t\t\tfalse, SLOT(slotGoToNextBookmark())},\n\t\t{&m_pActionPasteShownFrameNumberIntoScript,\n\t\t\tACTION_ID_PASTE_SHOWN_FRAME_NUMBER_INTO_SCRIPT,\n\t\t\tfalse, SLOT(slotPasteShownFrameNumberIntoScript())},\n\t\t{&m_pActionJumpToFrame, ACTION_ID_JUMP_TO_FRAME,\n\t\t\tfalse, SLOT(slotJumpToFrame())},\n\t\t{&m_pActionToggleFramePropsPanel, ACTION_ID_TOGGLE_FRAME_PROPS,\n\t\t\tfalse, SLOT(slotToggleFrameProps())},\n\t\t{&m_pActionSwitchToOutputIndex0, ACTION_ID_SET_OUTPUT_INDEX_0,\n\t\t\tfalse, SLOT(slotSwitchOutputIndex0())},\n\t\t{&m_pActionSwitchToOutputIndex1, ACTION_ID_SET_OUTPUT_INDEX_1,\n\t\t\tfalse, SLOT(slotSwitchOutputIndex1())},\n\t\t{&m_pActionSwitchToOutputIndex2, ACTION_ID_SET_OUTPUT_INDEX_2,\n\t\t\tfalse, SLOT(slotSwitchOutputIndex2())},\n\t\t{&m_pActionSwitchToOutputIndex3, ACTION_ID_SET_OUTPUT_INDEX_3,\n\t\t\tfalse, SLOT(slotSwitchOutputIndex3())},\n\t\t{&m_pActionSwitchToOutputIndex4, ACTION_ID_SET_OUTPUT_INDEX_4,\n\t\t\tfalse, SLOT(slotSwitchOutputIndex4())},\n\t\t{&m_pActionSwitchToOutputIndex5, ACTION_ID_SET_OUTPUT_INDEX_5,\n\t\t\tfalse, SLOT(slotSwitchOutputIndex5())},\n\t\t{&m_pActionSwitchToOutputIndex6, ACTION_ID_SET_OUTPUT_INDEX_6,\n\t\t\tfalse, SLOT(slotSwitchOutputIndex6())},\n\t\t{&m_pActionSwitchToOutputIndex7, ACTION_ID_SET_OUTPUT_INDEX_7,\n\t\t\tfalse, SLOT(slotSwitchOutputIndex7())},\n\t\t{&m_pActionSwitchToOutputIndex8, ACTION_ID_SET_OUTPUT_INDEX_8,\n\t\t\tfalse, SLOT(slotSwitchOutputIndex8())},\n\t\t{&m_pActionSwitchToOutputIndex9, ACTION_ID_SET_OUTPUT_INDEX_9,\n\t\t\tfalse, SLOT(slotSwitchOutputIndex9())},\n\t\t{&m_pActionSwitchToOutputIndex10, ACTION_ID_SET_OUTPUT_INDEX_10,\n\t\t\tfalse, SLOT(slotSwitchOutputIndex10())},\n\t\t{&m_pActionSwitchToOutputIndex11, ACTION_ID_SET_OUTPUT_INDEX_11,\n\t\t\tfalse, SLOT(slotSwitchOutputIndex11())},\n\t\t{&m_pActionSwitchToOutputIndex12, ACTION_ID_SET_OUTPUT_INDEX_12,\n\t\t\tfalse, SLOT(slotSwitchOutputIndex12())},\n\t\t{&m_pActionSwitchToOutputIndex13, ACTION_ID_SET_OUTPUT_INDEX_13,\n\t\t\tfalse, SLOT(slotSwitchOutputIndex13())},\n\t\t{&m_pActionSwitchToOutputIndex14, ACTION_ID_SET_OUTPUT_INDEX_14,\n\t\t\tfalse, SLOT(slotSwitchOutputIndex14())},\n\t\t{&m_pActionSwitchToOutputIndex15, ACTION_ID_SET_OUTPUT_INDEX_15,\n\t\t\tfalse, SLOT(slotSwitchOutputIndex15())},\n\t\t{&m_pActionSwitchToOutputIndex16, ACTION_ID_SET_OUTPUT_INDEX_16,\n\t\t\tfalse, SLOT(slotSwitchOutputIndex16())},\n\t\t{&m_pActionSwitchToOutputIndex17, ACTION_ID_SET_OUTPUT_INDEX_17,\n\t\t\tfalse, SLOT(slotSwitchOutputIndex17())},\n\t\t{&m_pActionSwitchToOutputIndex18, ACTION_ID_SET_OUTPUT_INDEX_18,\n\t\t\tfalse, SLOT(slotSwitchOutputIndex18())},\n\t\t{&m_pActionSwitchToOutputIndex19, ACTION_ID_SET_OUTPUT_INDEX_19,\n\t\t\tfalse, SLOT(slotSwitchOutputIndex19())},\n\t\t{&m_pActionSwitchToPreviousOutputIndex,\n\t\t\tACTION_ID_PREVIOUS_OUTPUT_INDEX,\n\t\t\tfalse, SLOT(slotSwitchToPreviousOutputIndex())},\n\t\t{&m_pActionSwitchToNextOutputIndex, ACTION_ID_NEXT_OUTPUT_INDEX,\n\t\t\tfalse, SLOT(slotSwitchToNextOutputIndex())},\n\t};\n\n\tfor(ActionToCreate & item : actionsToCreate)\n\t{\n\t\tQAction * pAction =\n\t\t\tm_pSettingsManager->createStandardAction(item.id, this);\n\t\t*item.ppAction = pAction;\n\t\tpAction->setCheckable(item.checkable);\n\t\tm_settableActionsList.push_back(pAction);\n\t}\n\n//------------------------------------------------------------------------------\n\n\tm_pPreviewContextMenu = new QMenu(this);\n\tvsedit::disableFontKerning(m_pPreviewContextMenu);\n\tm_pPreviewContextMenu->addAction(m_pActionJumpToFrame);\n\tm_pPreviewContextMenu->addAction(m_pActionFrameToClipboard);\n\tm_pPreviewContextMenu->addAction(m_pActionSaveSnapshot);\n\tm_pPreviewContextMenu->addAction(m_pActionToggleFramePropsPanel);\n\tm_pActionToggleZoomPanel->setChecked(\n\t\tm_pSettingsManager->getZoomPanelVisible());\n\tm_pPreviewContextMenu->addAction(m_pActionToggleZoomPanel);\n\n//------------------------------------------------------------------------------\n\n\tm_pMenuZoomModes = new QMenu(m_pPreviewContextMenu);\n\tvsedit::disableFontKerning(m_pMenuZoomModes);\n\tm_pMenuZoomModes->setTitle(tr(\"Zoom mode\"));\n\tm_pPreviewContextMenu->addMenu(m_pMenuZoomModes);\n\n\tm_pActionGroupZoomModes = new QActionGroup(this);\n\n\tZoomMode zoomMode = m_pSettingsManager->getZoomMode();\n\n\tstruct ZoomModeAction\n\t{\n\t\tQAction * pAction;\n\t\tZoomMode zoomMode;\n\t};\n\n\tZoomModeAction zoomModeActions[] =\n\t{\n\t\t{m_pActionSetZoomModeNoZoom, ZoomMode::NoZoom},\n\t\t{m_pActionSetZoomModeFixedRatio, ZoomMode::FixedRatio},\n\t\t{m_pActionSetZoomModeFitToFrame, ZoomMode::FitToFrame},\n\t};\n\n\tfor(ZoomModeAction & action : zoomModeActions)\n\t{\n\t\tQString id = action.pAction->data().toString();\n\t\taction.pAction->setActionGroup(m_pActionGroupZoomModes);\n\t\tm_pMenuZoomModes->addAction(action.pAction);\n\t\tm_actionIDToZoomModeMap[id] = action.zoomMode;\n\t\taddAction(action.pAction);\n\t\tif(zoomMode == action.zoomMode)\n\t\t\taction.pAction->setChecked(true);\n\t}\n\n//------------------------------------------------------------------------------\n\n\tm_pMenuZoomScaleModes = new QMenu(m_pPreviewContextMenu);\n\tvsedit::disableFontKerning(m_pMenuZoomScaleModes);\n\tm_pMenuZoomScaleModes->setTitle(tr(\"Zoom scale mode\"));\n\tm_pPreviewContextMenu->addMenu(m_pMenuZoomScaleModes);\n\n\tm_pActionGroupZoomScaleModes = new QActionGroup(this);\n\n\tQt::TransformationMode scaleMode = m_pSettingsManager->getScaleMode();\n\n\tstruct ScaleModeAction\n\t{\n\t\tQAction * pAction;\n\t\tQt::TransformationMode scaleMode;\n\t};\n\n\tScaleModeAction scaleModeActions[] =\n\t{\n\t\t{m_pActionSetZoomScaleModeNearest, Qt::FastTransformation},\n\t\t{m_pActionSetZoomScaleModeBilinear, Qt::SmoothTransformation},\n\t};\n\n\tfor(ScaleModeAction & action : scaleModeActions)\n\t{\n\t\tQString id = action.pAction->data().toString();\n\t\taction.pAction->setActionGroup(m_pActionGroupZoomScaleModes);\n\t\tm_pMenuZoomScaleModes->addAction(action.pAction);\n\t\tm_actionIDToZoomScaleModeMap[id] = action.scaleMode;\n\t\taddAction(action.pAction);\n\t\tif(scaleMode == action.scaleMode)\n\t\t\taction.pAction->setChecked(true);\n\t}\n\n\tbool noZoom = (zoomMode == ZoomMode::NoZoom);\n\tm_pMenuZoomScaleModes->setEnabled(!noZoom);\n\n//------------------------------------------------------------------------------\n\n\tm_pPreviewContextMenu->addAction(m_pActionToggleCropPanel);\n\tm_pPreviewContextMenu->addAction(m_pActionToggleTimeLinePanel);\n\tm_pActionToggleTimeLinePanel->setChecked(\n\t\tm_pSettingsManager->getTimeLinePanelVisible());\n\n//------------------------------------------------------------------------------\n\n\tm_pMenuTimeLineModes= new QMenu(m_pPreviewContextMenu);\n\tvsedit::disableFontKerning(m_pMenuTimeLineModes);\n\tm_pMenuTimeLineModes->setTitle(tr(\"Timeline display mode\"));\n\tm_pPreviewContextMenu->addMenu(m_pMenuTimeLineModes);\n\n\tm_pActionGroupTimeLineModes = new QActionGroup(this);\n\n\tTimeLineSlider::DisplayMode timeLineMode =\n\t\tm_pSettingsManager->getTimeLineMode();\n\n\tstruct TimeLineModeAction\n\t{\n\t\tQAction * pAction;\n\t\tTimeLineSlider::DisplayMode timeLineMode;\n\t};\n\n\tTimeLineModeAction timeLineModeAction[] =\n\t{\n\t\t{m_pActionSetTimeLineModeTime, TimeLineSlider::DisplayMode::Time},\n\t\t{m_pActionSetTimeLineModeFrames, TimeLineSlider::DisplayMode::Frames},\n\t};\n\n\tfor(TimeLineModeAction & action : timeLineModeAction)\n\t{\n\t\tQString id = action.pAction->data().toString();\n\t\taction.pAction->setActionGroup(m_pActionGroupTimeLineModes);\n\t\tm_pMenuTimeLineModes->addAction(action.pAction);\n\t\tm_actionIDToTimeLineModeMap[id] = action.timeLineMode;\n\t\taddAction(action.pAction);\n\t\tif(timeLineMode == action.timeLineMode)\n\t\t\taction.pAction->setChecked(true);\n\t}\n\n//------------------------------------------------------------------------------\n\n\taddAction(m_pActionTimeStepForward);\n\taddAction(m_pActionTimeStepBack);\n\n\tm_pActionToggleColorPicker->setChecked(\n\t\tm_pSettingsManager->getColorPickerVisible());\n\tm_pPreviewContextMenu->addAction(m_pActionToggleColorPicker);\n\n\tm_pActionPlay->setChecked(false);\n\taddAction(m_pActionPlay);\n\n\taddAction(m_pActionLoadChapters);\n\taddAction(m_pActionClearBookmarks);\n\taddAction(m_pActionBookmarkCurrentFrame);\n\taddAction(m_pActionUnbookmarkCurrentFrame);\n\taddAction(m_pActionGoToPreviousBookmark);\n\taddAction(m_pActionGoToNextBookmark);\n\n\taddAction(m_pActionPasteShownFrameNumberIntoScript);\n\tm_pPreviewContextMenu->addAction(m_pActionPasteShownFrameNumberIntoScript);\n\n\taddAction(m_pActionJumpToFrame);\n\taddAction(m_pActionToggleFramePropsPanel);\n//------------------------------------------------------------------------------\n\n\taddAction(m_pActionSwitchToOutputIndex0);\n\taddAction(m_pActionSwitchToOutputIndex1);\n\taddAction(m_pActionSwitchToOutputIndex2);\n\taddAction(m_pActionSwitchToOutputIndex3);\n\taddAction(m_pActionSwitchToOutputIndex4);\n\taddAction(m_pActionSwitchToOutputIndex5);\n\taddAction(m_pActionSwitchToOutputIndex6);\n\taddAction(m_pActionSwitchToOutputIndex7);\n\taddAction(m_pActionSwitchToOutputIndex8);\n\taddAction(m_pActionSwitchToOutputIndex9);\n\taddAction(m_pActionSwitchToOutputIndex10);\n\taddAction(m_pActionSwitchToOutputIndex11);\n\taddAction(m_pActionSwitchToOutputIndex12);\n\taddAction(m_pActionSwitchToOutputIndex13);\n\taddAction(m_pActionSwitchToOutputIndex14);\n\taddAction(m_pActionSwitchToOutputIndex15);\n\taddAction(m_pActionSwitchToOutputIndex16);\n\taddAction(m_pActionSwitchToOutputIndex17);\n\taddAction(m_pActionSwitchToOutputIndex18);\n\taddAction(m_pActionSwitchToOutputIndex19);\n\taddAction(m_pActionSwitchToPreviousOutputIndex);\n\taddAction(m_pActionSwitchToNextOutputIndex);\n\n//------------------------------------------------------------------------------\n\n\tfor(ActionToCreate & item : actionsToCreate)\n\t{\n\t\tconst char * signal =\n\t\t\titem.checkable ? SIGNAL(toggled(bool)) : SIGNAL(triggered());\n\t\tconnect(*item.ppAction, signal, this, item.slotToConnect);\n\t}\n}\n\n// END OF void PreviewDialog::createActionsAndMenus()\n//==============================================================================\n\nvoid PreviewDialog::setUpZoomPanel()\n{\n\tm_ui.zoomPanel->setVisible(m_pSettingsManager->getZoomPanelVisible());\n\n\tm_ui.zoomRatioSpinBox->setLocale(QLocale(\"C\"));\n\n\tm_ui.zoomCheckButton->setDefaultAction(m_pActionToggleZoomPanel);\n\n\tm_ui.zoomModeComboBox->addItem(QIcon(\":zoom_no_zoom.png\"),\n\t\ttr(\"No zoom\"), (int)ZoomMode::NoZoom);\n\tm_ui.zoomModeComboBox->addItem(QIcon(\":zoom_fixed_ratio.png\"),\n\t\ttr(\"Fixed ratio\"), (int)ZoomMode::FixedRatio);\n\tm_ui.zoomModeComboBox->addItem(QIcon(\":zoom_fit_to_frame.png\"),\n\t\ttr(\"Fit to frame\"), (int)ZoomMode::FitToFrame);\n\n\tZoomMode zoomMode = m_pSettingsManager->getZoomMode();\n\tint comboIndex = m_ui.zoomModeComboBox->findData((int)zoomMode);\n\tif(comboIndex != -1)\n\t\tm_ui.zoomModeComboBox->setCurrentIndex(comboIndex);\n\tbool fixedRatio(zoomMode == ZoomMode::FixedRatio);\n\tm_ui.zoomRatioSpinBox->setEnabled(fixedRatio);\n\n\tdouble zoomRatio = m_pSettingsManager->getZoomRatio();\n\tm_ui.zoomRatioSpinBox->setValue(zoomRatio);\n\n\tm_ui.scaleModeComboBox->addItem(tr(\"Nearest\"),\n\t\t(int)Qt::FastTransformation);\n\tm_ui.scaleModeComboBox->addItem(tr(\"Bilinear\"),\n\t\t(int)Qt::SmoothTransformation);\n\tbool noZoom = (zoomMode == ZoomMode::NoZoom);\n\tm_ui.scaleModeComboBox->setEnabled(!noZoom);\n\n\tQt::TransformationMode scaleMode = m_pSettingsManager->getScaleMode();\n\tm_ui.zoomRatioSpinBox->setScaleMode(scaleMode);\n\tcomboIndex = m_ui.scaleModeComboBox->findData((int)scaleMode);\n\tif(comboIndex != -1)\n\t\tm_ui.scaleModeComboBox->setCurrentIndex(comboIndex);\n\n\tconnect(m_ui.zoomModeComboBox, SIGNAL(currentIndexChanged(int)),\n\t\tthis, SLOT(slotZoomModeChanged()));\n\tconnect(m_ui.zoomRatioSpinBox, SIGNAL(valueChanged(double)),\n\t\tthis, SLOT(slotZoomRatioChanged(double)));\n\tconnect(m_ui.scaleModeComboBox, SIGNAL(currentIndexChanged(int)),\n\t\tthis, SLOT(slotScaleModeChanged()));\n}\n\n// END OF void PreviewDialog::setUpZoomPanel()\n//==============================================================================\n\nvoid PreviewDialog::setUpTimeLinePanel()\n{\n\tm_ui.timeLinePanel->setVisible(\n\t\tm_pSettingsManager->getTimeLinePanelVisible());\n\n    m_ui.playButton->setDefaultAction(m_pActionPlay);\n    m_ui.timeLineCheckButton->setDefaultAction(m_pActionToggleTimeLinePanel);\n    m_ui.timeStepForwardButton->setDefaultAction(m_pActionTimeStepForward);\n    m_ui.timeStepBackButton->setDefaultAction(m_pActionTimeStepBack);\n\n    m_ui.playFpsLimitModeComboBox->addItem(tr(\"From script\"),\n\t\t(int)PlayFPSLimitMode::FromVideo);\n    m_ui.playFpsLimitModeComboBox->addItem(tr(\"No limit\"),\n\t\t(int)PlayFPSLimitMode::NoLimit);\n    m_ui.playFpsLimitModeComboBox->addItem(tr(\"Custom\"),\n\t\t(int)PlayFPSLimitMode::Custom);\n\n\tPlayFPSLimitMode playFpsLimitMode =\n\t\tm_pSettingsManager->getPlayFPSLimitMode();\n\tint comboIndex = m_ui.playFpsLimitModeComboBox->findData(\n\t\t(int)playFpsLimitMode);\n\tif(comboIndex != -1)\n\t\tm_ui.playFpsLimitModeComboBox->setCurrentIndex(comboIndex);\n\n\tm_ui.playFpsLimitSpinBox->setLocale(QLocale(\"C\"));\n\tdouble customFPS = m_pSettingsManager->getPlayFPSLimit();\n\tm_ui.playFpsLimitSpinBox->setValue(customFPS);\n\n\tslotSetPlayFPSLimit();\n\n\tm_ui.loadChaptersButton->setDefaultAction(m_pActionLoadChapters);\n\tm_ui.clearBookmarksButton->setDefaultAction(m_pActionClearBookmarks);\n\tm_ui.bookmarkCurrentFrameButton->setDefaultAction(\n\t\tm_pActionBookmarkCurrentFrame);\n\tm_ui.unbookmarkCurrentFrameButton->setDefaultAction(\n\t\tm_pActionUnbookmarkCurrentFrame);\n\tm_ui.goToPreviousBookmarkButton->setDefaultAction(\n\t\tm_pActionGoToPreviousBookmark);\n\tm_ui.goToNextBookmarkButton->setDefaultAction(\n\t\tm_pActionGoToNextBookmark);\n\n    double timeStep = m_pSettingsManager->getTimeStep();\n    m_ui.timeStepEdit->setTime(vsedit::secondsToQTime(timeStep));\n\n    m_ui.timeLineModeComboBox->addItem(QIcon(\":timeline.png\"), tr(\"Time\"),\n\t\t(int)TimeLineSlider::DisplayMode::Time);\n    m_ui.timeLineModeComboBox->addItem(QIcon(\":timeline_frames.png\"),\n\t\ttr(\"Frames\"), (int)TimeLineSlider::DisplayMode::Frames);\n\n\tTimeLineSlider::DisplayMode timeLineMode =\n\t\tm_pSettingsManager->getTimeLineMode();\n\tcomboIndex = m_ui.timeLineModeComboBox->findData((int)timeLineMode);\n\tif(comboIndex != -1)\n\t\tm_ui.timeLineModeComboBox->setCurrentIndex(comboIndex);\n\n\tconnect(m_ui.timeStepEdit, SIGNAL(timeChanged(const QTime &)),\n\t\tthis, SLOT(slotTimeStepChanged(const QTime &)));\n\tconnect(m_ui.timeLineModeComboBox, SIGNAL(currentIndexChanged(int)),\n\t\tthis, SLOT(slotTimeLineModeChanged()));\n\tconnect(m_ui.playFpsLimitModeComboBox, SIGNAL(currentIndexChanged(int)),\n\t\tthis, SLOT(slotSetPlayFPSLimit()));\n\tconnect(m_ui.playFpsLimitSpinBox, SIGNAL(valueChanged(double)),\n\t\tthis, SLOT(slotSetPlayFPSLimit()));\n}\n\n// END OF void PreviewDialog::setUpTimeLinePanel()\n//==============================================================================\n\nvoid PreviewDialog::setUpCropPanel()\n{\n\tm_ui.cropCheckButton->setDefaultAction(m_pActionToggleCropPanel);\n\n\tm_ui.cropModeComboBox->addItem(tr(\"Absolute\"), (int)CropMode::Absolute);\n\tm_ui.cropModeComboBox->addItem(tr(\"Relative\"), (int)CropMode::Relative);\n\tCropMode cropMode = m_pSettingsManager->getCropMode();\n\tint cropModeIndex = m_ui.cropModeComboBox->findData((int)cropMode);\n\tm_ui.cropModeComboBox->setCurrentIndex(cropModeIndex);\n\tslotCropModeChanged();\n\n\tm_ui.cropZoomRatioSpinBox->setValue(m_pSettingsManager->getCropZoomRatio());\n\tm_ui.cropPasteToScriptButton->setDefaultAction(\n\t\tm_pActionPasteCropSnippetIntoScript);\n\tm_ui.cropPanel->setVisible(false);\n\n\tconnect(m_ui.cropModeComboBox, SIGNAL(currentIndexChanged(int)),\n\t\tthis, SLOT(slotCropModeChanged()));\n\tconnect(m_ui.cropLeftSpinBox, SIGNAL(valueChanged(int)),\n\t\tthis, SLOT(slotCropLeftValueChanged(int)));\n\tconnect(m_ui.cropTopSpinBox, SIGNAL(valueChanged(int)),\n\t\tthis, SLOT(slotCropTopValueChanged(int)));\n\tconnect(m_ui.cropWidthSpinBox, SIGNAL(valueChanged(int)),\n\t\tthis, SLOT(slotCropWidthValueChanged(int)));\n\tconnect(m_ui.cropHeightSpinBox, SIGNAL(valueChanged(int)),\n\t\tthis, SLOT(slotCropHeightValueChanged(int)));\n\tconnect(m_ui.cropRightSpinBox, SIGNAL(valueChanged(int)),\n\t\tthis, SLOT(slotCropRightValueChanged(int)));\n\tconnect(m_ui.cropBottomSpinBox, SIGNAL(valueChanged(int)),\n\t\tthis, SLOT(slotCropBottomValueChanged(int)));\n\tconnect(m_ui.cropZoomRatioSpinBox, SIGNAL(valueChanged(int)),\n\t\tthis, SLOT(slotCropZoomRatioValueChanged(int)));\n}\n\n// END OF void PreviewDialog::setUpCropPanel()\n//==============================================================================\n\nbool PreviewDialog::requestShowFrame(int a_frameNumber)\n{\n\tif(!m_pVapourSynthScriptProcessor->isInitialized())\n\t\treturn false;\n\n\tif((m_frameShown != -1) && (m_frameShown != m_frameExpected))\n\t\treturn false;\n\n\tm_pVapourSynthScriptProcessor->requestFrameAsync(a_frameNumber,\n\t\tm_outputIndex, true);\n\treturn true;\n}\n\n// END OF bool PreviewDialog::requestShowFrame(int a_frameNumber)\n//==============================================================================\n\nvoid PreviewDialog::setPreviewPixmap()\n{\n\tm_devicePixelRatio = window()->devicePixelRatioF();\n\tif(!m_framePixmap.isNull())\n\t\tm_framePixmap.setDevicePixelRatio(m_devicePixelRatio);\n\tif(m_ui.cropPanel->isVisible())\n\t{\n\t\tint cropLeft = m_ui.cropLeftSpinBox->value();\n\t\tint cropTop = m_ui.cropTopSpinBox->value();\n\t\tint cropWidth = m_ui.cropWidthSpinBox->value();\n\t\tint cropHeight = m_ui.cropHeightSpinBox->value();\n\t\tQPixmap croppedPixmap = m_framePixmap.copy(cropLeft, cropTop,\n\t\t\tcropWidth, cropHeight);\n\t\tint ratio = m_ui.cropZoomRatioSpinBox->value();\n\n\t\tif(abs(ratio * m_devicePixelRatio - 1) < 1e-7)\n\t\t{\n\t\t\tm_ui.previewArea->setPixmap(croppedPixmap);\n\t\t\treturn;\n\t\t}\n\n\t\tQPixmap zoomedPixmap = croppedPixmap.scaled(\n\t\t\tcroppedPixmap.width() * ratio, croppedPixmap.height() * ratio,\n\t\t\tQt::KeepAspectRatio, Qt::FastTransformation);\n\t\tm_ui.previewArea->setPixmap(zoomedPixmap);\n\t\treturn;\n\t}\n\n\tZoomMode zoomMode = (ZoomMode)m_ui.zoomModeComboBox->currentData().toInt();\n\tif(zoomMode == ZoomMode::NoZoom)\n\t{\n\t\tm_ui.previewArea->setPixmap(m_framePixmap, true);\n\t\treturn;\n\t}\n\n\tQPixmap previewPixmap;\n\tint frameWidth = 0;\n\tint frameHeight = 0;\n\tQt::TransformationMode scaleMode = (Qt::TransformationMode)\n\t\tm_ui.scaleModeComboBox->currentData().toInt();\n\n\tif(zoomMode == ZoomMode::FixedRatio)\n\t{\n\t\tdouble ratio = m_ui.zoomRatioSpinBox->value();\n\t\tframeWidth = m_framePixmap.width() * ratio;\n\t\tframeHeight = m_framePixmap.height() * ratio;\n\t}\n\telse\n\t{\n\t\tif(m_framePixmap.isNull())\n\t\t\treturn;\n\t\tQRect previewRect = m_ui.previewArea->geometry();\n\t\tint cropSize = m_ui.previewArea->frameWidth() * 2;\n\t\tframeWidth = previewRect.width() * m_devicePixelRatio - cropSize;\n\t\tframeHeight = previewRect.height() * m_devicePixelRatio - cropSize;\n\t}\n\n\tpreviewPixmap = m_framePixmap.scaled(frameWidth, frameHeight,\n\t\tQt::KeepAspectRatio, scaleMode);\n\n\tm_ui.previewArea->setPixmap(previewPixmap, true);\n}\n\n// END OF bool void PreviewDialog::setPreviewPixmap()\n//==============================================================================\n\nvoid PreviewDialog::recalculateCropMods()\n{\n\tQSpinBox * cropSpinBoxes[] = {m_ui.cropLeftSpinBox, m_ui.cropTopSpinBox,\n\t\tm_ui.cropWidthSpinBox, m_ui.cropHeightSpinBox, m_ui.cropRightSpinBox,\n\t\tm_ui.cropBottomSpinBox};\n\n\tfor(QSpinBox * pSpinBox : cropSpinBoxes)\n\t{\n\t\tint value = pSpinBox->value();\n\t\tif(value == 0)\n\t\t\tpSpinBox->setSuffix(\"\");\n\t\telse\n\t\t{\n\t\t\tint sizeMod = vsedit::mod(value);\n\t\t\tpSpinBox->setSuffix(QString(\" |%1|\").arg(sizeMod));\n\t\t}\n\t}\n}\n\n// END OF void PreviewDialog::recalculateCropMods()\n//==============================================================================\n\nvoid PreviewDialog::resetCropSpinBoxes()\n{\n\tBEGIN_CROP_VALUES_CHANGE\n\n\tconst VSVideoInfo * vi = m_nodeInfo[m_outputIndex].getAsVideo();\n\tif(!vi)\n\t{\n\t\tEND_CROP_VALUES_CHANGE\n\t\treturn;\n\t}\n\n\tm_ui.cropLeftSpinBox->setMaximum(vi->width - 1);\n\tm_ui.cropLeftSpinBox->setValue(0);\n\tm_ui.cropTopSpinBox->setMaximum(vi->height - 1);\n\tm_ui.cropTopSpinBox->setValue(0);\n\n\tm_ui.cropWidthSpinBox->setMaximum(vi->width);\n\tm_ui.cropWidthSpinBox->setValue(vi->width);\n\tm_ui.cropHeightSpinBox->setMaximum(vi->height);\n\tm_ui.cropHeightSpinBox->setValue(vi->height);\n\n\tm_ui.cropRightSpinBox->setMaximum(vi->width - 1);\n\tm_ui.cropRightSpinBox->setValue(0);\n\tm_ui.cropBottomSpinBox->setMaximum(vi->height - 1);\n\tm_ui.cropBottomSpinBox->setValue(0);\n\n\trecalculateCropMods();\n\n\tEND_CROP_VALUES_CHANGE\n}\n\n// END OF void PreviewDialog::resetCropSpinBoxes()\n//==============================================================================\n\nvoid PreviewDialog::setCurrentFrame(const VSFrame * a_cpOutputFrame,\n\tconst VSFrame * a_cpPreviewFrame)\n{\n\tQ_ASSERT(m_cpVSAPI);\n\tm_cpVSAPI->freeFrame(m_cpFrame);\n\tm_cpFrame = a_cpOutputFrame;\n\t// Copy clip and scene names\n\tconst VSMap *props = m_cpVSAPI->getFramePropertiesRO(m_cpFrame);\n\tint err;\n\tbool toChangeTitle = m_toChangeTitle;\n\tconst char * clipName = m_cpVSAPI->mapGetData(\n\t\tprops, \"Name\", 0, &err);\n\tif(m_clipName != clipName) // can be nullptr?\n\t{\n\t\tm_clipName = QString(clipName ? clipName : \"\");\n\t\ttoChangeTitle = true;\n\t}\n\tconst char * sceneName = m_cpVSAPI->mapGetData(\n\t\tprops, \"SceneName\", 0, &err);\n\tif(m_sceneName != sceneName)\n\t{\n\t\tm_sceneName = QString(sceneName ? sceneName : \"\");\n\t\ttoChangeTitle = true;\n\t}\n\tdouble absoluteTime = m_cpVSAPI->mapGetFloat(\n\t\tprops, \"_AbsoluteTime\", 0, &err);\n\tif(!err)\n\t{\n\t\tQString absTimeStr = vsedit::timeToString(absoluteTime);\n\t\tif(m_absoluteTime != absTimeStr)\n\t\t{\n\t\t\tm_absoluteTime = absTimeStr;\n\t\t\ttoChangeTitle = true;\n\t\t}\n\t}\n\telse\n\t{\n\t\tif(!m_absoluteTime.isEmpty())\n\t\t\tm_toChangeTitle = true;\n\t\tm_absoluteTime = \"\";\n\t}\n\tif(toChangeTitle)\n\t{\n\t\tm_toChangeTitle = false;\n\t\tsetTitle();\n\t}\n\tif (m_cpPreviewFrame)\n\t{\n\t\tm_cpVSAPI->freeFrame(m_cpPreviewFrame);\n\t\tm_cpPreviewFrame = nullptr;\n\t}\n\tm_framePixmap = pixmapFromRGB(a_cpPreviewFrame);\n\tm_cpPreviewFrame = a_cpPreviewFrame;\n\tsetPreviewPixmap();\n\tQPointF pixelPos = m_ui.previewArea->pixelPosition();\n\tm_ui.previewArea->checkMouseOverPreview(pixelPos);\n\tupdateFrameProps(false);\n}\n\n// END OF void PreviewDialog::setCurrentFrame(\n//\t\tconst VSFrame * a_cpOutputFrame,\n//\t\tconst VSFrame * a_cpPreviewFrame)\n//==============================================================================\n\nvoid PreviewDialog::updateFrameProps(bool a_forced)\n{\n\tif(a_forced || (isVisible() && m_cpFrame))\n\t{\n\t\tQString props = m_pVapourSynthScriptProcessor->\n\t\t\tframePropsString(m_cpFrame);\n\t\tQString info = QString(\"Index %1 | Frame %2 \\n\\n\")\n\t\t\t.arg(m_outputIndex).arg(m_frameExpected);\n\t\tm_pFramePropsPanel->setText(info + props + QString(\"\\n\"));\n\t}\n}\n\n// END OF void PreviewDialog::updateFrameProps(bool a_forced)\n//==============================================================================\n\ndouble PreviewDialog::valueAtPoint(size_t a_x, size_t a_y, int a_plane)\n{\n\tQ_ASSERT(m_cpVSAPI);\n\n\tif(!m_cpFrame)\n\t\treturn 0.0;\n\n\tconst VSVideoFormat * cpFormat = m_cpVSAPI->getVideoFrameFormat(m_cpFrame);\n\n\tQ_ASSERT((a_plane >= 0) && (a_plane < cpFormat->numPlanes));\n\n    const uint8_t * cpPlane =\n\t\tm_cpVSAPI->getReadPtr(m_cpFrame, a_plane);\n\n\tsize_t x = a_x;\n\tsize_t y = a_y;\n\n\tif(a_plane != 0)\n\t{\n\t\tx = (a_x >> cpFormat->subSamplingW);\n\t\ty = (a_y >> cpFormat->subSamplingH);\n\t}\n\tint stride = m_cpVSAPI->getStride(m_cpFrame, a_plane);\n\tconst uint8_t * cpLine = cpPlane + y * stride;\n\n\tdouble value = 0.0;\n\n\tif(cpFormat->sampleType == stInteger)\n\t{\n\t\tif(cpFormat->bytesPerSample == 1)\n\t\t\tvalue = (double)cpLine[x];\n\t\telse if(cpFormat->bytesPerSample == 2)\n\t\t\tvalue = (double)((uint16_t *)cpLine)[x];\n\t\telse if(cpFormat->bytesPerSample == 4)\n\t\t\tvalue = (double)((uint32_t *)cpLine)[x];\n\t}\n\telse if(cpFormat->sampleType == stFloat)\n\t{\n\t\tif(cpFormat->bytesPerSample == 2)\n\t\t{\n\t\t\tvsedit::FP16 half;\n\t\t\thalf.u = ((uint16_t *)cpLine)[x];\n\t\t\tvsedit::FP32 single = vsedit::halfToSingle(half);\n\t\t\tvalue = (double)single.f;\n\t\t}\n\t\telse if(cpFormat->bytesPerSample == 4)\n\t\t\tvalue = (double)((float *)cpLine)[x];\n\t}\n\n\treturn value;\n}\n\n// END OF double PreviewDialog::valueAtPoint(size_t a_x, size_t a_y,\n//\t\tint a_plane)\n//==============================================================================\n\nvoid PreviewDialog::previewValueAtPoint(size_t a_x, size_t a_y, int a_ret[])\n{\n\t// Read RGB values on screen from packed Gray8\n\n\tif(!m_cpPreviewFrame)\n\t\treturn;\n\n\tconst VSMap *props = m_cpVSAPI->getFramePropertiesRO(m_cpPreviewFrame);\n\tenum p2p_packing packing_fmt =\n\t\tstatic_cast<p2p_packing>(m_cpVSAPI->mapGetInt(props, \"PackingFormat\",\n\t\t0, nullptr));\n\tbool is_10_bits = (packing_fmt == p2p_rgb30);\n\tif (!is_10_bits)\n\t{\n\t\tQ_ASSERT(packing_fmt == p2p_argb32);\n\t}\n\n    const uint8_t * cpPlane = m_cpVSAPI->getReadPtr(m_cpPreviewFrame, 0);\n\n\tsize_t x = a_x;\n\tsize_t y = a_y;\n\n\tint stride = m_cpVSAPI->getStride(m_cpPreviewFrame, 0);\n\tconst uint8_t * cpLoc = cpPlane + y * stride + x * 4;\n\n\t// libp2p will handle endianness\n\tp2p_buffer_param p = {};\n\tp.width = 1;\n\tp.height = 1;\n\tp.packing = packing_fmt;\n\tp.src[0] = cpLoc;\n\tp.src_stride[0] = 1;\n\tif (is_10_bits)\n\t{\n\t\tuint16_t unpacked[3];\n\t\tfor (int plane = 0; plane < 3; ++plane)\n\t\t{\n\t\t\tp.dst[plane] = &unpacked[plane];\n\t\t\tp.dst_stride[plane] = 1;\n\t\t}\n\t\tp2p_unpack_frame(&p, 0);\n\t\tfor (int plane = 0; plane < 3; ++plane)\n\t\t{\n\t\t\ta_ret[plane] = static_cast<int>(unpacked[plane]);\n\t\t}\n\t}\n\telse\n\t{\n\t\tuint8_t unpacked[3];\n\t\tfor (int plane = 0; plane < 3; ++plane)\n\t\t{\n\t\t\tp.dst[plane] = &unpacked[plane];\n\t\t\tp.dst_stride[plane] = 1;\n\t\t}\n\t\tp2p_unpack_frame(&p, 0);\n\t\tfor (int plane = 0; plane < 3; ++plane)\n\t\t{\n\t\t\ta_ret[plane] = static_cast<int>(unpacked[plane]);\n\t\t}\n\t}\n}\n\n// END OF void PreviewDialog::previewValueAtPoint(size_t a_x, size_t a_y,\n//\t\tint a_ret[])\n//==============================================================================\n\nQPixmap PreviewDialog::pixmapFromRGB(\n\tconst VSFrame * a_cpFrame)\n{\n\tif((!m_cpVSAPI) || (!a_cpFrame))\n\t\treturn QPixmap();\n\n\tconst VSVideoFormat * cpFormat = m_cpVSAPI->getVideoFrameFormat(a_cpFrame);\n\tQ_ASSERT(cpFormat);\n\tint wwidth = m_cpVSAPI->getFrameWidth(a_cpFrame, 0);\n\n\tif((cpFormat->colorFamily != cfGray)\n\t\t|| (cpFormat->bitsPerSample != 8)\n\t\t|| (wwidth % 4))\n\t{\n\t\tQString errorString = tr(\"Error forming pixmap from frame. \"\n\t\t\t\"Expected format Gray8 with width divisible by 4. \");\n\t\temit signalWriteLogMessage(mtCritical, errorString);\n\t\treturn QPixmap();\n\t}\n\n\tconst VSMap *props = m_cpVSAPI->getFramePropertiesRO(a_cpFrame);\n\tenum p2p_packing packing_fmt = static_cast<p2p_packing>(\n\t\tm_cpVSAPI->mapGetInt(props, \"PackingFormat\", 0, nullptr));\n\tbool is_10_bits;\n\tif (packing_fmt == p2p_rgb30)\n\t{\n\t\tis_10_bits = true;\n\t}\n\telse if (packing_fmt == p2p_argb32)\n\t{\n\t\tis_10_bits = false;\n\t}\n\telse\n\t{\n\t\tQString errorString = tr(\"Error forming pixmap from frame. \"\n\t\t\t\"Expected frame being packed from RGB24 or RGB30.\");\n\t\temit signalWriteLogMessage(mtCritical, errorString);\n\t\treturn QPixmap();\n\t}\n\n\tint width = wwidth / 4;\n\tint height = m_cpVSAPI->getFrameHeight(a_cpFrame, 0);\n\tint stride = m_cpVSAPI->getStride(a_cpFrame, 0);\n\n\tconst uint8_t * pData = m_cpVSAPI->getReadPtr(a_cpFrame, 0);\n\tQImage frameImage(reinterpret_cast<const uchar *>(pData),\n\t\twidth, height, stride, is_10_bits ?\n\t\tQImage::Format_RGB30 : QImage::Format_ARGB32);\n\tQPixmap framePixmap = QPixmap::fromImage(frameImage, Qt::NoFormatConversion);\n\treturn framePixmap;\n}\n\n// END OF QPixmap PreviewDialog::pixmapFromRGB(\n//\t\tconst VSFrame * a_cpFrame)\n//==============================================================================\n\nvoid PreviewDialog::setTitle()\n{\n\tQString l_scriptName = scriptName();\n\tQString scriptNameTitle =\n\t\tl_scriptName.isEmpty() ? tr(\"(Untitled)\") : l_scriptName;\n\tif(m_scriptTextChanged)\n\t\tscriptNameTitle = scriptNameTitle + \"*\";\n\tQString title = tr(\"Preview - Index %1 | \").arg(m_outputIndex);\n\tif(!m_clipName.isEmpty())\n\t\ttitle = title + tr(\"Name: %1 | \").arg(m_clipName);\n\tif(!m_sceneName.isEmpty())\n\t\ttitle = title + tr(\"Scene: %1 | \").arg(m_sceneName);\n\tif(!m_absoluteTime.isEmpty())\n\t\ttitle = title + tr(\"Abs Time: %1 | \").arg(m_absoluteTime);\n\ttitle = title + scriptNameTitle;\n\tsetWindowTitle(title);\n}\n\n// END OF void PreviewDialog::setTitle()\n//==============================================================================\n\nqlonglong PreviewDialog::frameToTimestamp(int a_frame)\n{\n\tif(m_fpsDen == 0 || m_fpsNum == 0)\n\t\treturn 0;\n\treturn a_frame * m_fpsDen * 1000 / m_fpsNum;\n}\n\nint PreviewDialog::timestampToFrame(qlonglong a_timestamp)\n{\n\tif(m_fpsDen == 0 || m_fpsNum == 0)\n\t\treturn 0;\n\treturn std::round((double)a_timestamp * m_fpsNum / m_fpsDen / 1000);\n}\n\nvoid PreviewDialog::setExpectedFrame(int a_frame)\n{\n\tm_frameExpected = a_frame;\n\tm_frameTimestampExpected = frameToTimestamp(m_frameExpected);\n}\n\nvoid PreviewDialog::saveTimelineBookmarks()\n{\n\tQString l_scriptName = scriptName();\n\tif(l_scriptName.isEmpty())\n\t\treturn;\n\n\tQString bookmarksFilePath = l_scriptName +\n\t\tQString(TIMELINE_BOOKMARKS_FILE_SUFFIX);\n\tQFile bookmarksFile(bookmarksFilePath);\n\tif(!bookmarksFile.open(QIODevice::WriteOnly))\n\t\treturn;\n\n\tstd::set<int> bookmarks = m_ui.frameNumberSlider->bookmarks();\n\tQStringList bookmarksStringList;\n\tfor(int i : bookmarks)\n\t\tbookmarksStringList += QString::number(i);\n\n\tQString bookmarksString = bookmarksStringList.join(\", \");\n\tbookmarksFile.write(bookmarksString.toUtf8());\n\tbookmarksFile.close();\n}\n\n// END OF void PreviewDialog::saveTimelineBookmarks()\n//==============================================================================\n\nvoid PreviewDialog::loadTimelineBookmarks()\n{\n\tstd::set<int> bookmarks;\n\n\tQString l_scriptName = scriptName();\n\tif(l_scriptName.isEmpty())\n\t{\n\t\tm_ui.frameNumberSlider->setBookmarks(bookmarks);\n\t\treturn;\n\t}\n\n\tQString bookmarksFilePath = l_scriptName +\n\t\tQString(TIMELINE_BOOKMARKS_FILE_SUFFIX);\n\tQFile bookmarksFile(bookmarksFilePath);\n\tif(!bookmarksFile.open(QIODevice::ReadOnly))\n\t{\n\t\tm_ui.frameNumberSlider->setBookmarks(bookmarks);\n\t\treturn;\n\t}\n\n\tQString bookmarksString = tr(bookmarksFile.readAll().data());\n\tbookmarksFile.close();\n\n\tQStringList bookmarksStringList = bookmarksString.split(\",\");\n\tfor(const QString & string : bookmarksStringList)\n\t{\n\t\tbool converted = false;\n\t\tint i = string.simplified().toInt(&converted);\n\t\tif(converted)\n\t\t\tbookmarks.insert(i);\n\t}\n\n\tm_ui.frameNumberSlider->setBookmarks(bookmarks);\n}\n\n// END OF void PreviewDialog::loadTimelineBookmarks()\n//==============================================================================\n\nvoid PreviewDialog::saveGeometryDelayed()\n{\n\tQApplication::processEvents();\n\tif(!isMaximized())\n\t{\n\t\tm_windowGeometry = saveGeometry();\n\t\tm_pGeometrySaveTimer->start();\n\t}\n}\n\n// END OF void PreviewDialog::saveGeometryDelayed()\n//==============================================================================\n\nFramePropsPanel::FramePropsPanel(SettingsManager * a_pSettingsManager,\n\tPreviewDialog * a_pFakeParent)\n{\n\tm_pFakeParent = a_pFakeParent;\n\n\tsetWindowModality(Qt::NonModal);\n\tsetWindowTitle(QString(\"Frame Properties\"));\n\tQFont font = a_pSettingsManager->\n\t\tgetTextFormat(TEXT_FORMAT_ID_COMMON_SCRIPT_TEXT).font();\n\tsetFont(font);\n\tvsedit::disableFontKerning(this);\n\tsetAlignment(Qt::AlignmentFlag::AlignTop);\n\tsetTextInteractionFlags(Qt::TextSelectableByMouse);\n\tsetCursor(QCursor(Qt::IBeamCursor));\n\n\tsetVisible(false);\n\n\tsetHideAction(a_pSettingsManager);\t\n}\n\nvoid FramePropsPanel::keyPressEvent(QKeyEvent * a_pEvent)\n{\n\tif(a_pEvent->modifiers() != Qt::NoModifier)\n\t\tQTextEdit::keyPressEvent(a_pEvent);\n\telse if(a_pEvent->key() == Qt::Key_Escape)\n\t\tsetVisible(false);\n\telse\n\t\tm_pFakeParent->keyPressEvent(a_pEvent);\n}\n\nvoid FramePropsPanel::setHideAction(SettingsManager * a_pSettingsManager)\n{\n\tm_pActionHide = a_pSettingsManager->createStandardAction(\n\t\tACTION_ID_TOGGLE_FRAME_PROPS, this);\n\tm_pActionHide->setCheckable(false);\n\tQKeySequence hotkey = a_pSettingsManager->\n\t\tgetHotkey(m_pActionHide->data().toString());\n\tm_pActionHide->setShortcut(hotkey);\n\tconnect(m_pActionHide, SIGNAL(triggered()), this, SLOT(slotHide()));\n\taddAction(m_pActionHide);\n}\n\nvoid FramePropsPanel::setVisible(bool visible)\n{\n\tif(visible)\n\t\tresize(m_widgetWidth, m_widgetHeight);\n\telse\n\t{\n\t\tm_widgetWidth = width();\n\t\tm_widgetHeight = height();\n\t}\n\tQWidget::setVisible(visible);\n}\n"
  },
  {
    "path": "vsedit/src/preview/preview_dialog.h",
    "content": "#ifndef PREVIEWDIALOG_H_INCLUDED\n#define PREVIEWDIALOG_H_INCLUDED\n\n#include <ui_preview_dialog.h>\n\n#include \"../vapoursynth/vs_script_processor_dialog.h\"\n#include \"../../../common-src/settings/settings_definitions.h\"\n#include \"../../../common-src/chrono.h\"\n\n#include <QPixmap>\n#include <QTextEdit>\n#include <QIcon>\n#ifdef Q_OS_WIN // AUDIO\n#include <QAudioSink>\n#include <QIODevice>\n#endif\n#include <map>\n#include <vector>\n#include <chrono>\n\nclass QEvent;\nclass QMoveEvent;\nclass QResizeEvent;\nclass QKeyEvent;\nclass QMenu;\nclass QActionGroup;\nclass QAction;\nclass QTimer;\nclass SettingsManager;\nclass SettingsDialog;\nclass PreviewAdvancedSettingsDialog;\nclass VSNodeInfo;\nclass FramePropsPanel;\n\nextern const char TIMELINE_BOOKMARKS_FILE_SUFFIX[];\n\nclass PreviewDialog : public VSScriptProcessorDialog\n{\n\tQ_OBJECT\n\n#ifdef Q_OS_WIN // AUDIO\n\tstruct AudioFrame\n\t{\n\t\tint number;\n\t\tint outputIndex;\n\t\tQByteArray data;\n\n\t\tAudioFrame();\n\t\tAudioFrame(int a_number, int a_outputIndex, QByteArray a_data);\n\t\tbool valid() const { return !!data.size(); }\n\t\tbool operator==(const AudioFrame & a_other) const;\n\t};\n#endif\n\npublic:\n\n\tPreviewDialog(SettingsManager * a_pSettingsManager,\n\t\tVSScriptLibrary * a_pVSScriptLibrary, bool a_inPreviewer = false,\n\t\tQWidget * a_pParent = nullptr);\n\tvirtual ~PreviewDialog();\n\n\tvirtual void setScriptName(const QString & a_scriptName) override;\n\n\tvoid previewScript(const QString& a_script,\n\t\tconst QString& a_scriptName);\n\n\tbool busy() const\n\t{\n\t\treturn VSScriptProcessorDialog::busy(m_outputIndex);\n\t}\n\nsignals:\n\n\tvoid signalPasteIntoScriptAtNewLine(const QString& a_line);\n\tvoid signalPasteIntoScriptAtCursor(const QString& a_line);\n\npublic slots:\n\n\tvoid slotScriptTextChanged();\n\nprotected slots:\n\n\tvirtual void slotReceiveFrame(int a_frameNumber, int a_outputIndex,\n\t\tconst VSFrame * a_cpOutputFrame,\n\t\tconst VSFrame * a_cpPreviewFrame) override;\n\n\tvirtual void slotFrameRequestDiscarded(int a_frameNumber,\n\t\tint a_outputIndex, const QString & a_reason) override;\n\n\tvoid slotShowFrame(int a_frameNumber, bool a_refreshCache = true);\n\n\tvoid slotSaveSnapshot();\n\n\tvoid slotToggleZoomPanelVisible(bool a_zoomPanelVisible);\n\n\tvoid slotZoomModeChanged();\n\n\tvoid slotZoomRatioChanged(double a_zoomRatio);\n\n\tvoid slotScaleModeChanged();\n\n\tvoid slotToggleCropPanelVisible(bool a_cropPanelVisible);\n\n\tvoid slotCropModeChanged();\n\n\tvoid slotCropLeftValueChanged(int a_value);\n\n\tvoid slotCropTopValueChanged(int a_value);\n\n\tvoid slotCropWidthValueChanged(int a_value);\n\n\tvoid slotCropHeightValueChanged(int a_value);\n\n\tvoid slotCropRightValueChanged(int a_value);\n\n\tvoid slotCropBottomValueChanged(int a_value);\n\n\tvoid slotCropZoomRatioValueChanged(int a_cropZoomRatio);\n\n\tvoid slotPasteCropSnippetIntoScript();\n\n\tvoid slotCallAdvancedSettingsDialog();\n\n\tvoid slotToggleTimeLinePanelVisible(bool a_timeLinePanelVisible);\n\n\tvoid slotTimeLineModeChanged();\n\n\tvoid slotTimeStepChanged(const QTime & a_time);\n\n\tvoid slotTimeStepForward();\n\n\tvoid slotTimeStepBack();\n\n\tvoid slotSettingsChanged();\n\n\tvoid slotPreviewAreaSizeChanged();\n\n\tvoid slotPreviewAreaCtrlWheel(QPoint a_angleDelta);\n\n\tvoid slotPreviewAreaMouseMiddleButtonReleased();\n\n\tvoid slotPreviewAreaMouseRightButtonReleased();\n\n\tvoid slotPreviewAreaMouseOverPoint(double a_pX, double a_pY);\n\n\tvoid slotFrameToClipboard();\n\n\tvoid slotAdvancedSettingsChanged();\n\n\tvoid slotToggleColorPicker(bool a_colorPickerVisible);\n\n\tvoid slotSetPlayFPSLimit();\n\n\tvoid slotPlay(bool a_play);\n\n\tvoid slotProcessPlayQueue();\n#ifdef Q_OS_WIN // AUDIO\n\tvoid slotProcessAudioPlayQueue();\n#endif\n\n\tvoid slotLoadChapters();\n\tvoid slotClearBookmarks();\n\tvoid slotBookmarkCurrentFrame();\n\tvoid slotUnbookmarkCurrentFrame();\n\tvoid slotGoToPreviousBookmark();\n\tvoid slotGoToNextBookmark();\n\n\tvoid slotPasteShownFrameNumberIntoScript();\n\n\tvoid slotSaveGeometry();\n\n\tvoid slotJumpToFrame();\n\n\tvoid slotToggleFrameProps();\n\n\tvoid slotSwitchOutputIndex(int a_outputIndex);\n\n\tvoid slotEnableSwitchOutputIndex(bool a_idle);\n\n\tvoid setOutputIndex(int a_index);\n\n#define SLOT_SWITCH_OUTPUT_INDEX(a) \\\n\tvoid slotSwitchOutputIndex##a() { setOutputIndex(a); }\n\n\tSLOT_SWITCH_OUTPUT_INDEX(0)\n\tSLOT_SWITCH_OUTPUT_INDEX(1)\n\tSLOT_SWITCH_OUTPUT_INDEX(2)\n\tSLOT_SWITCH_OUTPUT_INDEX(3)\n\tSLOT_SWITCH_OUTPUT_INDEX(4)\n\tSLOT_SWITCH_OUTPUT_INDEX(5)\n\tSLOT_SWITCH_OUTPUT_INDEX(6)\n\tSLOT_SWITCH_OUTPUT_INDEX(7)\n\tSLOT_SWITCH_OUTPUT_INDEX(8)\n\tSLOT_SWITCH_OUTPUT_INDEX(9)\n\tSLOT_SWITCH_OUTPUT_INDEX(10)\n\tSLOT_SWITCH_OUTPUT_INDEX(11)\n\tSLOT_SWITCH_OUTPUT_INDEX(12)\n\tSLOT_SWITCH_OUTPUT_INDEX(13)\n\tSLOT_SWITCH_OUTPUT_INDEX(14)\n\tSLOT_SWITCH_OUTPUT_INDEX(15)\n\tSLOT_SWITCH_OUTPUT_INDEX(16)\n\tSLOT_SWITCH_OUTPUT_INDEX(17)\n\tSLOT_SWITCH_OUTPUT_INDEX(18)\n\tSLOT_SWITCH_OUTPUT_INDEX(19)\n\n#undef SLOT_SWITCH_OUTPUT_INDEX\n\n\tvoid slotSwitchToPreviousOutputIndex();\n\tvoid slotSwitchToNextOutputIndex();\n\nprotected:\n\n\tfriend class FramePropsPanel;\n\n\tvirtual void stopAndCleanUp() override;\n\n\tvoid moveEvent(QMoveEvent * a_pEvent) override;\n\n\tvoid resizeEvent(QResizeEvent * a_pEvent) override;\n\n\tvoid changeEvent(QEvent * a_pEvent) override;\n\n\tvoid closeEvent(QCloseEvent * a_pEvent) override;\n\n\tvoid keyPressEvent(QKeyEvent * a_pEvent) override;\n\n\tvoid createActionsAndMenus();\n\n\tvoid setUpZoomPanel();\n\n\tvoid setUpTimeLinePanel();\n\n\tvoid setUpCropPanel();\n\n\tbool requestShowFrame(int a_frameNumber);\n\n\tvoid setPreviewPixmap();\n\n\tvoid recalculateCropMods();\n\n\tvoid resetCropSpinBoxes();\n\n\tqlonglong frameToTimestamp(int a_frame);\n\tint timestampToFrame(qlonglong a_timestamp);\n\n\tvoid setExpectedFrame(int a_frame);\n\n\tvoid setCurrentFrame(const VSFrame * a_cpOutputFrame,\n\t\tconst VSFrame * a_cpPreviewFrame);\n\n\tvoid updateFrameProps(bool a_forced);\n\n\tdouble valueAtPoint(size_t a_x, size_t a_y, int a_plane);\n\n\tvoid previewValueAtPoint(size_t a_x, size_t a_y, int a_ret[]);\n\n\tQPixmap pixmapFromRGB(const VSFrame * a_cpFrame);\n\n\tvoid setTitle();\n\n\tvoid saveTimelineBookmarks();\n\tvoid loadTimelineBookmarks();\n\n\tvoid saveGeometryDelayed();\n\n\tQPoint loadLastScrollBarPositions() const;\n\tvoid saveLastScrollBarPositions();\n\n#ifdef Q_OS_WIN // AUDIO\n\tvoid setAudioOutput();\n\tvoid stopAudioOutput();\n\tvoid playAudioFrame();\n\n\tQByteArray readAudioFrame(const VSFrame * a_cpFrame);\n#endif\n\n\tUi::PreviewDialog m_ui;\n\n\tPreviewAdvancedSettingsDialog * m_pAdvancedSettingsDialog;\n\n\tint64_t m_fpsNum = 0;\n\tint64_t m_fpsDen = 0;\n\n\tint m_frameExpected;\n\tqlonglong m_frameTimestampExpected;\n\tint m_frameShown;\n\tint m_lastFrameRequestedForPlay;\n\n\tint m_bigFrameStep;\n\n\tconst VSFrame * m_cpFrame;\n\tconst VSFrame * m_cpPreviewFrame;\n\tQPixmap m_framePixmap;\n\n\tbool m_changingCropValues;\n\n\tQMenu * m_pPreviewContextMenu;\n\tQAction * m_pActionFrameToClipboard;\n\tQAction * m_pActionSaveSnapshot;\n\tQAction * m_pActionToggleZoomPanel;\n\tQMenu * m_pMenuZoomModes;\n\tQActionGroup * m_pActionGroupZoomModes;\n\tQAction * m_pActionSetZoomModeNoZoom;\n\tQAction * m_pActionSetZoomModeFixedRatio;\n\tQAction * m_pActionSetZoomModeFitToFrame;\n\tQMenu * m_pMenuZoomScaleModes;\n\tQActionGroup * m_pActionGroupZoomScaleModes;\n\tQAction * m_pActionSetZoomScaleModeNearest;\n\tQAction * m_pActionSetZoomScaleModeBilinear;\n\tQAction * m_pActionToggleCropPanel;\n\tQAction * m_pActionToggleTimeLinePanel;\n\tQMenu * m_pMenuTimeLineModes;\n\tQActionGroup * m_pActionGroupTimeLineModes;\n\tQAction * m_pActionSetTimeLineModeTime;\n\tQAction * m_pActionSetTimeLineModeFrames;\n\tQAction * m_pActionTimeStepForward;\n\tQAction * m_pActionTimeStepBack;\n\tQAction * m_pActionPasteCropSnippetIntoScript;\n\tQAction * m_pActionAdvancedSettingsDialog;\n\tQAction * m_pActionToggleColorPicker;\n\tQAction * m_pActionPlay;\n\tQAction * m_pActionLoadChapters;\n\tQAction * m_pActionClearBookmarks;\n\tQAction * m_pActionBookmarkCurrentFrame;\n\tQAction * m_pActionUnbookmarkCurrentFrame;\n\tQAction * m_pActionGoToPreviousBookmark;\n\tQAction * m_pActionGoToNextBookmark;\n\tQAction * m_pActionPasteShownFrameNumberIntoScript;\n\tQAction * m_pActionJumpToFrame;\n\tQAction * m_pActionToggleFramePropsPanel;\n\tQAction * m_pActionSwitchToOutputIndex0;\n\tQAction * m_pActionSwitchToOutputIndex1;\n\tQAction * m_pActionSwitchToOutputIndex2;\n\tQAction * m_pActionSwitchToOutputIndex3;\n\tQAction * m_pActionSwitchToOutputIndex4;\n\tQAction * m_pActionSwitchToOutputIndex5;\n\tQAction * m_pActionSwitchToOutputIndex6;\n\tQAction * m_pActionSwitchToOutputIndex7;\n\tQAction * m_pActionSwitchToOutputIndex8;\n\tQAction * m_pActionSwitchToOutputIndex9;\n\tQAction * m_pActionSwitchToOutputIndex10;\n\tQAction * m_pActionSwitchToOutputIndex11;\n\tQAction * m_pActionSwitchToOutputIndex12;\n\tQAction * m_pActionSwitchToOutputIndex13;\n\tQAction * m_pActionSwitchToOutputIndex14;\n\tQAction * m_pActionSwitchToOutputIndex15;\n\tQAction * m_pActionSwitchToOutputIndex16;\n\tQAction * m_pActionSwitchToOutputIndex17;\n\tQAction * m_pActionSwitchToOutputIndex18;\n\tQAction * m_pActionSwitchToOutputIndex19;\n\tQAction * m_pActionSwitchToPreviousOutputIndex;\n\tQAction * m_pActionSwitchToNextOutputIndex;\n\n\tstd::map<QString, ZoomMode> m_actionIDToZoomModeMap;\n\n\tstd::map<QString, Qt::TransformationMode> m_actionIDToZoomScaleModeMap;\n\n\tstd::map<QString, TimeLineSlider::DisplayMode>\n\t\tm_actionIDToTimeLineModeMap;\n\n\tstd::vector<QAction *> m_settableActionsList;\n\n\tbool m_playing;\n\tbool m_processingPlayQueue;\n\tbool m_nativePlaybackRate;\n\tdouble m_secondsBetweenFrames;\n\thr_time_point m_lastFrameShowTime;\n\tQTimer * m_pPlayTimer;\n\tQIcon m_iconPlay;\n\tQIcon m_iconPause;\n\n\tbool m_alwaysKeepCurrentFrame;\n\n\tQTimer * m_pGeometrySaveTimer;\n\tQByteArray m_windowGeometry;\n\n\tqreal m_devicePixelRatio;\n\n\tFramePropsPanel * m_pFramePropsPanel;\n\n\tbool m_toChangeTitle;\n\tbool m_scriptTextChanged = false;\n\n\tbool m_inPreviewer;\n\n\tQMetaObject::Connection m_outputIndexComboBoxConnection;\n\n#ifdef Q_OS_WIN // AUDIO\n\tbool m_currentIsAudio;\n\tQAudioSink * m_pAudioSink = nullptr;\n\tQIODevice * m_pAudioIODevice = nullptr;\n\tstd::map<int, AudioFrame> m_audioCache;\n\tQTimer * m_pAudioPlayTimer = nullptr;\n\tdouble m_audioVolume = 1.0;\n#endif\n};\n\nclass FramePropsPanel: public QTextEdit\n{\n\tQ_OBJECT\n\npublic:\n\tFramePropsPanel(SettingsManager * a_pSettingsManager,\n\t\tPreviewDialog * a_pFakeParent);\n\n\tvoid setVisible(bool visible) override;\n\n\tvoid keyPressEvent(QKeyEvent * a_pEvent) override;\n\npublic slots:\n\tvoid slotHide() { setVisible(false); }\n\nprivate:\n\tPreviewDialog * m_pFakeParent;\n\tQAction * m_pActionHide;\n\tint m_widgetWidth = 400;\n\tint m_widgetHeight = 400;\n\n\tvoid setHideAction(SettingsManager * a_pSettingsManager);\n};\n\n#endif // PREVIEWDIALOG_H_INCLUDED\n"
  },
  {
    "path": "vsedit/src/preview/preview_dialog.ui",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<ui version=\"4.0\">\n <class>PreviewDialog</class>\n <widget class=\"QDialog\" name=\"PreviewDialog\">\n  <property name=\"geometry\">\n   <rect>\n    <x>0</x>\n    <y>0</y>\n    <width>933</width>\n    <height>652</height>\n   </rect>\n  </property>\n  <property name=\"windowTitle\">\n   <string>Dialog</string>\n  </property>\n  <layout class=\"QVBoxLayout\" name=\"mainLayout\">\n   <property name=\"spacing\">\n    <number>0</number>\n   </property>\n   <property name=\"leftMargin\">\n    <number>0</number>\n   </property>\n   <property name=\"topMargin\">\n    <number>0</number>\n   </property>\n   <property name=\"rightMargin\">\n    <number>0</number>\n   </property>\n   <property name=\"bottomMargin\">\n    <number>0</number>\n   </property>\n   <item>\n    <widget class=\"PreviewArea\" name=\"previewArea\"/>\n   </item>\n   <item>\n    <widget class=\"QWidget\" name=\"toolBar\" native=\"true\">\n     <property name=\"sizePolicy\">\n      <sizepolicy hsizetype=\"Expanding\" vsizetype=\"Fixed\">\n       <horstretch>0</horstretch>\n       <verstretch>0</verstretch>\n      </sizepolicy>\n     </property>\n     <layout class=\"QHBoxLayout\" name=\"horizontalLayout\">\n      <property name=\"spacing\">\n       <number>2</number>\n      </property>\n      <property name=\"leftMargin\">\n       <number>0</number>\n      </property>\n      <property name=\"topMargin\">\n       <number>0</number>\n      </property>\n      <property name=\"rightMargin\">\n       <number>0</number>\n      </property>\n      <property name=\"bottomMargin\">\n       <number>0</number>\n      </property>\n      <item>\n       <widget class=\"QToolButton\" name=\"timeLineCheckButton\">\n        <property name=\"toolTip\">\n         <string>Timeline</string>\n        </property>\n        <property name=\"checkable\">\n         <bool>true</bool>\n        </property>\n       </widget>\n      </item>\n      <item>\n       <widget class=\"QLabel\" name=\"outputIndexLabel\">\n        <property name=\"text\">\n         <string>Index:</string>\n        </property>\n       </widget>\n      </item>\n      <item>\n       <widget class=\"QComboBox\" name=\"outputIndexComboBox\">\n        <property name=\"sizePolicy\">\n         <sizepolicy hsizetype=\"Minimum\" vsizetype=\"Fixed\">\n          <horstretch>0</horstretch>\n          <verstretch>0</verstretch>\n         </sizepolicy>\n        </property>\n       </widget>\n      </item>\n      <item>\n       <widget class=\"QLabel\" name=\"frameLabel\">\n        <property name=\"text\">\n         <string>Frame:</string>\n        </property>\n       </widget>\n      </item>\n      <item>\n       <widget class=\"QSpinBox\" name=\"frameNumberSpinBox\">\n        <property name=\"sizePolicy\">\n         <sizepolicy hsizetype=\"Minimum\" vsizetype=\"Fixed\">\n          <horstretch>0</horstretch>\n          <verstretch>0</verstretch>\n         </sizepolicy>\n        </property>\n        <property name=\"keyboardTracking\">\n         <bool>false</bool>\n        </property>\n        <property name=\"maximum\">\n         <number>999999999</number>\n        </property>\n       </widget>\n      </item>\n      <item>\n       <widget class=\"QLabel\" name=\"frameStatusLabel\">\n        <property name=\"minimumSize\">\n         <size>\n          <width>16</width>\n          <height>0</height>\n         </size>\n        </property>\n        <property name=\"text\">\n         <string/>\n        </property>\n       </widget>\n      </item>\n      <item>\n       <widget class=\"TimeLineSlider\" name=\"frameNumberSlider\" native=\"true\">\n        <property name=\"sizePolicy\">\n         <sizepolicy hsizetype=\"Expanding\" vsizetype=\"Preferred\">\n          <horstretch>0</horstretch>\n          <verstretch>0</verstretch>\n         </sizepolicy>\n        </property>\n       </widget>\n      </item>\n      <item>\n       <widget class=\"QToolButton\" name=\"frameToClipboardButton\">\n        <property name=\"toolTip\">\n         <string>Copy frame to clipboard</string>\n        </property>\n       </widget>\n      </item>\n      <item>\n       <widget class=\"QToolButton\" name=\"saveSnapshotButton\">\n        <property name=\"toolTip\">\n         <string>Save snapshot</string>\n        </property>\n       </widget>\n      </item>\n      <item>\n       <widget class=\"QToolButton\" name=\"advancedSettingsButton\">\n        <property name=\"toolTip\">\n         <string>Preview Advanced Settings</string>\n        </property>\n       </widget>\n      </item>\n      <item>\n       <widget class=\"QToolButton\" name=\"cropCheckButton\">\n        <property name=\"toolTip\">\n         <string>Crop assistant</string>\n        </property>\n        <property name=\"checkable\">\n         <bool>true</bool>\n        </property>\n       </widget>\n      </item>\n      <item>\n       <widget class=\"QToolButton\" name=\"zoomCheckButton\">\n        <property name=\"toolTip\">\n         <string>Zoom</string>\n        </property>\n        <property name=\"checkable\">\n         <bool>true</bool>\n        </property>\n        <property name=\"checked\">\n         <bool>true</bool>\n        </property>\n       </widget>\n      </item>\n      <item>\n       <widget class=\"QWidget\" name=\"zoomPanel\" native=\"true\">\n        <layout class=\"QHBoxLayout\" name=\"horizontalLayout_2\">\n         <property name=\"spacing\">\n          <number>2</number>\n         </property>\n         <property name=\"leftMargin\">\n          <number>0</number>\n         </property>\n         <property name=\"topMargin\">\n          <number>0</number>\n         </property>\n         <property name=\"rightMargin\">\n          <number>0</number>\n         </property>\n         <property name=\"bottomMargin\">\n          <number>0</number>\n         </property>\n         <item>\n          <widget class=\"QComboBox\" name=\"zoomModeComboBox\">\n           <property name=\"sizePolicy\">\n            <sizepolicy hsizetype=\"Minimum\" vsizetype=\"Fixed\">\n             <horstretch>0</horstretch>\n             <verstretch>0</verstretch>\n            </sizepolicy>\n           </property>\n          </widget>\n         </item>\n         <item>\n          <widget class=\"ZoomRatioSpinBox\" name=\"zoomRatioSpinBox\">\n           <property name=\"keyboardTracking\">\n            <bool>false</bool>\n           </property>\n           <property name=\"prefix\">\n            <string>x</string>\n           </property>\n           <property name=\"minimum\">\n            <double>0.010000000000000</double>\n           </property>\n           <property name=\"maximum\">\n            <double>1024.000000000000000</double>\n           </property>\n           <property name=\"value\">\n            <double>2.000000000000000</double>\n           </property>\n          </widget>\n         </item>\n         <item>\n          <widget class=\"QComboBox\" name=\"scaleModeComboBox\"/>\n         </item>\n        </layout>\n       </widget>\n      </item>\n      <item>\n       <widget class=\"QToolButton\" name=\"colorPickerButton\">\n        <property name=\"toolTip\">\n         <string>Color picker</string>\n        </property>\n        <property name=\"text\">\n         <string/>\n        </property>\n       </widget>\n      </item>\n     </layout>\n     <zorder>colorPickerButton</zorder>\n     <zorder>frameNumberSlider</zorder>\n     <zorder>frameToClipboardButton</zorder>\n     <zorder>saveSnapshotButton</zorder>\n     <zorder>advancedSettingsButton</zorder>\n     <zorder>cropCheckButton</zorder>\n     <zorder>zoomCheckButton</zorder>\n     <zorder>zoomPanel</zorder>\n     <zorder>timeLineCheckButton</zorder>\n     <zorder>frameNumberSpinBox</zorder>\n     <zorder>frameStatusLabel</zorder>\n    </widget>\n   </item>\n   <item>\n    <widget class=\"QWidget\" name=\"timeLinePanel\" native=\"true\">\n     <layout class=\"QHBoxLayout\" name=\"horizontalLayout_4\" stretch=\"0,0,0,0,1,0,0,0,0,0,0,1,0,0,0,0,0,0\">\n      <property name=\"spacing\">\n       <number>2</number>\n      </property>\n      <property name=\"leftMargin\">\n       <number>0</number>\n      </property>\n      <property name=\"topMargin\">\n       <number>0</number>\n      </property>\n      <property name=\"rightMargin\">\n       <number>0</number>\n      </property>\n      <property name=\"bottomMargin\">\n       <number>0</number>\n      </property>\n      <item>\n       <widget class=\"QToolButton\" name=\"playButton\">\n        <property name=\"text\">\n         <string/>\n        </property>\n       </widget>\n      </item>\n      <item>\n       <widget class=\"QLabel\" name=\"label\">\n        <property name=\"text\">\n         <string>FPS limit mode:</string>\n        </property>\n       </widget>\n      </item>\n      <item>\n       <widget class=\"QComboBox\" name=\"playFpsLimitModeComboBox\"/>\n      </item>\n      <item>\n       <widget class=\"QDoubleSpinBox\" name=\"playFpsLimitSpinBox\">\n        <property name=\"decimals\">\n         <number>5</number>\n        </property>\n        <property name=\"maximum\">\n         <double>100000.000000000000000</double>\n        </property>\n        <property name=\"value\">\n         <double>23.999990000000000</double>\n        </property>\n       </widget>\n      </item>\n      <item>\n       <spacer name=\"horizontalSpacer_2\">\n        <property name=\"orientation\">\n         <enum>Qt::Horizontal</enum>\n        </property>\n        <property name=\"sizeHint\" stdset=\"0\">\n         <size>\n          <width>571</width>\n          <height>20</height>\n         </size>\n        </property>\n       </spacer>\n      </item>\n      <item>\n       <widget class=\"QToolButton\" name=\"goToPreviousBookmarkButton\">\n        <property name=\"text\">\n         <string/>\n        </property>\n       </widget>\n      </item>\n      <item>\n       <widget class=\"QToolButton\" name=\"bookmarkCurrentFrameButton\"/>\n      </item>\n      <item>\n       <widget class=\"QToolButton\" name=\"unbookmarkCurrentFrameButton\"/>\n      </item>\n      <item>\n       <widget class=\"QToolButton\" name=\"loadChaptersButton\">\n        <property name=\"text\">\n         <string/>\n        </property>\n       </widget>\n      </item>\n      <item>\n       <widget class=\"QToolButton\" name=\"clearBookmarksButton\"/>\n      </item>\n      <item>\n       <widget class=\"QToolButton\" name=\"goToNextBookmarkButton\"/>\n      </item>\n      <item>\n       <spacer name=\"horizontalSpacer_3\">\n        <property name=\"orientation\">\n         <enum>Qt::Horizontal</enum>\n        </property>\n        <property name=\"sizeHint\" stdset=\"0\">\n         <size>\n          <width>40</width>\n          <height>20</height>\n         </size>\n        </property>\n       </spacer>\n      </item>\n      <item>\n       <widget class=\"QLabel\" name=\"timeLineModeLabel\">\n        <property name=\"text\">\n         <string>Timeline display mode:</string>\n        </property>\n        <property name=\"margin\">\n         <number>2</number>\n        </property>\n       </widget>\n      </item>\n      <item>\n       <widget class=\"QComboBox\" name=\"timeLineModeComboBox\">\n        <property name=\"sizePolicy\">\n         <sizepolicy hsizetype=\"Minimum\" vsizetype=\"Fixed\">\n          <horstretch>0</horstretch>\n          <verstretch>0</verstretch>\n         </sizepolicy>\n        </property>\n       </widget>\n      </item>\n      <item>\n       <widget class=\"QLabel\" name=\"stepLabel\">\n        <property name=\"text\">\n         <string>Step:</string>\n        </property>\n        <property name=\"margin\">\n         <number>2</number>\n        </property>\n       </widget>\n      </item>\n      <item>\n       <widget class=\"QTimeEdit\" name=\"timeStepEdit\">\n        <property name=\"displayFormat\">\n         <string>H:mm:ss.zzz</string>\n        </property>\n       </widget>\n      </item>\n      <item>\n       <widget class=\"QToolButton\" name=\"timeStepBackButton\">\n        <property name=\"toolTip\">\n         <string>Step back</string>\n        </property>\n       </widget>\n      </item>\n      <item>\n       <widget class=\"QToolButton\" name=\"timeStepForwardButton\">\n        <property name=\"toolTip\">\n         <string>Step forward</string>\n        </property>\n       </widget>\n      </item>\n     </layout>\n    </widget>\n   </item>\n   <item>\n    <widget class=\"QWidget\" name=\"cropPanel\" native=\"true\">\n     <layout class=\"QHBoxLayout\" name=\"horizontalLayout_3\">\n      <property name=\"spacing\">\n       <number>2</number>\n      </property>\n      <property name=\"leftMargin\">\n       <number>0</number>\n      </property>\n      <property name=\"topMargin\">\n       <number>0</number>\n      </property>\n      <property name=\"rightMargin\">\n       <number>0</number>\n      </property>\n      <property name=\"bottomMargin\">\n       <number>0</number>\n      </property>\n      <item>\n       <spacer name=\"horizontalSpacer\">\n        <property name=\"orientation\">\n         <enum>Qt::Horizontal</enum>\n        </property>\n        <property name=\"sizeHint\" stdset=\"0\">\n         <size>\n          <width>40</width>\n          <height>20</height>\n         </size>\n        </property>\n       </spacer>\n      </item>\n      <item>\n       <widget class=\"QLabel\" name=\"cropModeLabel\">\n        <property name=\"sizePolicy\">\n         <sizepolicy hsizetype=\"Preferred\" vsizetype=\"Preferred\">\n          <horstretch>0</horstretch>\n          <verstretch>0</verstretch>\n         </sizepolicy>\n        </property>\n        <property name=\"text\">\n         <string>Crop mode:</string>\n        </property>\n        <property name=\"alignment\">\n         <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>\n        </property>\n        <property name=\"margin\">\n         <number>4</number>\n        </property>\n       </widget>\n      </item>\n      <item>\n       <widget class=\"QComboBox\" name=\"cropModeComboBox\"/>\n      </item>\n      <item>\n       <widget class=\"QLabel\" name=\"cropLeftLabel\">\n        <property name=\"sizePolicy\">\n         <sizepolicy hsizetype=\"Preferred\" vsizetype=\"Preferred\">\n          <horstretch>0</horstretch>\n          <verstretch>0</verstretch>\n         </sizepolicy>\n        </property>\n        <property name=\"text\">\n         <string>Left:</string>\n        </property>\n        <property name=\"alignment\">\n         <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>\n        </property>\n        <property name=\"margin\">\n         <number>4</number>\n        </property>\n       </widget>\n      </item>\n      <item>\n       <widget class=\"QSpinBox\" name=\"cropLeftSpinBox\">\n        <property name=\"keyboardTracking\">\n         <bool>false</bool>\n        </property>\n       </widget>\n      </item>\n      <item>\n       <widget class=\"QLabel\" name=\"cropTopLabel\">\n        <property name=\"sizePolicy\">\n         <sizepolicy hsizetype=\"Preferred\" vsizetype=\"Preferred\">\n          <horstretch>0</horstretch>\n          <verstretch>0</verstretch>\n         </sizepolicy>\n        </property>\n        <property name=\"text\">\n         <string>Top:</string>\n        </property>\n        <property name=\"alignment\">\n         <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>\n        </property>\n        <property name=\"margin\">\n         <number>4</number>\n        </property>\n       </widget>\n      </item>\n      <item>\n       <widget class=\"QSpinBox\" name=\"cropTopSpinBox\">\n        <property name=\"keyboardTracking\">\n         <bool>false</bool>\n        </property>\n       </widget>\n      </item>\n      <item>\n       <widget class=\"QLabel\" name=\"cropWidthLabel\">\n        <property name=\"sizePolicy\">\n         <sizepolicy hsizetype=\"Preferred\" vsizetype=\"Preferred\">\n          <horstretch>0</horstretch>\n          <verstretch>0</verstretch>\n         </sizepolicy>\n        </property>\n        <property name=\"text\">\n         <string>Width:</string>\n        </property>\n        <property name=\"alignment\">\n         <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>\n        </property>\n        <property name=\"margin\">\n         <number>4</number>\n        </property>\n       </widget>\n      </item>\n      <item>\n       <widget class=\"QSpinBox\" name=\"cropWidthSpinBox\">\n        <property name=\"keyboardTracking\">\n         <bool>false</bool>\n        </property>\n        <property name=\"minimum\">\n         <number>1</number>\n        </property>\n       </widget>\n      </item>\n      <item>\n       <widget class=\"QLabel\" name=\"cropHeightLabel\">\n        <property name=\"sizePolicy\">\n         <sizepolicy hsizetype=\"Preferred\" vsizetype=\"Preferred\">\n          <horstretch>0</horstretch>\n          <verstretch>0</verstretch>\n         </sizepolicy>\n        </property>\n        <property name=\"text\">\n         <string>Height:</string>\n        </property>\n        <property name=\"alignment\">\n         <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>\n        </property>\n        <property name=\"margin\">\n         <number>4</number>\n        </property>\n       </widget>\n      </item>\n      <item>\n       <widget class=\"QSpinBox\" name=\"cropHeightSpinBox\">\n        <property name=\"keyboardTracking\">\n         <bool>false</bool>\n        </property>\n        <property name=\"minimum\">\n         <number>1</number>\n        </property>\n       </widget>\n      </item>\n      <item>\n       <widget class=\"QLabel\" name=\"cropRightLabel\">\n        <property name=\"sizePolicy\">\n         <sizepolicy hsizetype=\"Preferred\" vsizetype=\"Preferred\">\n          <horstretch>0</horstretch>\n          <verstretch>0</verstretch>\n         </sizepolicy>\n        </property>\n        <property name=\"text\">\n         <string>Right:</string>\n        </property>\n        <property name=\"alignment\">\n         <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>\n        </property>\n        <property name=\"margin\">\n         <number>4</number>\n        </property>\n       </widget>\n      </item>\n      <item>\n       <widget class=\"QSpinBox\" name=\"cropRightSpinBox\">\n        <property name=\"keyboardTracking\">\n         <bool>false</bool>\n        </property>\n       </widget>\n      </item>\n      <item>\n       <widget class=\"QLabel\" name=\"cropBottomLabel\">\n        <property name=\"sizePolicy\">\n         <sizepolicy hsizetype=\"Preferred\" vsizetype=\"Preferred\">\n          <horstretch>0</horstretch>\n          <verstretch>0</verstretch>\n         </sizepolicy>\n        </property>\n        <property name=\"text\">\n         <string>Bottom:</string>\n        </property>\n        <property name=\"alignment\">\n         <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>\n        </property>\n        <property name=\"margin\">\n         <number>4</number>\n        </property>\n       </widget>\n      </item>\n      <item>\n       <widget class=\"QSpinBox\" name=\"cropBottomSpinBox\">\n        <property name=\"keyboardTracking\">\n         <bool>false</bool>\n        </property>\n       </widget>\n      </item>\n      <item>\n       <widget class=\"QLabel\" name=\"cropZoomLabel\">\n        <property name=\"sizePolicy\">\n         <sizepolicy hsizetype=\"Preferred\" vsizetype=\"Preferred\">\n          <horstretch>0</horstretch>\n          <verstretch>0</verstretch>\n         </sizepolicy>\n        </property>\n        <property name=\"text\">\n         <string>Zoom:</string>\n        </property>\n        <property name=\"alignment\">\n         <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>\n        </property>\n        <property name=\"margin\">\n         <number>4</number>\n        </property>\n       </widget>\n      </item>\n      <item>\n       <widget class=\"QSpinBox\" name=\"cropZoomRatioSpinBox\">\n        <property name=\"keyboardTracking\">\n         <bool>false</bool>\n        </property>\n        <property name=\"prefix\">\n         <string>x</string>\n        </property>\n        <property name=\"minimum\">\n         <number>1</number>\n        </property>\n       </widget>\n      </item>\n      <item>\n       <widget class=\"QToolButton\" name=\"cropPasteToScriptButton\">\n        <property name=\"toolTip\">\n         <string>Paste into script</string>\n        </property>\n       </widget>\n      </item>\n     </layout>\n    </widget>\n   </item>\n  </layout>\n  <zorder>toolBar</zorder>\n  <zorder>previewArea</zorder>\n  <zorder>cropPanel</zorder>\n  <zorder>timeLinePanel</zorder>\n </widget>\n <customwidgets>\n  <customwidget>\n   <class>PreviewArea</class>\n   <extends>QWidget</extends>\n   <header>../../src/preview/preview_area.h</header>\n   <container>1</container>\n  </customwidget>\n  <customwidget>\n   <class>TimeLineSlider</class>\n   <extends>QWidget</extends>\n   <header>../../../common-src/timeline_slider/timeline_slider.h</header>\n   <container>1</container>\n  </customwidget>\n  <customwidget>\n   <class>ZoomRatioSpinBox</class>\n   <extends>QDoubleSpinBox</extends>\n   <header>../../src/preview/zoom_ratio_spinbox.h</header>\n   <container>1</container>\n  </customwidget>\n </customwidgets>\n <resources/>\n <connections/>\n</ui>\n"
  },
  {
    "path": "vsedit/src/preview/scroll_navigator.cpp",
    "content": "#include \"scroll_navigator.h\"\n\n#include <QPaintEvent>\n#include <QPainter>\n#include <QColor>\n\n//==============================================================================\n\nScrollNavigator::ScrollNavigator(QWidget * a_pParent) : QWidget(a_pParent)\n\t, m_contentsHeight(0)\n\t, m_contentsWidth(0)\n\t, m_viewportX(0)\n\t, m_viewportY(0)\n\t, m_viewportHeight(0)\n\t, m_viewportWidth(0)\n{\n\tsetAttribute(Qt::WA_NoSystemBackground);\n\tsetAttribute(Qt::WA_TransparentForMouseEvents);\n\tsetGeometry(0, 0, 100, 100);\n}\n\n// END OF ScrollNavigator::ScrollNavigator(QWidget * a_pParent)\n//==============================================================================\n\nScrollNavigator::~ScrollNavigator()\n{\n\n}\n\n// END OF ScrollNavigator::~ScrollNavigator()\n//==============================================================================\n\nvoid ScrollNavigator::draw(int a_contentsWidth, int a_contentsHeight,\n\tint a_viewportX, int a_viewportY, int a_viewportWidth,\n\tint a_viewportHeight)\n{\n\tm_contentsHeight = a_contentsHeight;\n\tm_contentsWidth = a_contentsWidth;\n\tm_viewportX = a_viewportX;\n\tm_viewportY = a_viewportY;\n\tm_viewportHeight = a_viewportHeight;\n\tm_viewportWidth = a_viewportWidth;\n\trepaint();\n}\n\n// END OF void ScrollNavigator::draw(int a_contentsWidth, int a_contentsHeight,\n//\t\tint a_viewportX, int a_viewportY, int a_viewportWidth,\n//\t\tint a_viewportHeight)\n//==============================================================================\n\nvoid ScrollNavigator::paintEvent(QPaintEvent * a_pPaintEvent)\n{\n\tif((m_contentsWidth == 0) || (m_contentsHeight == 0) ||\n\t\t(m_viewportWidth == 0) || (m_viewportHeight == 0) ||\n\t\t(m_viewportX >= m_contentsWidth) || (m_viewportY >= m_contentsHeight))\n\t{\n\t\ta_pPaintEvent->ignore();\n\t\treturn;\n\t}\n\n\tint measures[] = {m_contentsWidth, m_contentsHeight, m_viewportWidth,\n\t\tm_viewportHeight};\n\tint maxMeasure = 0;\n\tfor(int m : measures)\n\t\tif(m > maxMeasure)\n\t\t\tmaxMeasure = m;\n\n\tdouble dpr = window()->devicePixelRatioF();\n\n\tint normalizedContentsWidth = int((double)m_contentsWidth * 100.0 /\n\t\t(double)maxMeasure);\n\tint normalizedContentsHeight = int((double)m_contentsHeight * 100.0 /\n\t\t(double)maxMeasure);\n\tint normalizedVieportX = int(m_viewportX * dpr * 100.0 /\n\t\t(double)maxMeasure);\n\tint normalizedViwportY = int(m_viewportY * dpr * 100.0 /\n\t\t(double)maxMeasure);\n\tint normalizedViewportWidth = int(m_viewportWidth * dpr * 100.0 /\n\t\t(double)maxMeasure);\n\tint normalizedViewportHeight = int(m_viewportHeight * dpr * 100.0 /\n\t\t(double)maxMeasure);\n\n\tint cX1 = 0;\n\tint cY1 = 0;\n\tint cX2 = normalizedContentsWidth - 1;\n\tint cY2 = normalizedContentsHeight - 1;\n\n\tint vX1 = normalizedVieportX;\n\tint vY1 = normalizedViwportY;\n\tint vX2 = normalizedVieportX + normalizedViewportWidth - 1;\n\tint vY2 = normalizedViwportY + normalizedViewportHeight - 1;\n\n\tQPainter painter(this);\n\n\t// Draw contents rectangle.\n\tpainter.setPen(QColor::fromRgb(255, 0, 255));\n\tpainter.drawLine(cX1, cY1, cX2, cY1);\n\tpainter.drawLine(cX2, cY1, cX2, cY2);\n\tpainter.drawLine(cX2, cY2, cX1, cY2);\n\tpainter.drawLine(cX1, cY2, cX1, cY1);\n\n\t// Draw viewport rectangle.\n\tpainter.setPen(QColor::fromRgb(0, 255, 0));\n\tpainter.drawLine(vX1, vY1, vX2, vY1);\n\tpainter.drawLine(vX2, vY1, vX2, vY2);\n\tpainter.drawLine(vX2, vY2, vX1, vY2);\n\tpainter.drawLine(vX1, vY2, vX1, vY1);\n\n    a_pPaintEvent->accept();\n}\n\n// END OF void ScrollNavigator::paintEvent(QPaintEvent * a_pPaintEvent)\n//==============================================================================\n"
  },
  {
    "path": "vsedit/src/preview/scroll_navigator.h",
    "content": "#ifndef SCROLLNAVIGATOR_H\n#define SCROLLNAVIGATOR_H\n\n#include <QWidget>\n\nclass QPaintEvent;\n\nclass ScrollNavigator : public QWidget\n{\npublic:\n\n\tScrollNavigator(QWidget * a_pParent = 0);\n\n\tvirtual ~ScrollNavigator();\n\n\tvoid draw(int a_contentsWidth, int a_contentsHeight, int a_viewportX,\n\t\tint a_viewportY, int a_viewportWidth, int a_viewportHeight);\n\nprotected:\n\n\tvoid paintEvent(QPaintEvent * a_pPaintEvent) override;\n\nprivate:\n\n\tint m_contentsHeight;\n\tint m_contentsWidth;\n\tint m_viewportX;\n\tint m_viewportY;\n\tint m_viewportHeight;\n\tint m_viewportWidth;\n};\n\n#endif // SCROLLNAVIGATOR_H\n"
  },
  {
    "path": "vsedit/src/preview/zoom_ratio_spinbox.cpp",
    "content": "#include \"zoom_ratio_spinbox.h\"\n\n#include <cmath>\n\nZoomRatioSpinBox::ZoomRatioSpinBox(QWidget * a_pWidget): \n\tQDoubleSpinBox(a_pWidget)\n\t, m_scaleMode{Qt::SmoothTransformation}\n\t{}\n\nvoid ZoomRatioSpinBox::setScaleMode(Qt::TransformationMode a_mode)\n{\n\tm_scaleMode = a_mode;\n\tif(m_scaleMode == Qt::FastTransformation)\n\t{\n\t\tint ival = std::round(value());\n\t\tif(ival == 0)\n\t\t\tival = 1;\n\t\tif(ival > maximum())\n\t\t\tival = std::floor(maximum());\n\t\tQDoubleSpinBox::setValue(ival);\n\t}\n}\n\nvoid ZoomRatioSpinBox::stepBy(int steps)\n{\n\tif(steps == -1)\n\t{\n\t\tif(m_scaleMode == Qt::FastTransformation)\n\t\t{\n\t\t\tint ival = (int)value() - 1;\n\t\t\tif(ival <= 0)\n\t\t\t\tival = 1;\n\t\t\tQDoubleSpinBox::setValue(ival);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tdouble val = value();\n\t\t\tif(val > 2.0)\n\t\t\t\tQDoubleSpinBox::setValue(val - 1.0);\n\t\t\telse if(val > 1.0)\n\t\t\t\tQDoubleSpinBox::setValue(1.0);\n\t\t\telse if(val > 0.01 + minimum())\n\t\t\t\tQDoubleSpinBox::setValue(val - 0.01);\n\t\t\telse\n\t\t\t\tQDoubleSpinBox::setValue(minimum());\n\t\t}\n\t}\n\telse if(steps == 1)\n\t{\n\t\tif(m_scaleMode == Qt::FastTransformation)\n\t\t{\n\t\t\tint ival = (int)value() + 1;\n\t\t\tif(ival > maximum())\n\t\t\t\tival = std::floor(maximum());\n\t\t\tQDoubleSpinBox::setValue(ival);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tdouble val = value();\n\t\t\tif(val < 0.99)\n\t\t\t\tQDoubleSpinBox::setValue(val + 0.01);\n\t\t\telse if(val < 1.0)\n\t\t\t\tQDoubleSpinBox::setValue(1.0);\n\t\t\telse if(val + 0.1 < 4.1)\n\t\t\t\tQDoubleSpinBox::setValue(val + 0.1);\n\t\t\telse if(val + 1.0 < maximum())\n\t\t\t\tQDoubleSpinBox::setValue(val + 1.0);\n\t\t\telse\n\t\t\t\tQDoubleSpinBox::setValue(maximum());\n\t\t}\n\t}\n\telse if(steps > 0)\n\t{\n\t\tstepBy(1);\n\t\tstepBy(steps - 1);\n\t}\n\telse if(steps < 0)\n\t{\n\t\tstepBy(-1);\n\t\tstepBy(steps + 1);\n\t}\n}\n\nvoid ZoomRatioSpinBox::setValue(double val)\n{\n\tif(m_scaleMode == Qt::FastTransformation)\n\t{\n\t\tint ival = std::round(val);\n\t\tif(ival == 0)\n\t\t\tival = 1;\n\t\tif(ival > maximum())\n\t\t\tival = std::floor(maximum());\n\t\tQDoubleSpinBox::setValue(ival);\n\t}\n\telse\n\t\tQDoubleSpinBox::setValue(val);\n}\n"
  },
  {
    "path": "vsedit/src/preview/zoom_ratio_spinbox.h",
    "content": "#ifndef ZOOM_RATIO_SPINBOX_H_INCLUDED\n#define ZOOM_RATIO_SPINBOX_H_INCLUDED\n\n#include \"../../../common-src/settings/settings_definitions.h\"\n\n#include <QDoubleSpinBox>\n\nclass ZoomRatioSpinBox : public QDoubleSpinBox\n{\npublic:\n    ZoomRatioSpinBox(QWidget * a_pParent = nullptr);\n\n    void setScaleMode(Qt::TransformationMode a_mode);\n\n    void stepBy(int steps);\n\npublic slots:\n    void setValue(double val);\n\nprivate:\n    Qt::TransformationMode m_scaleMode;\n};\n\n#endif\n"
  },
  {
    "path": "vsedit/src/script_editor/number_matcher.cpp",
    "content": "#include \"number_matcher.h\"\n\n//==============================================================================\n\nNumberMatcher::NumberMatcher() : m_state(Initial), m_lastValidLength(0)\n{\n\n}\n\n// END OF NumberMatcher::NumberMatcher()\n//==============================================================================\n\nbool NumberMatcher::beginsWithNumber(const QString & a_string, int a_matchFrom)\n{\n\tm_state = Initial;\n\tm_lastValidLength = 0;\n\tint stringLength = a_string.length();\n\n\tfor(int i = a_matchFrom; i < stringLength; ++i)\n\t{\n\t\tif(m_state == Initial)\n\t\t{\n\t\t\tif(a_string[i] == '0')\n\t\t\t{\n\t\t\t\tm_state = FirstZero;\n\t\t\t\tm_lastValidLength = i - a_matchFrom + 1;\n\t\t\t}\n\t\t\telse if(QString(\"123456789\").contains(a_string[i]))\n\t\t\t{\n\t\t\t\tm_state = Integer;\n\t\t\t\tm_lastValidLength = i - a_matchFrom + 1;\n\t\t\t}\n\t\t\telse if(a_string[i] == '.')\n\t\t\t\tm_state = FirstDot;\n\t\t\telse\n\t\t\t\tbreak;\n\t\t}\n\t\telse if(m_state == FirstZero)\n\t\t{\n\t\t\tif(a_string[i].toLower() == 'b')\n\t\t\t\tm_state = BinLiteral;\n\t\t\telse if(a_string[i].toLower() == 'x')\n\t\t\t\tm_state = HexLiteral;\n\t\t\telse if(a_string[i].toLower() == 'o')\n\t\t\t\tm_state = OctLiteral;\n\t\t\telse if(QString(\"0123456789\").contains(a_string[i]))\n\t\t\t{\n\t\t\t\tm_state = Integer;\n\t\t\t\tm_lastValidLength = i - a_matchFrom + 1;\n\t\t\t}\n\t\t\telse if(a_string[i] == '.')\n\t\t\t{\n\t\t\t\tm_state = DotAfterInteger;\n\t\t\t\tm_lastValidLength = i - a_matchFrom + 1;\n\t\t\t}\n\t\t\telse if(a_string[i].toLower() == 'j')\n\t\t\t{\n\t\t\t\tm_lastValidLength = i - a_matchFrom + 1;\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\telse\n\t\t\t\tbreak;\n\t\t}\n\t\telse if(m_state == BinLiteral)\n\t\t{\n\t\t\tif(QString(\"01\").contains(a_string[i]))\n\t\t\t{\n\t\t\t\tm_state = BinNumber;\n\t\t\t\tm_lastValidLength = i - a_matchFrom + 1;\n\t\t\t}\n\t\t\telse\n\t\t\t\tbreak;\n\t\t}\n\t\telse if(m_state == BinNumber)\n\t\t{\n\t\t\tif(QString(\"01\").contains(a_string[i]))\n\t\t\t\tm_lastValidLength = i - a_matchFrom + 1;\n\t\t\telse\n\t\t\t\tbreak;\n\t\t}\n\t\telse if(m_state == OctLiteral)\n\t\t{\n\t\t\tif(QString(\"01234567\").contains(a_string[i]))\n\t\t\t{\n\t\t\t\tm_state = OctNumber;\n\t\t\t\tm_lastValidLength = i - a_matchFrom + 1;\n\t\t\t}\n\t\t\telse\n\t\t\t\tbreak;\n\t\t}\n\t\telse if(m_state == OctNumber)\n\t\t{\n\t\t\tif(QString(\"01234567\").contains(a_string[i]))\n\t\t\t\tm_lastValidLength = i - a_matchFrom + 1;\n\t\t\telse\n\t\t\t\tbreak;\n\t\t}\n\t\telse if(m_state == HexLiteral)\n\t\t{\n\t\t\tif(QString(\"0123456789abcdef\").contains(a_string[i].toLower()))\n\t\t\t{\n\t\t\t\tm_state = HexNumber;\n\t\t\t\tm_lastValidLength = i - a_matchFrom + 1;\n\t\t\t}\n\t\t\telse\n\t\t\t\tbreak;\n\t\t}\n\t\telse if(m_state == HexNumber)\n\t\t{\n\t\t\tif(QString(\"0123456789abcdef\").contains(a_string[i].toLower()))\n\t\t\t\tm_lastValidLength = i - a_matchFrom + 1;\n\t\t\telse\n\t\t\t\tbreak;\n\t\t}\n\t\telse if(m_state == Integer)\n\t\t{\n\t\t\tif(QString(\"0123456789\").contains(a_string[i]))\n\t\t\t\tm_lastValidLength = i - a_matchFrom + 1;\n\t\t\telse if(a_string[i] == '.')\n\t\t\t{\n\t\t\t\tm_state = DotAfterInteger;\n\t\t\t\tm_lastValidLength = i - a_matchFrom + 1;\n\t\t\t}\n\t\t\telse if(a_string[i].toLower() == 'e')\n\t\t\t\tm_state = ExpLiteral;\n\t\t\telse if(a_string[i].toLower() == 'j')\n\t\t\t{\n\t\t\t\tm_lastValidLength = i - a_matchFrom + 1;\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\telse\n\t\t\t\tbreak;\n\t\t}\n\t\telse if(m_state == DotAfterInteger)\n\t\t{\n\t\t\tif(QString(\"0123456789\").contains(a_string[i]))\n\t\t\t{\n\t\t\t\tm_state = Fraction;\n\t\t\t\tm_lastValidLength = i - a_matchFrom + 1;\n\t\t\t}\n\t\t\telse if(a_string[i].toLower() == 'e')\n\t\t\t\tm_state = ExpLiteral;\n\t\t\telse if(a_string[i].toLower() == 'j')\n\t\t\t{\n\t\t\t\tm_lastValidLength = i - a_matchFrom + 1;\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\telse\n\t\t\t\tbreak;\n\t\t}\n\t\telse if(m_state == FirstDot)\n\t\t{\n\t\t\tif(QString(\"0123456789\").contains(a_string[i]))\n\t\t\t{\n\t\t\t\tm_state = Fraction;\n\t\t\t\tm_lastValidLength = i - a_matchFrom + 1;\n\t\t\t}\n\t\t\telse\n\t\t\t\tbreak;\n\t\t}\n\t\telse if(m_state == Fraction)\n\t\t{\n\t\t\tif(QString(\"0123456789\").contains(a_string[i]))\n\t\t\t\tm_lastValidLength = i - a_matchFrom + 1;\n\t\t\telse if(a_string[i].toLower() == 'e')\n\t\t\t\tm_state = ExpLiteral;\n\t\t\telse if(a_string[i].toLower() == 'j')\n\t\t\t{\n\t\t\t\tm_lastValidLength = i - a_matchFrom + 1;\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\telse\n\t\t\t\tbreak;\n\t\t}\n\t\telse if(m_state == ExpLiteral)\n\t\t{\n\t\t\tif(QString(\"+-\").contains(a_string[i]))\n\t\t\t\tm_state = ExpSign;\n\t\t\telse if(QString(\"0123456789\").contains(a_string[i]))\n\t\t\t{\n\t\t\t\tm_state = ExpComplete;\n\t\t\t\tm_lastValidLength = i - a_matchFrom + 1;\n\t\t\t}\n\t\t\telse\n\t\t\t\tbreak;\n\t\t}\n\t\telse if(m_state == ExpSign)\n\t\t{\n\t\t\tif(QString(\"0123456789\").contains(a_string[i]))\n\t\t\t{\n\t\t\t\tm_state = ExpComplete;\n\t\t\t\tm_lastValidLength = i - a_matchFrom + 1;\n\t\t\t}\n\t\t\telse\n\t\t\t\tbreak;\n\t\t}\n\t\telse if(m_state == ExpComplete)\n\t\t{\n\t\t\tif(QString(\"0123456789\").contains(a_string[i]))\n\t\t\t\tm_lastValidLength = i - a_matchFrom + 1;\n\t\t\telse if(a_string[i].toLower() == 'j')\n\t\t\t{\n\t\t\t\tm_lastValidLength = i - a_matchFrom + 1;\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\t\telse\n\t\t\tbreak;\n\t}\n\n\treturn (m_lastValidLength != 0);\n}\n\n// END OF bool NumberMatcher::beginsWithNumber(const QString & a_string,\n//\t\tint a_matchFrom)\n//==============================================================================\n\nint NumberMatcher::matchedLength() const\n{\n\treturn m_lastValidLength;\n}\n\n\n// END OF int NumberMatcher::matchedLength() const\n//==============================================================================\n"
  },
  {
    "path": "vsedit/src/script_editor/number_matcher.h",
    "content": "#ifndef NUMBERMATCHER_H_INCLUDED\n#define NUMBERMATCHER_H_INCLUDED\n\n#include <QString>\n\n/// Finite state machine Python number matcher for QString.\nclass NumberMatcher\n{\npublic:\n\n\tNumberMatcher();\n\n\tbool beginsWithNumber(const QString & a_string, int a_matchFrom);\n\n\tint matchedLength() const;\n\nprivate:\n\n\tenum State\n\t{\n\t\tInitial,\n\t\tFirstZero, // Valid final state\n\t\tBinLiteral,\n\t\tBinNumber, // Valid final state\n\t\tOctLiteral,\n\t\tOctNumber, // Valid final state\n\t\tHexLiteral,\n\t\tHexNumber, // Valid final state\n\t\tInteger, // Valid final state\n\t\tDotAfterInteger, // Valid final state\n\t\tFirstDot,\n\t\tFraction, // Valid final state\n\t\tExpLiteral,\n\t\tExpSign,\n\t\tExpComplete, // Valid final state\n\t};\n\n\tState m_state;\n\n\tint m_lastValidLength;\n};\n\n#endif // NUMBERMATCHER_H_INCLUDED\n"
  },
  {
    "path": "vsedit/src/script_editor/script_completer.cpp",
    "content": "#include \"script_completer.h\"\n\n//==============================================================================\n\nScriptCompleter::ScriptCompleter(QAbstractItemModel * a_pModel,\n\tQObject * a_pParent) : QCompleter(a_pModel, a_pParent)\n{\n\n}\n\n//==============================================================================\n\nScriptCompleter::~ScriptCompleter()\n{\n\n}\n\n//==============================================================================\n\nQString ScriptCompleter::pathFromIndex(const QModelIndex & a_index) const\n{\n\tif(!a_index.isValid())\n\t\treturn QString();\n\n\tQString path = model()->data(a_index, Qt::EditRole).toString();\n\tQModelIndex index = a_index;\n\twhile(index.parent().isValid())\n\t{\n\t\tindex = index.parent();\n\t\tpath.prepend('.');\n\t\tpath.prepend(model()->data(index, Qt::EditRole).toString());\n\t}\n\n\treturn path;\n}\n\n//==============================================================================\n\nQStringList ScriptCompleter::splitPath(const QString & a_path) const\n{\n\treturn a_path.split('.');\n}\n\n//==============================================================================\n"
  },
  {
    "path": "vsedit/src/script_editor/script_completer.h",
    "content": "#ifndef SCRIPTCOMPLETER_H\n#define SCRIPTCOMPLETER_H\n\n#include <QCompleter>\n\nclass ScriptCompleter : public QCompleter\n{\n\tQ_OBJECT\n\npublic:\n\n\tScriptCompleter(QAbstractItemModel * a_pModel,\n\t\tQObject * a_pParent = nullptr);\n\n\tvirtual ~ScriptCompleter();\n\n\tQString pathFromIndex(const QModelIndex & a_index) const;\n\n\tQStringList splitPath(const QString & a_path) const;\n};\n\n#endif // SCRIPTCOMPLETER_H\n"
  },
  {
    "path": "vsedit/src/script_editor/script_completer_model.cpp",
    "content": "#include \"script_completer_model.h\"\n\n#include <algorithm>\n\n//==============================================================================\n\nconst char DEFAULT_CORE_NAME[] = \"core\";\n\n//==============================================================================\n\nScriptCompleterModel::ScriptCompleterModel(QObject * a_pParent):\n\tQStandardItemModel(a_pParent)\n{\n\tsetCoreName(DEFAULT_CORE_NAME);\n}\n\n// END OF ScriptCompleterModel::ScriptCompleterModel(QObject * a_pParent)\n//==============================================================================\n\nScriptCompleterModel::~ScriptCompleterModel()\n{\n\n}\n\n// END OF ScriptCompleterModel::~ScriptCompleterModel()\n//==============================================================================\n\nvoid ScriptCompleterModel::setPluginsList(const VSPluginsList & a_pluginsList)\n{\n\tif(invisibleRootItem()->rowCount() < 1)\n\t\tsetCoreName(DEFAULT_CORE_NAME);\n\n\tQStandardItem * pCoreItem = invisibleRootItem()->child(0, 0);\n\tpCoreItem->removeRows(0, pCoreItem->rowCount());\n\n\tfor(const VSData::Plugin & plugin : a_pluginsList)\n\t{\n\t\tQStandardItem * pPluginItem = new QStandardItem(plugin.pluginNamespace);\n\t\tpCoreItem->appendRow(pPluginItem);\n\t\tfor(const VSData::Function & function : plugin.functions)\n\t\t{\n\t\t\tQStringList argumentsList;\n\t\t\tfor(const VSData::FunctionArgument & argument : function.arguments)\n\t\t\t\targumentsList << argument.name;\n\t\t\tQString signature = QString(\"%1(%2)\").arg(function.name)\n\t\t\t\t.arg(argumentsList.join(\", \"));\n\n\t\t\tQStandardItem * pFunctionItem = new QStandardItem(signature);\n\t\t\tpPluginItem->appendRow(pFunctionItem);\n\t\t}\n\t}\n}\n\n// END OF void ScriptCompleterModel::setPluginsList(\n//\t\tconst VSPluginsList & a_pluginsList)\n//==============================================================================\n\nvoid ScriptCompleterModel::setCoreName(const QString & a_coreName)\n{\n\tQStandardItem * pRootItem = invisibleRootItem();\n\tif(pRootItem->rowCount() == 0)\n\t{\n\t\tQStandardItem * pCoreItem = new QStandardItem(a_coreName);\n\t\tpRootItem->appendRow(pCoreItem);\n\t}\n\telse\n\t{\n\t\tQStandardItem * pCoreItem = pRootItem->child(0, 0);\n\t\tpCoreItem->setText(a_coreName);\n\t}\n}\n\n// END OF void ScriptCompleterModel::setCoreName(const QString & a_coreName)\n//==============================================================================\n"
  },
  {
    "path": "vsedit/src/script_editor/script_completer_model.h",
    "content": "#ifndef SCRIPTCOMPLETERMODEL_H\n#define SCRIPTCOMPLETERMODEL_H\n\n#include \"../vapoursynth/vs_plugin_data.h\"\n\n#include <QStandardItemModel>\n\nclass ScriptCompleterModel : public QStandardItemModel\n{\n\tQ_OBJECT\n\npublic:\n\n\tScriptCompleterModel(QObject * a_pParent = nullptr);\n\n\tvirtual ~ScriptCompleterModel();\n\n\tvoid setPluginsList(const VSPluginsList & a_pluginsList);\n\n\tvoid setCoreName(const QString & a_coreName);\n};\n\n#endif // SCRIPTCOMPLETERMODEL_H\n"
  },
  {
    "path": "vsedit/src/script_editor/script_editor.cpp",
    "content": "#include \"script_editor.h\"\n\n#include \"script_completer_model.h\"\n#include \"script_completer.h\"\n#include \"syntax_highlighter.h\"\n#include \"../../../common-src/settings/settings_manager.h\"\n#include \"../settings/settings_dialog.h\"\n\n#include <QTextBlock>\n#include <QCursor>\n#include <QCompleter>\n#include <QKeyEvent>\n#include <QDragEnterEvent>\n#include <QDragMoveEvent>\n#include <QDropEvent>\n#include <QMimeData>\n#include <QPaintEvent>\n#include <QAbstractItemView>\n#include <QScrollBar>\n#include <QPainter>\n#include <QAction>\n#include <QFileInfo>\n#include <QDir>\n#include <QMenu>\n#include <QRegularExpression>\n#include <algorithm>\n\n//==============================================================================\n\nconst char COMMENT_TOKEN[] = \"#\";\n\n//==============================================================================\n\nScriptEditor::ScriptEditor(QWidget * a_pParent) :\n\tQPlainTextEdit(a_pParent)\n\t, m_pSettingsManager(nullptr)\n\t, m_pSideBox(nullptr)\n\t, m_sideBoxLineWidth(1)\n\t, m_sideBoxTextMargin(3)\n\t, m_pCompleterModel(nullptr)\n\t, m_pCompleter(nullptr)\n\t, m_pSyntaxHighlighter(nullptr)\n\t, m_typedCharacters(0)\n\t, m_charactersTypedToStartCompletion(\n\t\tDEFAULT_CHARACTERS_TYPED_TO_START_COMPLETION)\n\t, m_plainText()\n\t, m_backgroundColor(Qt::white)\n\t, m_activeLineColor(Qt::lightGray)\n\t, m_highlightSelectionMatches(DEFAULT_HIGHLIGHT_SELECTION_MATCHES)\n\t, m_highlightSelectionMatchesMinLength(\n\t\tDEFAULT_HIGHLIGHT_SELECTION_MATCHES_MIN_LENGTH)\n\t, m_commonScriptTextFormat()\n\t, m_tabText(\"\\t\")\n\t, m_spacesInTab(DEFAULT_SPACES_IN_TAB)\n\t, m_pContextMenu(nullptr)\n\t, m_pActionDuplicateSelection(nullptr)\n\t, m_pActionCommentSelection(nullptr)\n\t, m_pActionUncommentSelection(nullptr)\n\t, m_pActionReplaceTabWithSpaces(nullptr)\n\t, m_pActionAutocomplete(nullptr)\n\t, m_pActionMoveTextBlockUp(nullptr)\n\t, m_pActionMoveTextBlockDown(nullptr)\n\t, m_pActionToggleComment(nullptr)\n{\n\tm_pSideBox = new QWidget(this);\n\tm_pSideBox->installEventFilter(this);\n\n\tm_pCompleterModel = new ScriptCompleterModel(this);\n\n\tm_pCompleter = new ScriptCompleter(m_pCompleterModel, this);\n\tm_pCompleter->setWidget(this);\n\tm_pCompleter->setCompletionMode(QCompleter::PopupCompletion);\n\tm_pCompleter->setCaseSensitivity(Qt::CaseInsensitive);\n\tm_pCompleter->setWrapAround(false);\n\n\tm_pSyntaxHighlighter = new SyntaxHighlighter(document());\n\n\tfillVariables();\n\n\tconnect(m_pCompleter, SIGNAL(activated(const QString &)),\n\t\tthis, SLOT(slotInsertCompletion(const QString &)));\n\tconnect(this, SIGNAL(textChanged()), this, SLOT(slotTextChanged()));\n\tconnect(this, SIGNAL(blockCountChanged(int)),\n\t\tthis, SLOT(slotUpdateSideBoxWidth()));\n\tconnect(this, SIGNAL(updateRequest(const QRect &, int)),\n\t\tthis, SLOT(slotUpdateSideBox(const QRect &, int)));\n\tconnect(this, SIGNAL(cursorPositionChanged()),\n\t\tthis, SLOT(slotHighlightCurrentBlockAndMatches()));\n\tconnect(this, SIGNAL(selectionChanged()),\n\t\tthis, SLOT(slotHighlightCurrentBlockAndMatches()));\n\tconnect(this, SIGNAL(customContextMenuRequested(const QPoint &)),\n\t\tthis, SLOT(slotShowCustomMenu(const QPoint &)));\n\n\tsetContextMenuPolicy(Qt::CustomContextMenu);\n}\n\n// END OF ScriptEditor::ScriptEditor(QWidget * a_pParent)\n//==============================================================================\n\nScriptEditor::~ScriptEditor()\n{\n\n}\n\n// END OF ScriptEditor::~ScriptEditor()\n//==============================================================================\n\nQString ScriptEditor::text() const\n{\n\treturn document()->toPlainText();\n}\n\n// END OF QString ScriptEditor::text() const\n//==============================================================================\n\nQPoint ScriptEditor::cursorPosition() const\n{\n\tQTextCursor currentCursor = textCursor();\n\tint line = currentCursor.blockNumber();\n\tint index = currentCursor.positionInBlock();\n\n\treturn QPoint(line, index);\n}\n\n// END OF QPoint ScriptEditor::cursorPosition() const\n//==============================================================================\n\nvoid ScriptEditor::setCursorPosition(const QPoint & a_point)\n{\n\tsetCursorPosition(a_point.x(), a_point.y());\n}\n\n// END OF void ScriptEditor::setCursorPosition(const QPoint & a_point)\n//==============================================================================\n\nvoid ScriptEditor::setCursorPosition(int a_line, int a_index)\n{\n\tint line = std::max(0, std::min(a_line, blockCount() - 1));\n\tQTextBlock block = document()->findBlockByNumber(line);\n\tint index = std::max(0, std::min(a_index, block.length() - 1));\n\tint newCursorPosition = block.position() + index;\n\tQTextCursor newCursor = textCursor();\n\tnewCursor.setPosition(newCursorPosition);\n\tsetTextCursor(newCursor);\n}\n\n// END OF void ScriptEditor::setCursorPosition(int a_line, int a_index)\n//==============================================================================\n\nbool ScriptEditor::isModified() const\n{\n\treturn document()->isModified();\n}\n\n// END OF bool ScriptEditor::isModified() const\n//==============================================================================\n\nvoid ScriptEditor::setModified(bool a_modified)\n{\n\tdocument()->setModified(a_modified);\n}\n\n// END OF void ScriptEditor::setModified(bool a_modified)\n//==============================================================================\n\nvoid ScriptEditor::setPluginsList(const VSPluginsList & a_pluginsList)\n{\n\tm_pCompleterModel->setPluginsList(a_pluginsList);\n\tm_pSyntaxHighlighter->setPluginsList(a_pluginsList);\n\tupdate();\n}\n\n// END OF void ScriptEditor::setPluginsList(const VSPluginsList & a_pluginsList)\n//==============================================================================\n\nvoid ScriptEditor::setSettingsManager(SettingsManager * a_pSettingsManager)\n{\n\tm_pSettingsManager = a_pSettingsManager;\n\tm_pSyntaxHighlighter->setSettingsManager(a_pSettingsManager);\n\tcreateActionsAndMenus();\n\tslotLoadSettings();\n}\n\n// END OF void ScriptEditor::setSettingsManager(\n//\t\tSettingsManager * a_pSettingsManager)\n//==============================================================================\n\nstd::vector<QAction *> ScriptEditor::actionsForMenu() const\n{\n\treturn {m_pActionDuplicateSelection, m_pActionCommentSelection,\n\t\tm_pActionUncommentSelection, m_pActionReplaceTabWithSpaces,\n\t\tm_pActionMoveTextBlockUp, m_pActionMoveTextBlockDown,\n\t\tm_pActionToggleComment};\n}\n\n// END OF std::vector<QAction *> ScriptEditor::actionsForMenu() const\n//==============================================================================\n\nstd::vector<vsedit::VariableToken> ScriptEditor::variables() const\n{\n\tstd::vector<vsedit::VariableToken> cleanVariables = m_variables;\n\tfor(vsedit::VariableToken & variable : cleanVariables)\n\t\tvariable.evaluate = nullptr;\n\treturn cleanVariables;\n}\n\n// END OF std::vector<QAction *> ScriptEditor::actionsForMenu() const\n//==============================================================================\n\nvoid ScriptEditor::slotLoadSettings()\n{\n\tif(!m_pSettingsManager)\n\t\treturn;\n\n\tsetUpdatesEnabled(false);\n\n\tm_pSyntaxHighlighter->slotLoadSettings();\n\n\tm_charactersTypedToStartCompletion =\n\t\tm_pSettingsManager->getCharactersTypedToStartCompletion();\n\n\tm_commonScriptTextFormat = m_pSettingsManager->getTextFormat(\n\t\tTEXT_FORMAT_ID_COMMON_SCRIPT_TEXT);\n\tQFont commonScriptTextFont = m_commonScriptTextFormat.font();\n\tdocument()->setDefaultFont(commonScriptTextFont);\n\n\tm_tabText = m_pSettingsManager->getTabText();\n\tm_spacesInTab = m_pSettingsManager->getSpacesInTab();\n\tQFontMetrics metrics(commonScriptTextFont);\n\tsetTabStopDistance(metrics.horizontalAdvance(' ') * m_spacesInTab);\n\n\tm_backgroundColor = m_pSettingsManager->getColor(COLOR_ID_TEXT_BACKGROUND);\n\tQColor textColor = m_commonScriptTextFormat.foreground().color();\n\n\tQString sheet = QString(\"QFrame {color: %1; background-color: %2;}\")\n\t\t.arg(textColor.name()).arg(m_backgroundColor.name());\n\tsetStyleSheet(sheet);\n\n\tm_activeLineColor = m_pSettingsManager->getColor(COLOR_ID_ACTIVE_LINE);\n\tm_selectionMatchesColor =\n\t\tm_pSettingsManager->getColor(COLOR_ID_SELECTION_MATCHES);\n\tm_highlightSelectionMatches =\n\t\tm_pSettingsManager->getHighlightSelectionMatches();\n\tm_highlightSelectionMatchesMinLength =\n\t\tm_pSettingsManager->getHighlightSelectionMatchesMinLength();\n\n\tQKeySequence hotkey;\n\tfor(QAction * pAction : m_settableActionsList)\n\t{\n\t\thotkey = m_pSettingsManager->getHotkey(pAction->data().toString());\n\t\tpAction->setShortcut(hotkey);\n\t}\n\n\tslotUpdateSideBoxWidth();\n\tslotHighlightCurrentBlockAndMatches();\n\n\tsetUpdatesEnabled(true);\n}\n\n// END OF void ScriptEditor::slotLoadSettings()\n//==============================================================================\n\nvoid ScriptEditor::slotComplete()\n{\n\tQTextCursor currentCursor = textCursor();\n\tQString lineString = currentCursor.block().text();\n\tint cursorIndex = currentCursor.positionInBlock();\n\tint wordStart = cursorIndex;\n\twhile((wordStart > 0) && (lineString[wordStart - 1].isLetterOrNumber() ||\n\t\t(QString(\"._\").contains(lineString[wordStart - 1]))))\n\t\twordStart--;\n\tm_typedCharacters = cursorIndex - wordStart;\n\tQString typedWord = lineString.mid(wordStart, m_typedCharacters);\n\tint charactersAfterDot = m_typedCharacters - typedWord.lastIndexOf('.') - 1;\n\n\tQAction * pAction = qobject_cast<QAction *>(sender());\n\n\tif((charactersAfterDot < m_charactersTypedToStartCompletion) &&\n\t\t(pAction == nullptr))\n\t{\n\t\tm_pCompleter->popup()->hide();\n\t\treturn;\n\t}\n\n\tm_pCompleter->setCompletionPrefix(typedWord);\n\tm_pCompleter->popup()->setCurrentIndex(\n\t\tm_pCompleter->completionModel()->index(0, 0));\n\tQRect cursorRectangle = cursorRect();\n\tcursorRectangle.setWidth(m_pCompleter->popup()->sizeHintForColumn(0)\n\t\t+ m_pCompleter->popup()->verticalScrollBar()->sizeHint().width());\n\n\tm_pCompleter->complete(cursorRectangle);\n}\n\n// END OF void ScriptEditor::slotComplete()\n//==============================================================================\n\nvoid ScriptEditor::slotInsertCompletion(const QString & a_completionString)\n{\n\tQTextCursor currentCursor = textCursor();\n\tcurrentCursor.movePosition(QTextCursor::Left, QTextCursor::KeepAnchor,\n\t\tm_typedCharacters);\n\tcurrentCursor.deleteChar();\n\tsetTextCursor(currentCursor);\n\tinsertPlainText(a_completionString);\n}\n\n// END OF void ScriptEditor::slotInsertCompletion(\n//\t\tconst QString & a_completionString)\n//==============================================================================\n\nvoid ScriptEditor::slotDuplicateSelection()\n{\n\tQTextCursor cursor = textCursor();\n\tint l_selectionStart = cursor.selectionStart();\n\tint l_selectionEnd = cursor.selectionEnd();\n\n\tQString newText = cursor.selectedText();\n\tif(cursor.hasSelection())\n\t{\n\t\tcursor.clearSelection();\n\t}\n\telse\n\t{\n\t\tnewText = cursor.block().text() + QString(\"\\n\");\n\t\tcursor.movePosition(QTextCursor::StartOfBlock);\n\t}\n\tcursor.insertText(newText);\n\n\tcursor.setPosition(l_selectionStart, QTextCursor::MoveAnchor);\n\tcursor.setPosition(l_selectionEnd, QTextCursor::KeepAnchor);\n\tsetTextCursor(cursor);\n}\n\n// END OF void ScriptEditor::slotDuplicateSelection()\n//==============================================================================\n\nvoid ScriptEditor::slotCommentSelection()\n{\n\tinsertSelectedLinesBegin(COMMENT_TOKEN);\n}\n\n// END OF void ScriptEditor::slotCommentSelection()\n//==============================================================================\n\nvoid ScriptEditor::slotUncommentSelection()\n{\n\tremoveSelectedLinesBegin(COMMENT_TOKEN);\n}\n\n// END OF void ScriptEditor::slotUncommentSelection()\n//==============================================================================\n\nvoid ScriptEditor::slotReplaceTabWithSpaces()\n{\n\tconst QString spaces(m_spacesInTab, ' ');\n\tQTextDocument * pDocument = document();\n\tQTextCursor cursor(pDocument);\n\tcursor.beginEditBlock();\n\tQTextCursor newCursor = cursor;\n\twhile(!newCursor.isNull())\n\t{\n\t\tnewCursor = pDocument->find(\"\\t\", newCursor);\n\t\tif(newCursor.hasSelection())\n\t\t\tnewCursor.insertText(spaces);\n\t}\n\tcursor.endEditBlock();\n}\n\n// END OF void ScriptEditor::slotReplaceTabWithSpaces()\n//==============================================================================\n\nvoid ScriptEditor::slotTab()\n{\n\tQTextCursor cursor = textCursor();\n\tif(cursor.hasSelection())\n\t\tinsertSelectedLinesBegin(m_tabText);\n\telse\n\t\tcursor.insertText(m_tabText);\n}\n\n// END OF void ScriptEditor::slotTab()\n//==============================================================================\n\nvoid ScriptEditor::slotBackTab()\n{\n\tQTextCursor cursor = textCursor();\n\tQTextDocument * pDocument = document();\n\tQTextBlock firstBlock = pDocument->findBlock(cursor.selectionStart());\n\tQTextBlock lastBlock = pDocument->findBlock(cursor.selectionEnd());\n\tint firstBlockNumber = firstBlock.blockNumber();\n\tint lastBlockNumber = lastBlock.blockNumber();\n\tcursor.beginEditBlock();\n\tfor(int i = firstBlockNumber; i <= lastBlockNumber; ++i)\n\t{\n\t\tQTextBlock block = pDocument->findBlockByNumber(i);\n\t\tint position = block.position();\n\t\tcursor.setPosition(position);\n\n\t\t// If line begins with set tabulation text - remove it.\n\t\tcursor.setPosition(std::min<int>(position + m_tabText.length(),\n\t\t\tpDocument->characterCount() - 1), QTextCursor::KeepAnchor);\n\t\tif(cursor.selectedText() == m_tabText)\n\t\t{\n\t\t\tcursor.removeSelectedText();\n\t\t\tcontinue;\n\t\t}\n\n\t\t// Else remove standard tabulation character.\n\t\tcursor.setPosition(std::min(position + 1,\n\t\t\tpDocument->characterCount() - 1), QTextCursor::KeepAnchor);\n\t\tif(cursor.selectedText() == \"\\t\")\n\t\t{\n\t\t\tcursor.removeSelectedText();\n\t\t\tcontinue;\n\t\t}\n\n\t\t// Else remove set number of space characters used for tabulation.\n\t\tint tokenLength = 0;\n\t\tint spacesInTab = std::max(1, m_spacesInTab);\n\t\twhile((tokenLength < spacesInTab) &&\n\t\t\t(pDocument->characterAt(position + tokenLength) == ' '))\n\t\t\ttokenLength++;\n\t\tcursor.setPosition(position + tokenLength,\n\t\t\tQTextCursor::KeepAnchor);\n\t\tcursor.removeSelectedText();\n\t}\n\tcursor.endEditBlock();\n}\n\n// END OF void ScriptEditor::slotBackTab()\n//==============================================================================\n\nvoid ScriptEditor::slotHome(bool a_select)\n{\n\tQTextCursor cursor = textCursor();\n\tQTextDocument * pDocument = document();\n\tQTextBlock firstBlock = pDocument->findBlock(cursor.selectionStart());\n\tint blockLength = firstBlock.text().length();\n\tif(blockLength == 0)\n\t\treturn;\n\tint blockStart = firstBlock.position();\n        int position = blockStart;\n\tint endPosition = cursor.selectionEnd();\n\tfor(int i = 0; i < blockLength; ++i)\n\t{\n\t\tQChar character = pDocument->characterAt(position);\n\t\tif(!character.isSpace())\n\t\t\tbreak;\n\t\tposition++;\n\t}\n        if(position == cursor.position())\n            cursor.setPosition(blockStart);\n        else\n            cursor.setPosition(position);\n\tif(a_select)\n\t\tcursor.setPosition(endPosition, QTextCursor::KeepAnchor);\n\tsetTextCursor(cursor);\n}\n\n// END OF void ScriptEditor::slotHome(bool a_select)\n//==============================================================================\n\nvoid ScriptEditor::slotInsertTextAtNewLine(const QString & a_text)\n{\n\tQTextCursor cursor = textCursor();\n\tQTextDocument * pDocument = document();\n\tQTextBlock lastBlock = pDocument->findBlock(cursor.selectionEnd());\n\tcursor.setPosition(lastBlock.position() + lastBlock.text().length());\n\tsetTextCursor(cursor);\n\tinsertPlainText(QString(\"\\n\") + a_text);\n}\n\n// END OF void ScriptEditor::slotInsertTextAtNewLine(const QString & a_text)\n//==============================================================================\n\nvoid ScriptEditor::slotMoveTextBlockUp()\n{\n\tQTextCursor cursor = textCursor();\n\tQTextDocument * pDocument = document();\n\tQTextBlock firstBlock = pDocument->findBlock(cursor.selectionStart());\n\tQTextBlock lastBlock = pDocument->findBlock(cursor.selectionEnd());\n\tint firstBlockNumber = firstBlock.blockNumber();\n\tint lastBlockNumber = lastBlock.blockNumber();\n\n\tif(firstBlockNumber == 0)\n\t\treturn;\n\n\tcursor.beginEditBlock();\n\n\tQTextBlock block = pDocument->findBlockByNumber(firstBlockNumber - 1);\n\tQString blockText = block.text();\n\tcursor.setPosition(block.position());\n\tcursor.setPosition(firstBlock.position(), QTextCursor::KeepAnchor);\n\tcursor.removeSelectedText();\n\n\tblock = pDocument->findBlockByNumber(lastBlockNumber);\n\tif(block.blockNumber() == lastBlockNumber)\n\t{\n\t\tcursor.setPosition(block.position());\n\t\tcursor.insertText(blockText + QString(\"\\n\"));\n\t}\n\telse\n\t{\n\t\tcursor.movePosition(QTextCursor::End);\n\t\tcursor.insertText(QString(\"\\n\") + blockText);\n\t}\n\n\tcursor.endEditBlock();\n\n\t// Workaround for weird behavior when selection is snapped to the end\n\t// of the document\n\tcursor = textCursor();\n\tif(cursor.selectionEnd() < pDocument->lastBlock().position())\n\t\treturn;\n\tlastBlockNumber--;\n\tlastBlock = pDocument->findBlockByNumber(lastBlockNumber);\n\tcursor.setPosition(cursor.selectionStart());\n\tcursor.setPosition(lastBlock.position() + lastBlock.length() - 1,\n\t\tQTextCursor::KeepAnchor);\n\tsetTextCursor(cursor);\n}\n\n// END OF void ScriptEditor::slotMoveTextBlockUp()\n//==============================================================================\n\nvoid ScriptEditor::slotMoveTextBlockDown()\n{\n\tQTextCursor cursor = textCursor();\n\tQTextDocument * pDocument = document();\n\tQTextBlock firstBlock = pDocument->findBlock(cursor.selectionStart());\n\tQTextBlock lastBlock = pDocument->findBlock(cursor.selectionEnd());\n\tint lastBlockNumber = lastBlock.blockNumber();\n\n\tif((lastBlockNumber + 1) == pDocument->blockCount())\n\t\treturn;\n\n\tcursor.beginEditBlock();\n\n\tQTextBlock block = lastBlock.next();\n\tQString blockText = block.text();\n\tif((block.blockNumber() + 1) == pDocument->blockCount())\n\t{\n\t\tcursor.setPosition(lastBlock.position() + lastBlock.length() - 1);\n\t\tcursor.movePosition(QTextCursor::End, QTextCursor::KeepAnchor);\n\t}\n\telse\n\t{\n\t\tcursor.setPosition(block.position());\n\t\tcursor.movePosition(QTextCursor::NextBlock, QTextCursor::KeepAnchor);\n\t}\n\tcursor.removeSelectedText();\n\n\tcursor.setPosition(firstBlock.position());\n\tcursor.insertText(blockText + QString(\"\\n\"));\n\n\tcursor.endEditBlock();\n}\n\n// END OF void ScriptEditor::slotMoveTextBlockDown()\n//==============================================================================\n\nvoid ScriptEditor::slotToggleComment()\n{\n\tQTextCursor cursor = textCursor();\n\tQTextDocument * pDocument = document();\n\tQTextBlock firstBlock = pDocument->findBlock(cursor.selectionStart());\n\tQTextBlock lastBlock = pDocument->findBlock(cursor.selectionEnd());\n\tint firstBlockNumber = firstBlock.blockNumber();\n\tint lastBlockNumber = lastBlock.blockNumber();\n\tQString token(COMMENT_TOKEN);\n\tint tokenLength = token.length();\n\tbool allCommented = true;\n\tcursor.beginEditBlock();\n\n\tfor(int i = firstBlockNumber; i <= lastBlockNumber; ++i)\n\t{\n\t\tQTextBlock block = pDocument->findBlockByNumber(i);\n\t\tint position = block.position();\n\t\tcursor.setPosition(position);\n\t\tcursor.setPosition(std::min(position + tokenLength,\n\t\t\tpDocument->characterCount() - 1), QTextCursor::KeepAnchor);\n\t\tif(cursor.selectedText() != token)\n\t\t{\n\t\t\tallCommented = false;\n\t\t\tbreak;\n\t\t}\n\t}\n\n\tfor(int i = firstBlockNumber; i <= lastBlockNumber; ++i)\n\t{\n\t\tQTextBlock block = pDocument->findBlockByNumber(i);\n\t\tint position = block.position();\n\t\tcursor.setPosition(position);\n\t\tcursor.setPosition(std::min(position + tokenLength,\n\t\t\tpDocument->characterCount() - 1), QTextCursor::KeepAnchor);\n\t\tif(allCommented)\n\t\t\tcursor.removeSelectedText();\n\t\telse if(cursor.selectedText() != token)\n\t\t{\n\t\t\tcursor.setPosition(position);\n\t\t\tcursor.insertText(token);\n\t\t}\n\t}\n\n\tcursor.endEditBlock();\n}\n\n// END OF void ScriptEditor::slotToggleComment()\n//==============================================================================\n\nbool ScriptEditor::eventFilter(QObject * a_pObject, QEvent * a_pEvent)\n{\n\tif((a_pObject == m_pSideBox) && (a_pEvent->type() == QEvent::Paint))\n\t{\n\t\tQPaintEvent * pPaintEvent = static_cast<QPaintEvent *>(a_pEvent);\n\t\tpaintSideBox(pPaintEvent);\n\t\treturn true;\n\t}\n\n\treturn QPlainTextEdit::eventFilter(a_pObject, a_pEvent);\n}\n\n// END OF bool ScriptEditor::eventFilter(QObject * a_pObject, QEvent * a_pEvent)\n//==============================================================================\n\nvoid ScriptEditor::resizeEvent(QResizeEvent * a_pEvent)\n{\n\tQPlainTextEdit::resizeEvent(a_pEvent);\n\n\tQRect cr = contentsRect();\n\tm_pSideBox->setGeometry(QRect(cr.left(), cr.top(), sideBoxWidth(),\n\t\tcr.height()));\n\tslotHighlightCurrentBlockAndMatches();\n}\n\n// END OF void ScriptEditor::resizeEvent(QResizeEvent * a_pEvent)\n//==============================================================================\n\nvoid ScriptEditor::keyPressEvent(QKeyEvent * a_pEvent)\n{\n\tint key = a_pEvent->key();\n\tQt::KeyboardModifiers modifiers = a_pEvent->modifiers();\n\n\tif(m_pCompleter->popup()->isVisible())\n\t{\n\t\t// The following keys are forwarded by the completer to the widget\n\t\tswitch(key)\n\t\t{\n\t\t\tcase Qt::Key_Enter:\n\t\t\tcase Qt::Key_Return:\n\t\t\tcase Qt::Key_Escape:\n\t\t\tcase Qt::Key_Tab:\n\t\t\tcase Qt::Key_Backtab:\n\t\t\t\ta_pEvent->ignore();\n\t\t\t\treturn; // let the completer do default behavior\n\t\t\tcase Qt::Key_Left:\n\t\t\tcase Qt::Key_Right:\n\t\t\t\tm_pCompleter->popup()->hide();\n\t\t\t\tbreak;\n\t\t\tdefault:\n\t\t\t\tbreak;\n\t\t}\n\t}\n\n\tif((key == Qt::Key_Tab) && (modifiers == Qt::NoModifier))\n\t{\n\t\tslotTab();\n\t\treturn;\n\t}\n\n\tif((key == Qt::Key_Backtab) ||\n\t\t((key == Qt::Key_Tab) && (modifiers == Qt::ShiftModifier)))\n\t{\n\t\tslotBackTab();\n\t\treturn;\n\t}\n\n\tif((key == Qt::Key_Home) &&\n\t\t((modifiers == Qt::NoModifier) || (modifiers == Qt::ShiftModifier)))\n\t{\n\t\tbool select = (modifiers == Qt::ShiftModifier);\n\t\tslotHome(select);\n\t\treturn;\n\t}\n\n\tQString textBefore = toPlainText();\n\n\tQPlainTextEdit::keyPressEvent(a_pEvent);\n\n\tif(((key == Qt::Key_Return) && (modifiers == Qt::NoModifier)) ||\n\t\t((key == Qt::Key_Enter) && (modifiers == Qt::KeypadModifier)))\n\t\tindentNewLine();\n\n\tif(textBefore != toPlainText())\n\t\tslotComplete();\n}\n\n// END OF void ScriptEditor::keyPressEvent(QKeyEvent * a_pEvent)\n//==============================================================================\n\nvoid ScriptEditor::dragEnterEvent(QDragEnterEvent * a_pEvent)\n{\n\tif(!a_pEvent->mimeData()->hasUrls())\n\t{\n\t\tQPlainTextEdit::dragEnterEvent(a_pEvent);\n\t\treturn;\n\t}\n\n\tQList<QUrl> urls = a_pEvent->mimeData()->urls();\n\tfor(const QUrl & url : urls)\n\t{\n\t\tif(!url.isLocalFile())\n\t\t{\n\t\t\ta_pEvent->ignore();\n\t\t\treturn;\n\t\t}\n\t}\n\n\ta_pEvent->acceptProposedAction();\n}\n\n// END OF void ScriptEditor::dragEnterEvent(QDragEnterEvent * a_pEvent)\n//==============================================================================\n\nvoid ScriptEditor::dragMoveEvent(QDragMoveEvent * a_pEvent)\n{\n\tif(!a_pEvent->mimeData()->hasUrls())\n\t{\n\t\tQPlainTextEdit::dragMoveEvent(a_pEvent);\n\t\treturn;\n\t}\n\n\tQTextCursor cursor = cursorForPosition(a_pEvent->position().toPoint());\n\tsetTextCursor(cursor);\n\ta_pEvent->acceptProposedAction();\n}\n\n// END OF void ScriptEditor::dragMoveEvent(QDragMoveEvent * a_pEvent)\n//==============================================================================\n\nvoid ScriptEditor::dropEvent(QDropEvent * a_pEvent)\n{\n\tif(!a_pEvent->mimeData()->hasUrls())\n\t{\n\t\tQPlainTextEdit::dropEvent(a_pEvent);\n\t\treturn;\n\t}\n\n\tQList<QUrl> urls = a_pEvent->mimeData()->urls();\n\tQ_ASSERT(urls.size() > 0);\n\n\tif(urls.size() == 1)\n\t{\n\t\tQString filePath = urls[0].toLocalFile();\n\t\tstatic QRegularExpression re = QRegularExpression(\"\\\\.vpy$\");\n\t\tif(re.match(filePath).hasMatch())\n\t\t{\n\t\t\tbool handled = false;\n\t\t\temit signalScriptFileDropped(filePath, &handled);\n\t\t\tif(handled)\n\t\t\t{\n\t\t\t\ta_pEvent->acceptProposedAction();\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\t}\n\n\tQStringList textList;\n\tfor(m_droppedFileNumber = 0; m_droppedFileNumber < urls.size();\n\t\t++m_droppedFileNumber)\n\t{\n\t\tm_droppedFilePath =\n\t\t\tQDir::cleanPath(urls[m_droppedFileNumber].toLocalFile());\n\t\tm_droppedFilePath = QDir::toNativeSeparators(m_droppedFilePath);\n\t\tQString sourceTemplate =\n\t\t\tm_pSettingsManager->getDropFileTemplate(m_droppedFilePath);\n\t\tfor(const vsedit::VariableToken & variable : m_variables)\n\t\t\tsourceTemplate = sourceTemplate.replace(variable.token,\n\t\t\t\tvariable.evaluate());\n\t\ttextList += sourceTemplate;\n\t}\n\tslotInsertTextAtNewLine(textList.join(\"\\n\"));\n\n\ta_pEvent->acceptProposedAction();\n}\n\n// END OF void ScriptEditor::dropEvent(QDropEvent * a_pEvent)\n//==============================================================================\n\nvoid ScriptEditor::slotTextChanged()\n{\n\tQString newPlainText = toPlainText();\n\tif(m_plainText == newPlainText)\n\t\treturn;\n\n\tm_plainText = newPlainText;\n\tQString vsCoreName = getVapourSynthCoreName();\n\tsetChildrenCoreName(vsCoreName);\n}\n\n// END OF void ScriptEditor::slotTextChanged()\n//==============================================================================\n\nvoid ScriptEditor::slotUpdateSideBoxWidth()\n{\n\tsetViewportMargins(sideBoxWidth(), 0, 0, 0);\n}\n\n// END OF void ScriptEditor::slotUpdateSideBoxWidth()\n//==============================================================================\n\nvoid ScriptEditor::slotUpdateSideBox(const QRect & a_rect, int a_dy)\n{\n\tif(a_dy)\n\t\tm_pSideBox->scroll(0, a_dy);\n\telse\n\t\tm_pSideBox->update(0, a_rect.y(), m_pSideBox->width(), a_rect.height());\n}\n\n// END OF void ScriptEditor::slotUpdateSideBox(const QRect & a_rect, int a_dy)\n//==============================================================================\n\nvoid ScriptEditor::slotHighlightCurrentBlockAndMatches()\n{\n\tQTextDocument * pDocument = document();\n\tQList<QTextEdit::ExtraSelection> extraTextSelections;\n\tQTextCursor cursor = textCursor();\n\n\tQString selectedText = cursor.selectedText();\n\n\tcursor.movePosition(QTextCursor::StartOfBlock);\n\tint linesInBlock = cursor.block().lineCount();\n\tfor(int i = 0; i < linesInBlock; ++i)\n\t{\n\t\tQTextEdit::ExtraSelection selection;\n\t\tselection.format.setBackground(m_activeLineColor);\n\t\tselection.format.setProperty(QTextFormat::FullWidthSelection, true);\n\t\tselection.cursor = cursor;\n\t\tselection.cursor.clearSelection();\n\t\textraTextSelections.append(selection);\n\t\tcursor.movePosition(QTextCursor::EndOfLine);\n\t\tcursor.movePosition(QTextCursor::NextCharacter);\n\t}\n\n\tif(m_highlightSelectionMatches &&\n\t\t(selectedText.length() >= m_highlightSelectionMatchesMinLength))\n\t{\n\t\tcursor = QTextCursor(pDocument);\n\t\twhile(true)\n\t\t{\n\t\t\tcursor = pDocument->find(selectedText, cursor);\n\t\t\tif(cursor.isNull())\n\t\t\t\tbreak;\n\t\t\tQTextEdit::ExtraSelection selection;\n\t\t\tselection.format.setBackground(m_selectionMatchesColor);\n\t\t\tselection.cursor = cursor;\n\t\t\textraTextSelections.append(selection);\n\t\t}\n\t}\n\n\tsetExtraSelections(extraTextSelections);\n}\n\n// END OF void ScriptEditor::slotHighlightCurrentBlockAndMatches()\n//==============================================================================\n\nvoid ScriptEditor::slotShowCustomMenu(const QPoint & a_position)\n{\n\tif(m_pContextMenu)\n\t\tdelete m_pContextMenu;\n\n\tm_pContextMenu = createStandardContextMenu();\n\n\tif(m_pSettingsManager)\n\t{\n\t\tm_pContextMenu->addSeparator();\n\t\tstd::vector<QAction *> actionsList = actionsForMenu();\n\t\tfor(QAction * pAction : actionsList)\n\t\t\tm_pContextMenu->addAction(pAction);\n\t}\n\n\tQPoint globalPosition = mapToGlobal(a_position);\n    m_pContextMenu->popup(globalPosition);\n}\n\n// END OF void ScriptEditor::slotShowCustomMenu(const QPoint & a_position)\n//==============================================================================\n\nvoid ScriptEditor::createActionsAndMenus()\n{\n\tif(!m_pSettingsManager)\n\t\treturn;\n\n\tstruct ActionToCreate\n\t{\n\t\tQAction ** ppAction;\n\t\tconst char * id;\n\t\tconst char * slotToConnect;\n\t};\n\n\tActionToCreate actionsToCreate[] =\n\t{\n\t\t{&m_pActionDuplicateSelection, ACTION_ID_DUPLICATE_SELECTION,\n\t\t\tSLOT(slotDuplicateSelection())},\n\t\t{&m_pActionCommentSelection, ACTION_ID_COMMENT_SELECTION,\n\t\t\tSLOT(slotCommentSelection())},\n\t\t{&m_pActionUncommentSelection, ACTION_ID_UNCOMMENT_SELECTION,\n\t\t\tSLOT(slotUncommentSelection())},\n\t\t{&m_pActionReplaceTabWithSpaces, ACTION_ID_REPLACE_TAB_WITH_SPACES,\n\t\t\tSLOT(slotReplaceTabWithSpaces())},\n\t\t{&m_pActionAutocomplete, ACTION_ID_AUTOCOMPLETE,\n\t\t\tSLOT(slotComplete())},\n\t\t{&m_pActionMoveTextBlockUp, ACTION_ID_MOVE_TEXT_BLOCK_UP,\n\t\t\tSLOT(slotMoveTextBlockUp())},\n\t\t{&m_pActionMoveTextBlockDown, ACTION_ID_MOVE_TEXT_BLOCK_DOWN,\n\t\t\tSLOT(slotMoveTextBlockDown())},\n\t\t{&m_pActionToggleComment, ACTION_ID_TOGGLE_COMMENT,\n\t\t\tSLOT(slotToggleComment())},\n\t};\n\n\tfor(ActionToCreate & item : actionsToCreate)\n\t{\n\t\tif(*item.ppAction)\n\t\t\tcontinue;\n\n\t\tQAction * pAction = m_pSettingsManager->createStandardAction(\n\t\t\titem.id, this);\n\t\t*item.ppAction = pAction;\n\t\taddAction(pAction);\n\t\tm_settableActionsList.push_back(pAction);\n\t\tconnect(pAction, SIGNAL(triggered()), this, item.slotToConnect);\n\t}\n}\n\n// END OF void ScriptEditor::createActionsAndMenus()\n//==============================================================================\n\nQString ScriptEditor::getVapourSynthCoreName() const\n{\n\tQString vapourSynthName;\n\tQString vsCoreName = \"core\";\n\tint blocksCount = document()->blockCount();\n\n\t// Search for VapourSynth object.\n\t// Usually looks like: import vapoursynth as vs\n\tint vsImportBlock = -1;\n\tQString searchString(\"import vapoursynth\");\n\tfor(int k = 0; k < blocksCount; ++k)\n\t{\n\t\tQString simplifiedText =\n\t\t\tdocument()->findBlockByNumber(k).text().simplified();\n\t\tint i = simplifiedText.indexOf(searchString);\n\t\tif(i < 0)\n\t\t\tcontinue;\n\n\t\tvapourSynthName = \"vapoursynth\";\n\t\ti += searchString.length();\n\t\tif(simplifiedText.mid(i, 4) == \" as \")\n\t\t{\n\t\t\ti += 4;\n\t\t\tif(!(simplifiedText[i].isLetter() || (simplifiedText[i] == '_')))\n\t\t\t\tcontinue;\n\n\t\t\tint j = i;\n\t\t\tfor(; j < simplifiedText.length(); ++j)\n\t\t\t{\n\t\t\t\tif(!(simplifiedText[j].isLetterOrNumber() ||\n\t\t\t\t\t(simplifiedText[j] == '_')))\n\t\t\t\t\tbreak;\n\t\t\t}\n\t\t\tvapourSynthName = simplifiedText.mid(i, j - i);\n\t\t}\n\n\t\tvsImportBlock = k;\n\t\tbreak;\n\t}\n\n\tif((vsImportBlock < 0) || (vsImportBlock == (blocksCount - 1)))\n\t\treturn vsCoreName;\n\n\t// Search for VapourSynth core creation\n\t// Usually looks like: core = vs.get_core()\n\tsearchString = QString(\"%1.get_core\").arg(vapourSynthName);\n\tfor(int k = vsImportBlock + 1; k < blocksCount; ++k)\n\t{\n\t\tQString simplifiedText =\n\t\t\tdocument()->findBlockByNumber(k).text().simplified();\n\t\tint i = simplifiedText.indexOf(searchString);\n\t\tif(i < 0)\n\t\t\tcontinue;\n\n\t\ti--;\n\t\tif(simplifiedText[i].isSpace())\n\t\t\ti--;\n\t\tif(simplifiedText[i] != '=')\n\t\t\tbreak;\n\t\ti--;\n\t\tif(simplifiedText[i].isSpace())\n\t\t\ti--;\n\t\tint j = i + 1;\n\t\tfor(; i >= 0; --i)\n\t\t{\n\t\t\tif(!(simplifiedText[i].isLetterOrNumber() ||\n\t\t\t\t(simplifiedText[i] == '_')))\n\t\t\t\tbreak;\n\t\t}\n\t\ti++;\n\t\tif(simplifiedText[i].isDigit())\n\t\t\tbreak;\n\n\t\tvsCoreName = simplifiedText.mid(i, j - i);\n\t\treturn vsCoreName;\n\t}\n\n\treturn vsCoreName;\n}\n\n// END OF QString ScriptEditor::getVapourSynthCoreName() const\n//==============================================================================\n\nvoid ScriptEditor::setChildrenCoreName(const QString & a_coreName)\n{\n\tm_pCompleterModel->setCoreName(a_coreName);\n\tm_pSyntaxHighlighter->setCoreName(a_coreName);\n}\n\n// END OF void ScriptEditor::setChildrenCoreName(const QString & a_coreName)\n//\t\tconst\n//==============================================================================\n\nint ScriptEditor::sideBoxWidth() const\n{\n\tQString controlString(\"9\");\n\tint max = std::max(1, blockCount());\n\twhile(max >= 10)\n\t{\n\t\tmax /= 10;\n\t\tcontrolString += \"9\";\n\t}\n\n\tQFont commonTextFont = m_commonScriptTextFormat.font();\n\tQFontMetrics metrics(commonTextFont);\n\n\tint space = metrics.horizontalAdvance(controlString);\n\tspace += m_sideBoxTextMargin * 2;\n\tspace += m_sideBoxLineWidth;\n\n\treturn space;\n}\n\n// END OF int ScriptEditor::sideBoxWidth() const\n//==============================================================================\n\nvoid ScriptEditor::paintSideBox(QPaintEvent * a_pEvent)\n{\n\tQPainter painter(m_pSideBox);\n\tpainter.fillRect(a_pEvent->rect(), m_backgroundColor);\n\n\t// Draw border line between sidebox and text.\n\tQRect borderLineRect = a_pEvent->rect();\n\tborderLineRect.setLeft(borderLineRect.right() - m_sideBoxLineWidth + 1);\n\tpainter.fillRect(borderLineRect, m_activeLineColor);\n\n\t// Draw visible lines numbers.\n\n\tpainter.setPen(m_commonScriptTextFormat.foreground().color());\n\tQFont commonTextFont = m_commonScriptTextFormat.font();\n\tQFontMetrics metrics(commonTextFont);\n\tint labelHeight = metrics.height();\n\tpainter.setFont(commonTextFont);\n\n\tint lineNumberWidth = m_pSideBox->width() - m_sideBoxLineWidth -\n\t\tm_sideBoxTextMargin * 2;\n\tQPointF offset = contentOffset();\n\tint viewportHeight = viewport()->rect().height();\n\tqreal blockTop;\n\tfor(QTextBlock textBlock = firstVisibleBlock();\n\t\ttextBlock.isValid() &&\n\t\t((blockTop = blockBoundingGeometry(textBlock).translated(offset).top())\n\t\t< viewportHeight);\n\t\ttextBlock = textBlock.next())\n\t{\n\t\tif(!textBlock.isVisible())\n\t\t\tcontinue;\n\t\tQString number = QString::number(textBlock.blockNumber() + 1);\n\t\tpainter.drawText(m_sideBoxTextMargin, blockTop, lineNumberWidth,\n\t\t\tlabelHeight, Qt::AlignRight, number);\n\t}\n}\n\n// END OF void ScriptEditor::paintSideBox(QPaintEvent * a_pEvent)\n//==============================================================================\n\nvoid ScriptEditor::indentNewLine()\n{\n\tQTextCursor currentCursor = textCursor();\n\tQTextBlock currentBlock = currentCursor.block();\n\tint blockNumber = currentBlock.blockNumber();\n\tQ_ASSERT(blockNumber != 0);\n\tQTextBlock previousBlock =\n\t\tdocument()->findBlockByNumber(blockNumber - 1);\n\tQString blockText = previousBlock.text();\n\tint blockLength = blockText.length();\n\tQString indentation;\n\tfor(int i = 0; i < blockLength; ++i)\n\t{\n\t\tif(!blockText[i].isSpace())\n\t\t\tbreak;\n\t\tindentation += blockText[i];\n\t}\n\tcurrentCursor.insertText(indentation);\n}\n\n// END OF void ScriptEditor::indentNewLine()\n//==============================================================================\n\nvoid ScriptEditor::insertSelectedLinesBegin(const QString & a_text)\n{\n\tQTextCursor cursor = textCursor();\n\tQTextDocument * pDocument = document();\n\tQTextBlock firstBlock = pDocument->findBlock(cursor.selectionStart());\n\tQTextBlock lastBlock = pDocument->findBlock(cursor.selectionEnd());\n\tint firstBlockNumber = firstBlock.blockNumber();\n\tint lastBlockNumber = lastBlock.blockNumber();\n\tcursor.beginEditBlock();\n\tfor(int i = firstBlockNumber; i <= lastBlockNumber; ++i)\n\t{\n\t\tQTextBlock block = pDocument->findBlockByNumber(i);\n\t\tint position = block.position();\n\t\tcursor.setPosition(position);\n\t\tcursor.insertText(a_text);\n\t}\n\tcursor.endEditBlock();\n}\n\n// END OF void ScriptEditor::insertSelectedLinesBegin(const QString & a_text)\n//==============================================================================\n\nvoid ScriptEditor::removeSelectedLinesBegin(const QString & a_text)\n{\n\tQTextCursor cursor = textCursor();\n\tQTextDocument * pDocument = document();\n\tQTextBlock firstBlock = pDocument->findBlock(cursor.selectionStart());\n\tQTextBlock lastBlock = pDocument->findBlock(cursor.selectionEnd());\n\tint firstBlockNumber = firstBlock.blockNumber();\n\tint lastBlockNumber = lastBlock.blockNumber();\n\tint tokenLength = a_text.length();\n\tcursor.beginEditBlock();\n\tfor(int i = firstBlockNumber; i <= lastBlockNumber; ++i)\n\t{\n\t\tQTextBlock block = pDocument->findBlockByNumber(i);\n\t\tint position = block.position();\n\t\tcursor.setPosition(position);\n\t\tcursor.setPosition(std::min(position + tokenLength,\n\t\t\tpDocument->characterCount() - 1), QTextCursor::KeepAnchor);\n\t\tif(cursor.selectedText() == a_text)\n\t\t\tcursor.removeSelectedText();\n\t}\n\tcursor.endEditBlock();\n}\n\n// END OF void ScriptEditor::removeSelectedLinesBegin(const QString & a_text)\n//==============================================================================\n\nvoid ScriptEditor::fillVariables()\n{\n\tm_variables =\n\t{\n\t\t{\"{f}\", tr(\"file path\"),\n\t\t\t[&]()\n\t\t\t{\n\t\t\t\treturn m_droppedFilePath;\n\t\t\t}\n\t\t},\n\n\t\t{\"{d}\", tr(\"file directory\"),\n\t\t\t[&]()\n\t\t\t{\n\t\t\t\tQFileInfo file(m_droppedFilePath);\n\t\t\t\treturn QDir::toNativeSeparators(file.path());\n\t\t\t}\n\t\t},\n\n\t\t{\"{n}\", tr(\"file name\"),\n\t\t\t[&]()\n\t\t\t{\n\t\t\t\tQFileInfo file(m_droppedFilePath);\n\t\t\t\treturn file.completeBaseName();\n\t\t\t}\n\t\t},\n\n\t\t{\"{x}\", tr(\"file extension\"),\n\t\t\t[&]()\n\t\t\t{\n\t\t\t\tQFileInfo file(m_droppedFilePath);\n\t\t\t\treturn file.suffix();\n\t\t\t}\n\t\t},\n\n\t\t{\"{i}\", tr(\"file number in the list of dropped files\"),\n\t\t\t[&]()\n\t\t\t{\n\t\t\t\treturn m_droppedFileNumber > 0 ?\n\t\t\t\t\tQString::number(m_droppedFileNumber + 1) : QString();\n\t\t\t}\n\t\t},\n\t};\n\n\tstd::sort(m_variables.begin(), m_variables.end(),\n\t\t[&](const vsedit::VariableToken & a_first,\n\t\t\tconst vsedit::VariableToken & a_second) -> bool\n\t\t{\n\t\t\treturn (a_first.token.length() > a_second.token.length());\n\t\t});\n}\n\n// END OF void ScriptEditor::fillVariables()\n//==============================================================================\n"
  },
  {
    "path": "vsedit/src/script_editor/script_editor.h",
    "content": "#ifndef SCRIPTEDITOR_H\n#define SCRIPTEDITOR_H\n\n#include \"../../../common-src/helpers.h\"\n#include \"../vapoursynth/vs_plugin_data.h\"\n\n#include <QPlainTextEdit>\n#include <QPoint>\n#include <vector>\n\nclass QEvent;\nclass QKeyEvent;\nclass QResizeEvent;\nclass QPaintEvent;\nclass QDragEnterEvent;\nclass QDragMoveEvent;\nclass QDropEvent;\nclass QAction;\nclass ScriptCompleterModel;\nclass ScriptCompleter;\nclass SyntaxHighlighter;\nclass SettingsManager;\nclass SettingsDialog;\n\nclass ScriptEditor : public QPlainTextEdit\n{\n\tQ_OBJECT\n\npublic:\n\n\tScriptEditor(QWidget * a_pParent = nullptr);\n\n\tvirtual ~ScriptEditor();\n\n\tQString text() const;\n\n\tQPoint cursorPosition() const;\n\n\tvoid setCursorPosition(const QPoint & a_point);\n\n\tvoid setCursorPosition(int a_line, int a_index);\n\n\tbool isModified() const;\n\n\tvoid setModified(bool a_modified);\n\n\tvoid setPluginsList(const VSPluginsList & a_pluginsList);\n\n\tvoid setSettingsManager(SettingsManager * a_pSettingsManager);\n\n\tstd::vector<QAction *> actionsForMenu() const;\n\n\tstd::vector<vsedit::VariableToken> variables() const;\n\npublic slots:\n\n\tvoid slotLoadSettings();\n\n\tvoid slotComplete();\n\n\tvoid slotInsertCompletion(const QString & a_completionString);\n\n\tvoid slotDuplicateSelection();\n\n\tvoid slotCommentSelection();\n\n\tvoid slotUncommentSelection();\n\n\tvoid slotReplaceTabWithSpaces();\n\n\tvoid slotTab();\n\n\tvoid slotBackTab();\n\n\tvoid slotHome(bool a_select = false);\n\n\tvoid slotInsertTextAtNewLine(const QString & a_text);\n\n\tvoid slotMoveTextBlockUp();\n\n\tvoid slotMoveTextBlockDown();\n\n\tvoid slotToggleComment();\n\nsignals:\n\n\tvoid signalScriptFileDropped(const QString & a_filePath, bool * a_pHandled);\n\nprotected:\n\n\tvirtual bool eventFilter(QObject * a_pObject, QEvent * a_pEvent) override;\n\n\tvirtual void resizeEvent(QResizeEvent * a_pEvent) override;\n\n\tvirtual void keyPressEvent(QKeyEvent * a_pEvent) override;\n\n\tvirtual void dragEnterEvent(QDragEnterEvent * a_pEvent) override;\n\n\tvirtual void dragMoveEvent(QDragMoveEvent * a_pEvent) override;\n\n\tvirtual void dropEvent(QDropEvent * a_pEvent) override;\n\nprivate slots:\n\n\tvoid slotTextChanged();\n\n\tvoid slotUpdateSideBoxWidth();\n\n\tvoid slotUpdateSideBox(const QRect & a_rect, int a_dy);\n\n\tvoid slotHighlightCurrentBlockAndMatches();\n\n\tvoid slotShowCustomMenu(const QPoint & a_position);\n\nprivate:\n\n\tvoid createActionsAndMenus();\n\n\tQString getVapourSynthCoreName() const;\n\n\tvoid setChildrenCoreName(const QString & a_coreName);\n\n\tint sideBoxWidth() const;\n\n\tvoid paintSideBox(QPaintEvent * a_pEvent);\n\n\tvoid indentNewLine();\n\n\tvoid insertSelectedLinesBegin(const QString & a_text);\n\tvoid removeSelectedLinesBegin(const QString & a_text);\n\n\tvoid fillVariables();\n\n\tSettingsManager * m_pSettingsManager;\n\n\tQWidget * m_pSideBox;\n\n\tint m_sideBoxLineWidth;\n\n\tint m_sideBoxTextMargin;\n\n\tScriptCompleterModel * m_pCompleterModel;\n\n\tScriptCompleter * m_pCompleter;\n\n\tSyntaxHighlighter * m_pSyntaxHighlighter;\n\n\tint m_typedCharacters;\n\n\tint m_charactersTypedToStartCompletion;\n\n\tQString m_plainText;\n\n\tQColor m_backgroundColor;\n\n\tQColor m_activeLineColor;\n\n\tQColor m_selectionMatchesColor;\n\n\tbool m_highlightSelectionMatches;\n\n\tint m_highlightSelectionMatchesMinLength;\n\n\tQTextCharFormat m_commonScriptTextFormat;\n\n\tQString m_tabText;\n\n\tint m_spacesInTab;\n\n\tQMenu * m_pContextMenu;\n\tQAction * m_pActionDuplicateSelection;\n\tQAction * m_pActionCommentSelection;\n\tQAction * m_pActionUncommentSelection;\n\tQAction * m_pActionReplaceTabWithSpaces;\n\tQAction * m_pActionAutocomplete;\n\tQAction * m_pActionMoveTextBlockUp;\n\tQAction * m_pActionMoveTextBlockDown;\n\tQAction * m_pActionToggleComment;\n\n\tstd::vector<QAction *> m_settableActionsList;\n\n\tQString m_droppedFilePath;\n\tint m_droppedFileNumber;\n\n\tstd::vector<vsedit::VariableToken> m_variables;\n};\n\n#endif // SCRIPTEDITOR_H\n"
  },
  {
    "path": "vsedit/src/script_editor/syntax_highlighter.cpp",
    "content": "#include \"syntax_highlighter.h\"\n\n#include \"number_matcher.h\"\n#include \"../../../common-src/settings/settings_manager.h\"\n\n#include <vector>\n#include <algorithm>\n\n//==============================================================================\n\n// Text block states: 0 - 80 are used for indentation value.\n// Larger values are special cases.\n\nenum class BlockState : int\n{\n\tLongStringSingleStart = 81,\n\tLongStringSingleMiddle,\n\tLongStringDoubleStart,\n\tLongStringDoubleMiddle\n};\n\nenum class TokenType\n{\n\tUndecided,\n\tKeyword,\n\tOperator,\n\tString,\n\tNumber,\n\tComment,\n\tVSCore,\n\tVSNamespace,\n\tVSFunction,\n};\n\nstruct Token\n{\n\tQString text;\n\tint start;\n\tint length;\n\tTokenType type;\n\n\tToken(const QString & a_text, int a_start, int a_length, TokenType a_type):\n\t\ttext(a_text), start(a_start), length(a_length), type(a_type){}\n};\n\n//==============================================================================\n\nSyntaxHighlighter::SyntaxHighlighter(QTextDocument * a_pDocument,\n\tVSPluginsList a_pluginsList) : QSyntaxHighlighter(a_pDocument)\n\t, m_pSettingsManager(nullptr)\n\t, m_coreName(\"core\")\n\t, m_pluginsList(a_pluginsList)\n\t, m_keywordsList()\n\t, m_operatorsList()\n\t, m_keywordFormat()\n\t, m_operatorFormat()\n\t, m_stringFormat()\n\t, m_numberFormat()\n\t, m_commentFormat()\n\t, m_vsCoreFormat()\n\t, m_vsNamespaceFormat()\n\t, m_vsFunctionFormat()\n\t, m_vsArgumentFormat()\n{\n\tm_keywordsList << \"False\" << \"None\" << \"True\" << \"and\" << \"as\" <<\n                \"assert\" << \"break\" << \"case\" << \"class\" << \"continue\" << \"def\" <<\n                \"del\" << \"elif\" << \"else\" << \"except\" << \"finally\" << \"for\" <<\n                \"from\" << \"global\" << \"if\" << \"import\" << \"in\" << \"is\" << \"lambda\" <<\n                \"match\" << \"nonlocal\" << \"not\" << \"or\" << \"pass\" << \"raise\" <<\n                \"return\" << \"try\" << \"while\" << \"with\" << \"yield\";\n\n\t// MUST be sorted by length in descending order.\n\tm_operatorsList << \"//=\" << \">>=\" << \"<<=\" << \"**=\" << \"**\" << \"//\" <<\n\t\t\"<<\" << \">>\" << \"<=\" << \">=\" << \"==\" << \"!=\" << \"->\" << \"+=\" << \"-=\" <<\n\t\t\"*=\" << \"/=\" << \"%=\" << \"&=\" << \"|=\" << \"^=\" << \"+\" << \"-\" << \"*\" <<\n\t\t\"/\" << \"%\" << \"&\" << \"|\" << \"^\" << \"~\" << \"<\" << \">\" << \"(\" << \")\" <<\n\t\t\"[\" << \"]\" << \"{\" << \"}\" << \",\" << \":\" << \".\" << \";\" << \"@\" << \"=\";\n\t// Don't trust yourself. Sort it.\n\tstd::sort(m_operatorsList.begin(), m_operatorsList.end(),\n\t\t[&](const QString & a_first, const QString & a_second)->bool\n\t\t{\n\t\t\treturn (a_first.length() > a_second.length());\n\t\t});\n}\n\n// END OF SyntaxHighlighter::SyntaxHighlighter(QTextDocument * a_pDocument,\n//\t\tVSPluginsList a_pluginsList)\n//==============================================================================\n\nSyntaxHighlighter::~SyntaxHighlighter()\n{\n\n}\n\n// END OF SyntaxHighlighter::~SyntaxHighlighter()\n//==============================================================================\n\nvoid SyntaxHighlighter::setSettingsManager(SettingsManager * a_pSettingsManager)\n{\n\tm_pSettingsManager = a_pSettingsManager;\n\tslotLoadSettings();\n}\n\n// END OF void SyntaxHighlighter::setSettingsManager(\n//\t\tSettingsManager * a_pSettingsManager)\n//==============================================================================\n\nvoid SyntaxHighlighter::setCoreName(const QString & a_coreName)\n{\n\tif(m_coreName == a_coreName)\n\t\treturn;\n\n\tm_coreName = a_coreName;\n\trehighlight();\n}\n\n// END OF void SyntaxHighlighter::setCoreName(const QString & a_coreName)\n//==============================================================================\n\nvoid SyntaxHighlighter::setPluginsList(VSPluginsList a_pluginsList)\n{\n\tm_pluginsList = a_pluginsList;\n}\n\n// END OF void SyntaxHighlighter::setPluginsList(VSPluginsList a_pluginsList)\n//==============================================================================\n\nvoid SyntaxHighlighter::slotLoadSettings()\n{\n\tm_keywordFormat = m_pSettingsManager->getTextFormat(\n\t\tTEXT_FORMAT_ID_KEYWORD);\n\tm_operatorFormat = m_pSettingsManager->getTextFormat(\n\t\tTEXT_FORMAT_ID_OPERATOR);\n\tm_stringFormat = m_pSettingsManager->getTextFormat(\n\t\tTEXT_FORMAT_ID_STRING);\n\tm_numberFormat = m_pSettingsManager->getTextFormat(\n\t\tTEXT_FORMAT_ID_NUMBER);\n\tm_commentFormat = m_pSettingsManager->getTextFormat(\n\t\tTEXT_FORMAT_ID_COMMENT);\n\tm_vsCoreFormat = m_pSettingsManager->getTextFormat(\n\t\tTEXT_FORMAT_ID_VS_CORE);\n\tm_vsNamespaceFormat = m_pSettingsManager->getTextFormat(\n\t\tTEXT_FORMAT_ID_VS_NAMESPACE);\n\tm_vsFunctionFormat = m_pSettingsManager->getTextFormat(\n\t\tTEXT_FORMAT_ID_VS_FUNCTION);\n\tm_vsArgumentFormat = m_pSettingsManager->getTextFormat(\n\t\tTEXT_FORMAT_ID_VS_ARGUMENT);\n\trehighlight();\n}\n\n// END OF void SyntaxHighlighter::slotLoadSettings()\n//==============================================================================\n\nvoid SyntaxHighlighter::highlightBlock(const QString & a_text)\n{\n\tsetCurrentBlockState(0);\n\tstd::vector<Token> tokens;\n\n\tint i = 0;\n\tint j = 0;\n\tint textLength = a_text.length();\n\tbool goToNextToken = false;\n\n\twhile(i < textLength)\n\t{\n//------Long string continuation, single quotes---------------------------------\n\n\t\tif((i == 0) && (\n\t\t\t(previousBlockState() == (int)BlockState::LongStringSingleStart) ||\n\t\t\t(previousBlockState() == (int)BlockState::LongStringSingleMiddle)))\n\t\t{\n\t\t\tbool foundMatchingQuotes = false;\n\t\t\tfor(j = i; j < textLength - 2; ++j)\n\t\t\t{\n\t\t\t\tif((a_text.mid(j, 3) == \"'''\") &&\n\t\t\t\t\t((j == 0) || ((j != 0) && (a_text[j - 1] != '\\\\'))))\n\t\t\t\t{\n\t\t\t\t\tfoundMatchingQuotes = true;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif(foundMatchingQuotes)\n\t\t\t{\n\t\t\t\tj += 3;\n\t\t\t\tToken newToken(a_text.mid(i, j-i), i, j, TokenType::String);\n\t\t\t\ttokens.push_back(newToken);\n\t\t\t\ti = j;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tsetCurrentBlockState((int)BlockState::LongStringSingleMiddle);\n\t\t\t\tsetFormat(0, a_text.length(), m_stringFormat);\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\n//------Long string continuation, double quotes---------------------------------\n\n\t\tif((i == 0) && (\n\t\t\t(previousBlockState() == (int)BlockState::LongStringDoubleStart) ||\n\t\t\t(previousBlockState() == (int)BlockState::LongStringDoubleMiddle)))\n\t\t{\n\t\t\tbool foundMatchingQuotes = false;\n\t\t\tfor(j = i; j < textLength - 2; ++j)\n\t\t\t{\n\t\t\t\tif((a_text.mid(j, 3) == \"\\\"\\\"\\\"\") &&\n\t\t\t\t\t((j == 0) || ((j != 0) && (a_text[j - 1] != '\\\\'))))\n\t\t\t\t{\n\t\t\t\t\tfoundMatchingQuotes = true;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif(foundMatchingQuotes)\n\t\t\t{\n\t\t\t\tj += 3;\n\t\t\t\tToken newToken(a_text.mid(i, j-i), i, j - i, TokenType::String);\n\t\t\t\ttokens.push_back(newToken);\n\t\t\t\ti = j;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tsetCurrentBlockState((int)BlockState::LongStringDoubleMiddle);\n\t\t\t\tsetFormat(0, a_text.length(), m_stringFormat);\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\n//------Long string, single quotes.---------------------------------------------\n\n\t\tif((((a_text[i].toLower() == 'r') || (a_text[i].toLower() == 'u')) &&\n\t\t\t(a_text.mid(i + 1, 3) == \"'''\")) || (a_text.mid(i, 3) == \"'''\"))\n\t\t{\n\t\t\tif(a_text[i] == '\\'')\n\t\t\t\tj = i + 3;\n\t\t\telse\n\t\t\t\tj = i + 4;\n\n\t\t\tbool foundMatchingQuotes = false;\n\t\t\tfor(; j < textLength - 2; ++j)\n\t\t\t{\n\t\t\t\tif((a_text.mid(j, 3) == \"'''\") &&\n\t\t\t\t\t((j == 0) || ((j != 0) && (a_text[j - 1] != '\\\\'))))\n\t\t\t\t{\n\t\t\t\t\tfoundMatchingQuotes = true;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif(foundMatchingQuotes)\n\t\t\t{\n\t\t\t\tj += 3 - i;\n\t\t\t\tToken newToken(a_text.mid(i, j), i, j, TokenType::String);\n\t\t\t\ttokens.push_back(newToken);\n\t\t\t\ti += j;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tj = textLength - i;\n\t\t\t\tToken newToken(a_text.mid(i, j), i, j, TokenType::String);\n\t\t\t\ttokens.push_back(newToken);\n\t\t\t\tsetCurrentBlockState((int)BlockState::LongStringSingleStart);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n//------Long string, double quotes----------------------------------------------\n\n\t\tif((((a_text[i].toLower() == 'r') || (a_text[i].toLower() == 'u')) &&\n\t\t\t(a_text.mid(i + 1, 3) == \"\\\"\\\"\\\"\")) ||\n\t\t\t(a_text.mid(i, 3) == \"\\\"\\\"\\\"\"))\n\t\t{\n\t\t\tif(a_text[i] == '\\\"')\n\t\t\t\tj = i + 3;\n\t\t\telse\n\t\t\t\tj = i + 4;\n\n\t\t\tbool foundMatchingQuotes = false;\n\t\t\tfor(; j < textLength - 2; ++j)\n\t\t\t{\n\t\t\t\tif((a_text.mid(j, 3) == \"\\\"\\\"\\\"\") &&\n\t\t\t\t\t((j == 0) || ((j != 0) && (a_text[j - 1] != '\\\\'))))\n\t\t\t\t{\n\t\t\t\t\tfoundMatchingQuotes = true;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif(foundMatchingQuotes)\n\t\t\t{\n\t\t\t\tj += 3 - i;\n\t\t\t\tToken newToken(a_text.mid(i, j), i, j, TokenType::String);\n\t\t\t\ttokens.push_back(newToken);\n\t\t\t\ti += j;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tj = textLength - i;\n\t\t\t\tToken newToken(a_text.mid(i, j), i, j, TokenType::String);\n\t\t\t\ttokens.push_back(newToken);\n\t\t\t\tsetCurrentBlockState((int)BlockState::LongStringDoubleStart);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n//------Short string, single quotes---------------------------------------------\n\n\t\tif((a_text[i] == '\\'') || (a_text.mid(i, 2).toLower() == \"r'\") ||\n\t\t\t(a_text.mid(i, 2).toLower() == \"u'\"))\n\t\t{\n\t\t\tif(a_text[i] == '\\'')\n\t\t\t\tj = i + 1;\n\t\t\telse\n\t\t\t\tj = i + 2;\n\n\t\t\tfor(; j < textLength; ++j)\n\t\t\t{\n\t\t\t\tif((a_text[j] == '\\'') &&\n\t\t\t\t\t((j == 0) || ((j != 0) && (a_text[j - 1] != '\\\\'))))\n\t\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tj += 1 - i;\n\t\t\tToken newToken(a_text.mid(i, j), i, j, TokenType::String);\n\t\t\ttokens.push_back(newToken);\n\t\t\ti += j;\n\t\t\tcontinue;\n\t\t}\n\n//------Short string, double quotes---------------------------------------------\n\n\t\tif((a_text[i] == '\\\"') || (a_text.mid(i, 2).toLower() == \"r\\\"\") ||\n\t\t\t(a_text.mid(i, 2).toLower() == \"u\\\"\"))\n\t\t{\n\t\t\tif(a_text[i] == '\\\"')\n\t\t\t\tj = i + 1;\n\t\t\telse\n\t\t\t\tj = i + 2;\n\n\t\t\tfor(; j < textLength; ++j)\n\t\t\t{\n\t\t\t\tif((a_text[j] == '\\\"') &&\n\t\t\t\t\t((j == 0) || ((j != 0) && (a_text[j - 1] != '\\\\'))))\n\t\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tj += 1 - i;\n\t\t\tToken newToken(a_text.mid(i, j), i, j, TokenType::String);\n\t\t\ttokens.push_back(newToken);\n\t\t\ti += j;\n\t\t\tcontinue;\n\t\t}\n\n//------Comment-----------------------------------------------------------------\n\n\t\tif(a_text[i] == '#')\n\t\t{\n\t\t\tj = a_text.length();\n\t\t\tToken newToken(a_text.mid(i, j-i), i, j, TokenType::Comment);\n\t\t\ttokens.push_back(newToken);\n\t\t\tbreak;\n\t\t}\n\n//------Keyword or unknown word-------------------------------------------------\n\n\t\tif((a_text[i].isLetter()) || (a_text[i] == '_'))\n\t\t{\n\t\t\tfor(j = i; j < textLength; ++j)\n\t\t\t{\n\t\t\t\tif(!(a_text[j].isLetterOrNumber() || (a_text[j] == '_')))\n\t\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tj = j - i;\n\t\t\tQString word = a_text.mid(i, j);\n\t\t\tToken newToken(word, i, j , TokenType::Undecided);\n\t\t\tfor(const QString & keyword : m_keywordsList)\n\t\t\t{\n\t\t\t\tif(word == keyword)\n\t\t\t\t{\n\t\t\t\t\tnewToken.type = TokenType::Keyword;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t\ttokens.push_back(newToken);\n\t\t\ti += j;\n\t\t\tcontinue;\n\t\t}\n\n//------Number------------------------------------------------------------------\n\n\t\tNumberMatcher matcher;\n\t\tif(matcher.beginsWithNumber(a_text, i))\n\t\t{\n\t\t\tj = matcher.matchedLength();\n\t\t\tToken newToken(a_text.mid(i, j), i, j, TokenType::Number);\n\t\t\ttokens.push_back(newToken);\n\t\t\ti += j;\n\t\t\tcontinue;\n\t\t}\n\n//------Operator----------------------------------------------------------------\n\n\t\tgoToNextToken = false;\n\t\tfor(const QString & operatorString : m_operatorsList)\n\t\t{\n\t\t\tif(goToNextToken)\n\t\t\t\tbreak;\n\n\t\t\tj = operatorString.length();\n\t\t\tQString substring = a_text.mid(i, j);\n\t\t\tif(substring == operatorString)\n\t\t\t{\n\t\t\t\tToken newToken(substring, i, j, TokenType::Operator);\n\t\t\t\ttokens.push_back(newToken);\n\t\t\t\ti += j;\n\t\t\t\tgoToNextToken = true;\n\t\t\t}\n\t\t}\n\t\tif(goToNextToken)\n\t\t\tcontinue;\n\n//------------------------------------------------------------------------------\n\n\t\ti++;\n\t}\n\n\tsize_t tokensNumber = tokens.size();\n\n\tif(tokensNumber == 0)\n\t\tsetCurrentBlockState(previousBlockState());\n\n\tfor(size_t k = 0; k < tokensNumber; ++k)\n\t{\n\t\tToken & token = tokens[k];\n\n\t\tif(token.text == m_coreName)\n\t\t\ttoken.type = TokenType::VSCore;\n\t\telse if((k > 1) && (tokens[k - 1].text == \".\") &&\n\t\t\t(tokens[k - 2].type == TokenType::VSCore))\n\t\t{\n\t\t\tfor(const VSData::Plugin & plugin : m_pluginsList)\n\t\t\t{\n\t\t\t\tif(token.text == plugin.pluginNamespace)\n\t\t\t\t{\n\t\t\t\t\ttoken.type = TokenType::VSNamespace;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\telse if((k > 3) && (tokens[k - 1].text == \".\") &&\n\t\t\t(tokens[k - 2].type == TokenType::VSNamespace) &&\n\t\t\t(tokens[k - 3].text == \".\") &&\n\t\t\t(tokens[k - 4].type == TokenType::VSCore))\n\t\t{\n\t\t\tbool foundFunction = false;\n\t\t\tfor(const VSData::Plugin & plugin : m_pluginsList)\n\t\t\t{\n\t\t\t\tfoundFunction = false;\n\t\t\t\tif(tokens[k - 2].text == plugin.pluginNamespace)\n\t\t\t\t{\n\t\t\t\t\tfor(const VSData::Function & function : plugin.functions)\n\t\t\t\t\t{\n\t\t\t\t\t\tif(token.text == function.name)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\ttoken.type = TokenType::VSFunction;\n\t\t\t\t\t\t\tfoundFunction = true;\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tif(foundFunction)\n\t\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif(token.type == TokenType::Keyword)\n\t\t\tsetFormat(token.start, token.length, m_keywordFormat);\n\t\telse if(token.type == TokenType::Operator)\n\t\t\tsetFormat(token.start, token.length, m_operatorFormat);\n\t\telse if(token.type == TokenType::String)\n\t\t\tsetFormat(token.start, token.length, m_stringFormat);\n\t\telse if(token.type == TokenType::Number)\n\t\t\tsetFormat(token.start, token.length, m_numberFormat);\n\t\telse if(token.type == TokenType::Comment)\n\t\t\tsetFormat(token.start, token.length, m_commentFormat);\n\t\telse if(token.type == TokenType::VSCore)\n\t\t\tsetFormat(token.start, token.length, m_vsCoreFormat);\n\t\telse if(token.type == TokenType::VSNamespace)\n\t\t\tsetFormat(token.start, token.length, m_vsNamespaceFormat);\n\t\telse if(token.type == TokenType::VSFunction)\n\t\t\tsetFormat(token.start, token.length, m_vsFunctionFormat);\n\n\t}\n}\n\n// END OF void SyntaxHighlighter::highlightBlock(const QString & a_text)\n//==============================================================================\n"
  },
  {
    "path": "vsedit/src/script_editor/syntax_highlighter.h",
    "content": "#ifndef SYNTAXHIGHLIGHTER_H\n#define SYNTAXHIGHLIGHTER_H\n\n#include \"../vapoursynth/vs_plugin_data.h\"\n\n#include <QSyntaxHighlighter>\n#include <QTextCharFormat>\n#include <QStringList>\n\nclass SettingsManager;\n\nclass SyntaxHighlighter : public QSyntaxHighlighter\n{\n\tQ_OBJECT\n\npublic:\n\n\tSyntaxHighlighter(QTextDocument * a_pDocument,\n\t\tVSPluginsList a_pluginsList = VSPluginsList());\n\tvirtual ~SyntaxHighlighter();\n\n\tvoid setSettingsManager(SettingsManager * a_pSettingsManager);\n\n\tvoid setCoreName(const QString & a_coreName);\n\n\tvoid setPluginsList(VSPluginsList a_pluginsList);\n\npublic slots:\n\n\tvoid slotLoadSettings();\n\nprotected:\n\n\tvoid highlightBlock(const QString & a_text);\n\nprivate:\n\n\tSettingsManager * m_pSettingsManager;\n\n\tQString m_coreName;\n\n\tVSPluginsList m_pluginsList;\n\n\tQStringList m_keywordsList;\n\tQStringList m_operatorsList;\n\n\tQTextCharFormat m_keywordFormat;\n\tQTextCharFormat m_operatorFormat;\n\tQTextCharFormat m_stringFormat;\n\tQTextCharFormat m_numberFormat;\n\tQTextCharFormat m_commentFormat;\n\tQTextCharFormat m_vsCoreFormat;\n\tQTextCharFormat m_vsNamespaceFormat;\n\tQTextCharFormat m_vsFunctionFormat;\n\tQTextCharFormat m_vsArgumentFormat;\n};\n\n#endif // SYNTAXHIGHLIGHTER_H\n"
  },
  {
    "path": "vsedit/src/script_status_bar_widget/script_status_bar_widget.cpp",
    "content": "#include \"script_status_bar_widget.h\"\n\n#include \"../../../common-src/helpers.h\"\n\n#include <QLocale>\n\n//==============================================================================\n\nScriptStatusBarWidget::ScriptStatusBarWidget(QWidget * a_pParent) :\n\t  QWidget(a_pParent)\n\t, m_readyPixmap(\":tick.png\")\n\t, m_busyPixmap(\":busy.png\")\n{\n\tvsedit::disableFontKerning(this);\n\tm_ui.setupUi(this);\n\tm_ui.colorPickerWidget->setVisible(false);\n\tm_ui.colorPickerIconLabel->setPixmap(QPixmap(\":color_picker.png\"));\n\tm_ui.colorPickerLabel->clear();\n\tm_ui.scriptProcessorQueueLabel->clear();\n\tm_ui.videoInfoLabel->clear();\n\n\tm_ui.scriptProcessorQueueIconLabel->setPixmap(m_readyPixmap);\n\tsetQueueState(0, 0, 0, 0.0);\n}\n\n// END OF ScriptStatusBarWidget::ScriptStatusBarWidget(QWidget * a_pParent)\n//==============================================================================\n\nScriptStatusBarWidget::~ScriptStatusBarWidget()\n{\n}\n\n// END OF ScriptStatusBarWidget::~ScriptStatusBarWidget()\n//==============================================================================\n\nbool ScriptStatusBarWidget::colorPickerVisible() const\n{\n\treturn m_ui.colorPickerWidget->isVisible();\n}\n\n// END OF bool ScriptStatusBarWidget::colorPickerVisible() const\n//==============================================================================\n\nvoid ScriptStatusBarWidget::setColorPickerVisible(bool a_visible)\n{\n\tm_ui.colorPickerWidget->setVisible(a_visible);\n}\n\n// END OF void ScriptStatusBarWidget::setColorPickerVisible(bool a_visible)\n//==============================================================================\n\nvoid ScriptStatusBarWidget::setColorPickerString(const QString & a_string)\n{\n\tm_ui.colorPickerLabel->setText(a_string);\n}\n\n// END OF void ScriptStatusBarWidget::setColorPickerString(\n//\t\tconst QString & a_string)\n//==============================================================================\n\nvoid ScriptStatusBarWidget::setQueueState(size_t a_inQueue, size_t a_inProcess,\n\tsize_t a_maxThreads, double a_usedCacheRatio)\n{\n\tif((a_inProcess + a_inQueue) > 0)\n\t\tm_ui.scriptProcessorQueueIconLabel->setPixmap(m_busyPixmap);\n\telse\n\t\tm_ui.scriptProcessorQueueIconLabel->setPixmap(m_readyPixmap);\n\n\tint percentage_int = (int)(a_usedCacheRatio * 100);\n\tint percentage_dec = (int)(a_usedCacheRatio * 1000) - 10 * percentage_int;\n\n\tm_ui.scriptProcessorQueueLabel->setText(\n\t\ttr(\"Script processor queue: %1:%2(%3) | Core cache used: %4.%5%\")\n\t\t.arg(a_inQueue).arg(a_inProcess).arg(a_maxThreads)\n\t\t.arg(percentage_int).arg(percentage_dec));\n}\n\n// END OF void ScriptStatusBarWidget::setQueueState(size_t a_inQueue,\n//\t\tsize_t a_inProcess, size_t a_maxThreads)\n//==============================================================================\n\nvoid ScriptStatusBarWidget::setNodeInfo(const VSNodeInfo & a_nodeInfo,\n\tconst VSAPI * a_cpVSAPI)\n{\n\tQString infoString = vsedit::nodeInfoString(a_nodeInfo, a_cpVSAPI);\n\tm_ui.videoInfoLabel->setText(infoString);\n}\n\n// END OF void ScriptStatusBarWidget::setVideoInfo(\n//\t\tconst VSVideoInfo * a_cpVideoInfo)\n//==============================================================================\n"
  },
  {
    "path": "vsedit/src/script_status_bar_widget/script_status_bar_widget.h",
    "content": "#ifndef SCRIPT_STATUS_BAR_WIDGET_H_INCLUDED\n#define SCRIPT_STATUS_BAR_WIDGET_H_INCLUDED\n\n#include <ui_script_status_bar_widget.h>\n\n#include <VapourSynth4.h>\n#include <QPixmap>\n\nclass VSNodeInfo;\n\nclass ScriptStatusBarWidget: public QWidget\n{\n\tQ_OBJECT\n\npublic:\n\n\tScriptStatusBarWidget(QWidget * a_pParent = nullptr);\n\tvirtual ~ScriptStatusBarWidget();\n\n\tvirtual bool colorPickerVisible() const;\n\npublic slots:\n\n\tvirtual void setColorPickerVisible(bool a_visible = true);\n\n\tvirtual void setColorPickerString(const QString & a_string);\n\n\tvirtual void setQueueState(size_t a_inQueue, size_t a_inProcess,\n\t\tsize_t a_maxThreads, double a_usedCacheRatio);\n\n\tvirtual void setNodeInfo(const VSNodeInfo & a_nodeInfo,\n\t\tconst VSAPI * a_cpVSAPI);\n\nprotected:\n\n\tUi::ScriptStatusBarWidget m_ui;\n\n\tQPixmap m_readyPixmap;\n\tQPixmap m_busyPixmap;\n};\n\n#endif // SCRIPT_STATUS_BAR_WIDGET_H_INCLUDED\n"
  },
  {
    "path": "vsedit/src/script_status_bar_widget/script_status_bar_widget.ui",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<ui version=\"4.0\">\n <class>ScriptStatusBarWidget</class>\n <widget class=\"QWidget\" name=\"ScriptStatusBarWidget\">\n  <property name=\"geometry\">\n   <rect>\n    <x>0</x>\n    <y>0</y>\n    <width>674</width>\n    <height>67</height>\n   </rect>\n  </property>\n  <property name=\"sizePolicy\">\n   <sizepolicy hsizetype=\"Preferred\" vsizetype=\"Minimum\">\n    <horstretch>0</horstretch>\n    <verstretch>0</verstretch>\n   </sizepolicy>\n  </property>\n  <property name=\"windowTitle\">\n   <string>Form</string>\n  </property>\n  <layout class=\"QVBoxLayout\" name=\"verticalLayout\">\n   <property name=\"spacing\">\n    <number>2</number>\n   </property>\n   <property name=\"leftMargin\">\n    <number>2</number>\n   </property>\n   <property name=\"topMargin\">\n    <number>2</number>\n   </property>\n   <property name=\"rightMargin\">\n    <number>2</number>\n   </property>\n   <property name=\"bottomMargin\">\n    <number>2</number>\n   </property>\n   <item>\n    <widget class=\"QWidget\" name=\"colorPickerWidget\" native=\"true\">\n     <layout class=\"QHBoxLayout\" name=\"horizontalLayout\">\n      <property name=\"spacing\">\n       <number>4</number>\n      </property>\n      <property name=\"leftMargin\">\n       <number>0</number>\n      </property>\n      <property name=\"topMargin\">\n       <number>0</number>\n      </property>\n      <property name=\"rightMargin\">\n       <number>0</number>\n      </property>\n      <property name=\"bottomMargin\">\n       <number>0</number>\n      </property>\n      <item>\n       <widget class=\"QLabel\" name=\"colorPickerIconLabel\">\n        <property name=\"text\">\n         <string>colorPickerIconLabel</string>\n        </property>\n       </widget>\n      </item>\n      <item>\n       <widget class=\"QLabel\" name=\"colorPickerLabel\">\n        <property name=\"text\">\n         <string>colorPickerLabel</string>\n        </property>\n       </widget>\n      </item>\n      <item>\n       <spacer name=\"horizontalSpacer_2\">\n        <property name=\"orientation\">\n         <enum>Qt::Horizontal</enum>\n        </property>\n        <property name=\"sizeHint\" stdset=\"0\">\n         <size>\n          <width>486</width>\n          <height>20</height>\n         </size>\n        </property>\n       </spacer>\n      </item>\n     </layout>\n    </widget>\n   </item>\n   <item>\n    <widget class=\"QWidget\" name=\"scriptProcessonInfoPanel\" native=\"true\">\n     <layout class=\"QHBoxLayout\" name=\"horizontalLayout_2\">\n      <property name=\"spacing\">\n       <number>4</number>\n      </property>\n      <property name=\"leftMargin\">\n       <number>0</number>\n      </property>\n      <property name=\"topMargin\">\n       <number>0</number>\n      </property>\n      <property name=\"rightMargin\">\n       <number>0</number>\n      </property>\n      <property name=\"bottomMargin\">\n       <number>0</number>\n      </property>\n      <item>\n       <widget class=\"QLabel\" name=\"scriptProcessorQueueIconLabel\">\n        <property name=\"text\">\n         <string>scriptProcessorQueueIconLabel</string>\n        </property>\n       </widget>\n      </item>\n      <item>\n       <widget class=\"QLabel\" name=\"scriptProcessorQueueLabel\">\n        <property name=\"text\">\n         <string>scriptProcessorQueueLabel</string>\n        </property>\n       </widget>\n      </item>\n      <item>\n       <spacer name=\"horizontalSpacer\">\n        <property name=\"orientation\">\n         <enum>Qt::Horizontal</enum>\n        </property>\n        <property name=\"sizeHint\" stdset=\"0\">\n         <size>\n          <width>268</width>\n          <height>20</height>\n         </size>\n        </property>\n       </spacer>\n      </item>\n     </layout>\n    </widget>\n   </item>\n   <item>\n    <widget class=\"QLabel\" name=\"videoInfoLabel\">\n     <property name=\"text\">\n      <string>videoInfoLabel</string>\n     </property>\n     <property name=\"textInteractionFlags\">\n      <set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>\n     </property>\n    </widget>\n   </item>\n  </layout>\n </widget>\n <resources/>\n <connections/>\n</ui>\n"
  },
  {
    "path": "vsedit/src/script_templates/drop_file_category_model.cpp",
    "content": "#include \"drop_file_category_model.h\"\n\n#include <QRegularExpression>\n#include <QSet>\n\n//==============================================================================\n\nconst int COLUMNS_NUMBER = 2;\nconst int NAME_COLUMN = 0;\nconst int MASK_LIST_COLUMN = 1;\n\nconst char MASK_LIST_SPLITTER = ';';\n\n//==============================================================================\n\nDropFileCategoryModel::DropFileCategoryModel(QObject * a_pParent) :\n\tQAbstractItemModel(a_pParent)\n{\n}\n\n// END OF DropFileCategoryModel::DropFileCategoryModel(QObject * a_pParent) :\n//\t\tQAbstractItemModel(a_pParent)\n//==============================================================================\n\nDropFileCategoryModel::~DropFileCategoryModel()\n{\n\n}\n\n// END OF DropFileCategoryModel::~DropFileCategoryModel()\n//==============================================================================\n\nQModelIndex DropFileCategoryModel::index(int a_row, int a_column,\n\tconst QModelIndex & a_parent) const\n{\n\t(void)a_parent;\n\treturn createIndex(a_row, a_column);\n}\n\n// END OF QModelIndex DropFileCategoryModel::index(int a_row, int a_column,\n//\t\tconst QModelIndex & a_parent) const\n//==============================================================================\n\nQModelIndex DropFileCategoryModel::parent(const QModelIndex & a_child) const\n{\n\t(void)a_child;\n\treturn QModelIndex();\n}\n\n// END OF QModelIndex DropFileCategoryModel::parent(\n//\t\tconst QModelIndex & a_child) const\n//==============================================================================\n\nQt::ItemFlags DropFileCategoryModel::flags(const QModelIndex & a_index) const\n{\n\tif (!a_index.isValid())\n\t{\n\t\treturn Qt::NoItemFlags;\n\t}\n\n\tQt::ItemFlags cellFlags = Qt::NoItemFlags\n\t\t| Qt::ItemIsEnabled\n\t\t| Qt::ItemIsSelectable\n\t\t| Qt::ItemIsEditable\n\t\t| Qt::ItemNeverHasChildren\n\t;\n\n\treturn cellFlags;\n}\n\n// END OF Qt::ItemFlags DropFileCategoryModel::flags(\n//\t\tconst QModelIndex & a_index) const\n//==============================================================================\n\nQVariant DropFileCategoryModel::data(const QModelIndex & a_index, int a_role)\n\tconst\n{\n\tif(!a_index.isValid())\n\t\treturn QVariant();\n\n\tif((a_index.row() >= (int)m_categories.size()) ||\n\t\t(a_index.column() >= COLUMNS_NUMBER))\n\t\treturn QVariant();\n\n\tif((a_index.column() == NAME_COLUMN) &&\n\t\t((a_role == Qt::DisplayRole) || (a_role == Qt::ToolTipRole) ||\n\t\t(a_role == Qt::EditRole)))\n\t\treturn m_categories[a_index.row()].name;\n\telse if((a_index.column() == MASK_LIST_COLUMN) &&\n\t\t((a_role == Qt::DisplayRole) || (a_role == Qt::ToolTipRole) ||\n\t\t(a_role == Qt::EditRole)))\n\t\treturn m_categories[a_index.row()].maskList.join(MASK_LIST_SPLITTER);\n\n\treturn QVariant();\n}\n\n// END OF QVariant DropFileCategoryModel::data(const QModelIndex & a_index,\n//\t\tint a_role)\n//==============================================================================\n\nQVariant DropFileCategoryModel::headerData(int a_section,\n\tQt::Orientation a_orientation, int a_role) const\n{\n\tif(a_orientation != Qt::Horizontal)\n\t\treturn QVariant();\n\n\tif(a_role != Qt::DisplayRole)\n\t\treturn QVariant();\n\n\tif(a_section == NAME_COLUMN)\n\t\treturn tr(\"Category\");\n\n\tif(a_section == MASK_LIST_COLUMN)\n\t\treturn tr(\"File name mask list\");\n\n\treturn QVariant();\n}\n\n// END OF QVariant DropFileCategoryModel::headerData(int a_section,\n//\t\tQt::Orientation a_orientation, int a_role) const\n//==============================================================================\n\nint DropFileCategoryModel::rowCount(const QModelIndex & a_parent) const\n{\n\t(void)a_parent;\n\treturn (int)m_categories.size();\n}\n\n// END OF int DropFileCategoryModel::rowCount(const QModelIndex & a_parent)\n//\t\tconst\n//==============================================================================\n\nint DropFileCategoryModel::columnCount(const QModelIndex & a_parent) const\n{\n\t(void)a_parent;\n\treturn COLUMNS_NUMBER;\n}\n\n// END OF int DropFileCategoryModel::columnCount(const QModelIndex & a_parent)\n//\t\tconst\n//==============================================================================\n\nbool DropFileCategoryModel::setData(const QModelIndex & a_index,\n\tconst QVariant & a_value, int a_role)\n{\n\tif(a_role != Qt::EditRole)\n\t\treturn false;\n\n\tif((a_index.row() >= (int)m_categories.size()) ||\n\t\t(a_index.column() >= COLUMNS_NUMBER))\n\t\treturn false;\n\n\tif(a_index.column() == NAME_COLUMN)\n\t{\n\t\tfor(int i = 0; i < (int)m_categories.size(); ++i)\n\t\t{\n\t\t\tif((i != a_index.row()) &&\n\t\t\t\t(m_categories[i].name == a_value.toString()))\n\t\t\t\treturn false;\n\t\t}\n\t\tm_categories[a_index.row()].name = a_value.toString();\n\t\treturn true;\n\t}\n\n\tif(a_index.column() == MASK_LIST_COLUMN)\n\t{\n\t\tQStringList maskList = a_value.toString().split(MASK_LIST_SPLITTER);\n\t\tfor(int i = 0; i < (int)m_categories.size(); ++i)\n\t\t{\n\t\t\tif(i == a_index.row())\n\t\t\t\tcontinue;\n\t\t\tQSet<QString> set_curr(maskList.begin(), maskList.end());\n\t\t\tQSet<QString> set_i(m_categories[i].maskList.begin(),\n\t\t\t\tm_categories[i].maskList.end());\n\t\t\tQSet<QString> intersection = set_curr.intersect(set_i);\n\t\t\tif(intersection.size() > 0)\n\t\t\t\treturn false;\n\t\t}\n\n\t\tfor(const QString & mask : maskList)\n\t\t{\n\t\t\tauto re = QRegularExpression::fromWildcard(mask,\n\t\t\t\tQt::CaseInsensitive,\n\t\t\t\tQRegularExpression::UnanchoredWildcardConversion);\n\t\t\tif(!re.isValid())\n\t\t\t\treturn false;\n\t\t}\n\n\t\tm_categories[a_index.row()].maskList = maskList;\n\t\treturn true;\n\t}\n\n\treturn false;\n}\n\n// END OF bool DropFileCategoryModel::setData(const QModelIndex & a_index,\n//\t\tconst QVariant & a_value, int a_role)\n//==============================================================================\n\nstd::vector<DropFileCategory> DropFileCategoryModel::getCategories() const\n{\n\treturn m_categories;\n}\n\n// END OF std::vector<DropFileCategory> DropFileCategoryModel::getCategories()\n//\t\tconst\n//==============================================================================\n\nvoid DropFileCategoryModel::setCategories(\n\tconst std::vector<DropFileCategory> & a_categories)\n{\n\tm_categories = a_categories;\n\temit layoutChanged();\n}\n\n// END OF void DropFileCategoryModel::setCategories(\n//\t\tconst std::vector<DropFileCategory> & a_categories)\n//==============================================================================\n\nvoid DropFileCategoryModel::addCategory()\n{\n\tbeginInsertRows(QModelIndex(), (int)m_categories.size(),\n\t\t(int)m_categories.size());\n\tm_categories.emplace_back();\n\tendInsertRows();\n}\n\n// END OF void DropFileCategoryModel::addCategory()\n//==============================================================================\n\nvoid DropFileCategoryModel::deleteCategory(int a_index)\n{\n\tif(a_index >= (int)m_categories.size() || a_index < 0)\n\t\treturn;\n\tbeginRemoveRows(QModelIndex(), a_index, a_index);\n\tm_categories.erase(m_categories.begin() + a_index);\n\tendRemoveRows();\n}\n\n// END OF void DropFileCategoryModel::deleteCategory(int a_index)\n//==============================================================================\n\nQString DropFileCategoryModel::sourceTemplate(int a_index) const\n{\n\tif(a_index >= (int)m_categories.size() || a_index < 0)\n\t\treturn QString();\n\treturn m_categories[a_index].sourceTemplate;\n}\n\n// END OF QString DropFileCategoryModel::sourceTemplate(int a_index) const\n//==============================================================================\n\nvoid DropFileCategoryModel::setSourceTemplate(int a_index,\n\tconst QString & a_text)\n{\n\tif(a_index >= (int)m_categories.size() || a_index < 0)\n\t\treturn;\n\tm_categories[a_index].sourceTemplate = a_text;\n}\n\n// END OF void DropFileCategoryModel::setSourceTemplate(int a_index,\n//\t\tconst QString & a_text)\n//==============================================================================\n"
  },
  {
    "path": "vsedit/src/script_templates/drop_file_category_model.h",
    "content": "#ifndef DROP_FILE_CATEGORY_MODEL_H_INCLUDED\n#define DROP_FILE_CATEGORY_MODEL_H_INCLUDED\n\n#include \"../../../common-src/settings/settings_definitions.h\"\n\n#include <QAbstractItemModel>\n\nclass DropFileCategoryModel : public QAbstractItemModel\n{\n\tQ_OBJECT\n\npublic:\n\n\tDropFileCategoryModel(QObject * a_pParent = nullptr);\n\n\tvirtual ~DropFileCategoryModel();\n\n\tvirtual QModelIndex index(int a_row, int a_column,\n\t\tconst QModelIndex & a_parent = QModelIndex()) const override;\n\n\tvirtual QModelIndex parent(const QModelIndex & a_child) const override;\n\n\tvirtual Qt::ItemFlags flags(const QModelIndex & a_index) const override;\n\n\tvirtual QVariant data(const QModelIndex & a_index,\n\t\tint a_role = Qt::DisplayRole) const override;\n\n\tvirtual QVariant headerData(int a_section, Qt::Orientation a_orientation,\n\t\tint a_role = Qt::DisplayRole) const override;\n\n\tvirtual int rowCount(const QModelIndex & a_parent = QModelIndex())\n\t\tconst override;\n\n\tvirtual int columnCount(const QModelIndex & a_parent = QModelIndex())\n\t\tconst override;\n\n\tvirtual bool setData(const QModelIndex & a_index, const QVariant & a_value,\n\t\tint a_role = Qt::EditRole) override;\n\n\tstd::vector<DropFileCategory> getCategories() const;\n\n\tvoid setCategories(const std::vector<DropFileCategory> & a_categories);\n\n\tvoid addCategory();\n\n\tvoid deleteCategory(int a_index);\n\n\tQString sourceTemplate(int a_index) const;\n\n\tvoid setSourceTemplate(int a_index, const QString & a_text);\n\nprivate:\n\n\tstd::vector<DropFileCategory> m_categories;\n};\n\n#endif // DROP_FILE_CATEGORY_MODEL_H_INCLUDED\n"
  },
  {
    "path": "vsedit/src/script_templates/templates_dialog.cpp",
    "content": "#include \"templates_dialog.h\"\n\n#include \"drop_file_category_model.h\"\n#include \"../../../common-src/settings/settings_manager.h\"\n\n#include <QAction>\n#include <QMessageBox>\n\n//==============================================================================\n\nTemplatesDialog::TemplatesDialog(SettingsManager * a_pSettingsManager,\n\tQWidget * a_pParent, Qt::WindowFlags a_flags) :\n\t  QDialog(a_pParent, a_flags)\n\t, m_pSettingsManager(a_pSettingsManager)\n\t, m_pDropFileCategoryModel(nullptr)\n\t, m_pSaveAction(nullptr)\n{\n\tQ_ASSERT(m_pSettingsManager);\n\tvsedit::disableFontKerning(this);\n\tm_ui.setupUi(this);\n\n\tm_scriptEditors = {m_ui.snippetEdit, m_ui.newScriptTemplateEdit,\n\t\tm_ui.dropFileCategoryTemplateEdit};\n\n\tfor(ScriptEditor * pEdit : m_scriptEditors)\n\t\tpEdit->setSettingsManager(m_pSettingsManager);\n\n\tm_pDropFileCategoryModel = new DropFileCategoryModel(this);\n\tm_ui.dropFileCategoryView->setModel(m_pDropFileCategoryModel);\n\n\tQString fileDropTemplatesInfo = tr(\"Write file name mask list \"\n\t\t\"as a list of wildcards, separated by semicolons without spaces.\\n\"\n\t\t\"In the template below use tokens: \");\n\tQStringList tokenInfoList;\n\tstd::vector<vsedit::VariableToken> variables =\n\t\tm_ui.dropFileCategoryTemplateEdit->variables();\n\tfor(const vsedit::VariableToken & variable : variables)\n\t\ttokenInfoList += QString(\"%1 - %2\").arg(variable.token)\n\t\t\t.arg(variable.description);\n\tfileDropTemplatesInfo += tokenInfoList.join(\"; \");\n\tfileDropTemplatesInfo += tr(\".\");\n\tm_ui.fileDropTemplatesInfoLabel->setText(fileDropTemplatesInfo);\n\n\tm_pSaveAction = m_pSettingsManager->createStandardAction(\n\t\tACTION_ID_SAVE_SCRIPT, this);\n\taddAction(m_pSaveAction);\n\n\tconnect(m_pSaveAction, SIGNAL(triggered()),\n\t\tthis, SLOT(slotSaveActionTriggered()));\n\tconnect(m_ui.snippetPasteIntoScriptButton, SIGNAL(clicked()),\n\t\tthis, SLOT(slotSnippetPasteIntoScriptButtonClicked()));\n\tconnect(m_ui.snippetSaveButton, SIGNAL(clicked()),\n\t\tthis, SLOT(slotSnippetSaveButtonClicked()));\n\tconnect(m_ui.snippetDeleteButton, SIGNAL(clicked()),\n\t\tthis, SLOT(slotSnippetDeleteButtonClicked()));\n\tconnect(m_ui.snippetNameComboBox, SIGNAL(textActivated(const QString &)),\n\t\tthis, SLOT(slotSnippetNameComboBoxActivated(const QString &)));\n\tconnect(m_ui.newScriptTemplateRevertButton, SIGNAL(clicked()),\n\t\tthis, SLOT(slotNewScriptTemplateRevertButtonClicked()));\n\tconnect(m_ui.newScriptTemplateLoadDefaultButton, SIGNAL(clicked()),\n\t\tthis, SLOT(slotNewScriptTemplateLoadDefaultButtonClicked()));\n\tconnect(m_ui.newScriptTemplateSaveButton, SIGNAL(clicked()),\n\t\tthis, SLOT(slotNewScriptTemplateSaveButtonClicked()));\n\tconnect(m_ui.saveDropFileCategoriesButton, SIGNAL(clicked()),\n\t\tthis, SLOT(slotSaveDropFileCategoriesButtonClicked()));\n\tconnect(m_ui.revertDropFileCategoriesButton, SIGNAL(clicked()),\n\t\tthis, SLOT(slotRevertDropFileCategoriesButtonClicked()));\n\tconnect(m_ui.addDropFileCategoryButton, SIGNAL(clicked()),\n\t\tthis, SLOT(slotAddDropFileCategoryButtonClicked()));\n\tconnect(m_ui.deleteSelectedDropFileCategoryButton, SIGNAL(clicked()),\n\t\tthis, SLOT(slotDeleteSelectedDropFileCategoryButtonClicked()));\n\tconnect(m_ui.dropFileCategoryView, SIGNAL(pressed(const QModelIndex &)),\n\t\tthis, SLOT(slotDropFileCategoryViewPressed(const QModelIndex &)));\n\tconnect(m_ui.dropFileCategoryTemplateEdit, SIGNAL(textChanged()),\n\t\tthis, SLOT(slotUpdateDropFileCategories()));\n\n\tslotLoadSettings();\n}\n\n// END OF TemplatesDialog::TemplatesDialog(SettingsManager * a_pSettingsManager,\n//\t\tQWidget * a_pParent, Qt::WindowFlags a_flags)\n//==============================================================================\n\nTemplatesDialog::~TemplatesDialog()\n{\n}\n\n// END OF TemplatesDialog::~TemplatesDialog()\n//==============================================================================\n\nvoid TemplatesDialog::setPluginsList(const VSPluginsList & a_pluginsList)\n{\n\tfor(ScriptEditor * pEdit : m_scriptEditors)\n\t\tpEdit->setPluginsList(a_pluginsList);\n}\n\n// END OF void TemplatesDialog::setPluginsList(\n//\t\tconst VSPluginsList & a_pluginsList)\n//==============================================================================\n\nvoid TemplatesDialog::call()\n{\n\tslotLoadSettings();\n\tshow();\n}\n\n// END OF void TemplatesDialog::call()\n//==============================================================================\n\nvoid TemplatesDialog::slotLoadSettings()\n{\n\tfor(ScriptEditor * pEdit : m_scriptEditors)\n\t\tpEdit->slotLoadSettings();\n\n\tm_pSaveAction->setShortcut(m_pSettingsManager->getHotkey(\n\t\tm_pSaveAction->data().toString()));\n\n\tm_ui.snippetNameComboBox->clear();\n\tm_codeSnippets = m_pSettingsManager->getAllCodeSnippets();\n\tfor(const CodeSnippet & snippet : m_codeSnippets)\n\t\tm_ui.snippetNameComboBox->addItem(snippet.name);\n\tm_ui.snippetNameComboBox->setCurrentIndex(0);\n\tslotSnippetNameComboBoxActivated(m_ui.snippetNameComboBox->currentText());\n\n\tQString newScriptTemplate = m_pSettingsManager->getNewScriptTemplate();\n\tm_ui.newScriptTemplateEdit->setPlainText(newScriptTemplate);\n\n\tslotRevertDropFileCategoriesButtonClicked();\n}\n\n// END OF void TemplatesDialog::slotLoadSettings()\n//==============================================================================\n\nvoid TemplatesDialog::slotSnippetPasteIntoScriptButtonClicked()\n{\n\tQString text = m_ui.snippetEdit->text();\n\tif(!text.isEmpty())\n\t\temit signalPasteCodeSnippet(text);\n}\n\n// END OF void TemplatesDialog::slotSnippetPasteIntoScriptButtonClicked()\n//==============================================================================\n\nvoid TemplatesDialog::slotSnippetSaveButtonClicked()\n{\n\tCodeSnippet snippet(m_ui.snippetNameComboBox->currentText(),\n\t\tm_ui.snippetEdit->text());\n\n\tbool success = m_pSettingsManager->saveCodeSnippet(snippet);\n\tif(!success)\n\t\treturn;\n\n\tstd::vector<CodeSnippet>::iterator it = std::find(\n\t\tm_codeSnippets.begin(), m_codeSnippets.end(), snippet);\n\tif(it == m_codeSnippets.end())\n\t{\n\t\tQ_ASSERT(m_ui.snippetNameComboBox->findText(snippet.name) == -1);\n\t\tm_codeSnippets.push_back(snippet);\n\t\tm_ui.snippetNameComboBox->addItem(snippet.name);\n\t\tm_ui.snippetNameComboBox->model()->sort(0);\n\t}\n\telse\n\t{\n\t\tQ_ASSERT(m_ui.snippetNameComboBox->findText(snippet.name) != -1);\n\t\t*it = snippet;\n\t}\n}\n\n// END OF void TemplatesDialog::slotSnippetSaveButtonClicked()\n//==============================================================================\n\nvoid TemplatesDialog::slotSnippetDeleteButtonClicked()\n{\n\tCodeSnippet snippet(m_ui.snippetNameComboBox->currentText());\n\tif(snippet.name.isEmpty())\n\t\treturn;\n\n\tQMessageBox quesBox(this);\n\tvsedit::disableFontKerning(&quesBox);\n\tquesBox.setWindowTitle(tr(\"Delete snippet\"));\n\tquesBox.setText(tr(\"Do you really want to delete \"\n\t\t\"snippet \\'%1\\'?\").arg(snippet.name));\n\tquesBox.setStandardButtons(QMessageBox::Yes | QMessageBox::No);\n\tquesBox.setDefaultButton(QMessageBox::No);\n\tint result = quesBox.exec();\n\tif(result == QMessageBox::No)\n\t\treturn;\n\n\tstd::vector<CodeSnippet>::iterator it = std::find(\n\t\tm_codeSnippets.begin(), m_codeSnippets.end(), snippet);\n\tif(it == m_codeSnippets.end())\n\t{\n\t\tQ_ASSERT(m_ui.snippetNameComboBox->findText(snippet.name) == -1);\n\t\treturn;\n\t}\n\n\tint index = m_ui.snippetNameComboBox->findText(snippet.name);\n\tQ_ASSERT(index != -1);\n\tm_ui.snippetNameComboBox->removeItem(index);\n\tm_codeSnippets.erase(it);\n\tm_ui.snippetNameComboBox->setCurrentIndex(0);\n\tslotSnippetNameComboBoxActivated(m_ui.snippetNameComboBox->currentText());\n\n\tm_pSettingsManager->deleteCodeSnippet(snippet.name);\n}\n\n// END OF void TemplatesDialog::slotSnippetDeleteButtonClicked()\n//==============================================================================\n\nvoid TemplatesDialog::slotSnippetNameComboBoxActivated(const QString & a_text)\n{\n\tif(a_text.isEmpty())\n\t{\n\t\tm_ui.snippetEdit->clear();\n\t\treturn;\n\t}\n\n\tCodeSnippet snippet(a_text);\n\n\tstd::vector<CodeSnippet>::iterator it = std::find(\n\t\tm_codeSnippets.begin(), m_codeSnippets.end(), snippet);\n\tif(it == m_codeSnippets.end())\n\t\treturn;\n\n\tsnippet = *it;\n\n\tm_ui.snippetEdit->setPlainText(snippet.text);\n}\n\n// END OF void TemplatesDialog::slotSnippetNameComboBoxActivated(\n//\t\tconst QString & a_text)\n//==============================================================================\n\nvoid TemplatesDialog::slotNewScriptTemplateRevertButtonClicked()\n{\n\tQString newScriptTemplate = m_pSettingsManager->getNewScriptTemplate();\n\tm_ui.newScriptTemplateEdit->setPlainText(newScriptTemplate);\n}\n\n// END OF void TemplatesDialog::slotNewScriptTemplateRevertButtonClicked()\n//==============================================================================\n\nvoid TemplatesDialog::slotNewScriptTemplateLoadDefaultButtonClicked()\n{\n\tQString defaultNewScriptTemplate =\n\t\tm_pSettingsManager->getDefaultNewScriptTemplate();\n\tm_ui.newScriptTemplateEdit->setPlainText(defaultNewScriptTemplate);\n}\n\n// END OF void TemplatesDialog::slotNewScriptTemplateLoadDefaultButtonClicked()\n//==============================================================================\n\nvoid TemplatesDialog::slotNewScriptTemplateSaveButtonClicked()\n{\n\tQString newScriptTemplate = m_ui.newScriptTemplateEdit->toPlainText();\n\tm_pSettingsManager->setNewScriptTemplate(newScriptTemplate);\n}\n\n// END OF void TemplatesDialog::slotNewScriptTemplateSaveButtonClicked()\n//==============================================================================\n\nvoid TemplatesDialog::slotSaveDropFileCategoriesButtonClicked()\n{\n\tint index = m_ui.dropFileCategoryView->currentIndex().row();\n\tm_pDropFileCategoryModel->setSourceTemplate(index,\n\t\tm_ui.dropFileCategoryTemplateEdit->text());\n\tstd::vector<DropFileCategory> categories =\n\t\tm_pDropFileCategoryModel->getCategories();\n\tm_pSettingsManager->setDropFileTemplates(categories);\n}\n\n// END OF void TemplatesDialog::slotSaveDropFileCategoriesButtonClicked()\n//==============================================================================\n\nvoid TemplatesDialog::slotRevertDropFileCategoriesButtonClicked()\n{\n\tstd::vector<DropFileCategory> categories =\n\t\tm_pSettingsManager->getAllDropFileTemplates();\n\tm_pDropFileCategoryModel->setCategories(categories);\n\tm_ui.dropFileCategoryView->resizeColumnToContents(0);\n\tm_ui.dropFileCategoryView->setCurrentIndex(\n\t\tm_pDropFileCategoryModel->index(0, 0));\n\tslotDisplayCurrentDropFileCategoryTemplate();\n}\n\n// END OF void TemplatesDialog::slotRevertDropFileCategoriesButtonClicked()\n//==============================================================================\n\nvoid TemplatesDialog::slotAddDropFileCategoryButtonClicked()\n{\n\tm_pDropFileCategoryModel->addCategory();\n\tQModelIndex index = m_pDropFileCategoryModel->index(\n\t\tm_pDropFileCategoryModel->rowCount() - 1, 0);\n\tm_ui.dropFileCategoryView->setCurrentIndex(index);\n\tslotDisplayCurrentDropFileCategoryTemplate();\n\tm_ui.dropFileCategoryView->edit(index);\n}\n\n// END OF void TemplatesDialog::slotAddDropFileCategoryButtonClicked()\n//==============================================================================\n\nvoid TemplatesDialog::slotDeleteSelectedDropFileCategoryButtonClicked()\n{\n\tQModelIndex index = m_ui.dropFileCategoryView->currentIndex();\n\tif(!index.isValid())\n\t\treturn;\n\n\tint row = index.row();\n\tstd::vector<DropFileCategory> categories =\n\t\tm_pDropFileCategoryModel->getCategories();\n\tif(categories.empty())\n\t\treturn;\n\tDropFileCategory category = categories[row];\n\n\tQMessageBox quesBox(this);\n\tvsedit::disableFontKerning(&quesBox);\n\tquesBox.setWindowTitle(tr(\"Delete category\"));\n\tquesBox.setText(tr(\"Do you really want to delete \"\n\t\t\"category \\'%1\\'?\").arg(category.name));\n\tquesBox.setStandardButtons(QMessageBox::Yes | QMessageBox::No);\n\tquesBox.setDefaultButton(QMessageBox::No);\n\tint result = quesBox.exec();\n\tif(result == QMessageBox::No)\n\t\treturn;\n\n\tm_pDropFileCategoryModel->deleteCategory(row);\n\tslotDisplayCurrentDropFileCategoryTemplate();\n}\n\n// END OF void TemplatesDialog::\n//\t\tslotDeleteSelectedDropFileCategoryButtonClicked()\n//==============================================================================\n\nvoid TemplatesDialog::slotDropFileCategoryViewPressed(\n\tconst QModelIndex & a_index)\n{\n\t(void)a_index;\n\tslotDisplayCurrentDropFileCategoryTemplate();\n}\n\n// END OF void TemplatesDialog::slotDropFileCategoryViewPressed(\n//\t\tconst QModelIndex & a_index)\n//==============================================================================\n\nvoid TemplatesDialog::slotDisplayCurrentDropFileCategoryTemplate()\n{\n\tQModelIndex index = m_ui.dropFileCategoryView->currentIndex();\n\tif(!index.isValid())\n\t\treturn;\n\tQString sourceTemplate =\n\t\tm_pDropFileCategoryModel->sourceTemplate(index.row());\n\tm_ui.dropFileCategoryTemplateEdit->setPlainText(sourceTemplate);\n}\n\n// END OF void TemplatesDialog::slotDisplayCurrentDropFileCategoryTemplate()\n//==============================================================================\n\nvoid TemplatesDialog::slotUpdateDropFileCategories()\n{\n\tQModelIndex index = m_ui.dropFileCategoryView->currentIndex();\n\tif(!index.isValid())\n\t\treturn;\n\tQString sourceTemplate = m_ui.dropFileCategoryTemplateEdit->text();\n\tm_pDropFileCategoryModel->setSourceTemplate(index.row(), sourceTemplate);\n}\n\n// END OF void TemplatesDialog::slotUpdateDropFileCategories()\n//==============================================================================\n\nvoid TemplatesDialog::slotSaveActionTriggered()\n{\n\tQWidget * pCurrentWidget = m_ui.templatesTabWidget->currentWidget();\n\tif(pCurrentWidget == m_ui.codeSnippetsTab)\n\t\tslotSnippetSaveButtonClicked();\n\telse if(pCurrentWidget == m_ui.newScriptTemplateTab)\n\t\tslotNewScriptTemplateSaveButtonClicked();\n\telse if(pCurrentWidget == m_ui.fileDropTemplatesTab)\n\t\tslotSaveDropFileCategoriesButtonClicked();\n}\n\n// END OF void TemplatesDialog::slotSaveActionTriggered()\n//==============================================================================\n"
  },
  {
    "path": "vsedit/src/script_templates/templates_dialog.h",
    "content": "#ifndef TEMPLATES_DIALOG_H_INCLUDED\n#define TEMPLATES_DIALOG_H_INCLUDED\n\n#include <ui_templates_dialog.h>\n\n#include \"../../../common-src/settings/settings_definitions.h\"\n\n#include <QDialog>\n\nclass DropFileCategoryModel;\nclass SettingsManager;\nclass QAction;\n\nclass TemplatesDialog : public QDialog\n{\n\tQ_OBJECT\n\npublic:\n\n\tTemplatesDialog(SettingsManager * a_pSettingsManager,\n\t\tQWidget * a_pParent = nullptr,\n\t\tQt::WindowFlags a_flags =\n\t\t  Qt::Window\n\t\t| Qt::CustomizeWindowHint\n\t\t| Qt::WindowMinimizeButtonHint\n\t\t| Qt::WindowMaximizeButtonHint\n\t\t| Qt::WindowCloseButtonHint);\n\n\tvirtual ~TemplatesDialog();\n\n\tvoid setPluginsList(const VSPluginsList & a_pluginsList);\n\npublic slots:\n\n\tvoid call();\n\n\tvoid slotLoadSettings();\n\nsignals:\n\n\tvoid signalPasteCodeSnippet(const QString & a_text);\n\nprivate slots:\n\n\tvoid slotSnippetPasteIntoScriptButtonClicked();\n\tvoid slotSnippetSaveButtonClicked();\n\tvoid slotSnippetDeleteButtonClicked();\n\tvoid slotSnippetNameComboBoxActivated(const QString & a_text);\n\n\tvoid slotNewScriptTemplateRevertButtonClicked();\n\tvoid slotNewScriptTemplateLoadDefaultButtonClicked();\n\tvoid slotNewScriptTemplateSaveButtonClicked();\n\n\tvoid slotSaveDropFileCategoriesButtonClicked();\n\tvoid slotRevertDropFileCategoriesButtonClicked();\n\tvoid slotAddDropFileCategoryButtonClicked();\n\tvoid slotDeleteSelectedDropFileCategoryButtonClicked();\n\tvoid slotDropFileCategoryViewPressed(const QModelIndex & a_index);\n\tvoid slotDisplayCurrentDropFileCategoryTemplate();\n\tvoid slotUpdateDropFileCategories();\n\n\tvoid slotSaveActionTriggered();\n\nprivate:\n\n\tUi::TemplatesDialog m_ui;\n\n\tSettingsManager * m_pSettingsManager;\n\n\tstd::vector<CodeSnippet> m_codeSnippets;\n\n\tDropFileCategoryModel * m_pDropFileCategoryModel;\n\n\tQAction * m_pSaveAction;\n\n\tstd::vector<ScriptEditor *> m_scriptEditors;\n};\n\n#endif // TEMPLATES_DIALOG_H_INCLUDED\n"
  },
  {
    "path": "vsedit/src/script_templates/templates_dialog.ui",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<ui version=\"4.0\">\n <class>TemplatesDialog</class>\n <widget class=\"QDialog\" name=\"TemplatesDialog\">\n  <property name=\"geometry\">\n   <rect>\n    <x>0</x>\n    <y>0</y>\n    <width>770</width>\n    <height>578</height>\n   </rect>\n  </property>\n  <property name=\"windowTitle\">\n   <string>Script templates</string>\n  </property>\n  <layout class=\"QVBoxLayout\" name=\"verticalLayout\">\n   <property name=\"spacing\">\n    <number>0</number>\n   </property>\n   <property name=\"leftMargin\">\n    <number>0</number>\n   </property>\n   <property name=\"topMargin\">\n    <number>0</number>\n   </property>\n   <property name=\"rightMargin\">\n    <number>0</number>\n   </property>\n   <property name=\"bottomMargin\">\n    <number>0</number>\n   </property>\n   <item>\n    <widget class=\"QTabWidget\" name=\"templatesTabWidget\">\n     <property name=\"currentIndex\">\n      <number>0</number>\n     </property>\n     <widget class=\"QWidget\" name=\"codeSnippetsTab\">\n      <attribute name=\"title\">\n       <string>Code snippets</string>\n      </attribute>\n      <layout class=\"QVBoxLayout\" name=\"verticalLayout_3\">\n       <property name=\"spacing\">\n        <number>4</number>\n       </property>\n       <property name=\"leftMargin\">\n        <number>0</number>\n       </property>\n       <property name=\"topMargin\">\n        <number>0</number>\n       </property>\n       <property name=\"rightMargin\">\n        <number>0</number>\n       </property>\n       <property name=\"bottomMargin\">\n        <number>0</number>\n       </property>\n       <item>\n        <layout class=\"QHBoxLayout\" name=\"horizontalLayout_2\">\n         <property name=\"spacing\">\n          <number>4</number>\n         </property>\n         <item>\n          <widget class=\"QComboBox\" name=\"snippetNameComboBox\">\n           <property name=\"sizePolicy\">\n            <sizepolicy hsizetype=\"Expanding\" vsizetype=\"Fixed\">\n             <horstretch>0</horstretch>\n             <verstretch>0</verstretch>\n            </sizepolicy>\n           </property>\n           <property name=\"editable\">\n            <bool>true</bool>\n           </property>\n           <property name=\"insertPolicy\">\n            <enum>QComboBox::NoInsert</enum>\n           </property>\n          </widget>\n         </item>\n         <item>\n          <widget class=\"QPushButton\" name=\"snippetPasteIntoScriptButton\">\n           <property name=\"text\">\n            <string>Paste into script</string>\n           </property>\n           <property name=\"default\">\n            <bool>true</bool>\n           </property>\n          </widget>\n         </item>\n         <item>\n          <widget class=\"QPushButton\" name=\"snippetSaveButton\">\n           <property name=\"text\">\n            <string>Save</string>\n           </property>\n          </widget>\n         </item>\n         <item>\n          <widget class=\"QPushButton\" name=\"snippetDeleteButton\">\n           <property name=\"text\">\n            <string>Delete</string>\n           </property>\n          </widget>\n         </item>\n        </layout>\n       </item>\n       <item>\n        <widget class=\"ScriptEditor\" name=\"snippetEdit\"/>\n       </item>\n      </layout>\n     </widget>\n     <widget class=\"QWidget\" name=\"newScriptTemplateTab\">\n      <attribute name=\"title\">\n       <string>New script template</string>\n      </attribute>\n      <layout class=\"QVBoxLayout\" name=\"verticalLayout_2\">\n       <property name=\"spacing\">\n        <number>4</number>\n       </property>\n       <property name=\"leftMargin\">\n        <number>0</number>\n       </property>\n       <property name=\"topMargin\">\n        <number>0</number>\n       </property>\n       <property name=\"rightMargin\">\n        <number>0</number>\n       </property>\n       <property name=\"bottomMargin\">\n        <number>0</number>\n       </property>\n       <item>\n        <layout class=\"QHBoxLayout\" name=\"horizontalLayout\">\n         <property name=\"spacing\">\n          <number>4</number>\n         </property>\n         <item>\n          <spacer name=\"horizontalSpacer\">\n           <property name=\"orientation\">\n            <enum>Qt::Horizontal</enum>\n           </property>\n           <property name=\"sizeHint\" stdset=\"0\">\n            <size>\n             <width>318</width>\n             <height>20</height>\n            </size>\n           </property>\n          </spacer>\n         </item>\n         <item>\n          <widget class=\"QPushButton\" name=\"newScriptTemplateRevertButton\">\n           <property name=\"text\">\n            <string>Revert</string>\n           </property>\n          </widget>\n         </item>\n         <item>\n          <widget class=\"QPushButton\" name=\"newScriptTemplateLoadDefaultButton\">\n           <property name=\"text\">\n            <string>Load default</string>\n           </property>\n          </widget>\n         </item>\n         <item>\n          <widget class=\"QPushButton\" name=\"newScriptTemplateSaveButton\">\n           <property name=\"text\">\n            <string>Save</string>\n           </property>\n          </widget>\n         </item>\n        </layout>\n       </item>\n       <item>\n        <widget class=\"ScriptEditor\" name=\"newScriptTemplateEdit\"/>\n       </item>\n      </layout>\n     </widget>\n     <widget class=\"QWidget\" name=\"fileDropTemplatesTab\">\n      <attribute name=\"title\">\n       <string>File drop templates</string>\n      </attribute>\n      <layout class=\"QVBoxLayout\" name=\"verticalLayout_5\">\n       <property name=\"spacing\">\n        <number>4</number>\n       </property>\n       <property name=\"leftMargin\">\n        <number>0</number>\n       </property>\n       <property name=\"topMargin\">\n        <number>0</number>\n       </property>\n       <property name=\"rightMargin\">\n        <number>0</number>\n       </property>\n       <property name=\"bottomMargin\">\n        <number>0</number>\n       </property>\n       <item>\n        <layout class=\"QHBoxLayout\" name=\"horizontalLayout_3\">\n         <property name=\"spacing\">\n          <number>4</number>\n         </property>\n         <item>\n          <widget class=\"QTableView\" name=\"dropFileCategoryView\">\n           <property name=\"alternatingRowColors\">\n            <bool>true</bool>\n           </property>\n           <property name=\"selectionMode\">\n            <enum>QAbstractItemView::SingleSelection</enum>\n           </property>\n           <property name=\"selectionBehavior\">\n            <enum>QAbstractItemView::SelectRows</enum>\n           </property>\n           <property name=\"textElideMode\">\n            <enum>Qt::ElideNone</enum>\n           </property>\n           <property name=\"verticalScrollMode\">\n            <enum>QAbstractItemView::ScrollPerPixel</enum>\n           </property>\n           <property name=\"horizontalScrollMode\">\n            <enum>QAbstractItemView::ScrollPerPixel</enum>\n           </property>\n           <attribute name=\"horizontalHeaderHighlightSections\">\n            <bool>false</bool>\n           </attribute>\n           <attribute name=\"horizontalHeaderStretchLastSection\">\n            <bool>true</bool>\n           </attribute>\n           <attribute name=\"verticalHeaderVisible\">\n            <bool>false</bool>\n           </attribute>\n          </widget>\n         </item>\n         <item>\n          <layout class=\"QVBoxLayout\" name=\"verticalLayout_4\">\n           <property name=\"spacing\">\n            <number>4</number>\n           </property>\n           <item>\n            <widget class=\"QPushButton\" name=\"saveDropFileCategoriesButton\">\n             <property name=\"text\">\n              <string>Save all</string>\n             </property>\n            </widget>\n           </item>\n           <item>\n            <widget class=\"QPushButton\" name=\"revertDropFileCategoriesButton\">\n             <property name=\"text\">\n              <string>Revert</string>\n             </property>\n            </widget>\n           </item>\n           <item>\n            <widget class=\"QPushButton\" name=\"addDropFileCategoryButton\">\n             <property name=\"text\">\n              <string>Add</string>\n             </property>\n            </widget>\n           </item>\n           <item>\n            <widget class=\"QPushButton\" name=\"deleteSelectedDropFileCategoryButton\">\n             <property name=\"text\">\n              <string>Delete</string>\n             </property>\n            </widget>\n           </item>\n           <item>\n            <spacer name=\"verticalSpacer\">\n             <property name=\"orientation\">\n              <enum>Qt::Vertical</enum>\n             </property>\n             <property name=\"sizeHint\" stdset=\"0\">\n              <size>\n               <width>20</width>\n               <height>40</height>\n              </size>\n             </property>\n            </spacer>\n           </item>\n          </layout>\n         </item>\n        </layout>\n       </item>\n       <item>\n        <widget class=\"QLabel\" name=\"fileDropTemplatesInfoLabel\">\n         <property name=\"text\">\n          <string>Write file name mask list as a list of wildcards, separated by semicolons without spaces.\nIn the template below use tokens: </string>\n         </property>\n         <property name=\"wordWrap\">\n          <bool>true</bool>\n         </property>\n        </widget>\n       </item>\n       <item>\n        <widget class=\"ScriptEditor\" name=\"dropFileCategoryTemplateEdit\"/>\n       </item>\n      </layout>\n     </widget>\n    </widget>\n   </item>\n  </layout>\n </widget>\n <customwidgets>\n  <customwidget>\n   <class>ScriptEditor</class>\n   <extends>QPlainTextEdit</extends>\n   <header>../../src/script_editor/script_editor.h</header>\n  </customwidget>\n </customwidgets>\n <resources/>\n <connections/>\n</ui>\n"
  },
  {
    "path": "vsedit/src/settings/actions_hotkey_edit_model.cpp",
    "content": "#include \"actions_hotkey_edit_model.h\"\n\n//==============================================================================\n\nconst int COLUMNS_NUMBER = 3;\nconst int ICON_COLUMN = 0;\nconst int TITLE_COLUMN = 1;\nconst int HOTKEY_COLUMN = 2;\n\n//==============================================================================\n\nActionsHotkeyEditModel::ActionsHotkeyEditModel(\n\tSettingsManager * a_pSettingsManager, QObject * a_pParent) :\n\tQAbstractItemModel(a_pParent)\n\t, m_pSettingsManager(a_pSettingsManager)\n{\n\tQ_ASSERT(m_pSettingsManager);\n\tm_actions = m_pSettingsManager->getStandardActions();\n\treloadHotkeysSettings();\n}\n\n// END OF ActionsHotkeyEditModel::ActionsHotkeyEditModel(\n//\t\tSettingsManager * a_pSettingsManager, QObject * a_pParent)\n//==============================================================================\n\nActionsHotkeyEditModel::~ActionsHotkeyEditModel()\n{\n\n}\n\n// END OF ActionsHotkeyEditModel::~ActionsHotkeyEditModel()\n//==============================================================================\n\nQModelIndex ActionsHotkeyEditModel::index(int a_row, int a_column,\n\tconst QModelIndex & a_parent) const\n{\n\t(void)a_parent;\n\treturn createIndex(a_row, a_column);\n}\n\n// END OF QModelIndex ActionsHotkeyEditModel::index(int a_row, int a_column,\n//\t\tconst QModelIndex & a_parent) const\n//==============================================================================\n\nQModelIndex ActionsHotkeyEditModel::parent(const QModelIndex & a_child) const\n{\n\t(void)a_child;\n\treturn QModelIndex();\n}\n\n// END OF QModelIndex ActionsHotkeyEditModel::parent(\n//\t\tconst QModelIndex & a_child) const\n//==============================================================================\n\nQt::ItemFlags ActionsHotkeyEditModel::flags(const QModelIndex & a_index) const\n{\n\tif (!a_index.isValid())\n\t{\n\t\treturn Qt::NoItemFlags;\n\t}\n\n\tQt::ItemFlags cellFlags = Qt::NoItemFlags\n\t\t| Qt::ItemIsEnabled\n\t\t| Qt::ItemIsSelectable\n\t;\n\n\tif(a_index.column() == HOTKEY_COLUMN)\n\t\tcellFlags |= Qt::ItemIsEditable;\n\n\treturn cellFlags;\n}\n\n// END OF Qt::ItemFlags ActionsHotkeyEditModel::flags(\n//\t\tconst QModelIndex & a_index) const\n//==============================================================================\n\nQVariant ActionsHotkeyEditModel::data(const QModelIndex & a_index, int a_role)\n\tconst\n{\n\tif(!a_index.isValid())\n\t\treturn QVariant();\n\n\tif((a_index.row() >= (int)m_actions.size()) ||\n\t\t(a_index.column() >= COLUMNS_NUMBER))\n\t\treturn QVariant();\n\n\tif((a_index.column() == ICON_COLUMN) && (a_role == Qt::DecorationRole))\n\t\treturn m_actions[a_index.row()].icon;\n\telse if((a_index.column() == TITLE_COLUMN) &&\n\t\t((a_role == Qt::DisplayRole) || (a_role == Qt::ToolTipRole)))\n\t\treturn m_actions[a_index.row()].title;\n\telse if((a_index.column() == HOTKEY_COLUMN) &&\n\t\t((a_role == Qt::DisplayRole) || (a_role == Qt::ToolTipRole) ||\n\t\t(a_role == Qt::EditRole)))\n\t\treturn m_actions[a_index.row()].hotkey;\n\n\treturn QVariant();\n}\n\n// END OF QVariant ActionsHotkeyEditModel::data(const QModelIndex & a_index,\n//\t\tint a_role) const\n//==============================================================================\n\nint ActionsHotkeyEditModel::rowCount(const QModelIndex & a_parent) const\n{\n\t(void)a_parent;\n\treturn (int)m_actions.size();\n}\n\n// END OF int ActionsHotkeyEditModel::rowCount(const QModelIndex & a_parent)\n//\t\tconst\n//==============================================================================\n\nint ActionsHotkeyEditModel::columnCount(const QModelIndex & a_parent) const\n{\n\t(void)a_parent;\n\treturn COLUMNS_NUMBER;\n}\n\n// END OF int ActionsHotkeyEditModel::columnCount(const QModelIndex & a_parent)\n//\t\tconst\n//==============================================================================\n\nbool ActionsHotkeyEditModel::setData(const QModelIndex & a_index,\n\tconst QVariant & a_value, int a_role)\n{\n\tif((a_index.column() != HOTKEY_COLUMN) || (a_role != Qt::EditRole))\n\t\treturn false;\n\n\tm_actions[a_index.row()].hotkey = a_value.value<QKeySequence>();\n\treturn true;\n}\n\n// END OF bool ActionsHotkeyEditModel::setData(const QModelIndex & a_index,\n//\t\tconst QVariant & a_value, int a_role)\n//==============================================================================\n\nvoid ActionsHotkeyEditModel::reloadHotkeysSettings()\n{\n\tfor(StandardAction & action : m_actions)\n\t\taction.hotkey = m_pSettingsManager->getHotkey(action.id);\n\temit dataChanged(createIndex(HOTKEY_COLUMN, 0),\n\t\tcreateIndex(HOTKEY_COLUMN, (int)m_actions.size() - 1));\n}\n\n// END OF void ActionsHotkeyEditModel::reloadHotkeysSettings()\n//==============================================================================\n\nvoid ActionsHotkeyEditModel::slotSaveActionsHotkeys()\n{\n\tfor(const StandardAction & action : m_actions)\n\t\tm_pSettingsManager->setHotkey(action.id, action.hotkey);\n}\n\n// END OF void ActionsHotkeyEditModel::slotSaveActionsHotkeys()\n//==============================================================================\n"
  },
  {
    "path": "vsedit/src/settings/actions_hotkey_edit_model.h",
    "content": "#ifndef ACTIONSHOTKEYEDITMODEL_H\n#define ACTIONSHOTKEYEDITMODEL_H\n\n#include \"../../../common-src/settings/settings_manager.h\"\n\n#include <QAbstractItemModel>\n\nclass ActionsHotkeyEditModel : public QAbstractItemModel\n{\n\tQ_OBJECT\n\npublic:\n\n\tActionsHotkeyEditModel(SettingsManager * a_pSettingsManager,\n\t\tQObject * a_pParent = nullptr);\n\n\tvirtual ~ActionsHotkeyEditModel();\n\n\tQModelIndex index(int a_row, int a_column,\n\t\tconst QModelIndex & a_parent = QModelIndex()) const override;\n\n\tQModelIndex parent(const QModelIndex & a_child) const override;\n\n\tQt::ItemFlags flags(const QModelIndex & a_index) const override;\n\n\tQVariant data(const QModelIndex & a_index, int a_role = Qt::DisplayRole)\n\t\tconst override;\n\n\tint rowCount(const QModelIndex & a_parent = QModelIndex()) const\n\t\toverride;\n\n\tint columnCount(const QModelIndex & a_parent = QModelIndex()) const\n\t\toverride;\n\n\tbool setData(const QModelIndex & a_index, const QVariant & a_value,\n\t\tint a_role = Qt::EditRole) override;\n\n\tvoid reloadHotkeysSettings();\n\npublic slots:\n\n\tvoid slotSaveActionsHotkeys();\n\nprivate:\n\n\tstd::vector<StandardAction> m_actions;\n\n\tSettingsManager * m_pSettingsManager;\n};\n\n#endif // ACTIONSHOTKEYEDITMODEL_H\n"
  },
  {
    "path": "vsedit/src/settings/clearable_key_sequence_editor.cpp",
    "content": "#include \"clearable_key_sequence_editor.h\"\n\n#include <QKeySequenceEdit>\n#include <QToolButton>\n#include <QBoxLayout>\n\n//==============================================================================\n\nClearableKeySequenceEditor::ClearableKeySequenceEditor(QWidget * a_pParent):\n\tQWidget(a_pParent)\n\t, m_pKeySequenceEdit(nullptr)\n\t, m_pClearKeySequenceButton(nullptr)\n{\n\tQHBoxLayout * pLayout = new QHBoxLayout(this);\n\tpLayout->setContentsMargins(0, 0, 0, 0);\n\tpLayout->setSpacing(0);\n\tsetLayout(pLayout);\n\n\tm_pKeySequenceEdit = new QKeySequenceEdit(this);\n\tpLayout->addWidget(m_pKeySequenceEdit);\n\n\tconnect(m_pKeySequenceEdit, SIGNAL(editingFinished()),\n\t\tthis, SIGNAL(editingFinished()));\n\n\tm_pClearKeySequenceButton = new QToolButton(this);\n\tm_pClearKeySequenceButton->setToolTip(tr(\"Erase hotkey\"));\n\tm_pClearKeySequenceButton->setIcon(QIcon(\":erase.png\"));\n\tpLayout->addWidget(m_pClearKeySequenceButton);\n\n\tconnect(m_pClearKeySequenceButton, SIGNAL(clicked()),\n\t\tm_pKeySequenceEdit, SLOT(clear()));\n}\n\n//==============================================================================\n\nClearableKeySequenceEditor::~ClearableKeySequenceEditor()\n{\n\n}\n\n//==============================================================================\n\nQKeySequence ClearableKeySequenceEditor::keySequence() const\n{\n\treturn m_pKeySequenceEdit->keySequence();\n}\n\n//==============================================================================\n\nvoid ClearableKeySequenceEditor::slotSetKeySequence(\n\tconst QKeySequence & a_keySequence)\n{\n\tm_pKeySequenceEdit->setKeySequence(a_keySequence);\n}\n\n//==============================================================================\n"
  },
  {
    "path": "vsedit/src/settings/clearable_key_sequence_editor.h",
    "content": "#ifndef CLEARABLE_KEY_SEQUENCE_EDITOR_H_INCLUDED\n#define CLEARABLE_KEY_SEQUENCE_EDITOR_H_INCLUDED\n\n#include <QWidget>\n#include <QKeySequence>\n\nclass QKeySequenceEdit;\nclass QToolButton;\n\nclass ClearableKeySequenceEditor : public QWidget\n{\n\tQ_OBJECT\n\npublic:\n\n\tClearableKeySequenceEditor(QWidget * a_pParent);\n\n\tvirtual ~ClearableKeySequenceEditor();\n\n\tQKeySequence keySequence() const;\n\npublic slots:\n\n\tvoid slotSetKeySequence(const QKeySequence & a_keySequence);\n\nsignals:\n\n\tvoid editingFinished();\n\nprivate:\n\n\tQKeySequenceEdit * m_pKeySequenceEdit;\n\n\tQToolButton * m_pClearKeySequenceButton;\n};\n\n#endif // CLEARABLE_KEY_SEQUENCE_EDITOR_H_INCLUDED\n"
  },
  {
    "path": "vsedit/src/settings/item_delegate_for_hotkey.cpp",
    "content": "#include \"item_delegate_for_hotkey.h\"\n\n#include \"clearable_key_sequence_editor.h\"\n\n//==============================================================================\n\nItemDelegateForHotkey::ItemDelegateForHotkey(QObject * a_pParent):\n\tQStyledItemDelegate(a_pParent)\n{\n\n}\n\n//==============================================================================\n\nItemDelegateForHotkey::~ItemDelegateForHotkey()\n{\n\n}\n\n//==============================================================================\n\nQWidget * ItemDelegateForHotkey::createEditor(QWidget * a_pParent,\n\tconst QStyleOptionViewItem & a_option, const QModelIndex & a_index) const\n{\n\t(void)a_option;\n\t(void)a_index;\n\tClearableKeySequenceEditor * pEditor =\n\t\tnew ClearableKeySequenceEditor(a_pParent);\n\tconnect(pEditor, SIGNAL(editingFinished()),\n\t\tthis, SLOT(slotCommitAndCloseEditor()));\n\treturn pEditor;\n}\n\n//==============================================================================\n\nvoid ItemDelegateForHotkey::setEditorData(QWidget * a_pEditor,\n\tconst QModelIndex & a_index) const\n{\n\tClearableKeySequenceEditor * pEditor =\n\t\tstatic_cast<ClearableKeySequenceEditor *>(a_pEditor);\n\tQVariant newValue = a_index.model()->data(a_index, Qt::EditRole);\n\tpEditor->slotSetKeySequence(newValue.value<QKeySequence>());\n}\n\n//==============================================================================\n\nvoid ItemDelegateForHotkey::updateEditorGeometry(QWidget * a_pEditor,\n\tconst QStyleOptionViewItem & a_option, const QModelIndex & a_index) const\n{\n\t(void)a_option;\n\t(void)a_index;\n\ta_pEditor->setGeometry(a_option.rect);\n\treturn;\n}\n\n//==============================================================================\n\nvoid ItemDelegateForHotkey::setModelData(QWidget * a_pEditor,\n\tQAbstractItemModel * a_model, const QModelIndex & a_index) const\n{\n\tClearableKeySequenceEditor * pEditor =\n\t\tstatic_cast<ClearableKeySequenceEditor *>(a_pEditor);\n\ta_model->setData(a_index, pEditor->keySequence(), Qt::EditRole);\n\treturn;\n}\n\n//==============================================================================\n\nvoid ItemDelegateForHotkey::slotCommitAndCloseEditor()\n{\n\tClearableKeySequenceEditor * pEditor =\n\t\tqobject_cast<ClearableKeySequenceEditor *>(sender());\n    emit commitData(pEditor);\n    emit closeEditor(pEditor);\n}\n\n//==============================================================================\n"
  },
  {
    "path": "vsedit/src/settings/item_delegate_for_hotkey.h",
    "content": "#ifndef ITEMDELEGATEFORHOTKEY_H\n#define ITEMDELEGATEFORHOTKEY_H\n\n#include <QStyledItemDelegate>\n\nclass ItemDelegateForHotkey : public QStyledItemDelegate\n{\n\tQ_OBJECT\n\npublic:\n\n\tItemDelegateForHotkey(QObject * a_pParent = nullptr);\n\n\tvirtual ~ItemDelegateForHotkey();\n\n\tQWidget * createEditor(QWidget * a_pParent,\n\t\tconst QStyleOptionViewItem & a_option, const QModelIndex & a_index)\n\t\tconst override;\n\n\tvoid setEditorData(QWidget * a_pEditor, const QModelIndex & a_index)\n\t\tconst override;\n\n\tvoid updateEditorGeometry(QWidget * a_pEditor,\n\t\tconst QStyleOptionViewItem & a_option, const QModelIndex & a_index)\n\t\tconst override;\n\n\tvoid setModelData(QWidget * a_pEditor, QAbstractItemModel * a_model,\n\t\tconst QModelIndex & a_index) const override;\n\nprivate slots:\n\n\tvoid slotCommitAndCloseEditor();\n};\n\n#endif // ITEMDELEGATEFORHOTKEY_H\n"
  },
  {
    "path": "vsedit/src/settings/settings_dialog.cpp",
    "content": "#include \"settings_dialog.h\"\n\n#include \"../../../common-src/settings/settings_manager.h\"\n#include \"../../../common-src/helpers.h\"\n\n#include \"item_delegate_for_hotkey.h\"\n#include \"theme_elements_model.h\"\n\n#include <QFileDialog>\n#include <QListWidgetItem>\n#include <QFontDialog>\n#include <QColorDialog>\n\n//==============================================================================\n\nSettingsDialog::SettingsDialog(SettingsManager * a_pSettingsManager,\n\tQWidget * a_pParent) :\n\tQDialog(a_pParent,\n\t\t  Qt::Dialog\n\t\t| Qt::CustomizeWindowHint\n\t\t| Qt::WindowTitleHint\n\t\t| Qt::WindowCloseButtonHint)\n\t, m_pSettingsManager(a_pSettingsManager)\n\t, m_pActionsHotkeyEditModel(nullptr)\n\t, m_pItemDelegateForHotkey(nullptr)\n\t, m_pThemeElementsModel(nullptr)\n{\n\tvsedit::disableFontKerning(this);\n\tm_ui.setupUi(this);\n\tvsedit::disableFontKerning(m_ui.hotkeysTable);\n\tvsedit::disableFontKerning(m_ui.themeElementsList);\n\tsetWindowIcon(QIcon(\":settings.png\"));\n\n\tm_ui.addVSLibraryPathButton->setIcon(QIcon(\":folder_add.png\"));\n\tm_ui.removeVSLibraryPathButton->setIcon(QIcon(\":folder_remove.png\"));\n\tm_ui.selectVSLibraryPathButton->setIcon(QIcon(\":folder.png\"));\n\n\tm_pActionsHotkeyEditModel = new ActionsHotkeyEditModel(m_pSettingsManager,\n\t\tthis);\n\tm_ui.hotkeysTable->setModel(m_pActionsHotkeyEditModel);\n\n\tm_pItemDelegateForHotkey = new ItemDelegateForHotkey(this);\n\tm_ui.hotkeysTable->setItemDelegateForColumn(2, m_pItemDelegateForHotkey);\n\n\tm_ui.hotkeysTable->resizeColumnsToContents();\n\n\tm_pThemeElementsModel = new ThemeElementsModel(m_pSettingsManager, this);\n\tm_ui.themeElementsList->setModel(m_pThemeElementsModel);\n\taddThemeElements();\n\n\tconnect(m_ui.okButton, SIGNAL(clicked()), this, SLOT(slotOk()));\n\tconnect(m_ui.applyButton, SIGNAL(clicked()), this, SLOT(slotApply()));\n\tconnect(m_ui.cancelButton, SIGNAL(clicked()), this, SLOT(reject()));\n\n\tconnect(m_ui.addVSLibraryPathButton, SIGNAL(clicked()),\n\t\tthis, SLOT(slotAddVSLibraryPath()));\n\tconnect(m_ui.removeVSLibraryPathButton, SIGNAL(clicked()),\n\t\tthis, SLOT(slotRemoveVSLibraryPath()));\n\tconnect(m_ui.selectVSLibraryPathButton, SIGNAL(clicked()),\n\t\tthis, SLOT(slotSelectVSLibraryPath()));\n\n\tconnect(m_ui.themeElementsList, SIGNAL(clicked(const QModelIndex &)),\n\t\tthis, SLOT(slotThemeElementSelected(const QModelIndex &)));\n\tconnect(m_ui.fontButton, SIGNAL(clicked()),\n\t\tthis, SLOT(slotFontButtonClicked()));\n\tconnect(m_ui.colourButton, SIGNAL(clicked()),\n\t\tthis, SLOT(slotColourButtonClicked()));\n}\n\n// END OF SettingsDialog::SettingsDialog(SettingsManager * a_pSettingsManager,\n//\t\tQWidget * a_pParent)\n//==============================================================================\n\nSettingsDialog::~SettingsDialog()\n{\n\n}\n\n// END OF SettingsDialog::~SettingsDialog()\n//==============================================================================\n\nvoid SettingsDialog::slotCall()\n{\n\tm_ui.autoLoadLastScriptCheckBox->setChecked(\n\t\tm_pSettingsManager->getAutoLoadLastScript());\n\tm_ui.reloadFromDiskCheckBox->setChecked(\n\t\tm_pSettingsManager->getReloadScriptFromDisk());\n\tm_ui.promptToSaveChangesCheckBox->setChecked(\n\t\tm_pSettingsManager->getPromptToSaveChanges());\n\tm_ui.portableModeCheckBox->setChecked(\n\t\tm_pSettingsManager->getPortableMode());\n\tm_ui.maxRecentFilesSpinBox->setValue(\n\t\tm_pSettingsManager->getMaxRecentFilesNumber());\n\tm_ui.charactersTypedToStartCompletionSpinBox->setValue(\n\t\tm_pSettingsManager->getCharactersTypedToStartCompletion());\n\tm_ui.useSpacesAsTabCheckBox->setChecked(\n\t\tm_pSettingsManager->getUseSpacesAsTab());\n\tm_ui.spacesInTabSpinBox->setValue(\n\t\tm_pSettingsManager->getSpacesInTab());\n\tm_ui.highlightSelectionMatchesCheckBox->setChecked(\n\t\tm_pSettingsManager->getHighlightSelectionMatches());\n\tm_ui.highlightSelectionMatchesMinLengthSpinBox->setValue(\n\t\tm_pSettingsManager->getHighlightSelectionMatchesMinLength());\n\tm_ui.rememberLastPreviewFrameCheckBox->setChecked(\n\t\tm_pSettingsManager->getRememberLastPreviewFrame());\n\tm_ui.alwaysKeepCurrentFrameCheckBox->setChecked(\n\t\tm_pSettingsManager->getAlwaysKeepCurrentFrame());\n\tm_ui.debugMsgCheckBox->setChecked(\n\t\tm_pSettingsManager->getShowDebugMessages());\n\tm_ui.snapshotCompressionLevelSpinBox->setValue(\n\t\tm_pSettingsManager->getPNGSnapshotCompressionLevel());\n\tm_ui.preferLibraryFromListCheckBox->setChecked(\n\t\tm_pSettingsManager->getPreferVSLibrariesFromList());\n\tm_ui.darkModeCheckBox->setChecked(m_pSettingsManager->getDarkMode());\n\n\tm_ui.vsLibraryPathsListWidget->clear();\n\tm_ui.vsLibraryPathsListWidget->addItems(\n\t\tm_pSettingsManager->getVapourSynthLibraryPaths());\n\tm_ui.vsLibraryPathEdit->clear();\n\n\tm_ui.settingsTabWidget->setCurrentIndex(0);\n\n\tm_pActionsHotkeyEditModel->reloadHotkeysSettings();\n\n\tm_pThemeElementsModel->reloadThemeSettings();\n\n\tQModelIndex firstElement = m_pActionsHotkeyEditModel->index(0, 0);\n\tm_ui.themeElementsList->setCurrentIndex(firstElement);\n\n\tshow();\n}\n\n// END OF void SettingsDialog::slotCall()\n//==============================================================================\n\nvoid SettingsDialog::addThemeElements()\n{\n\tm_pThemeElementsModel->addTextCharFormat(TEXT_FORMAT_ID_COMMON_SCRIPT_TEXT,\n\t\ttr(\"Common script text\"));\n\tm_pThemeElementsModel->addTextCharFormat(TEXT_FORMAT_ID_KEYWORD,\n\t\ttr(\"Keyword\"));\n\tm_pThemeElementsModel->addTextCharFormat(TEXT_FORMAT_ID_OPERATOR,\n\t\ttr(\"Operator\"));\n\tm_pThemeElementsModel->addTextCharFormat(TEXT_FORMAT_ID_STRING,\n\t\ttr(\"String\"));\n\tm_pThemeElementsModel->addTextCharFormat(TEXT_FORMAT_ID_NUMBER,\n\t\ttr(\"Number\"));\n\tm_pThemeElementsModel->addTextCharFormat(TEXT_FORMAT_ID_COMMENT,\n\t\ttr(\"Comment\"));\n\tm_pThemeElementsModel->addTextCharFormat(TEXT_FORMAT_ID_VS_CORE,\n\t\ttr(\"VapourSynth core\"));\n\tm_pThemeElementsModel->addTextCharFormat(TEXT_FORMAT_ID_VS_NAMESPACE,\n\t\ttr(\"VapourSynth namespace\"));\n\tm_pThemeElementsModel->addTextCharFormat(TEXT_FORMAT_ID_VS_FUNCTION,\n\t\ttr(\"VapourSynth function\"));\n\tm_pThemeElementsModel->addTextCharFormat(TEXT_FORMAT_ID_VS_ARGUMENT,\n\t\ttr(\"VapourSynth argument\"));\n\tm_pThemeElementsModel->addTextCharFormat(TEXT_FORMAT_ID_TIMELINE,\n\t\ttr(\"Timeline labels\"));\n\tm_pThemeElementsModel->addColor(COLOR_ID_TEXT_BACKGROUND,\n\t\ttr(\"Text background color\"));\n\tm_pThemeElementsModel->addColor(COLOR_ID_ACTIVE_LINE,\n\t\ttr(\"Active line color\"));\n\tm_pThemeElementsModel->addColor(COLOR_ID_SELECTION_MATCHES,\n\t\ttr(\"Selection matches color\"));\n\tm_pThemeElementsModel->addColor(COLOR_ID_TIMELINE_BOOKMARKS,\n\t\ttr(\"Timeline bookmarks color\"));\n}\n\n// END OF void SettingsDialog::addThemeElements()\n//==============================================================================\n\nvoid SettingsDialog::slotOk()\n{\n\tslotApply();\n\taccept();\n}\n\n// END OF void SettingsDialog::slotOk()\n//==============================================================================\n\nvoid SettingsDialog::slotApply()\n{\n\tm_pSettingsManager->setAutoLoadLastScript(\n\t\tm_ui.autoLoadLastScriptCheckBox->isChecked());\n\tm_pSettingsManager->setReloadScriptFromDisk(\n\t\tm_ui.reloadFromDiskCheckBox->isChecked());\n\tm_pSettingsManager->setPromptToSaveChanges(\n\t\tm_ui.promptToSaveChangesCheckBox->isChecked());\n\tm_pSettingsManager->setPortableMode(\n\t\tm_ui.portableModeCheckBox->isChecked());\n\tm_pSettingsManager->setMaxRecentFilesNumber(\n\t\tm_ui.maxRecentFilesSpinBox->value());\n\tm_pSettingsManager->setCharactersTypedToStartCompletion(\n\t\tm_ui.charactersTypedToStartCompletionSpinBox->value());\n\tm_pSettingsManager->setUseSpacesAsTab(\n\t\tm_ui.useSpacesAsTabCheckBox->isChecked());\n\tm_pSettingsManager->setSpacesInTab(\n\t\tm_ui.spacesInTabSpinBox->value());\n\tm_pSettingsManager->setHighlightSelectionMatches(\n\t\tm_ui.highlightSelectionMatchesCheckBox->isChecked());\n\tm_pSettingsManager->setHighlightSelectionMatchesMinLength(\n\t\tm_ui.highlightSelectionMatchesMinLengthSpinBox->value());\n\tm_pSettingsManager->setRememberLastPreviewFrame(\n\t\tm_ui.rememberLastPreviewFrameCheckBox->isChecked());\n\tm_pSettingsManager->setAlwaysKeepCurrentFrame(\n\t\tm_ui.alwaysKeepCurrentFrameCheckBox->isChecked());\n\tm_pSettingsManager->setShowDebugMessages(\n\t\tm_ui.debugMsgCheckBox->isChecked());\n\tm_pSettingsManager->setPNGSnapshotCompressionLevel(\n\t\tm_ui.snapshotCompressionLevelSpinBox->value());\n\tm_pSettingsManager->setPreferVSLibrariesFromList(\n\t\tm_ui.preferLibraryFromListCheckBox->isChecked());\n\n\tQStringList vapourSynthLibraryPaths;\n\tint vsLibraryPathsNumber = m_ui.vsLibraryPathsListWidget->count();\n\tfor(int i = 0; i < vsLibraryPathsNumber; ++i)\n\t{\n\t\tQString path = m_ui.vsLibraryPathsListWidget->item(i)->text();\n\t\tvapourSynthLibraryPaths.append(path);\n\t}\n\tvapourSynthLibraryPaths.removeDuplicates();\n\tm_pSettingsManager->setVapourSynthLibraryPaths(vapourSynthLibraryPaths);\n\n\tm_pActionsHotkeyEditModel->slotSaveActionsHotkeys();\n\n\tm_pThemeElementsModel->slotSaveThemeSettings();\n\tm_pSettingsManager->setDarkMode(m_ui.darkModeCheckBox->isChecked());\n\temit signalSettingsChanged();\n}\n\n// END OF void SettingsDialog::slotApply()\n//==============================================================================\n\nvoid SettingsDialog::slotAddVSLibraryPath()\n{\n\tQString newPath = m_ui.vsLibraryPathEdit->text();\n\tif(newPath.isEmpty())\n\t\treturn;\n\tint pathsNumber = m_ui.vsLibraryPathsListWidget->count();\n\tfor(int i = 0; i < pathsNumber; ++i)\n\t{\n\t\tQString path = m_ui.vsLibraryPathsListWidget->item(i)->text();\n\t\tif(path == newPath)\n\t\t\treturn;\n\t}\n\tQListWidgetItem * pListItem = new QListWidgetItem(newPath,\n\t\tm_ui.vsLibraryPathsListWidget);\n\tpListItem->setToolTip(newPath);\n}\n\n// END OF void SettingsDialog::slotAddVSLibraryPath()\n//==============================================================================\n\nvoid SettingsDialog::slotRemoveVSLibraryPath()\n{\n\tQListWidgetItem * pCurrentItem =\n\t\tm_ui.vsLibraryPathsListWidget->currentItem();\n\tif(pCurrentItem)\n\t\tdelete pCurrentItem;\n}\n\nvoid SettingsDialog::slotSelectVSLibraryPath()\n{\n\tQString path = QFileDialog::getExistingDirectory(this,\n\t\ttr(\"Select VapourSynth library search path\"),\n\t\tm_ui.vsLibraryPathEdit->text());\n\tif(!path.isEmpty())\n\t\tm_ui.vsLibraryPathEdit->setText(path);\n}\n\n// END OF void SettingsDialog::slotSelectVSLibraryPath()\n//==============================================================================\n\nvoid SettingsDialog::slotThemeElementSelected(const QModelIndex & a_index)\n{\n\tif(!a_index.isValid())\n\t\treturn;\n\n    QString themeElementId = m_pThemeElementsModel->data(\n\t\ta_index, Qt::UserRole).toString();\n    ThemeElementData themeElementData =\n\t\tm_pThemeElementsModel->getThemeElementData(themeElementId);\n\n\tif(themeElementData.id.isEmpty())\n\t\treturn;\n\n\tif(themeElementData.type == ThemeElementType::TextCharFormat)\n\t{\n\t\tm_ui.fontButton->setEnabled(true);\n\t\tm_ui.colourButton->setEnabled(true);\n\n\t\tm_ui.fontLabel->setText(\n\t\t\tthemeElementData.textCharFormat.font().family());\n\t\tm_ui.fontLabel->setFont(themeElementData.textCharFormat.font());\n\t\tQPalette newPalette = m_ui.fontLabel->palette();\n\t\tnewPalette.setColor(QPalette::WindowText,\n\t\t\tthemeElementData.textCharFormat.foreground().color());\n\t\tm_ui.fontLabel->setPalette(newPalette);\n\t\tm_ui.fontLabel->update();\n\n\t\tnewPalette = m_ui.colourFrame->palette();\n\t\tnewPalette.setColor(QPalette::Window,\n\t\t\tthemeElementData.textCharFormat.foreground().color());\n\t\tm_ui.colourFrame->setPalette(newPalette);\n\t\tm_ui.colourFrame->update();\n\t}\n\telse if(themeElementData.type == ThemeElementType::Color)\n\t{\n\t\tm_ui.fontButton->setEnabled(false);\n\t\tm_ui.colourButton->setEnabled(true);\n\n\t\tm_ui.fontLabel->setText(QString());\n\t\tm_ui.fontLabel->setFont(QFont());\n\t\tm_ui.fontLabel->setPalette(QPalette());\n\t\tm_ui.fontLabel->update();\n\n\t\tQPalette newPalette = m_ui.colourFrame->palette();\n\t\tnewPalette.setColor(QPalette::Window, themeElementData.color);\n\t\tm_ui.colourFrame->setPalette(newPalette);\n\t\tm_ui.colourFrame->update();\n\t}\n}\n\n// END OF void SettingsDialog::slotThemeElementSelected(\n//\t\tconst QModelIndex & a_index)\n//==============================================================================\n\nvoid SettingsDialog::slotFontButtonClicked()\n{\n\tQModelIndex index = m_ui.themeElementsList->currentIndex();\n\tQString id = m_pThemeElementsModel->data(index, Qt::UserRole).toString();\n\tThemeElementData themeElementData =\n\t\tm_pThemeElementsModel->getThemeElementData(id);\n\n\tQFontDialog fontDialog;\n\tfontDialog.setCurrentFont(themeElementData.textCharFormat.font());\n\tint returnCode = fontDialog.exec();\n\tif(returnCode == QDialog::Rejected)\n\t\treturn;\n\n\tQFont newFont = fontDialog.selectedFont();\n\tthemeElementData.textCharFormat.setFont(newFont);\n\tm_pThemeElementsModel->saveThemeElementData(themeElementData);\n\tm_ui.fontLabel->setText(newFont.family());\n\tm_ui.fontLabel->setFont(newFont);\n}\n\n// END OF void SettingsDialog::slotFontButtonClicked()\n//==============================================================================\n\nvoid SettingsDialog::slotColourButtonClicked()\n{\n\tQModelIndex index = m_ui.themeElementsList->currentIndex();\n\tQString id = m_pThemeElementsModel->data(index, Qt::UserRole).toString();\n\tThemeElementData themeElementData =\n\t\tm_pThemeElementsModel->getThemeElementData(id);\n\n\tQColorDialog colorDialog;\n\n\tif(themeElementData.type == ThemeElementType::TextCharFormat)\n\t{\n\t\tcolorDialog.setCurrentColor(\n\t\tthemeElementData.textCharFormat.foreground().color());\n\t}\n\telse if(themeElementData.type == ThemeElementType::Color)\n\t\tcolorDialog.setCurrentColor(themeElementData.color);\n\n\tint returnCode = colorDialog.exec();\n\tif(returnCode == QDialog::Rejected)\n\t\treturn;\n\n\tQColor newColor = colorDialog.selectedColor();\n\n\tif(themeElementData.type == ThemeElementType::TextCharFormat)\n\t{\n\t\tQBrush brush = themeElementData.textCharFormat.foreground();\n\t\tbrush.setColor(newColor);\n\t\tthemeElementData.textCharFormat.setForeground(brush);\n\n\t\tQPalette newPalette = m_ui.fontLabel->palette();\n\t\tnewPalette.setColor(QPalette::WindowText,\n\t\t\tthemeElementData.textCharFormat.foreground().color());\n\t\tm_ui.fontLabel->setPalette(newPalette);\n\t\tm_ui.fontLabel->update();\n\n\t\tnewPalette = m_ui.colourFrame->palette();\n\t\tnewPalette.setColor(QPalette::Window,\n\t\t\tthemeElementData.textCharFormat.foreground().color());\n\t\tm_ui.colourFrame->setPalette(newPalette);\n\t\tm_ui.colourFrame->update();\n\t}\n\telse if(themeElementData.type == ThemeElementType::Color)\n\t{\n\t\tthemeElementData.color = newColor;\n\n\t\tQPalette newPalette = m_ui.colourFrame->palette();\n\t\tnewPalette.setColor(QPalette::Window, themeElementData.color);\n\t\tm_ui.colourFrame->setPalette(newPalette);\n\t\tm_ui.colourFrame->update();\n\t}\n\n\tm_pThemeElementsModel->saveThemeElementData(themeElementData);\n}\n\n// END OF void SettingsDialog::slotColourButtonClicked()\n//==============================================================================\n"
  },
  {
    "path": "vsedit/src/settings/settings_dialog.h",
    "content": "#ifndef SETTINGSDIALOG_H\n#define SETTINGSDIALOG_H\n\n#include <ui_settings_dialog.h>\n\n#include \"actions_hotkey_edit_model.h\"\n\nclass SettingsManager;\nclass ItemDelegateForHotkey;\nclass ThemeElementsModel;\n\nclass SettingsDialog : public QDialog\n{\n\tQ_OBJECT\n\npublic:\n\n\tSettingsDialog(SettingsManager * a_pSettingsManager,\n\t\tQWidget * a_pParent = nullptr);\n\n\tvirtual ~SettingsDialog();\n\npublic slots:\n\n\tvoid slotCall();\n\nprotected:\n\nsignals:\n\n\tvoid signalSettingsChanged();\n\nprivate:\n\n\tvoid addThemeElements();\n\n\tUi::SettingsDialog m_ui;\n\n\tSettingsManager * m_pSettingsManager;\n\n\tActionsHotkeyEditModel * m_pActionsHotkeyEditModel;\n\n\tItemDelegateForHotkey * m_pItemDelegateForHotkey;\n\n\tThemeElementsModel * m_pThemeElementsModel;\n\nprivate slots:\n\n\tvoid slotOk();\n\n\tvoid slotApply();\n\n\tvoid slotAddVSLibraryPath();\n\n\tvoid slotRemoveVSLibraryPath();\n\n\tvoid slotSelectVSLibraryPath();\n\n\tvoid slotThemeElementSelected(const QModelIndex & a_index);\n\n\tvoid slotFontButtonClicked();\n\n\tvoid slotColourButtonClicked();\n};\n\n#endif // SETTINGSDIALOG_H\n"
  },
  {
    "path": "vsedit/src/settings/settings_dialog.ui",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<ui version=\"4.0\">\n <class>SettingsDialog</class>\n <widget class=\"QDialog\" name=\"SettingsDialog\">\n  <property name=\"geometry\">\n   <rect>\n    <x>0</x>\n    <y>0</y>\n    <width>512</width>\n    <height>665</height>\n   </rect>\n  </property>\n  <property name=\"windowTitle\">\n   <string>Settings - VapourSynth Editor</string>\n  </property>\n  <layout class=\"QVBoxLayout\" name=\"verticalLayout\">\n   <property name=\"spacing\">\n    <number>0</number>\n   </property>\n   <property name=\"leftMargin\">\n    <number>0</number>\n   </property>\n   <property name=\"topMargin\">\n    <number>0</number>\n   </property>\n   <property name=\"rightMargin\">\n    <number>0</number>\n   </property>\n   <property name=\"bottomMargin\">\n    <number>0</number>\n   </property>\n   <item>\n    <widget class=\"QTabWidget\" name=\"settingsTabWidget\">\n     <property name=\"currentIndex\">\n      <number>0</number>\n     </property>\n     <widget class=\"QWidget\" name=\"commonSettingsTab\">\n      <attribute name=\"title\">\n       <string>Common</string>\n      </attribute>\n      <layout class=\"QVBoxLayout\" name=\"verticalLayout_2\">\n       <property name=\"spacing\">\n        <number>4</number>\n       </property>\n       <property name=\"leftMargin\">\n        <number>6</number>\n       </property>\n       <property name=\"topMargin\">\n        <number>6</number>\n       </property>\n       <property name=\"rightMargin\">\n        <number>6</number>\n       </property>\n       <property name=\"bottomMargin\">\n        <number>6</number>\n       </property>\n       <item>\n        <widget class=\"QCheckBox\" name=\"autoLoadLastScriptCheckBox\">\n         <property name=\"text\">\n          <string>Automatically load the last script</string>\n         </property>\n         <property name=\"checked\">\n          <bool>true</bool>\n         </property>\n        </widget>\n       </item>\n       <item>\n        <widget class=\"QCheckBox\" name=\"reloadFromDiskCheckBox\">\n         <property name=\"text\">\n          <string>Periodically reload script text from disk (to sync with external changes)</string>\n         </property>\n         <property name=\"checked\">\n          <bool>false</bool>\n         </property>\n        </widget>\n       </item>\n       <item>\n        <widget class=\"QCheckBox\" name=\"promptToSaveChangesCheckBox\">\n         <property name=\"text\">\n          <string>Prompt to save changes when closing script file</string>\n         </property>\n         <property name=\"checked\">\n          <bool>true</bool>\n         </property>\n        </widget>\n       </item>\n       <item>\n        <layout class=\"QHBoxLayout\" name=\"recentFilesSettingsLayout\">\n         <item>\n          <widget class=\"QLabel\" name=\"maxRecentFilesLabel\">\n           <property name=\"text\">\n            <string>Limit the number of recent scripts in history to</string>\n           </property>\n          </widget>\n         </item>\n         <item>\n          <widget class=\"QSpinBox\" name=\"maxRecentFilesSpinBox\">\n           <property name=\"minimum\">\n            <number>1</number>\n           </property>\n           <property name=\"value\">\n            <number>10</number>\n           </property>\n          </widget>\n         </item>\n         <item>\n          <spacer name=\"horizontalSpacer_2\">\n           <property name=\"orientation\">\n            <enum>Qt::Horizontal</enum>\n           </property>\n           <property name=\"sizeHint\" stdset=\"0\">\n            <size>\n             <width>40</width>\n             <height>20</height>\n            </size>\n           </property>\n          </spacer>\n         </item>\n        </layout>\n       </item>\n       <item>\n        <layout class=\"QHBoxLayout\" name=\"autocompletionLayout\">\n         <item>\n          <widget class=\"QLabel\" name=\"charactersTypedToStartCompletionLabel\">\n           <property name=\"text\">\n            <string>Characters typed to start autocompletion</string>\n           </property>\n          </widget>\n         </item>\n         <item>\n          <widget class=\"QSpinBox\" name=\"charactersTypedToStartCompletionSpinBox\">\n           <property name=\"minimum\">\n            <number>0</number>\n           </property>\n           <property name=\"maximum\">\n            <number>10</number>\n           </property>\n           <property name=\"value\">\n            <number>2</number>\n           </property>\n          </widget>\n         </item>\n         <item>\n          <spacer name=\"horizontalSpacer_3\">\n           <property name=\"orientation\">\n            <enum>Qt::Horizontal</enum>\n           </property>\n           <property name=\"sizeHint\" stdset=\"0\">\n            <size>\n             <width>40</width>\n             <height>20</height>\n            </size>\n           </property>\n          </spacer>\n         </item>\n        </layout>\n       </item>\n       <item>\n        <widget class=\"QCheckBox\" name=\"useSpacesAsTabCheckBox\">\n         <property name=\"text\">\n          <string>Use spaces as Tab</string>\n         </property>\n        </widget>\n       </item>\n       <item>\n        <layout class=\"QHBoxLayout\" name=\"horizontalLayout\">\n         <item>\n          <widget class=\"QLabel\" name=\"spacesInTabLabel\">\n           <property name=\"text\">\n            <string>Space characters in Tab</string>\n           </property>\n          </widget>\n         </item>\n         <item>\n          <widget class=\"QSpinBox\" name=\"spacesInTabSpinBox\">\n           <property name=\"minimum\">\n            <number>1</number>\n           </property>\n           <property name=\"maximum\">\n            <number>80</number>\n           </property>\n           <property name=\"value\">\n            <number>4</number>\n           </property>\n          </widget>\n         </item>\n         <item>\n          <spacer name=\"horizontalSpacer_4\">\n           <property name=\"orientation\">\n            <enum>Qt::Horizontal</enum>\n           </property>\n           <property name=\"sizeHint\" stdset=\"0\">\n            <size>\n             <width>40</width>\n             <height>20</height>\n            </size>\n           </property>\n          </spacer>\n         </item>\n        </layout>\n       </item>\n       <item>\n        <widget class=\"QCheckBox\" name=\"highlightSelectionMatchesCheckBox\">\n         <property name=\"text\">\n          <string>Highlight selection matches</string>\n         </property>\n        </widget>\n       </item>\n       <item>\n        <layout class=\"QHBoxLayout\" name=\"horizontalLayout_2\">\n         <item>\n          <widget class=\"QLabel\" name=\"highlightSelectionMatchesMinLengthLabel\">\n           <property name=\"text\">\n            <string>Minimum legth to highlight</string>\n           </property>\n          </widget>\n         </item>\n         <item>\n          <widget class=\"QSpinBox\" name=\"highlightSelectionMatchesMinLengthSpinBox\">\n           <property name=\"maximum\">\n            <number>80</number>\n           </property>\n           <property name=\"value\">\n            <number>3</number>\n           </property>\n          </widget>\n         </item>\n         <item>\n          <spacer name=\"horizontalSpacer_5\">\n           <property name=\"orientation\">\n            <enum>Qt::Horizontal</enum>\n           </property>\n           <property name=\"sizeHint\" stdset=\"0\">\n            <size>\n             <width>40</width>\n             <height>20</height>\n            </size>\n           </property>\n          </spacer>\n         </item>\n        </layout>\n       </item>\n       <item>\n        <widget class=\"QCheckBox\" name=\"rememberLastPreviewFrameCheckBox\">\n         <property name=\"text\">\n          <string>Remember last previewed frame on exit</string>\n         </property>\n        </widget>\n       </item>\n       <item>\n        <widget class=\"QCheckBox\" name=\"alwaysKeepCurrentFrameCheckBox\">\n         <property name=\"text\">\n          <string>Keep current frame when previewing different script</string>\n         </property>\n        </widget>\n       </item>\n       <item>\n        <layout class=\"QHBoxLayout\" name=\"horizontalLayout_3\">\n         <item>\n          <widget class=\"QLabel\" name=\"snapshotCompressionLevelLabel\">\n           <property name=\"text\">\n            <string>PNG snapshot compression level (0-100 for size factor)</string>\n           </property>\n          </widget>\n         </item>\n         <item>\n          <widget class=\"QSpinBox\" name=\"snapshotCompressionLevelSpinBox\">\n           <property name=\"maximum\">\n            <number>100</number>\n           </property>\n           <property name=\"minimum\">\n            <number>0</number>\n           </property>\n           <property name=\"value\">\n            <number>0</number>\n           </property>\n          </widget>\n         </item>\n         <item>\n          <spacer name=\"horizontalSpacer_6\">\n           <property name=\"orientation\">\n            <enum>Qt::Horizontal</enum>\n           </property>\n           <property name=\"sizeHint\" stdset=\"0\">\n            <size>\n             <width>40</width>\n             <height>20</height>\n            </size>\n           </property>\n          </spacer>\n         </item>\n        </layout>\n       </item>\n       <item>\n        <widget class=\"QCheckBox\" name=\"debugMsgCheckBox\">\n         <property name=\"text\">\n          <string>Show debug messages</string>\n         </property>\n        </widget>\n       </item>\n       <item>\n        <widget class=\"QCheckBox\" name=\"darkModeCheckBox\">\n         <property name=\"text\">\n          <string>Dark theme (overriding OS theme; relaunching required)</string>\n         </property>\n        </widget>\n       </item>\n       <item>\n        <widget class=\"QFrame\" name=\"delimiter\">\n         <property name=\"frameShape\">\n          <enum>QFrame::HLine</enum>\n         </property>\n         <property name=\"frameShadow\">\n          <enum>QFrame::Sunken</enum>\n         </property>\n        </widget>\n       </item>\n       <item>\n        <widget class=\"QLabel\" name=\"portableModeLabel\">\n         <property name=\"text\">\n          <string>Portable mode means that editor stores its settings in the same folder with its executable. Editors determines if it is running in portable mode by looking for the configuration file in its folder. Please make sure you have the rights to write files in the editor's folder before you switch to this mode.</string>\n         </property>\n         <property name=\"wordWrap\">\n          <bool>true</bool>\n         </property>\n        </widget>\n       </item>\n       <item>\n        <widget class=\"QCheckBox\" name=\"portableModeCheckBox\">\n         <property name=\"text\">\n          <string>Portable mode enabled</string>\n         </property>\n        </widget>\n       </item>\n       <item>\n        <spacer name=\"verticalSpacer\">\n         <property name=\"orientation\">\n          <enum>Qt::Vertical</enum>\n         </property>\n         <property name=\"sizeHint\" stdset=\"0\">\n          <size>\n           <width>20</width>\n           <height>31</height>\n          </size>\n         </property>\n        </spacer>\n       </item>\n      </layout>\n     </widget>\n     <widget class=\"QWidget\" name=\"pathsSettingsTab\">\n      <attribute name=\"title\">\n       <string>Paths</string>\n      </attribute>\n      <layout class=\"QVBoxLayout\" name=\"verticalLayout_3\">\n       <property name=\"spacing\">\n        <number>2</number>\n       </property>\n       <property name=\"leftMargin\">\n        <number>2</number>\n       </property>\n       <property name=\"topMargin\">\n        <number>2</number>\n       </property>\n       <property name=\"rightMargin\">\n        <number>2</number>\n       </property>\n       <property name=\"bottomMargin\">\n        <number>2</number>\n       </property>\n       <item>\n        <widget class=\"QGroupBox\" name=\"vsLibraryPathsGroupBox\">\n         <property name=\"title\">\n          <string>VapourSynth library (VSScript) search paths</string>\n         </property>\n         <layout class=\"QGridLayout\" name=\"gridLayout_2\">\n          <property name=\"leftMargin\">\n           <number>0</number>\n          </property>\n          <property name=\"topMargin\">\n           <number>0</number>\n          </property>\n          <property name=\"rightMargin\">\n           <number>0</number>\n          </property>\n          <property name=\"bottomMargin\">\n           <number>0</number>\n          </property>\n          <property name=\"spacing\">\n           <number>2</number>\n          </property>\n          <item row=\"0\" column=\"0\" rowspan=\"3\">\n           <widget class=\"QListWidget\" name=\"vsLibraryPathsListWidget\">\n            <property name=\"horizontalScrollBarPolicy\">\n             <enum>Qt::ScrollBarAlwaysOff</enum>\n            </property>\n            <property name=\"alternatingRowColors\">\n             <bool>true</bool>\n            </property>\n            <property name=\"textElideMode\">\n             <enum>Qt::ElideNone</enum>\n            </property>\n           </widget>\n          </item>\n          <item row=\"0\" column=\"1\">\n           <widget class=\"QToolButton\" name=\"removeVSLibraryPathButton\">\n            <property name=\"toolTip\">\n             <string>Remove VapourSynth library search path</string>\n            </property>\n            <property name=\"text\">\n             <string/>\n            </property>\n           </widget>\n          </item>\n          <item row=\"1\" column=\"1\">\n           <spacer name=\"verticalSpacer_3\">\n            <property name=\"orientation\">\n             <enum>Qt::Vertical</enum>\n            </property>\n            <property name=\"sizeHint\" stdset=\"0\">\n             <size>\n              <width>20</width>\n              <height>124</height>\n             </size>\n            </property>\n           </spacer>\n          </item>\n          <item row=\"2\" column=\"1\">\n           <widget class=\"QToolButton\" name=\"addVSLibraryPathButton\">\n            <property name=\"toolTip\">\n             <string>Add VapourSynth library search path</string>\n            </property>\n            <property name=\"text\">\n             <string/>\n            </property>\n           </widget>\n          </item>\n          <item row=\"3\" column=\"0\">\n           <widget class=\"QLineEdit\" name=\"vsLibraryPathEdit\"/>\n          </item>\n          <item row=\"3\" column=\"1\">\n           <widget class=\"QToolButton\" name=\"selectVSLibraryPathButton\">\n            <property name=\"toolTip\">\n             <string>Select path</string>\n            </property>\n            <property name=\"text\">\n             <string/>\n            </property>\n           </widget>\n          </item>\n         </layout>\n        </widget>\n       </item>\n       <item>\n        <widget class=\"QCheckBox\" name=\"preferLibraryFromListCheckBox\">\n         <property name=\"text\">\n          <string>Libraries from this list are loaded prior to environment configs</string>\n         </property>\n        </widget>\n       </item>\n      </layout>\n     </widget>\n     <widget class=\"QWidget\" name=\"hotkeysSettingsTab\">\n      <attribute name=\"title\">\n       <string>Hotkeys</string>\n      </attribute>\n      <layout class=\"QVBoxLayout\" name=\"verticalLayout_4\">\n       <property name=\"spacing\">\n        <number>0</number>\n       </property>\n       <property name=\"leftMargin\">\n        <number>0</number>\n       </property>\n       <property name=\"topMargin\">\n        <number>0</number>\n       </property>\n       <property name=\"rightMargin\">\n        <number>0</number>\n       </property>\n       <property name=\"bottomMargin\">\n        <number>0</number>\n       </property>\n       <item>\n        <widget class=\"QTableView\" name=\"hotkeysTable\">\n         <property name=\"editTriggers\">\n          <set>QAbstractItemView::AnyKeyPressed|QAbstractItemView::DoubleClicked|QAbstractItemView::EditKeyPressed|QAbstractItemView::SelectedClicked</set>\n         </property>\n         <property name=\"alternatingRowColors\">\n          <bool>true</bool>\n         </property>\n         <property name=\"selectionMode\">\n          <enum>QAbstractItemView::SingleSelection</enum>\n         </property>\n         <property name=\"selectionBehavior\">\n          <enum>QAbstractItemView::SelectRows</enum>\n         </property>\n         <property name=\"textElideMode\">\n          <enum>Qt::ElideNone</enum>\n         </property>\n         <property name=\"horizontalScrollMode\">\n          <enum>QAbstractItemView::ScrollPerPixel</enum>\n         </property>\n         <attribute name=\"horizontalHeaderVisible\">\n          <bool>false</bool>\n         </attribute>\n         <attribute name=\"horizontalHeaderStretchLastSection\">\n          <bool>true</bool>\n         </attribute>\n         <attribute name=\"verticalHeaderVisible\">\n          <bool>false</bool>\n         </attribute>\n        </widget>\n       </item>\n      </layout>\n     </widget>\n     <widget class=\"QWidget\" name=\"themeSettingsTab\">\n      <property name=\"contextMenuPolicy\">\n       <enum>Qt::PreventContextMenu</enum>\n      </property>\n      <attribute name=\"title\">\n       <string>Theme</string>\n      </attribute>\n      <layout class=\"QVBoxLayout\" name=\"verticalLayout_5\">\n       <property name=\"spacing\">\n        <number>4</number>\n       </property>\n       <property name=\"leftMargin\">\n        <number>6</number>\n       </property>\n       <property name=\"topMargin\">\n        <number>6</number>\n       </property>\n       <property name=\"rightMargin\">\n        <number>6</number>\n       </property>\n       <property name=\"bottomMargin\">\n        <number>6</number>\n       </property>\n       <item>\n        <widget class=\"QLabel\" name=\"themeElementsLabel\">\n         <property name=\"text\">\n          <string>Theme elements</string>\n         </property>\n        </widget>\n       </item>\n       <item>\n        <widget class=\"QListView\" name=\"themeElementsList\">\n         <property name=\"editTriggers\">\n          <set>QAbstractItemView::NoEditTriggers</set>\n         </property>\n         <property name=\"selectionBehavior\">\n          <enum>QAbstractItemView::SelectRows</enum>\n         </property>\n         <property name=\"verticalScrollMode\">\n          <enum>QAbstractItemView::ScrollPerPixel</enum>\n         </property>\n         <property name=\"horizontalScrollMode\">\n          <enum>QAbstractItemView::ScrollPerPixel</enum>\n         </property>\n         <property name=\"resizeMode\">\n          <enum>QListView::Adjust</enum>\n         </property>\n        </widget>\n       </item>\n       <item>\n        <layout class=\"QFormLayout\" name=\"formLayout\">\n         <item row=\"0\" column=\"0\">\n          <widget class=\"QPushButton\" name=\"fontButton\">\n           <property name=\"text\">\n            <string>Font</string>\n           </property>\n          </widget>\n         </item>\n         <item row=\"0\" column=\"1\">\n          <widget class=\"QLabel\" name=\"fontLabel\">\n           <property name=\"sizePolicy\">\n            <sizepolicy hsizetype=\"MinimumExpanding\" vsizetype=\"Minimum\">\n             <horstretch>0</horstretch>\n             <verstretch>0</verstretch>\n            </sizepolicy>\n           </property>\n           <property name=\"text\">\n            <string/>\n           </property>\n          </widget>\n         </item>\n         <item row=\"1\" column=\"0\">\n          <widget class=\"QPushButton\" name=\"colourButton\">\n           <property name=\"text\">\n            <string>Colour</string>\n           </property>\n          </widget>\n         </item>\n         <item row=\"1\" column=\"1\">\n          <widget class=\"QFrame\" name=\"colourFrame\">\n           <property name=\"autoFillBackground\">\n            <bool>true</bool>\n           </property>\n           <property name=\"frameShape\">\n            <enum>QFrame::Box</enum>\n           </property>\n           <property name=\"frameShadow\">\n            <enum>QFrame::Plain</enum>\n           </property>\n          </widget>\n         </item>\n        </layout>\n       </item>\n      </layout>\n     </widget>\n    </widget>\n   </item>\n   <item>\n    <layout class=\"QHBoxLayout\" name=\"decisionButtonsLayout\">\n     <property name=\"spacing\">\n      <number>2</number>\n     </property>\n     <item>\n      <spacer name=\"horizontalSpacer\">\n       <property name=\"orientation\">\n        <enum>Qt::Horizontal</enum>\n       </property>\n       <property name=\"sizeHint\" stdset=\"0\">\n        <size>\n         <width>40</width>\n         <height>20</height>\n        </size>\n       </property>\n      </spacer>\n     </item>\n     <item>\n      <widget class=\"QPushButton\" name=\"okButton\">\n       <property name=\"text\">\n        <string>OK</string>\n       </property>\n      </widget>\n     </item>\n     <item>\n      <widget class=\"QPushButton\" name=\"applyButton\">\n       <property name=\"text\">\n        <string>Apply</string>\n       </property>\n      </widget>\n     </item>\n     <item>\n      <widget class=\"QPushButton\" name=\"cancelButton\">\n       <property name=\"text\">\n        <string>Cancel</string>\n       </property>\n      </widget>\n     </item>\n    </layout>\n   </item>\n  </layout>\n </widget>\n <resources/>\n <connections/>\n</ui>\n"
  },
  {
    "path": "vsedit/src/settings/theme_elements_model.cpp",
    "content": "#include \"theme_elements_model.h\"\n\n#include \"../../../common-src/settings/settings_manager.h\"\n\n//==============================================================================\n\nThemeElementsModel::ThemeElementsModel(SettingsManager * a_pSettingsManager,\n\tQObject * a_pParent) : QAbstractItemModel(a_pParent)\n\t, m_pSettingsManager(a_pSettingsManager)\n{\n\n}\n\n// END OF ThemeElementsModel::ThemeElementsModel(\n//\t\tSettingsManager * a_pSettingsManager, QObject * a_pParent)\n//==============================================================================\n\nThemeElementsModel::~ThemeElementsModel()\n{\n\n}\n\n// END OF ThemeElementsModel::~ThemeElementsModel()\n//==============================================================================\n\nQModelIndex ThemeElementsModel::index(int a_row, int a_column,\n\tconst QModelIndex & a_parent) const\n{\n\t(void)a_parent;\n\treturn createIndex(a_row, a_column);\n}\n\n// END OF QModelIndex ThemeElementsModel::index(int a_row, int a_column,\n//\t\tconst QModelIndex & a_parent) const\n//==============================================================================\n\nQModelIndex ThemeElementsModel::parent(const QModelIndex & a_child) const\n{\n\t(void)a_child;\n\treturn QModelIndex();\n}\n\n// END OF QModelIndex ThemeElementsModel::parent(const QModelIndex & a_child)\n//\t\tconst\n//==============================================================================\n\nQt::ItemFlags ThemeElementsModel::flags(const QModelIndex & a_index) const\n{\n\tif (!a_index.isValid())\n\t{\n\t\treturn Qt::NoItemFlags;\n\t}\n\n\tQt::ItemFlags cellFlags = Qt::NoItemFlags\n\t\t| Qt::ItemIsEnabled\n\t\t| Qt::ItemIsSelectable\n\t;\n\n\treturn cellFlags;\n}\n\n// END OF Qt::ItemFlags ThemeElementsModel::flags(const QModelIndex & a_index)\n//\t\tconst\n//==============================================================================\n\nQVariant ThemeElementsModel::data(const QModelIndex & a_index, int a_role) const\n{\n\tif(!a_index.isValid())\n\t\treturn QVariant();\n\n\tif((a_index.row() >= (int)m_themeElementsList.size()) ||\n\t\t(a_index.column() >= 1))\n\t\treturn QVariant();\n\n\tif(a_role == Qt::DecorationRole)\n\t\treturn m_themeElementsList[a_index.row()].icon;\n\telse if((a_role == Qt::DisplayRole) ||\n\t\t(a_role == Qt::ToolTipRole))\n\t\treturn m_themeElementsList[a_index.row()].text;\n\telse if(a_role == Qt::UserRole)\n\t\treturn m_themeElementsList[a_index.row()].id;\n\n\treturn QVariant();\n}\n\n// END OF QVariant ThemeElementsModel::data(const QModelIndex & a_index,\n//\t\tint a_role) const\n//==============================================================================\n\nint ThemeElementsModel::rowCount(const QModelIndex & a_parent) const\n{\n\t(void)a_parent;\n\treturn (int)m_themeElementsList.size();\n}\n\n// END OF int ThemeElementsModel::rowCount(const QModelIndex & a_parent) const\n//==============================================================================\n\nint ThemeElementsModel::columnCount(const QModelIndex & a_parent) const\n{\n\t(void)a_parent;\n\treturn 2;\n}\n\n// END OF int ThemeElementsModel::columnCount(const QModelIndex & a_parent)\n//\t\tconst\n//==============================================================================\n\nbool ThemeElementsModel::setData(const QModelIndex & a_index,\n\tconst QVariant & a_value, int a_role)\n{\n\t(void)a_index;\n\t(void)a_value;\n\t(void)a_role;\n\treturn false;\n}\n\n// END OF bool ThemeElementsModel::setData(const QModelIndex & a_index,\n//\t\tconst QVariant & a_value, int a_role)\n//==============================================================================\n\nvoid ThemeElementsModel::addThemeElement(\n\tconst ThemeElementData & a_themeElementData)\n{\n\tfor(size_t i = 0; i < m_themeElementsList.size(); ++i)\n\t{\n\t\tif(m_themeElementsList[i].id == a_themeElementData.id)\n\t\t\treturn;\n\t}\n\n\tm_themeElementsList.push_back(a_themeElementData);\n\temit layoutChanged();\n}\n\n// END OF void ThemeElementsModel::addThemeElement(\n//\t\tconst ThemeElementData & a_themeElementData)\n//==============================================================================\n\nvoid ThemeElementsModel::addTextCharFormat(const QString & a_id,\n\tconst QString & a_text)\n{\n\tThemeElementData newThemeElementData;\n\tnewThemeElementData.type = ThemeElementType::TextCharFormat;\n\tnewThemeElementData.id = a_id;\n\tnewThemeElementData.text = a_text;\n\tnewThemeElementData.icon = QIcon(QString(\":font.png\"));\n\tnewThemeElementData.textCharFormat =\n\t\tm_pSettingsManager->getTextFormat(a_id);\n\taddThemeElement(newThemeElementData);\n}\n\n// END OF void ThemeElementsModel::addTextCharFormat(const QString & a_id,\n//\t\tconst QString & a_text)\n//==============================================================================\n\nvoid ThemeElementsModel::addColor(const QString & a_id,\n\tconst QString & a_text)\n{\n\tThemeElementData newThemeElementData;\n\tnewThemeElementData.type = ThemeElementType::Color;\n\tnewThemeElementData.id = a_id;\n\tnewThemeElementData.text = a_text;\n\tnewThemeElementData.icon = QIcon(QString(\":color_swatch.png\"));\n\tnewThemeElementData.color = m_pSettingsManager->getColor(a_id);\n\taddThemeElement(newThemeElementData);\n}\n\n// END OF void ThemeElementsModel::addColor(const QString & a_id,\n//\t\tconst QString & a_text)\n//==============================================================================\n\nvoid ThemeElementsModel::reloadThemeSettings()\n{\n\tfor(size_t i = 0; i < m_themeElementsList.size(); ++i)\n\t{\n\t\tif(m_themeElementsList[i].type == ThemeElementType::TextCharFormat)\n\t\t{\n\t\t\tm_themeElementsList[i].textCharFormat =\n\t\t\t\tm_pSettingsManager->getTextFormat(m_themeElementsList[i].id);\n\t\t}\n\t\telse if(m_themeElementsList[i].type == ThemeElementType::Color)\n\t\t{\n\t\t\tm_themeElementsList[i].color =\n\t\t\t\tm_pSettingsManager->getColor(m_themeElementsList[i].id);\n\t\t}\n\t}\n}\n\n// END OF void ThemeElementsModel::reloadThemeSettings()\n//==============================================================================\n\nThemeElementData ThemeElementsModel::getThemeElementData(const QString & a_id)\n{\n\tfor(size_t i = 0; i < m_themeElementsList.size(); ++i)\n\t{\n\t\tif(m_themeElementsList[i].id == a_id)\n\t\t\treturn m_themeElementsList[i];\n\t}\n\n\treturn ThemeElementData();\n}\n\n// END OF ThemeElementData ThemeElementsModel::getThemeElementData(\n//\t\tconst QString & a_id)\n//==============================================================================\n\nbool ThemeElementsModel::saveThemeElementData(\n\tconst ThemeElementData & a_themeElementData)\n{\n\tfor(size_t i = 0; i < m_themeElementsList.size(); ++i)\n\t{\n\t\tif(m_themeElementsList[i].id != a_themeElementData.id)\n\t\t\tcontinue;\n\n\t\tm_themeElementsList[i].textCharFormat =\n\t\t\ta_themeElementData.textCharFormat;\n\t\tm_themeElementsList[i].color = a_themeElementData.color;\n\t\treturn true;\n\t}\n\n\treturn false;\n}\n\n// END OF bool ThemeElementsModel::saveThemeElementData(\n//\t\tconst ThemeElementData & a_themeElementData)\n//==============================================================================\n\nvoid ThemeElementsModel::slotSaveThemeSettings()\n{\n\tfor(size_t i = 0; i < m_themeElementsList.size(); ++i)\n\t{\n\t\tif(m_themeElementsList[i].type == ThemeElementType::TextCharFormat)\n\t\t{\n\t\t\tm_pSettingsManager->setTextFormat(m_themeElementsList[i].id,\n\t\t\t\tm_themeElementsList[i].textCharFormat);\n\t\t}\n\t\telse if(m_themeElementsList[i].type == ThemeElementType::Color)\n\t\t{\n\t\t\tm_pSettingsManager->setColor(m_themeElementsList[i].id,\n\t\t\t\tm_themeElementsList[i].color);\n\t\t}\n\t}\n}\n\n// END OF void ThemeElementsModel::slotSaveThemeSettings()\n//==============================================================================\n"
  },
  {
    "path": "vsedit/src/settings/theme_elements_model.h",
    "content": "#ifndef THEME_ELEMENTS_MODEL_H_INCLUDED\n#define THEME_ELEMENTS_MODEL_H_INCLUDED\n\n#include \"../../../common-src/settings/settings_definitions.h\"\n\n#include <QAbstractItemModel>\n#include <QIcon>\n#include <vector>\n\nclass SettingsManager;\n\nenum class ThemeElementType\n{\n\tTextCharFormat,\n\tColor\n};\n\nstruct ThemeElementData\n{\n\tThemeElementType type;\n\tQString id;\n\tQString text;\n\tQIcon icon;\n\tQTextCharFormat textCharFormat;\n\tQColor color;\n};\n\ntypedef std::vector<ThemeElementData> ThemeElementsList;\n\nclass ThemeElementsModel : public QAbstractItemModel\n{\n\tQ_OBJECT\n\npublic:\n\n\tThemeElementsModel(SettingsManager * a_pSettingsManager,\n\t\tQObject * a_pParent = nullptr);\n\n\tvirtual ~ThemeElementsModel();\n\n\tQModelIndex index(int a_row, int a_column,\n\t\tconst QModelIndex & a_parent = QModelIndex()) const override;\n\n\tQModelIndex parent(const QModelIndex & a_child) const override;\n\n\tQt::ItemFlags flags(const QModelIndex & a_index) const override;\n\n\tQVariant data(const QModelIndex & a_index, int a_role = Qt::DisplayRole)\n\t\tconst override;\n\n\tint rowCount(const QModelIndex & a_parent = QModelIndex()) const\n\t\toverride;\n\n\tint columnCount(const QModelIndex & a_parent = QModelIndex()) const\n\t\toverride;\n\n\tbool setData(const QModelIndex & a_index, const QVariant & a_value,\n\t\tint a_role = Qt::EditRole) override;\n\n\tvoid addThemeElement(const ThemeElementData & a_themeElementData);\n\n\tvoid addTextCharFormat(const QString & a_id, const QString & a_text);\n\n\tvoid addColor(const QString & a_id, const QString & a_text);\n\n\tvoid reloadThemeSettings();\n\n\tThemeElementData getThemeElementData(const QString & a_id);\n\n\tbool saveThemeElementData(const ThemeElementData & a_themeElementData);\n\npublic slots:\n\n\tvoid slotSaveThemeSettings();\n\nprivate:\n\n\tThemeElementsList m_themeElementsList;\n\n\tSettingsManager * m_pSettingsManager;\n};\n\n#endif // THEME_ELEMENTS_MODEL_H_INCLUDED\n"
  },
  {
    "path": "vsedit/src/vapoursynth/vapoursynth_plugins_manager.cpp",
    "content": "#include \"vapoursynth_plugins_manager.h\"\n\n#include \"../../../common-src/helpers.h\"\n#include \"../../../common-src/settings/settings_manager.h\"\n\n#include <QDir>\n#include <QLibrary>\n#include <QFileInfoList>\n#include <QSettings>\n#include <QProcessEnvironment>\n#include <algorithm>\n\n//==============================================================================\n\nconst char CORE_PLUGINS_FILEPATH[] = \"core\";\n\n//==============================================================================\n\nVapourSynthPluginsManager::VapourSynthPluginsManager(\n\tSettingsManager * a_pSettingsManager, const VSAPI * a_cpVSAPI, QObject * a_pParent):\n\tQObject(a_pParent)\n\t, m_pluginsList()\n\t, m_currentPluginPath()\n\t, m_pluginAlreadyLoaded(false)\n\t, m_pSettingsManager(a_pSettingsManager)\n{\n\tif(a_pParent)\n\t{\n\t\tconnect(this, SIGNAL(signalWriteLogMessage(int, const QString &)),\n\t\ta_pParent, SLOT(slotWriteLogMessage(int, const QString &)));\n\t}\n\tslotRefill(a_cpVSAPI);\n}\n\n// END OF VapourSynthPluginsManager::VapourSynthPluginsManager(\n//\t\tSettingsManager * a_pSettingsManager, QObject * a_pParent)\n//==============================================================================\n\nVapourSynthPluginsManager::~VapourSynthPluginsManager()\n{\n\tslotClear();\n}\n\n// END OF VapourSynthPluginsManager::~VapourSynthPluginsManager()\n//==============================================================================\n\nvoid VapourSynthPluginsManager::getCorePlugins(const VSAPI * a_cpVSAPI)\n{\n\tif(!a_cpVSAPI)\n\t\treturn;\n\n\tVSCore * pCore = a_cpVSAPI->createCore(0);\n\tif(!pCore)\n\t{\n\t\temit signalWriteLogMessage(mtCritical, \"VapourSynth plugins manager: \"\n\t\t\t\"Failed to create VapourSynth core!\");\n\t\treturn;\n\t}\n\n\tVSPlugin * pPlugin = a_cpVSAPI->getNextPlugin(nullptr, pCore);\n\twhile(pPlugin)\n\t{\n\t\tm_pluginsList.emplace_back();\n\t\tVSData::Plugin & pluginData = m_pluginsList.back();\n\t\tpluginData.filepath = a_cpVSAPI->getPluginPath(pPlugin);\n\t\tpluginData.id = a_cpVSAPI->getPluginID(pPlugin);\n\t\tpluginData.pluginNamespace = a_cpVSAPI->getPluginNamespace(pPlugin);\n\t\tpluginData.name = a_cpVSAPI->getPluginName(pPlugin);\n\n\t\tVSPluginFunction * pPluginFunction =\n\t\t\ta_cpVSAPI->getNextPluginFunction(nullptr, pPlugin);\n\t\twhile(pPluginFunction)\n\t\t{\n\t\t\tconst char * pluginFunctionName =\n\t\t\t\ta_cpVSAPI->getPluginFunctionName(pPluginFunction);\n\t\t\tconst char * pluginFunctionArgs =\n\t\t\t\ta_cpVSAPI->getPluginFunctionArguments(pPluginFunction);\n\n\t\t\tVSData::Function function = parseFunctionSignature(pluginFunctionName,\n\t\t\t\tpluginFunctionArgs);\n\t\t\tpluginData.functions.push_back(function);\n\n\t\t\tpPluginFunction = a_cpVSAPI->getNextPluginFunction(pPluginFunction, pPlugin);\n\t\t}\n\t\tpPlugin = a_cpVSAPI->getNextPlugin(pPlugin, pCore);\n\t}\n\n\ta_cpVSAPI->freeCore(pCore);\n}\n\n// END OF void VapourSynthPluginsManager::getCorePlugins(const VSAPI * a_cpVSAPI)\n//==============================================================================\n\nQStringList VapourSynthPluginsManager::functions() const\n{\n\tQStringList functionsList;\n\tfor(const VSData::Plugin & plugin : m_pluginsList)\n\t{\n\t\tQString functionNamespace = plugin.pluginNamespace + \".\";\n\t\tfor(const VSData::Function & function : plugin.functions)\n\t\t\tfunctionsList << functionNamespace + function.toString();\n\t}\n\n\treturn functionsList;\n}\n\n// END OF QStringList VapourSynthPluginsManager::functions() const\n//==============================================================================\n\nVSPluginsList VapourSynthPluginsManager::pluginsList() const\n{\n\treturn m_pluginsList;\n}\n\n// END OF VSPluginsList VapourSynthPluginsManager::pluginsList() const\n//==============================================================================\n\nVSData::Function VapourSynthPluginsManager::parseFunctionSignature(\n\tconst QString & a_name, const QString & a_arguments)\n{\n\tVSData::Function function;\n\tfunction.name = a_name;\n\tQStringList argumentsList = a_arguments.split(';', Qt::SkipEmptyParts);\n\tif(argumentsList.size() == 0)\n\t\treturn function;\n\n\t// This is true for arguments lists returned by VSAPI.\n\tif(argumentsList[0] == a_name)\n\t\targumentsList.removeFirst();\n\n\tfor(const QString& argumentString : argumentsList)\n\t{\n\t\tQStringList argumentParts = argumentString.split(':');\n\t\tint partsNumber = argumentParts.size();\n\t\tif(partsNumber < 2)\n\t\t\tcontinue;\n\n\t\tfunction.arguments.emplace_back();\n\t\tVSData::FunctionArgument & argument = function.arguments.back();\n\t\targument.name = argumentParts[0];\n\t\targument.type = argumentParts[1];\n\n\t\tfor(int i = 2; i < partsNumber; ++i)\n\t\t{\n\t\t\tif(argumentParts[i] == \"opt\")\n\t\t\t\targument.optional = true;\n\t\t\telse if(argumentParts[i] == \"empty\")\n\t\t\t\targument.empty = true;\n\t\t}\n\t}\n\n\treturn function;\n}\n\n// END OF VSData::Function VapourSynthPluginsManager::parseFunctionSignature(\n//\t\tconst QString & a_name, const QString & a_arguments)\n//==============================================================================\n\nvoid VapourSynthPluginsManager::slotClear()\n{\n\tm_pluginsList.clear();\n}\n\n// END OF void VapourSynthPluginsManager::slotClear()\n//==============================================================================\n\nvoid VapourSynthPluginsManager::slotSort()\n{\n\tstd::stable_sort(m_pluginsList.begin(), m_pluginsList.end());\n\tfor(VSData::Plugin & plugin : m_pluginsList)\n\t\tstd::stable_sort(plugin.functions.begin(), plugin.functions.end());\n}\n\n// END OF void VapourSynthPluginsManager::slotSort()\n//==============================================================================\n\nvoid VapourSynthPluginsManager::slotRefill(const VSAPI * a_cpVSAPI)\n{\n\tslotClear();\n\tgetCorePlugins(a_cpVSAPI);\n\tslotSort();\n}\n\n// END OF void VapourSynthPluginsManager::slotRefill(const VSAPI * a_cpVSAPI)\n//==============================================================================\n"
  },
  {
    "path": "vsedit/src/vapoursynth/vapoursynth_plugins_manager.h",
    "content": "#ifndef VAPOURSYNTHPLUGINSMANAGER_H\n#define VAPOURSYNTHPLUGINSMANAGER_H\n\n#include \"vs_plugin_data.h\"\n\n#include <VapourSynth4.h>\n\n#include <QObject>\n#include <QStringList>\n\nclass SettingsManager;\n\nclass VapourSynthPluginsManager : public QObject\n{\n\tQ_OBJECT\n\npublic:\n\n\tVapourSynthPluginsManager(SettingsManager * a_pSettingsManager,\n\t\tconst VSAPI * a_cpVSAPI, QObject * a_pParent = nullptr);\n\n\tvirtual ~VapourSynthPluginsManager();\n\n\tvoid getCorePlugins(const VSAPI * a_cpVSAPI = nullptr);\n\n\tQStringList functions() const;\n\n\tVSPluginsList pluginsList() const;\n\n\tstatic VSData::Function parseFunctionSignature(const QString & a_name,\n\t\tconst QString & a_arguments);\n\npublic slots:\n\n\tvoid slotClear();\n\n\tvoid slotSort();\n\n\tvoid slotRefill(const VSAPI * a_cpVSAPI);\n\nsignals:\n\n\tvoid signalWriteLogMessage(int a_messageType,\n\t\tconst QString & a_message);\n\nprivate:\n\n\tVSPluginsList m_pluginsList;\n\n\tQString m_currentPluginPath;\n\n\tbool m_pluginAlreadyLoaded;\n\n\tSettingsManager * m_pSettingsManager;\n\n\tVSPLUGINAPI m_VSPAPI;\n};\n\n#endif // VAPOURSYNTHPLUGINSMANAGER_H\n"
  },
  {
    "path": "vsedit/src/vapoursynth/vs_plugin_data.cpp",
    "content": "#include \"vs_plugin_data.h\"\n\n#include <QStringList>\n\n//==============================================================================\n\nVSData::FunctionArgument::FunctionArgument():\n\tname()\n\t, type()\n\t, optional(false)\n\t, empty(false)\n{\n\n}\n\nVSData::FunctionArgument::FunctionArgument(\n\tconst VSData::FunctionArgument & a_other):\n\tname(a_other.name)\n\t, type(a_other.type)\n\t, optional(a_other.optional)\n\t, empty(a_other.empty)\n{\n\n}\n\nVSData::FunctionArgument::FunctionArgument(\n\tVSData::FunctionArgument && a_other):\n\tname(std::move(a_other.name))\n\t, type(std::move(a_other.type))\n\t, optional(std::move(a_other.optional))\n\t, empty(std::move(a_other.empty))\n{\n\n}\n\nVSData::FunctionArgument & VSData::FunctionArgument::operator=(\n\tVSData::FunctionArgument a_other)\n{\n\tstd::swap(name, a_other.name);\n\tstd::swap(type, a_other.type);\n\tstd::swap(optional, a_other.optional);\n\tstd::swap(empty, a_other.empty);\n\n\treturn *this;\n}\n\nQString VSData::FunctionArgument::toString() const\n{\n\treturn QString(\"%1 %2\").arg(type).arg(name);\n}\n\nbool VSData::FunctionArgument::operator<(\n\tconst VSData::FunctionArgument & a_other) const\n{\n\treturn (!optional && a_other.optional);\n}\n\n//==============================================================================\n\nVSData::Function::Function():\n\tname()\n\t, arguments()\n{\n\n}\n\nVSData::Function::Function(const VSData::Function & a_other):\n\tname(a_other.name)\n\t, arguments(a_other.arguments)\n{\n\n}\n\nVSData::Function::Function(VSData::Function && a_other):\n\tname(std::move(a_other.name))\n\t, arguments(std::move(a_other.arguments))\n{\n\n}\n\nVSData::Function & VSData::Function::operator=(VSData::Function a_other)\n{\n\tif(&a_other == this)\n\t\treturn *this;\n\n\tstd::swap(name, a_other.name);\n\tstd::swap(arguments, a_other.arguments);\n\n\treturn *this;\n}\n\nQString VSData::Function::toString() const\n{\n\tstd::vector<VSData::FunctionArgument> argumentsCopy = arguments;\n\tstd::sort(argumentsCopy.begin(), argumentsCopy.end());\n\tsize_t argumentsNumber = argumentsCopy.size();\n\tsize_t firstOptional;\n\tfor(firstOptional = 0; (firstOptional < argumentsNumber) &&\n\t\t(!argumentsCopy[firstOptional].optional); ++firstOptional){};\n\tQStringList mandatoryArguments;\n\tfor(size_t i = 0; i < firstOptional; ++i)\n\t\tmandatoryArguments << argumentsCopy[i].toString();\n\tQStringList optionalArguments;\n\tfor(size_t i = firstOptional; i < argumentsNumber; ++i)\n\t\toptionalArguments << argumentsCopy[i].toString();\n\tQString argumentsString = mandatoryArguments.join(\", \");\n\tif(!optionalArguments.isEmpty())\n\t\targumentsString += QString(\"[, %1]\").arg(optionalArguments.join(\", \"));\n\treturn QString(\"%1(%2)\").arg(name).arg(argumentsString);\n}\n\nbool VSData::Function::operator==(const VSData::Function & a_other) const\n{\n\treturn (name == a_other.name);\n}\n\nbool VSData::Function::operator<(const VSData::Function & a_other) const\n{\n\treturn (name.compare(a_other.name, Qt::CaseInsensitive) < 0);\n}\n\n//==============================================================================\n\nVSData::Plugin::Plugin():\n\tfilepath()\n\t, id()\n\t, pluginNamespace()\n\t, name()\n\t, functions()\n{\n\n}\n\nVSData::Plugin::Plugin(const VSData::Plugin & a_other):\n\tfilepath(a_other.filepath)\n\t, id(a_other.id)\n\t, pluginNamespace(a_other.pluginNamespace)\n\t, name(a_other.name)\n\t, functions(a_other.functions)\n{\n\n}\n\nVSData::Plugin::Plugin(VSData::Plugin && a_other):\n\tfilepath(std::move(a_other.filepath))\n\t, id(std::move(a_other.id))\n\t, pluginNamespace(std::move(a_other.pluginNamespace))\n\t, name(std::move(a_other.name))\n\t, functions(std::move(a_other.functions))\n{\n\n}\n\nVSData::Plugin & VSData::Plugin::operator=(VSData::Plugin a_other)\n{\n\tif(&a_other == this)\n\t\treturn *this;\n\n\tstd::swap(filepath, a_other.filepath);\n\tstd::swap(id, a_other.id);\n\tstd::swap(pluginNamespace, a_other.pluginNamespace);\n\tstd::swap(name, a_other.name);\n\tstd::swap(functions, a_other.functions);\n\n\treturn *this;\n}\n\nbool VSData::Plugin::operator==(const VSData::Plugin & a_other) const\n{\n\treturn (id == a_other.id);\n}\n\nbool VSData::Plugin::operator<(const VSData::Plugin & a_other) const\n{\n\treturn (pluginNamespace.compare(a_other.pluginNamespace,\n\t\tQt::CaseInsensitive) < 0);\n}\n\n//==============================================================================\n"
  },
  {
    "path": "vsedit/src/vapoursynth/vs_plugin_data.h",
    "content": "#ifndef VSPLUGINDATA_H_INCLUDED\n#define VSPLUGINDATA_H_INCLUDED\n\n#include <QString>\n#include <vector>\n\n/// Data, gathered from VS core and plugins for syntax highlighting,\n/// autocompletion and reference.\nnamespace VSData\n{\n\nstruct FunctionArgument\n{\n\tQString name;\n\tQString type;\n\tbool optional;\n\tbool empty;\n\n\tFunctionArgument();\n\tFunctionArgument(const VSData::FunctionArgument & a_other);\n\tFunctionArgument(VSData::FunctionArgument && a_other);\n\tVSData::FunctionArgument & operator=(VSData::FunctionArgument a_other);\n\n\tQString toString() const;\n\tbool operator<(const VSData::FunctionArgument & a_other) const;\n};\n\nstruct Function\n{\n\tQString name;\n\tstd::vector<VSData::FunctionArgument> arguments;\n\n\tFunction();\n\tFunction(const VSData::Function & a_other);\n\tFunction(VSData::Function && a_other);\n\tVSData::Function & operator=(VSData::Function a_other);\n\n\tQString toString() const;\n\tbool operator==(const VSData::Function & a_other) const;\n\tbool operator<(const VSData::Function & a_other) const;\n};\n\nstruct Plugin\n{\n\tQString filepath;\n\tQString id;\n\tQString pluginNamespace;\n\tQString name;\n\tstd::vector<VSData::Function> functions;\n\n\tPlugin();\n\tPlugin(const VSData::Plugin & a_other);\n\tPlugin(VSData::Plugin && a_other);\n\tVSData::Plugin & operator=(VSData::Plugin a_other);\n\n\tbool operator==(const VSData::Plugin & a_other) const;\n\tbool operator<(const VSData::Plugin & a_other) const;\n};\n\n}\n\ntypedef std::vector<VSData::Plugin> VSPluginsList;\n\n#endif // VSPLUGINDATA_H_INCLUDED\n"
  },
  {
    "path": "vsedit/src/vapoursynth/vs_script_processor_dialog.cpp",
    "content": "#include \"vs_script_processor_dialog.h\"\n\n#include \"../../../common-src/helpers.h\"\n#include \"../../../common-src/settings/settings_manager.h\"\n#include \"../../../common-src/vapoursynth/vapoursynth_script_processor.h\"\n#include \"../../../common-src/vapoursynth/vs_script_library.h\"\n\n#include <VapourSynth4.h>\n\n#include <QCloseEvent>\n#include <QStatusBar>\n#include <QLabel>\n#include <QLayout>\n\n//==============================================================================\n\nVSScriptProcessorDialog::VSScriptProcessorDialog(\n\tSettingsManager * a_pSettingsManager, VSScriptLibrary * a_pVSScriptLibrary,\n\tQWidget * a_pParent, Qt::WindowFlags a_flags):\n\t  QDialog(a_pParent, a_flags)\n\t, m_pSettingsManager(a_pSettingsManager)\n\t, m_pVSScriptLibrary(a_pVSScriptLibrary)\n\t, m_pVapourSynthScriptProcessor(nullptr)\n\t, m_cpVSAPI(nullptr)\n\t, m_framesInQueue()\n\t, m_framesInProcess()\n\t, m_maxThreads(0)\n\t, m_usedCacheRatio(0.0)\n\t, m_outputIndex(0)\n\t, m_wantToFinalize(false)\n\t, m_wantToClose(false)\n\t, m_pStatusBar(nullptr)\n\t, m_pStatusBarWidget(nullptr)\n\t, m_readyPixmap(\":tick.png\")\n\t, m_busyPixmap(\":busy.png\")\n\t, m_errorPixmap(\":cross.png\")\n\t, m_cachedFramesLimit(100)\n\t, m_clipName(\"\")\n\t, m_sceneName(\"\")\n\t, m_absoluteTime(\"\")\n{\n\tQ_ASSERT(m_pSettingsManager);\n\tQ_ASSERT(m_pVSScriptLibrary);\n\n\t//connect(m_pVSScriptLibrary,\n\t//\tSIGNAL(signalWriteLogMessage(int, const QString &)),\n\t//\tthis, SLOT(slotWriteLogMessage(int, const QString &)));\n\n\tm_pVapourSynthScriptProcessor = new VapourSynthScriptProcessor(\n\t\tm_pSettingsManager, m_pVSScriptLibrary, this);\n\n\tm_pStatusBarWidget = new ScriptStatusBarWidget();\n\n\tconnect(m_pVapourSynthScriptProcessor,\n\t\tSIGNAL(signalWriteLogMessage(int, const QString &)),\n\t\tthis, SLOT(slotWriteLogMessage(int, const QString &)));\n\tconnect(m_pVapourSynthScriptProcessor,\n\t\tSIGNAL(signalFrameQueueStateChanged(size_t, size_t, size_t, double)),\n\t\tthis, SLOT(slotFrameQueueStateChanged(size_t, size_t, size_t, double)));\n\tconnect(m_pVapourSynthScriptProcessor, SIGNAL(signalFinalized()),\n\t\tthis, SLOT(slotScriptProcessorFinalized()));\n\tconnect(m_pVapourSynthScriptProcessor,\n\t\tSIGNAL(signalDistributeFrame(int, int, const VSFrame *,\n\t\t\tconst VSFrame *)),\n\t\tthis, SLOT(slotReceiveFrame(int, int, const VSFrame *,\n\t\t\tconst VSFrame *)));\n\tconnect(m_pVapourSynthScriptProcessor,\n\t\tSIGNAL(signalFrameRequestDiscarded(int, int, const QString &)),\n\t\tthis, SLOT(slotFrameRequestDiscarded(int, int, const QString &)));\n}\n\n// END OF VSScriptProcessorDialog::VSScriptProcessorDialog(\n//\t\tSettingsManager * a_pSettingsManager,\n//\t\tVSScriptLibrary * a_pVSScriptLibrary,\n//\t\tQWidget * a_pParent, Qt::WindowFlags a_flags)\n//==============================================================================\n\nVSScriptProcessorDialog::~VSScriptProcessorDialog()\n{\n\tstopAndCleanUp();\n\tm_pVapourSynthScriptProcessor->finalize();\n}\n\n// END OF VSScriptProcessorDialog::~VSScriptProcessorDialog()\n//==============================================================================\n\nbool VSScriptProcessorDialog::initialize(const QString & a_script,\n\tconst QString & a_scriptName, ProcessReason a_reason)\n{\n\tQ_ASSERT(m_pVapourSynthScriptProcessor);\n\n\tm_cpVSAPI = m_pVSScriptLibrary->getVSAPI();\n\tif(!m_cpVSAPI)\n\t\treturn false;\n\n\tif(m_pVapourSynthScriptProcessor->isInitialized())\n\t{\n\t\tstopAndCleanUp();\n\t\tbool finalized = m_pVapourSynthScriptProcessor->finalize();\n\t\tif(!finalized)\n\t\t{\n\t\t\tm_wantToFinalize = true;\n\t\t\treturn false;\n\t\t}\n\t}\n\n\tbool initialized = m_pVapourSynthScriptProcessor->initialize(a_script,\n\t\ta_scriptName, m_outputIndex, a_reason);\n\tif(!initialized)\n\t{\n\t\tif(isVisible())\n\t\t\thide();\n\t\treturn false;\n\t}\n\n\tm_nodeInfo[m_outputIndex] =\n\t\tm_pVapourSynthScriptProcessor->nodeInfo(m_outputIndex);\n\tQ_ASSERT(!m_nodeInfo[m_outputIndex].isInvalid());\n\n\tm_pStatusBarWidget->setNodeInfo(m_nodeInfo[m_outputIndex], m_cpVSAPI);\n\n\treturn true;\n}\n\n// END OF bool VSScriptProcessorDialog::initialize(const QString & a_script,\n//\t\tconst QString & a_scriptName)\n//==============================================================================\n\nbool VSScriptProcessorDialog::busy(int a_outputIndex) const\n{\n\tif(m_framesInProcess.find(a_outputIndex) == m_framesInProcess.end())\n\t\treturn false;\n\treturn ((m_framesInProcess.at(a_outputIndex)\n\t\t+ m_framesInQueue.at(a_outputIndex)) != 0);\n}\n\n// END OF bool VSScriptProcessorDialog::busy(int a_outputIndex)\n//==============================================================================\n\nconst QString & VSScriptProcessorDialog::script() const\n{\n\treturn m_pVapourSynthScriptProcessor->script();\n}\n\n// END OF const QString & VSScriptProcessorDialog::script() const\n//==============================================================================\n\nconst QString & VSScriptProcessorDialog::scriptName() const\n{\n\treturn m_pVapourSynthScriptProcessor->scriptName();\n}\n\n// END OF const QString & VSScriptProcessorDialog::scriptName() const\n//==============================================================================\n\nvoid VSScriptProcessorDialog::setScriptName(const QString & a_scriptName)\n{\n\tm_pVapourSynthScriptProcessor->setScriptName(a_scriptName);\n}\n\n// END OF void VSScriptProcessorDialog::setScriptName(\n//\t\tconst QString & a_scriptName)\n//==============================================================================\n\nvoid VSScriptProcessorDialog::slotWriteLogMessage(int a_messageType,\n\tconst QString & a_message)\n{\n\temit signalWriteLogMessage(a_messageType, a_message);\n}\n\n// END OF void VSScriptProcessorDialog::slotWriteLogMessage(int a_messageType,\n//\t\tconst QString & a_message)\n//==============================================================================\n\nvoid VSScriptProcessorDialog::slotFrameQueueStateChanged(size_t a_inQueue,\n\tsize_t a_inProcess, size_t a_maxThreads, double a_usedCacheRatio)\n{\n\tm_framesInQueue[m_outputIndex] = a_inQueue;\n\tm_framesInProcess[m_outputIndex] = a_inProcess;\n\tm_maxThreads = a_maxThreads;\n\tm_usedCacheRatio = a_usedCacheRatio;\n\n\tm_pStatusBarWidget->setQueueState(m_framesInQueue[m_outputIndex],\n\t\tm_framesInProcess[m_outputIndex], m_maxThreads, m_usedCacheRatio);\n\n\temit signalProcessorIdle(!busy(m_outputIndex));\n}\n\n// END OF void VSScriptProcessorDialog::slotFrameQueueStateChanged(\n//\t\tsize_t a_inQueue, size_t a_inProcess, size_t a_maxThreads,\n//\t\tdouble a_usedCacheRatio)\n//==============================================================================\n\nvoid VSScriptProcessorDialog::slotScriptProcessorFinalized()\n{\n\tm_wantToFinalize = false;\n\tif(m_wantToClose)\n\t{\n\t\tm_wantToClose = false;\n\t\tclose();\n\t}\n}\n\n// END OF void VSScriptProcessorDialog::slotScriptProcessofFinalized()\n//==============================================================================\n\n\nvoid VSScriptProcessorDialog::closeEvent(QCloseEvent * a_pEvent)\n{\n\tif(m_wantToClose)\n\t\treturn;\n\n\tm_wantToClose = true;\n\tstopAndCleanUp();\n\n\tbool finalized = m_pVapourSynthScriptProcessor->finalize();\n\tif(!finalized)\n\t{\n\t\tm_wantToFinalize = true;\n\t\temit signalWriteLogMessage(mtWarning, tr(\"Script processor \"\n\t\t\t\"is busy. Dialog will close when it is finalized.\"));\n\t\ta_pEvent->ignore();\n\t\treturn;\n\t}\n\n\tQDialog::closeEvent(a_pEvent);\n\tm_wantToClose = false;\n}\n\n// END OF void VSScriptProcessorDialog::closeEvent(QCloseEvent * a_pEvent)\n//==============================================================================\n\nvoid VSScriptProcessorDialog::stopAndCleanUp()\n{\n\tclearFramesCache();\n\tfor(auto & pair : m_nodeInfo)\n\t\tpair.second.setNull();\n\n\tm_outputIndex = 0;\n}\n\n// END OF void VSScriptProcessorDialog::stopAndCleanUp()\n//==============================================================================\n\nvoid VSScriptProcessorDialog::clearFramesCache()\n{\n\tfor(auto & pair : m_framesCache)\n\t{\n\t\tif(!pair.second.empty())\n\t\t{\n\t\t\tfor(Frame & frame : pair.second)\n\t\t\t{\n\t\t\t\tm_cpVSAPI->freeFrame(frame.cpOutputFrame);\n\t\t\t\tm_cpVSAPI->freeFrame(frame.cpPreviewFrame);\n\t\t\t}\n\t\t\tpair.second.clear();\n\t\t}\n\t}\n}\n\n// END OF void VSScriptProcessorDialog::stopAndCleanUp()\n//==============================================================================\n\nvoid VSScriptProcessorDialog::createStatusBar()\n{\n\tQLayout * pLayout = layout();\n\tQ_ASSERT(pLayout);\n\tif(!pLayout)\n\t\treturn;\n\n\tm_pStatusBar = new QStatusBar(this);\n\tpLayout->addWidget(m_pStatusBar);\n\n\tm_pStatusBar->addPermanentWidget(m_pStatusBarWidget, 1);\n}\n\n// END OF void VSScriptProcessorDialog::createStatusBar()\n//==============================================================================\n"
  },
  {
    "path": "vsedit/src/vapoursynth/vs_script_processor_dialog.h",
    "content": "#ifndef VS_SCRIPT_PROCESSOR_DIALOG_H_INCLUDED\n#define VS_SCRIPT_PROCESSOR_DIALOG_H_INCLUDED\n\n#include \"../../../common-src/helpers.h\"\n#include \"../../../common-src/vapoursynth/vs_script_processor_structures.h\"\n#include \"../../../common-src/vapoursynth/vapoursynth_script_processor.h\"\n#include \"../script_status_bar_widget/script_status_bar_widget.h\"\n\n#include <QDialog>\n#include <QPixmap>\n#include <QString>\n#include <list>\n#include <vector>\n#include <map>\n\nclass QCloseEvent;\nclass QStatusBar;\nclass QLabel;\nclass SettingsManager;\nclass VSScriptLibrary;\nclass VapourSynthScriptProcessor;\nstruct VSAPI;\nstruct VSVideoInfo;\nstruct VSFrame;\n\nclass VSScriptProcessorDialog : public QDialog\n{\n\tQ_OBJECT\n\npublic:\n\n\tVSScriptProcessorDialog(SettingsManager * a_pSettingsManager,\n\t\tVSScriptLibrary * a_pVSScriptLibrary, QWidget * a_pParent = nullptr,\n\t\tQt::WindowFlags a_flags =\n\t\t  Qt::Window\n\t\t| Qt::CustomizeWindowHint\n\t\t| Qt::WindowMinimizeButtonHint\n\t\t| Qt::WindowMaximizeButtonHint\n\t\t| Qt::WindowCloseButtonHint);\n\n\tvirtual ~VSScriptProcessorDialog();\n\n\tvirtual bool initialize(const QString & a_script,\n\t\tconst QString & a_scriptName, ProcessReason a_reason);\n\n\tvirtual bool busy(int a_outputIndex = 0) const;\n\n\tvirtual const QString & script() const;\n\n\tvirtual const QString & scriptName() const;\n\n\tvirtual void setScriptName(const QString & a_scriptName);\n\nprotected slots:\n\n\tvirtual void slotWriteLogMessage(int a_messageType,\n\t\tconst QString & a_message);\n\n\tvirtual void slotFrameQueueStateChanged(size_t a_inQueue,\n\t\tsize_t a_inProcess, size_t a_maxThreads, double a_usedCacheRatio);\n\n\tvirtual void slotScriptProcessorFinalized();\n\n\tvirtual void slotReceiveFrame(int a_frameNumber, int a_outputIndex,\n\t\tconst VSFrame * a_cpOutputFrame,\n\t\tconst VSFrame * a_cpPreviewFrame) = 0;\n\n\tvirtual void slotFrameRequestDiscarded(int a_frameNumber,\n\t\tint a_outputIndex, const QString & a_reason) = 0;\n\nsignals:\n\n\tvoid signalWriteLogMessage(int a_messageType,\n\t\tconst QString & a_message);\n\n\tvoid signalProcessorIdle(bool a_idle);\n\nprotected:\n\n\tvirtual void closeEvent(QCloseEvent * a_pEvent) override;\n\n\tvirtual void stopAndCleanUp();\n\n\tvirtual void clearFramesCache();\n\n\t/// Adds status bar to the dialog.\n\t/// Relies on dialog having a layout.\n\t/// Call in derived class after GUI is created.\n\tvirtual void createStatusBar();\n\n\tSettingsManager * m_pSettingsManager;\n\n\tVSScriptLibrary * m_pVSScriptLibrary;\n\n\tVapourSynthScriptProcessor * m_pVapourSynthScriptProcessor;\n\n\tconst VSAPI * m_cpVSAPI;\n\n\tstd::map<int, VSNodeInfo> m_nodeInfo;\n\n\tstd::map<int, size_t> m_framesInQueue;\n\tstd::map<int, size_t> m_framesInProcess;\n\tsize_t m_maxThreads;\n\tdouble m_usedCacheRatio;\n\n\tint m_outputIndex;\n\tstd::vector<int> m_outputIndices;\n\n\tbool m_wantToFinalize;\n\tbool m_wantToClose;\n\n\tQStatusBar * m_pStatusBar;\n\tScriptStatusBarWidget * m_pStatusBarWidget;\n\n\tQPixmap m_readyPixmap;\n\tQPixmap m_busyPixmap;\n\tQPixmap m_errorPixmap;\n\n\tstd::map<int, std::list<Frame>> m_framesCache;\n\tsize_t m_cachedFramesLimit;\n\n\tQString m_clipName;\n\tQString m_sceneName;\n\tQString m_absoluteTime;\n};\n\n#endif // VS_SCRIPT_PROCESSOR_DIALOG_H_INCLUDED\n"
  },
  {
    "path": "vsedit/src/vsedit_encode_main.cpp",
    "content": "#include \"../../common-src/settings/settings_manager.h\"\n#include \"../../common-src/vapoursynth/vs_script_library.h\"\n#include \"../../common-src/log/vs_editor_log_definitions.h\"\n#include \"../../common-src/helpers.h\"\n\n#include \"frame_consumers/encode_dialog.h\"\n\n#include <QFileInfo>\n#include <QMessageBox>\n#include <QResource>\n\n#include <iostream>\n#include <string>\n\nQ_DECLARE_OPAQUE_POINTER(const VSFrame *)\nQ_DECLARE_OPAQUE_POINTER(VSNode *)\n\nSettingsManager * pSettings = nullptr;\nVSScriptLibrary * pVSSLibrary = nullptr;\nEncodeDialog * pEncodeDialog = nullptr;\nint exitCode = 0;\n\nvoid writeLogMessageByTypename(const QString & a_msg, const QString & a_style)\n{\n\tQString debugTypes[] = {\n\t\tLOG_STYLE_DEBUG,\n\t\tLOG_STYLE_QT_DEBUG,\n\t\tLOG_STYLE_VS_DEBUG,\n\t};\n\n\tif(pSettings->getShowDebugMessages() || !vsedit::contains(debugTypes, a_style))\n\t{\n\t\tstd::cerr << \"[\" << a_style.toUpper().toStdString() << \"] \"\n\t\t\t<< std::string(a_msg.toLocal8Bit()) << std::endl;\n\t}\n\n\tQString breakingTypes[] = {\n\t\tLOG_STYLE_VS_CRITICAL,\n\t\tLOG_STYLE_QT_CRITICAL,\n\t\tLOG_STYLE_ERROR,\n\t\tLOG_STYLE_VS_FATAL,\n\t\tLOG_STYLE_QT_FATAL,\n\t};\n\n\tif(vsedit::contains(breakingTypes, a_style))\n\t{\n\t\tif(pEncodeDialog)\n\t\t{\n\t\t\tpEncodeDialog->show();\n\t\t\tQMessageBox * msgBox = new QMessageBox(pEncodeDialog);\n\t\t\tmsgBox->setText(a_msg);\n\t\t\tmsgBox->setWindowTitle(a_style.toUpper());\n\t\t\tvsedit::disableFontKerning(msgBox);\n\t\t\tmsgBox->setTextInteractionFlags(Qt::TextSelectableByMouse);\n\t\t\tmsgBox->exec();\n\t\t}\n\n\t\t// Handle fatal errors and save to current dir\n\t\tQString fatalTypes[] = {LOG_STYLE_VS_FATAL, LOG_STYLE_QT_FATAL};\n\t\tif(vsedit::contains(fatalTypes, a_style))\n\t\t{\n\t\t\tQDateTime now = QDateTime::currentDateTime();\n\t\t\tQString timeString = now.toString(\"hh:mm:ss.zzz\");\n\t\t\tQString dateString = now.toString(\"yyyy-MM-dd\");\n\t\t\tQString caption = QObject::tr(\"vsedit-encode fatal error!\");\n\t\t\tQString fullMessage = dateString + QString(\" \") + timeString +\n\t\t\t\tQString(\"\\n\") + caption + QString(\"\\n\") + a_msg;\n\n\t\t\tQString applicationDir = QCoreApplication::applicationDirPath();\n\t\t\tQString errorLogFilePath = applicationDir + QString(\"/\") +\n\t\t\t\tQString(\"vsedit-encode-crashlog-\") +\tdateString + QString(\"-\") +\n\t\t\t\ttimeString.replace(':', '-') + QString(\".txt\");\n\n\t\t\tQFile errorLogFile(errorLogFilePath);\n\t\t\tif(errorLogFile.open(QIODevice::WriteOnly))\n\t\t\t{\n\t\t\t\terrorLogFile.write(fullMessage.toUtf8());\n\t\t\t\terrorLogFile.close();\n\t\t\t}\n\t\t}\n\n\t\tqApp->exit(-1);\n\t\texitCode = -1;\n\t}\n}\n\nvoid writeLogMessage(int a_msgType, const QString & a_msg)\n{\n\tQString style = vsMessageTypeToStyleName(a_msgType);\n\twriteLogMessageByTypename(a_msg, style);\n}\n\nvoid handleQtMessage(QtMsgType a_type,\n\tconst QMessageLogContext & a_context, const QString & a_message)\n{\n\tQString style = LOG_STYLE_DEFAULT;\n\n\tswitch(a_type)\n\t{\n\tcase QtDebugMsg:\n\t\tstyle = LOG_STYLE_QT_DEBUG;\n\t\tbreak;\n\tcase QtInfoMsg:\n\t\tstyle = LOG_STYLE_QT_INFO;\n\t\tbreak;\n\tcase QtWarningMsg:\n\t\tstyle = LOG_STYLE_QT_WARNING;\n\t\tbreak;\n\tcase QtCriticalMsg:\n\t\tstyle = LOG_STYLE_QT_CRITICAL;\n\t\tbreak;\n\tcase QtFatalMsg:\n\t\tstyle = LOG_STYLE_QT_FATAL;\n\t\tbreak;\n\tdefault:\n\t\tQ_ASSERT(false);\n\t}\n\n\tQString fullMessage = QString(\"%1: %2\").arg(style.toUpper()).arg(a_message);\n\n\tQString fileString(a_context.file);\n\tQString lineString = QString::number(a_context.line);\n\tQString functionString(a_context.function);\n\n\tQString lineInfo = QString(\"\\n(%1:%2\").arg(fileString).arg(lineString);\n\tif(!functionString.isEmpty())\n\t\tlineInfo += QString(\", %1\").arg(functionString);\n\tlineInfo += QString(\")\");\n\tif(!fileString.isEmpty())\n\t\tfullMessage += lineInfo;\n\n\twriteLogMessageByTypename(fullMessage, style);\n}\n\nint main(int argc, char *argv[])\n{\n\tQString scriptFilePath;\n\tif(argc > 1)\n\t{\n\t\tscriptFilePath = QString::fromLocal8Bit(argv[1], -1);\n\t}\n\telse\n\t{\n\t\tstd::cerr << \"vsedit-encode: Please provide the path to your script.\" << std::endl;\n\t\treturn -2;\n\t}\n\n\tQApplication::setAttribute(Qt::AA_DontUseNativeMenuBar);\n\tQGuiApplication::setHighDpiScaleFactorRoundingPolicy(\n\t\tQt::HighDpiScaleFactorRoundingPolicy::Floor);\n\tQApplication application(argc, argv);\n\n\tqInstallMessageHandler(handleQtMessage);\n\n\tpSettings = new SettingsManager(qApp);\n\n\tvsedit::disableFontKerning(qApp);\n\n\t// Make text in message box selectable\n\tapplication.setStyleSheet(\n\t\t\"QToolTip { font-kerning: none; }\"\n\t\t\"QMessageBox { messagebox-text-interaction-flags: 5; }\"\n\t\t\"QLabel { padding: 0px; }\");\n\n\tqRegisterMetaType<const VSFrame *>(\"const VSFrame *\");\n\tqRegisterMetaType<VSNode *>(\"VSNode *\");\n\n\tQResource digitalMiniFontResource(\":/fonts/DigitalMini.ttf\");\n\tQByteArray digitalMiniFontData(\n\t\t(const char *)digitalMiniFontResource.data(),\n\t\tdigitalMiniFontResource.size());\n\tQFontDatabase::addApplicationFontFromData(digitalMiniFontData);\n\n\tif(pSettings->inDarkMode())\n\t{\n\t\t// Load qDarkStyle colors\n\t\tQFile styleSheetDark(\":/dark/style.qss\");\n\t\tif(!styleSheetDark.open(QFile::ReadOnly | QFile::Text))\n\t\t{\n\t\t\tQMessageBox::critical(nullptr,\n\t\t\t\tQString::fromUtf8(\"File open error\"),\n\t\t\t\tQString::fromUtf8(\"Failed to open stylesheet file \")\n\t\t\t\t\t+ styleSheetDark.errorString());\n\t\t}\n\t\tqApp->setStyleSheet(styleSheetDark.readAll());\n\t\tQPalette newPal(qApp->palette());\n\t\tnewPal.setColor(QPalette::Base, QColor(0, 0, 0));\n\t\tnewPal.setColor(QPalette::Highlight, QColor(128, 128, 128));\n\t\tnewPal.setColor(QPalette::Dark, QColor(192, 192, 192));\n\t\tnewPal.setColor(QPalette::Text, QColor(64, 192, 0));\n\t\tqApp->setPalette(newPal);\n\t}\n#ifdef Q_OS_WIN\n\telse\n\t\tqApp->setStyle(\"fusion\");\n#endif\n\n\tQFileInfo fileInfo(scriptFilePath);\n\tQString scriptFileFullPath = fileInfo.absoluteFilePath();\n\tQFile scriptFile(scriptFileFullPath);\n\tbool loaded = scriptFile.open(QIODevice::ReadOnly | QIODevice::Text);\n\tif(!loaded)\n\t{\n\t\tQString errorMsg = QString(\"Failed to open script [%1]!\")\n\t\t\t.arg(scriptFilePath);\n\t\twriteLogMessageByTypename(errorMsg, LOG_STYLE_ERROR);\n\t\tdelete pSettings;\n\t\treturn -1;\n\t}\n\n\tpVSSLibrary = new VSScriptLibrary(pSettings, qApp);\n\tQObject::connect(pVSSLibrary, &VSScriptLibrary::signalWriteLogMessage,\n\t\twriteLogMessage);\n\n    pEncodeDialog = new EncodeDialog(pSettings, pVSSLibrary, nullptr);\n    QObject::connect(pEncodeDialog, &EncodeDialog::signalWriteLogMessage,\n        writeLogMessageByTypename);\n\n\tif(exitCode != 0)\n\t\treturn exitCode;\n\n\tQString scriptText = QString::fromUtf8(scriptFile.readAll());\n\tpSettings->setLastUsedPath(scriptFileFullPath);\n\n\tif(pVSSLibrary->initialize())\n\t{\n\t\tif(pEncodeDialog->initialize(scriptText, scriptFilePath))\n\t\t{\n\t\t\tpEncodeDialog->showActive();\n\t\t\texitCode = pEncodeDialog->exec();\n\t\t}\n\t}\n\treturn exitCode;\n}\n"
  },
  {
    "path": "vsedit/src/vsedit_previewer_main.cpp",
    "content": "#include \"../../common-src/settings/settings_manager.h\"\n#include \"../../common-src/vapoursynth/vs_script_library.h\"\n#include \"../../common-src/vapoursynth/vapoursynth_script_processor.h\"\n#include \"../../common-src/log/vs_editor_log_definitions.h\"\n#include \"../../common-src/helpers.h\"\n#include \"../../common-src/version_info.h\"\n\n#include \"preview/preview_dialog.h\"\n\n#include <QFileInfo>\n#include <QFontDatabase>\n#include <QMessageBox>\n#include <QResource>\n\n#include <iostream>\n#include <string>\n\nQ_DECLARE_OPAQUE_POINTER(const VSFrame *)\nQ_DECLARE_OPAQUE_POINTER(VSNode *)\n\nSettingsManager * pSettings = nullptr;\nVSScriptLibrary * pVSSLibrary = nullptr;\nPreviewDialog * pPreviewDialog = nullptr;\nint exitCode = 0;\n\nvoid writeLogMessageByTypename(const QString & a_msg, const QString & a_style)\n{\n\tQString debugTypes[] = {\n\t\tLOG_STYLE_DEBUG,\n\t\tLOG_STYLE_QT_DEBUG,\n\t\tLOG_STYLE_VS_DEBUG,\n\t};\n\n\tif(pSettings->getShowDebugMessages() || !vsedit::contains(debugTypes, a_style))\n\t{\n\t\tstd::cerr << \"[\" << a_style.toUpper().toStdString() << \"] \"\n\t\t\t<< std::string(a_msg.toLocal8Bit()) << std::endl;\n\t}\n\n\tQString breakingTypes[] = {\n\t\tLOG_STYLE_VS_CRITICAL,\n\t\tLOG_STYLE_QT_CRITICAL,\n\t\tLOG_STYLE_ERROR,\n\t\tLOG_STYLE_VS_FATAL,\n\t\tLOG_STYLE_QT_FATAL,\n\t};\n\n\tif(vsedit::contains(breakingTypes, a_style))\n\t{\n\t\tif(pPreviewDialog)\n\t\t{\n\t\t\tpPreviewDialog->show();\n\t\t\tQMessageBox * msgBox = new QMessageBox(pPreviewDialog);\n\t\t\tmsgBox->setText(a_msg);\n\t\t\tmsgBox->setWindowTitle(a_style.toUpper());\n\t\t\tvsedit::disableFontKerning(msgBox);\n\t\t\tmsgBox->setTextInteractionFlags(Qt::TextSelectableByMouse);\n\t\t\tmsgBox->exec();\n\t\t}\n\n\t\t// Handle fatal errors and save to current dir\n\t\tQString fatalTypes[] = {LOG_STYLE_VS_FATAL, LOG_STYLE_QT_FATAL};\n\t\tif(vsedit::contains(fatalTypes, a_style))\n\t\t{\n\t\t\tQDateTime now = QDateTime::currentDateTime();\n\t\t\tQString timeString = now.toString(\"hh:mm:ss.zzz\");\n\t\t\tQString dateString = now.toString(\"yyyy-MM-dd\");\n\t\t\tQString caption = QObject::tr(\"VSE-Previewer fatal error!\");\n\t\t\tQString fullMessage = dateString + QString(\" \") + timeString +\n\t\t\t\tQString(\"\\n\") + caption + QString(\"\\n\") + a_msg;\n\n\t\t\tQString applicationDir = QCoreApplication::applicationDirPath();\n\t\t\tQString errorLogFilePath = applicationDir + QString(\"/\") +\n\t\t\t\tQString(\"VSE-Previwer-crashlog-\") +\tdateString + QString(\"-\") +\n\t\t\t\ttimeString.replace(':', '-') + QString(\".txt\");\n\n\t\t\tQFile errorLogFile(errorLogFilePath);\n\t\t\tif(errorLogFile.open(QIODevice::WriteOnly))\n\t\t\t{\n\t\t\t\terrorLogFile.write(fullMessage.toUtf8());\n\t\t\t\terrorLogFile.close();\n\t\t\t}\n\t\t}\n\n\t\tqApp->exit(-1);\n\t\texitCode = -1;\n\t}\n}\n\nvoid writeLogMessage(int a_msgType, const QString & a_msg)\n{\n\tQString style = vsMessageTypeToStyleName(a_msgType);\n\twriteLogMessageByTypename(a_msg, style);\n}\n\nvoid handleQtMessage(QtMsgType a_type,\n\tconst QMessageLogContext & a_context, const QString & a_message)\n{\n\tQString style = LOG_STYLE_DEFAULT;\n\n\tswitch(a_type)\n\t{\n\tcase QtDebugMsg:\n\t\tstyle = LOG_STYLE_QT_DEBUG;\n\t\tbreak;\n\tcase QtInfoMsg:\n\t\tstyle = LOG_STYLE_QT_INFO;\n\t\tbreak;\n\tcase QtWarningMsg:\n\t\tstyle = LOG_STYLE_QT_WARNING;\n\t\tbreak;\n\tcase QtCriticalMsg:\n\t\tstyle = LOG_STYLE_QT_CRITICAL;\n\t\tbreak;\n\tcase QtFatalMsg:\n\t\tstyle = LOG_STYLE_QT_FATAL;\n\t\tbreak;\n\tdefault:\n\t\tQ_ASSERT(false);\n\t}\n\n\tQString fullMessage = QString(\"%1: %2\").arg(style.toUpper()).arg(a_message);\n\n\tQString fileString(a_context.file);\n\tQString lineString = QString::number(a_context.line);\n\tQString functionString(a_context.function);\n\n\tQString lineInfo = QString(\"\\n(%1:%2\").arg(fileString).arg(lineString);\n\tif(!functionString.isEmpty())\n\t\tlineInfo += QString(\", %1\").arg(functionString);\n\tlineInfo += QString(\")\");\n\tif(!fileString.isEmpty())\n\t\tfullMessage += lineInfo;\n\n\twriteLogMessageByTypename(fullMessage, style);\n}\n\nint main(int argc, char *argv[])\n{\n\tQString scriptFilePath;\n\tif(argc > 1)\n\t{\n\t\tif(strcmp(argv[1], \"-v\") == 0 ||\n\t\t\tstrcmp(argv[1], \"--version\") == 0)\n\t\t{\n\t\t\tprint_version();\n\t\t\treturn 0;\n\t\t}\n\t\telse\n\t\t\tscriptFilePath = QString::fromLocal8Bit(argv[1], -1);\n\t}\n\telse\n\t{\n\t\tstd::cerr << \"vsedit-previewer: Please provide the path to your script.\" << std::endl;\n\t\treturn -2;\n\t}\n\n\tprint_version();\n\n\tQApplication::setAttribute(Qt::AA_DontUseNativeMenuBar);\n\tQGuiApplication::setHighDpiScaleFactorRoundingPolicy(\n\t\tQt::HighDpiScaleFactorRoundingPolicy::Floor);\n\tQApplication application(argc, argv);\n\n\tqInstallMessageHandler(handleQtMessage);\n\n\tpSettings = new SettingsManager(qApp);\n\n\tvsedit::disableFontKerning(qApp);\n\n\t// Make text in message box selectable\n\tapplication.setStyleSheet(\n\t\t\"QToolTip { font-kerning: none; }\"\n\t\t\"QMessageBox { messagebox-text-interaction-flags: 5; }\"\n\t\t\"QLabel { padding: 0px; }\");\n\n\tqRegisterMetaType<const VSFrame *>(\"const VSFrame *\");\n\tqRegisterMetaType<VSNode *>(\"VSNode *\");\n\n\tQResource digitalMiniFontResource(\":/fonts/DigitalMini.ttf\");\n\tQByteArray digitalMiniFontData(\n\t\t(const char *)digitalMiniFontResource.data(),\n\t\tdigitalMiniFontResource.size());\n\tQFontDatabase::addApplicationFontFromData(digitalMiniFontData);\n\n\tif(pSettings->inDarkMode())\n\t{\n\t\t// Load qDarkStyle colors\n\t\tQFile styleSheetDark(\":/dark/style.qss\");\n\t\tif(!styleSheetDark.open(QFile::ReadOnly | QFile::Text))\n\t\t{\n\t\t\tQMessageBox::critical(nullptr,\n\t\t\t\tQString::fromUtf8(\"File open error\"),\n\t\t\t\tQString::fromUtf8(\"Failed to open stylesheet file \")\n\t\t\t\t\t+ styleSheetDark.errorString());\n\t\t}\n\t\tqApp->setStyleSheet(styleSheetDark.readAll());\n\t\tQPalette newPal(qApp->palette());\n\t\tnewPal.setColor(QPalette::Base, QColor(0, 0, 0));\n\t\tnewPal.setColor(QPalette::Highlight, QColor(128, 128, 128));\n\t\tnewPal.setColor(QPalette::Dark, QColor(192, 192, 192));\n\t\tnewPal.setColor(QPalette::Text, QColor(64, 192, 0));\n\t\tqApp->setPalette(newPal);\n\t}\n#ifdef Q_OS_WIN\n\telse\n\t\tqApp->setStyle(\"fusion\");\n#endif\n\n\tQFileInfo fileInfo(scriptFilePath);\n\tQString scriptFileFullPath = fileInfo.absoluteFilePath();\n\tQFile scriptFile(scriptFileFullPath);\n\tbool loaded = scriptFile.open(QIODevice::ReadOnly | QIODevice::Text);\n\tif(!loaded)\n\t{\n\t\tQString errorMsg = QString(\"Failed to open script [%1]!\")\n\t\t\t.arg(scriptFilePath);\n\t\twriteLogMessageByTypename(errorMsg, LOG_STYLE_ERROR);\n\t\tdelete pSettings;\n\t\treturn -1;\n\t}\n\n\tpVSSLibrary = new VSScriptLibrary(pSettings, qApp);\n\tQObject::connect(pVSSLibrary, &VSScriptLibrary::signalWriteLogMessage,\n\t\twriteLogMessage);\n\n\tpPreviewDialog = new PreviewDialog(pSettings, pVSSLibrary, true);\n\tQObject::connect(pPreviewDialog, &PreviewDialog::signalWriteLogMessage,\n\t\twriteLogMessage);\n\n\tif(exitCode != 0)\n\t\treturn exitCode;\n\n\tQString scriptText = QString::fromUtf8(scriptFile.readAll());\n\tpSettings->setLastUsedPath(scriptFileFullPath);\n\n\tif(pVSSLibrary->initialize())\n\t{\n\t\tpPreviewDialog->previewScript(scriptText, scriptFileFullPath);\n\t\texitCode = pPreviewDialog->exec();\n\t}\n\treturn exitCode;\n}\n"
  },
  {
    "path": "vsedit-job-server/src/job_server.cpp",
    "content": "#include \"job_server.h\"\n\n#include \"../../common-src/ipc_defines.h\"\n#include \"../../common-src/helpers.h\"\n#include \"jobs/jobs_manager.h\"\n\n#include <QWebSocketServer>\n#include <QWebSocket>\n\n//==============================================================================\n\nJobServer::JobServer(QObject * a_pParent) : QObject(a_pParent)\n\t, m_pSettingsManager(nullptr)\n\t, m_pJobsManager(nullptr)\n\t, m_pWebSocketServer(nullptr)\n{\n\tm_pSettingsManager = new SettingsManagerCore(this);\n\n\tm_trustedClientsAddresses =\n\t\tm_pSettingsManager->getTrustedClientsAddresses();\n\n\tm_pJobsManager = new JobsManager(m_pSettingsManager, this);\n\tm_pJobsManager->loadJobs();\n\tconnect(m_pJobsManager, &JobsManager::signalLogMessage,\n\t\tthis, &JobServer::slotLogMessage);\n\tconnect(m_pJobsManager, &JobsManager::signalJobCreated,\n\t\tthis, &JobServer::slotJobCreated);\n\tconnect(m_pJobsManager, &JobsManager::signalJobChanged,\n\t\tthis, &JobServer::slotJobChanged);\n\tconnect(m_pJobsManager, &JobsManager::signalJobStateChanged,\n\t\tthis, &JobServer::slotJobStateChanged);\n\tconnect(m_pJobsManager, &JobsManager::signalJobProgressChanged,\n\t\tthis, &JobServer::slotJobProgressChanged);\n\tconnect(m_pJobsManager, &JobsManager::signalJobStartTimeChanged,\n\t\tthis, &JobServer::slotJobStartTimeChanged);\n\tconnect(m_pJobsManager, &JobsManager::signalJobEndTimeChanged,\n\t\tthis, &JobServer::slotJobEndTimeChanged);\n\tconnect(m_pJobsManager, &JobsManager::signalJobDependenciesChanged,\n\t\tthis, &JobServer::slotJobDependenciesChanged);\n\tconnect(m_pJobsManager, &JobsManager::signalJobsSwapped,\n\t\tthis, &JobServer::slotJobsSwapped);\n\tconnect(m_pJobsManager, &JobsManager::signalJobsDeleted,\n\t\tthis, &JobServer::slotJobsDeleted);\n\n\tm_pWebSocketServer = new QWebSocketServer(JOB_SERVER_NAME,\n\t\tQWebSocketServer::NonSecureMode, this);\n\tconnect(m_pWebSocketServer, &QWebSocketServer::newConnection,\n\t\tthis, &JobServer::slotNewConnection);\n}\n\n// END OF JobServer::JobServer(QObject * a_pParent)\n//==============================================================================\n\nJobServer::~JobServer()\n{\n\tfor(QWebSocket * pClient : m_clients)\n\t{\n\t\tdisconnect(pClient, &QWebSocket::disconnected,\n\t\t\tthis, &JobServer::slotSocketDisconnected);\n\t\tdelete pClient;\n\t}\n\tm_clients.clear();\n\tm_subscribers.clear();\n\tm_pWebSocketServer->close();\n\tm_pJobsManager->saveJobs();\n}\n\n// END OF JobServer::~JobServer()\n//==============================================================================\n\nbool JobServer::start()\n{\n\tQ_ASSERT(m_pWebSocketServer);\n\treturn m_pWebSocketServer->listen(QHostAddress::Any, JOB_SERVER_PORT);\n}\n\n// END OF bool JobServer::start()\n//==============================================================================\n\nvoid JobServer::slotNewConnection()\n{\n\tQWebSocket * pSocket = m_pWebSocketServer->nextPendingConnection();\n\tm_clients.push_back(pSocket);\n\n\tconnect(pSocket, &QWebSocket::binaryMessageReceived,\n\t\tthis, &JobServer::slotBinaryMessageReceived);\n\tconnect(pSocket, &QWebSocket::textMessageReceived,\n\t\tthis, &JobServer::slotTextMessageReceived);\n\tconnect(pSocket, &QWebSocket::disconnected,\n\t\tthis, &JobServer::slotSocketDisconnected);\n\n\tif(trustedClientAddress(pSocket->peerAddress()))\n\t{\n\t\tQByteArray message = vsedit::jsonMessage(SMSG_TRUSTED_CLIENTS_INFO,\n\t\t\tQJsonArray::fromStringList(m_trustedClientsAddresses));\n\t\tpSocket->sendBinaryMessage(message);\n\t}\n}\n\n// END OF void JobServer::slotNewConnection()\n//==============================================================================\n\nvoid JobServer::slotBinaryMessageReceived(\n\tconst QByteArray & a_message)\n{\n\tQWebSocket * pClient = qobject_cast<QWebSocket *>(sender());\n\tif(!pClient)\n\t\treturn;\n\tQString messageString = tr(a_message);\n\tprocessMessage(pClient, messageString);\n}\n\n// END OF void JobServer::slotBinaryMessageReceived(\n//\t\tconst QByteArray & a_message)\n//==============================================================================\n\nvoid JobServer::slotTextMessageReceived(const QString & a_message)\n{\n\tQWebSocket * pClient = qobject_cast<QWebSocket *>(sender());\n\tif(!pClient)\n\t\treturn;\n\tprocessMessage(pClient, a_message);\n}\n\n// END OF void JobServer::slotTextMessageReceived(const QString & a_message)\n//==============================================================================\n\nvoid JobServer::slotSocketDisconnected()\n{\n\tQWebSocket * pClient = qobject_cast<QWebSocket *>(sender());\n\tif(!pClient)\n\t\treturn;\n\tm_clients.remove(pClient);\n\tm_subscribers.remove(pClient);\n\tpClient->deleteLater();\n}\n\n// END OF void JobServer::slotSocketDisconnected()\n//==============================================================================\n\nvoid JobServer::slotLogMessage(const QString & a_message,\n\tconst QString & a_style)\n{\n\tLogEntry entry(a_message, a_style);\n\tm_logEntries.push_back(entry);\n\tbroadcastMessage(vsedit::jsonMessage(SMSG_LOG_MESSAGE, entry.toJson()));\n}\n\n// END OF void JobServer::slotLogMessage(const QString & a_message,\n//\t\tconst QString & a_style)\n//==============================================================================\n\nvoid JobServer::slotJobCreated(const JobProperties & a_properties)\n{\n\tbroadcastMessage(vsedit::jsonMessage(SMSG_JOB_CREATED,\n\t\ta_properties.toJson()));\n}\n\n// END OF void JobServer::slotJobCreated(const JobProperties & a_properties)\n//==============================================================================\n\nvoid JobServer::slotJobChanged(const JobProperties & a_properties)\n{\n\tbroadcastMessage(vsedit::jsonMessage(SMSG_JOB_UPDATE,\n\t\ta_properties.toJson()));\n}\n\n// END OF void JobServer::slotJobChanged(const JobProperties & a_properties)\n//==============================================================================\n\nvoid JobServer::slotJobStateChanged(const QUuid & a_jobID, JobState a_state)\n{\n\tQJsonObject jsJob;\n\tjsJob[JP_ID] = a_jobID.toString();\n\tjsJob[JP_JOB_STATE] = (int)a_state;\n\tbroadcastMessage(vsedit::jsonMessage(SMSG_JOB_STATE_UPDATE, jsJob));\n}\n\n// END OF void JobServer::slotJobStateChanged(const QUuid & a_jobID,\n//\t\tJobState a_state)\n//==============================================================================\n\nvoid JobServer::slotJobProgressChanged(const QUuid & a_jobID, int a_progress,\n\tdouble a_fps)\n{\n\tQJsonObject jsJob;\n\tjsJob[JP_ID] = a_jobID.toString();\n\tjsJob[JP_FRAMES_PROCESSED] = a_progress;\n\tjsJob[JP_FPS] = a_fps;\n\tbroadcastMessage(vsedit::jsonMessage(SMSG_JOB_PROGRESS_UPDATE, jsJob));\n}\n\n// END OF void JobServer::slotJobProgressChanged(const QUuid & a_jobID,\n//\t\tint a_progress, double a_fps)\n//==============================================================================\n\nvoid JobServer::slotJobStartTimeChanged(const QUuid & a_jobID,\n\tconst QDateTime & a_time)\n{\n\tQJsonObject jsJob;\n\tjsJob[JP_ID] = a_jobID.toString();\n\tjsJob[JP_TIME_STARTED] = a_time.toMSecsSinceEpoch();\n\tbroadcastMessage(vsedit::jsonMessage(SMSG_JOB_START_TIME_UPDATE, jsJob));\n}\n\n// END OF void JobServer::slotJobStartTimeChanged(const QUuid & a_jobID,\n//\t\tconst QDateTime & a_time)\n//==============================================================================\n\nvoid JobServer::slotJobEndTimeChanged(const QUuid & a_jobID,\n\tconst QDateTime & a_time)\n{\n\tQJsonObject jsJob;\n\tjsJob[JP_ID] = a_jobID.toString();\n\tjsJob[JP_TIME_ENDED] = a_time.toMSecsSinceEpoch();\n\tbroadcastMessage(vsedit::jsonMessage(SMSG_JOB_END_TIME_UPDATE, jsJob));\n}\n\n// END OF void JobServer::slotJobEndTimeChanged(const QUuid & a_jobID,\n//\t\tconst QDateTime & a_time)\n//==============================================================================\n\nvoid JobServer::slotJobDependenciesChanged(const QUuid & a_jobID,\n\tconst std::vector<QUuid> & a_dependencies)\n{\n\tQJsonObject jsJob;\n\tjsJob[JP_ID] = a_jobID.toString();\n\tQJsonArray jsDependencies;\n\tfor(const QUuid & id : a_dependencies)\n\t\tjsDependencies << id.toString();\n\tjsJob[JP_DEPENDS_ON_JOB_IDS] = jsDependencies;\n\tbroadcastMessage(vsedit::jsonMessage(SMSG_JOB_DEPENDENCIES_UPDATE, jsJob));\n}\n\n// END OF void JobServer::slotJobDependenciesChanged(const QUuid & a_jobID,\n//\t\tconst std::vector<QUuid> & a_dependencies)\n//==============================================================================\n\nvoid JobServer::slotJobsSwapped(const QUuid & a_jobID1, const QUuid & a_jobID2)\n{\n\tQJsonArray jsSwap;\n\tjsSwap << a_jobID1.toString();\n\tjsSwap << a_jobID2.toString();\n\tbroadcastMessage(vsedit::jsonMessage(SMSG_JOBS_SWAPPED, jsSwap));\n}\n\n// END OF void JobServer::slotJobsSwapped(const QUuid & a_jobID1,\n//\t\tconst QUuid & a_jobID2)\n//==============================================================================\n\nvoid JobServer::slotJobsDeleted(const std::vector<QUuid> & a_ids)\n{\n\tQJsonArray jsIdsArray;\n\tfor(const QUuid & id : a_ids)\n\t\tjsIdsArray.push_back(id.toString());\n\tbroadcastMessage(vsedit::jsonMessage(SMSG_JOBS_DELETED, jsIdsArray));\n}\n\n// END OF void JobServer::slotJobsDeleted(const std::vector<QUuid> & a_ids)\n//==============================================================================\n\nvoid JobServer::processMessage(QWebSocket * a_pClient,\n\tconst QString & a_message)\n{\n\tbool trustedClient = trustedClientAddress(a_pClient->peerAddress());\n\n\tQString command = a_message;\n\tQString arguments;\n\tint spaceIndex = a_message.indexOf(' ');\n\tif(spaceIndex >= 0)\n\t{\n\t\tcommand = a_message.left(spaceIndex);\n\t\targuments = a_message.mid(spaceIndex + 1);\n\t}\n\n\tQString trustedOnlyCommands[] = {MSG_CLOSE_SERVER, MSG_CREATE_JOB,\n\t\tMSG_CHANGE_JOB, MSG_SWAP_JOBS, MSG_RESET_JOBS, MSG_DELETE_JOBS,\n\t\tMSG_START_ALL_WAITING_JOBS, MSG_PAUSE_ACTIVE_JOBS,\n\t\tMSG_RESUME_PAUSED_JOBS, MSG_ABORT_ACTIVE_JOBS, MSG_GET_TRUSTED_CLIENTS,\n\t\tMSG_SET_TRUSTED_CLIENTS};\n\n\tif(vsedit::contains(trustedOnlyCommands, command) && (!trustedClient))\n\t{\n\t\ta_pClient->sendBinaryMessage(\"You're naughty! This command can not \"\n\t\t\t\"be executed remotely.\");\n\t\treturn;\n\t}\n\n\tQJsonDocument jsArguments = QJsonDocument::fromJson(arguments.toUtf8());\n\n\tif(command == QString(MSG_GET_JOBS_INFO))\n\t{\n\t\ta_pClient->sendBinaryMessage(jobsInfoMessage());\n\t\treturn;\n\t}\n\n\tif(command == QString(MSG_GET_LOG))\n\t{\n\t\ta_pClient->sendBinaryMessage(completeLogMessage());\n\t\treturn;\n\t}\n\n\tif(command == QString(MSG_SUBSCRIBE))\n\t{\n\t\tm_subscribers.push_back(a_pClient);\n\t\ta_pClient->sendBinaryMessage(\"Subscribed to jobs updates.\");\n\t\treturn;\n\t}\n\n\tif(command == QString(MSG_UNSUBSCRIBE))\n\t{\n\t\tm_subscribers.remove(a_pClient);\n\t\ta_pClient->sendBinaryMessage(\"Unsubscribed from jobs updates.\");\n\t\treturn;\n\t}\n\n\tif(command == QString(MSG_CLOSE_SERVER))\n\t{\n\t\tbroadcastMessage(SMSG_CLOSING_SERVER, true);\n\t\temit finish();\n\t\treturn;\n\t}\n\n\tif(command == QString(MSG_GET_TRUSTED_CLIENTS))\n\t{\n\t\tQByteArray message = vsedit::jsonMessage(SMSG_TRUSTED_CLIENTS_INFO,\n\t\t\tQJsonArray::fromStringList(m_trustedClientsAddresses));\n\t\ta_pClient->sendBinaryMessage(message);\n\t\treturn;\n\t}\n\n\tif(command == QString(MSG_SET_TRUSTED_CLIENTS))\n\t{\n\t\tQStringList trustedClientsAddresses;\n\t\tfor(QJsonValue value : jsArguments.array())\n\t\t{\n\t\t\tQString address = value.toString();\n\t\t\tQHostAddress hostAddress(address);\n\t\t\tif(hostAddress.isLoopback())\n\t\t\t\tcontinue;\n\t\t\ttrustedClientsAddresses << address;\n\t\t}\n\t\ttrustedClientsAddresses.removeDuplicates();\n        m_trustedClientsAddresses = trustedClientsAddresses;\n        m_pSettingsManager->setTrustedClientsAddresses(\n\t\t\tm_trustedClientsAddresses);\n\t\tQByteArray message = vsedit::jsonMessage(SMSG_TRUSTED_CLIENTS_INFO,\n\t\t\tQJsonArray::fromStringList(m_trustedClientsAddresses));\n\t\tbroadcastMessage(message, true, true);\n\t\treturn;\n\t}\n\n\tif(command == QString(MSG_CREATE_JOB))\n\t{\n\t\tJobProperties properties =\n\t\t\tJobProperties::fromJson(jsArguments.object());\n\t\tm_pJobsManager->createJob(properties);\n\t\treturn;\n\t}\n\n\tif(command == QString(MSG_CHANGE_JOB))\n\t{\n\t\tJobProperties properties =\n\t\t\tJobProperties::fromJson(jsArguments.object());\n\t\tm_pJobsManager->changeJob(properties);\n\t\treturn;\n\t}\n\n\tif(command == QString(MSG_SET_JOB_DEPENDENCIES))\n\t{\n\t\tQJsonObject jsJob = jsArguments.object();\n\t\tif(!jsJob.contains(JP_ID))\n\t\t\treturn;\n\t\tQUuid id(jsJob[JP_ID].toString());\n\t\tif(!jsJob.contains(JP_DEPENDS_ON_JOB_IDS))\n\t\t\treturn;\n\t\tQJsonArray jsDependencies = jsJob[JP_DEPENDS_ON_JOB_IDS].toArray();\n\t\tstd::vector<QUuid> dependencies;\n\t\tfor(int i = 0; i < jsDependencies.count(); ++i)\n\t\t\tdependencies.push_back(QUuid(jsDependencies[i].toString()));\n\t\tm_pJobsManager->setJobDependsOnIds(id, dependencies);\n\t\treturn;\n\t}\n\n\tif(command == QString(MSG_SWAP_JOBS))\n\t{\n\t\tQJsonArray jsIDs = jsArguments.array();\n\t\tif(jsIDs.count() != 2)\n\t\t\treturn;\n\t\tm_pJobsManager->swapJobs(QUuid(jsIDs[0].toString()),\n\t\t\tQUuid(jsIDs[1].toString()));\n\t\treturn;\n\t}\n\n\tif(command == QString(MSG_RESET_JOBS))\n\t{\n\t\tQJsonArray jsIDs = jsArguments.array();\n\t\tstd::vector<QUuid> ids;\n\t\tfor(int i = 0; i < jsIDs.count(); ++i)\n\t\t\tids.push_back(QUuid(jsIDs[i].toString()));\n\t\tm_pJobsManager->resetJobs(ids);\n\t\treturn;\n\t}\n\n\tif(command == QString(MSG_DELETE_JOBS))\n\t{\n\t\tQJsonArray jsIDs = jsArguments.array();\n\t\tstd::vector<QUuid> ids;\n\t\tfor(int i = 0; i < jsIDs.count(); ++i)\n\t\t\tids.push_back(QUuid(jsIDs[i].toString()));\n\t\tm_pJobsManager->deleteJobs(ids);\n\t\treturn;\n\t}\n\n\tif(command == QString(MSG_START_ALL_WAITING_JOBS))\n\t{\n\t\tm_pJobsManager->startWaitingJobs();\n\t\treturn;\n\t}\n\n\tif(command == QString(MSG_PAUSE_ACTIVE_JOBS))\n\t{\n\t\tm_pJobsManager->pauseActiveJobs();\n\t\treturn;\n\t}\n\n\tif(command == QString(MSG_RESUME_PAUSED_JOBS))\n\t{\n\t\tm_pJobsManager->resumePausedJobs();\n\t\treturn;\n\t}\n\n\tif(command == QString(MSG_ABORT_ACTIVE_JOBS))\n\t{\n\t\tm_pJobsManager->abortActiveJobs();\n\t\treturn;\n\t}\n\n\ta_pClient->sendBinaryMessage(QString(\"Received an unknown command: %1\")\n\t\t.arg(a_message).toUtf8());\n}\n\n// END OF void JobServer::processMessage(QWebSocket * a_pClient,\n//\t\tconst QString & a_message)\n//==============================================================================\n\nQByteArray JobServer::jobsInfoMessage() const\n{\n\tQJsonArray jsJobs;\n\tfor(const JobProperties & properties : m_pJobsManager->jobsProperties())\n\t\tjsJobs.push_back(properties.toJson());\n\tQByteArray message = vsedit::jsonMessage(SMSG_JOBS_INFO, jsJobs);\n\treturn message;\n}\n\n// END OF QByteArray JobServer::jobsInfoMessage() const\n//==============================================================================\n\nQByteArray JobServer::completeLogMessage() const\n{\n\tQJsonArray jsEntries;\n\tfor(const LogEntry & entry : m_logEntries)\n\t\tjsEntries.push_back(entry.toJson());\n\tQByteArray message = vsedit::jsonMessage(SMSG_COMPLETE_LOG, jsEntries);\n\treturn message;\n}\n\n// END OF QByteArray JobServer::completeLogMessage() const\n//==============================================================================\n\nvoid JobServer::broadcastMessage(const QString & a_message,\n\tbool a_includeNonSubscribers, bool a_trustedOnly)\n{\n\tbroadcastMessage(a_message.toUtf8(), a_includeNonSubscribers,\n\t\ta_trustedOnly);\n}\n\n// END OF void JobServer::broadcastMessage(const QString & a_message,\n//\t\tbool a_includeNonSubscribers, bool a_trustedOnly)\n//==============================================================================\n\nvoid JobServer::broadcastMessage(const char * a_message,\n\tbool a_includeNonSubscribers, bool a_trustedOnly)\n{\n\tbroadcastMessage(QByteArray(a_message), a_includeNonSubscribers,\n\t\ta_trustedOnly);\n}\n\n// END OF void JobServer::broadcastMessage(const char * a_message,\n//\t\tbool a_includeNonSubscribers, bool a_trustedOnly)\n//==============================================================================\n\nvoid JobServer::broadcastMessage(const QByteArray & a_message,\n\tbool a_includeNonSubscribers, bool a_trustedOnly)\n{\n\tstd::list<QWebSocket *> & clients =\n\t\ta_includeNonSubscribers ? m_clients : m_subscribers;\n\tfor(QWebSocket * pClient : clients)\n\t{\n\t\tif((!a_trustedOnly) || trustedClientAddress(pClient->peerAddress()))\n\t\t\tpClient->sendBinaryMessage(a_message);\n\t}\n}\n\n// END OF void JobServer::broadcastMessage(const QByteArray & a_message,\n//\t\tbool a_includeNonSubscribers, bool a_trustedOnly)\n//==============================================================================\n\nbool JobServer::trustedClientAddress(const QHostAddress & a_address)\n{\n\treturn (a_address.isLoopback() ||\n\t\tm_trustedClientsAddresses.contains(a_address.toString()) ||\n\t\tm_trustedClientsAddresses.contains(\n\t\ta_address.toString().remove(\"::ffff:\")));\n}\n\n// END OF bool JobServer::trustedClientAddress(const QHostAddress & a_address)\n//==============================================================================\n"
  },
  {
    "path": "vsedit-job-server/src/job_server.h",
    "content": "#ifndef WEB_SOCKET_JOB_SERVER_H_INCLUDED\n#define WEB_SOCKET_JOB_SERVER_H_INCLUDED\n\n#include \"../../common-src/settings/settings_manager_core.h\"\n#include \"../../common-src/log/styled_log_view_core.h\"\n\n#include <QObject>\n#include <QJsonDocument>\n#include <QJsonObject>\n#include <QJsonArray>\n#include <list>\n#include <vector>\n\nclass SettingsManagerCore;\nclass JobsManager;\nclass QWebSocketServer;\nclass QWebSocket;\nclass QHostAddress;\n\nclass JobServer : public QObject\n{\n\tQ_OBJECT\n\npublic:\n\n\tJobServer(QObject * a_pParent = nullptr);\n\tvirtual ~JobServer();\n\n\tbool start();\n\nsignals:\n\n\tvoid finish();\n\nprivate slots:\n\n\tvoid slotNewConnection();\n\tvoid slotBinaryMessageReceived(const QByteArray & a_message);\n\tvoid slotTextMessageReceived(const QString & a_message);\n\tvoid slotSocketDisconnected();\n\n\tvoid slotLogMessage(const QString & a_message, const QString & a_style);\n\tvoid slotJobCreated(const JobProperties & a_properties);\n\tvoid slotJobChanged(const JobProperties & a_properties);\n\tvoid slotJobStateChanged(const QUuid & a_jobID, JobState a_state);\n\tvoid slotJobProgressChanged(const QUuid & a_jobID, int a_progress,\n\t\tdouble a_fps);\n\tvoid slotJobStartTimeChanged(const QUuid & a_jobID,\n\t\tconst QDateTime & a_time);\n\tvoid slotJobEndTimeChanged(const QUuid & a_jobID,\n\t\tconst QDateTime & a_time);\n\tvoid slotJobDependenciesChanged(const QUuid & a_jobID,\n\t\tconst std::vector<QUuid> & a_dependencies);\n\tvoid slotJobsSwapped(const QUuid & a_jobID1, const QUuid & a_jobID2);\n\tvoid slotJobsDeleted(const std::vector<QUuid> & a_ids);\n\nprivate:\n\n\tvoid processMessage(QWebSocket * a_pClient, const QString & a_message);\n\tQByteArray jobsInfoMessage() const;\n\tQByteArray completeLogMessage() const;\n\n\tvoid broadcastMessage(const QString & a_message,\n\t\tbool a_includeNonSubscribers = false, bool a_trustedOnly = false);\n\tvoid broadcastMessage(const char * a_message,\n\t\tbool a_includeNonSubscribers = false, bool a_trustedOnly = false);\n\tvoid broadcastMessage(const QByteArray & a_message,\n\t\tbool a_includeNonSubscribers = false, bool a_trustedOnly = false);\n\n\tbool trustedClientAddress(const QHostAddress & a_address);\n\n\tSettingsManagerCore * m_pSettingsManager;\n\tJobsManager * m_pJobsManager;\n\tQWebSocketServer * m_pWebSocketServer;\n\n\tstd::vector<LogEntry> m_logEntries;\n\n\tstd::list<QWebSocket *> m_clients;\n\tstd::list<QWebSocket *> m_subscribers;\n\n\tQStringList m_trustedClientsAddresses;\n};\n\n#endif // WEB_SOCKET_JOB_SERVER_H_INCLUDED\n"
  },
  {
    "path": "vsedit-job-server/src/jobs/job_definitions.h",
    "content": "#ifndef JOB_DEFINITIONS_H_INCLUDED\n#define JOB_DEFINITIONS_H_INCLUDED\n\n#include \"../../../common-src/jobs/job.h\"\n\nenum class JobWantTo\n{\n\tNothing,\n\tRunNext,\n};\n\nstruct JobTicket\n{\n\tvsedit::Job * pJob;\n\tJobWantTo whenDone;\n};\n\n#endif // JOB_DEFINITIONS_H_INCLUDED\n"
  },
  {
    "path": "vsedit-job-server/src/jobs/jobs_manager.cpp",
    "content": "#include \"jobs_manager.h\"\n\n#include \"../../../common-src/settings/settings_manager_core.h\"\n#include \"../../../common-src/vapoursynth/vs_script_library.h\"\n\n//==============================================================================\n\nJobsManager::JobsManager(SettingsManagerCore * a_pSettingsManager,\n\tQObject * a_pParent) :\n\t  QObject(a_pParent)\n\t, m_pSettingsManager(a_pSettingsManager)\n\t, m_pVSScriptLibrary(nullptr)\n{\n\tQ_ASSERT(m_pSettingsManager);\n\n\tm_pVSScriptLibrary = new VSScriptLibrary(m_pSettingsManager, this);\n\n\tconnect(m_pVSScriptLibrary,\n\t\tSIGNAL(signalWriteLogMessage(int, const QString &)),\n\t\tthis, SLOT(slotLogMessage(int, const QString &)));\n}\n\n// END OF\n//==============================================================================\n\nJobsManager::~JobsManager()\n{\n}\n\n// END OF\n//==============================================================================\n\nstd::vector<JobProperties> JobsManager::jobsProperties() const\n{\n\tstd::vector<JobProperties> properties;\n\tfor(const JobTicket & ticket : m_tickets)\n\t\tproperties.push_back(ticket.pJob->properties());\n\treturn properties;\n}\n\n// END OF\n//==============================================================================\n\nint JobsManager::createJob(const JobProperties & a_jobProperties)\n{\n\tvsedit::Job * pJob = new vsedit::Job(a_jobProperties,  m_pSettingsManager,\n\t\tm_pVSScriptLibrary, this);\n\tconnectJob(pJob);\n\tJobTicket ticket = {pJob, JobWantTo::Nothing};\n\tm_tickets.push_back(ticket);\n\tint newRow = (int)m_tickets.size();\n\tsaveJobs();\n\temit signalJobCreated(a_jobProperties);\n\treturn newRow;\n}\n\n// END OF\n//==============================================================================\n\nbool JobsManager::swapJobs(const QUuid & a_jobID1, const QUuid & a_jobID2)\n{\n\tint lowerIndex = indexOfJob(a_jobID1);\n\tif(lowerIndex < 0)\n\t\treturn false;\n\tint higherIndex = indexOfJob(a_jobID2);\n\tif(higherIndex < 0)\n\t\treturn false;\n\tif(higherIndex < lowerIndex)\n\t\tstd::swap(lowerIndex, higherIndex);\n\n\tfor(int i = lowerIndex; i < higherIndex; ++i)\n\t{\n\t\tif(vsedit::contains(m_tickets[higherIndex].pJob->dependsOnJobIds(),\n\t\t\tm_tickets[i].pJob->id()))\n\t\t\treturn false;\n\t}\n\n\tfor(int i = lowerIndex + 1; i < higherIndex; ++i)\n\t{\n\t\tif(vsedit::contains(m_tickets[i].pJob->dependsOnJobIds(),\n\t\t\tm_tickets[lowerIndex].pJob->id()))\n\t\t\treturn false;\n\t}\n\n\tstd::swap(m_tickets[lowerIndex], m_tickets[higherIndex]);\n\tsaveJobs();\n\temit signalJobsSwapped(a_jobID1, a_jobID2);\n\treturn true;\n}\n\n// END OF\n//==============================================================================\n\nbool JobsManager::setJobState(const QUuid & a_jobID, JobState a_state)\n{\n\tint index = indexOfJob(a_jobID);\n\tif(!checkCanModifyJobAndNotify(index))\n\t\treturn false;\n\tbool result = m_tickets[index].pJob->setState(a_state);\n\tif(result)\n\t\tsaveJobs();\n\treturn result;\n}\n\n// END OF\n//==============================================================================\n\nbool JobsManager::setJobDependsOnIds(const QUuid & a_jobID,\n\tconst std::vector<QUuid> & a_dependencies)\n{\n\tint index = indexOfJob(a_jobID);\n\tif(!checkCanModifyJobAndNotify(index))\n\t\treturn false;\n\n\tfor(const QUuid & id : a_dependencies)\n\t{\n\t\tint dependencyIndex = indexOfJob(id);\n\t\tif((dependencyIndex < 0) || (dependencyIndex >= index))\n\t\t\treturn false;\n\t}\n\n\tbool result = m_tickets[index].pJob->setDependsOnJobIds(a_dependencies);\n\tif(!result)\n\t\treturn false;\n\n\tsaveJobs();\n\temit signalJobDependenciesChanged(a_jobID, a_dependencies);\n\n\treturn true;\n}\n\n// END OF\n//==============================================================================\n\nbool JobsManager::changeJob(const JobProperties & a_jobProperties)\n{\n\tint index = indexOfJob(a_jobProperties.id);\n\tif(!checkCanModifyJobAndNotify(index))\n\t\treturn false;\n\tvsedit::Job * pJob = m_tickets[index].pJob;\n\tbool result = pJob->setProperties(a_jobProperties);\n\tif(result)\n\t\tresult = pJob->setState(JobState::Waiting);\n\tsaveJobs();\n\temit signalJobChanged(pJob->properties());\n\treturn result;\n}\n\n// END OF\n//==============================================================================\n\nbool JobsManager::loadJobs()\n{\n\tif(hasActiveJobs())\n\t{\n\t\temit signalLogMessage(tr(\"Can not load jobs. \"\n\t\t\t\"Some of current jobs are still active.\", LOG_STYLE_WARNING));\n\t\treturn false;\n\t}\n\n\tif((!m_pSettingsManager) || (!m_pVSScriptLibrary))\n\t{\n\t\temit signalLogMessage(tr(\"Can not load jobs. \"\n\t\t\t\"Model is not initialized correctly.\", LOG_STYLE_ERROR));\n\t\treturn false;\n\t}\n\n\tclearJobs();\n\n\tstd::vector<JobProperties> jobPropertiesList =\n\t\tm_pSettingsManager->getJobs();\n\tfor(const JobProperties & properties : jobPropertiesList)\n\t{\n\t\tvsedit::Job * pJob = new vsedit::Job(properties, m_pSettingsManager,\n\t\t\tm_pVSScriptLibrary);\n\t\tif(vsedit::contains(ACTIVE_JOB_STATES, pJob->state()))\n\t\t\tpJob->setState(JobState::Aborted);\n\t\tconnectJob(pJob);\n\t\tJobTicket ticket = {pJob, JobWantTo::Nothing};\n\t\tm_tickets.push_back(ticket);\n\t}\n\n\treturn true;\n}\n\n// END OF\n//==============================================================================\n\nbool JobsManager::saveJobs()\n{\n\tif(!m_pSettingsManager)\n\t{\n\t\temit signalLogMessage(tr(\"Can not save jobs. \"\n\t\t\t\"Model is not initialized correctly.\", LOG_STYLE_ERROR));\n\t\treturn false;\n\t}\n\n\tstd::vector<JobProperties> jobPropertiesList;\n\tfor(const JobTicket & ticket : m_tickets)\n\t\tjobPropertiesList.push_back(ticket.pJob->properties());\n\n\tbool result = m_pSettingsManager->setJobs(jobPropertiesList);\n\n\tif(!result)\n\t\temit signalLogMessage(tr(\"Failed to save jobs.\", LOG_STYLE_ERROR));\n\n\treturn result;\n}\n\n// END OF\n//==============================================================================\n\nbool JobsManager::hasActiveJobs()\n{\n\tfor(const JobTicket & ticket : m_tickets)\n\t{\n\t\tif(vsedit::contains(ACTIVE_JOB_STATES, ticket.pJob->state()))\n\t\t\treturn true;\n\t}\n\treturn false;\n}\n\n// END OF\n//==============================================================================\n\nvoid JobsManager::startWaitingJobs()\n{\n\tstartFirstReadyJob();\n}\n\n// END OF\n//==============================================================================\n\nvoid JobsManager::abortActiveJobs()\n{\n\tfor(JobTicket & ticket : m_tickets)\n\t{\n\t\tif(!vsedit::contains(ACTIVE_JOB_STATES, ticket.pJob->state()))\n\t\t\tcontinue;\n\t\tticket.whenDone = JobWantTo::Nothing;\n\t\tticket.pJob->abort();\n\t}\n}\n\n// END OF\n//==============================================================================\n\nvoid JobsManager::pauseActiveJobs()\n{\n\tfor(JobTicket & ticket : m_tickets)\n\t{\n\t\tif(ticket.pJob->state() != JobState::Running)\n\t\t\tcontinue;\n\t\tticket.pJob->pause();\n\t}\n}\n\n// END OF\n//==============================================================================\n\nvoid JobsManager::resumePausedJobs()\n{\n\tfor(JobTicket & ticket : m_tickets)\n\t{\n\t\tif(ticket.pJob->state() != JobState::Paused)\n\t\t\tcontinue;\n\t\tticket.pJob->start();\n\t}\n}\n\n// END OF\n//==============================================================================\n\nvoid JobsManager::resetJobs(const std::vector<QUuid> & a_ids)\n{\n\tfor(const QUuid & id : a_ids)\n\t\tsetJobState(id, JobState::Waiting);\n}\n\n// END OF\n//==============================================================================\n\nvoid JobsManager::deleteJobs(const std::vector<QUuid> & a_ids)\n{\n\tstd::vector<QUuid> deletedJobs;\n\tfor(const QUuid & id : a_ids)\n\t{\n\t\tint index = indexOfJob(id);\n\t\tif(index < 0)\n\t\t\tcontinue;\n\n\t\tvsedit::Job * pJob = m_tickets[index].pJob;\n\t\tif(vsedit::contains(ACTIVE_JOB_STATES, pJob->state()))\n\t\t{\n\t\t\temit signalLogMessage(tr(\"Can not delete an active job.\"),\n\t\t\t\tLOG_STYLE_WARNING);\n\t\t\treturn;\n\t\t}\n\n\t\tfor(const JobTicket & ticket : m_tickets)\n\t\t{\n\t\t\tif(vsedit::contains(ticket.pJob->dependsOnJobIds(), pJob->id()))\n\t\t\t{\n\t\t\t\temit signalLogMessage(tr(\"Can not delete a job while \"\n\t\t\t\t\t\"other jobs depend on it.\"), LOG_STYLE_WARNING);\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\n\t\tdelete pJob;\n\t\tm_tickets.erase(m_tickets.begin() + index);\n\t\tdeletedJobs.push_back(id);\n\t}\n\tsaveJobs();\n\temit signalJobsDeleted(deletedJobs);\n}\n\n// END OF\n//==============================================================================\n\nvoid JobsManager::slotLogMessage(const QString & a_message,\n\tconst QString & a_style)\n{\n\tQString message = a_message;\n\tconst vsedit::Job * cpJob = qobject_cast<const vsedit::Job *>(sender());\n\tif(cpJob)\n\t{\n\t\tptrdiff_t index = indexOfJob(cpJob->id());\n\t\tif(index >= 0)\n\t\t\tmessage = QString(\"Job %1: %2\").arg(index + 1).arg(a_message);\n\t}\n\n\temit signalLogMessage(message, a_style);\n}\n\n// END OF\n//==============================================================================\n\nvoid JobsManager::slotLogMessage(int a_type, const QString & a_message)\n{\n\tQString style = vsMessageTypeToStyleName(a_type);\n\tslotLogMessage(a_message, style);\n}\n\n// END OF\n//==============================================================================\n\nvoid JobsManager::slotJobPropertiesChanged()\n{\n\tvsedit::Job * pJob = qobject_cast<vsedit::Job *>(sender());\n\tif(!pJob)\n\t\treturn;\n\temit signalJobChanged(pJob->properties());\n}\n\n// END OF\n//==============================================================================\n\nvoid JobsManager::slotJobStateChanged(JobState a_newState, JobState a_oldState)\n{\n\tif(a_oldState == a_newState)\n\t\treturn;\n\n\tvsedit::Job * pJob = qobject_cast<vsedit::Job *>(sender());\n\tif(!pJob)\n\t\treturn;\n\n\tsaveJobs();\n\temit signalJobStateChanged(pJob->id(), a_newState);\n\n\tif(vsedit::contains(ACTIVE_JOB_STATES, a_newState))\n\t\treturn;\n\n\t// Recursion\n\tif(a_newState == JobState::DependencyNotMet)\n\t\treturn;\n\n\t// State reset\n\tif(a_newState == JobState::Waiting)\n\t\treturn;\n\n\tint jobIndex = indexOfJob(pJob->id());\n\n\tif(m_tickets[jobIndex].whenDone == JobWantTo::RunNext)\n\t\tstartFirstReadyJob(jobIndex + 1);\n\n\tm_tickets[jobIndex].whenDone = JobWantTo::Nothing;\n}\n\n// END OF\n//==============================================================================\n\nvoid JobsManager::slotJobProgressChanged()\n{\n\tvsedit::Job * pJob = qobject_cast<vsedit::Job *>(sender());\n\tif(!pJob)\n\t\treturn;\n\temit signalJobProgressChanged(pJob->id(), pJob->framesProcessed(),\n\t\tpJob->fps());\n}\n\n// END OF\n//==============================================================================\n\nvoid JobsManager::slotJobStartTimeChanged()\n{\n\tvsedit::Job * pJob = qobject_cast<vsedit::Job *>(sender());\n\tif(!pJob)\n\t\treturn;\n\temit signalJobStartTimeChanged(pJob->id(), pJob->properties().timeStarted);\n}\n\n// END OF\n//==============================================================================\n\nvoid JobsManager::slotJobEndTimeChanged()\n{\n\tvsedit::Job * pJob = qobject_cast<vsedit::Job *>(sender());\n\tif(!pJob)\n\t\treturn;\n\temit signalJobEndTimeChanged(pJob->id(), pJob->properties().timeEnded);\n}\n\n// END OF\n//==============================================================================\n\nbool JobsManager::canModifyJob(int a_index) const\n{\n\tif((a_index < 0) || ((size_t)a_index >= m_tickets.size()))\n\t\treturn false;\n\n\tvsedit::Job * pJob = m_tickets[a_index].pJob;\n\tQ_ASSERT(pJob);\n\tif(!pJob)\n\t\treturn false;\n\n\tif(vsedit::contains(ACTIVE_JOB_STATES, pJob->state()))\n\t\treturn false;\n\n\treturn true;\n}\n\n// END OF\n//==============================================================================\n\nint JobsManager::indexOfJob(const QUuid & a_uuid) const\n{\n\tstd::vector<JobTicket>::const_iterator it =\n\t\tstd::find_if(m_tickets.cbegin(), m_tickets.cend(),\n\t\t\t[&](const JobTicket & a_ticket)->bool\n\t\t\t{\n\t\t\t\treturn (a_ticket.pJob->id() == a_uuid);\n\t\t\t});\n\n\treturn (it == m_tickets.cend()) ?\n\t\t-1 : std::distance(m_tickets.cbegin(), it);\n}\n\n// END OF\n//==============================================================================\n\nvoid JobsManager::clearJobs()\n{\n\tfor(JobTicket & ticket : m_tickets)\n\t\tdelete ticket.pJob;\n\tm_tickets.clear();\n}\n\n// END OF\n//==============================================================================\n\nbool JobsManager::checkCanModifyJobAndNotify(int a_index)\n{\n\tbool result = canModifyJob(a_index);\n\tif(!result)\n\t{\n\t\temit signalLogMessage(tr(\"Can not modify an active job.\"),\n\t\t\tLOG_STYLE_WARNING);\n\t}\n\treturn result;\n}\n\n// END OF\n//==============================================================================\n\nJobsManager::DependenciesState JobsManager::dependenciesState(int a_index)\n{\n\tif((a_index < 0) || (a_index >= (int)m_tickets.size()))\n\t\treturn DependenciesState::Failed;\n\n\tJobState failStates[] = {JobState::Aborted, JobState::Aborting,\n\t\tJobState::DependencyNotMet, JobState::Failed, JobState::FailedCleanUp};\n\n\tbool incomplete = false;\n\n\tfor(const QUuid & id : m_tickets[a_index].pJob->dependsOnJobIds())\n\t{\n\t\tint dependencyIndex = indexOfJob(id);\n\t\tif((dependencyIndex < 0) || (dependencyIndex >= (int)m_tickets.size()))\n\t\t\treturn DependenciesState::Failed;\n\t\tconst vsedit::Job * pDependentJob = m_tickets[dependencyIndex].pJob;\n\t\tif(pDependentJob->state() != JobState::Completed)\n\t\t\tincomplete = true;\n\t\tif(vsedit::contains(failStates, pDependentJob->state()))\n\t\t\treturn DependenciesState::Failed;\n\t}\n\n\tif(incomplete)\n\t\treturn DependenciesState::Incomplete;\n\n\treturn DependenciesState::Complete;\n}\n\n// END OF\n//==============================================================================\n\nvoid JobsManager::connectJob(vsedit::Job * a_pJob)\n{\n\tconnect(a_pJob, SIGNAL(signalPropertiesChanged()),\n\t\tthis, SLOT(slotJobPropertiesChanged()));\n\tconnect(a_pJob, SIGNAL(signalStateChanged(JobState, JobState)),\n\t\tthis, SLOT(slotJobStateChanged(JobState, JobState)));\n\tconnect(a_pJob, SIGNAL(signalProgressChanged()),\n\t\tthis, SLOT(slotJobProgressChanged()));\n\tconnect(a_pJob, SIGNAL(signalStartTimeChanged()),\n\t\tthis, SLOT(slotJobStartTimeChanged()));\n\tconnect(a_pJob, SIGNAL(signalEndTimeChanged()),\n\t\tthis, SLOT(slotJobEndTimeChanged()));\n\tconnect(a_pJob, SIGNAL(signalLogMessage(const QString &, const QString &)),\n\t\tthis, SLOT(slotLogMessage(const QString &, const QString &)));\n}\n\n// END OF\n//==============================================================================\n\nvoid JobsManager::startFirstReadyJob(int a_fromIndex)\n{\n\tif((a_fromIndex < 0) || (a_fromIndex >= (int)m_tickets.size()))\n\t\treturn;\n\n\tJobState validStates[] = {JobState::Waiting, JobState::Paused};\n\n\tfor(int i = a_fromIndex; i < (a_fromIndex + (int)m_tickets.size()); ++i)\n\t{\n\t\tint nextIndex = i % m_tickets.size();\n\t\tvsedit::Job * pNextJob = m_tickets[nextIndex].pJob;\n\t\tif(pNextJob->isActive())\n\t\t\treturn;\n\t\tif(!vsedit::contains(validStates, pNextJob->state()))\n\t\t\tcontinue;\n\t\tDependenciesState jobDependenciesState = dependenciesState(i);\n\t\tif(jobDependenciesState == DependenciesState::Failed)\n\t\t\tpNextJob->setState(JobState::DependencyNotMet);\n\t\tif(jobDependenciesState != DependenciesState::Complete)\n\t\t\tcontinue;\n\t\tm_tickets[nextIndex].whenDone = JobWantTo::RunNext;\n\t\tpNextJob->start();\n\t\treturn;\n\t}\n}\n\n// END OF\n//==============================================================================\n"
  },
  {
    "path": "vsedit-job-server/src/jobs/jobs_manager.h",
    "content": "#ifndef JOBS_MANAGER_H_INCLUDED\n#define JOBS_MANAGER_H_INCLUDED\n\n#include \"../../../common-src/jobs/job.h\"\n#include \"job_definitions.h\"\n#include \"../../../common-src/log/vs_editor_log_definitions.h\"\n\n#include <QObject>\n#include <vector>\n\nclass SettingsManagerCore;\nclass VSScriptLibrary;\n\nclass JobsManager : public QObject\n{\n\tQ_OBJECT\n\npublic:\n\n\tJobsManager(SettingsManagerCore * a_pSettingsManager,\n\t\tQObject * a_pParent = nullptr);\n\tvirtual ~JobsManager();\n\n\tstd::vector<JobProperties> jobsProperties() const;\n\n\tint createJob(const JobProperties & a_jobProperties = JobProperties());\n\n\tbool swapJobs(const QUuid & a_jobID1, const QUuid & a_jobID2);\n\n\tbool setJobState(const QUuid & a_jobID, JobState a_state);\n\tbool setJobDependsOnIds(const QUuid & a_jobID,\n\t\tconst std::vector<QUuid> & a_dependencies);\n\tbool changeJob(const JobProperties & a_jobProperties);\n\n\tbool loadJobs();\n\tbool saveJobs();\n\n\tbool hasActiveJobs();\n\n\tvoid startWaitingJobs();\n\tvoid abortActiveJobs();\n\tvoid pauseActiveJobs();\n\tvoid resumePausedJobs();\n\tvoid resetJobs(const std::vector<QUuid> & a_ids);\n\tvoid deleteJobs(const std::vector<QUuid> & a_ids);\n\nsignals:\n\n\tvoid signalLogMessage(const QString & a_message,\n\t\tconst QString & a_style = LOG_STYLE_DEFAULT);\n\tvoid signalJobCreated(const JobProperties & a_properties);\n\tvoid signalJobChanged(const JobProperties & a_properties);\n\tvoid signalJobStateChanged(const QUuid & a_jobID, JobState a_state);\n\tvoid signalJobProgressChanged(const QUuid & a_jobID, int a_progress,\n\t\tdouble a_fps);\n\tvoid signalJobStartTimeChanged(const QUuid & a_jobID,\n\t\tconst QDateTime & a_time);\n\tvoid signalJobEndTimeChanged(const QUuid & a_jobID,\n\t\tconst QDateTime & a_time);\n\tvoid signalJobDependenciesChanged(const QUuid & a_jobID,\n\t\tconst std::vector<QUuid> & a_dependencies);\n\tvoid signalJobsSwapped(const QUuid & a_jobID1, const QUuid & a_jobID2);\n\tvoid signalJobsDeleted(const std::vector<QUuid> & a_ids);\n\nprivate slots:\n\n\tvoid slotLogMessage(const QString & a_message,\n\t\tconst QString & a_style = LOG_STYLE_DEFAULT);\n\tvoid slotLogMessage(int a_type, const QString & a_message);\n\n\tvoid slotJobPropertiesChanged();\n\tvoid slotJobStateChanged(JobState a_newState, JobState a_oldState);\n\tvoid slotJobProgressChanged();\n\tvoid slotJobStartTimeChanged();\n\tvoid slotJobEndTimeChanged();\n\nprivate:\n\n\tenum class DependenciesState\n\t{\n\t\tIncomplete,\n\t\tComplete,\n\t\tFailed,\n\t};\n\n\tbool canModifyJob(int a_index) const;\n\n\tint indexOfJob(const QUuid & a_uuid) const;\n\n\tvoid clearJobs();\n\n\tbool checkCanModifyJobAndNotify(int a_index);\n\n\tDependenciesState dependenciesState(int a_index);\n\n\tvoid connectJob(vsedit::Job * a_pJob);\n\n\tvoid startFirstReadyJob(int a_fromIndex = 0);\n\n\tstd::vector<JobTicket> m_tickets;\n\n\tSettingsManagerCore * m_pSettingsManager;\n\tVSScriptLibrary * m_pVSScriptLibrary;\n};\n\n#endif // JOBS_MANAGER_H_INCLUDED\n"
  },
  {
    "path": "vsedit-job-server/src/main.cpp",
    "content": "#include \"job_server.h\"\n\n#include \"../../common-src/application_instance_file_guard/application_instance_file_guard.h\"\n#include \"../../common-src/ipc_defines.h\"\n#include \"../../common-src/version_info.h\"\n#include <VapourSynth4.h>\n\n#include <QCoreApplication>\n\nQ_DECLARE_OPAQUE_POINTER(const VSFrame *)\nQ_DECLARE_OPAQUE_POINTER(VSNode *)\n\nint main(int argc, char *argv[])\n{\n\tif(argc > 1)\n\t{\n\t\tif(strcmp(argv[1], \"-v\") == 0 ||\n\t\t\tstrcmp(argv[1], \"--version\") == 0)\n\t\t{\n\t\t\tprint_version();\n\t\t\treturn 0;\n\t\t}\n\t}\n\n\tQCoreApplication application(argc, argv);\n\n\tqRegisterMetaType<const VSFrame *>(\"const VSFrame *\");\n\tqRegisterMetaType<VSNode *>(\"VSNode *\");\n\n\tApplicationInstanceFileGuard guard(\"vsedit_job_server_running\");\n\tif(!guard.isLocked())\n\t{\n\t\tqCritical(\"Couldn't start the server. \"\n\t\t\t\"Another instance is probably already running.\");\n\t\treturn 1;\n\t}\n\n\tJobServer jobServer;\n\n\tapplication.connect(&jobServer, &JobServer::finish,\n\t\t&application, &QCoreApplication::quit);\n\n\tbool started = jobServer.start();\n\tif(!started)\n\t{\n\t\tqCritical(\"Couldn't start the server.\");\n\t\treturn 1;\n\t}\n\n\tint exitCode = application.exec();\n\n\tif(!guard.unlock())\n\t\tqCritical(\"%s\", guard.error().toLocal8Bit().data());\n\n\treturn exitCode;\n}\n"
  },
  {
    "path": "vsedit-job-server-watcher/src/connect_to_server_dialog.cpp",
    "content": "#include \"connect_to_server_dialog.h\"\n\n#include \"../../common-src/settings/settings_manager.h\"\n\n#include <QComboBox>\n\nConnectToServerDialog::ConnectToServerDialog(\n\tSettingsManager * a_pSettingsManager, QWidget * a_pParent) :\n\t  QDialog(a_pParent)\n\t, m_pSettingsManager(a_pSettingsManager)\n{\n\tQ_ASSERT(m_pSettingsManager);\n\tm_ui.setupUi(this);\n\n\tconnect(m_ui.connectButton, SIGNAL(clicked()),\n\t\tthis, SLOT(slotConnectButtonClicked()));\n\tconnect(m_ui.cancelButton, SIGNAL(clicked()), this, SLOT(reject()));\n}\n\nConnectToServerDialog::~ConnectToServerDialog()\n{\n}\n\nint ConnectToServerDialog::call(const QHostAddress & a_address)\n{\n\tm_ui.serverAddressComboBox->clear();\n\tQStringList recentServers = m_pSettingsManager->getRecentJobServers();\n\tm_ui.serverAddressComboBox->addItems(recentServers);\n\tm_ui.serverAddressComboBox->setCurrentText(a_address.toString());\n    return exec();\n}\n\nvoid ConnectToServerDialog::slotConnectButtonClicked()\n{\n\tQString address = m_ui.serverAddressComboBox->currentText();\n\tQHostAddress host(address);\n\tif(host.isNull())\n\t\treturn;\n\tint index = -1;\n\twhile((index = m_ui.serverAddressComboBox->findText(address)) >= 0)\n\t{\n\t\tm_ui.serverAddressComboBox->removeItem(index);\n\t}\n\tm_ui.serverAddressComboBox->insertItem(0, address);\n\tsaveServersList();\n\taccept();\n\temit signalConnectToServer(host);\n}\n\nvoid ConnectToServerDialog::saveServersList()\n{\n\tQStringList recentServers;\n\tfor(int i = 0; i < m_ui.serverAddressComboBox->count(); ++i)\n\t{\n\t\tQString address = m_ui.serverAddressComboBox->itemText(i);\n\t\tif(QHostAddress(address).isNull())\n\t\t\tcontinue;\n\t\trecentServers << address;\n\t}\n\tm_pSettingsManager->setRecentJobServers(recentServers);\n}\n"
  },
  {
    "path": "vsedit-job-server-watcher/src/connect_to_server_dialog.h",
    "content": "#ifndef CONNECT_TO_SERVER_DIALOG_H_INCLUDED\n#define CONNECT_TO_SERVER_DIALOG_H_INCLUDED\n\n#include <ui_connect_to_server_dialog.h>\n\n#include <QHostAddress>\n\nclass SettingsManager;\n\nclass ConnectToServerDialog : public QDialog\n{\n\tQ_OBJECT\n\npublic:\n\n\tConnectToServerDialog(SettingsManager * a_pSettingsManager,\n\t\tQWidget * a_pParent = nullptr);\n\tvirtual ~ConnectToServerDialog();\n\n\tint call(const QHostAddress & a_address);\n\nsignals:\n\n\tvoid signalConnectToServer(const QHostAddress & a_address);\n\nprivate slots:\n\n\tvoid slotConnectButtonClicked();\n\nprivate:\n\n\tvoid saveServersList();\n\n\tUi::ConnectToServerDialog m_ui;\n\n\tSettingsManager * m_pSettingsManager;\n};\n\n#endif // CONNECT_TO_SERVER_DIALOG_H_INCLUDED\n"
  },
  {
    "path": "vsedit-job-server-watcher/src/connect_to_server_dialog.ui",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<ui version=\"4.0\">\n <class>ConnectToServerDialog</class>\n <widget class=\"QDialog\" name=\"ConnectToServerDialog\">\n  <property name=\"geometry\">\n   <rect>\n    <x>0</x>\n    <y>0</y>\n    <width>462</width>\n    <height>67</height>\n   </rect>\n  </property>\n  <property name=\"windowTitle\">\n   <string>Connect to server</string>\n  </property>\n  <property name=\"windowIcon\">\n   <iconset resource=\"../../resources/vsedit-job-server-watcher.qrc\">\n    <normaloff>:/link.png</normaloff>:/link.png</iconset>\n  </property>\n  <layout class=\"QGridLayout\" name=\"gridLayout\" rowstretch=\"1,1\" columnstretch=\"1,0\">\n   <property name=\"leftMargin\">\n    <number>4</number>\n   </property>\n   <property name=\"topMargin\">\n    <number>4</number>\n   </property>\n   <property name=\"rightMargin\">\n    <number>4</number>\n   </property>\n   <property name=\"bottomMargin\">\n    <number>4</number>\n   </property>\n   <property name=\"spacing\">\n    <number>4</number>\n   </property>\n   <item row=\"0\" column=\"0\">\n    <widget class=\"QLabel\" name=\"label\">\n     <property name=\"text\">\n      <string>Server address:</string>\n     </property>\n    </widget>\n   </item>\n   <item row=\"0\" column=\"1\">\n    <widget class=\"QPushButton\" name=\"connectButton\">\n     <property name=\"sizePolicy\">\n      <sizepolicy hsizetype=\"Minimum\" vsizetype=\"Expanding\">\n       <horstretch>0</horstretch>\n       <verstretch>0</verstretch>\n      </sizepolicy>\n     </property>\n     <property name=\"text\">\n      <string>Connect</string>\n     </property>\n    </widget>\n   </item>\n   <item row=\"1\" column=\"0\">\n    <widget class=\"QComboBox\" name=\"serverAddressComboBox\">\n     <property name=\"editable\">\n      <bool>true</bool>\n     </property>\n     <property name=\"insertPolicy\">\n      <enum>QComboBox::InsertAtTop</enum>\n     </property>\n    </widget>\n   </item>\n   <item row=\"1\" column=\"1\">\n    <widget class=\"QPushButton\" name=\"cancelButton\">\n     <property name=\"sizePolicy\">\n      <sizepolicy hsizetype=\"Minimum\" vsizetype=\"Expanding\">\n       <horstretch>0</horstretch>\n       <verstretch>0</verstretch>\n      </sizepolicy>\n     </property>\n     <property name=\"text\">\n      <string>Cancel</string>\n     </property>\n     <property name=\"default\">\n      <bool>true</bool>\n     </property>\n    </widget>\n   </item>\n  </layout>\n </widget>\n <resources>\n  <include location=\"../../resources/vsedit-job-server-watcher.qrc\"/>\n </resources>\n <connections/>\n</ui>\n"
  },
  {
    "path": "vsedit-job-server-watcher/src/jobs/job_dependencies_delegate.cpp",
    "content": "#include \"job_dependencies_delegate.h\"\n\n#include \"jobs_model.h\"\n\n#include \"../../../common-src/helpers.h\"\n\n#include <QListWidget>\n#include <QTableView>\n#include <QHeaderView>\n\n//==============================================================================\n\nJobDependenciesDelegate::JobDependenciesDelegate(QObject * a_pParent) :\n\tQStyledItemDelegate(a_pParent)\n{\n}\n\n// END OF JobDependenciesDelegate::JobDependenciesDelegate(QObject * a_pParent)\n//==============================================================================\n\nJobDependenciesDelegate::~JobDependenciesDelegate()\n{\n}\n\n// END OF JobDependenciesDelegate::~JobDependenciesDelegate()\n//==============================================================================\n\nQWidget * JobDependenciesDelegate::createEditor(QWidget * a_pParent,\n\tconst QStyleOptionViewItem & a_option,\n\tconst QModelIndex & a_index) const\n{\n\t(void)a_pParent;\n\t(void)a_option;\n\t(void)a_index;\n\tQListWidget * pListWidget = new QListWidget();\n\tpListWidget->setWindowFlags(Qt::FramelessWindowHint);\n\treturn pListWidget;\n}\n\n// END OF QWidget * JobDependenciesDelegate::createEditor(QWidget * a_pParent,\n//\t\tconst QStyleOptionViewItem & a_option,\n//\t\tconst QModelIndex & a_index) const\n//==============================================================================\n\nvoid JobDependenciesDelegate::setEditorData(QWidget * a_pEditor,\n\tconst QModelIndex & a_index) const\n{\n\tQListWidget * pListWidget = qobject_cast<QListWidget *>(a_pEditor);\n\tif(!pListWidget)\n\t\treturn;\n\n\tconst JobsModel * cpModel =\n\t\tqobject_cast<const JobsModel *>(a_index.model());\n\tif(!cpModel)\n\t\treturn;\n\n\tJobProperties properties = cpModel->jobProperties(a_index.row());\n\n\tstd::vector<QUuid> dependencyIds = properties.dependsOnJobIds;\n\n\tpListWidget->clear();\n\tfor(int i = 0; i < a_index.row(); ++i)\n\t{\n\t\tQString name = tr(\"Job %1\").arg(i + 1);\n\t\tQListWidgetItem * pItem = new QListWidgetItem(name, pListWidget);\n\t\tQUuid id = cpModel->jobProperties(i).id;\n\t\tpItem->setData(Qt::UserRole, id);\n\t\tpItem->setFlags(Qt::ItemIsEnabled | Qt::ItemIsEditable |\n\t\t\tQt::ItemIsUserCheckable);\n\t\tbool depends = vsedit::contains(dependencyIds, id);\n\t\tpItem->setCheckState(depends ? Qt::Checked : Qt::Unchecked);\n\t}\n}\n\n// END OF void JobDependenciesDelegate::setEditorData(QWidget * a_pEditor,\n//\t\tconst QModelIndex & a_index) const\n//==============================================================================\n\nvoid JobDependenciesDelegate::setModelData(QWidget * a_pEditor,\n\tQAbstractItemModel * a_pModel, const QModelIndex & a_index) const\n{\n\tQListWidget * pListWidget = qobject_cast<QListWidget *>(a_pEditor);\n\tif(!pListWidget)\n\t\treturn;\n\n\tJobsModel * pModel = qobject_cast<JobsModel *>(a_pModel);\n\tif(!pModel)\n\t\treturn;\n\n\tJobProperties properties = pModel->jobProperties(a_index.row());\n\n\tstd::vector<QUuid> dependencyIds;\n\n\tfor(int i = 0; i < pListWidget->count(); ++i)\n\t{\n\t\tQListWidgetItem * pItem = pListWidget->item(i);\n\t\tif(pItem->checkState() != Qt::Checked)\n\t\t\tcontinue;\n\t\tQUuid id = pItem->data(Qt::UserRole).toUuid();\n\t\tdependencyIds.push_back(id);\n\t}\n\n\tpModel->requestJobDependsOnIds(properties.id, dependencyIds);\n}\n\n// END OF void JobDependenciesDelegate::setModelData(QWidget * a_pEditor,\n//\t\tQAbstractItemModel * a_pModel, const QModelIndex & a_index) const\n//==============================================================================\n\nvoid JobDependenciesDelegate::updateEditorGeometry(QWidget * a_pEditor,\n\tconst QStyleOptionViewItem & a_option, const QModelIndex & a_index) const\n{\n\t(void)a_index;\n\tQListWidget * pListWidget = qobject_cast<QListWidget *>(a_pEditor);\n\tif(!pListWidget)\n\t\treturn;\n\tQPoint origin = a_option.widget->mapToGlobal(a_option.rect.topLeft());\n\tconst QTableView * cpTableView =\n\t\tqobject_cast<const QTableView *>(a_option.widget);\n\tif(cpTableView)\n\t{\n\t\tint headerWidth = 0;\n\t\tif(cpTableView->verticalHeader()->isVisible())\n\t\t\theaderWidth = cpTableView->verticalHeader()->width();\n\t\tint headerHeight = 0;\n\t\tif(cpTableView->horizontalHeader()->isVisible())\n\t\t\theaderHeight = cpTableView->horizontalHeader()->height();\n\t\torigin += QPoint(headerWidth, headerHeight);\n\t}\n\tpListWidget->move(origin);\n}\n\n// END OF void JobDependenciesDelegate::updateEditorGeometry(\n//\t\tQWidget * a_pEditor, const QStyleOptionViewItem & a_option,\n//\t\tconst QModelIndex & a_index) const\n//==============================================================================\n"
  },
  {
    "path": "vsedit-job-server-watcher/src/jobs/job_dependencies_delegate.h",
    "content": "#ifndef JOB_DEPENDENCIES_DELEGATE_H_INCLUDED\n#define JOB_DEPENDENCIES_DELEGATE_H_INCLUDED\n\n#include <QStyledItemDelegate>\n\nclass JobDependenciesDelegate : public QStyledItemDelegate\n{\n\tQ_OBJECT\n\npublic:\n\n\tJobDependenciesDelegate(QObject * a_pParent = nullptr);\n\tvirtual ~JobDependenciesDelegate();\n\n\tvirtual QWidget * createEditor(QWidget * a_pParent,\n\t\tconst QStyleOptionViewItem & a_option,\n\t\tconst QModelIndex & a_index) const override;\n\n\tvirtual void setEditorData(QWidget * a_pEditor,\n\t\tconst QModelIndex & a_index) const override;\n\n\tvirtual void setModelData(QWidget * a_pEditor,\n\t\tQAbstractItemModel * a_pModel, const QModelIndex & a_index)\n\t\tconst override;\n\n\tvirtual void updateEditorGeometry(QWidget * a_pEditor,\n\t\tconst QStyleOptionViewItem & a_option,\n\t\tconst QModelIndex & a_index) const override;\n\n};\n\n#endif // JOB_DEPENDENCIES_DELEGATE_H_INCLUDED\n"
  },
  {
    "path": "vsedit-job-server-watcher/src/jobs/job_edit_dialog.cpp",
    "content": "#include \"job_edit_dialog.h\"\n\n#include \"../../../common-src/settings/settings_manager.h\"\n#include \"../../../common-src/vapoursynth/vapoursynth_script_processor.h\"\n#include \"../../../common-src/jobs/job_variables.h\"\n#include \"../../../common-src/helpers.h\"\n\n#include <QMessageBox>\n#include <QFileDialog>\n#include <QFile>\n#include <map>\n#include <limits>\n\n//==============================================================================\n\nJobEditDialog::JobEditDialog(SettingsManager * a_pSettingsManager,\n\tVSScriptLibrary * a_pVSScriptLibrary, QWidget * a_pParent) :\n\t  QDialog(a_pParent,\n\t\t  Qt::Dialog\n\t\t| Qt::CustomizeWindowHint\n\t\t| Qt::WindowTitleHint\n\t\t| Qt::WindowMinimizeButtonHint\n\t\t| Qt::WindowMaximizeButtonHint\n\t\t| Qt::WindowCloseButtonHint)\n\t, m_pSettingsManager(a_pSettingsManager)\n\t, m_pVSScriptLibrary(a_pVSScriptLibrary)\n{\n\tvsedit::disableFontKerning(this);\n\tm_ui.setupUi(this);\n\n\tJobType jobTypes[] = {JobType::EncodeScriptCLI, JobType::RunProcess,\n\t\tJobType::RunShellCommand};\n\tfor(const JobType & jobType : jobTypes)\n\t\tm_ui.jobTypeComboBox->addItem(JobProperties::typeName(jobType),\n\t\t\t(int)jobType);\n\tm_ui.jobTypeComboBox->setCurrentIndex(0);\n\tslotJobTypeChanged(m_ui.jobTypeComboBox->currentIndex());\n\n\tm_ui.encodingHeaderTypeComboBox->addItem(tr(\"No header\"),\n\t\t(int)EncodingHeaderType::NoHeader);\n\tm_ui.encodingHeaderTypeComboBox->addItem(tr(\"Y4M\"),\n\t\t(int)EncodingHeaderType::Y4M);\n\n\tm_ui.encodingFirstFrameSpinBox->setMaximum(std::numeric_limits<int>::max());\n\tm_ui.encodingLastFrameSpinBox->setMaximum(std::numeric_limits<int>::max());\n\n\tsetUpEncodingPresets();\n\n\tconnect(m_ui.jobTypeComboBox, SIGNAL(currentIndexChanged(int)),\n\t\tthis, SLOT(slotJobTypeChanged(int)));\n\tconnect(m_ui.encodingScriptBrowseButton, SIGNAL(clicked()),\n\t\tthis, SLOT(slotEncodingScriptBrowseButtonClicked()));\n\tconnect(m_ui.encodingPresetComboBox, SIGNAL(textActivated(const QString &)),\n\t\tthis, SLOT(slotEncodingPresetComboBoxActivated(const QString &)));\n\tconnect(m_ui.encodingPresetSaveButton, SIGNAL(clicked()),\n\t\tthis, SLOT(slotEncodingPresetSaveButtonClicked()));\n\tconnect(m_ui.encodingPresetDeleteButton, SIGNAL(clicked()),\n\t\tthis, SLOT(slotEncodingPresetDeleteButton()));\n\tconnect(m_ui.encodingExecutableBrowseButton, SIGNAL(clicked()),\n\t\tthis, SLOT(slotEncodingExecutableBrowseButtonClicked()));\n\tconnect(m_ui.encodingArgumentsHelpButton, SIGNAL(clicked()),\n\t\tthis, SLOT(slotEncodingArgumentsHelpButtonClicked()));\n\tconnect(m_ui.encodingFramesFromVideoButton, SIGNAL(clicked()),\n\t\tthis, SLOT(slotEncodingFramesFromVideoButtonClicked()));\n\tconnect(m_ui.processExecutableBrowseButton, SIGNAL(clicked()),\n\t\tthis, SLOT(slotProcessExecutableBrowseButtonClicked()));\n\tconnect(m_ui.jobSaveButton, SIGNAL(clicked()), this, SLOT(accept()));\n\tconnect(m_ui.cancelButton, SIGNAL(clicked()), this, SLOT(reject()));\n}\n\n// END OF JobEditDialog::JobEditDialog(SettingsManager * a_pSettingsManager,\n//\t\tQWidget * a_pParent)\n//==============================================================================\n\nJobEditDialog::~JobEditDialog()\n{\n}\n\n// END OF JobEditDialog::~JobEditDialog()\n//==============================================================================\n\nJobProperties JobEditDialog::jobProperties() const\n{\n\tJobProperties newProperties;\n\tnewProperties.type = (JobType)m_ui.jobTypeComboBox->currentData().toInt();\n\tnewProperties.scriptName = m_ui.encodingScriptPathEdit->text();\n\tnewProperties.encodingHeaderType = (EncodingHeaderType)m_ui\n\t\t.encodingHeaderTypeComboBox->currentData().toInt();\n\tif(newProperties.type == JobType::EncodeScriptCLI)\n\t{\n\t\tnewProperties.executablePath = m_ui.encodingExecutablePathEdit->text();\n\t\tnewProperties.arguments = m_ui.encodingArgumentsTextEdit->toPlainText();\n\t}\n\telse if(newProperties.type == JobType::RunProcess)\n\t{\n\t\tnewProperties.executablePath = m_ui.processExecutablePathEdit->text();\n\t\tnewProperties.arguments = m_ui.processArgumentsTextEdit->toPlainText();\n\t}\n\tnewProperties.shellCommand = m_ui.shellCommandTextEdit->toPlainText();\n\tnewProperties.firstFrame = m_ui.encodingFirstFrameSpinBox->value();\n\tnewProperties.lastFrame = m_ui.encodingLastFrameSpinBox->value();\n\treturn newProperties;\n}\n\n// END OF JobProperties JobEditDialog::jobProperties() const\n//==============================================================================\n\nint JobEditDialog::call(const QString & a_title,\n\tconst JobProperties & a_jobProperties)\n{\n\tsetUpEncodingPresets();\n\tsetWindowTitle(a_title);\n\n\tint index = m_ui.jobTypeComboBox->findData((int)a_jobProperties.type);\n\tm_ui.jobTypeComboBox->setCurrentIndex(index);\n\tm_ui.encodingScriptPathEdit->setText(a_jobProperties.scriptName);\n\tm_ui.encodingPresetComboBox->clearEditText();\n\tindex = m_ui.encodingHeaderTypeComboBox->findData(\n\t\t(int)a_jobProperties.encodingHeaderType);\n\tm_ui.encodingHeaderTypeComboBox->setCurrentIndex(index);\n\tm_ui.encodingExecutablePathEdit->setText(a_jobProperties.executablePath);\n\tm_ui.encodingArgumentsTextEdit->setPlainText(a_jobProperties.arguments);\n\tm_ui.processExecutablePathEdit->setText(a_jobProperties.executablePath);\n\tm_ui.processArgumentsTextEdit->setPlainText(a_jobProperties.arguments);\n\tm_ui.shellCommandTextEdit->setPlainText(a_jobProperties.shellCommand);\n\n\tm_ui.encodingFirstFrameSpinBox->setValue(a_jobProperties.firstFrame);\n\tm_ui.encodingLastFrameSpinBox->setValue(a_jobProperties.lastFrame);\n\n\treturn exec();\n}\n\n// END OF int JobEditDialog::call(const QString & a_title,\n//\t\tconst JobProperties & a_jobProperties)\n//==============================================================================\n\nvoid JobEditDialog::slotJobTypeChanged(int a_index)\n{\n\tstd::map<JobType, QWidget *> panels =\n\t{\n\t\t{JobType::EncodeScriptCLI, m_ui.encodingPanel},\n\t\t{JobType::RunProcess, m_ui.processPanel},\n\t\t{JobType::RunShellCommand, m_ui.shellCommandPanel},\n\t};\n\n\tJobType jobType = (JobType)m_ui.jobTypeComboBox->itemData(a_index).toInt();\n\n\tfor(const std::pair<const JobType, QWidget *> & pair : panels)\n\t{\n\t\tif(pair.first == jobType)\n\t\t\tpair.second->setVisible(true);\n\t\telse\n\t\t\tpair.second->setVisible(false);\n\t}\n}\n\n// END OF void JobEditDialog::slotJobTypeChanged(int a_index)\n//==============================================================================\n\nvoid JobEditDialog::slotEncodingScriptBrowseButtonClicked()\n{\n\tQFileDialog fileDialog(this);\n\tfileDialog.setWindowTitle(tr(\"Open VapourSynth script\"));\n\tfileDialog.setNameFilter(\n\t\ttr(\"VapourSynth script (*.vpy);;All files (*)\"));\n\n\tQString path = m_ui.encodingScriptPathEdit->text();\n\tif(path.isEmpty())\n\t\tpath = m_pSettingsManager->getLastUsedPath();\n\tQFileInfo fileInfo(path);\n\tQString dirPath = fileInfo.absoluteDir().path();\n\tfileDialog.setDirectory(dirPath);\n\tfileDialog.selectFile(fileInfo.fileName());\n\n\tif(!fileDialog.exec())\n\t\treturn;\n\n\tQStringList filesList = fileDialog.selectedFiles();\n\tm_ui.encodingScriptPathEdit->setText(filesList[0]);\n\tm_pSettingsManager->setLastUsedPath(filesList[0]);\n}\n\n// END OF void JobEditDialog::slotEncodingScriptBrowseButtonClicked()\n//==============================================================================\n\nvoid JobEditDialog::slotEncodingPresetComboBoxActivated(const QString & a_text)\n{\n\tif(a_text.isEmpty())\n\t{\n\t\tm_ui.encodingExecutablePathEdit->clear();\n\t\tm_ui.encodingArgumentsTextEdit->clear();\n\t\treturn;\n\t}\n\n\tEncodingPreset preset(a_text);\n\n\tstd::vector<EncodingPreset>::iterator it = std::find(\n\t\tm_encodingPresets.begin(), m_encodingPresets.end(), preset);\n\tif(it == m_encodingPresets.end())\n\t\treturn;\n\n\tpreset = *it;\n\n\tm_ui.encodingExecutablePathEdit->setText(preset.executablePath);\n\tm_ui.encodingArgumentsTextEdit->setPlainText(preset.arguments);\n\n\tint headerTypeIndex =\n\t\tm_ui.encodingHeaderTypeComboBox->findData((int)preset.headerType);\n\tif(headerTypeIndex < 0)\n\t\theaderTypeIndex = 0;\n\tm_ui.encodingHeaderTypeComboBox->setCurrentIndex(headerTypeIndex);\n}\n\n// END OF void JobEditDialog::slotEncodingPresetComboBoxActivated(\n//\t\tconst QString & a_text)\n//==============================================================================\n\nvoid JobEditDialog::slotEncodingPresetSaveButtonClicked()\n{\n\tEncodingPreset preset(m_ui.encodingPresetComboBox->currentText());\n\tif(preset.name.isEmpty())\n\t{\n\t\tQMessageBox::warning(this, tr(\"Preset save error.\"),\n\t\t\ttr(\"Preset name must not be empty.\"));\n\t\treturn;\n\t}\n\n\tif(preset.type == EncodingType::CLI)\n\t{\n\t\tpreset.executablePath = m_ui.encodingExecutablePathEdit->text();\n\t\tif(preset.executablePath.isEmpty())\n\t\t{\n\t\t\tQMessageBox::warning(this, tr(\"Preset save error.\"),\n\t\t\t\ttr(\"Executable path must not be empty.\"));\n\t\t\treturn;\n\t\t}\n\n\t\tpreset.arguments = m_ui.encodingArgumentsTextEdit->toPlainText();\n\t}\n\n\tpreset.headerType = (EncodingHeaderType)\n\t\tm_ui.encodingHeaderTypeComboBox->currentData().toInt();\n\n\tbool success = m_pSettingsManager->saveEncodingPreset(preset);\n\tif(!success)\n\t{\n\t\tQMessageBox::critical(this, tr(\"Preset save error.\"),\n\t\t\ttr(\"Error saving encoding preset.\"));\n\t\treturn;\n\t}\n\n\tstd::vector<EncodingPreset>::iterator it = std::find(\n\t\tm_encodingPresets.begin(), m_encodingPresets.end(), preset);\n\tif(it == m_encodingPresets.end())\n\t{\n\t\tQ_ASSERT(m_ui.encodingPresetComboBox->findText(preset.name) == -1);\n\t\tm_encodingPresets.push_back(preset);\n\t\tm_ui.encodingPresetComboBox->addItem(preset.name);\n\t\tm_ui.encodingPresetComboBox->model()->sort(0);\n\t}\n\telse\n\t{\n\t\tQ_ASSERT(m_ui.encodingPresetComboBox->findText(preset.name) != -1);\n\t\t*it = preset;\n\t}\n}\n\n// END OF void JobEditDialog::slotEncodingPresetSaveButtonClicked()\n//==============================================================================\n\nvoid JobEditDialog::slotEncodingPresetDeleteButton()\n{\n\tEncodingPreset preset(m_ui.encodingPresetComboBox->currentText());\n\tif(preset.name.isEmpty())\n\t\treturn;\n\n\tQMessageBox quesBox(this);\n\tvsedit::disableFontKerning(&quesBox);\n\tquesBox.setWindowTitle(tr(\"Delete preset\"));\n\tquesBox.setText(tr(\"Do you really want to delete \"\n\t\t\"preset \\'%1\\'?\").arg(preset.name));\n\tquesBox.setStandardButtons(QMessageBox::Yes | QMessageBox::No);\n\tquesBox.setDefaultButton(QMessageBox::No);\n\tint result = quesBox.exec();\n\tif(result == QMessageBox::No)\n\t\treturn;\n\n\tstd::vector<EncodingPreset>::iterator it = std::find(\n\t\tm_encodingPresets.begin(), m_encodingPresets.end(), preset);\n\tif(it == m_encodingPresets.end())\n\t{\n\t\tQ_ASSERT(m_ui.encodingPresetComboBox->findText(preset.name) == -1);\n\t\tQMessageBox::critical(this, tr(\"Preset delete error.\"),\n\t\t\ttr(\"Error deleting preset. Preset was never saved.\"));\n\t\treturn;\n\t}\n\n\tint index = m_ui.encodingPresetComboBox->findText(preset.name);\n\tQ_ASSERT(index != -1);\n\tm_ui.encodingPresetComboBox->removeItem(index);\n\tm_encodingPresets.erase(it);\n\tm_ui.encodingPresetComboBox->setCurrentIndex(0);\n\tslotEncodingPresetComboBoxActivated(\n\t\tm_ui.encodingPresetComboBox->currentText());\n\n\tbool success = m_pSettingsManager->deleteEncodingPreset(preset.name);\n\tif(!success)\n\t{\n\t\tQMessageBox::critical(this, tr(\"Preset delete error.\"),\n\t\t\ttr(\"Error deleting preset \\'%1\\'.\").arg(preset.name));\n\t\treturn;\n\t}\n}\n\n// END OF void JobEditDialog::slotEncodingPresetDeleteButton()\n//==============================================================================\n\nvoid JobEditDialog::slotEncodingExecutableBrowseButtonClicked()\n{\n\tQString executablePath = chooseExecutable(\n\t\ttr(\"Choose encoder executable\"),\n\t\tm_ui.encodingExecutablePathEdit->text());\n\n\tif(!executablePath.isEmpty())\n\t\tm_ui.encodingExecutablePathEdit->setText(executablePath);\n}\n\n// END OF void JobEditDialog::slotEncodingExecutableBrowseButtonClicked()\n//==============================================================================\n\nvoid JobEditDialog::slotEncodingFramesFromVideoButtonClicked()\n{\n\tQString scriptName = m_ui.encodingScriptPathEdit->text();\n\tQString absoluteScriptPath =\n\t\tvsedit::resolvePathFromApplication(scriptName);\n\tQFile scriptFile(absoluteScriptPath);\n\tbool opened = scriptFile.open(QIODevice::ReadOnly);\n\tif(!opened)\n\t\treturn;\n\n\tQString script = QString::fromUtf8(scriptFile.readAll());\n\tscriptFile.close();\n\n\tVapourSynthScriptProcessor processor(m_pSettingsManager,\n\t\tm_pVSScriptLibrary);\n\tbool initialized = processor.initialize(script, scriptName, 0,\n\t\tProcessReason::Encode);\n\tif(!initialized)\n\t\treturn;\n\n\tconst VSVideoInfo * cpVideoInfo = processor.nodeInfo().getAsVideo();\n\tm_ui.encodingFirstFrameSpinBox->setValue(0);\n\tm_ui.encodingLastFrameSpinBox->setValue(cpVideoInfo->numFrames - 1);\n}\n\n// END OF void JobEditDialog::slotEncodingFramesFromVideoButtonClicked()\n//==============================================================================\n\nvoid JobEditDialog::slotEncodingArgumentsHelpButtonClicked()\n{\n\tJobVariables variables;\n\tQString argumentsHelpString = tr(\"Use following placeholders:\");\n\tfor(const vsedit::VariableToken & variable : variables.variables())\n\t{\n\t\targumentsHelpString += QString(\"\\n%1 - %2\")\n\t\t\t.arg(variable.token).arg(variable.description);\n\t}\n\tQString title = tr(\"Encoder arguments\");\n\tQMessageBox msgBox(this);\n\tmsgBox.setWindowTitle(title);\n\tmsgBox.setText(argumentsHelpString);\n\tvsedit::disableFontKerning(&msgBox);\n\tmsgBox.exec();\n}\n\n// END OF void JobEditDialog::slotEncodingArgumentsHelpButtonClicked()\n//==============================================================================\n\nvoid JobEditDialog::slotProcessExecutableBrowseButtonClicked()\n{\n\tQString executablePath = chooseExecutable(\n\t\ttr(\"Choose process executable\"),\n\t\tm_ui.processExecutablePathEdit->text());\n\n\tif(!executablePath.isEmpty())\n\t\tm_ui.processExecutablePathEdit->setText(executablePath);\n}\n\n// END OF void JobEditDialog::slotProcessExecutableBrowseButtonClicked()\n//==============================================================================\n\nvoid JobEditDialog::setUpEncodingPresets()\n{\n\tm_ui.encodingPresetComboBox->clear();\n\n\tm_encodingPresets = m_pSettingsManager->getAllEncodingPresets();\n\tfor(const EncodingPreset & preset : m_encodingPresets)\n\t\tm_ui.encodingPresetComboBox->addItem(preset.name);\n\n\tm_ui.encodingPresetComboBox->setCurrentIndex(0);\n\tslotEncodingPresetComboBoxActivated(\n\t\tm_ui.encodingPresetComboBox->currentText());\n}\n\n// END OF void JobEditDialog::setUpEncodingPresets()\n//==============================================================================\n\nQString JobEditDialog::chooseExecutable(const QString & a_dialogTitle,\n\tconst QString & a_initialPath)\n{\n\tQString applicationPath = QCoreApplication::applicationDirPath();\n\n\tQFileDialog fileDialog;\n\tfileDialog.setWindowTitle(a_dialogTitle);\n\tif(a_initialPath.isEmpty())\n\t\tfileDialog.setDirectory(applicationPath);\n\telse\n\t\tfileDialog.selectFile(a_initialPath);\n\n#ifdef Q_OS_WIN\n\tfileDialog.setNameFilter(\"*.exe\");\n#endif\n\n\tif(!fileDialog.exec())\n\t\treturn QString();\n\n\tQStringList filesList = fileDialog.selectedFiles();\n\treturn filesList[0];\n}\n\n// END OF QString JobEditDialog::chooseExecutable(const QString & a_dialogTitle,\n//\t\tconst QString & a_initialPath)\n//==============================================================================\n"
  },
  {
    "path": "vsedit-job-server-watcher/src/jobs/job_edit_dialog.h",
    "content": "#ifndef JOB_EDIT_DIALOG_H_INCLUDED\n#define JOB_EDIT_DIALOG_H_INCLUDED\n\n#include <ui_job_edit_dialog.h>\n\n#include \"../../../common-src/settings/settings_definitions_core.h\"\n\nclass SettingsManager;\nclass VSScriptLibrary;\n\nclass JobEditDialog : public QDialog\n{\n\tQ_OBJECT\n\npublic:\n\n\tJobEditDialog(SettingsManager * a_pSettingsManager,\n\t\tVSScriptLibrary * a_pVSScriptLibrary, QWidget * a_pParent = nullptr);\n\n\tvirtual ~JobEditDialog();\n\n\tJobProperties jobProperties() const;\n\npublic slots:\n\n\tint call(const QString & a_title, const JobProperties & a_jobProperties);\n\nprivate slots:\n\n\tvoid slotJobTypeChanged(int a_index);\n\tvoid slotEncodingScriptBrowseButtonClicked();\n\tvoid slotEncodingPresetComboBoxActivated(const QString & a_text);\n\tvoid slotEncodingPresetSaveButtonClicked();\n\tvoid slotEncodingPresetDeleteButton();\n\tvoid slotEncodingExecutableBrowseButtonClicked();\n\tvoid slotEncodingFramesFromVideoButtonClicked();\n\tvoid slotEncodingArgumentsHelpButtonClicked();\n\tvoid slotProcessExecutableBrowseButtonClicked();\n\nprivate:\n\n\tvoid setUpEncodingPresets();\n\n\tQString chooseExecutable(const QString & a_dialogTitle,\n\t\tconst QString & a_initialPath = QString());\n\n\tUi::JobEditDialog m_ui;\n\n\tSettingsManager * m_pSettingsManager;\n\tVSScriptLibrary * m_pVSScriptLibrary;\n\n\tstd::vector<EncodingPreset> m_encodingPresets;\n};\n\n#endif // JOB_EDIT_DIALOG_H_INCLUDED\n"
  },
  {
    "path": "vsedit-job-server-watcher/src/jobs/job_edit_dialog.ui",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<ui version=\"4.0\">\n <class>JobEditDialog</class>\n <widget class=\"QDialog\" name=\"JobEditDialog\">\n  <property name=\"geometry\">\n   <rect>\n    <x>0</x>\n    <y>0</y>\n    <width>566</width>\n    <height>466</height>\n   </rect>\n  </property>\n  <property name=\"windowIcon\">\n   <iconset resource=\"../../resources/resources.qrc\">\n    <normaloff>:/jobs.png</normaloff>:/jobs.png</iconset>\n  </property>\n  <layout class=\"QVBoxLayout\" name=\"verticalLayout_4\">\n   <property name=\"spacing\">\n    <number>4</number>\n   </property>\n   <property name=\"leftMargin\">\n    <number>4</number>\n   </property>\n   <property name=\"topMargin\">\n    <number>4</number>\n   </property>\n   <property name=\"rightMargin\">\n    <number>4</number>\n   </property>\n   <property name=\"bottomMargin\">\n    <number>4</number>\n   </property>\n   <item>\n    <layout class=\"QHBoxLayout\" name=\"horizontalLayout\">\n     <property name=\"spacing\">\n      <number>4</number>\n     </property>\n     <item>\n      <widget class=\"QLabel\" name=\"label\">\n       <property name=\"text\">\n        <string>Job type:</string>\n       </property>\n      </widget>\n     </item>\n     <item>\n      <widget class=\"QComboBox\" name=\"jobTypeComboBox\"/>\n     </item>\n     <item>\n      <spacer name=\"horizontalSpacer\">\n       <property name=\"orientation\">\n        <enum>Qt::Horizontal</enum>\n       </property>\n       <property name=\"sizeHint\" stdset=\"0\">\n        <size>\n         <width>40</width>\n         <height>20</height>\n        </size>\n       </property>\n      </spacer>\n     </item>\n    </layout>\n   </item>\n   <item>\n    <widget class=\"QWidget\" name=\"encodingPanel\" native=\"true\">\n     <layout class=\"QVBoxLayout\" name=\"verticalLayout\">\n      <property name=\"spacing\">\n       <number>2</number>\n      </property>\n      <property name=\"leftMargin\">\n       <number>0</number>\n      </property>\n      <property name=\"topMargin\">\n       <number>0</number>\n      </property>\n      <property name=\"rightMargin\">\n       <number>0</number>\n      </property>\n      <property name=\"bottomMargin\">\n       <number>0</number>\n      </property>\n      <item>\n       <layout class=\"QHBoxLayout\" name=\"horizontalLayout_2\">\n        <property name=\"spacing\">\n         <number>4</number>\n        </property>\n        <item>\n         <widget class=\"QLabel\" name=\"label_8\">\n          <property name=\"text\">\n           <string>Script file:</string>\n          </property>\n         </widget>\n        </item>\n        <item>\n         <widget class=\"QLineEdit\" name=\"encodingScriptPathEdit\"/>\n        </item>\n        <item>\n         <widget class=\"QToolButton\" name=\"encodingScriptBrowseButton\">\n          <property name=\"text\">\n           <string/>\n          </property>\n          <property name=\"icon\">\n           <iconset resource=\"../../resources/resources.qrc\">\n            <normaloff>:/folder.png</normaloff>:/folder.png</iconset>\n          </property>\n         </widget>\n        </item>\n       </layout>\n      </item>\n      <item>\n       <layout class=\"QHBoxLayout\" name=\"horizontalLayout_8\">\n        <property name=\"spacing\">\n         <number>4</number>\n        </property>\n        <item>\n         <widget class=\"QLabel\" name=\"encodingPresetLabel\">\n          <property name=\"text\">\n           <string>Preset:</string>\n          </property>\n         </widget>\n        </item>\n        <item>\n         <widget class=\"QComboBox\" name=\"encodingPresetComboBox\">\n          <property name=\"sizePolicy\">\n           <sizepolicy hsizetype=\"Expanding\" vsizetype=\"Fixed\">\n            <horstretch>0</horstretch>\n            <verstretch>0</verstretch>\n           </sizepolicy>\n          </property>\n          <property name=\"editable\">\n           <bool>true</bool>\n          </property>\n          <property name=\"insertPolicy\">\n           <enum>QComboBox::NoInsert</enum>\n          </property>\n         </widget>\n        </item>\n        <item>\n         <widget class=\"QPushButton\" name=\"encodingPresetSaveButton\">\n          <property name=\"text\">\n           <string>Save</string>\n          </property>\n         </widget>\n        </item>\n        <item>\n         <widget class=\"QPushButton\" name=\"encodingPresetDeleteButton\">\n          <property name=\"text\">\n           <string>Delete</string>\n          </property>\n         </widget>\n        </item>\n       </layout>\n      </item>\n      <item>\n       <layout class=\"QHBoxLayout\" name=\"horizontalLayout_5\">\n        <property name=\"spacing\">\n         <number>4</number>\n        </property>\n        <item>\n         <widget class=\"QLabel\" name=\"label_5\">\n          <property name=\"text\">\n           <string>Header:</string>\n          </property>\n         </widget>\n        </item>\n        <item>\n         <widget class=\"QComboBox\" name=\"encodingHeaderTypeComboBox\">\n          <property name=\"sizeAdjustPolicy\">\n           <enum>QComboBox::AdjustToContents</enum>\n          </property>\n         </widget>\n        </item>\n        <item>\n         <widget class=\"QLabel\" name=\"label_6\">\n          <property name=\"text\">\n           <string>Executable:</string>\n          </property>\n         </widget>\n        </item>\n        <item>\n         <widget class=\"QLineEdit\" name=\"encodingExecutablePathEdit\">\n          <property name=\"text\">\n           <string/>\n          </property>\n         </widget>\n        </item>\n        <item>\n         <widget class=\"QToolButton\" name=\"encodingExecutableBrowseButton\">\n          <property name=\"text\">\n           <string/>\n          </property>\n          <property name=\"icon\">\n           <iconset resource=\"../../resources/resources.qrc\">\n            <normaloff>:/folder.png</normaloff>:/folder.png</iconset>\n          </property>\n         </widget>\n        </item>\n       </layout>\n      </item>\n      <item>\n       <layout class=\"QHBoxLayout\" name=\"horizontalLayout_7\">\n        <property name=\"spacing\">\n         <number>4</number>\n        </property>\n        <item>\n         <widget class=\"QLabel\" name=\"label_7\">\n          <property name=\"text\">\n           <string>Arguments (newlines will be replaced with spaces):</string>\n          </property>\n         </widget>\n        </item>\n        <item>\n         <widget class=\"QToolButton\" name=\"encodingArgumentsHelpButton\">\n          <property name=\"text\">\n           <string/>\n          </property>\n          <property name=\"icon\">\n           <iconset resource=\"../../resources/resources.qrc\">\n            <normaloff>:/information.png</normaloff>:/information.png</iconset>\n          </property>\n         </widget>\n        </item>\n        <item>\n         <spacer name=\"horizontalSpacer_4\">\n          <property name=\"orientation\">\n           <enum>Qt::Horizontal</enum>\n          </property>\n          <property name=\"sizeHint\" stdset=\"0\">\n           <size>\n            <width>40</width>\n            <height>20</height>\n           </size>\n          </property>\n         </spacer>\n        </item>\n       </layout>\n      </item>\n      <item>\n       <widget class=\"QPlainTextEdit\" name=\"encodingArgumentsTextEdit\">\n        <property name=\"plainText\">\n         <string/>\n        </property>\n       </widget>\n      </item>\n      <item>\n       <layout class=\"QHBoxLayout\" name=\"horizontalLayout_6\">\n        <property name=\"spacing\">\n         <number>4</number>\n        </property>\n        <item>\n         <widget class=\"QLabel\" name=\"label_2\">\n          <property name=\"text\">\n           <string>Frames from</string>\n          </property>\n         </widget>\n        </item>\n        <item>\n         <widget class=\"QSpinBox\" name=\"encodingFirstFrameSpinBox\">\n          <property name=\"specialValueText\">\n           <string>Min</string>\n          </property>\n          <property name=\"minimum\">\n           <number>-1</number>\n          </property>\n         </widget>\n        </item>\n        <item>\n         <widget class=\"QLabel\" name=\"label_3\">\n          <property name=\"text\">\n           <string>to</string>\n          </property>\n         </widget>\n        </item>\n        <item>\n         <widget class=\"QSpinBox\" name=\"encodingLastFrameSpinBox\">\n          <property name=\"specialValueText\">\n           <string>Max</string>\n          </property>\n          <property name=\"minimum\">\n           <number>-1</number>\n          </property>\n         </widget>\n        </item>\n        <item>\n         <widget class=\"QPushButton\" name=\"encodingFramesFromVideoButton\">\n          <property name=\"text\">\n           <string>From video</string>\n          </property>\n         </widget>\n        </item>\n        <item>\n         <spacer name=\"horizontalSpacer_3\">\n          <property name=\"orientation\">\n           <enum>Qt::Horizontal</enum>\n          </property>\n          <property name=\"sizeHint\" stdset=\"0\">\n           <size>\n            <width>40</width>\n            <height>20</height>\n           </size>\n          </property>\n         </spacer>\n        </item>\n       </layout>\n      </item>\n     </layout>\n    </widget>\n   </item>\n   <item>\n    <widget class=\"QWidget\" name=\"processPanel\" native=\"true\">\n     <layout class=\"QVBoxLayout\" name=\"verticalLayout_2\">\n      <property name=\"spacing\">\n       <number>4</number>\n      </property>\n      <property name=\"leftMargin\">\n       <number>0</number>\n      </property>\n      <property name=\"topMargin\">\n       <number>0</number>\n      </property>\n      <property name=\"rightMargin\">\n       <number>0</number>\n      </property>\n      <property name=\"bottomMargin\">\n       <number>0</number>\n      </property>\n      <item>\n       <layout class=\"QHBoxLayout\" name=\"horizontalLayout_3\">\n        <property name=\"spacing\">\n         <number>4</number>\n        </property>\n        <item>\n         <widget class=\"QLabel\" name=\"label_9\">\n          <property name=\"text\">\n           <string>Executable:</string>\n          </property>\n         </widget>\n        </item>\n        <item>\n         <widget class=\"QLineEdit\" name=\"processExecutablePathEdit\">\n          <property name=\"text\">\n           <string/>\n          </property>\n         </widget>\n        </item>\n        <item>\n         <widget class=\"QToolButton\" name=\"processExecutableBrowseButton\">\n          <property name=\"text\">\n           <string/>\n          </property>\n          <property name=\"icon\">\n           <iconset resource=\"../../resources/resources.qrc\">\n            <normaloff>:/folder.png</normaloff>:/folder.png</iconset>\n          </property>\n         </widget>\n        </item>\n       </layout>\n      </item>\n      <item>\n       <widget class=\"QLabel\" name=\"label_10\">\n        <property name=\"text\">\n         <string>Arguments (newlines will be replaced with spaces):</string>\n        </property>\n       </widget>\n      </item>\n      <item>\n       <widget class=\"QPlainTextEdit\" name=\"processArgumentsTextEdit\">\n        <property name=\"plainText\">\n         <string/>\n        </property>\n       </widget>\n      </item>\n     </layout>\n    </widget>\n   </item>\n   <item>\n    <widget class=\"QWidget\" name=\"shellCommandPanel\" native=\"true\">\n     <layout class=\"QVBoxLayout\" name=\"verticalLayout_3\">\n      <property name=\"spacing\">\n       <number>4</number>\n      </property>\n      <property name=\"leftMargin\">\n       <number>0</number>\n      </property>\n      <property name=\"topMargin\">\n       <number>0</number>\n      </property>\n      <property name=\"rightMargin\">\n       <number>0</number>\n      </property>\n      <property name=\"bottomMargin\">\n       <number>0</number>\n      </property>\n      <item>\n       <widget class=\"QLabel\" name=\"label_11\">\n        <property name=\"text\">\n         <string>Shell command (newlines will be replaced with spaces):</string>\n        </property>\n       </widget>\n      </item>\n      <item>\n       <widget class=\"QPlainTextEdit\" name=\"shellCommandTextEdit\">\n        <property name=\"plainText\">\n         <string/>\n        </property>\n       </widget>\n      </item>\n     </layout>\n    </widget>\n   </item>\n   <item>\n    <layout class=\"QHBoxLayout\" name=\"horizontalLayout_4\">\n     <property name=\"spacing\">\n      <number>4</number>\n     </property>\n     <item>\n      <spacer name=\"horizontalSpacer_2\">\n       <property name=\"orientation\">\n        <enum>Qt::Horizontal</enum>\n       </property>\n       <property name=\"sizeHint\" stdset=\"0\">\n        <size>\n         <width>40</width>\n         <height>20</height>\n        </size>\n       </property>\n      </spacer>\n     </item>\n     <item>\n      <widget class=\"QPushButton\" name=\"jobSaveButton\">\n       <property name=\"text\">\n        <string>Save</string>\n       </property>\n      </widget>\n     </item>\n     <item>\n      <widget class=\"QPushButton\" name=\"cancelButton\">\n       <property name=\"text\">\n        <string>Cancel</string>\n       </property>\n       <property name=\"default\">\n        <bool>true</bool>\n       </property>\n      </widget>\n     </item>\n    </layout>\n   </item>\n  </layout>\n </widget>\n <resources>\n  <include location=\"../../resources/resources.qrc\"/>\n </resources>\n <connections/>\n</ui>\n"
  },
  {
    "path": "vsedit-job-server-watcher/src/jobs/job_state_delegate.cpp",
    "content": "#include \"job_state_delegate.h\"\n\n#include \"jobs_model.h\"\n\n#include \"../../../common-src/helpers.h\"\n\n#include <QPainter>\n\nJobStateDelegate::JobStateDelegate(QObject * a_pParent) :\n\tQStyledItemDelegate(a_pParent)\n{\n}\n\nJobStateDelegate::~JobStateDelegate()\n{\n}\n\nvoid JobStateDelegate::paint(QPainter * a_pPainter,\n\tconst QStyleOptionViewItem & a_option, const QModelIndex & a_index) const\n{\n\ta_pPainter->save();\n\tconst JobsModel * cpModel =\n\t\tqobject_cast<const JobsModel *>(a_index.model());\n\tQ_ASSERT(cpModel);\n\tQ_ASSERT(a_index.column() == JobsModel::STATE_COLUMN);\n\tJobProperties properties = cpModel->jobProperties(a_index.row());\n\tJobState state = properties.jobState;\n\tQColor cellColor = jobStateColor(state, a_option);\n\n\tJobState noProgressBarStates[] = {JobState::Waiting,\n\t\tJobState::DependencyNotMet};\n\tbool drawProgress = (properties.type == JobType::EncodeScriptCLI) &&\n\t\t(!vsedit::contains(noProgressBarStates, state));\n\n\ta_pPainter->setPen(cellColor);\n\ta_pPainter->setBrush(a_option.palette.color(QPalette::Base));\n\n\tQRect innerRect = a_option.rect;\n\tinnerRect.setWidth(a_option.rect.width() - 1);\n\tinnerRect.setHeight(a_option.rect.height() - 1);\n\n\tif(drawProgress)\n\t{\n\t\tint progressWidth = properties.framesProcessed * innerRect.width() /\n\t\t\tproperties.framesTotal();\n\t\tQRect progressRect = innerRect;\n\t\tprogressRect.setWidth(progressWidth);\n\t\ta_pPainter->drawRect(progressRect);\n\t\tQRect blankRect = innerRect;\n\t\tblankRect.setWidth(innerRect.width() - progressWidth);\n\t\tblankRect.translate(progressWidth, 0);\n\t\ta_pPainter->setBrush(a_option.palette.color(QPalette::Base));\n\t\ta_pPainter->drawRect(blankRect);\n\t}\n\telse\n\t\ta_pPainter->drawRect(innerRect);\n\n\tQString stateText = cpModel->data(a_index).toString();\n\tif(drawProgress)\n\t{\n\t\tstateText += QString(\" %1 / %2\").arg(properties.framesProcessed)\n\t\t\t.arg(properties.framesTotal());\n\t}\n\n\ta_pPainter->setPen(a_option.palette.color(QPalette::Text));\n\ta_pPainter->setFont(a_option.font);\n\ta_pPainter->drawText(innerRect, Qt::AlignCenter | Qt::TextWordWrap,\n\t\tstateText);\n\n\ta_pPainter->restore();\n}\n\nQColor JobStateDelegate::jobStateColor(JobState a_state,\n\tconst QStyleOptionViewItem & a_option) const\n{\n\tswitch(a_state)\n\t{\n\tcase JobState::Aborted:\n\tcase JobState::Failed:\n\tcase JobState::DependencyNotMet:\n\t\treturn QColor(\"#ffcccc\");\n\tcase JobState::Aborting:\n\tcase JobState::FailedCleanUp:\n\t\treturn QColor(\"#ffeeee\");\n\tcase JobState::Pausing:\n\tcase JobState::Paused:\n\t\treturn QColor(\"#fffddd\");\n\tcase JobState::CompletedCleanUp:\n\tcase JobState::Completed:\n\t\treturn QColor(\"#ddffdd\");\n\tcase JobState::Running:\n\t\treturn QColor(\"#ddeeff\");\n\tdefault:\n\t\treturn a_option.palette.color(QPalette::Base);\n\t}\n}\n"
  },
  {
    "path": "vsedit-job-server-watcher/src/jobs/job_state_delegate.h",
    "content": "#ifndef JOB_STATE_DELEGATE_H_INCLUDED\n#define JOB_STATE_DELEGATE_H_INCLUDED\n\n#include \"../../../common-src/settings/settings_definitions_core.h\"\n\n#include <QStyledItemDelegate>\n\nclass JobStateDelegate : public QStyledItemDelegate\n{\n\tQ_OBJECT\n\npublic:\n\n\tJobStateDelegate(QObject * a_pParent = nullptr);\n\tvirtual ~JobStateDelegate();\n\n\tvirtual void paint(QPainter * a_pPainter,\n\t\tconst QStyleOptionViewItem & a_option,\n\t\tconst QModelIndex & a_index) const override;\n\nprotected:\n\n\tvirtual QColor jobStateColor(JobState a_state,\n\t\tconst QStyleOptionViewItem & a_option) const;\n};\n\n#endif // JOB_STATE_DELEGATE_H_INCLUDED\n"
  },
  {
    "path": "vsedit-job-server-watcher/src/jobs/jobs_model.cpp",
    "content": "#include \"jobs_model.h\"\n\n#include \"../../../common-src/settings/settings_manager.h\"\n#include \"../../../common-src/helpers.h\"\n\n#include <QGuiApplication>\n\n//==============================================================================\n\nconst int JobsModel::NAME_COLUMN = 0;\nconst int JobsModel::TYPE_COLUMN = 1;\nconst int JobsModel::SUBJECT_COLUMN = 2;\nconst int JobsModel::STATE_COLUMN = 3;\nconst int JobsModel::DEPENDS_ON_COLUMN = 4;\nconst int JobsModel::TIME_START_COLUMN = 5;\nconst int JobsModel::TIME_END_COLUMN = 6;\nconst int JobsModel::FPS_COLUMN = 7;\nconst int JobsModel::COLUMNS_NUMBER = 8;\n\n//==============================================================================\n\nJobsModel::JobsModel(SettingsManager * a_pSettingsManager,\n\tQObject * a_pParent) :\n\t  QAbstractItemModel(a_pParent)\n\t, m_pSettingsManager(a_pSettingsManager)\n\t, m_fpsDisplayPrecision(DEFAULT_FPS_DISPLAY_PRECISION)\n{\n\tQ_ASSERT(m_pSettingsManager);\n}\n\n// END OF JobsModel::JobsModel(SettingsManager * a_pSettingsManager,\n//\t\tQObject * a_pParent)\n//==============================================================================\n\nJobsModel::~JobsModel()\n{\n}\n\n// END OF JobsModel::~JobsModel()\n//==============================================================================\n\nQModelIndex JobsModel::index(int a_row, int a_column,\n\tconst QModelIndex & a_parent) const\n{\n\t(void)a_parent;\n\treturn createIndex(a_row, a_column);\n}\n\n// END OF QModelIndex JobsModel::index(int a_row, int a_column,\n//\t\tconst QModelIndex & a_parent) const\n//==============================================================================\n\nQModelIndex JobsModel::parent(const QModelIndex & a_child) const\n{\n\t(void)a_child;\n\treturn QModelIndex();\n}\n\n// END OF QModelIndex JobsModel::parent(const QModelIndex & a_child) const\n//==============================================================================\n\nQt::ItemFlags JobsModel::flags(const QModelIndex & a_index) const\n{\n\tif (!a_index.isValid())\n\t\treturn Qt::NoItemFlags;\n\n\tint row = a_index.row();\n\tint column = a_index.column();\n\n\tif((row >= (int)m_jobs.size()) || (column >= COLUMNS_NUMBER))\n\t\treturn Qt::NoItemFlags;\n\n\tQt::ItemFlags cellFlags = Qt::NoItemFlags\n\t\t| Qt::ItemIsEnabled\n\t\t| Qt::ItemIsSelectable\n\t;\n\n\tbool modifiable = canModifyJob(row);\n\tif((a_index.column() == DEPENDS_ON_COLUMN) && modifiable && (row > 0))\n\t\tcellFlags |= Qt::ItemIsEditable;\n\n\treturn cellFlags;\n}\n\n// END OF Qt::ItemFlags JobsModel::flags(const QModelIndex & a_index) const\n//==============================================================================\n\nQVariant JobsModel::headerData(int a_section, Qt::Orientation a_orientation,\n\tint a_role) const\n{\n\tif(a_orientation != Qt::Horizontal)\n\t\treturn QVariant();\n\n\tif((a_role != Qt::DisplayRole) && (a_role != Qt::ToolTipRole))\n\t\treturn QVariant();\n\n\tswitch(a_section)\n\t{\n\tcase NAME_COLUMN:\n\t\treturn tr(\"Name\");\n\tcase TYPE_COLUMN:\n\t\treturn tr(\"Type\");\n\tcase SUBJECT_COLUMN:\n\t\treturn tr(\"Subject\");\n\tcase STATE_COLUMN:\n\t\treturn tr(\"State\");\n\tcase DEPENDS_ON_COLUMN:\n\t\treturn tr(\"Depends on jobs\");\n\tcase TIME_START_COLUMN:\n\t\treturn tr(\"Started\");\n\tcase TIME_END_COLUMN:\n\t\treturn tr(\"Ended\");\n\tcase FPS_COLUMN:\n\t\treturn tr(\"FPS\");\n\tdefault:\n\t\treturn QVariant();\n\t}\n\n\treturn QVariant();\n}\n\n// END OF QVariant JobsModel::headerData(int a_section,\n//\t\tQt::Orientation a_orientation, int a_role) const\n//==============================================================================\n\nQVariant JobsModel::data(const QModelIndex & a_index, int a_role) const\n{\n\tif(!a_index.isValid())\n\t\treturn QVariant();\n\n\tint row = a_index.row();\n\tint column = a_index.column();\n\n\tif((a_index.row() >= (int)m_jobs.size()) ||\n\t\t(a_index.column() >= COLUMNS_NUMBER))\n\t\treturn QVariant();\n\n\tconst QString dateTimeFormat = \"yyyy-MM-dd\\nhh:mm:ss.z\";\n\n\tif((a_role == Qt::DisplayRole) || (a_role == Qt::ToolTipRole))\n\t{\n\t\tif(column == NAME_COLUMN)\n\t\t\treturn tr(\"Job %1\").arg(row + 1);\n\t\telse if(column == TYPE_COLUMN)\n\t\t\treturn JobProperties::typeName(m_jobs[row].type);\n\t\telse if(column == SUBJECT_COLUMN)\n\t\t\treturn m_jobs[row].subject();\n\t\telse if(column == STATE_COLUMN)\n\t\t\treturn JobProperties::stateName(m_jobs[row].jobState);\n\t\telse if(column == DEPENDS_ON_COLUMN)\n\t\t{\n\t\t\tQStringList dependsList;\n\t\t\tfor(const QUuid & id : m_jobs[row].dependsOnJobIds)\n\t\t\t{\n\t\t\t\tptrdiff_t index = indexOfJob(id);\n\t\t\t\tif(index < 0)\n\t\t\t\t\tdependsList << tr(\"<invalid job>\");\n\t\t\t\telse\n\t\t\t\t\tdependsList << tr(\"Job %1\").arg(index + 1);\n\t\t\t}\n\t\t\treturn dependsList.join(\", \");\n\t\t}\n\t\telse if(column == TIME_START_COLUMN)\n\t\t{\n\t\t\tQDateTime timeStarted = m_jobs[row].timeStarted;\n\t\t\tif(timeStarted != QDateTime())\n\t\t\t\treturn timeStarted.toLocalTime().toString(dateTimeFormat);\n\t\t}\n\t\telse if(column == TIME_END_COLUMN)\n\t\t{\n\t\t\tQDateTime timeStarted = m_jobs[row].timeEnded;\n\t\t\tif(timeStarted != QDateTime())\n\t\t\t\treturn timeStarted.toLocalTime().toString(dateTimeFormat);\n\t\t}\n\t\telse if((column == FPS_COLUMN) &&\n\t\t\t(m_jobs[row].type == JobType::EncodeScriptCLI) &&\n\t\t\t(m_jobs[row].framesProcessed > 0))\n\t\t{\n\t\t\tQString fps = QString::number(m_jobs[row].fps, 'f',\n\t\t\t\tm_fpsDisplayPrecision);\n\t\t\tint framesTotal = m_jobs[row].framesTotal();\n\t\t\tif(vsedit::contains(ACTIVE_JOB_STATES, m_jobs[row].jobState) &&\n\t\t\t\t(m_jobs[row].framesProcessed < framesTotal))\n\t\t\t{\n\t\t\t\tint framesLeft = framesTotal - m_jobs[row].framesProcessed;\n\t\t\t\tdouble secondsToFinish = (double)framesLeft / m_jobs[row].fps;\n\t\t\t\tfps += \"\\n\";\n\t\t\t\tfps += vsedit::timeToString(secondsToFinish);\n\t\t\t}\n\t\t\treturn fps;\n\t\t}\n\t}\n\telse if(a_role == Qt::TextAlignmentRole)\n\t{\n\t\tconst int centeredColumns[] = {STATE_COLUMN, TIME_START_COLUMN,\n\t\t\tTIME_END_COLUMN};\n\t\tif(vsedit::contains(centeredColumns, column))\n\t\t\treturn Qt::AlignCenter;\n\t}\n\n\treturn QVariant();\n}\n\n// END OF QVariant JobsModel::data(const QModelIndex & a_index, int a_role)\n//\t\tconst\n//==============================================================================\n\nint JobsModel::rowCount(const QModelIndex & a_parent) const\n{\n\t(void)a_parent;\n\treturn (int)m_jobs.size();\n}\n\n// END OF int JobsModel::rowCount(const QModelIndex & a_parent) const\n//==============================================================================\n\nint JobsModel::columnCount(const QModelIndex & a_parent) const\n{\n\t(void)a_parent;\n\treturn COLUMNS_NUMBER;\n}\n\n// END OF int JobsModel::columnCount(const QModelIndex & a_parent) const\n//==============================================================================\n\nbool JobsModel::setData(const QModelIndex & a_index, const QVariant & a_value,\n\tint a_role)\n{\n\t(void)a_role;\n\n\tif(!a_index.isValid())\n\t\treturn false;\n\n\tint row = a_index.row();\n\tint column = a_index.column();\n\n\tif((row >= (int)m_jobs.size()) || (column != DEPENDS_ON_COLUMN))\n\t\treturn false;\n\n\tif(!a_value.canConvert<QVariantList>())\n\t\treturn false;\n\n\tQVariantList variantList = a_value.toList();\n\tstd::vector<QUuid> ids;\n\tfor(const QVariant & variant : variantList)\n\t{\n\t\tif(!variant.canConvert<QUuid>())\n\t\t\treturn false;\n\t\tQUuid id = variant.toUuid();\n\t\tint index = indexOfJob(id);\n\t\tif((index < 0) || (index > row))\n\t\t\treturn false;\n\t\tids.push_back(id);\n\t}\n\n\temit signalSetDependencies(m_jobs[row].id, ids);\n\n\treturn true;\n}\n\n// END OF bool JobsModel::setData(const QModelIndex & a_index,\n//\t\tconst QVariant & a_value, int a_role)\n//==============================================================================\n\nvoid JobsModel::clear()\n{\n\tif(m_jobs.empty())\n\t\treturn;\n\n\tbeginRemoveRows(QModelIndex(), 0, (int)m_jobs.size() - 1);\n\tm_jobs.clear();\n\tendRemoveRows();\n}\n\n// END OF void JobsModel::clear()\n//==============================================================================\n\n\nstd::vector<JobProperties> JobsModel::jobs() const\n{\n\treturn m_jobs;\n}\n\n// END OF std::vector<JobProperties> JobsModel::jobs() const\n//==============================================================================\n\nbool JobsModel::setJobs(const std::vector<JobProperties> & a_jobs)\n{\n\tbeginResetModel();\n\tm_jobs = a_jobs;\n\tendResetModel();\n\treturn true;\n}\n\n// END OF bool JobsModel::setJobs(const std::vector<JobProperties> & a_jobs)\n//==============================================================================\n\nJobProperties JobsModel::jobProperties(int a_index) const\n{\n\tif((a_index < 0) || ((size_t)a_index >= m_jobs.size()))\n\t\treturn JobProperties();\n\treturn m_jobs[a_index];\n}\n\n// END OF JobProperties JobsModel::jobProperties(int a_index) const\n//==============================================================================\n\nint JobsModel::createJob(const JobProperties & a_jobProperties)\n{\n\tint newRow = (int)m_jobs.size();\n\tbeginInsertRows(QModelIndex(), newRow, newRow);\n\tm_jobs.push_back(a_jobProperties);\n\tendInsertRows();\n\treturn newRow;\n}\n\n// END OF int JobsModel::createJob(const JobProperties & a_jobProperties)\n//==============================================================================\n\nbool JobsModel::swapJobs(const QUuid & a_id1, const QUuid & a_id2)\n{\n\tint index1 = indexOfJob(a_id1);\n\tif(index1 < 0)\n\t\treturn false;\n\n\tint index2 = indexOfJob(a_id2);\n\tif(index2 < 0)\n\t\treturn false;\n\n\tstd::swap(m_jobs[index1], m_jobs[index2]);\n\n\tnotifyJobUpdated(index1);\n\tnotifyJobUpdated(index2);\n\n\treturn true;\n}\n\n// END OF bool JobsModel::swapJobs(const QUuid & a_id1, const QUuid & a_id2)\n//==============================================================================\n\nbool JobsModel::deleteJobs(std::vector<QUuid> a_ids)\n{\n\tfor(const QUuid & id : a_ids)\n\t{\n\t\tint index = indexOfJob(id);\n\t\tif(index < 0)\n\t\t\tcontinue;\n\n\t\tbeginRemoveRows(QModelIndex(), index, index);\n\t\tm_jobs.erase(m_jobs.begin() + index);\n\t\tendRemoveRows();\n\t}\n\n\treturn true;\n}\n\n// END OF bool JobsModel::deleteJobs(std::vector<QUuid> a_ids)\n//==============================================================================\n\nbool JobsModel::updateJobProperties(const JobProperties & a_jobProperties)\n{\n\tint index = indexOfJob(a_jobProperties.id);\n\tif(index < 0)\n\t\treturn false;\n\tm_jobs[index] = a_jobProperties;\n\tnotifyJobUpdated(index);\n\treturn true;\n}\n\n// END OF bool JobsModel::updateJobProperties(\n//\t\tconst JobProperties & a_jobProperties)\n//==============================================================================\n\nbool JobsModel::setJobDependsOnIds(const QUuid & a_id,\n\tconst std::vector<QUuid> & a_dependencies)\n{\n\tint index = indexOfJob(a_id);\n\tif(index < 0)\n\t\treturn false;\n\tm_jobs[index].dependsOnJobIds = a_dependencies;\n\tnotifyJobUpdated(index, DEPENDS_ON_COLUMN);\n\treturn true;\n}\n\n// END OF bool JobsModel::setJobDependsOnIds(const QUuid & a_id,\n//\t\tconst std::vector<QUuid> & a_dependencies)\n//==============================================================================\n\nvoid JobsModel::requestJobDependsOnIds(const QUuid & a_id,\n\tconst std::vector<QUuid> & a_dependencies)\n{\n\temit signalSetDependencies(a_id, a_dependencies);\n}\n\n// END OF void JobsModel::requestJobDependsOnIds(const QUuid & a_id,\n//\t\tconst std::vector<QUuid> & a_dependencies)\n//==============================================================================\n\nbool JobsModel::setJobProgress(const QUuid & a_id, int a_progress, double a_fps)\n{\n\tint index = indexOfJob(a_id);\n\tif(index < 0)\n\t\treturn false;\n\tm_jobs[index].framesProcessed = a_progress;\n\tm_jobs[index].fps = a_fps;\n\tnotifyJobUpdated(index, STATE_COLUMN);\n\tnotifyJobUpdated(index, FPS_COLUMN);\n\temit signalProgressChanged(index, a_progress, m_jobs[index].framesTotal());\n\treturn true;\n}\n\n// END OF bool JobsModel::setJobProgress(const QUuid & a_id, int a_progress,\n//\t\tdouble a_fps)\n//==============================================================================\n\nbool JobsModel::setJobState(const QUuid & a_id, JobState a_state)\n{\n\tint index = indexOfJob(a_id);\n\tif(index < 0)\n\t\treturn false;\n\tm_jobs[index].jobState = a_state;\n\tnotifyJobUpdated(index, STATE_COLUMN);\n\temit signalStateChanged(index, a_state);\n\treturn true;\n}\n\n// END OF bool JobsModel::setJobState(const QUuid & a_id, JobState a_state)\n//==============================================================================\n\nbool JobsModel::setJobStartTime(const QUuid & a_id, const QDateTime & a_time)\n{\n\tint index = indexOfJob(a_id);\n\tif(index < 0)\n\t\treturn false;\n\tm_jobs[index].timeStarted = a_time;\n\tnotifyJobUpdated(index, TIME_START_COLUMN);\n\treturn true;\n}\n\n// END OF bool JobsModel::setJobStartTime(const QUuid & a_id,\n//\t\tconst QDateTime & a_time)\n//==============================================================================\n\nbool JobsModel::setJobEndTime(const QUuid & a_id, const QDateTime & a_time)\n{\n\tint index = indexOfJob(a_id);\n\tif(index < 0)\n\t\treturn false;\n\tm_jobs[index].timeEnded = a_time;\n\tnotifyJobUpdated(index, TIME_END_COLUMN);\n\treturn true;\n}\n\n// END OF bool JobsModel::setJobEndTime(const QUuid & a_id,\n//\t\tconst QDateTime & a_time)\n//==============================================================================\n\nbool JobsModel::canModifyJob(int a_index) const\n{\n\tif((a_index < 0) || ((size_t)a_index >= m_jobs.size()))\n\t\treturn false;\n\n\tJobState forbiddenStates[] = {JobState::Running, JobState::Paused,\n\t\tJobState::Aborting};\n\tif(vsedit::contains(forbiddenStates, m_jobs[a_index].jobState))\n\t\treturn false;\n\n\treturn true;\n}\n\n// END OF bool JobsModel::canModifyJob(int a_index) const\n//==============================================================================\n\nbool JobsModel::hasActiveJobs()\n{\n\tfor(const JobProperties & properties : m_jobs)\n\t{\n\t\tif(vsedit::contains(ACTIVE_JOB_STATES, properties.jobState))\n\t\t\treturn true;\n\t}\n\treturn false;\n}\n\n// END OF bool JobsModel::hasActiveJobs()\n//==============================================================================\n\nbool JobsModel::hasWaitingJobs()\n{\n\tfor(const JobProperties & properties : m_jobs)\n\t{\n\t\tif(properties.jobState == JobState::Waiting)\n\t\t\treturn true;\n\t}\n\treturn false;\n}\n\n// END OF bool JobsModel::hasActiveJobs()\n//==============================================================================\n\nstd::vector<int> JobsModel::indexesFromSelection(\n\tconst QItemSelection & a_selection)\n{\n\tstd::set<int> indexesSet;\n\tQModelIndexList modelIndexList = a_selection.indexes();\n\tfor(const QModelIndex & jobIndex : modelIndexList)\n\t\tindexesSet.insert(jobIndex.row());\n\tstd::vector<int> indexesVector;\n\tstd::copy(indexesSet.begin(), indexesSet.end(),\n\t\tstd::back_inserter(indexesVector));\n\treturn indexesVector;\n}\n\n// END OF std::vector<int> JobsModel::indexesFromSelection(\n//\t\tconst QItemSelection & a_selection)\n//==============================================================================\n\nstd::vector<QUuid> JobsModel::idsFromSelection(\n\tconst QItemSelection & a_selection)\n{\n\tstd::vector<int> indexesVector = indexesFromSelection(a_selection);\n\tstd::vector<QUuid> idsVector;\n\tfor(int jobIndex : indexesVector)\n\t\tidsVector.push_back(m_jobs[jobIndex].id);\n\treturn idsVector;\n}\n\n// END OF std::vector<QUuid> JobsModel::idsFromSelection(\n//\t\tconst QItemSelection & a_selection)\n//==============================================================================\n\nint JobsModel::indexOfJob(const QUuid & a_uuid) const\n{\n\tstd::vector<JobProperties>::const_iterator it =\n\t\tstd::find_if(m_jobs.cbegin(), m_jobs.cend(),\n\t\t\t[&](const JobProperties & a_properties)->bool\n\t\t\t{\n\t\t\t\treturn (a_properties.id == a_uuid);\n\t\t\t});\n\n\treturn (it == m_jobs.cend()) ?\n\t\t-1 : std::distance(m_jobs.cbegin(), it);\n}\n\n// END OF int JobsModel::indexOfJob(const QUuid & a_uuid) const\n//==============================================================================\n\nvoid JobsModel::notifyJobUpdated(int a_index, int a_column)\n{\n\tQModelIndex first;\n\tQModelIndex last;\n\n\tif(a_column < 0)\n\t{\n\t\tfirst = createIndex(a_index, 0);\n\t\tlast = createIndex(a_index, COLUMNS_NUMBER - 1);\n\t}\n\telse\n\t{\n\t\tfirst = createIndex(a_index, a_column);\n\t\tlast = createIndex(a_index, a_column);\n\t}\n\n\temit dataChanged(first, last);\n}\n\n// END OF void JobsModel::noifyJobUpdated(int a_index)\n//==============================================================================\n"
  },
  {
    "path": "vsedit-job-server-watcher/src/jobs/jobs_model.h",
    "content": "#ifndef JOBS_MODEL_H_INCLUDED\n#define JOBS_MODEL_H_INCLUDED\n\n#include \"../../../common-src/settings/settings_definitions_core.h\"\n#include \"../../../common-src/log/styled_log_view_core.h\"\n\n#include <QAbstractItemModel>\n#include <QItemSelection>\n#include <vector>\n\nclass SettingsManager;\n\nclass JobsModel : public QAbstractItemModel\n{\n\tQ_OBJECT\n\npublic:\n\n\tstatic const int NAME_COLUMN;\n\tstatic const int TYPE_COLUMN;\n\tstatic const int SUBJECT_COLUMN;\n\tstatic const int STATE_COLUMN;\n\tstatic const int DEPENDS_ON_COLUMN;\n\tstatic const int TIME_START_COLUMN;\n\tstatic const int TIME_END_COLUMN;\n\tstatic const int FPS_COLUMN;\n\tstatic const int COLUMNS_NUMBER;\n\n\tJobsModel(SettingsManager * a_pSettingsManager,\n\t\tQObject * a_pParent = nullptr);\n\tvirtual ~JobsModel();\n\n\tvirtual QModelIndex index(int a_row, int a_column,\n\t\tconst QModelIndex & a_parent = QModelIndex()) const override;\n\n\tvirtual QModelIndex parent(const QModelIndex & a_child) const override;\n\n\tvirtual Qt::ItemFlags flags(const QModelIndex & a_index) const override;\n\n\tvirtual QVariant headerData(int a_section, Qt::Orientation a_orientation,\n\t\tint a_role = Qt::DisplayRole) const override;\n\n\tvirtual QVariant data(const QModelIndex & a_index,\n\t\tint a_role = Qt::DisplayRole) const override;\n\n\tvirtual int rowCount(const QModelIndex & a_parent = QModelIndex()) const\n\t\toverride;\n\n\tvirtual int columnCount(const QModelIndex & a_parent = QModelIndex()) const\n\t\toverride;\n\n\tvirtual bool setData(const QModelIndex & a_index, const QVariant & a_value,\n\t\tint a_role = Qt::EditRole) override;\n\n\tvoid clear();\n\n\tstd::vector<JobProperties> jobs() const;\n\tbool setJobs(const std::vector<JobProperties> & a_jobs);\n\n\tJobProperties jobProperties(int a_index) const;\n\n\tint createJob(const JobProperties & a_jobProperties);\n\n\tbool swapJobs(const QUuid & a_id1, const QUuid & a_id2);\n\n\tbool deleteJobs(std::vector<QUuid> a_ids);\n\n\tbool updateJobProperties(const JobProperties & a_jobProperties);\n\tbool setJobDependsOnIds(const QUuid & a_id,\n\t\tconst std::vector<QUuid> & a_dependencies);\n\tvoid requestJobDependsOnIds(const QUuid & a_id,\n\t\tconst std::vector<QUuid> & a_dependencies);\n\tbool setJobProgress(const QUuid & a_id, int a_progress, double a_fps);\n\tbool setJobState(const QUuid & a_id, JobState a_state);\n\tbool setJobStartTime(const QUuid & a_id, const QDateTime & a_time);\n\tbool setJobEndTime(const QUuid & a_id, const QDateTime & a_time);\n\n\tbool canModifyJob(int a_index) const;\n\n\tbool hasActiveJobs();\n\tbool hasWaitingJobs();\n\n\tstd::vector<int> indexesFromSelection(const QItemSelection & a_selection);\n\tstd::vector<QUuid> idsFromSelection(const QItemSelection & a_selection);\n\nsignals:\n\n\tvoid signalLogMessage(const QString & a_message,\n\t\tconst QString & a_style = LOG_STYLE_DEFAULT);\n\n\tvoid signalStateChanged(int a_job, JobState a_state);\n\n\tvoid signalProgressChanged(int a_job, int a_progress, int a_progressMax);\n\n\tvoid signalSetDependencies(const QUuid & a_id,\n\t\tstd::vector<QUuid> a_dependencies);\n\nprivate:\n\n\tint indexOfJob(const QUuid & a_id) const;\n\n\tvoid notifyJobUpdated(int a_index, int a_column = -1);\n\n\tstd::vector<JobProperties> m_jobs;\n\n\tSettingsManager * m_pSettingsManager;\n\n\tint m_fpsDisplayPrecision;\n};\n\n#endif // JOBS_MODEL_H_INCLUDED\n"
  },
  {
    "path": "vsedit-job-server-watcher/src/main.cpp",
    "content": "#include \"main_window.h\"\n\n#include \"../../common-src/settings/settings_manager.h\"\n#include \"../../common-src/log/vs_editor_log.h\"\n#include \"../../common-src/application_instance_file_guard/application_instance_file_guard.h\"\n#include \"../../common-src/ipc_defines.h\"\n#include \"../../common-src/helpers.h\"\n#include \"../../common-src/version_info.h\"\n#include <QApplication>\n#include <QLocalSocket>\n\nMainWindow * pMainWindow = nullptr;\n\nvoid handleQtMessage(QtMsgType a_type, const QMessageLogContext & a_context,\n\tconst QString & a_message)\n{\n\tQString prefix = \"Qt debug\";\n\tQString style = LOG_STYLE_DEFAULT;\n\n    switch(a_type)\n    {\n    case QtDebugMsg:\n\t\tprefix = \"Qt debug\";\n\t\tstyle = LOG_STYLE_QT_DEBUG;\n        break;\n    case QtInfoMsg:\n\t\tprefix = \"Qt info\";\n\t\tstyle = LOG_STYLE_QT_INFO;\n        break;\n    case QtWarningMsg:\n\t\tprefix = \"Qt warning\";\n\t\tstyle = LOG_STYLE_QT_WARNING;\n        break;\n    case QtCriticalMsg:\n\t\tprefix = \"Qt critical\";\n\t\tstyle = LOG_STYLE_QT_CRITICAL;\n        break;\n    case QtFatalMsg:\n\t\tprefix = \"Qt fatal\";\n\t\tstyle = LOG_STYLE_QT_FATAL;\n\t\tbreak;\n\tdefault:\n\t\tQ_ASSERT(false);\n    }\n\n    QString fullMessage = QString(\"%1: %2\").arg(prefix).arg(a_message);\n\n\tQString fileString(a_context.file);\n\tQString lineString = QString::number(a_context.line);\n\tQString functionString(a_context.function);\n\n\tQString lineInfo = QString(\"\\n(%1:%2\").arg(fileString).arg(lineString);\n\tif(!functionString.isEmpty())\n\t\tlineInfo += QString(\", %1\").arg(functionString);\n\tlineInfo += QString(\")\");\n\tif(!fileString.isEmpty())\n\t\tfullMessage += lineInfo;\n\n    pMainWindow->slotWriteLogMessage(fullMessage, style);\n\n    if(a_type == QtFatalMsg)\n\t\tabort();\n}\n\nint main(int argc, char *argv[])\n{\n\tif(argc > 1)\n\t{\n\t\tif(strcmp(argv[1], \"-v\") == 0 ||\n\t\t\tstrcmp(argv[1], \"--version\") == 0)\n\t\t{\n\t\t\tprint_version();\n\t\t\treturn 0;\n\t\t}\n\t}\n\n\tQApplication::setAttribute(Qt::AA_DontUseNativeMenuBar);\n\tQApplication application(argc, argv);\n\n\tSettingsManager *settings = new SettingsManager(qApp);\n\n\tvsedit::disableFontKerning(qApp);\n\tapplication.setQuitOnLastWindowClosed(false);\n\n\tApplicationInstanceFileGuard guard(\"vsedit_job_server_watcher_running\");\n\tif(!guard.isLocked())\n\t{\n\t\tQLocalSocket socket;\n\t\tsocket.connectToServer(JOB_SERVER_WATCHER_LOCAL_SERVER_NAME,\n\t\t\tQIODevice::WriteOnly);\n\t\tbool connected = socket.waitForConnected(5000);\n\t\tif(connected)\n\t\t{\n\t\t\tsocket.write(WMSG_SHOW_WINDOW);\n\t\t\tsocket.waitForBytesWritten(5000);\n\t\t}\n\t\telse\n\t\t\tqCritical(\"Couldn't start the server watcher.\");\n\t\treturn 1;\n\t}\n\n\t// Make text in message box selectable\n\tapplication.setStyleSheet(\n\t\t\"QToolTip { font-kerning: none; }\"\n\t\t\"QMessageBox { messagebox-text-interaction-flags: 5; }\");\n\n\tpMainWindow = new MainWindow(settings);\n\tqInstallMessageHandler(handleQtMessage);\n\tpMainWindow->showAndConnect();\n\tint exitCode = application.exec();\n\n\tdelete pMainWindow;\n\tdelete settings;\n\tif(!guard.unlock())\n\t\tqCritical(\"%s\", guard.error().toLocal8Bit().data());\n\n\treturn exitCode;\n}\n"
  },
  {
    "path": "vsedit-job-server-watcher/src/main_window.cpp",
    "content": "#include \"main_window.h\"\n\n#include \"jobs/jobs_model.h\"\n#include \"jobs/job_state_delegate.h\"\n#include \"jobs/job_dependencies_delegate.h\"\n#include \"jobs/job_edit_dialog.h\"\n#include \"connect_to_server_dialog.h\"\n#include \"trusted_clients_addresses_dialog.h\"\n\n#include \"../../common-src/helpers.h\"\n#include \"../../common-src/ipc_defines.h\"\n#include \"../../common-src/settings/settings_definitions.h\"\n#include \"../../common-src/settings/settings_manager.h\"\n#include \"../../common-src/vapoursynth/vs_script_library.h\"\n\n#include <QCoreApplication>\n#include <QMenu>\n#include <QAction>\n#include <QCloseEvent>\n#include <QMoveEvent>\n#include <QResizeEvent>\n#include <QSocketNotifier>\n#include <QToolTip>\n#include <QMessageBox>\n#include <QFileDialog>\n#include <QFile>\n#include <QStandardPaths>\n#include <QStringList>\n#include <QFileInfo>\n#include <QDir>\n#include <QDateTime>\n#include <QDesktopServices>\n#include <QWebSocket>\n#include <QJsonDocument>\n#include <QJsonArray>\n#include <QJsonValue>\n#include <QProcess>\n#include <QSystemTrayIcon>\n#include <QTimer>\n#include <QLocalServer>\n#include <QLocalSocket>\n#include <map>\n\n//==============================================================================\n\nconst char MainWindow::WINDOW_TITLE[] = \"VapourSynth jobs server watcher\";\n\n//==============================================================================\n\nMainWindow::MainWindow(SettingsManager *settings) : QMainWindow()\n\t, m_pSettingsManager(settings)\n\t, m_pJobsModel(nullptr)\n\t, m_pJobStateDelegate(nullptr)\n\t, m_pJobDependenciesDelegate(nullptr)\n\t, m_pVSScriptLibrary(nullptr)\n\t, m_pJobEditDialog(nullptr)\n\t, m_pServerSocket(nullptr)\n\t, m_connectionAttempts(0)\n\t, m_maxConnectionAttempts(DEFAULT_MAX_WATCHER_CONNECTION_ATTEMPTS)\n\t, m_state(WatcherState::NotConnected)\n\t, m_pTrayIcon(nullptr)\n\t, m_pTrayMenu(nullptr)\n\t, m_pActionSetTrustedClientsAddresses(nullptr)\n\t, m_pActionExit(nullptr)\n\t, m_pActionShutdownServerAndExit(nullptr)\n\t, m_pConnectToServerDialog(nullptr)\n\t, m_nextServerAddress(QHostAddress::LocalHost)\n\t, m_pTaskServer(nullptr)\n\t, m_pGeometrySaveTimer(nullptr)\n{\n\tvsedit::disableFontKerning(this);\n\tm_ui.setupUi(this);\n\tsetWindowTitle(tr(WINDOW_TITLE));\n\n\tif(m_pSettingsManager->inDarkMode())\n\t{\n\t\t// Load qDarkStyle colors\n\t\tQFile styleSheetDark(\":/dark/style.qss\");\n\t\tif(!styleSheetDark.open(QFile::ReadOnly | QFile::Text))\n\t\t{\n\t\t\tQMessageBox::critical(this,\n\t\t\t\tQString::fromUtf8(\"File open error\"),\n\t\t\t\tQString::fromUtf8(\"Failed to open stylesheet file \")\n\t\t\t\t\t+ styleSheetDark.errorString());\n\t\t}\n\t\tqApp->setStyleSheet(styleSheetDark.readAll());\n\t\t// With the current impl of the timeline slider\n\t\t// we have to relaunch anyway\n\t\tQPalette newPal(qApp->palette());\n\t\tnewPal.setColor(QPalette::Base, QColor(0, 0, 0));\n\t\tnewPal.setColor(QPalette::Highlight, QColor(128, 128, 128));\n\t\tnewPal.setColor(QPalette::Dark, QColor(192, 192, 192));\n\t\tnewPal.setColor(QPalette::Text, QColor(64, 192, 0));\n\t\tqApp->setPalette(newPal);\n\t}\n#ifdef Q_OS_WIN\n\telse\n\t\tqApp->setStyle(\"fusion\");\n#endif\n\tm_pVSScriptLibrary = new VSScriptLibrary(m_pSettingsManager, this);\n\tm_pJobEditDialog = new JobEditDialog(m_pSettingsManager,\n\t\tm_pVSScriptLibrary, this);\n\n\tm_pJobsModel = new JobsModel(m_pSettingsManager, this);\n\tm_ui.jobsTableView->setModel(m_pJobsModel);\n\tm_pJobStateDelegate = new JobStateDelegate(this);\n\tm_ui.jobsTableView->setItemDelegateForColumn(\n\t\tJobsModel::STATE_COLUMN, m_pJobStateDelegate);\n\tm_pJobDependenciesDelegate = new JobDependenciesDelegate(this);\n\tm_ui.jobsTableView->setItemDelegateForColumn(\n\t\tJobsModel::DEPENDS_ON_COLUMN, m_pJobDependenciesDelegate);\n\n\tQHeaderView * pHorizontalHeader = m_ui.jobsTableView->horizontalHeader();\n\tpHorizontalHeader->setSectionsMovable(true);\n\n\tQHeaderView * pVerticalHeader = m_ui.jobsTableView->verticalHeader();\n\tpVerticalHeader->setSectionResizeMode(QHeaderView::ResizeToContents);\n\n\tm_ui.logView->setName(\"job_server_watcher_main_log\");\n\tm_ui.logView->setSettingsManager(m_pSettingsManager);\n\tm_ui.logView->loadSettings();\n\n\tm_pConnectToServerDialog =\n\t\tnew ConnectToServerDialog(m_pSettingsManager, this);\n\n\tm_pServerSocket = new QWebSocket(QString(),\n\t\tQWebSocketProtocol::VersionLatest, this);\n\n\tm_pGeometrySaveTimer = new QTimer(this);\n\tm_pGeometrySaveTimer->setInterval(DEFAULT_WINDOW_GEOMETRY_SAVE_DELAY);\n\tconnect(m_pGeometrySaveTimer, &QTimer::timeout,\n\t\tthis, &MainWindow::slotSaveGeometry);\n\n\tm_windowGeometry = m_pSettingsManager->getJobServerWatcherGeometry();\n\tif(!m_windowGeometry.isEmpty())\n\t\trestoreGeometry(m_windowGeometry);\n\n\tQByteArray headerState = m_pSettingsManager->getJobsHeaderState();\n\tif(!headerState.isEmpty())\n\t\tpHorizontalHeader->restoreState(headerState);\n\n\tpHorizontalHeader->setContextMenuPolicy(Qt::CustomContextMenu);\n\tm_pJobsHeaderMenu = new QMenu(pHorizontalHeader);\n\tvsedit::disableFontKerning(m_pJobsHeaderMenu);\n\tfor(int i = 0; i < m_pJobsModel->columnCount(); ++i)\n\t{\n\t\tQAction * pAction = new QAction(m_pJobsHeaderMenu);\n\t\tpAction->setText(\n\t\t\tm_pJobsModel->headerData(i, Qt::Horizontal).toString());\n\t\tpAction->setData(i);\n\t\tpAction->setCheckable(true);\n\t\tpAction->setChecked(!pHorizontalHeader->isSectionHidden(i));\n\t\tvsedit::disableFontKerning(pAction);\n\t\tm_pJobsHeaderMenu->addAction(pAction);\n\t\tconnect(pAction, SIGNAL(toggled(bool)),\n\t\t\tthis, SLOT(slotShowJobsHeaderSection(bool)));\n\t}\n\n\tif(QSystemTrayIcon::isSystemTrayAvailable())\n\t{\n\t\tm_pTrayIcon = new QSystemTrayIcon(QIcon(\":watcher.ico\"), this);\n\t\tm_pTrayIcon->setToolTip(WINDOW_TITLE);\n\n\t\tconnect(m_pTrayIcon, &QSystemTrayIcon::activated,\n\t\t\tthis, &MainWindow::slotTrayIconActivated);\n\n\t\tm_pTrayIcon->show();\n\t}\n\n\tm_pTaskServer = new QLocalServer(this);\n\n\tconnect(m_ui.jobNewButton, SIGNAL(clicked()),\n\t\tthis, SLOT(slotJobNewButtonClicked()));\n\tconnect(m_ui.jobEditButton, SIGNAL(clicked()),\n\t\tthis, SLOT(slotJobEditButtonClicked()));\n\tconnect(m_ui.jobMoveUpButton, SIGNAL(clicked()),\n\t\tthis, SLOT(slotJobMoveUpButtonClicked()));\n\tconnect(m_ui.jobMoveDownButton, SIGNAL(clicked()),\n\t\tthis, SLOT(slotJobMoveDownButtonClicked()));\n\tconnect(m_ui.jobDeleteButton, SIGNAL(clicked()),\n\t\tthis, SLOT(slotJobDeleteButtonClicked()));\n\tconnect(m_ui.jobResetStateButton, SIGNAL(clicked()),\n\t\tthis, SLOT(slotJobResetStateButtonClicked()));\n\tconnect(m_ui.startButton, SIGNAL(clicked()),\n\t\tthis, SLOT(slotStartButtonClicked()));\n\tconnect(m_ui.pauseButton, SIGNAL(clicked()),\n\t\tthis, SLOT(slotPauseButtonClicked()));\n\tconnect(m_ui.resumeButton, SIGNAL(clicked()),\n\t\tthis, SLOT(slotResumeButtonClicked()));\n\tconnect(m_ui.abortButton, SIGNAL(clicked()),\n\t\tthis, SLOT(slotAbortButtonClicked()));\n\tconnect(m_ui.startServerButton, SIGNAL(clicked()),\n\t\tthis, SLOT(slotStartLocalServer()));\n\tconnect(m_ui.connectToServerButton, SIGNAL(clicked()),\n\t\tthis, SLOT(slotConnectToServerDialog()));\n\tconnect(m_ui.shutdownServerButton, SIGNAL(clicked()),\n\t\tthis, SLOT(slotShutdownServer()));\n\tconnect(m_ui.jobsTableView, SIGNAL(doubleClicked(const QModelIndex &)),\n\t\tthis, SLOT(slotJobDoubleClicked(const QModelIndex &)));\n\tconnect(m_ui.jobsTableView->selectionModel(),\n\t\t&QItemSelectionModel::selectionChanged,\n\t\tthis, &MainWindow::slotSelectionChanged);\n\tconnect(pHorizontalHeader, SIGNAL(sectionResized(int, int, int)),\n\t\tthis, SLOT(slotSaveHeaderState()));\n\tconnect(pHorizontalHeader, SIGNAL(sectionMoved(int, int, int)),\n\t\tthis, SLOT(slotSaveHeaderState()));\n\tconnect(pHorizontalHeader, SIGNAL(sectionCountChanged(int, int)),\n\t\tthis, SLOT(slotSaveHeaderState()));\n\tconnect(pHorizontalHeader, SIGNAL(geometriesChanged()),\n\t\tthis, SLOT(slotSaveHeaderState()));\n\tconnect(pHorizontalHeader,\n\t\tSIGNAL(customContextMenuRequested(const QPoint &)),\n\t\tthis, SLOT(slotJobsHeaderContextMenu(const QPoint &)));\n\tconnect(m_pConnectToServerDialog,\n\t\tSIGNAL(signalConnectToServer(const QHostAddress &)),\n\t\tthis, SLOT(slotConnectToServer(const QHostAddress &)));\n\tconnect(m_pServerSocket, &QWebSocket::connected,\n\t\tthis, &MainWindow::slotServerConnected);\n\tconnect(m_pServerSocket, &QWebSocket::disconnected,\n\t\tthis, &MainWindow::slotServerDisconnected);\n\tconnect(m_pServerSocket, &QWebSocket::binaryMessageReceived,\n\t\tthis, &MainWindow::slotBinaryMessageReceived);\n\tconnect(m_pServerSocket, &QWebSocket::textMessageReceived,\n\t\tthis, &MainWindow::slotTextMessageReceived);\n\tconnect(m_pServerSocket, SIGNAL(error(QAbstractSocket::SocketError)),\n\t\tthis, SLOT(slotServerError(QAbstractSocket::SocketError)));\n\tconnect(m_pJobsModel, SIGNAL(signalLogMessage(const QString &,\n\t\tconst QString &)),\n\t\tm_ui.logView, SLOT(addEntry(const QString &, const QString &)));\n\tconnect(m_pJobsModel, &JobsModel::signalStateChanged,\n\t\tthis, &MainWindow::slotJobStateChanged);\n\tconnect(m_pJobsModel, &JobsModel::signalProgressChanged,\n\t\tthis, &MainWindow::slotJobProgressChanged);\n\tconnect(m_pJobsModel, &JobsModel::signalSetDependencies,\n\t\tthis, &MainWindow::slotSetJobDependencies);\n\tconnect(m_pTaskServer, &QLocalServer::newConnection,\n\t\tthis, &MainWindow::slotTaskServerNewConnection);\n\n\tcreateActionsAndMenus();\n\tsetUiEnabled();\n\n\tm_pTaskServer->setSocketOptions(QLocalServer::WorldAccessOption);\n\tbool taskServerStarted =\n\t\tm_pTaskServer->listen(JOB_SERVER_WATCHER_LOCAL_SERVER_NAME);\n\tif(!taskServerStarted)\n\t{\n\t\tm_ui.logView->addEntry(tr(\"Couldn't start task server.\"),\n\t\t\tLOG_STYLE_ERROR);\n\t}\n}\n\n// END OF MainWindow::MainWindow()\n//==============================================================================\n\nMainWindow::~MainWindow()\n{\n\tif(m_pGeometrySaveTimer->isActive())\n\t{\n\t\tm_pGeometrySaveTimer->stop();\n\t\tslotSaveGeometry();\n\t}\n\n\tm_pServerSocket->close(QWebSocketProtocol::CloseCodeNormal,\n\t\ttr(\"Closing watcher.\"));\n\tfor(QLocalSocket * pClient : m_taskClients)\n\t{\n\t\tdisconnect(pClient, &QLocalSocket::disconnected,\n\t\t\tthis, &MainWindow::slotTaskClientDisconnected);\n\t\tdelete pClient;\n\t}\n\tqInstallMessageHandler(0);\n}\n\n// END OF MainWindow::~MainWindow()\n//==============================================================================\n\nvoid MainWindow::showAndConnect()\n{\n\tshow();\n\tif(m_state != WatcherState::NotConnected)\n\t\treturn;\n\n\tslotWriteLogMessage(tr(\"Connecting to local server.\"));\n\tchangeState(WatcherState::ProbingLocal);\n\tslotConnectToLocalServer();\n}\n\n// END OF MainWindow::showAndConnect()\n//==============================================================================\n\nvoid MainWindow::show()\n{\n\tif(m_pSettingsManager->getJobServerWatcherMaximized())\n\t\tshowMaximized();\n\telse\n\t\tshowNormal();\n\tactivateWindow();\n}\n\n// END OF MainWindow::show()\n//==============================================================================\n\nvoid MainWindow::close()\n{\n\tchangeState(WatcherState::ShuttingDown);\n\tQMainWindow::close();\n}\n\n// END OF void MainWindow::close()\n//==============================================================================\n\nvoid MainWindow::slotWriteLogMessage(int a_messageType,\n\tconst QString & a_message)\n{\n\tQString style = vsMessageTypeToStyleName(a_messageType);\n\tslotWriteLogMessage(a_message, style);\n}\n\n// END OF void MainWindow::slotWriteLogMessage(int a_messageType,\n//\t\tconst QString & a_message)\n//==============================================================================\n\nvoid MainWindow::slotWriteLogMessage(const QString & a_message,\n\tconst QString & a_style)\n{\n\tQString debugTypes[] = {\n\t\tLOG_STYLE_DEBUG,\n\t\tLOG_STYLE_QT_DEBUG,\n\t\tLOG_STYLE_VS_DEBUG,\n\t};\n\tif(m_pSettingsManager->getShowDebugMessages() ||\n\t\t!vsedit::contains(debugTypes, a_style))\n\t{\n\t\tm_ui.logView->addEntry(a_message, a_style);\n\t}\n\n\tQString fatalTypes[] = {LOG_STYLE_VS_FATAL, LOG_STYLE_QT_FATAL};\n\tif(!vsedit::contains(fatalTypes, a_style))\n\t\treturn;\n\n\tQDateTime now = QDateTime::currentDateTime();\n\tQString timeString = now.toString(\"hh:mm:ss.zzz\");\n\tQString dateString = now.toString(\"yyyy-MM-dd\");\n\tQString caption = QObject::tr(\"VapourSynth Editor Job Server \"\n\t\t\"fatal error!\");\n\tQString fullMessage = dateString + QString(\" \") + timeString +\n\t\tQString(\"\\n\") + caption + QString(\"\\n\") + a_message;\n\n\tQString tempPath =\n\t\tQStandardPaths::writableLocation(QStandardPaths::TempLocation);\n\tif(tempPath.isEmpty())\n\t{\n\t\tQMessageBox::critical(nullptr, caption, fullMessage);\n\t\treturn;\n\t}\n\n\tQString filePath = tempPath + QString(\"/\") +\n\t\tQString(\"VapourSynth-Editor-Job-Server-Watcher-crashlog-\") +\n\t\tdateString + QString(\"-\") + timeString.replace(':', '-') +\n\t\tQString(\".html\");\n\n\tbool saved = m_ui.logView->saveHtml(filePath);\n\tif(!saved)\n\t{\n\t\tQMessageBox::critical(nullptr, caption, fullMessage);\n\t\treturn;\n\t}\n\n\tQUrl fileUrl = QUrl::fromLocalFile(filePath);\n\tQDesktopServices::openUrl(fileUrl);\n}\n\n// END OF void MainWindow::slotWriteLogMessage(const QString & a_message,\n//\t\tconst QString & a_style);\n//==============================================================================\n\nvoid MainWindow::moveEvent(QMoveEvent * a_pEvent)\n{\n\tQMainWindow::moveEvent(a_pEvent);\n\tsaveGeometryDelayed();\n}\n\n// END OF void MainWindow::moveEvent(QMoveEvent * a_pEvent)\n//==============================================================================\n\nvoid MainWindow::resizeEvent(QResizeEvent * a_pEvent)\n{\n\tQMainWindow::resizeEvent(a_pEvent);\n\tsaveGeometryDelayed();\n}\n\n// END OF void MainWindow::resizeEvent(QResizeEvent * a_pEvent)\n//==============================================================================\n\nvoid MainWindow::changeEvent(QEvent * a_pEvent)\n{\n\tif(a_pEvent->type() == QEvent::WindowStateChange)\n\t{\n\t\tif(isMaximized())\n\t\t\tm_pSettingsManager->setJobServerWatcherMaximized(true);\n\t\telse\n\t\t\tm_pSettingsManager->setJobServerWatcherMaximized(false);\n\t}\n\tQMainWindow::changeEvent(a_pEvent);\n}\n\n// END OF void MainWindow::changeEvent(QEvent * a_pEvent)\n//==============================================================================\n\nvoid MainWindow::showEvent(QShowEvent * a_pEvent)\n{\n\tQMainWindow::showEvent(a_pEvent);\n}\n\n// END OF void MainWindow::showEvent(QShowEvent * a_pEvent)\n//==============================================================================\n\nvoid MainWindow::closeEvent(QCloseEvent * a_pEvent)\n{\n\tWatcherState statesToClose[] = {WatcherState::ShuttingDown,\n\t\tWatcherState::ClosingServerShuttingDown};\n\tbool closeToTray = QSystemTrayIcon::isSystemTrayAvailable() &&\n\t\t(!vsedit::contains(statesToClose, m_state));\n\n\tif(closeToTray)\n\t{\n\t\ta_pEvent->ignore();\n\t\thide();\n\t}\n\telse\n\t{\n\t\tQMainWindow::closeEvent(a_pEvent);\n\t\tQCoreApplication::quit();\n\t}\n}\n\n// END OF void MainWindow::closeEvent(QCloseEvent * a_pEvent)\n//==============================================================================\n\nvoid MainWindow::slotTrayIconActivated(\n\tQSystemTrayIcon::ActivationReason a_reason)\n{\n\tif(a_reason == QSystemTrayIcon::DoubleClick)\n\t\tshow();\n}\n\n// END OF void MainWindow::slotTrayIconActivated(\n//\t\tQSystemTrayIcon::ActivationReason a_reason)\n//==============================================================================\n\nvoid MainWindow::slotJobNewButtonClicked()\n{\n\tint result = m_pJobEditDialog->call(tr(\"New job\"), JobProperties());\n\tif(result == QDialog::Accepted)\n\t{\n\t\tJobProperties newJobProperties = m_pJobEditDialog->jobProperties();\n\t\tm_pServerSocket->sendBinaryMessage(\n\t\t\tvsedit::jsonMessage(MSG_CREATE_JOB, newJobProperties.toJson()));\n\t}\n\tprocessTaskList();\n}\n\n// END OF void MainWindow::slotJobNewButtonClicked()\n//==============================================================================\n\nvoid MainWindow::slotJobEditButtonClicked()\n{\n\tQItemSelectionModel * pSelectionModel =\n\t\tm_ui.jobsTableView->selectionModel();\n\tQModelIndexList selection = pSelectionModel->selectedRows();\n\tif(selection.size() != 1)\n\t\treturn;\n\teditJob(selection[0]);\n}\n\n// END OF void MainWindow::slotJobEditButtonClicked()\n//==============================================================================\n\nvoid MainWindow::slotJobMoveUpButtonClicked()\n{\n\tstd::vector<int> selection = selectedIndexes();\n\tif(selection.size() != 1)\n\t\treturn;\n\tif(selection[0] == 0)\n\t\treturn;\n\tQJsonArray jsSwap;\n\tjsSwap << m_pJobsModel->jobProperties(selection[0] - 1).id.toString();\n\tjsSwap << m_pJobsModel->jobProperties(selection[0]).id.toString();\n\tm_pServerSocket->sendBinaryMessage(\n\t\tvsedit::jsonMessage(MSG_SWAP_JOBS, jsSwap));\n}\n\n// END OF void MainWindow::slotJobMoveUpButtonClicked()\n//==============================================================================\n\nvoid MainWindow::slotJobMoveDownButtonClicked()\n{\n\tstd::vector<int> selection = selectedIndexes();\n\tif(selection.size() != 1)\n\t\treturn;\n\tif(selection[0] >= (int)m_pJobsModel->jobs().size())\n\t\treturn;\n\tQJsonArray jsSwap;\n\tjsSwap << m_pJobsModel->jobProperties(selection[0]).id.toString();\n\tjsSwap << m_pJobsModel->jobProperties(selection[0] + 1).id.toString();\n\tm_pServerSocket->sendBinaryMessage(\n\t\tvsedit::jsonMessage(MSG_SWAP_JOBS, jsSwap));\n}\n\n// END OF void MainWindow::slotJobMoveDownButtonClicked()\n//==============================================================================\n\nvoid MainWindow::slotJobDeleteButtonClicked()\n{\n\tstd::vector<int> selection = selectedIndexes();\n\tif(selection.empty())\n\t\treturn;\n\tQJsonArray jsIds;\n\tfor(int index : selection)\n\t\tjsIds << m_pJobsModel->jobProperties(index).id.toString();\n\tm_pServerSocket->sendBinaryMessage(\n\t\tvsedit::jsonMessage(MSG_DELETE_JOBS, jsIds));\n}\n\n// END OF void MainWindow::slotJobDeleteButtonClicked()\n//==============================================================================\n\nvoid MainWindow::slotJobResetStateButtonClicked()\n{\n\tstd::vector<int> selection = selectedIndexes();\n\tif(selection.empty())\n\t\treturn;\n\tQJsonArray jsIds;\n\tfor(int index : selection)\n\t\tjsIds << m_pJobsModel->jobProperties(index).id.toString();\n\tm_pServerSocket->sendBinaryMessage(\n\t\tvsedit::jsonMessage(MSG_RESET_JOBS, jsIds));\n}\n\n// END OF void MainWindow::slotJobResetStateButtonClicked()\n//==============================================================================\n\nvoid MainWindow::slotStartButtonClicked()\n{\n\tm_pServerSocket->sendBinaryMessage(MSG_START_ALL_WAITING_JOBS);\n}\n\n// END OF void MainWindow::slotStartButtonClicked()\n//==============================================================================\n\nvoid MainWindow::slotPauseButtonClicked()\n{\n\tm_pServerSocket->sendBinaryMessage(MSG_PAUSE_ACTIVE_JOBS);\n}\n\n// END OF void MainWindow::slotPauseButtonClicked()\n//==============================================================================\n\nvoid MainWindow::slotResumeButtonClicked()\n{\n\tm_pServerSocket->sendBinaryMessage(MSG_RESUME_PAUSED_JOBS);\n}\n\n// END OF void MainWindow::slotResumeButtonClicked()\n//==============================================================================\n\nvoid MainWindow::slotAbortButtonClicked()\n{\n\tm_pServerSocket->sendBinaryMessage(MSG_ABORT_ACTIVE_JOBS);\n}\n\n// END OF void MainWindow::slotAbortButtonClicked()\n//==============================================================================\n\nvoid MainWindow::slotJobDoubleClicked(const QModelIndex & a_index)\n{\n\tif(a_index.column() == JobsModel::DEPENDS_ON_COLUMN)\n\t\treturn;\n\teditJob(a_index);\n}\n\n// END OF void MainWindow::slotJobDoubleClicked(const QModelIndex & a_index)\n//==============================================================================\n\nvoid MainWindow::slotSelectionChanged()\n{\n\tsetUiEnabled();\n}\n\n// END OF void MainWindow::slotSelectionChanged()\n//==============================================================================\n\nvoid MainWindow::slotSaveHeaderState()\n{\n\tQHeaderView * pHeader = m_ui.jobsTableView->horizontalHeader();\n\tm_pSettingsManager->setJobsHeaderState(pHeader->saveState());\n}\n\n// END OF void MainWindow::slotSaveHeaderState()\n//==============================================================================\n\nvoid MainWindow::slotJobsHeaderContextMenu(const QPoint & a_point)\n{\n\t(void)a_point;\n\tm_pJobsHeaderMenu->exec(QCursor::pos());\n}\n\n// END OF void MainWindow::slotJobsHeaderContextMenu(const QPoint & a_point)\n//==============================================================================\n\nvoid MainWindow::slotShowJobsHeaderSection(bool a_show)\n{\n\tQAction * pAction = qobject_cast<QAction *>(sender());\n\tif(!pAction)\n\t\treturn;\n\tint section = pAction->data().toInt();\n\tQHeaderView * pHeader = m_ui.jobsTableView->horizontalHeader();\n\tpHeader->setSectionHidden(section, !a_show);\n}\n\n// END OF void MainWindow::slotShowJobsHeaderSection(bool a_show)\n//==============================================================================\n\nvoid MainWindow::slotJobStateChanged(int a_job, JobState a_state)\n{\n\tsetUiEnabled();\n\tresetWindowTitle(a_job);\n\n\t// Tray\n\tJobState finalStates[] = {JobState::Completed, JobState::Aborted,\n\t\tJobState::Failed};\n\tif(QSystemTrayIcon::isSystemTrayAvailable() &&\n\t\tvsedit::contains(finalStates, a_state))\n\t{\n\t\tQ_ASSERT(m_pTrayIcon);\n\t\tQString message;\n\t\tQSystemTrayIcon::MessageIcon icon = QSystemTrayIcon::NoIcon;\n\n\t\tif(m_pJobsModel->hasActiveJobs() || m_pJobsModel->hasWaitingJobs())\n\t\t{\n\t\t\tif(a_state == JobState::Completed)\n\t\t\t\tmessage = tr(\"Job%1 has finished successfully\");\n\t\t\telse if(a_state == JobState::Aborted)\n\t\t\t{\n\t\t\t\tmessage = tr(\"Job%1 was aborted\");\n\t\t\t\ticon = QSystemTrayIcon::Warning;\n\t\t\t}\n\t\t\telse if(a_state == JobState::Failed)\n\t\t\t{\n\t\t\t\tmessage = tr(\"Job%1 has failed\");\n\t\t\t\ticon = QSystemTrayIcon::Critical;\n\t\t\t}\n\t\t\tmessage = message.arg(a_job + 1);\n\t\t}\n\t\telse\n\t\t\tmessage = tr(\"All jobs are finished.\");\n\n\t\tm_pTrayIcon->showMessage(WINDOW_TITLE, message, icon);\n\t}\n}\n\n// END OF void MainWindow::slotJobStateChanged(int a_job, JobState a_state)\n//==============================================================================\n\nvoid MainWindow::slotJobProgressChanged(int a_job, int a_progress,\n\tint a_progressMax)\n{\n\t(void)a_progress;\n\t(void)a_progressMax;\n\tresetWindowTitle(a_job);\n\n\tJobProperties properties = m_pJobsModel->jobProperties(a_job);\n}\n\n// END OF void MainWindow::slotJobProgressChanged(int a_job, int a_progress,\n//\t\tint a_progressMax)\n//==============================================================================\n\nvoid MainWindow::slotSetJobDependencies(const QUuid & a_id,\n\tstd::vector<QUuid> a_dependencies)\n{\n\tQJsonObject jsJob;\n\tjsJob[JP_ID] = a_id.toString();\n\tQJsonArray jsDependencies;\n\tfor(QUuid id : a_dependencies)\n\t\tjsDependencies << id.toString();\n\tjsJob[JP_DEPENDS_ON_JOB_IDS] = jsDependencies;\n\tm_pServerSocket->sendBinaryMessage(\n\t\tvsedit::jsonMessage(MSG_SET_JOB_DEPENDENCIES, jsJob));\n}\n\n// END OF void MainWindow::slotSetJobDependencies(const QUuid & a_id,\n//\t\tstd::vector<QUuid> a_dependencies)\n//==============================================================================\n\nvoid MainWindow::slotServerConnected()\n{\n\tchangeState(WatcherState::Connected);\n\tm_connectionAttempts = 0;\n\tm_pServerSocket->sendBinaryMessage(MSG_GET_JOBS_INFO);\n\tm_pServerSocket->sendBinaryMessage(MSG_GET_LOG);\n\tm_pServerSocket->sendBinaryMessage(MSG_SUBSCRIBE);\n\tprocessTaskList();\n}\n\n// END OF void MainWindow::slotServerConnected()\n//==============================================================================\n\nvoid MainWindow::slotServerDisconnected()\n{\n\tm_pJobsModel->clear();\n\tm_trustedClientsAddresses.clear();\n\tm_pActionSetTrustedClientsAddresses->setEnabled(false);\n\n\tif(m_state == WatcherState::ProbingLocal)\n\t{\n\t\tchangeState(WatcherState::StartingLocal);\n\t\tQString serverPath = vsedit::resolvePathFromApplication(\n\t\t\t\"./vsedit-job-server\");\n\t\tQString thisDir = vsedit::resolvePathFromApplication(\".\");\n\t\tQProcess serverProcess;\n\n\t\tbool started = serverProcess.startDetached(serverPath, QStringList(),\n\t\t\tthisDir);\n\t\tif(!started)\n\t\t{\n\t\t\tchangeState(WatcherState::NotConnected);\n\t\t\tm_ui.logView->addEntry(tr(\"Could not start server.\"),\n\t\t\t\tLOG_STYLE_ERROR);\n\t\t\treturn;\n\t\t}\n\n\t\tchangeState(WatcherState::Connecting);\n\t\tQTimer::singleShot(1000, Qt::PreciseTimer, this,\n\t\t\t&MainWindow::slotConnectToLocalServer);\n\t}\n\telse if(m_state == WatcherState::Connecting)\n\t{\n\t\tm_connectionAttempts++;\n\t\tif(m_connectionAttempts >= m_maxConnectionAttempts)\n\t\t{\n\t\t\tchangeState(WatcherState::NotConnected);\n\t\t\tm_connectionAttempts = 0;\n\t\t\tm_ui.logView->addEntry(tr(\"Could not connect to server.\"),\n\t\t\t\tLOG_STYLE_ERROR);\n\t\t\treturn;\n\t\t}\n\t\tQTimer::singleShot(500, Qt::PreciseTimer, this,\n\t\t\t&MainWindow::slotReconnectToServer);\n\t}\n\telse if(m_state == WatcherState::SwitchingServer)\n\t{\n\t\tchangeState(WatcherState::Connecting);\n\t\tslotReconnectToServer();\n\t\treturn;\n\t}\n\telse if((m_state == WatcherState::Disconnecting) ||\n\t\t(m_state == WatcherState::ShuttingDown))\n\t{\n\t\tchangeState(WatcherState::NotConnected);\n\t\tm_ui.logView->addEntry(tr(\"Disconnected from server\"));\n\t}\n\telse if(m_state == WatcherState::Connected)\n\t{\n\t\tm_ui.logView->addEntry(tr(\"Disconnected from server. \"\n\t\t\t\"Reconnecting\"), LOG_STYLE_ERROR);\n\t\tchangeState(WatcherState::Connecting);\n\t\tslotReconnectToServer();\n\t}\n\telse if(m_state == WatcherState::ClosingServerShuttingDown)\n\t\tclose();\n}\n\n// END OF void MainWindow::slotServerDisconnected()\n//==============================================================================\n\nvoid MainWindow::slotBinaryMessageReceived(const QByteArray & a_message)\n{\n\tslotTextMessageReceived(QString::fromUtf8(a_message));\n}\n\n// END OF void MainWindow::slotBinaryMessageReceived(\n//\t\tconst QByteArray & a_message)\n//==============================================================================\n\nvoid MainWindow::slotTextMessageReceived(const QString & a_message)\n{\n\tQString command = a_message;\n\tQString arguments;\n\tint spaceIndex = a_message.indexOf(' ');\n\tif(spaceIndex >= 0)\n\t{\n\t\tcommand = a_message.left(spaceIndex);\n\t\targuments = a_message.mid(spaceIndex + 1);\n\t}\n\n\tQJsonDocument jsArguments = QJsonDocument::fromJson(arguments.toUtf8());\n\n\tif(command == QString(SMSG_JOBS_INFO))\n\t{\n\t\tprocessSMsgJobInfo(arguments);\n\t\treturn;\n\t}\n\n\tif(command == QString(SMSG_COMPLETE_LOG))\n\t{\n\t\tQJsonArray jsEntries = jsArguments.array();\n\t\tfor(int i = 0; i < jsEntries.size(); ++i)\n\t\t{\n\t\t\tLogEntry entry = LogEntry::fromJson(jsEntries[i].toObject());\n\t\t\tm_ui.logView->addEntry(entry);\n\t\t}\n\t\treturn;\n\t}\n\n\tif(command == QString(SMSG_LOG_MESSAGE))\n\t{\n\t\tLogEntry entry = LogEntry::fromJson(jsArguments.object());\n\t\tm_ui.logView->addEntry(entry);\n\t\treturn;\n\t}\n\n\tif(command == QString(SMSG_JOB_CREATED))\n\t{\n\t\tQJsonObject jsJobProperties = jsArguments.object();\n\t\tm_pJobsModel->createJob(JobProperties::fromJson(jsJobProperties));\n\t\treturn;\n\t}\n\n\tif(command == QString(SMSG_JOB_UPDATE))\n\t{\n\t\tQJsonObject jsJobProperties = jsArguments.object();\n\t\tJobProperties properties = JobProperties::fromJson(jsJobProperties);\n\t\tm_pJobsModel->updateJobProperties(properties);\n\t\treturn;\n\t}\n\n\tif(command == QString(SMSG_JOB_STATE_UPDATE))\n\t{\n\t\tQJsonObject jsJob = jsArguments.object();\n\t\tif(!jsJob.contains(JP_ID))\n\t\t\treturn;\n\t\tQUuid id(jsJob[JP_ID].toString());\n\t\tif(!jsJob.contains(JP_JOB_STATE))\n\t\t\treturn;\n\t\tJobState state = (JobState)jsJob[JP_JOB_STATE].toInt();\n\t\tm_pJobsModel->setJobState(id, state);\n\t\treturn;\n\t}\n\n\tif(command == QString(SMSG_JOB_PROGRESS_UPDATE))\n\t{\n\t\tQJsonObject jsJob = jsArguments.object();\n\t\tif(!jsJob.contains(JP_ID))\n\t\t\treturn;\n\t\tQUuid id(jsJob[JP_ID].toString());\n\t\tif(!jsJob.contains(JP_FRAMES_PROCESSED))\n\t\t\treturn;\n\t\tint progress = jsJob[JP_FRAMES_PROCESSED].toInt();\n\t\tif(!jsJob.contains(JP_FPS))\n\t\t\treturn;\n\t\tdouble fps = jsJob[JP_FPS].toDouble();\n\t\tm_pJobsModel->setJobProgress(id, progress, fps);\n\t\treturn;\n\t}\n\n\tif(command == QString(SMSG_JOB_START_TIME_UPDATE))\n\t{\n\t\tQJsonObject jsJob = jsArguments.object();\n\t\tif(!jsJob.contains(JP_ID))\n\t\t\treturn;\n\t\tQUuid id(jsJob[JP_ID].toString());\n\t\tif(!jsJob.contains(JP_TIME_STARTED))\n\t\t\treturn;\n\t\tQDateTime time = QDateTime::fromMSecsSinceEpoch(\n\t\t\tjsJob[JP_TIME_STARTED].toVariant().toLongLong());\n\t\tm_pJobsModel->setJobStartTime(id, time);\n\t\treturn;\n\t}\n\n\tif(command == QString(SMSG_JOB_END_TIME_UPDATE))\n\t{\n\t\tQJsonObject jsJob = jsArguments.object();\n\t\tif(!jsJob.contains(JP_ID))\n\t\t\treturn;\n\t\tQUuid id(jsJob[JP_ID].toString());\n\t\tif(!jsJob.contains(JP_TIME_ENDED))\n\t\t\treturn;\n\t\tQDateTime time = QDateTime::fromMSecsSinceEpoch(\n\t\t\tjsJob[JP_TIME_ENDED].toVariant().toLongLong());\n\t\tm_pJobsModel->setJobEndTime(id, time);\n\t\treturn;\n\t}\n\n\tif(command == QString(SMSG_JOB_DEPENDENCIES_UPDATE))\n\t{\n\t\tQJsonObject jsJob = jsArguments.object();\n\t\tif(!jsJob.contains(JP_ID))\n\t\t\treturn;\n\t\tQUuid id(jsJob[JP_ID].toString());\n\t\tif(!jsJob.contains(JP_DEPENDS_ON_JOB_IDS))\n\t\t\treturn;\n\t\tQJsonArray jsDependencies = jsJob[JP_DEPENDS_ON_JOB_IDS].toArray();\n\t\tstd::vector<QUuid> dependencies;\n\t\tfor(int i = 0; i < jsDependencies.count(); ++i)\n\t\t\tdependencies.push_back(QUuid(jsDependencies[i].toString()));\n\t\tm_pJobsModel->setJobDependsOnIds(id, dependencies);\n\t\treturn;\n\t}\n\n\tif(command == QString(SMSG_JOBS_SWAPPED))\n\t{\n\t\tQJsonArray jsSwap = jsArguments.array();\n\t\tif(jsSwap.size() != 2)\n\t\t\treturn;\n\t\tQUuid id1(jsSwap[0].toString());\n\t\tQUuid id2(jsSwap[1].toString());\n\t\tm_pJobsModel->swapJobs(id1, id2);\n\t\treturn;\n\t}\n\n\tif(command == QString(SMSG_JOBS_DELETED))\n\t{\n\t\tQJsonArray jsIds = jsArguments.array();\n\t\tstd::vector<QUuid> ids;\n\t\tfor(int i = 0; i < jsIds.count(); ++i)\n\t\t\tids.push_back(QUuid(jsIds[i].toString()));\n\t\tm_pJobsModel->deleteJobs(ids);\n\t\treturn;\n\t}\n\n\tif(command == QString(SMSG_REFUSE))\n\t{\n\t\treturn;\n\t}\n\n\tif(command == QString(SMSG_CLOSING_SERVER))\n\t{\n\t\tm_ui.logView->addEntry(tr(\"Server is shutting down.\"));\n\t\treturn;\n\t}\n\n\tif(command == QString(SMSG_TRUSTED_CLIENTS_INFO))\n\t{\n\t\tQStringList trustedClientsAddresses;\n\t\tQVariantList values = jsArguments.array().toVariantList();\n\t\tfor(const QVariant & value : values)\n\t\t\ttrustedClientsAddresses << value.toString();\n\t\tm_trustedClientsAddresses = trustedClientsAddresses;\n\t\tm_pActionSetTrustedClientsAddresses->setEnabled(true);\n\t\treturn;\n\t}\n\n\tm_ui.logView->addEntry(a_message);\n}\n\n// END OF void MainWindow::slotTextMessageReceived(const QString & a_message)\n//==============================================================================\n\nvoid MainWindow::slotServerError(QAbstractSocket::SocketError a_error)\n{\n\tif(a_error == QAbstractSocket::ConnectionRefusedError)\n\t\treturn; // Handled by slotServerDisconnected()\n\tm_ui.logView->addEntry(m_pServerSocket->errorString(), LOG_STYLE_ERROR);\n}\n\n// END OF void MainWindow::slotServerError(QAbstractSocket::SocketError a_error)\n//==============================================================================\n\nvoid MainWindow::slotStartLocalServer()\n{\n\tif(m_state != WatcherState::NotConnected)\n\t\treturn;\n\n\tslotWriteLogMessage(tr(\"Starting local server.\"));\n\tchangeState(WatcherState::ProbingLocal);\n\tslotConnectToLocalServer();\n}\n\n// END OF void MainWindow::slotStartLocalServer()\n//==============================================================================\n\nvoid MainWindow::slotShutdownServer()\n{\n\tif(m_state != WatcherState::Connected)\n\t\treturn;\n\tif(!m_pServerSocket->peerAddress().isLoopback())\n\t\treturn;\n\tchangeState(WatcherState::Disconnecting);\n\tm_pServerSocket->sendBinaryMessage(MSG_CLOSE_SERVER);\n}\n\n// END OF void MainWindow::slotShutdownServer()\n//==============================================================================\n\nvoid MainWindow::slotConnectToServerDialog()\n{\n\tm_pConnectToServerDialog->call(m_pServerSocket->peerAddress());\n}\n\n// END OF void MainWindow::slotConnectToServerDialog()\n//==============================================================================\n\nvoid MainWindow::slotReconnectToServer()\n{\n\tslotConnectToServer(m_nextServerAddress);\n}\n\n// END OF void MainWindow::slotReconnectToServer()\n//==============================================================================\n\nvoid MainWindow::slotConnectToServer(const QHostAddress & a_address)\n{\n\tif(a_address.isNull())\n\t\treturn;\n\n\tm_nextServerAddress = a_address;\n\tQString addressString = a_address.toString();\n\tQString connectionURL = QString(\"ws://%1:%2\").arg(addressString)\n\t\t.arg(JOB_SERVER_PORT);\n\n\tif(m_state == WatcherState::Connected)\n\t{\n//\t\tif(m_nextServerAddress == m_pServerSocket->peerAddress())\n//\t\t\treturn;\n\t\tchangeState(WatcherState::SwitchingServer);\n\t\tm_pServerSocket->close();\n\t}\n\telse if((m_state == WatcherState::NotConnected) ||\n\t\t(m_state == WatcherState::Connecting))\n\t{\n\t\tchangeState(WatcherState::Connecting);\n\t\tslotWriteLogMessage(tr(\"Connecting to server %1. Try %2.\")\n\t\t\t.arg(addressString).arg(m_connectionAttempts + 1));\n\t\tm_pServerSocket->open(connectionURL);\n\t}\n\telse if(m_state == WatcherState::ProbingLocal)\n\t{\n\t\tm_pServerSocket->open(connectionURL);\n\t}\n}\n\n// END OF void MainWindow::slotConnectToServer(const QHostAddress & a_address)\n//==============================================================================\n\nvoid MainWindow::slotConnectToLocalServer()\n{\n\tslotConnectToServer(QHostAddress::LocalHost);\n}\n\n// END OF void MainWindow::slotConnectToLocalServer()\n//==============================================================================\n\nvoid MainWindow::slotShutdownServerAndExit()\n{\n\tif(m_state != WatcherState::Connected)\n\t\tclose();\n\n\tif(!m_pServerSocket->peerAddress().isLoopback())\n\t{\n\t\tm_ui.logView->addEntry(\n\t\t\ttr(\"Not allowed to shut down remote server.\"),\n\t\t\tLOG_STYLE_ERROR);\n\t\treturn;\n\t}\n\tchangeState(WatcherState::ClosingServerShuttingDown);\n\tm_pServerSocket->sendBinaryMessage(MSG_CLOSE_SERVER);\n}\n\n// END OF void MainWindow::slotShutdownServerAndExit()\n//==============================================================================\n\nvoid MainWindow::slotTaskServerNewConnection()\n{\n\tQLocalSocket * pSocket = m_pTaskServer->nextPendingConnection();\n\tif(!pSocket)\n\t\treturn;\n\n\tconnect(pSocket, &QLocalSocket::disconnected,\n\t\tthis, &MainWindow::slotTaskClientDisconnected);\n\tconnect(pSocket, &QLocalSocket::readyRead,\n\t\tthis, &MainWindow::slotTaskClientReadyRead);\n\tm_taskClients.push_back(pSocket);\n}\n\n// END OF void MainWindow::slotTaskServerNewConnection()\n//==============================================================================\n\nvoid MainWindow::slotTaskClientReadyRead()\n{\n\tQLocalSocket * pSocket = qobject_cast<QLocalSocket *>(sender());\n\tif(!pSocket)\n\t\treturn;\n\n\tQByteArray message = pSocket->readAll();\n\n\tQString command = QString::fromUtf8(message);\n\tQByteArray arguments;\n\tint spaceIndex = message.indexOf(' ');\n\tif(spaceIndex >= 0)\n\t{\n\t\tcommand = QString::fromUtf8(message.left(spaceIndex));\n\t\targuments = message.mid(spaceIndex + 1);\n\t}\n\n\tif(command == QString(WMSG_SHOW_WINDOW))\n\t{\n\t\tshow();\n\t}\n\telse if(command == QString(WMSG_CLI_ENCODE_JOB))\n\t{\n\t\tshow();\n\n\t\tQJsonDocument jsArguments = QJsonDocument::fromJson(arguments);\n\t\tJobProperties properties =\n\t\t\tJobProperties::fromJson(jsArguments.object());\n\n\t\tm_taskList.push_back(properties);\n\n\t\tif(m_state != WatcherState::Connected)\n\t\t{\n\t\t\tm_ui.logView->addEntry(tr(\"New job task is put on hold \"\n\t\t\t\t\"until watcher connects to server.\"), LOG_STYLE_WARNING);\n\t\t\treturn;\n\t\t}\n\n\t\tif(m_pJobEditDialog->isVisible())\n\t\t\treturn;\n\n\t\tprocessTaskList();\n\t}\n}\n\n// END OF void MainWindow::slotTaskClientReadyRead()\n//==============================================================================\n\nvoid MainWindow::slotTaskClientDisconnected()\n{\n\tQLocalSocket * pClient = qobject_cast<QLocalSocket *>(sender());\n\tif(!pClient)\n\t\treturn;\n\tm_taskClients.remove(pClient);\n\tpClient->deleteLater();\n}\n\n// END OF void MainWindow::slotTaskClientDisconnected()\n//==============================================================================\n\nvoid MainWindow::slotSetTrustedClientsAddresses()\n{\n    TrustedClientsAddressesDialog dialog(this);\n    int result = dialog.call(m_trustedClientsAddresses);\n    if(result == QDialog::Rejected)\n\t\treturn;\n\tQByteArray message = vsedit::jsonMessage(MSG_SET_TRUSTED_CLIENTS,\n\t\tQJsonArray::fromStringList(dialog.addresses()));\n\tm_pServerSocket->sendBinaryMessage(message);\n}\n\n// END OF void MainWindow::slotSetTrustedClientsAddresses()\n//==============================================================================\n\nvoid MainWindow::slotSaveGeometry()\n{\n\tm_pGeometrySaveTimer->stop();\n\tm_pSettingsManager->setJobServerWatcherGeometry(m_windowGeometry);\n}\n\n// END OF void MainWindow::slotSaveGeometry()\n//==============================================================================\n\nvoid MainWindow::createActionsAndMenus()\n{\n\tstruct ActionToCreate\n\t{\n\t\tQAction ** ppAction;\n\t\tconst char * id;\n\t\tQObject * pObjectToConnect;\n\t\tconst char * slotToConnect;\n\t};\n\n\tActionToCreate actionsToCreate[] =\n\t{\n\t\t{&m_pActionSetTrustedClientsAddresses,\n\t\t\tACTION_ID_SET_TRUSTED_CLIENTS_ADDRESSES,\n\t\t\tthis, SLOT(slotSetTrustedClientsAddresses())},\n\t\t{&m_pActionExit, ACTION_ID_EXIT,\n\t\t\tthis, SLOT(close())},\n\t\t{&m_pActionShutdownServerAndExit, ACTION_ID_SHUTDOWN_SERVER_AND_EXIT,\n\t\t\tthis, SLOT(slotShutdownServerAndExit())},\n\t};\n\n\tfor(ActionToCreate & item : actionsToCreate)\n\t{\n\t\tQAction * pAction = m_pSettingsManager->createStandardAction(\n\t\t\titem.id, this);\n\t\t*item.ppAction = pAction;\n\t\t//m_settableActionsList.push_back(pAction);\n\t\tconnect(pAction, SIGNAL(triggered()),\n\t\t\titem.pObjectToConnect, item.slotToConnect);\n\t}\n\n\tm_pActionSetTrustedClientsAddresses->setEnabled(false);\n\n\tQMenu * pMainMenu = m_ui.menuBar->addMenu(tr(\"Main\"));\n\tvsedit::disableFontKerning(pMainMenu);\n\tpMainMenu->addAction(m_pActionSetTrustedClientsAddresses);\n\tpMainMenu->addAction(m_pActionExit);\n\tpMainMenu->addAction(m_pActionShutdownServerAndExit);\n\n\tif(QSystemTrayIcon::isSystemTrayAvailable())\n\t{\n\t\tQ_ASSERT(m_pTrayIcon);\n\t\tm_pTrayMenu = new QMenu(this);\n\t\tvsedit::disableFontKerning(m_pTrayMenu);\n\t\tm_pTrayMenu->addAction(m_pActionExit);\n\t\tm_pTrayMenu->addAction(m_pActionShutdownServerAndExit);\n\t\tm_pTrayIcon->setContextMenu(m_pTrayMenu);\n\t}\n}\n\n// END OF void MainWindow::createActionsAndMenus()\n//==============================================================================\n\nvoid MainWindow::editJob(const QModelIndex & a_index)\n{\n\tJobProperties properties = m_pJobsModel->jobProperties(a_index.row());\n\n\tif(vsedit::contains(ACTIVE_JOB_STATES, properties.jobState))\n\t{\n\t\tm_ui.logView->addEntry(tr(\"Can not edit active job.\"),\n\t\t\tLOG_STYLE_WARNING);\n\t\treturn;\n\t}\n\n\tint result = m_pJobEditDialog->call(tr(\"Edit Job %1\")\n\t\t.arg(a_index.row() + 1), properties);\n\tif(result == QDialog::Accepted)\n\t{\n\t\tQUuid id = properties.id;\n\t\tproperties = m_pJobEditDialog->jobProperties();\n\t\tproperties.id = id;\n\t\tm_pServerSocket->sendBinaryMessage(vsedit::jsonMessage(MSG_CHANGE_JOB,\n\t\t\tproperties.toJson()));\n\t}\n\n\tprocessTaskList();\n}\n\n// END OF void MainWindow::editJob(const QModelIndex & a_index)\n//==============================================================================\n\nvoid MainWindow::processSMsgJobInfo(const QString & a_message)\n{\n\tif(a_message.isEmpty())\n\t\treturn;\n\n\tQJsonDocument doc = QJsonDocument::fromJson(a_message.toUtf8());\n\tif(!doc.isArray())\n\t\treturn;\n\n\tstd::vector<JobProperties> propertiesVector;\n\n\tfor(const QJsonValue & value : doc.array())\n\t{\n\t\tif(!value.isObject())\n\t\t\tcontinue;\n\t\tJobProperties properties = JobProperties::fromJson(value.toObject());\n\t\tpropertiesVector.push_back(properties);\n\t}\n\n\tm_pJobsModel->setJobs(propertiesVector);\n}\n\n// END OF void MainWindow::processSMsgJobInfo(const QString & a_message)\n//==============================================================================\n\nstd::vector<int> MainWindow::selectedIndexes()\n{\n\tstd::vector<int> indexes;\n\tQItemSelectionModel * pSelectionModel =\n\t\tm_ui.jobsTableView->selectionModel();\n\tQModelIndexList selection = pSelectionModel->selectedRows();\n\tfor(const QModelIndex & index : selection)\n\t\tindexes.push_back(index.row());\n\treturn indexes;\n}\n\n// END OF std::vector<int> MainWindow::selectedIndexes()\n//==============================================================================\n\nvoid MainWindow::setUiEnabled()\n{\n\tstd::map<QPushButton *, bool> buttonsToEnable;\n\n\tbuttonsToEnable[m_ui.jobNewButton] = false;\n\tbuttonsToEnable[m_ui.jobEditButton] = false;\n\tbuttonsToEnable[m_ui.jobMoveUpButton] = false;\n\tbuttonsToEnable[m_ui.jobMoveDownButton] = false;\n\tbuttonsToEnable[m_ui.jobDeleteButton] = false;\n\tbuttonsToEnable[m_ui.jobResetStateButton] = false;\n\tbuttonsToEnable[m_ui.startButton] = false;\n\tbuttonsToEnable[m_ui.pauseButton] = false;\n\tbuttonsToEnable[m_ui.resumeButton] = false;\n\tbuttonsToEnable[m_ui.abortButton] = false;\n\tbuttonsToEnable[m_ui.startServerButton] = false;\n\tbuttonsToEnable[m_ui.connectToServerButton] = false;\n\tbuttonsToEnable[m_ui.shutdownServerButton] = false;\n\n\tif(m_state == WatcherState::NotConnected)\n\t{\n\t\tbuttonsToEnable[m_ui.startServerButton] = true;\n\t}\n\n\tif((m_state == WatcherState::NotConnected) ||\n\t\t(m_state == WatcherState::Connected))\n\t{\n\t\tbuttonsToEnable[m_ui.connectToServerButton] = true;\n\t}\n\n\tif(m_state == WatcherState::Connected)\n\t{\n\t\tbuttonsToEnable[m_ui.jobNewButton] = true;\n\t\tbuttonsToEnable[m_ui.shutdownServerButton] = true;\n\n\t\tstd::vector<int> l_selectedIndexes = selectedIndexes();\n\n\t\tif(l_selectedIndexes.size() == 1)\n\t\t{\n\t\t\tJobProperties jobProperties =\n\t\t\t\tm_pJobsModel->jobProperties(l_selectedIndexes[0]);\n\t\t\tif(!vsedit::contains(ACTIVE_JOB_STATES, jobProperties.jobState))\n\t\t\t{\n\t\t\t\tbuttonsToEnable[m_ui.jobEditButton] = true;\n\t\t\t\tif(l_selectedIndexes[0] > 0)\n\t\t\t\t\tbuttonsToEnable[m_ui.jobMoveUpButton] = true;\n\t\t\t\tif(l_selectedIndexes[0] < (m_pJobsModel->rowCount() - 1))\n\t\t\t\t\tbuttonsToEnable[m_ui.jobMoveDownButton] = true;\n\t\t\t}\n\t\t}\n\n\t\tbool allInactive = !l_selectedIndexes.empty();\n\n\t\tfor(size_t i = 0; i < l_selectedIndexes.size(); ++i)\n\t\t{\n\t\t\tJobProperties jobProperties =\n\t\t\t\tm_pJobsModel->jobProperties(l_selectedIndexes[i]);\n\t\t\tif(vsedit::contains(ACTIVE_JOB_STATES, jobProperties.jobState))\n\t\t\t\tallInactive = false;\n\t\t}\n\n\t\tbuttonsToEnable[m_ui.jobResetStateButton] = allInactive;\n\t\tbuttonsToEnable[m_ui.jobDeleteButton] = allInactive;\n\n\t\tbuttonsToEnable[m_ui.startButton] = true;\n\t\tbuttonsToEnable[m_ui.pauseButton] = true;\n\t\tbuttonsToEnable[m_ui.resumeButton] = true;\n\t\tbuttonsToEnable[m_ui.abortButton] = true;\n\t}\n\n\tfor(std::pair<QPushButton *, bool> buttonToEnable : buttonsToEnable)\n\t{\n\t\tif(buttonToEnable.first->isEnabled() != buttonToEnable.second)\n\t\t\tbuttonToEnable.first->setEnabled(buttonToEnable.second);\n\t}\n}\n\n// END OF void MainWindow::setUiEnabled()\n//==============================================================================\n\nvoid MainWindow::resetWindowTitle(int a_jobIndex)\n{\n\tQString title = WINDOW_TITLE;\n\tJobProperties properties = m_pJobsModel->jobProperties(a_jobIndex);\n\tif(m_pJobsModel->hasActiveJobs())\n\t{\n\t\tQString progress;\n\t\tif(properties.type == JobType::EncodeScriptCLI)\n\t\t{\n\t\t\tprogress = QString(\"%1% \").arg(properties.framesProcessed * 100 /\n\t\t\t\tproperties.framesTotal());\n\t\t}\n\n\t\ttitle = QString(\"%1%2/%3 %4\").arg(progress).arg(a_jobIndex + 1)\n\t\t\t.arg(m_pJobsModel->jobs().size()).arg(WINDOW_TITLE);\n\t}\n\tsetWindowTitle(title);\n\n\tif(QSystemTrayIcon::isSystemTrayAvailable())\n\t{\n\t\tQ_ASSERT(m_pTrayIcon);\n\t\tm_pTrayIcon->setToolTip(title);\n\t}\n}\n\n// END OF void MainWindow::resetWindowTitle(int a_jobIndex)\n//==============================================================================\n\nvoid MainWindow::changeState(WatcherState a_newState)\n{\n\tif(m_state == a_newState)\n\t\treturn;\n\tm_state = a_newState;\n\tsetUiEnabled();\n}\n\n// END OF void MainWindow::changeState(WatcherState a_newState)\n//==============================================================================\n\nvoid MainWindow::processTaskList()\n{\n\twhile(!m_taskList.empty())\n\t{\n\t\tint result = m_pJobEditDialog->call(tr(\"New job\"),\n\t\t\tm_taskList.front());\n\t\tif(result == QDialog::Accepted)\n\t\t{\n\t\t\tJobProperties newJobProperties = m_pJobEditDialog->jobProperties();\n\t\t\tm_pServerSocket->sendBinaryMessage(\n\t\t\t\tvsedit::jsonMessage(MSG_CREATE_JOB, newJobProperties.toJson()));\n\t\t}\n\t\tm_taskList.pop_front();\n\t}\n}\n\n// END OF void MainWindow::processTaskList()\n//==============================================================================\n\nvoid MainWindow::saveGeometryDelayed()\n{\n\tQApplication::processEvents();\n\tif(!isMaximized())\n\t{\n\t\tm_windowGeometry = saveGeometry();\n\t\tm_pGeometrySaveTimer->start();\n\t}\n}\n\n// END OF void MainWindow::saveGeometryDelayed()\n//==============================================================================\n"
  },
  {
    "path": "vsedit-job-server-watcher/src/main_window.h",
    "content": "#ifndef MAINWINDOW_H\n#define MAINWINDOW_H\n\n#include <ui_main_window.h>\n\n#include \"../../common-src/settings/settings_definitions_core.h\"\n#include \"../../common-src/settings/settings_definitions.h\"\n\n#include <QSystemTrayIcon>\n#include <QWebSocket>\n#include <QJsonObject>\n#include <QHostAddress>\n#include <list>\n\nclass SettingsManager;\nclass JobsModel;\nclass JobEditDialog;\nclass JobStateDelegate;\nclass JobDependenciesDelegate;\nclass VSScriptLibrary;\nclass QMenu;\nclass ConnectToServerDialog;\nclass QLocalServer;\nclass QLocalSocket;\nclass TrustedClientsAddressesDialog;\nclass QTimer;\n\nclass MainWindow : public QMainWindow\n{\n\tQ_OBJECT\n\npublic:\n\n\tMainWindow(SettingsManager *settings);\n\n\tvirtual ~MainWindow();\n\n\tvoid showAndConnect();\n\npublic slots:\n\n\tvoid show();\n\tvoid close();\n\tvoid slotWriteLogMessage(int a_messageType, const QString & a_message);\n\tvoid slotWriteLogMessage(const QString & a_message,\n\t\tconst QString & a_style = LOG_STYLE_DEFAULT);\n\nprotected:\n\n\tvirtual void moveEvent(QMoveEvent * a_pEvent) override;\n\tvirtual void resizeEvent(QResizeEvent * a_pEvent) override;\n\tvirtual void changeEvent(QEvent * a_pEvent) override;\n\tvirtual void showEvent(QShowEvent * a_pEvent) override;\n\tvirtual void closeEvent(QCloseEvent * a_pEvent) override;\n\nprivate slots:\n\n\tvoid slotTrayIconActivated(QSystemTrayIcon::ActivationReason a_reason);\n\n\tvoid slotJobNewButtonClicked();\n\tvoid slotJobEditButtonClicked();\n\tvoid slotJobMoveUpButtonClicked();\n\tvoid slotJobMoveDownButtonClicked();\n\tvoid slotJobDeleteButtonClicked();\n\tvoid slotJobResetStateButtonClicked();\n\tvoid slotStartButtonClicked();\n\tvoid slotPauseButtonClicked();\n\tvoid slotResumeButtonClicked();\n\tvoid slotAbortButtonClicked();\n\n\tvoid slotJobDoubleClicked(const QModelIndex & a_index);\n\n\tvoid slotSelectionChanged();\n\n\tvoid slotSaveHeaderState();\n\n\tvoid slotJobsHeaderContextMenu(const QPoint & a_point);\n\tvoid slotShowJobsHeaderSection(bool a_show);\n\n\tvoid slotJobStateChanged(int a_job, JobState a_state);\n\tvoid slotJobProgressChanged(int a_job, int a_progress, int a_progressMax);\n\tvoid slotSetJobDependencies(const QUuid & a_id,\n\t\tstd::vector<QUuid> a_dependencies);\n\n\tvoid slotServerConnected();\n\tvoid slotServerDisconnected();\n\tvoid slotBinaryMessageReceived(const QByteArray & a_message);\n\tvoid slotTextMessageReceived(const QString & a_message);\n\tvoid slotServerError(QAbstractSocket::SocketError a_error);\n\n\tvoid slotStartLocalServer();\n\tvoid slotShutdownServer();\n\n\tvoid slotConnectToServerDialog();\n\n\tvoid slotReconnectToServer();\n\tvoid slotConnectToServer(const QHostAddress & a_address);\n\tvoid slotConnectToLocalServer();\n\n\tvoid slotShutdownServerAndExit();\n\n\tvoid slotTaskServerNewConnection();\n\tvoid slotTaskClientReadyRead();\n\tvoid slotTaskClientDisconnected();\n\n\tvoid slotSetTrustedClientsAddresses();\n\n\tvoid slotSaveGeometry();\n\nprivate:\n\n\tenum class WatcherState\n\t{\n\t\tNotConnected,\n\t\tProbingLocal,\n\t\tStartingLocal,\n\t\tConnecting,\n\t\tConnected,\n\t\tDisconnecting,\n\t\tSwitchingServer,\n\t\tShuttingDown,\n\t\tClosingServerShuttingDown,\n\t};\n\n\tvoid createActionsAndMenus();\n\n\tvoid editJob(const QModelIndex & a_index);\n\n\tvoid processSMsgJobInfo(const QString & a_message);\n\n\tstd::vector<int> selectedIndexes();\n\n\tvoid setUiEnabled();\n\n\tvoid resetWindowTitle(int a_jobIndex);\n\n\tvoid changeState(WatcherState a_newState);\n\n\tvoid processTaskList();\n\n\tvoid saveGeometryDelayed();\n\n\tstatic const char WINDOW_TITLE[];\n\n\tUi::MainWindow m_ui;\n\n\tSettingsManager * m_pSettingsManager;\n\n\tJobsModel * m_pJobsModel;\n\tJobStateDelegate * m_pJobStateDelegate;\n\tJobDependenciesDelegate * m_pJobDependenciesDelegate;\n\n\tVSScriptLibrary * m_pVSScriptLibrary;\n\tJobEditDialog * m_pJobEditDialog;\n\n\tQMenu * m_pJobsHeaderMenu;\n\n\tQWebSocket * m_pServerSocket;\n\n\tint m_connectionAttempts;\n\tint m_maxConnectionAttempts;\n\n\tWatcherState m_state;\n\n\tQSystemTrayIcon * m_pTrayIcon;\n\n\tQMenu * m_pTrayMenu;\n\n\tQAction * m_pActionSetTrustedClientsAddresses;\n\tQAction * m_pActionExit;\n\tQAction * m_pActionShutdownServerAndExit;\n\n\tConnectToServerDialog * m_pConnectToServerDialog;\n\n\tQHostAddress m_nextServerAddress;\n\n\tQLocalServer * m_pTaskServer;\n\tstd::list<QLocalSocket *> m_taskClients;\n\n\tstd::list<JobProperties> m_taskList;\n\n\tQStringList m_trustedClientsAddresses;\n\n\tQTimer * m_pGeometrySaveTimer;\n\tQByteArray m_windowGeometry;\n\n};\n\n#endif // MAINWINDOW_H\n"
  },
  {
    "path": "vsedit-job-server-watcher/src/main_window.ui",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<ui version=\"4.0\">\n <class>MainWindow</class>\n <widget class=\"QMainWindow\" name=\"MainWindow\">\n  <property name=\"geometry\">\n   <rect>\n    <x>0</x>\n    <y>0</y>\n    <width>1015</width>\n    <height>756</height>\n   </rect>\n  </property>\n  <property name=\"windowIcon\">\n   <iconset resource=\"../../resources/vsedit-job-server-watcher.qrc\">\n    <normaloff>:/watcher.ico</normaloff>:/watcher.ico</iconset>\n  </property>\n  <widget class=\"QWidget\" name=\"centralWidget\">\n   <layout class=\"QHBoxLayout\" name=\"horizontalLayout\">\n    <property name=\"spacing\">\n     <number>2</number>\n    </property>\n    <property name=\"leftMargin\">\n     <number>0</number>\n    </property>\n    <property name=\"topMargin\">\n     <number>0</number>\n    </property>\n    <property name=\"rightMargin\">\n     <number>0</number>\n    </property>\n    <property name=\"bottomMargin\">\n     <number>0</number>\n    </property>\n    <item>\n     <widget class=\"QTableView\" name=\"jobsTableView\">\n      <property name=\"autoScroll\">\n       <bool>false</bool>\n      </property>\n      <property name=\"selectionBehavior\">\n       <enum>QAbstractItemView::SelectRows</enum>\n      </property>\n      <property name=\"verticalScrollMode\">\n       <enum>QAbstractItemView::ScrollPerPixel</enum>\n      </property>\n      <property name=\"horizontalScrollMode\">\n       <enum>QAbstractItemView::ScrollPerPixel</enum>\n      </property>\n      <attribute name=\"horizontalHeaderHighlightSections\">\n       <bool>false</bool>\n      </attribute>\n      <attribute name=\"verticalHeaderVisible\">\n       <bool>false</bool>\n      </attribute>\n     </widget>\n    </item>\n    <item>\n     <layout class=\"QVBoxLayout\" name=\"verticalLayout\">\n      <property name=\"spacing\">\n       <number>4</number>\n      </property>\n      <property name=\"leftMargin\">\n       <number>0</number>\n      </property>\n      <property name=\"topMargin\">\n       <number>2</number>\n      </property>\n      <property name=\"rightMargin\">\n       <number>2</number>\n      </property>\n      <property name=\"bottomMargin\">\n       <number>2</number>\n      </property>\n      <item>\n       <widget class=\"QPushButton\" name=\"jobNewButton\">\n        <property name=\"text\">\n         <string>New</string>\n        </property>\n       </widget>\n      </item>\n      <item>\n       <widget class=\"QPushButton\" name=\"jobEditButton\">\n        <property name=\"text\">\n         <string>Edit</string>\n        </property>\n       </widget>\n      </item>\n      <item>\n       <widget class=\"QPushButton\" name=\"jobMoveUpButton\">\n        <property name=\"text\">\n         <string>Up</string>\n        </property>\n       </widget>\n      </item>\n      <item>\n       <widget class=\"QPushButton\" name=\"jobMoveDownButton\">\n        <property name=\"text\">\n         <string>Down</string>\n        </property>\n       </widget>\n      </item>\n      <item>\n       <widget class=\"QPushButton\" name=\"jobDeleteButton\">\n        <property name=\"text\">\n         <string>Delete</string>\n        </property>\n       </widget>\n      </item>\n      <item>\n       <widget class=\"QPushButton\" name=\"jobResetStateButton\">\n        <property name=\"text\">\n         <string>Reset state</string>\n        </property>\n       </widget>\n      </item>\n      <item>\n       <spacer name=\"verticalSpacer_2\">\n        <property name=\"orientation\">\n         <enum>Qt::Vertical</enum>\n        </property>\n        <property name=\"sizeType\">\n         <enum>QSizePolicy::Preferred</enum>\n        </property>\n        <property name=\"sizeHint\" stdset=\"0\">\n         <size>\n          <width>20</width>\n          <height>16</height>\n         </size>\n        </property>\n       </spacer>\n      </item>\n      <item>\n       <widget class=\"QPushButton\" name=\"startButton\">\n        <property name=\"text\">\n         <string>Start</string>\n        </property>\n       </widget>\n      </item>\n      <item>\n       <widget class=\"QPushButton\" name=\"pauseButton\">\n        <property name=\"text\">\n         <string>Pause</string>\n        </property>\n       </widget>\n      </item>\n      <item>\n       <widget class=\"QPushButton\" name=\"resumeButton\">\n        <property name=\"text\">\n         <string>Resume</string>\n        </property>\n       </widget>\n      </item>\n      <item>\n       <widget class=\"QPushButton\" name=\"abortButton\">\n        <property name=\"text\">\n         <string>Abort</string>\n        </property>\n       </widget>\n      </item>\n      <item>\n       <spacer name=\"verticalSpacer_3\">\n        <property name=\"orientation\">\n         <enum>Qt::Vertical</enum>\n        </property>\n        <property name=\"sizeType\">\n         <enum>QSizePolicy::Preferred</enum>\n        </property>\n        <property name=\"sizeHint\" stdset=\"0\">\n         <size>\n          <width>20</width>\n          <height>16</height>\n         </size>\n        </property>\n       </spacer>\n      </item>\n      <item>\n       <widget class=\"QPushButton\" name=\"startServerButton\">\n        <property name=\"text\">\n         <string>Start server</string>\n        </property>\n       </widget>\n      </item>\n      <item>\n       <widget class=\"QPushButton\" name=\"connectToServerButton\">\n        <property name=\"text\">\n         <string>Connect to server</string>\n        </property>\n       </widget>\n      </item>\n      <item>\n       <widget class=\"QPushButton\" name=\"shutdownServerButton\">\n        <property name=\"text\">\n         <string>Shutdown server</string>\n        </property>\n       </widget>\n      </item>\n      <item>\n       <spacer name=\"verticalSpacer\">\n        <property name=\"orientation\">\n         <enum>Qt::Vertical</enum>\n        </property>\n        <property name=\"sizeHint\" stdset=\"0\">\n         <size>\n          <width>20</width>\n          <height>40</height>\n         </size>\n        </property>\n       </spacer>\n      </item>\n     </layout>\n    </item>\n   </layout>\n  </widget>\n  <widget class=\"QMenuBar\" name=\"menuBar\">\n   <property name=\"geometry\">\n    <rect>\n     <x>0</x>\n     <y>0</y>\n     <width>1015</width>\n     <height>21</height>\n    </rect>\n   </property>\n  </widget>\n  <widget class=\"QStatusBar\" name=\"statusBar\"/>\n  <widget class=\"QDockWidget\" name=\"dockWidget\">\n   <property name=\"features\">\n    <set>QDockWidget::NoDockWidgetFeatures</set>\n   </property>\n   <property name=\"allowedAreas\">\n    <set>Qt::BottomDockWidgetArea</set>\n   </property>\n   <property name=\"windowTitle\">\n    <string>Log</string>\n   </property>\n   <attribute name=\"dockWidgetArea\">\n    <number>8</number>\n   </attribute>\n   <widget class=\"QWidget\" name=\"dockWidgetContents\">\n    <layout class=\"QGridLayout\" name=\"gridLayout\">\n     <property name=\"leftMargin\">\n      <number>0</number>\n     </property>\n     <property name=\"topMargin\">\n      <number>0</number>\n     </property>\n     <property name=\"rightMargin\">\n      <number>0</number>\n     </property>\n     <property name=\"bottomMargin\">\n      <number>0</number>\n     </property>\n     <property name=\"spacing\">\n      <number>0</number>\n     </property>\n     <item row=\"0\" column=\"0\">\n      <widget class=\"VSEditorLog\" name=\"logView\">\n       <property name=\"textInteractionFlags\">\n        <set>Qt::LinksAccessibleByKeyboard|Qt::LinksAccessibleByMouse|Qt::TextBrowserInteraction|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set>\n       </property>\n      </widget>\n     </item>\n    </layout>\n   </widget>\n  </widget>\n </widget>\n <customwidgets>\n  <customwidget>\n   <class>VSEditorLog</class>\n   <extends>QTextEdit</extends>\n   <header>../../common-src/log/vs_editor_log.h</header>\n  </customwidget>\n </customwidgets>\n <resources>\n  <include location=\"../../resources/vsedit-job-server-watcher.qrc\"/>\n </resources>\n <connections/>\n</ui>\n"
  },
  {
    "path": "vsedit-job-server-watcher/src/trusted_clients_addresses_dialog.cpp",
    "content": "#include \"trusted_clients_addresses_dialog.h\"\n\n#include <QHostAddress>\n\n//==============================================================================\n\nTrustedClientsAddressesDialog::TrustedClientsAddressesDialog(\n\tQWidget * a_pParent) : QDialog(a_pParent)\n{\n\tm_ui.setupUi(this);\n\n\tconnect(m_ui.addButton, &QToolButton::clicked,\n\t\tthis, &TrustedClientsAddressesDialog::slotAddButtonClicked);\n\tconnect(m_ui.removeButton, &QToolButton::clicked,\n\t\tthis, &TrustedClientsAddressesDialog::slotRemoveButtonClicked);\n\tconnect(m_ui.okButton, &QPushButton::clicked,\n\t\tthis, &TrustedClientsAddressesDialog::accept);\n\tconnect(m_ui.cancelButton, &QPushButton::clicked,\n\t\tthis, &TrustedClientsAddressesDialog::reject);\n}\n\n// END OF TrustedClientsAddressesDialog::TrustedClientsAddressesDialog(\n//\t\tQWidget * a_pParent)\n//==============================================================================\n\nTrustedClientsAddressesDialog::~TrustedClientsAddressesDialog()\n{\n}\n\n// END OF TrustedClientsAddressesDialog::~TrustedClientsAddressesDialog()\n//==============================================================================\n\nint TrustedClientsAddressesDialog::call(const QStringList & a_addresses)\n{\n\tm_ui.addressesList->clear();\n\n\tQStringList clientAddresses = a_addresses;\n\tclientAddresses.removeDuplicates();\n\n\tfor(const QString & address : clientAddresses)\n\t\tcheckAndAddAddress(address);\n\n\treturn exec();\n}\n\n// END OF int TrustedClientsAddressesDialog::call(\n//\t\tconst QStringList & a_addresses)\n//==============================================================================\n\nQStringList TrustedClientsAddressesDialog::addresses() const\n{\n\tQStringList clientAddresses;\n\tfor(int i = 0; i < m_ui.addressesList->count(); ++i)\n\t\tclientAddresses << m_ui.addressesList->item(i)->text();\n\treturn clientAddresses;\n}\n\n// END OF QStringList TrustedClientsAddressesDialog::addresses() const\n//==============================================================================\n\nvoid TrustedClientsAddressesDialog::slotAddButtonClicked()\n{\n\tcheckAndAddAddress(m_ui.addressEdit->text());\n}\n\n// END OF void TrustedClientsAddressesDialog::slotAddButtonClicked()\n//==============================================================================\n\nvoid TrustedClientsAddressesDialog::slotRemoveButtonClicked()\n{\n\tQList<QListWidgetItem *> items = m_ui.addressesList->selectedItems();\n\tfor(QListWidgetItem * pItem : items)\n\t\tdelete pItem;\n}\n\n// END OF void TrustedClientsAddressesDialog::slotRemoveButtonClicked()\n//==============================================================================\n\nvoid TrustedClientsAddressesDialog::checkAndAddAddress(\n\tconst QString & a_address)\n{\n\tQHostAddress hostAddress(a_address);\n\tif(hostAddress.isLoopback() || (hostAddress.protocol() ==\n\t\tQAbstractSocket::UnknownNetworkLayerProtocol))\n\t\treturn;\n\tm_ui.addressesList->addItem(a_address);\n\tm_ui.addressesList->sortItems();\n}\n\n// END OF void TrustedClientsAddressesDialog::checkAndAddAddress(\n//\t\tconst QString & a_address)\n//==============================================================================\n"
  },
  {
    "path": "vsedit-job-server-watcher/src/trusted_clients_addresses_dialog.h",
    "content": "#ifndef TRUSTED_CLIENTS_ADDRESSES_DIALOG_H_INCLUDED\n#define TRUSTED_CLIENTS_ADDRESSES_DIALOG_H_INCLUDED\n\n#include <ui_trusted_clients_addresses_dialog.h>\n\n#include <QStringList>\n\nclass TrustedClientsAddressesDialog : public QDialog\n{\n\tQ_OBJECT\n\npublic:\n\n\tTrustedClientsAddressesDialog(QWidget * a_pParent = nullptr);\n\tvirtual ~TrustedClientsAddressesDialog();\n\n\tint call(const QStringList & a_addresses);\n\n\tQStringList addresses() const;\n\nprivate slots:\n\n\tvoid slotAddButtonClicked();\n\tvoid slotRemoveButtonClicked();\n\nprivate:\n\n\tvoid checkAndAddAddress(const QString & a_address);\n\n\tUi::TrustedClientsAddressesDialog m_ui;\n};\n\n#endif // TRUSTED_CLIENTS_ADDRESSES_DIALOG_H_INCLUDED\n"
  },
  {
    "path": "vsedit-job-server-watcher/src/trusted_clients_addresses_dialog.ui",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<ui version=\"4.0\">\n <class>TrustedClientsAddressesDialog</class>\n <widget class=\"QDialog\" name=\"TrustedClientsAddressesDialog\">\n  <property name=\"geometry\">\n   <rect>\n    <x>0</x>\n    <y>0</y>\n    <width>525</width>\n    <height>484</height>\n   </rect>\n  </property>\n  <property name=\"windowTitle\">\n   <string>Trusted clients addresses</string>\n  </property>\n  <layout class=\"QGridLayout\" name=\"gridLayout\">\n   <property name=\"leftMargin\">\n    <number>4</number>\n   </property>\n   <property name=\"topMargin\">\n    <number>4</number>\n   </property>\n   <property name=\"rightMargin\">\n    <number>4</number>\n   </property>\n   <property name=\"bottomMargin\">\n    <number>4</number>\n   </property>\n   <property name=\"spacing\">\n    <number>4</number>\n   </property>\n   <item row=\"2\" column=\"1\">\n    <widget class=\"QToolButton\" name=\"removeButton\">\n     <property name=\"text\">\n      <string/>\n     </property>\n     <property name=\"icon\">\n      <iconset resource=\"../../resources/vsedit-job-server-watcher.qrc\">\n       <normaloff>:/delete.png</normaloff>:/delete.png</iconset>\n     </property>\n    </widget>\n   </item>\n   <item row=\"1\" column=\"1\">\n    <widget class=\"QToolButton\" name=\"addButton\">\n     <property name=\"text\">\n      <string/>\n     </property>\n     <property name=\"icon\">\n      <iconset resource=\"../../resources/vsedit-job-server-watcher.qrc\">\n       <normaloff>:/add.png</normaloff>:/add.png</iconset>\n     </property>\n    </widget>\n   </item>\n   <item row=\"0\" column=\"0\" colspan=\"2\">\n    <widget class=\"QLabel\" name=\"warningLabel\">\n     <property name=\"styleSheet\">\n      <string notr=\"true\">background-color: rgb(0, 0, 0);\ncolor: rgb(255, 0, 0);\nfont-size: 24px;\nfont-weight: bold;</string>\n     </property>\n     <property name=\"text\">\n      <string>WARNING! Adding any address to this list opens your PC for a full control and makes it vulnerable for potential hacker attack!</string>\n     </property>\n     <property name=\"wordWrap\">\n      <bool>true</bool>\n     </property>\n     <property name=\"margin\">\n      <number>4</number>\n     </property>\n    </widget>\n   </item>\n   <item row=\"1\" column=\"0\">\n    <widget class=\"QLineEdit\" name=\"addressEdit\"/>\n   </item>\n   <item row=\"4\" column=\"0\" colspan=\"2\">\n    <layout class=\"QHBoxLayout\" name=\"horizontalLayout\">\n     <item>\n      <spacer name=\"horizontalSpacer\">\n       <property name=\"orientation\">\n        <enum>Qt::Horizontal</enum>\n       </property>\n       <property name=\"sizeHint\" stdset=\"0\">\n        <size>\n         <width>308</width>\n         <height>20</height>\n        </size>\n       </property>\n      </spacer>\n     </item>\n     <item>\n      <widget class=\"QPushButton\" name=\"okButton\">\n       <property name=\"text\">\n        <string>OK</string>\n       </property>\n      </widget>\n     </item>\n     <item>\n      <widget class=\"QPushButton\" name=\"cancelButton\">\n       <property name=\"text\">\n        <string>Cancel</string>\n       </property>\n      </widget>\n     </item>\n    </layout>\n   </item>\n   <item row=\"3\" column=\"1\">\n    <spacer name=\"verticalSpacer\">\n     <property name=\"orientation\">\n      <enum>Qt::Vertical</enum>\n     </property>\n     <property name=\"sizeHint\" stdset=\"0\">\n      <size>\n       <width>20</width>\n       <height>40</height>\n      </size>\n     </property>\n    </spacer>\n   </item>\n   <item row=\"2\" column=\"0\" rowspan=\"2\">\n    <widget class=\"QListWidget\" name=\"addressesList\"/>\n   </item>\n  </layout>\n </widget>\n <resources>\n  <include location=\"../../resources/vsedit-job-server-watcher.qrc\"/>\n </resources>\n <connections/>\n</ui>\n"
  }
]