You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

375 lines
10KB

  1. --- ../Rack/src/app/Scene.cpp 2021-12-14 21:35:44.414568198 +0000
  2. +++ Scene.cpp 2022-01-24 11:12:33.268767988 +0000
  3. @@ -1,3 +1,30 @@
  4. +/*
  5. + * DISTRHO Cardinal Plugin
  6. + * Copyright (C) 2021-2022 Filipe Coelho <falktx@falktx.com>
  7. + *
  8. + * This program is free software; you can redistribute it and/or
  9. + * modify it under the terms of the GNU General Public License as
  10. + * published by the Free Software Foundation; either version 3 of
  11. + * the License, or any later version.
  12. + *
  13. + * This program is distributed in the hope that it will be useful,
  14. + * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16. + * GNU General Public License for more details.
  17. + *
  18. + * For a full copy of the GNU General Public License see the LICENSE file.
  19. + */
  20. +
  21. +/**
  22. + * This file is an edited version of VCVRack's app/Scene.cpp
  23. + * Copyright (C) 2016-2021 VCV.
  24. + *
  25. + * This program is free software: you can redistribute it and/or
  26. + * modify it under the terms of the GNU General Public License as
  27. + * published by the Free Software Foundation; either version 3 of
  28. + * the License, or (at your option) any later version.
  29. + */
  30. +
  31. #include <thread>
  32. #include <osdialog.h>
  33. @@ -7,6 +34,7 @@
  34. #include <app/TipWindow.hpp>
  35. #include <app/MenuBar.hpp>
  36. #include <context.hpp>
  37. +#include <engine/Engine.hpp>
  38. #include <system.hpp>
  39. #include <network.hpp>
  40. #include <history.hpp>
  41. @@ -14,31 +42,58 @@
  42. #include <patch.hpp>
  43. #include <asset.hpp>
  44. +#ifdef NDEBUG
  45. +# undef DEBUG
  46. +#endif
  47. +
  48. +#ifdef HAVE_LIBLO
  49. +# include <lo/lo.h>
  50. +#endif
  51. +
  52. +#include "../CardinalCommon.hpp"
  53. +#include "DistrhoUtils.hpp"
  54. +
  55. namespace rack {
  56. namespace app {
  57. struct ResizeHandle : widget::OpaqueWidget {
  58. - math::Vec size;
  59. -
  60. void draw(const DrawArgs& args) override {
  61. + nvgStrokeColor(args.vg, nvgRGBf(1, 1, 1));
  62. + nvgStrokeWidth(args.vg, 1);
  63. +
  64. nvgBeginPath(args.vg);
  65. - nvgMoveTo(args.vg, box.size.x, box.size.y);
  66. + nvgMoveTo(args.vg, box.size.x, 0);
  67. nvgLineTo(args.vg, 0, box.size.y);
  68. - nvgLineTo(args.vg, box.size.x, 0);
  69. - nvgClosePath(args.vg);
  70. - nvgFillColor(args.vg, nvgRGBAf(1, 1, 1, 0.15));
  71. - nvgFill(args.vg);
  72. - }
  73. + nvgStroke(args.vg);
  74. - void onDragStart(const DragStartEvent& e) override {
  75. - size = APP->window->getSize();
  76. - }
  77. + nvgBeginPath(args.vg);
  78. + nvgMoveTo(args.vg, box.size.x + 5, 0);
  79. + nvgLineTo(args.vg, 0, box.size.y + 5);
  80. + nvgStroke(args.vg);
  81. +
  82. + nvgBeginPath(args.vg);
  83. + nvgMoveTo(args.vg, box.size.x + 10, 0);
  84. + nvgLineTo(args.vg, 0, box.size.y + 10);
  85. + nvgStroke(args.vg);
  86. +
  87. + nvgStrokeColor(args.vg, nvgRGBf(0, 0, 0));
  88. - void onDragMove(const DragMoveEvent& e) override {
  89. - size = size.plus(e.mouseDelta);
  90. - APP->window->setSize(size.round());
  91. + nvgBeginPath(args.vg);
  92. + nvgMoveTo(args.vg, box.size.x+1, 0);
  93. + nvgLineTo(args.vg, 0, box.size.y+1);
  94. + nvgStroke(args.vg);
  95. +
  96. + nvgBeginPath(args.vg);
  97. + nvgMoveTo(args.vg, box.size.x + 6, 0);
  98. + nvgLineTo(args.vg, 0, box.size.y + 6);
  99. + nvgStroke(args.vg);
  100. +
  101. + nvgBeginPath(args.vg);
  102. + nvgMoveTo(args.vg, box.size.x + 11, 0);
  103. + nvgLineTo(args.vg, 0, box.size.y + 11);
  104. + nvgStroke(args.vg);
  105. }
  106. };
  107. @@ -46,9 +101,32 @@
  108. struct Scene::Internal {
  109. ResizeHandle* resizeHandle;
  110. - double lastAutosaveTime = 0.0;
  111. -
  112. bool heldArrowKeys[4] = {};
  113. +
  114. +#ifdef HAVE_LIBLO
  115. + double lastSceneChangeTime = 0.0;
  116. + int historyActionIndex = -1;
  117. +
  118. + bool oscAutoDeploy = false;
  119. + bool oscConnected = false;
  120. + lo_server oscServer = nullptr;
  121. +
  122. + static int osc_handler(const char* const path, const char* const types, lo_arg** argv, const int argc, lo_message, void* const self)
  123. + {
  124. + d_stdout("osc_handler(\"%s\", \"%s\", %p, %i)", path, types, argv, argc);
  125. +
  126. + if (std::strcmp(path, "/resp") == 0 && argc == 2 && types[0] == 's' && types[1] == 's') {
  127. + d_stdout("osc_handler(\"%s\", ...) - got resp | '%s' '%s'", path, &argv[0]->s, &argv[1]->s);
  128. + if (std::strcmp(&argv[0]->s, "hello") == 0 && std::strcmp(&argv[1]->s, "ok") == 0)
  129. + static_cast<Internal*>(self)->oscConnected = true;
  130. + }
  131. + return 0;
  132. + }
  133. +
  134. + ~Internal() {
  135. + lo_server_free(oscServer);
  136. + }
  137. +#endif
  138. };
  139. @@ -67,17 +145,17 @@
  140. browser->hide();
  141. addChild(browser);
  142. - if (settings::showTipsOnLaunch) {
  143. - addChild(tipWindowCreate());
  144. - }
  145. -
  146. internal->resizeHandle = new ResizeHandle;
  147. - internal->resizeHandle->box.size = math::Vec(15, 15);
  148. - internal->resizeHandle->hide();
  149. + internal->resizeHandle->box.size = math::Vec(16, 16);
  150. addChild(internal->resizeHandle);
  151. }
  152. +void hideResizeHandle(Scene* scene) {
  153. + scene->internal->resizeHandle->hide();
  154. +}
  155. +
  156. +
  157. Scene::~Scene() {
  158. delete internal;
  159. }
  160. @@ -89,32 +167,13 @@
  161. void Scene::step() {
  162. - if (APP->window->isFullScreen()) {
  163. - // Expand RackScrollWidget to cover entire screen if fullscreen
  164. - rackScroll->box.pos.y = 0;
  165. - }
  166. - else {
  167. - // Always show MenuBar if not fullscreen
  168. - menuBar->show();
  169. - rackScroll->box.pos.y = menuBar->box.size.y;
  170. - }
  171. -
  172. internal->resizeHandle->box.pos = box.size.minus(internal->resizeHandle->box.size);
  173. // Resize owned descendants
  174. menuBar->box.size.x = box.size.x;
  175. + rackScroll->box.pos.y = menuBar->box.size.y;
  176. rackScroll->box.size = box.size.minus(rackScroll->box.pos);
  177. - // Autosave periodically
  178. - if (settings::autosaveInterval > 0.0) {
  179. - double time = system::getTime();
  180. - if (time - internal->lastAutosaveTime >= settings::autosaveInterval) {
  181. - internal->lastAutosaveTime = time;
  182. - APP->patch->saveAutosave();
  183. - settings::save();
  184. - }
  185. - }
  186. -
  187. // Scroll RackScrollWidget with arrow keys
  188. math::Vec arrowDelta;
  189. if (internal->heldArrowKeys[0]) {
  190. @@ -143,6 +202,22 @@
  191. rackScroll->offset += arrowDelta * arrowSpeed;
  192. }
  193. +#ifdef HAVE_LIBLO
  194. + if (internal->oscServer != nullptr) {
  195. + while (lo_server_recv_noblock(internal->oscServer, 0) != 0) {}
  196. +
  197. + if (internal->oscAutoDeploy) {
  198. + const int actionIndex = APP->history->actionIndex;
  199. + const double time = system::getTime();
  200. + if (internal->historyActionIndex != actionIndex && time - internal->lastSceneChangeTime >= 5.0) {
  201. + internal->historyActionIndex = actionIndex;
  202. + internal->lastSceneChangeTime = time;
  203. + patchUtils::deployToRemote();
  204. + }
  205. + }
  206. + }
  207. +#endif
  208. +
  209. Widget::step();
  210. }
  211. @@ -172,7 +247,7 @@
  212. if (e.action == GLFW_PRESS || e.action == GLFW_REPEAT) {
  213. // DEBUG("key '%d '%c' scancode %d '%c' keyName '%s'", e.key, e.key, e.scancode, e.scancode, e.keyName.c_str());
  214. if (e.keyName == "n" && (e.mods & RACK_MOD_MASK) == RACK_MOD_CTRL) {
  215. - APP->patch->loadTemplateDialog();
  216. + patchUtils::loadTemplateDialog();
  217. e.consume(this);
  218. }
  219. if (e.keyName == "q" && (e.mods & RACK_MOD_MASK) == RACK_MOD_CTRL) {
  220. @@ -180,19 +255,20 @@
  221. e.consume(this);
  222. }
  223. if (e.keyName == "o" && (e.mods & RACK_MOD_MASK) == RACK_MOD_CTRL) {
  224. - APP->patch->loadDialog();
  225. + patchUtils::loadDialog();
  226. e.consume(this);
  227. }
  228. if (e.keyName == "o" && (e.mods & RACK_MOD_MASK) == (RACK_MOD_CTRL | GLFW_MOD_SHIFT)) {
  229. - APP->patch->revertDialog();
  230. + patchUtils::revertDialog();
  231. e.consume(this);
  232. }
  233. if (e.keyName == "s" && (e.mods & RACK_MOD_MASK) == RACK_MOD_CTRL) {
  234. - APP->patch->saveDialog();
  235. + // NOTE: will do nothing if path is empty, intentionally
  236. + patchUtils::saveDialog(APP->patch->path);
  237. e.consume(this);
  238. }
  239. if (e.keyName == "s" && (e.mods & RACK_MOD_MASK) == (RACK_MOD_CTRL | GLFW_MOD_SHIFT)) {
  240. - APP->patch->saveAsDialog();
  241. + patchUtils::saveAsDialog();
  242. e.consume(this);
  243. }
  244. if (e.keyName == "z" && (e.mods & RACK_MOD_MASK) == RACK_MOD_CTRL) {
  245. @@ -232,10 +308,8 @@
  246. settings::cpuMeter ^= true;
  247. e.consume(this);
  248. }
  249. - if (e.key == GLFW_KEY_F11 && (e.mods & RACK_MOD_MASK) == 0) {
  250. - APP->window->setFullScreen(!APP->window->isFullScreen());
  251. - // The MenuBar will be hidden when the mouse moves over the RackScrollWidget.
  252. - // menuBar->hide();
  253. + if (e.key == GLFW_KEY_F7 && (e.mods & RACK_MOD_MASK) == 0) {
  254. + patchUtils::deployToRemote();
  255. e.consume(this);
  256. }
  257. @@ -326,13 +400,6 @@
  258. // Key commands that can be overridden by children
  259. if (e.action == GLFW_PRESS || e.action == GLFW_REPEAT) {
  260. - // Alternate key command for exiting fullscreen, since F11 doesn't work reliably on Mac due to "Show desktop" OS binding.
  261. - if (e.key == GLFW_KEY_ESCAPE && (e.mods & RACK_MOD_MASK) == 0) {
  262. - if (APP->window->isFullScreen()) {
  263. - APP->window->setFullScreen(false);
  264. - e.consume(this);
  265. - }
  266. - }
  267. if (e.keyName == "v" && (e.mods & RACK_MOD_MASK) == RACK_MOD_CTRL) {
  268. rack->pasteClipboardAction();
  269. e.consume(this);
  270. @@ -351,7 +418,7 @@
  271. std::string extension = system::getExtension(path);
  272. if (extension == ".vcv") {
  273. - APP->patch->loadPathDialog(path);
  274. + patchUtils::loadPathDialog(path);
  275. e.consume(this);
  276. return;
  277. }
  278. @@ -368,3 +435,73 @@
  279. } // namespace app
  280. } // namespace rack
  281. +
  282. +
  283. +namespace patchUtils {
  284. +
  285. +
  286. +bool connectToRemote() {
  287. + rack::app::Scene::Internal* const internal = APP->scene->internal;
  288. +
  289. + if (internal->oscServer == nullptr) {
  290. + const lo_server oscServer = lo_server_new_with_proto(nullptr, LO_UDP, nullptr);
  291. + DISTRHO_SAFE_ASSERT_RETURN(oscServer != nullptr, false);
  292. + lo_server_add_method(oscServer, "/resp", nullptr, rack::app::Scene::Internal::osc_handler, internal);
  293. + internal->oscServer = oscServer;
  294. + }
  295. +
  296. + const lo_address addr = lo_address_new_with_proto(LO_UDP, REMOTE_HOST, REMOTE_HOST_PORT);
  297. + DISTRHO_SAFE_ASSERT_RETURN(addr != nullptr, false);
  298. + lo_send(addr, "/hello", "");
  299. + lo_address_free(addr);
  300. +
  301. + return true;
  302. +}
  303. +
  304. +
  305. +bool isRemoteConnected() {
  306. +#ifdef HAVE_LIBLO
  307. + return APP->scene->internal->oscConnected;
  308. +#else
  309. + return false;
  310. +#endif
  311. +}
  312. +
  313. +
  314. +bool isRemoteAutoDeployed() {
  315. +#ifdef HAVE_LIBLO
  316. + return APP->scene->internal->oscAutoDeploy;
  317. +#else
  318. + return false;
  319. +#endif
  320. +}
  321. +
  322. +
  323. +void setRemoteAutoDeploy(bool autoDeploy) {
  324. +#ifdef HAVE_LIBLO
  325. + APP->scene->internal->oscAutoDeploy = autoDeploy;
  326. +#endif
  327. +}
  328. +
  329. +
  330. +void deployToRemote() {
  331. +#ifdef HAVE_LIBLO
  332. + const lo_address addr = lo_address_new_with_proto(LO_UDP, REMOTE_HOST, REMOTE_HOST_PORT);
  333. + DISTRHO_SAFE_ASSERT_RETURN(addr != nullptr,);
  334. +
  335. + APP->engine->prepareSave();
  336. + APP->patch->saveAutosave();
  337. + APP->patch->cleanAutosave();
  338. + std::vector<uint8_t> data(rack::system::archiveDirectory(APP->patch->autosavePath, 1));
  339. +
  340. + if (const lo_blob blob = lo_blob_new(data.size(), data.data())) {
  341. + lo_send(addr, "/load", "b", blob);
  342. + lo_blob_free(blob);
  343. + }
  344. +
  345. + lo_address_free(addr);
  346. +#endif
  347. +}
  348. +
  349. +
  350. +} // namespace patchUtils