├── .gitignore ├── README.md ├── browserify_entries.js ├── components ├── canvas │ ├── canvas.js │ └── pd_canvas.html ├── dialogs │ ├── .gitkeep │ ├── dialog_canvas.html │ ├── dialog_data.html │ ├── dialog_external.html │ ├── dialog_font.html │ ├── dialog_gatom.html │ ├── dialog_iemgui.html │ ├── dialog_prefs.html │ ├── dialog_search.html │ └── dialog_text.html └── menu │ ├── menu.html │ └── menu.js ├── css ├── c64.css ├── default.css ├── dejavu.css ├── extended.css ├── footgun.css ├── inverted.css ├── solarized.css ├── solarized_inverted.css ├── strongbad.css ├── subdued.css ├── vanilla.css ├── vanilla_inverted.css └── webapp │ └── webapp.css ├── dist └── bundle.js ├── index.html ├── index.js ├── libs ├── bootstrap │ ├── bootstrap.min.css │ ├── bootstrap.min.js │ └── popper.min.js ├── fa │ └── fontawesome_1b8a796d74.js ├── jquery │ ├── jquery-3.6.0.min.js │ └── jquery-ui.js └── webmidi │ └── webmidi.min.js ├── main.data ├── main.html ├── main.js ├── main.wasm ├── package-lock.json ├── package.json ├── purr.png ├── screenshot.png └── utils ├── actions.js ├── console_find.js └── console_search.js /.gitignore: -------------------------------------------------------------------------------- 1 | # ignore all those dependencies 2 | node_modules 3 | 4 | # ignore weird mac files 5 | .DS_Store 6 | 7 | # ignore binary files 8 | main.data 9 | main.html 10 | main.js 11 | main.wasm 12 | 13 | # ignore copied files 14 | components/dialogs/dialog_*.html 15 | css/*.css 16 | 17 | # ignore build files 18 | dist/ 19 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Purr Data 2 | screenshot 3 | 4 | ## Table of Contents 5 | - [Overview](#overview) 6 | - [Developers](#developers) 7 | - [Accomplished Milestones](#accomplished-milestones) 8 | - [Setup](#setup) 9 | - [Directory Structure](#directory-structure) 10 | - [Future Work](#future-work) 11 | - [Reporting Bugs](#reporting-bugs) 12 | 13 | ## Overview 14 | This document describes the work that was done under [Google Summer of Code 2020](https://summerofcode.withgoogle.com/) a.k.a. GSoC for organization Purr Data. The project idea was to make the native Purr Data run in a web browser by adding a WebAssembly target and HTML5 GUI framework. 15 | 16 | **Purr Data** a.k.a. **Pd-l2ork 2** is an improved version of Miller Puckette’s Pd. 17 | 18 | [Pd](https://puredata.info/) (Pure Data) is a graphical data-flow programming environment which is geared towards real-time interactive computer music and multimedia applications. It is a full-featured open-source alternative to its commercial sibling, Cycling74’s [Max](https://cycling74.com/products/max-features). 19 | 20 | [Purr Data](https://agraef.github.io/purr-data/) serves the same purpose, but offers a new and much improved graphical user interface and includes many 3rd party plug-ins. Like Pd, it runs on Linux, macOS and Windows, and is open-source throughout. 21 | 22 | The goal of this project is to make the graphical programming environment Purr Data run in a web browser so it can be more accessible to users. 23 | 24 | You can try the latest version from https://purrdata.glitch.me/ 25 | 26 | ## Developers 27 | - The backend part of the software has been mainly done by Zack Lee (cuinjune@gmail.com) 28 | - The frontend part of the software has been mainly done by Hugo Carvalho (hugonvsc@gmail.com) 29 | 30 | ## Accomplished Milestones 31 | - Modified the native Purr Data and libpd codebase to make them compatible with [Emscripten](https://emscripten.org/). (Zack) 32 | - Modified and created Makefile to build for Emscripten and to generate WebAssembly(`.wasm`) binaries for external libraries. (Zack) 33 | - Cleaned the backend codebase and organized the file system so the project can be easily maintained. (Zack) 34 | - Modified the existing NW.js based source code to make them compatible with web browsers. (Hugo) 35 | - Reimplemented some elements(menu, canvas, style) specifically for the web browser. (Hugo) 36 | - Integrated the backend with the frontend. (Hugo, Zack) 37 | - Fixed some major bugs and errors in the frontend. (Hugo, Zack) 38 | 39 | ## Setup 40 | 41 | ### Installing Dependencies (Linux) 42 | ``` 43 | sudo apt-get install git automake cmake fakeroot dpkg-dev libgconf-2-4 44 | ``` 45 | 46 | ### Installing Node.js (macOS, Linux) 47 | ``` 48 | curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.37.2/install.sh | bash 49 | ``` 50 | 51 | ### Installing/Activating Emscripten (macOS, Linux) 52 | ``` 53 | git clone https://github.com/emscripten-core/emsdk.git 54 | cd emsdk 55 | git pull 56 | ./emsdk install latest 57 | ./emsdk activate latest 58 | source ./emsdk_env.sh 59 | cd .. 60 | ``` 61 | 62 | ### Building Purr Data for Emscripten (macOS, Linux) 63 | ``` 64 | git clone https://git.purrdata.net/jwilkes/purr-data.git 65 | cd purr-data 66 | git checkout emscripten 67 | make emscripten 68 | ``` 69 | ### Setting up the project (Windows) 70 | ``` 71 | Method 1 72 | 73 | - git clone https://git.purrdata.net/jwilkes/purr-data.git 74 | - cd purr-data 75 | - run command npm install. 76 | - Change directory to purr-data/emscripten/project/purr-data. 77 | - run command npm run build. 78 | - run command npm start. 79 | 80 | Method 2 81 | 82 | - Follow the steps given in the link inorder to install Ubuntu LTS (https://docs.microsoft.com/en-us/windows/wsl/) . 83 | - Then follow the steps mentioned in above sections for Linux. 84 | ``` 85 | ### Running Purr Data in a web browser 86 | - After the building is successfully completed, visit http://localhost:5000 in your browser. 87 | - You can run `npm start` under `purr-data/emscripten/project/purr-data` to run the app again. 88 | 89 | ## Directory Structure 90 | - components: Elements that are dynamically added to the page. (canvas, dialogs, menu) 91 | - components/dialogs: Copied dialogs files from `purr-data/pd/nw` folder. 92 | - css: Copied css files from `purr-data/pd/nw/css` folder. 93 | - css/webapp: Styles created for the web browser. 94 | - dist: Browserified Javascript files. (pdgui.js, pd_shortcuts.js, pd_canvas.js) 95 | - libs: External dependencies. 96 | - utils: Common functions used for this project. 97 | 98 | ## Future Work 99 | - Fix shortcuts so they can work identically in browsers as the native Purr Data. 100 | - Fix getting stuck in the loading screen until a mouse/key event is triggered in Firefox/Safari. 101 | - Fix the patch not responding to mouse event after the help file is opened and not being clicked. 102 | - Fix wrong mouse coordinate issue that happens in some circumstances. 103 | - Fix or disable some of the global menu items not working. 104 | - Fix graphical arrays being opened if the patch font size changes. 105 | - Ask for saving the patch when the user closes an edited patch. 106 | - Make the GUI(e.g. bang, toggle) property dialog window work. 107 | - Make the dialog windows(e.g. property, text) appear on the right side of the patch instead of the left sidebar. 108 | - Merge the patch menu into the global menu and make it work depending on the focus of patches. 109 | - Style the patch window menu bar so it can show the focus state and add some buttons (e.g. close) for convenience. 110 | - Make the patch window resizable by dragging its border. 111 | - Make the patch window rearrangeable by dragging its menu bar. 112 | - Improve the file manager so the files/folders can be added/renamed/deleted. 113 | - Clean the frontend codebase and organize the file system. 114 | - Make the work storable and shareable between users. 115 | 116 | ## Reporting Bugs 117 | If you find any bugs, please let us know. You can contact using the [mailing list](http://disis.music.vt.edu/listinfo/l2ork-dev) or create an [issue](https://git.purrdata.net/jwilkes/purr-data/-/issues). 118 | -------------------------------------------------------------------------------- /browserify_entries.js: -------------------------------------------------------------------------------- 1 | import pdgui from "../../../pd/nw/pdgui.js" 2 | import shortcuts from "../../../pd/nw/pd_shortcuts.js" 3 | import pd_canvas from "../../../pd/nw/pd_canvas.js" 4 | 5 | export const pdgui = pdgui 6 | export const shortcuts = shortcuts 7 | export const pd_canvas = pd_canvas 8 | -------------------------------------------------------------------------------- /components/canvas/canvas.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | window.update_canvas_id = function(cid){ 4 | // Update patch id 5 | var patch = document.getElementById("patch") 6 | patch.id = patch.id + cid; 7 | 8 | // Remain elements 9 | var elems = document.getElementById("patch"+cid).getElementsByTagName("*"); 10 | for (const elem of elems) { 11 | elem.id = elem.id + cid 12 | } 13 | } 14 | 15 | window.add_canvas_name = function(cid, name){ 16 | // Update patch id 17 | var patch_filename = document.getElementById("patch-filename"+cid) 18 | 19 | // Remain elements 20 | patch_filename.innerHTML=""; 21 | patch_filename.append(name); 22 | } -------------------------------------------------------------------------------- /components/canvas/pd_canvas.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 | 7 |
8 |
9 | 10 | 95 |
96 | 97 | 98 |
99 |
100 | 107 |
108 |
109 | 110 | 111 |
112 | 130 |
131 |
132 | -------------------------------------------------------------------------------- /components/dialogs/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cuinjune/purr-data/ef041237ab270f2533409c9bd31ee8ff5873640a/components/dialogs/.gitkeep -------------------------------------------------------------------------------- /components/dialogs/dialog_data.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 |
9 |
10 | 11 |
12 | 13 |
14 | 17 | 20 |
21 | 22 |
23 |
24 | 25 | 375 | 376 | 377 | -------------------------------------------------------------------------------- /components/dialogs/dialog_external.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 |
9 |
10 | 11 |
12 |
13 | 19 | 25 | 30 |
31 |
32 |
33 | 219 | 220 | 221 | -------------------------------------------------------------------------------- /components/dialogs/dialog_font.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 |
9 |
10 | 11 | 12 | 20 | 21 |
22 | 23 | 31 | 32 |
33 | 34 | 42 | 43 |
44 | 45 | 53 | 54 |
55 | 56 | 64 | 65 |
66 | 67 | 75 | 76 |
77 | 78 |
79 | 80 |
81 | 84 |
85 | 86 |
87 |
88 | 89 | 202 | 203 | 204 | -------------------------------------------------------------------------------- /components/dialogs/dialog_gatom.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 |
9 |
10 | 11 | 12 | 13 | 14 | 19 | 23 | 25 | 27 | 28 | 29 | 34 | 38 | 43 | 47 | 48 | 49 | 50 | 55 | 63 | 64 | 65 | 70 | 75 | 76 | 77 | 82 | 87 | 88 | 89 | 94 | 99 | 100 | 101 | 106 |
15 | 18 | 20 | 22 | 24 | 26 |
30 | 33 | 35 | 37 | 39 | 42 | 44 | 46 |
51 | 54 | 57 | 62 |
66 | 69 | 72 | 74 |
78 | 81 | 84 | 86 |
90 | 93 | 96 | 98 |
102 | 105 | 107 | 147 | 148 |
149 | 150 |
151 | 152 |
153 | 156 | 159 | 162 |
163 | 164 |
165 |
166 | 167 | 406 | 407 | 408 | -------------------------------------------------------------------------------- /components/dialogs/dialog_text.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 | 10 |
11 |
12 | 15 | 18 |
19 | 20 |

Do you want to save the changes you made before closing the window? 21 |

22 |
23 | 29 | 35 | 41 |
42 |
43 | 192 | 193 | 194 | -------------------------------------------------------------------------------- /components/menu/menu.html: -------------------------------------------------------------------------------- 1 |
2 | 70 |
-------------------------------------------------------------------------------- /css/c64.css: -------------------------------------------------------------------------------- 1 | /* Global CSS */ 2 | 3 | /* 4 | @font-face { 5 | font-family: "DejaVu Sans Mono"; 6 | src: url("../DejaVuSansMono.ttf"); 7 | } 8 | */ 9 | 10 | body { 11 | margin: 0px; 12 | font-family: "DejaVu Sans Mono"; 13 | } 14 | 15 | .noselect { 16 | -webkit-touch-callout: none; 17 | -webkit-user-select: none; 18 | -khtml-user-select: none; 19 | -moz-user-select: none; 20 | -ms-user-select: none; 21 | user-select: none; 22 | } 23 | 24 | ::selection { 25 | background: #a49aea; 26 | color: #cc9933; 27 | } 28 | 29 | /* The main Pd Window */ 30 | 31 | #console_controls { 32 | background-color: LightGray; 33 | height: 50px; 34 | } 35 | 36 | #control_frame { 37 | padding: 12px; 38 | } 39 | 40 | #printout { 41 | margin: 8px; 42 | } 43 | 44 | #console_bottom { 45 | position: absolute; 46 | top: 50px; 47 | left: 0px; 48 | right: 0px; 49 | bottom: 0px; 50 | overflow-y: scroll; 51 | background-color: #3e32a2; 52 | color: #a49aea; 53 | } 54 | 55 | /* The console API allows classes for different types of messages to print. 56 | Currently the only class is "error". More may be added, especially once 57 | we port the "loglevel" functionality that was available in Pd Extended. */ 58 | #console_bottom .error { 59 | color: #cc9933; 60 | } 61 | 62 | #console_bottom .error a { 63 | color: #ccc; 64 | } 65 | 66 | /* Find bar */ 67 | 68 | #console_find label, #canvas_find label { 69 | font-family: "DejaVu Sans", sans-serif; 70 | font-size: 10pt; 71 | } 72 | 73 | /* marks for matches to console_find */ 74 | mark { 75 | background: white !important; 76 | padding: 0 !important; 77 | } 78 | 79 | mark.console_find_current.console_find_highlighted, 80 | mark.console_find_current { 81 | background: yellow !important; 82 | } 83 | 84 | mark.console_find_highlighted { 85 | background: #6bd4e6 !important; 86 | } 87 | 88 | #console_find { 89 | width: 100%; 90 | height: 1em; 91 | padding: 0.2em; 92 | background: silver; 93 | position: fixed; 94 | bottom: 0; 95 | left: 0; 96 | } 97 | 98 | /* Pure Data Patch Window (aka canvas) */ 99 | 100 | /* patch font and background color. */ 101 | .patch_body { 102 | background-color: #3e32a2; 103 | } 104 | 105 | #selection_rectangle { 106 | stroke: #7c71da; 107 | } 108 | 109 | /* The outline to show the visible area for a Graph-On-Parent canvas, 110 | i.e., the "red rectangle" */ 111 | .gop_rect { 112 | fill: none; 113 | stroke: #ff9933; 114 | } 115 | 116 | .cord.signal { 117 | stroke-width: 2; 118 | stroke: #7569d7; 119 | } 120 | 121 | .cord.control { 122 | stroke-width: 1; 123 | stroke: #7569d7; 124 | } 125 | 126 | /* selected connection between objects */ 127 | .cord.signal.selected_line, 128 | .cord.control.selected_line, 129 | #newcord { 130 | stroke: #cc9933; 131 | } 132 | 133 | #cord_inspector_rect { 134 | fill: black; 135 | stroke: black; 136 | } 137 | 138 | #cord_inspector_text { 139 | fill: white; 140 | } 141 | 142 | #cord_inspector_text.flash { 143 | fill: #e87216; 144 | } 145 | 146 | /* text inside boxes: message boxes, object boxes, graphs, comments, etc. */ 147 | .box_text { 148 | fill: #a49aea; 149 | } 150 | 151 | /* hyperlinks: for now, just pddplink and helplink */ 152 | .pd_link text { 153 | } 154 | 155 | .pd_link text:hover { 156 | fill: red; 157 | } 158 | 159 | .pd_link.selected text { 160 | fill: #e87216 !important; 161 | } 162 | 163 | #new_object_textentry { 164 | /* max-width: 10ch; */ 165 | min-width: 3ch; 166 | position: absolute; 167 | display: table-cell; 168 | padding: 3px 2px 3px 2px; 169 | /* box-shadow: inset 1px 0px 0px 1px #000; */ 170 | color: #a49aea; /* text color */ 171 | background-color: transparent; 172 | white-space: pre-wrap; 173 | overflow-wrap: break-word; 174 | -webkit-margin-before: 0px; 175 | } 176 | 177 | #new_object_textentry.obj { 178 | outline: 1px solid #a49aea; 179 | } 180 | 181 | #new_object_textentry.msg { 182 | outline: 0px solid #a49aea; 183 | background-image: url(../msg-box.svg); 184 | } 185 | 186 | p.msg::after { 187 | content: ""; 188 | height: 100%; 189 | width: 5px; 190 | background-image: url(../msg-box-flag.svg); 191 | position: absolute; 192 | top: 0%; 193 | left: 100%; 194 | } 195 | 196 | /* not sure what this is doing here... */ 197 | text { 198 | // fill: red; 199 | //cursor: default; 200 | } 201 | 202 | /* not sure if this is still needed */ 203 | .selected_border { 204 | stroke: blue; 205 | stroke-dasharray: none; 206 | stroke-width: 1; 207 | } 208 | 209 | .msg .border { 210 | stroke: #7569d7; 211 | fill: #3e32a2; 212 | } 213 | 214 | /* state of msg box when clicking it */ 215 | .msg.flashed .border { 216 | stroke-width: 4; 217 | } 218 | 219 | /* atom box */ 220 | .atom .border { 221 | stroke: #7569d7; 222 | fill: #3e32a2; 223 | } 224 | 225 | /* for dropdown box we want to visually distinguish boxes that output 226 | the index from boxes that output the value. For now we do that by 227 | stroking the arrow for boxes that output an index. For boxes that 228 | output the value we don't need a CSS rule, as the arrow will be filled 229 | black by default */ 230 | .atom .index_arrow { 231 | stroke: black; 232 | stroke-width: 1; 233 | fill: none; 234 | } 235 | 236 | /* gatom "activated" text (i.e., when it has the keyboard focus) */ 237 | .atom.activated text { 238 | fill: red; 239 | } 240 | 241 | #dropdown_list { 242 | position: absolute; 243 | border-width: 1px; 244 | border-style: solid; 245 | border-color: #7569d7; 246 | cursor: pointer; 247 | box-shadow: 2px 2px 0px #7569d7; 248 | overflow-y: auto; 249 | } 250 | 251 | #dropdown_list ol { 252 | list-style-position: inside; 253 | margin: 0; 254 | padding: 0; 255 | background: #3e32a2; 256 | outline: #7569d7; 257 | } 258 | 259 | #dropdown_list li { 260 | color: #a49aea; 261 | list-style-type: none; 262 | padding: 5px; 263 | } 264 | 265 | #dropdown_list li.highlighted { 266 | color: black; 267 | background: #e87216; 268 | } 269 | 270 | .obj .border { 271 | fill: #3e32a2; 272 | stroke: #7569d7; 273 | } 274 | 275 | .comment .border { 276 | fill: none; 277 | } 278 | svg[id^="patchsvg"].editmode .comment .border { 279 | stroke: #7569d7; 280 | stroke-dasharray: 8 4; 281 | } 282 | 283 | /* A little hack for special case of [cnv]. 284 | All other iemguis have a black border, but 285 | [cnv] sets its selection rectangle to the 286 | user-supplied fill color when the object 287 | isn't selected */ 288 | .iemgui .border:not(.mycanvas_border) { 289 | stroke: #7569d7; 290 | } 291 | 292 | .graph .border { 293 | stroke: #777; 294 | fill: none; 295 | } 296 | 297 | /* Graph (or subpatch) that has been opened to inspect its contents */ 298 | .graph.has_window .border { 299 | stroke: #7569d7; 300 | fill: #7569d7; 301 | } 302 | 303 | /* border color for selected objects 304 | * an element with the class "border" 305 | * the element is contained within a parent element of class "selected" 306 | * that parent element is not in class "gop" 307 | in plain English: 308 | This lets us highlight an object's border, unless it is inside a gop 309 | canvas. 310 | */ 311 | :not(.gop).selected .border { 312 | stroke: #cc9933; 313 | display: inline; 314 | } 315 | 316 | /* text inside selected objects */ 317 | :not(.gop).selected text { 318 | fill: #cc9933; 319 | } 320 | 321 | /* for an object that didn't create */ 322 | .obj .border.broken_border { 323 | fill: #3e32a2; 324 | stroke: #ff9933; 325 | stroke-dasharray: 3 2; 326 | } 327 | 328 | /* control inlet */ 329 | .xlet_control { 330 | stroke: #7c71da; 331 | fill: #7c71da; 332 | // stroke-width: 1; 333 | } 334 | 335 | /* signal inlet */ 336 | .xlet_signal { 337 | stroke: #7569d7; 338 | fill: #7569d7; 339 | stroke-width: 1; 340 | } 341 | 342 | /* iemgui inlet or outlet */ 343 | .xlet_iemgui { 344 | stroke: #7569d7; 345 | fill: #7569d7; 346 | stroke-width: 1; 347 | } 348 | 349 | /* text label for an iemgui */ 350 | .iemgui_label_selected { 351 | fill: blue; 352 | } 353 | 354 | /* test of xlet hover animation... this should 355 | probably use the web animation API instead. That 356 | way the animation won't get cut off when you 357 | move off the object */ 358 | @-webkit-keyframes fizzle { 359 | 0% { 360 | stroke-width: 1; 361 | stroke-opacity: 1; 362 | rx: 1; 363 | ry: 1; 364 | } 365 | 100% { 366 | stroke-width: 20; 367 | stroke-opacity: 0.2; 368 | rx: 50; 369 | ry: 50; 370 | } 371 | } 372 | 373 | /* can't remember why this was tagged !important */ 374 | .xlet_selected { 375 | stroke: #cc9933 !important; 376 | fill: #7569d7; 377 | -webkit-animation: fizzle 0.5s linear 1; 378 | } 379 | 380 | #canvas_find { 381 | width: 100%; 382 | height: 1em; 383 | padding: 3px; 384 | background: silver; 385 | position: fixed; 386 | bottom: 0; 387 | left: 0; 388 | } 389 | 390 | /* Dialog to ask to save the patch before quitting */ 391 | #save_before_quit { 392 | color: white; 393 | background-color: #3e32a2; 394 | border:3px solid #cc9933; 395 | padding: 12px; 396 | margin: 12px; 397 | box-shadow: 7px 7px 5px black; 398 | } 399 | 400 | /* Search dialog */ 401 | 402 | .search_body { 403 | font-family: "DejaVu Sans", sans-serif; 404 | font-size: 10pt; 405 | padding: 8px; 406 | } 407 | 408 | /* Common to all dialogs */ 409 | 410 | .dialog_body { 411 | font-family: "DejaVu Sans", sans-serif; 412 | font-size: 10pt; 413 | background-color: #3e32a2; 414 | } 415 | 416 | .submit_buttons { 417 | text-align: center; 418 | padding: 8px; 419 | } 420 | 421 | fieldset { 422 | color: #a49aea; 423 | background-color: #3e32a2; 424 | border-radius:3px; 425 | border:1px solid #cc9933; 426 | margin-left:auto; 427 | margin-right:auto; 428 | padding: 10px; 429 | } 430 | 431 | .hidden { 432 | display: none; 433 | } 434 | 435 | .container{ 436 | display: none; 437 | } 438 | 439 | /* Iemgui dialog */ 440 | 441 | #iemgui_dialog_body { 442 | font-family:Verdana; 443 | margin: 0px; 444 | } 445 | 446 | input[type="text"]{ 447 | width:3em; 448 | } 449 | 450 | input[type="number"]{ 451 | width:3em; 452 | } 453 | 454 | label { 455 | text-align: right; 456 | } 457 | 458 | /* Pair of properties that are related */ 459 | .pair { 460 | width: 75%; 461 | text-align: left; 462 | align: left; 463 | } 464 | 465 | .item1 { 466 | width: 50%; 467 | } 468 | 469 | .item2 { 470 | width: 50%; 471 | } 472 | 473 | input[name="x_offset"] { 474 | width: 2em; 475 | } 476 | 477 | input[name="y_offset"] { 478 | width: 2em; 479 | } 480 | 481 | input[name="send_symbol"] { 482 | width: 8em; 483 | } 484 | 485 | input[name="receive_symbol"] { 486 | width: 8em; 487 | } 488 | 489 | input[name="label"] { 490 | width: 8em; 491 | } 492 | 493 | input[name="font_size"] { 494 | width: 3em; 495 | } 496 | 497 | input[name="startup_flags"] { 498 | width: 16em; 499 | } 500 | 501 | /* Canvas dialog */ 502 | 503 | div.x-scale { 504 | padding: 3px; 505 | text-align: center; 506 | } 507 | 508 | div.gop-range { 509 | } 510 | 511 | div.y1 { 512 | text-align: center; 513 | padding: 3px; 514 | } 515 | 516 | div.x1 { 517 | text-align: center; 518 | padding: 3px; 519 | } 520 | 521 | div.y2 { 522 | text-align: center; 523 | padding: 3px; 524 | } 525 | 526 | .disabled { 527 | color: #aaa; 528 | } 529 | 530 | /* Preferences dialog */ 531 | 532 | #prefs_html_element { 533 | /* height: 100%; */ 534 | margin: 0px; 535 | padding: 0px; 536 | height: 100vh; 537 | } 538 | 539 | .prefs_body { 540 | padding: 0px; 541 | } 542 | 543 | #prefs_container { 544 | display: table; 545 | } 546 | 547 | /* Main tab widget */ 548 | 549 | /* All the display, width, and height settings below are a house of cards. 550 | I don't have the schooling to actually predict how all these CSS elements 551 | work together to create the whole. I just fudged around until I found a 552 | way to get the buttons anchored at the bottom of the dialog without 553 | triggering scrollbars to appear. If someone knows a way to do it "right" 554 | without becoming an order of magnitude more complex, do feel free... */ 555 | .prefs_tab_group { 556 | display: table; 557 | width: 90%; 558 | } 559 | 560 | /* Configure the radio buttons to hide off-screen */ 561 | .prefs_tab { 562 | position: absolute; 563 | left:-100px; 564 | top:-100px; 565 | } 566 | 567 | /* Configure labels to look like tabs */ 568 | .prefs_tab + label { 569 | /* inline-block such that the label can be given dimensions */ 570 | display: inline-block; 571 | /* A nice curved border around the tab */ 572 | border: 1px solid #bbb; 573 | border-top-left-radius: 5px; 574 | border-top-right-radius: 5px; 575 | /* the bottom border is handled by the tab content div */ 576 | border-bottom: 0; 577 | /* Padding around tab text */ 578 | padding: 5px 10px; 579 | /* put a small margin to the left to make the first tab clear */ 580 | margin-left: 4px; 581 | margin-top: 8px; 582 | margin-bottom: 0px; 583 | /* Set the background color to default gray (non-selected tab) */ 584 | background-color:#7569d7; 585 | } 586 | 587 | /* Focused tabs */ 588 | .prefs_tab:focus + label { 589 | border: 1px dashed #bbb; 590 | } 591 | 592 | /* Checked tabs must be white with the bottom border removed */ 593 | .prefs_tab:checked + label { 594 | background-color: #cc9933; 595 | text-shadow: 1px 0px 0px; /* substitute for "bold" to retain div width */ 596 | border-bottom: 1px solid #f3f3f3; 597 | margin-bottom: -1px; 598 | } 599 | 600 | /* The tab content must fill the widgets size and have a nice border */ 601 | .prefs_tab_group > div { 602 | display: none; 603 | border-top: 1px solid #ddd; 604 | padding: 0px; 605 | margin: 0px; 606 | height: 100%; 607 | } 608 | 609 | /* This matches tabs displaying to their associated radio inputs */ 610 | .tab1:checked ~ .tab1, .tab2:checked ~ .tab2, .tab3:checked ~ .tab3, .tab4:checked ~ .tab4 { 611 | display: table; 612 | padding: 8px; 613 | line-height: 20px; 614 | width: 100%; 615 | height: 78vh; 616 | } 617 | 618 | .tab_settings { 619 | padding-top: 8px; 620 | color: #a49aea; 621 | } 622 | 623 | /* Sample rate input */ 624 | input[name="rate"] { 625 | width: 4em; 626 | } 627 | 628 | #prefs_buttons { 629 | display: table; 630 | height: 10vh; 631 | padding: 0px; 632 | margin: 0px; 633 | margin-top: -10px; 634 | margin-bottom: -10px; 635 | padding: 30px; 636 | } 637 | -------------------------------------------------------------------------------- /css/extended.css: -------------------------------------------------------------------------------- 1 | /* Global CSS */ 2 | 3 | /* 4 | @font-face { 5 | font-family: "DejaVu Sans Mono"; 6 | src: url("../DejaVuSansMono.ttf"); 7 | } 8 | */ 9 | 10 | body { 11 | margin: 0px; 12 | font-family: "DejaVu Sans Mono"; 13 | } 14 | 15 | .noselect { 16 | -webkit-touch-callout: none; 17 | -webkit-user-select: none; 18 | -khtml-user-select: none; 19 | -moz-user-select: none; 20 | -ms-user-select: none; 21 | user-select: none; 22 | } 23 | 24 | ::selection { 25 | background: #c3c3c3; 26 | color: black; 27 | } 28 | 29 | /* The main Pd Window */ 30 | 31 | #console_controls { 32 | background-color: LightGray; 33 | height: 50px; 34 | } 35 | 36 | #control_frame { 37 | padding: 12px; 38 | } 39 | 40 | #printout { 41 | margin: 8px; 42 | } 43 | 44 | #console_bottom { 45 | position: absolute; 46 | top: 50px; 47 | left: 0px; 48 | right: 0px; 49 | bottom: 0px; 50 | overflow-y: scroll; 51 | } 52 | 53 | /* The console API allows classes for different types of messages to print. 54 | Currently the only class is "error". More may be added, especially once 55 | we port the "loglevel" functionality that was available in Pd Extended. */ 56 | #console_bottom .error { 57 | color: red; 58 | } 59 | 60 | /* Find bar */ 61 | 62 | #console_find label, #canvas_find label { 63 | font-family: "DejaVu Sans", sans-serif; 64 | font-size: 10pt; 65 | } 66 | 67 | /* marks for matches to console_find */ 68 | mark { 69 | background: white !important; 70 | padding: 0 !important; 71 | } 72 | 73 | mark.console_find_current.console_find_highlighted, 74 | mark.console_find_current { 75 | background: yellow !important; 76 | } 77 | 78 | mark.console_find_highlighted { 79 | background: #6bd4e6 !important; 80 | } 81 | 82 | #console_find { 83 | width: 100%; 84 | height: 1em; 85 | padding: 0.2em; 86 | background: silver; 87 | position: fixed; 88 | bottom: 0; 89 | left: 0; 90 | } 91 | 92 | /* Pure Data Patch Window (aka canvas) */ 93 | 94 | /* patch font and background color. (Note: margin needs to stay at zero.) */ 95 | .patch_body { 96 | font-family: "DejaVu Sans Mono"; 97 | } 98 | 99 | #selection_rectangle { 100 | stroke: black; 101 | } 102 | 103 | /* The outline to show the visible area for a Graph-On-Parent canvas, 104 | i.e., the "red rectangle" */ 105 | .gop_rect { 106 | fill: none; 107 | stroke: red; 108 | } 109 | 110 | .cord.signal { 111 | stroke-width: 2; 112 | stroke: #828297; 113 | } 114 | 115 | .cord.control { 116 | stroke-width: 1; 117 | stroke: #565; 118 | } 119 | 120 | /* selected connection between objects */ 121 | .cord.signal.selected_line, 122 | .cord.control.selected_line { 123 | stroke: blue; 124 | } 125 | 126 | #cord_inspector_rect { 127 | fill: black; 128 | stroke: black; 129 | } 130 | 131 | #cord_inspector_text { 132 | fill: white; 133 | } 134 | 135 | #cord_inspector_text.flash { 136 | fill: #e87216; 137 | } 138 | 139 | /* text inside boxes: message boxes, object boxes, graphs, comments, etc. */ 140 | .box_text { 141 | fill: black; 142 | } 143 | 144 | /* hyperlinks: for now, just pddplink and helplink */ 145 | .pd_link text { 146 | fill: blue; 147 | } 148 | 149 | .pd_link text:hover { 150 | fill: red; 151 | } 152 | 153 | .pd_link.selected text { 154 | fill: #e87216 !important; 155 | } 156 | 157 | #new_object_textentry { 158 | /* max-width: 10ch; */ 159 | min-width: 3ch; 160 | position: absolute; 161 | display: table-cell; 162 | padding: 3px 2px 3px 2px; 163 | /* box-shadow: inset 1px 0px 0px 1px #000; */ 164 | background-color: transparent; 165 | white-space: pre-wrap; 166 | overflow-wrap: break-word; 167 | -webkit-margin-before: 0px; 168 | } 169 | 170 | #new_object_textentry.obj { 171 | outline: 1px solid blue; 172 | } 173 | 174 | #new_object_textentry.msg { 175 | outline: 0px solid blue; 176 | background-image: url(../msg-box.svg); 177 | } 178 | 179 | p.msg::after { 180 | content: ""; 181 | height: 100%; 182 | width: 5px; 183 | background-image: url(../msg-box-flag.svg); 184 | position: absolute; 185 | top: 0%; 186 | left: 100%; 187 | } 188 | 189 | /* not sure what this is doing here... */ 190 | text { 191 | // fill: red; 192 | //cursor: default; 193 | } 194 | 195 | /* not sure if this is still needed */ 196 | .selected_border { 197 | stroke: blue; 198 | stroke-dasharray: none; 199 | stroke-width: 1; 200 | } 201 | 202 | .msg .border { 203 | stroke: #c1c1c1; 204 | fill: #f8f8f6; 205 | } 206 | 207 | /* state of msg box when clicking it */ 208 | .msg.flashed .border { 209 | stroke-width: 4; 210 | } 211 | 212 | /* atom box */ 213 | .atom .border { 214 | stroke: #c1c1c1; 215 | fill: #e0e0e0; 216 | } 217 | 218 | /* for dropdown box we want to visually distinguish boxes that output 219 | the index from boxes that output the value. For now we do that by 220 | stroking the arrow for boxes that output an index. For boxes that 221 | output the value we don't need a CSS rule, as the arrow will be filled 222 | black by default */ 223 | .atom .index_arrow { 224 | stroke: black; 225 | stroke-width: 1; 226 | fill: none; 227 | } 228 | 229 | /* gatom "activated" text (i.e., when it has the keyboard focus) */ 230 | .atom.activated text { 231 | fill: red; 232 | } 233 | 234 | #dropdown_list { 235 | position: absolute; 236 | border-width: 1px; 237 | border-style: solid; 238 | border-color: #c3c3c3; 239 | cursor: pointer; 240 | box-shadow: 5px 0 5px -5px #888, 0 5px 5px -5px #888, -5px 0 5px -5px #888; 241 | overflow-y: auto; 242 | } 243 | 244 | #dropdown_list ol { 245 | list-style-position: inside; 246 | margin: 0; 247 | padding: 0; 248 | background: #eee; 249 | } 250 | 251 | #dropdown_list li { 252 | list-style-type: none; 253 | padding: 5px; 254 | } 255 | 256 | #dropdown_list li.highlighted { 257 | background: #c3c3c3; 258 | } 259 | 260 | .obj .border { 261 | fill: #f6f8f8; 262 | stroke: #c1c1c1; 263 | } 264 | 265 | .comment .border { 266 | fill: none; 267 | } 268 | 269 | svg[id^="patchsvg"].editmode .comment .border { 270 | stroke: #aaa; 271 | stroke-dasharray: 8 4; 272 | } 273 | 274 | /* A little hack for special canvas of [cnv]. 275 | All other iemguis have a black border, but 276 | [cnv] sets its selection rectangle to the 277 | user-supplied fill color when the object 278 | isn't selected */ 279 | .iemgui .border:not(.mycanvas_border) { 280 | stroke: black; 281 | } 282 | 283 | .graph .border { 284 | stroke: #777; 285 | fill: none; 286 | } 287 | 288 | /* Graph (or subpatch) that has been opened to inspect its contents */ 289 | .graph.has_window .border { 290 | stroke: black; 291 | fill: gray; 292 | } 293 | 294 | /* border color for selected objects 295 | * an element with the class "border" 296 | * the element is contained within a parent element of class "selected" 297 | * that parent element is not in class "gop" 298 | in plain English: 299 | This lets us highlight an object's border, unless it is inside a gop 300 | canvas. 301 | */ 302 | :not(.gop).selected .border { 303 | stroke: blue; 304 | display: inline; 305 | } 306 | 307 | /* text inside selected objects */ 308 | :not(.gop).selected text { 309 | fill: blue; 310 | } 311 | 312 | /* for an object that didn't create */ 313 | .obj .border.broken_border { 314 | fill: #f7f7f7; 315 | stroke: #f00; 316 | stroke-dasharray: 3 2; 317 | } 318 | 319 | /* control inlet */ 320 | .xlet_control { 321 | stroke: #536253; 322 | fill: white; 323 | // stroke-width: 1; 324 | } 325 | 326 | /* signal inlet */ 327 | .xlet_signal { 328 | stroke: #828297; 329 | fill: #808095; 330 | stroke-width: 1; 331 | } 332 | 333 | /* iemgui inlet or outlet */ 334 | .xlet_iemgui { 335 | stroke: black; 336 | fill: black; 337 | stroke-width: 1; 338 | } 339 | 340 | /* text label for an iemgui */ 341 | .iemgui_label_selected { 342 | fill: blue; 343 | } 344 | 345 | /* test of xlet hover animation... this should 346 | probably use the web animation API instead. That 347 | way the animation won't get cut off when you 348 | move off the object */ 349 | @-webkit-keyframes fizzle { 350 | 0% { 351 | stroke-width: 1; 352 | stroke-opacity: 1; 353 | rx: 1; 354 | ry: 1; 355 | } 356 | 100% { 357 | stroke-width: 20; 358 | stroke-opacity: 0.2; 359 | rx: 50; 360 | ry: 50; 361 | } 362 | } 363 | 364 | /* can't remember why this was tagged !important */ 365 | .xlet_selected { 366 | stroke: blue !important; 367 | fill: blue; 368 | -webkit-animation: fizzle 0.5s linear 1; 369 | } 370 | 371 | #canvas_find { 372 | width: 100%; 373 | height: 1em; 374 | padding: 3px; 375 | background: silver; 376 | position: fixed; 377 | bottom: 0; 378 | left: 0; 379 | } 380 | 381 | /* Search dialog */ 382 | 383 | .search_body { 384 | font-family: "DejaVu Sans", sans-serif; 385 | font-size: 10pt; 386 | padding: 8px; 387 | } 388 | 389 | /* Common to all dialogs */ 390 | 391 | .dialog_body { 392 | font-family: "DejaVu Sans", sans-serif; 393 | font-size: 10pt; 394 | background-color: #f3f3f3; 395 | } 396 | 397 | .submit_buttons { 398 | text-align: center; 399 | padding: 8px; 400 | } 401 | 402 | fieldset { 403 | background-color:#eeeeee; 404 | border-radius:3px; 405 | border:2px solid black; 406 | margin-left:auto; 407 | margin-right:auto; 408 | padding: 10px; 409 | } 410 | 411 | .hidden { 412 | display: none; 413 | } 414 | 415 | .container{ 416 | display: none; 417 | } 418 | 419 | /* Iemgui dialog */ 420 | 421 | input[type="text"]{ 422 | width:3em; 423 | } 424 | 425 | input[type="number"]{ 426 | width:3em; 427 | } 428 | 429 | label { 430 | text-align: right; 431 | } 432 | 433 | /* Pair of properties that are related */ 434 | .pair { 435 | width: 75%; 436 | text-align: left; 437 | align: left; 438 | } 439 | 440 | .item1 { 441 | width: 50%; 442 | } 443 | 444 | .item2 { 445 | width: 50%; 446 | } 447 | 448 | input[name="x_offset"] { 449 | width: 2em; 450 | } 451 | 452 | input[name="y_offset"] { 453 | width: 2em; 454 | } 455 | 456 | input[name="send_symbol"] { 457 | width: 8em; 458 | } 459 | 460 | input[name="receive_symbol"] { 461 | width: 8em; 462 | } 463 | 464 | input[name="label"] { 465 | width: 8em; 466 | } 467 | 468 | input[name="font_size"] { 469 | width: 3em; 470 | } 471 | 472 | input[name="startup_flags"] { 473 | width: 16em; 474 | } 475 | 476 | /* Canvas dialog */ 477 | 478 | div.x-scale { 479 | padding: 3px; 480 | text-align: center; 481 | } 482 | 483 | div.gop-range { 484 | } 485 | 486 | div.y1 { 487 | text-align: center; 488 | padding: 3px; 489 | } 490 | 491 | div.x1 { 492 | text-align: center; 493 | padding: 3px; 494 | } 495 | 496 | div.y2 { 497 | text-align: center; 498 | padding: 3px; 499 | } 500 | 501 | .disabled { 502 | color: #aaa; 503 | } 504 | 505 | /* Preferences dialog */ 506 | 507 | #prefs_html_element { 508 | /* height: 100%; */ 509 | margin: 0px; 510 | padding: 0px; 511 | height: 100vh; 512 | } 513 | 514 | .prefs_body { 515 | padding: 0px; 516 | } 517 | 518 | #prefs_container { 519 | display: table; 520 | } 521 | 522 | /* Main tab widget */ 523 | 524 | /* All the display, width, and height settings below are a house of cards. 525 | I don't have the schooling to actually predict how all these CSS elements 526 | work together to create the whole. I just fudged around until I found a 527 | way to get the buttons anchored at the bottom of the dialog without 528 | triggering scrollbars to appear. If someone knows a way to do it "right" 529 | without becoming an order of magnitude more complex, do feel free... */ 530 | .prefs_tab_group { 531 | display: table; 532 | width: 90%; 533 | } 534 | 535 | /* Configure the radio buttons to hide off-screen */ 536 | .prefs_tab { 537 | position: absolute; 538 | left:-100px; 539 | top:-100px; 540 | } 541 | 542 | /* Configure labels to look like tabs */ 543 | .prefs_tab + label { 544 | /* inline-block such that the label can be given dimensions */ 545 | display: inline-block; 546 | /* A nice curved border around the tab */ 547 | border: 1px solid #bbb; 548 | border-top-left-radius: 5px; 549 | border-top-right-radius: 5px; 550 | /* the bottom border is handled by the tab content div */ 551 | border-bottom: 0; 552 | /* Padding around tab text */ 553 | padding: 5px 10px; 554 | /* put a small margin to the left to make the first tab clear */ 555 | margin-left: 4px; 556 | margin-top: 8px; 557 | margin-bottom: 0px; 558 | /* Set the background color to default gray (non-selected tab) */ 559 | background-color:#ececec; 560 | } 561 | 562 | /* Focused tabs */ 563 | .prefs_tab:focus + label { 564 | border: 1px dashed #bbb; 565 | } 566 | 567 | /* Checked tabs must be white with the bottom border removed */ 568 | .prefs_tab:checked + label { 569 | background-color: #f3f3f3; 570 | text-shadow: 1px 0px 0px; /* substitute for "bold" to retain div width */ 571 | border-bottom: 1px solid #f3f3f3; 572 | margin-bottom: -1px; 573 | } 574 | 575 | /* The tab content must fill the widgets size and have a nice border */ 576 | .prefs_tab_group > div { 577 | display: none; 578 | border-top: 1px solid #ddd; 579 | padding: 0px; 580 | margin: 0px; 581 | height: 100%; 582 | } 583 | 584 | /* This matches tabs displaying to their associated radio inputs */ 585 | .tab1:checked ~ .tab1, .tab2:checked ~ .tab2, .tab3:checked ~ .tab3, .tab4:checked ~ .tab4 { 586 | display: table; 587 | padding: 8px; 588 | line-height: 20px; 589 | width: 100%; 590 | height: 78vh; 591 | } 592 | 593 | .tab_settings { 594 | padding-top: 8px; 595 | } 596 | 597 | /* Sample rate input */ 598 | input[name="rate"] { 599 | width: 4em; 600 | } 601 | 602 | #prefs_buttons { 603 | display: table; 604 | height: 10vh; 605 | padding: 0px; 606 | margin: 0px; 607 | margin-top: -10px; 608 | margin-bottom: -10px; 609 | padding: 30px; 610 | } 611 | -------------------------------------------------------------------------------- /css/solarized.css: -------------------------------------------------------------------------------- 1 | /* Global CSS */ 2 | 3 | /* 4 | @font-face { 5 | font-family: "DejaVu Sans Mono"; 6 | src: url("../DejaVuSansMono.ttf"); 7 | } 8 | */ 9 | 10 | body { 11 | margin: 0px; 12 | font-family: "DejaVu Sans Mono"; 13 | } 14 | 15 | .noselect { 16 | -webkit-touch-callout: none; 17 | -webkit-user-select: none; 18 | -khtml-user-select: none; 19 | -moz-user-select: none; 20 | -ms-user-select: none; 21 | user-select: none; 22 | } 23 | 24 | ::selection { 25 | background: #eee8d5; 26 | color: #657b83; 27 | } 28 | 29 | /* The main Pd Window */ 30 | 31 | #console_controls { 32 | color: #657b83; 33 | background-color: #eee8d5; 34 | height: 50px; 35 | } 36 | 37 | #control_frame { 38 | padding: 12px; 39 | } 40 | 41 | #printout { 42 | margin: 8px; 43 | } 44 | 45 | #console_bottom { 46 | position: absolute; 47 | top: 50px; 48 | left: 0px; 49 | right: 0px; 50 | bottom: 0px; 51 | overflow-y: scroll; 52 | background-color: #fdf6e3; 53 | color: #657b83; 54 | } 55 | 56 | /* The console API allows classes for different types of messages to print. 57 | Currently the only class is "error". More may be added, especially once 58 | we port the "loglevel" functionality that was available in Pd Extended. */ 59 | #console_bottom .error { 60 | color: #586e75; 61 | } 62 | 63 | #console_bottom .error a { 64 | color: #268bd2; 65 | font-weight: 600; 66 | } 67 | 68 | /* Find bar */ 69 | 70 | #console_find label, #canvas_find label { 71 | font-family: "DejaVu Sans", sans-serif; 72 | font-size: 10pt; 73 | } 74 | 75 | /* marks for matches to console_find */ 76 | mark { 77 | background: #eee8d5 !important; 78 | padding: 0 !important; 79 | } 80 | 81 | mark.console_find_current.console_find_highlighted, 82 | mark.console_find_current { 83 | background: #b58900 !important; 84 | } 85 | 86 | mark.console_find_highlighted { 87 | background: #6bd4e6 !important; 88 | } 89 | 90 | #console_find { 91 | width: 100%; 92 | height: 1em; 93 | padding: 0.2em; 94 | background: #eee8d5; 95 | position: fixed; 96 | bottom: 0; 97 | left: 0; 98 | color: #586e75; 99 | } 100 | 101 | /* Pure Data Patch Window (aka canvas) */ 102 | 103 | /* patch font and background color. (Note: margin needs to stay at zero.) */ 104 | .patch_body { 105 | background-color: #fdf6e3; 106 | } 107 | 108 | #selection_rectangle { 109 | stroke: #073642; 110 | } 111 | 112 | /* The outline to show the visible area for a Graph-On-Parent canvas, 113 | i.e., the "red rectangle" */ 114 | .gop_rect { 115 | fill: none; 116 | stroke: #dc322f; 117 | stroke-opacity: 0.4; 118 | } 119 | 120 | .cord.signal { 121 | stroke-width: 2; 122 | stroke: #93a1a1; 123 | } 124 | 125 | .cord.control { 126 | stroke-width: 1; 127 | stroke: #93a1a1; 128 | } 129 | 130 | /* selected connection between objects */ 131 | .cord.signal.selected_line, 132 | .cord.control.selected_line, 133 | #newcord { 134 | stroke: #268bd2; 135 | } 136 | 137 | #cord_inspector_rect { 138 | fill: #93a1a1; 139 | stroke: #93a1a1; 140 | } 141 | 142 | #cord_inspector_text { 143 | fill: white; 144 | } 145 | 146 | #cord_inspector_text.flash { 147 | fill: #e87216; 148 | } 149 | 150 | /* text inside boxes: message boxes, object boxes, graphs, comments, etc. */ 151 | .box_text { 152 | fill: #657b83; 153 | } 154 | 155 | /* hyperlinks: for now, just pddplink and helplink */ 156 | .pd_link text { 157 | fill: blue; 158 | } 159 | 160 | .pd_link text:hover { 161 | fill: red; 162 | } 163 | 164 | .pd_link.selected text { 165 | fill: white; 166 | } 167 | 168 | #new_object_textentry { 169 | /* max-width: 10ch; */ 170 | min-width: 3ch; 171 | position: absolute; 172 | display: table-cell; 173 | padding: 3px 2px 3px 2px; 174 | /* box-shadow: inset 1px 0px 0px 1px #000; */ 175 | background-color: transparent; 176 | white-space: pre-wrap; 177 | overflow-wrap: break-word; 178 | -webkit-margin-before: 0px; 179 | color: #586e75; 180 | } 181 | 182 | #new_object_textentry.obj { 183 | outline: 1px solid #268bd2; 184 | } 185 | 186 | #new_object_textentry.msg { 187 | outline: 0px solid #268bd2; 188 | background-image: url(../msg-box.svg); 189 | } 190 | 191 | p.msg::after { 192 | content: ""; 193 | height: 100%; 194 | width: 5px; 195 | background-image: url(../msg-box-flag.svg); 196 | position: absolute; 197 | top: 0%; 198 | left: 100%; 199 | } 200 | 201 | /* not sure what this is doing here... */ 202 | text { 203 | // fill: red; 204 | //cursor: default; 205 | } 206 | 207 | /* not sure if this is still needed */ 208 | .selected_border { 209 | stroke: blue; 210 | stroke-dasharray: none; 211 | stroke-width: 1; 212 | } 213 | 214 | .msg .border { 215 | stroke: #93a1a1; 216 | fill: #fdf6e3; 217 | } 218 | 219 | /* state of msg box when clicking it */ 220 | .msg.flashed .border { 221 | stroke-width: 4; 222 | } 223 | 224 | /* atom box */ 225 | .atom .border { 226 | stroke: #93a1a1; 227 | fill: #fdf6e3; 228 | } 229 | 230 | /* for dropdown box we want to visually distinguish boxes that output 231 | the index from boxes that output the value. For now we do that by 232 | stroking the arrow for boxes that output an index. For boxes that 233 | output the value we don't need a CSS rule, as the arrow will be filled 234 | black by default */ 235 | .atom .index_arrow { 236 | stroke: #93a1a1; 237 | stroke-width: 1; 238 | fill: none; 239 | } 240 | 241 | .atom .value_arrow { 242 | stroke: #93a1a1; 243 | fill: #93a1a1; 244 | } 245 | 246 | /* gatom "activated" text (i.e., when it has the keyboard focus) */ 247 | .atom.activated text { 248 | fill: #dc322f; 249 | } 250 | 251 | #dropdown_list { 252 | position: absolute; 253 | border-width: 1px; 254 | border-style: solid; 255 | border-color: #93a1a1; 256 | cursor: pointer; 257 | color: #586e75; 258 | overflow-y: auto; 259 | } 260 | 261 | #dropdown_list ol { 262 | list-style-position: inside; 263 | margin: 0; 264 | padding: 0; 265 | background: #fdf6e3; 266 | } 267 | 268 | #dropdown_list li { 269 | list-style-type: none; 270 | padding: 5px; 271 | } 272 | 273 | #dropdown_list li.highlighted { 274 | background: #eee8d5; 275 | } 276 | 277 | .obj .border { 278 | fill: #fdf6e3; 279 | stroke: #93a1a1; 280 | } 281 | 282 | .comment .border { 283 | fill: none; 284 | } 285 | 286 | svg[id^="patchsvg"].editmode .comment .border { 287 | stroke: #94b2b2; 288 | stroke-dasharray: 8 4; 289 | } 290 | 291 | /* A little hack for special canvas of [cnv]. 292 | All other iemguis have a black border, but 293 | [cnv] sets its selection rectangle to the 294 | user-supplied fill color when the object 295 | isn't selected */ 296 | .iemgui .border:not(.mycanvas_border) { 297 | stroke: #93a1a1; 298 | } 299 | 300 | .graph .border { 301 | stroke: #93a1a1; 302 | fill: none; 303 | } 304 | 305 | /* Graph (or subpatch) that has been opened to inspect its contents */ 306 | .graph.has_window .border { 307 | stroke: #93a1a1; 308 | fill: #eee8d5; 309 | } 310 | 311 | /* border color for selected objects 312 | * an element with the class "border" 313 | * the element is contained within a parent element of class "selected" 314 | * that parent element is not in class "gop" 315 | in plain English: 316 | This lets us highlight an object's border, unless it is inside a gop 317 | canvas. 318 | */ 319 | :not(.gop).selected .border { 320 | stroke: #268bd2; 321 | display: inline; 322 | } 323 | 324 | /* text inside selected objects */ 325 | :not(.gop).selected text { 326 | fill: #268bd2; 327 | } 328 | 329 | /* for an object that didn't create */ 330 | .obj .border.broken_border { 331 | fill: transparent; 332 | stroke: #dc322f; 333 | stroke-dasharray: 3 2; 334 | } 335 | 336 | /* control inlet */ 337 | .xlet_control { 338 | stroke: #657b83; 339 | fill: #fdf6e3; 340 | } 341 | 342 | /* signal inlet */ 343 | .xlet_signal { 344 | stroke: #657b83; 345 | fill: #657b83; 346 | stroke-width: 1; 347 | } 348 | 349 | /* iemgui inlet or outlet */ 350 | .xlet_iemgui { 351 | stroke: #657b83; 352 | fill: #fdf6e3; 353 | stroke-width: 1; 354 | } 355 | 356 | /* text label for an iemgui */ 357 | .iemgui_label_selected { 358 | fill: #268bd2; 359 | } 360 | 361 | /* test of xlet hover animation... this should 362 | probably use the web animation API instead. That 363 | way the animation won't get cut off when you 364 | move off the object */ 365 | @-webkit-keyframes fizzle { 366 | 0% { 367 | stroke-width: 1; 368 | stroke-opacity: 1; 369 | rx: 1; 370 | ry: 1; 371 | } 372 | 100% { 373 | stroke-width: 20; 374 | stroke-opacity: 0.2; 375 | rx: 50; 376 | ry: 50; 377 | } 378 | } 379 | 380 | /* can't remember why this was tagged !important */ 381 | .xlet_selected { 382 | stroke: gray !important; 383 | fill: gray; 384 | -webkit-animation: fizzle 0.5s linear 1; 385 | } 386 | 387 | #canvas_find { 388 | width: 100%; 389 | height: 1em; 390 | padding: 3px; 391 | background: #eee8d5; 392 | position: fixed; 393 | bottom: 0; 394 | left: 0; 395 | color: #586e75; 396 | } 397 | 398 | /* Dialog to ask to save the patch before quitting */ 399 | #save_before_quit { 400 | background-color: #fdf6e3; 401 | border:1px solid #eee8d5; 402 | padding: 12px; 403 | margin: 12px; 404 | box-shadow: 7px 7px 5px grey; 405 | } 406 | 407 | /* Search dialog */ 408 | 409 | .search_body { 410 | font-family: "DejaVu Sans", sans-serif; 411 | font-size: 10pt; 412 | padding: 8px; 413 | background: #fdf6e3; 414 | color: #657b83; 415 | } 416 | 417 | .search_body a { 418 | color: #268bd2; 419 | } 420 | 421 | /* Common to all dialogs */ 422 | 423 | .dialog_body { 424 | font-family: "DejaVu Sans", sans-serif; 425 | font-size: 10pt; 426 | background: #fdf6e3; 427 | } 428 | 429 | .submit_buttons { 430 | text-align: center; 431 | padding: 8px; 432 | } 433 | 434 | fieldset { 435 | border-radius:3px; 436 | border:2px solid #eee8d5; 437 | margin-left:auto; 438 | margin-right:auto; 439 | padding: 10px; 440 | } 441 | 442 | .hidden { 443 | display: none; 444 | } 445 | 446 | .container{ 447 | display: none; 448 | } 449 | 450 | /* Iemgui dialog */ 451 | 452 | input[type="text"]{ 453 | width:3em; 454 | } 455 | 456 | input[type="number"]{ 457 | width:3em; 458 | } 459 | 460 | label { 461 | text-align: right; 462 | } 463 | 464 | /* Pair of properties that are related */ 465 | .pair { 466 | width: 75%; 467 | text-align: left; 468 | align: left; 469 | } 470 | 471 | .item1 { 472 | width: 50%; 473 | } 474 | 475 | .item2 { 476 | width: 50%; 477 | } 478 | 479 | input[name="x_offset"] { 480 | width: 2em; 481 | } 482 | 483 | input[name="y_offset"] { 484 | width: 2em; 485 | } 486 | 487 | input[name="send_symbol"] { 488 | width: 8em; 489 | } 490 | 491 | input[name="receive_symbol"] { 492 | width: 8em; 493 | } 494 | 495 | input[name="label"] { 496 | width: 8em; 497 | } 498 | 499 | input[name="font_size"] { 500 | width: 3em; 501 | } 502 | 503 | input[name="startup_flags"] { 504 | width: 16em; 505 | } 506 | 507 | /* Canvas dialog */ 508 | 509 | div.x-scale { 510 | padding: 3px; 511 | text-align: center; 512 | } 513 | 514 | div.gop-range { 515 | } 516 | 517 | div.y1 { 518 | text-align: center; 519 | padding: 3px; 520 | } 521 | 522 | div.x1 { 523 | text-align: center; 524 | padding: 3px; 525 | } 526 | 527 | div.y2 { 528 | text-align: center; 529 | padding: 3px; 530 | } 531 | 532 | .disabled { 533 | color: #aaa; 534 | } 535 | 536 | /* Preferences dialog */ 537 | 538 | #prefs_html_element { 539 | /* height: 100%; */ 540 | margin: 0px; 541 | padding: 0px; 542 | height: 100vh; 543 | } 544 | 545 | .prefs_body { 546 | padding: 0px; 547 | } 548 | 549 | #prefs_container { 550 | display: table; 551 | } 552 | 553 | /* Main tab widget */ 554 | 555 | /* All the display, width, and height settings below are a house of cards. 556 | I don't have the schooling to actually predict how all these CSS elements 557 | work together to create the whole. I just fudged around until I found a 558 | way to get the buttons anchored at the bottom of the dialog without 559 | triggering scrollbars to appear. If someone knows a way to do it "right" 560 | without becoming an order of magnitude more complex, do feel free... */ 561 | .prefs_tab_group { 562 | display: table; 563 | width: 90%; 564 | } 565 | 566 | /* Configure the radio buttons to hide off-screen */ 567 | .prefs_tab { 568 | position: absolute; 569 | left:-100px; 570 | top:-100px; 571 | } 572 | 573 | /* Configure labels to look like tabs */ 574 | .prefs_tab + label { 575 | /* inline-block such that the label can be given dimensions */ 576 | display: inline-block; 577 | /* A nice curved border around the tab */ 578 | border: 1px solid #bbb; 579 | border-top-left-radius: 5px; 580 | border-top-right-radius: 5px; 581 | /* the bottom border is handled by the tab content div */ 582 | border-bottom: 0; 583 | /* Padding around tab text */ 584 | padding: 5px 10px; 585 | /* put a small margin to the left to make the first tab clear */ 586 | margin-left: 4px; 587 | margin-top: 8px; 588 | margin-bottom: 0px; 589 | /* Set the background color to default gray (non-selected tab) */ 590 | background-color:#ececec; 591 | } 592 | 593 | /* Focused tabs */ 594 | .prefs_tab:focus + label { 595 | border: 1px dashed #bbb; 596 | } 597 | 598 | /* Checked tabs must be white with the bottom border removed */ 599 | .prefs_tab:checked + label { 600 | background-color: #f3f3f3; 601 | text-shadow: 1px 0px 0px; /* substitute for "bold" to retain div width */ 602 | border-bottom: 1px solid #f3f3f3; 603 | margin-bottom: -1px; 604 | } 605 | 606 | /* The tab content must fill the widgets size and have a nice border */ 607 | .prefs_tab_group > div { 608 | display: none; 609 | border-top: 1px solid #ddd; 610 | padding: 0px; 611 | margin: 0px; 612 | height: 100%; 613 | } 614 | 615 | /* This matches tabs displaying to their associated radio inputs */ 616 | .tab1:checked ~ .tab1, .tab2:checked ~ .tab2, .tab3:checked ~ .tab3, .tab4:checked ~ .tab4 { 617 | display: table; 618 | padding: 8px; 619 | line-height: 20px; 620 | width: 100%; 621 | height: 78vh; 622 | } 623 | 624 | .tab_settings { 625 | padding-top: 8px; 626 | } 627 | 628 | /* Sample rate input */ 629 | input[name="rate"] { 630 | width: 4em; 631 | } 632 | 633 | #prefs_buttons { 634 | display: table; 635 | height: 10vh; 636 | padding: 0px; 637 | margin: 0px; 638 | margin-top: -10px; 639 | margin-bottom: -10px; 640 | padding: 30px; 641 | } 642 | -------------------------------------------------------------------------------- /css/solarized_inverted.css: -------------------------------------------------------------------------------- 1 | /* Global CSS */ 2 | 3 | /* 4 | @font-face { 5 | font-family: "DejaVu Sans Mono"; 6 | src: url("../DejaVuSansMono.ttf"); 7 | } 8 | */ 9 | 10 | body { 11 | margin: 0px; 12 | font-family: "DejaVu Sans Mono"; 13 | } 14 | 15 | .noselect { 16 | -webkit-touch-callout: none; 17 | -webkit-user-select: none; 18 | -khtml-user-select: none; 19 | -moz-user-select: none; 20 | -ms-user-select: none; 21 | user-select: none; 22 | } 23 | 24 | ::selection { 25 | background: #073642; 26 | color: #839496; 27 | } 28 | 29 | /* The main Pd Window */ 30 | 31 | #console_controls { 32 | color: #657b83; 33 | background-color: #073642; 34 | height: 50px; 35 | } 36 | 37 | #control_frame { 38 | padding: 12px; 39 | } 40 | 41 | #printout { 42 | margin: 8px; 43 | } 44 | 45 | #console_bottom { 46 | position: absolute; 47 | top: 50px; 48 | left: 0px; 49 | right: 0px; 50 | bottom: 0px; 51 | overflow-y: scroll; 52 | background-color: #002b36; 53 | color: #839496; 54 | } 55 | 56 | /* The console API allows classes for different types of messages to print. 57 | Currently the only class is "error". More may be added, especially once 58 | we port the "loglevel" functionality that was available in Pd Extended. */ 59 | #console_bottom .error { 60 | color: #93a1a1; 61 | } 62 | 63 | #console_bottom .error a { 64 | color: #b58900; 65 | font-weight: 600; 66 | } 67 | 68 | /* Find bar */ 69 | 70 | #console_find label, #canvas_find label { 71 | font-family: "DejaVu Sans", sans-serif; 72 | font-size: 10pt; 73 | } 74 | 75 | /* marks for matches to console_find */ 76 | mark { 77 | background: #eee8d5 !important; 78 | padding: 0 !important; 79 | } 80 | 81 | mark.console_find_current.console_find_highlighted, 82 | mark.console_find_current { 83 | background: #b58900 !important; 84 | } 85 | 86 | mark.console_find_highlighted { 87 | background: #6bd4e6 !important; 88 | } 89 | 90 | #console_find { 91 | width: 100%; 92 | height: 1em; 93 | padding: 0.2em; 94 | background: #073642; 95 | position: fixed; 96 | bottom: 0; 97 | left: 0; 98 | color: #586e75; 99 | } 100 | 101 | /* Pure Data Patch Window (aka canvas) */ 102 | 103 | /* patch font and background color. (Note: margin needs to stay at zero.) */ 104 | .patch_body { 105 | background-color: #002b36; 106 | } 107 | 108 | #selection_rectangle { 109 | stroke: #b58900; 110 | } 111 | 112 | /* The outline to show the visible area for a Graph-On-Parent canvas, 113 | i.e., the "red rectangle" */ 114 | .gop_rect { 115 | fill: none; 116 | stroke: #dc322f; 117 | stroke-opacity: 0.4; 118 | } 119 | 120 | .cord.signal { 121 | stroke-width: 2; 122 | stroke: #586e75; 123 | } 124 | 125 | .cord.control { 126 | stroke-width: 1; 127 | stroke: #586e75; 128 | } 129 | 130 | /* selected connection between objects */ 131 | .cord.signal.selected_line, 132 | .cord.control.selected_line, 133 | #newcord { 134 | stroke: #b58900; 135 | } 136 | 137 | #cord_inspector_rect { 138 | fill: #93a1a1; 139 | stroke: #93a1a1; 140 | } 141 | 142 | #cord_inspector_text { 143 | fill: white; 144 | } 145 | 146 | #cord_inspector_text.flash { 147 | fill: #e87216; 148 | } 149 | 150 | /* text inside boxes: message boxes, object boxes, graphs, comments, etc. */ 151 | .box_text { 152 | fill: #839496; 153 | } 154 | 155 | /* hyperlinks: for now, just pddplink and helplink */ 156 | .pd_link text { 157 | fill: blue; 158 | } 159 | 160 | .pd_link text:hover { 161 | fill: red; 162 | } 163 | 164 | .pd_link.selected text { 165 | fill: white; 166 | } 167 | 168 | #new_object_textentry { 169 | /* max-width: 10ch; */ 170 | min-width: 3ch; 171 | position: absolute; 172 | display: table-cell; 173 | padding: 3px 2px 3px 2px; 174 | /* box-shadow: inset 1px 0px 0px 1px #000; */ 175 | background-color: transparent; 176 | white-space: pre-wrap; 177 | overflow-wrap: break-word; 178 | -webkit-margin-before: 0px; 179 | color: #93a1a1; 180 | } 181 | 182 | #new_object_textentry.obj { 183 | outline: 1px solid #b58900; 184 | } 185 | 186 | #new_object_textentry.msg { 187 | outline: 0px solid #b58900; 188 | background-image: url(../msg-box.svg); 189 | } 190 | 191 | p.msg::after { 192 | content: ""; 193 | height: 100%; 194 | width: 5px; 195 | background-image: url(../msg-box-flag.svg); 196 | position: absolute; 197 | top: 0%; 198 | left: 100%; 199 | } 200 | 201 | /* not sure what this is doing here... */ 202 | text { 203 | // fill: red; 204 | //cursor: default; 205 | } 206 | 207 | /* not sure if this is still needed */ 208 | .selected_border { 209 | stroke: blue; 210 | stroke-dasharray: none; 211 | stroke-width: 1; 212 | } 213 | 214 | .msg .border { 215 | stroke: #586e75; 216 | fill: #002b36; 217 | } 218 | 219 | /* state of msg box when clicking it */ 220 | .msg.flashed .border { 221 | stroke-width: 4; 222 | } 223 | 224 | /* atom box */ 225 | .atom .border { 226 | stroke: #586e75; 227 | fill: #002b36; 228 | } 229 | 230 | /* for dropdown box we want to visually distinguish boxes that output 231 | the index from boxes that output the value. For now we do that by 232 | stroking the arrow for boxes that output an index. For boxes that 233 | output the value we don't need a CSS rule, as the arrow will be filled 234 | black by default */ 235 | .atom .index_arrow { 236 | stroke: #586e75; 237 | stroke-width: 1; 238 | fill: none; 239 | } 240 | 241 | .atom .value_arrow { 242 | stroke: #586e75; 243 | fill: #586e75; 244 | } 245 | 246 | /* gatom "activated" text (i.e., when it has the keyboard focus) */ 247 | .atom.activated text { 248 | fill: #dc322f; 249 | } 250 | 251 | #dropdown_list { 252 | position: absolute; 253 | border-width: 1px; 254 | border-style: solid; 255 | border-color: #586e75; 256 | cursor: pointer; 257 | color: #93a1a1; 258 | overflow-y: auto; 259 | } 260 | 261 | #dropdown_list ol { 262 | list-style-position: inside; 263 | margin: 0; 264 | padding: 0; 265 | background: #002b36; 266 | } 267 | 268 | #dropdown_list li { 269 | list-style-type: none; 270 | padding: 5px; 271 | } 272 | 273 | #dropdown_list li.highlighted { 274 | background: #073642; 275 | } 276 | 277 | .obj .border { 278 | fill: #002b36; 279 | stroke: #586e75; 280 | } 281 | 282 | .comment .border { 283 | fill: none; 284 | } 285 | 286 | svg[id^="patchsvg"].editmode .comment .border { 287 | stroke: #475d64; 288 | stroke-dasharray: 8 4; 289 | } 290 | 291 | /* A little hack for special canvas of [cnv]. 292 | All other iemguis have a black border, but 293 | [cnv] sets its selection rectangle to the 294 | user-supplied fill color when the object 295 | isn't selected */ 296 | .iemgui .border:not(.mycanvas_border) { 297 | stroke: #93a1a1; 298 | } 299 | 300 | .graph .border { 301 | stroke: #586e75; 302 | fill: none; 303 | } 304 | 305 | /* Graph (or subpatch) that has been opened to inspect its contents */ 306 | .graph.has_window .border { 307 | stroke: #93a1a1; 308 | fill: #eee8d5; 309 | } 310 | 311 | /* border color for selected objects 312 | * an element with the class "border" 313 | * the element is contained within a parent element of class "selected" 314 | * that parent element is not in class "gop" 315 | in plain English: 316 | This lets us highlight an object's border, unless it is inside a gop 317 | canvas. 318 | */ 319 | :not(.gop).selected .border { 320 | stroke: #b58900; 321 | display: inline; 322 | } 323 | 324 | /* text inside selected objects */ 325 | :not(.gop).selected text { 326 | fill: #b58900; 327 | } 328 | 329 | /* for an object that didn't create */ 330 | .obj .border.broken_border { 331 | fill: transparent; 332 | stroke: #dc322f; 333 | stroke-dasharray: 3 2; 334 | } 335 | 336 | /* control inlet */ 337 | .xlet_control { 338 | stroke: #586e75; 339 | fill: #002b36; 340 | } 341 | 342 | /* signal inlet */ 343 | .xlet_signal { 344 | stroke: #586e75; 345 | fill: #002b36; 346 | stroke-width: 1; 347 | } 348 | 349 | /* iemgui inlet or outlet */ 350 | .xlet_iemgui { 351 | stroke: #586e75; 352 | fill: #002b36; 353 | stroke-width: 1; 354 | } 355 | 356 | /* text label for an iemgui */ 357 | .iemgui_label_selected { 358 | fill: #268bd2; 359 | } 360 | 361 | /* test of xlet hover animation... this should 362 | probably use the web animation API instead. That 363 | way the animation won't get cut off when you 364 | move off the object */ 365 | @-webkit-keyframes fizzle { 366 | 0% { 367 | stroke-width: 1; 368 | stroke-opacity: 1; 369 | rx: 1; 370 | ry: 1; 371 | } 372 | 100% { 373 | stroke-width: 20; 374 | stroke-opacity: 0.2; 375 | rx: 50; 376 | ry: 50; 377 | } 378 | } 379 | 380 | /* can't remember why this was tagged !important */ 381 | .xlet_selected { 382 | stroke: gray !important; 383 | fill: gray; 384 | -webkit-animation: fizzle 0.5s linear 1; 385 | } 386 | 387 | #canvas_find { 388 | width: 100%; 389 | height: 1em; 390 | padding: 3px; 391 | background: #073642; 392 | position: fixed; 393 | bottom: 0; 394 | left: 0; 395 | color: #586e75; 396 | } 397 | 398 | /* Dialog to ask to save the patch before quitting */ 399 | #save_before_quit { 400 | color: white; 401 | background-color: #002b36; 402 | border:1px solid #839496; 403 | padding: 12px; 404 | margin: 12px; 405 | box-shadow: 7px 7px 5px grey; 406 | } 407 | 408 | /* Search dialog */ 409 | 410 | .search_body { 411 | font-family: "DejaVu Sans", sans-serif; 412 | font-size: 10pt; 413 | padding: 8px; 414 | background: #fdf6e3; 415 | color: #657b83; 416 | } 417 | 418 | .search_body a { 419 | color: #268bd2; 420 | } 421 | 422 | /* Common to all dialogs */ 423 | 424 | .dialog_body { 425 | font-family: "DejaVu Sans", sans-serif; 426 | font-size: 10pt; 427 | background: #fdf6e3; 428 | } 429 | 430 | .submit_buttons { 431 | text-align: center; 432 | padding: 8px; 433 | } 434 | 435 | fieldset { 436 | border-radius:3px; 437 | border:2px solid #eee8d5; 438 | margin-left:auto; 439 | margin-right:auto; 440 | padding: 10px; 441 | } 442 | 443 | .hidden { 444 | display: none; 445 | } 446 | 447 | .container{ 448 | display: none; 449 | } 450 | 451 | /* Iemgui dialog */ 452 | 453 | input[type="text"]{ 454 | width:3em; 455 | } 456 | 457 | input[type="number"]{ 458 | width:3em; 459 | } 460 | 461 | label { 462 | text-align: right; 463 | } 464 | 465 | /* Pair of properties that are related */ 466 | .pair { 467 | width: 75%; 468 | text-align: left; 469 | align: left; 470 | } 471 | 472 | .item1 { 473 | width: 50%; 474 | } 475 | 476 | .item2 { 477 | width: 50%; 478 | } 479 | 480 | input[name="x_offset"] { 481 | width: 2em; 482 | } 483 | 484 | input[name="y_offset"] { 485 | width: 2em; 486 | } 487 | 488 | input[name="send_symbol"] { 489 | width: 8em; 490 | } 491 | 492 | input[name="receive_symbol"] { 493 | width: 8em; 494 | } 495 | 496 | input[name="label"] { 497 | width: 8em; 498 | } 499 | 500 | input[name="font_size"] { 501 | width: 3em; 502 | } 503 | 504 | input[name="startup_flags"] { 505 | width: 16em; 506 | } 507 | 508 | /* Canvas dialog */ 509 | 510 | div.x-scale { 511 | padding: 3px; 512 | text-align: center; 513 | } 514 | 515 | div.gop-range { 516 | } 517 | 518 | div.y1 { 519 | text-align: center; 520 | padding: 3px; 521 | } 522 | 523 | div.x1 { 524 | text-align: center; 525 | padding: 3px; 526 | } 527 | 528 | div.y2 { 529 | text-align: center; 530 | padding: 3px; 531 | } 532 | 533 | .disabled { 534 | color: #aaa; 535 | } 536 | 537 | /* Preferences dialog */ 538 | 539 | #prefs_html_element { 540 | /* height: 100%; */ 541 | margin: 0px; 542 | padding: 0px; 543 | height: 100vh; 544 | } 545 | 546 | .prefs_body { 547 | padding: 0px; 548 | } 549 | 550 | #prefs_container { 551 | display: table; 552 | } 553 | 554 | /* Main tab widget */ 555 | 556 | /* All the display, width, and height settings below are a house of cards. 557 | I don't have the schooling to actually predict how all these CSS elements 558 | work together to create the whole. I just fudged around until I found a 559 | way to get the buttons anchored at the bottom of the dialog without 560 | triggering scrollbars to appear. If someone knows a way to do it "right" 561 | without becoming an order of magnitude more complex, do feel free... */ 562 | .prefs_tab_group { 563 | display: table; 564 | width: 90%; 565 | } 566 | 567 | /* Configure the radio buttons to hide off-screen */ 568 | .prefs_tab { 569 | position: absolute; 570 | left:-100px; 571 | top:-100px; 572 | } 573 | 574 | /* Configure labels to look like tabs */ 575 | .prefs_tab + label { 576 | /* inline-block such that the label can be given dimensions */ 577 | display: inline-block; 578 | /* A nice curved border around the tab */ 579 | border: 1px solid #bbb; 580 | border-top-left-radius: 5px; 581 | border-top-right-radius: 5px; 582 | /* the bottom border is handled by the tab content div */ 583 | border-bottom: 0; 584 | /* Padding around tab text */ 585 | padding: 5px 10px; 586 | /* put a small margin to the left to make the first tab clear */ 587 | margin-left: 4px; 588 | margin-top: 8px; 589 | margin-bottom: 0px; 590 | /* Set the background color to default gray (non-selected tab) */ 591 | background-color:#ececec; 592 | } 593 | 594 | /* Focused tabs */ 595 | .prefs_tab:focus + label { 596 | border: 1px dashed #bbb; 597 | } 598 | 599 | /* Checked tabs must be white with the bottom border removed */ 600 | .prefs_tab:checked + label { 601 | background-color: #f3f3f3; 602 | text-shadow: 1px 0px 0px; /* substitute for "bold" to retain div width */ 603 | border-bottom: 1px solid #f3f3f3; 604 | margin-bottom: -1px; 605 | } 606 | 607 | /* The tab content must fill the widgets size and have a nice border */ 608 | .prefs_tab_group > div { 609 | display: none; 610 | border-top: 1px solid #ddd; 611 | padding: 0px; 612 | margin: 0px; 613 | height: 100%; 614 | } 615 | 616 | /* This matches tabs displaying to their associated radio inputs */ 617 | .tab1:checked ~ .tab1, .tab2:checked ~ .tab2, .tab3:checked ~ .tab3, .tab4:checked ~ .tab4 { 618 | display: table; 619 | padding: 8px; 620 | line-height: 20px; 621 | width: 100%; 622 | height: 78vh; 623 | } 624 | 625 | .tab_settings { 626 | padding-top: 8px; 627 | } 628 | 629 | /* Sample rate input */ 630 | input[name="rate"] { 631 | width: 4em; 632 | } 633 | 634 | #prefs_buttons { 635 | display: table; 636 | height: 10vh; 637 | padding: 0px; 638 | margin: 0px; 639 | margin-top: -10px; 640 | margin-bottom: -10px; 641 | padding: 30px; 642 | } 643 | -------------------------------------------------------------------------------- /css/strongbad.css: -------------------------------------------------------------------------------- 1 | /* Global CSS */ 2 | 3 | /* 4 | @font-face { 5 | font-family: "DejaVu Sans Mono"; 6 | src: url("../DejaVuSansMono.ttf"); 7 | } 8 | */ 9 | 10 | body { 11 | margin: 0px; 12 | font-family: "DejaVu Sans Mono"; 13 | } 14 | 15 | .noselect { 16 | -webkit-touch-callout: none; 17 | -webkit-user-select: none; 18 | -khtml-user-select: none; 19 | -moz-user-select: none; 20 | -ms-user-select: none; 21 | user-select: none; 22 | } 23 | 24 | ::selection { 25 | background: #4bd046; 26 | color: black; 27 | } 28 | 29 | /* The main Pd Window */ 30 | 31 | #console_controls { 32 | background-color: LightGray; 33 | height: 50px; 34 | } 35 | 36 | #control_frame { 37 | padding: 12px; 38 | } 39 | 40 | #printout { 41 | margin: 8px; 42 | } 43 | 44 | #console_bottom { 45 | position: absolute; 46 | top: 50px; 47 | left: 0px; 48 | right: 0px; 49 | bottom: 0px; 50 | overflow-y: scroll; 51 | background: black; 52 | color: #4bd046; 53 | } 54 | 55 | /* The console API allows classes for different types of messages to print. 56 | Currently the only class is "error". More may be added, especially once 57 | we port the "loglevel" functionality that was available in Pd Extended. */ 58 | #console_bottom .error { 59 | color: #cc9933; 60 | } 61 | 62 | #console_bottom .error a { 63 | color: #ccc; 64 | } 65 | 66 | /* Find bar */ 67 | 68 | #console_find label, #canvas_find label { 69 | font-family: "DejaVu Sans", sans-serif; 70 | font-size: 10pt; 71 | } 72 | 73 | /* marks for matches to console_find */ 74 | mark { 75 | background: white !important; 76 | padding: 0 !important; 77 | } 78 | 79 | mark.console_find_current.console_find_highlighted, 80 | mark.console_find_current { 81 | background: yellow !important; 82 | } 83 | 84 | mark.console_find_highlighted { 85 | background: #6bd4e6 !important; 86 | } 87 | 88 | #console_find { 89 | width: 100%; 90 | height: 1em; 91 | padding: 0.2em; 92 | background: silver; 93 | position: fixed; 94 | bottom: 0; 95 | left: 0; 96 | } 97 | 98 | /* Pure Data Patch Window (aka canvas) */ 99 | 100 | /* patch font and background color. (Note: margin needs to stay at zero.) */ 101 | .patch_body { 102 | background-color: black; 103 | } 104 | 105 | #selection_rectangle { 106 | stroke: #53b83b; 107 | } 108 | 109 | /* The outline to show the visible area for a Graph-On-Parent canvas, 110 | i.e., the "red rectangle" */ 111 | .gop_rect { 112 | fill: none; 113 | stroke: red; 114 | stroke-opacity: 0.6; 115 | } 116 | 117 | .cord.signal { 118 | stroke-width: 2; 119 | stroke: green; 120 | } 121 | 122 | .cord.control { 123 | stroke-width: 1; 124 | stroke: green; 125 | } 126 | 127 | /* selected connection between objects */ 128 | .cord.signal.selected_line, 129 | .cord.control.selected_line, 130 | #newcord { 131 | stroke: #53b83b; 132 | } 133 | 134 | #cord_inspector_rect { 135 | fill: black; 136 | stroke: black; 137 | } 138 | 139 | #cord_inspector_text { 140 | fill: white; 141 | } 142 | 143 | #cord_inspector_text.flash { 144 | fill: #e87216; 145 | } 146 | 147 | /* text inside boxes: message boxes, object boxes, graphs, comments, etc. */ 148 | .box_text { 149 | fill: #4bd046; 150 | } 151 | 152 | /* hyperlinks: for now, just pddplink and helplink */ 153 | .pd_link text { 154 | fill: #4bd046; 155 | } 156 | 157 | .pd_link text:hover { 158 | fill: red; 159 | } 160 | 161 | .pd_link.selected text { 162 | fill: white; 163 | } 164 | 165 | #new_object_textentry { 166 | /* max-width: 10ch; */ 167 | min-width: 3ch; 168 | position: absolute; 169 | display: table-cell; 170 | padding: 3px 2px 3px 2px; 171 | /* box-shadow: inset 1px 0px 0px 1px #000; */ 172 | color: #4bd046; 173 | background-color: transparent; 174 | white-space: pre-wrap; 175 | overflow-wrap: break-word; 176 | -webkit-margin-before: 0px; 177 | } 178 | 179 | #new_object_textentry.obj { 180 | outline: 1px solid #0b560b; 181 | } 182 | 183 | #new_object_textentry.msg { 184 | outline: 0px solid #0b560b; 185 | background-image: url(../msg-box.svg); 186 | } 187 | 188 | p.msg::after { 189 | content: ""; 190 | height: 100%; 191 | width: 5px; 192 | background-image: url(../msg-box-flag.svg); 193 | position: absolute; 194 | top: 0%; 195 | left: 100%; 196 | } 197 | 198 | /* not sure what this is doing here... */ 199 | text { 200 | // fill: red; 201 | //cursor: default; 202 | } 203 | 204 | /* not sure if this is still needed */ 205 | .selected_border { 206 | stroke: blue; 207 | stroke-dasharray: none; 208 | stroke-width: 1; 209 | } 210 | 211 | .msg .border { 212 | stroke: #0b560b; 213 | fill: black; 214 | } 215 | 216 | /* state of msg box when clicking it */ 217 | .msg.flashed .border { 218 | stroke-width: 4; 219 | } 220 | 221 | /* atom box */ 222 | .atom .border { 223 | stroke: #0b560b; 224 | fill: black; 225 | } 226 | 227 | /* for dropdown box we want to visually distinguish boxes that output 228 | the index from boxes that output the value. For now we do that by 229 | stroking the arrow for boxes that output an index. */ 230 | .atom .index_arrow { 231 | stroke: #4bd046; 232 | stroke-width: 1; 233 | fill: none; 234 | } 235 | 236 | .atom .value_arrow { 237 | fill: #4bd046; 238 | } 239 | 240 | /* gatom "activated" text (i.e., when it has the keyboard focus) */ 241 | .atom.activated text { 242 | fill: red; 243 | } 244 | 245 | #dropdown_list { 246 | position: absolute; 247 | border-width: 1px; 248 | border-style: solid; 249 | border-color: #0b560b; 250 | cursor: pointer; 251 | color: #4bd046; 252 | box-shadow: 1px 1px 1px 1px #0b560b; 253 | overflow-y: auto; 254 | } 255 | 256 | #dropdown_list ol { 257 | list-style-position: inside; 258 | margin: 0; 259 | padding: 0; 260 | background: black; 261 | } 262 | 263 | #dropdown_list li { 264 | list-style-type: none; 265 | padding: 5px; 266 | } 267 | 268 | #dropdown_list li.highlighted { 269 | background: #4bd046; 270 | color: black; 271 | } 272 | 273 | .obj .border { 274 | fill: black; 275 | stroke: #0b560b; 276 | } 277 | 278 | .comment .border { 279 | fill: none; 280 | } 281 | 282 | svg[id^="patchsvg"].editmode .comment .border { 283 | stroke: #0b560b; 284 | stroke-dasharray: 8 4; 285 | } 286 | 287 | /* A little hack for special canvas of [cnv]. 288 | All other iemguis have a black border, but 289 | [cnv] sets its selection rectangle to the 290 | user-supplied fill color when the object 291 | isn't selected */ 292 | .iemgui .border:not(.mycanvas_border) { 293 | stroke: #0b560b; 294 | } 295 | 296 | .graph .border { 297 | stroke: #777; 298 | fill: none; 299 | } 300 | 301 | /* Graph (or subpatch) that has been opened to inspect its contents */ 302 | .graph.has_window .border { 303 | stroke: #0b560b; 304 | fill: #0b560b; 305 | } 306 | 307 | /* border color for selected objects 308 | * an element with the class "border" 309 | * the element is contained within a parent element of class "selected" 310 | * that parent element is not in class "gop" 311 | in plain English: 312 | This lets us highlight an object's border, unless it is inside a gop 313 | canvas. 314 | */ 315 | :not(.gop).selected .border { 316 | stroke: green; 317 | display: inline; 318 | } 319 | 320 | /* text inside selected objects */ 321 | :not(.gop).selected text { 322 | fill: green; 323 | } 324 | 325 | /* for an object that didn't create */ 326 | .obj .border.broken_border { 327 | fill: transparent; 328 | stroke: #f00; 329 | stroke-dasharray: 3 2; 330 | } 331 | 332 | /* control inlet */ 333 | .xlet_control { 334 | stroke: green; 335 | fill: #53b83b; 336 | // stroke-width: 1; 337 | } 338 | 339 | /* signal inlet */ 340 | .xlet_signal { 341 | stroke: green; 342 | fill: #53b83b; 343 | stroke-width: 1; 344 | } 345 | 346 | /* iemgui inlet or outlet */ 347 | .xlet_iemgui { 348 | stroke: green; 349 | fill: #0b560b; 350 | stroke-width: 1; 351 | } 352 | 353 | /* text label for an iemgui */ 354 | .iemgui_label_selected { 355 | fill: blue; 356 | } 357 | 358 | /* test of xlet hover animation... this should 359 | probably use the web animation API instead. That 360 | way the animation won't get cut off when you 361 | move off the object */ 362 | @-webkit-keyframes fizzle { 363 | 0% { 364 | stroke-width: 1; 365 | stroke-opacity: 1; 366 | rx: 1; 367 | ry: 1; 368 | } 369 | 100% { 370 | stroke-width: 20; 371 | stroke-opacity: 0.2; 372 | rx: 50; 373 | ry: 50; 374 | } 375 | } 376 | 377 | /* can't remember why this was tagged !important */ 378 | .xlet_selected { 379 | stroke: #53b83b !important; 380 | fill: green; 381 | -webkit-animation: fizzle 0.5s linear 1; 382 | } 383 | 384 | #canvas_find { 385 | width: 100%; 386 | height: 1em; 387 | padding: 3px; 388 | background: silver; 389 | position: fixed; 390 | bottom: 0; 391 | left: 0; 392 | } 393 | 394 | /* Search dialog */ 395 | 396 | .search_body { 397 | font-family: "DejaVu Sans", sans-serif; 398 | font-size: 10pt; 399 | padding: 8px; 400 | } 401 | 402 | /* Common to all dialogs */ 403 | 404 | .dialog_body { 405 | font-family: "DejaVu Sans", sans-serif; 406 | font-size: 10pt; 407 | background-color: #f3f3f3; 408 | } 409 | 410 | .submit_buttons { 411 | text-align: center; 412 | padding: 8px; 413 | } 414 | 415 | fieldset { 416 | background-color:#eeeeee; 417 | border-radius:3px; 418 | border:2px solid black; 419 | margin-left:auto; 420 | margin-right:auto; 421 | padding: 10px; 422 | } 423 | 424 | .hidden { 425 | display: none; 426 | } 427 | 428 | .container{ 429 | display: none; 430 | } 431 | 432 | /* Iemgui dialog */ 433 | 434 | input[type="text"]{ 435 | width:3em; 436 | } 437 | 438 | input[type="number"]{ 439 | width:3em; 440 | } 441 | 442 | label { 443 | text-align: right; 444 | } 445 | 446 | /* Pair of properties that are related */ 447 | .pair { 448 | width: 75%; 449 | text-align: left; 450 | align: left; 451 | } 452 | 453 | .item1 { 454 | width: 50%; 455 | } 456 | 457 | .item2 { 458 | width: 50%; 459 | } 460 | 461 | input[name="x_offset"] { 462 | width: 2em; 463 | } 464 | 465 | input[name="y_offset"] { 466 | width: 2em; 467 | } 468 | 469 | input[name="send_symbol"] { 470 | width: 8em; 471 | } 472 | 473 | input[name="receive_symbol"] { 474 | width: 8em; 475 | } 476 | 477 | input[name="label"] { 478 | width: 8em; 479 | } 480 | 481 | input[name="font_size"] { 482 | width: 3em; 483 | } 484 | 485 | input[name="startup_flags"] { 486 | width: 16em; 487 | } 488 | 489 | /* Canvas dialog */ 490 | 491 | div.x-scale { 492 | padding: 3px; 493 | text-align: center; 494 | } 495 | 496 | div.gop-range { 497 | } 498 | 499 | div.y1 { 500 | text-align: center; 501 | padding: 3px; 502 | } 503 | 504 | div.x1 { 505 | text-align: center; 506 | padding: 3px; 507 | } 508 | 509 | div.y2 { 510 | text-align: center; 511 | padding: 3px; 512 | } 513 | 514 | .disabled { 515 | color: #aaa; 516 | } 517 | 518 | /* Preferences dialog */ 519 | 520 | #prefs_html_element { 521 | /* height: 100%; */ 522 | margin: 0px; 523 | padding: 0px; 524 | height: 100vh; 525 | } 526 | 527 | .prefs_body { 528 | padding: 0px; 529 | } 530 | 531 | #prefs_container { 532 | display: table; 533 | } 534 | 535 | /* Main tab widget */ 536 | 537 | /* All the display, width, and height settings below are a house of cards. 538 | I don't have the schooling to actually predict how all these CSS elements 539 | work together to create the whole. I just fudged around until I found a 540 | way to get the buttons anchored at the bottom of the dialog without 541 | triggering scrollbars to appear. If someone knows a way to do it "right" 542 | without becoming an order of magnitude more complex, do feel free... */ 543 | .prefs_tab_group { 544 | display: table; 545 | width: 90%; 546 | } 547 | 548 | /* Configure the radio buttons to hide off-screen */ 549 | .prefs_tab { 550 | position: absolute; 551 | left:-100px; 552 | top:-100px; 553 | } 554 | 555 | /* Configure labels to look like tabs */ 556 | .prefs_tab + label { 557 | /* inline-block such that the label can be given dimensions */ 558 | display: inline-block; 559 | /* A nice curved border around the tab */ 560 | border: 1px solid #bbb; 561 | border-top-left-radius: 5px; 562 | border-top-right-radius: 5px; 563 | /* the bottom border is handled by the tab content div */ 564 | border-bottom: 0; 565 | /* Padding around tab text */ 566 | padding: 5px 10px; 567 | /* put a small margin to the left to make the first tab clear */ 568 | margin-left: 4px; 569 | margin-top: 8px; 570 | margin-bottom: 0px; 571 | /* Set the background color to default gray (non-selected tab) */ 572 | background-color:#ececec; 573 | } 574 | 575 | /* Focused tabs */ 576 | .prefs_tab:focus + label { 577 | border: 1px dashed #bbb; 578 | } 579 | 580 | /* Checked tabs must be white with the bottom border removed */ 581 | .prefs_tab:checked + label { 582 | background-color: #f3f3f3; 583 | text-shadow: 1px 0px 0px; /* substitute for "bold" to retain div width */ 584 | border-bottom: 1px solid #f3f3f3; 585 | margin-bottom: -1px; 586 | } 587 | 588 | /* The tab content must fill the widgets size and have a nice border */ 589 | .prefs_tab_group > div { 590 | display: none; 591 | border-top: 1px solid #ddd; 592 | padding: 0px; 593 | margin: 0px; 594 | height: 100%; 595 | } 596 | 597 | /* This matches tabs displaying to their associated radio inputs */ 598 | .tab1:checked ~ .tab1, .tab2:checked ~ .tab2, .tab3:checked ~ .tab3, .tab4:checked ~ .tab4 { 599 | display: table; 600 | padding: 8px; 601 | line-height: 20px; 602 | width: 100%; 603 | height: 78vh; 604 | } 605 | 606 | .tab_settings { 607 | padding-top: 8px; 608 | } 609 | 610 | /* Sample rate input */ 611 | input[name="rate"] { 612 | width: 4em; 613 | } 614 | 615 | #prefs_buttons { 616 | display: table; 617 | height: 10vh; 618 | padding: 0px; 619 | margin: 0px; 620 | margin-top: -10px; 621 | margin-bottom: -10px; 622 | padding: 30px; 623 | } 624 | -------------------------------------------------------------------------------- /css/subdued.css: -------------------------------------------------------------------------------- 1 | /* Global CSS */ 2 | 3 | /* 4 | @font-face { 5 | font-family: "DejaVu Sans Mono"; 6 | src: url("../DejaVuSansMono.ttf"); 7 | } 8 | */ 9 | 10 | body { 11 | margin: 0px; 12 | font-family: "DejaVu Sans Mono"; 13 | } 14 | 15 | .noselect { 16 | -webkit-touch-callout: none; 17 | -webkit-user-select: none; 18 | -khtml-user-select: none; 19 | -moz-user-select: none; 20 | -ms-user-select: none; 21 | user-select: none; 22 | } 23 | 24 | ::selection { 25 | background: #c3c3c3; 26 | color: black; 27 | } 28 | 29 | /* The main Pd Window */ 30 | 31 | #console_controls { 32 | background-color: LightGray; 33 | height: 50px; 34 | } 35 | 36 | #control_frame { 37 | padding: 12px; 38 | } 39 | 40 | #printout { 41 | margin: 8px; 42 | } 43 | 44 | #console_bottom { 45 | position: absolute; 46 | top: 50px; 47 | left: 0px; 48 | right: 0px; 49 | bottom: 0px; 50 | overflow-y: scroll; 51 | background-color: #c0dcc0; 52 | } 53 | 54 | /* The console API allows classes for different types of messages to print. 55 | Currently the only class is "error". More may be added, especially once 56 | we port the "loglevel" functionality that was available in Pd Extended. */ 57 | #console_bottom .error { 58 | color: black; 59 | } 60 | 61 | #console_bottom .error a { 62 | color: black; 63 | font-weight: 600; 64 | } 65 | 66 | /* Find bar */ 67 | 68 | #console_find label, #canvas_find label { 69 | font-family: "DejaVu Sans", sans-serif; 70 | font-size: 10pt; 71 | } 72 | 73 | /* marks for matches to console_find */ 74 | mark { 75 | background: white !important; 76 | padding: 0 !important; 77 | } 78 | 79 | mark.console_find_current.console_find_highlighted, 80 | mark.console_find_current { 81 | background: yellow !important; 82 | } 83 | 84 | mark.console_find_highlighted { 85 | background: #6bd4e6 !important; 86 | } 87 | 88 | #console_find { 89 | width: 100%; 90 | height: 1em; 91 | padding: 0.2em; 92 | background: silver; 93 | position: fixed; 94 | bottom: 0; 95 | left: 0; 96 | } 97 | 98 | /* Pure Data Patch Window (aka canvas) */ 99 | 100 | /* patch font and background color. (Note: margin needs to stay at zero.) */ 101 | .patch_body { 102 | background-color: #c0dcc0; 103 | } 104 | 105 | #selection_rectangle { 106 | stroke: #333333; 107 | } 108 | 109 | /* The outline to show the visible area for a Graph-On-Parent canvas, 110 | i.e., the "red rectangle" */ 111 | .gop_rect { 112 | fill: none; 113 | stroke: blue; 114 | stroke-opacity: 0.4; 115 | } 116 | 117 | .cord.signal { 118 | stroke-width: 2; 119 | stroke: #666666; 120 | } 121 | 122 | .cord.control { 123 | stroke-width: 1; 124 | stroke: #333333; 125 | } 126 | 127 | /* selected connection between objects */ 128 | .cord.signal.selected_line, 129 | .cord.control.selected_line, 130 | #newcord { 131 | stroke: blue; 132 | } 133 | 134 | #cord_inspector_rect { 135 | fill: black; 136 | stroke: black; 137 | } 138 | 139 | #cord_inspector_text { 140 | fill: white; 141 | } 142 | 143 | #cord_inspector_text.flash { 144 | fill: #e87216; 145 | } 146 | 147 | /* text inside boxes: message boxes, object boxes, graphs, comments, etc. */ 148 | .box_text { 149 | fill: black; 150 | } 151 | 152 | /* hyperlinks: for now, just pddplink and helplink */ 153 | .pd_link text { 154 | fill: blue; 155 | } 156 | 157 | .pd_link text:hover { 158 | fill: red; 159 | } 160 | 161 | .pd_link.selected text { 162 | fill: white; 163 | } 164 | 165 | #new_object_textentry { 166 | /* max-width: 10ch; */ 167 | min-width: 3ch; 168 | position: absolute; 169 | display: table-cell; 170 | padding: 3px 2px 3px 2px; 171 | /* box-shadow: inset 1px 0px 0px 1px #000; */ 172 | background-color: transparent; 173 | white-space: pre-wrap; 174 | overflow-wrap: break-word; 175 | -webkit-margin-before: 0px; 176 | } 177 | 178 | #new_object_textentry.obj { 179 | outline: 1px solid blue; 180 | } 181 | 182 | #new_object_textentry.msg { 183 | outline: 0px solid blue; 184 | background-image: url(../msg-box.svg); 185 | } 186 | 187 | p.msg::after { 188 | content: ""; 189 | height: 100%; 190 | width: 5px; 191 | background-image: url(../msg-box-flag.svg); 192 | position: absolute; 193 | top: 0%; 194 | left: 100%; 195 | } 196 | 197 | /* not sure what this is doing here... */ 198 | text { 199 | // fill: red; 200 | //cursor: default; 201 | } 202 | 203 | /* not sure if this is still needed */ 204 | .selected_border { 205 | stroke: blue; 206 | stroke-dasharray: none; 207 | stroke-width: 1; 208 | } 209 | 210 | .msg .border { 211 | stroke: #666666; 212 | fill: #c0dcc0; 213 | } 214 | 215 | /* state of msg box when clicking it */ 216 | .msg.flashed .border { 217 | stroke-width: 4; 218 | } 219 | 220 | /* atom box */ 221 | .atom .border { 222 | stroke: #b1d3b1; 223 | fill: #9fc79f; 224 | } 225 | 226 | /* for dropdown box we want to visually distinguish boxes that output 227 | the index from boxes that output the value. For now we do that by 228 | stroking the arrow for boxes that output an index. For boxes that 229 | output the value we don't need a CSS rule, as the arrow will be filled 230 | black by default */ 231 | .atom .index_arrow { 232 | stroke: black; 233 | stroke-width: 1; 234 | fill: none; 235 | } 236 | 237 | /* gatom "activated" text (i.e., when it has the keyboard focus) */ 238 | .atom.activated text { 239 | fill: red; 240 | } 241 | 242 | #dropdown_list { 243 | position: absolute; 244 | border-width: 1px; 245 | border-style: solid; 246 | border-color: #b1d3b1; 247 | cursor: pointer; 248 | overflow-y: auto; 249 | } 250 | 251 | #dropdown_list ol { 252 | list-style-position: inside; 253 | margin: 0; 254 | padding: 0; 255 | background: #9fc79f; 256 | } 257 | 258 | #dropdown_list li { 259 | list-style-type: none; 260 | padding: 5px; 261 | } 262 | 263 | #dropdown_list li.highlighted { 264 | background: #c3c3c3; 265 | } 266 | 267 | .obj .border { 268 | fill: #c0dcc0; 269 | stroke: #666666; 270 | } 271 | 272 | .comment .border { 273 | fill: none; 274 | } 275 | 276 | svg[id^="patchsvg"].editmode .comment .border { 277 | stroke: #777; 278 | stroke-dasharray: 8 4; 279 | } 280 | 281 | /* A little hack for special canvas of [cnv]. 282 | All other iemguis have a black border, but 283 | [cnv] sets its selection rectangle to the 284 | user-supplied fill color when the object 285 | isn't selected */ 286 | .iemgui .border:not(.mycanvas_border) { 287 | stroke: #666666; 288 | } 289 | 290 | .graph .border { 291 | stroke: #777; 292 | fill: none; 293 | } 294 | 295 | /* Graph (or subpatch) that has been opened to inspect its contents */ 296 | .graph.has_window .border { 297 | stroke: black; 298 | fill: #bbb; 299 | } 300 | 301 | /* border color for selected objects 302 | * an element with the class "border" 303 | * the element is contained within a parent element of class "selected" 304 | * that parent element is not in class "gop" 305 | in plain English: 306 | This lets us highlight an object's border, unless it is inside a gop 307 | canvas. 308 | */ 309 | :not(.gop).selected .border { 310 | stroke: blue; 311 | display: inline; 312 | } 313 | 314 | /* text inside selected objects */ 315 | :not(.gop).selected text { 316 | fill: blue; 317 | } 318 | 319 | /* for an object that didn't create */ 320 | .obj .border.broken_border { 321 | fill: transparent; 322 | stroke: #f00; 323 | stroke-dasharray: 3 2; 324 | } 325 | 326 | /* control inlet */ 327 | .xlet_control { 328 | stroke: #333333; 329 | fill: #333333; 330 | // stroke-width: 1; 331 | } 332 | 333 | /* signal inlet */ 334 | .xlet_signal { 335 | stroke: #666666; 336 | fill: #666666; 337 | stroke-width: 1; 338 | } 339 | 340 | /* iemgui inlet or outlet */ 341 | .xlet_iemgui { 342 | stroke: #666666; 343 | fill: #666666; 344 | stroke-width: 1; 345 | } 346 | 347 | /* text label for an iemgui */ 348 | .iemgui_label_selected { 349 | fill: blue; 350 | } 351 | 352 | /* test of xlet hover animation... this should 353 | probably use the web animation API instead. That 354 | way the animation won't get cut off when you 355 | move off the object */ 356 | @-webkit-keyframes fizzle { 357 | 0% { 358 | stroke-width: 1; 359 | stroke-opacity: 1; 360 | rx: 1; 361 | ry: 1; 362 | } 363 | 100% { 364 | stroke-width: 20; 365 | stroke-opacity: 0.2; 366 | rx: 50; 367 | ry: 50; 368 | } 369 | } 370 | 371 | /* can't remember why this was tagged !important */ 372 | .xlet_selected { 373 | stroke: gray !important; 374 | fill: gray; 375 | -webkit-animation: fizzle 0.5s linear 1; 376 | } 377 | 378 | #canvas_find { 379 | width: 100%; 380 | height: 1em; 381 | padding: 3px; 382 | background: silver; 383 | position: fixed; 384 | bottom: 0; 385 | left: 0; 386 | } 387 | 388 | /* Dialog to ask to save the patch before quitting */ 389 | #save_before_quit { 390 | background-color: #c0dcc0; 391 | border:1px solid black; 392 | padding: 12px; 393 | margin: 12px; 394 | box-shadow: 7px 7px 5px grey; 395 | } 396 | 397 | /* Search dialog */ 398 | 399 | .search_body { 400 | font-family: "DejaVu Sans", sans-serif; 401 | font-size: 10pt; 402 | padding: 8px; 403 | } 404 | 405 | /* Common to all dialogs */ 406 | 407 | .dialog_body { 408 | font-family: "DejaVu Sans", sans-serif; 409 | font-size: 10pt; 410 | background-color: #f3f3f3; 411 | } 412 | 413 | .submit_buttons { 414 | text-align: center; 415 | padding: 8px; 416 | } 417 | 418 | fieldset { 419 | background-color:#eeeeee; 420 | border-radius:3px; 421 | border:2px solid black; 422 | margin-left:auto; 423 | margin-right:auto; 424 | padding: 10px; 425 | } 426 | 427 | .hidden { 428 | display: none; 429 | } 430 | 431 | .container{ 432 | display: none; 433 | } 434 | 435 | /* Iemgui dialog */ 436 | 437 | input[type="text"]{ 438 | width:3em; 439 | } 440 | 441 | input[type="number"]{ 442 | width:3em; 443 | } 444 | 445 | label { 446 | text-align: right; 447 | } 448 | 449 | /* Pair of properties that are related */ 450 | .pair { 451 | width: 75%; 452 | text-align: left; 453 | align: left; 454 | } 455 | 456 | .item1 { 457 | width: 50%; 458 | } 459 | 460 | .item2 { 461 | width: 50%; 462 | } 463 | 464 | input[name="x_offset"] { 465 | width: 2em; 466 | } 467 | 468 | input[name="y_offset"] { 469 | width: 2em; 470 | } 471 | 472 | input[name="send_symbol"] { 473 | width: 8em; 474 | } 475 | 476 | input[name="receive_symbol"] { 477 | width: 8em; 478 | } 479 | 480 | input[name="label"] { 481 | width: 8em; 482 | } 483 | 484 | input[name="font_size"] { 485 | width: 3em; 486 | } 487 | 488 | input[name="startup_flags"] { 489 | width: 16em; 490 | } 491 | 492 | /* Canvas dialog */ 493 | 494 | div.x-scale { 495 | padding: 3px; 496 | text-align: center; 497 | } 498 | 499 | div.gop-range { 500 | } 501 | 502 | div.y1 { 503 | text-align: center; 504 | padding: 3px; 505 | } 506 | 507 | div.x1 { 508 | text-align: center; 509 | padding: 3px; 510 | } 511 | 512 | div.y2 { 513 | text-align: center; 514 | padding: 3px; 515 | } 516 | 517 | .disabled { 518 | color: #aaa; 519 | } 520 | 521 | /* Preferences dialog */ 522 | 523 | #prefs_html_element { 524 | /* height: 100%; */ 525 | margin: 0px; 526 | padding: 0px; 527 | height: 100vh; 528 | } 529 | 530 | .prefs_body { 531 | padding: 0px; 532 | } 533 | 534 | #prefs_container { 535 | display: table; 536 | } 537 | 538 | /* Main tab widget */ 539 | 540 | /* All the display, width, and height settings below are a house of cards. 541 | I don't have the schooling to actually predict how all these CSS elements 542 | work together to create the whole. I just fudged around until I found a 543 | way to get the buttons anchored at the bottom of the dialog without 544 | triggering scrollbars to appear. If someone knows a way to do it "right" 545 | without becoming an order of magnitude more complex, do feel free... */ 546 | .prefs_tab_group { 547 | display: table; 548 | width: 90%; 549 | } 550 | 551 | /* Configure the radio buttons to hide off-screen */ 552 | .prefs_tab { 553 | position: absolute; 554 | left:-100px; 555 | top:-100px; 556 | } 557 | 558 | /* Configure labels to look like tabs */ 559 | .prefs_tab + label { 560 | /* inline-block such that the label can be given dimensions */ 561 | display: inline-block; 562 | /* A nice curved border around the tab */ 563 | border: 1px solid #bbb; 564 | border-top-left-radius: 5px; 565 | border-top-right-radius: 5px; 566 | /* the bottom border is handled by the tab content div */ 567 | border-bottom: 0; 568 | /* Padding around tab text */ 569 | padding: 5px 10px; 570 | /* put a small margin to the left to make the first tab clear */ 571 | margin-left: 4px; 572 | margin-top: 8px; 573 | margin-bottom: 0px; 574 | /* Set the background color to default gray (non-selected tab) */ 575 | background-color:#ececec; 576 | } 577 | 578 | /* Focused tabs */ 579 | .prefs_tab:focus + label { 580 | border: 1px dashed #bbb; 581 | } 582 | 583 | /* Checked tabs must be white with the bottom border removed */ 584 | .prefs_tab:checked + label { 585 | background-color: #f3f3f3; 586 | text-shadow: 1px 0px 0px; /* substitute for "bold" to retain div width */ 587 | border-bottom: 1px solid #f3f3f3; 588 | margin-bottom: -1px; 589 | } 590 | 591 | /* The tab content must fill the widgets size and have a nice border */ 592 | .prefs_tab_group > div { 593 | display: none; 594 | border-top: 1px solid #ddd; 595 | padding: 0px; 596 | margin: 0px; 597 | height: 100%; 598 | } 599 | 600 | /* This matches tabs displaying to their associated radio inputs */ 601 | .tab1:checked ~ .tab1, .tab2:checked ~ .tab2, .tab3:checked ~ .tab3, .tab4:checked ~ .tab4 { 602 | display: table; 603 | padding: 8px; 604 | line-height: 20px; 605 | width: 100%; 606 | height: 78vh; 607 | } 608 | 609 | .tab_settings { 610 | padding-top: 8px; 611 | } 612 | 613 | /* Sample rate input */ 614 | input[name="rate"] { 615 | width: 4em; 616 | } 617 | 618 | #prefs_buttons { 619 | display: table; 620 | height: 10vh; 621 | padding: 0px; 622 | margin: 0px; 623 | margin-top: -10px; 624 | margin-bottom: -10px; 625 | padding: 30px; 626 | } 627 | -------------------------------------------------------------------------------- /css/vanilla.css: -------------------------------------------------------------------------------- 1 | /* Global CSS */ 2 | 3 | /* 4 | @font-face { 5 | font-family: "DejaVu Sans Mono"; 6 | src: url("../DejaVuSansMono.ttf"); 7 | } 8 | */ 9 | 10 | body { 11 | margin: 0px; 12 | font-family: "DejaVu Sans Mono"; 13 | } 14 | 15 | .noselect { 16 | -webkit-touch-callout: none; 17 | -webkit-user-select: none; 18 | -khtml-user-select: none; 19 | -moz-user-select: none; 20 | -ms-user-select: none; 21 | user-select: none; 22 | } 23 | 24 | ::selection { 25 | background: #c3c3c3; 26 | color: black; 27 | } 28 | 29 | /* The main Pd Window */ 30 | 31 | #console_controls { 32 | background-color: LightGray; 33 | height: 50px; 34 | } 35 | 36 | #control_frame { 37 | padding: 12px; 38 | } 39 | 40 | #printout { 41 | margin: 8px; 42 | } 43 | 44 | #console_bottom { 45 | position: absolute; 46 | top: 50px; 47 | left: 0px; 48 | right: 0px; 49 | bottom: 0px; 50 | overflow-y: scroll; 51 | } 52 | 53 | /* The console API allows classes for different types of messages to print. 54 | Currently the only class is "error". More may be added, especially once 55 | we port the "loglevel" functionality that was available in Pd Extended. */ 56 | #console_bottom .error { 57 | color: red; 58 | } 59 | 60 | /* Find bar */ 61 | 62 | #console_find label, #canvas_find label { 63 | font-family: "DejaVu Sans", sans-serif; 64 | font-size: 10pt; 65 | } 66 | 67 | /* marks for matches to console_find */ 68 | mark { 69 | background: white !important; 70 | padding: 0 !important; 71 | } 72 | 73 | mark.console_find_current.console_find_highlighted, 74 | mark.console_find_current { 75 | background: yellow !important; 76 | } 77 | 78 | mark.console_find_highlighted { 79 | background: #6bd4e6 !important; 80 | } 81 | 82 | #console_find { 83 | width: 100%; 84 | height: 1em; 85 | padding: 0.2em; 86 | background: silver; 87 | position: fixed; 88 | bottom: 0; 89 | left: 0; 90 | } 91 | 92 | /* Pure Data Patch Window (aka canvas) */ 93 | 94 | /* canvas font and background color. (Note: margin needs to stay at zero.) */ 95 | .patch_body { 96 | background-color: white; 97 | } 98 | 99 | #selection_rectangle { 100 | stroke: black; 101 | } 102 | 103 | /* The outline to show the visible area for a Graph-On-Parent canvas, 104 | i.e., the "red rectangle" */ 105 | .gop_rect { 106 | fill: none; 107 | stroke: red; 108 | } 109 | 110 | .cord.signal { 111 | stroke-width: 2; 112 | stroke: black; 113 | } 114 | 115 | .cord.control { 116 | stroke-width: 1; 117 | stroke: black; 118 | } 119 | 120 | /* selected connection between objects */ 121 | .cord.signal.selected_line, 122 | .cord.control.selected_line { 123 | stroke: blue; 124 | } 125 | 126 | #cord_inspector_rect { 127 | fill: black; 128 | stroke: black; 129 | } 130 | 131 | #cord_inspector_text { 132 | fill: white; 133 | } 134 | 135 | #cord_inspector_text.flash { 136 | fill: #e87216; 137 | } 138 | 139 | /* text inside boxes: message boxes, object boxes, graphs, comments, etc. */ 140 | .box_text { 141 | fill: black; 142 | } 143 | 144 | /* hyperlinks: for now, just pddplink and helplink */ 145 | .pd_link text { 146 | fill: blue; 147 | } 148 | 149 | .pd_link text:hover { 150 | fill: red; 151 | } 152 | 153 | .pd_link.selected text { 154 | fill: #e87216 !important; 155 | } 156 | 157 | 158 | #new_object_textentry { 159 | /* max-width: 10ch; */ 160 | min-width: 3ch; 161 | position: absolute; 162 | display: table-cell; 163 | padding: 3px 2px 3px 2px; 164 | /* box-shadow: inset 1px 0px 0px 1px #000; */ 165 | background-color: transparent; 166 | white-space: pre-wrap; 167 | overflow-wrap: break-word; 168 | -webkit-margin-before: 0px; 169 | } 170 | 171 | #new_object_textentry.obj { 172 | outline: 1px solid blue; 173 | } 174 | 175 | #new_object_textentry.msg { 176 | outline: 0px solid blue; 177 | background-image: url(../msg-box.svg); 178 | } 179 | 180 | p.msg::after { 181 | content: ""; 182 | height: 100%; 183 | width: 5px; 184 | background-image: url(../msg-box-flag.svg); 185 | position: absolute; 186 | top: 0%; 187 | left: 100%; 188 | } 189 | 190 | /* not sure what this is doing here... */ 191 | text { 192 | // fill: red; 193 | //cursor: default; 194 | } 195 | 196 | /* not sure if this is still needed */ 197 | .selected_border { 198 | stroke: blue; 199 | stroke-dasharray: none; 200 | stroke-width: 1; 201 | } 202 | 203 | .msg .border { 204 | stroke: black; 205 | fill: none; 206 | } 207 | 208 | /* state of msg box when clicking it */ 209 | .msg.flashed .border { 210 | stroke-width: 4; 211 | } 212 | 213 | /* atom box */ 214 | .atom .border { 215 | stroke: black; 216 | fill: none; 217 | } 218 | 219 | /* for dropdown box we want to visually distinguish boxes that output 220 | the index from boxes that output the value. For now we do that by 221 | stroking the arrow for boxes that output an index. For boxes that 222 | output the value we don't need a CSS rule, as the arrow will be filled 223 | black by default */ 224 | .atom .index_arrow { 225 | stroke: black; 226 | stroke-width: 1; 227 | fill: none; 228 | } 229 | 230 | /* gatom "activated" text (i.e., when it has the keyboard focus) */ 231 | .atom.activated text { 232 | fill: red; 233 | } 234 | 235 | #dropdown_list { 236 | position: absolute; 237 | border-width: 1px; 238 | border-style: solid; 239 | border-color: black; 240 | cursor: pointer; 241 | overflow-y: auto; 242 | } 243 | 244 | #dropdown_list ol { 245 | list-style-position: inside; 246 | margin: 0; 247 | padding: 0; 248 | background: white; 249 | } 250 | 251 | #dropdown_list li { 252 | list-style-type: none; 253 | padding: 5px; 254 | } 255 | 256 | #dropdown_list li.highlighted { 257 | background: #c3c3c3; 258 | } 259 | 260 | .obj .border { 261 | fill: none; 262 | stroke: black; 263 | } 264 | 265 | .comment .border { 266 | fill: none; 267 | } 268 | 269 | svg[id^="patchsvg"].editmode .comment .border { 270 | stroke: black; 271 | stroke-dasharray: 8 4; 272 | } 273 | 274 | /* A little hack for special canvas of [cnv]. 275 | All other iemguis have a black border, but 276 | [cnv] sets its selection rectangle to the 277 | user-supplied fill color when the object 278 | isn't selected */ 279 | .iemgui .border:not(.mycanvas_border) { 280 | stroke: black; 281 | } 282 | 283 | /* text inside selected objects */ 284 | :not(.gop).selected text { 285 | fill: black; 286 | } 287 | 288 | .graph .border { 289 | stroke: black; 290 | fill: none; 291 | } 292 | 293 | /* Graph (or subpatch) that has been opened to inspect its contents */ 294 | .graph.has_window .border { 295 | stroke: black; 296 | fill: none; 297 | } 298 | 299 | /* border color for selected objects 300 | * an element with the class "border" 301 | * the element is contained within a parent element of class "selected" 302 | * that parent element is not in class "gop" 303 | in plain English: 304 | This lets us highlight an object's border, unless it is inside a gop 305 | canvas. 306 | */ 307 | :not(.gop).selected .border { 308 | stroke: blue; 309 | display: inline; 310 | } 311 | 312 | /* for an object that didn't create */ 313 | .obj .border.broken_border { 314 | fill: none; 315 | stroke: #f00; 316 | stroke-dasharray: 3 2; 317 | } 318 | 319 | /* control inlet */ 320 | .xlet_control { 321 | stroke: black; 322 | fill: black; 323 | // stroke-width: 1; 324 | } 325 | 326 | /* signal inlet */ 327 | .xlet_signal { 328 | stroke: black; 329 | fill: black; 330 | stroke-width: 1; 331 | } 332 | 333 | /* iemgui inlet or outlet */ 334 | .xlet_iemgui { 335 | stroke: black; 336 | fill: black; 337 | stroke-width: 1; 338 | } 339 | 340 | /* text label for an iemgui */ 341 | .iemgui_label_selected { 342 | fill: blue; 343 | } 344 | 345 | /* test of xlet hover animation... this should 346 | probably use the web animation API instead. That 347 | way the animation won't get cut off when you 348 | move off the object */ 349 | @-webkit-keyframes fizzle { 350 | 0% { 351 | stroke-width: 1; 352 | stroke-opacity: 1; 353 | rx: 1; 354 | ry: 1; 355 | } 356 | 100% { 357 | stroke-width: 20; 358 | stroke-opacity: 0.2; 359 | rx: 50; 360 | ry: 50; 361 | } 362 | } 363 | 364 | /* can't remember why this was tagged !important */ 365 | .xlet_selected { 366 | stroke: purple !important; 367 | fill: purple; 368 | -webkit-animation: fizzle 0.5s linear 1; 369 | } 370 | 371 | #canvas_find { 372 | width: 100%; 373 | height: 1em; 374 | padding: 3px; 375 | background: silver; 376 | position: fixed; 377 | bottom: 0; 378 | left: 0; 379 | } 380 | 381 | /* Search dialog */ 382 | 383 | .search_body { 384 | font-family: "DejaVu Sans", sans-serif; 385 | font-size: 10pt; 386 | padding: 8px; 387 | } 388 | 389 | /* Common to all dialogs */ 390 | 391 | .dialog_body { 392 | font-family: "DejaVu Sans", sans-serif; 393 | font-size: 10pt; 394 | background-color: #f3f3f3; 395 | } 396 | 397 | .submit_buttons { 398 | text-align: center; 399 | padding: 8px; 400 | } 401 | 402 | fieldset { 403 | background-color:#eeeeee; 404 | border-radius:3px; 405 | border:2px solid black; 406 | margin-left:auto; 407 | margin-right:auto; 408 | padding: 10px; 409 | } 410 | 411 | .hidden { 412 | display: none; 413 | } 414 | 415 | .container{ 416 | display: none; 417 | } 418 | 419 | /* Iemgui dialog */ 420 | 421 | input[type="text"]{ 422 | width:3em; 423 | } 424 | 425 | input[type="number"]{ 426 | width:3em; 427 | } 428 | 429 | label { 430 | text-align: right; 431 | } 432 | 433 | /* Pair of properties that are related */ 434 | .pair { 435 | width: 75%; 436 | text-align: left; 437 | align: left; 438 | } 439 | 440 | .item1 { 441 | width: 50%; 442 | } 443 | 444 | .item2 { 445 | width: 50%; 446 | } 447 | 448 | input[name="x_offset"] { 449 | width: 2em; 450 | } 451 | 452 | input[name="y_offset"] { 453 | width: 2em; 454 | } 455 | 456 | input[name="send_symbol"] { 457 | width: 8em; 458 | } 459 | 460 | input[name="receive_symbol"] { 461 | width: 8em; 462 | } 463 | 464 | input[name="label"] { 465 | width: 8em; 466 | } 467 | 468 | input[name="font_size"] { 469 | width: 3em; 470 | } 471 | 472 | input[name="startup_flags"] { 473 | width: 16em; 474 | } 475 | 476 | /* Canvas dialog */ 477 | 478 | div.x-scale { 479 | padding: 3px; 480 | text-align: center; 481 | } 482 | 483 | div.gop-range { 484 | } 485 | 486 | div.y1 { 487 | text-align: center; 488 | padding: 3px; 489 | } 490 | 491 | div.x1 { 492 | text-align: center; 493 | padding: 3px; 494 | } 495 | 496 | div.y2 { 497 | text-align: center; 498 | padding: 3px; 499 | } 500 | 501 | .disabled { 502 | color: #aaa; 503 | } 504 | 505 | /* Preferences dialog */ 506 | 507 | #prefs_html_element { 508 | /* height: 100%; */ 509 | margin: 0px; 510 | padding: 0px; 511 | height: 100vh; 512 | } 513 | 514 | .prefs_body { 515 | padding: 0px; 516 | } 517 | 518 | #prefs_container { 519 | display: table; 520 | } 521 | 522 | /* Main tab widget */ 523 | 524 | /* All the display, width, and height settings below are a house of cards. 525 | I don't have the schooling to actually predict how all these CSS elements 526 | work together to create the whole. I just fudged around until I found a 527 | way to get the buttons anchored at the bottom of the dialog without 528 | triggering scrollbars to appear. If someone knows a way to do it "right" 529 | without becoming an order of magnitude more complex, do feel free... */ 530 | .prefs_tab_group { 531 | display: table; 532 | width: 90%; 533 | } 534 | 535 | /* Configure the radio buttons to hide off-screen */ 536 | .prefs_tab { 537 | position: absolute; 538 | left:-100px; 539 | top:-100px; 540 | } 541 | 542 | /* Configure labels to look like tabs */ 543 | .prefs_tab + label { 544 | /* inline-block such that the label can be given dimensions */ 545 | display: inline-block; 546 | /* A nice curved border around the tab */ 547 | border: 1px solid #bbb; 548 | border-top-left-radius: 5px; 549 | border-top-right-radius: 5px; 550 | /* the bottom border is handled by the tab content div */ 551 | border-bottom: 0; 552 | /* Padding around tab text */ 553 | padding: 5px 10px; 554 | /* put a small margin to the left to make the first tab clear */ 555 | margin-left: 4px; 556 | margin-top: 8px; 557 | margin-bottom: 0px; 558 | /* Set the background color to default gray (non-selected tab) */ 559 | background-color:#ececec; 560 | } 561 | 562 | /* Focused tabs */ 563 | .prefs_tab:focus + label { 564 | border: 1px dashed #bbb; 565 | } 566 | 567 | /* Checked tabs must be white with the bottom border removed */ 568 | .prefs_tab:checked + label { 569 | background-color: #f3f3f3; 570 | text-shadow: 1px 0px 0px; /* substitute for "bold" to retain div width */ 571 | border-bottom: 1px solid #f3f3f3; 572 | margin-bottom: -1px; 573 | } 574 | 575 | /* The tab content must fill the widgets size and have a nice border */ 576 | .prefs_tab_group > div { 577 | display: none; 578 | border-top: 1px solid #ddd; 579 | padding: 0px; 580 | margin: 0px; 581 | height: 100%; 582 | } 583 | 584 | /* This matches tabs displaying to their associated radio inputs */ 585 | .tab1:checked ~ .tab1, .tab2:checked ~ .tab2, .tab3:checked ~ .tab3, .tab4:checked ~ .tab4 { 586 | display: table; 587 | padding: 8px; 588 | line-height: 20px; 589 | width: 100%; 590 | height: 78vh; 591 | } 592 | 593 | .tab_settings { 594 | padding-top: 8px; 595 | } 596 | 597 | /* Sample rate input */ 598 | input[name="rate"] { 599 | width: 4em; 600 | } 601 | 602 | #prefs_buttons { 603 | display: table; 604 | height: 10vh; 605 | padding: 0px; 606 | margin: 0px; 607 | margin-top: -10px; 608 | margin-bottom: -10px; 609 | padding: 30px; 610 | } 611 | -------------------------------------------------------------------------------- /css/vanilla_inverted.css: -------------------------------------------------------------------------------- 1 | /* Global CSS */ 2 | 3 | /* 4 | @font-face { 5 | font-family: "DejaVu Sans Mono"; 6 | src: url("../DejaVuSansMono.ttf"); 7 | } 8 | */ 9 | 10 | body { 11 | margin: 0px; 12 | font-family: "DejaVu Sans Mono"; 13 | } 14 | 15 | .noselect { 16 | -webkit-touch-callout: none; 17 | -webkit-user-select: none; 18 | -khtml-user-select: none; 19 | -moz-user-select: none; 20 | -ms-user-select: none; 21 | user-select: none; 22 | } 23 | 24 | ::selection { 25 | background: white; 26 | color: black; 27 | } 28 | 29 | /* The main Pd Window */ 30 | 31 | #console_controls { 32 | background-color: LightGray; 33 | height: 50px; 34 | } 35 | 36 | #control_frame { 37 | padding: 12px; 38 | } 39 | 40 | #printout { 41 | margin: 8px; 42 | } 43 | 44 | #console_bottom { 45 | position: absolute; 46 | top: 50px; 47 | left: 0px; 48 | right: 0px; 49 | bottom: 0px; 50 | overflow-y: scroll; 51 | background: black; 52 | color: white; 53 | } 54 | 55 | /* The console API allows classes for different types of messages to print. 56 | Currently the only class is "error". More may be added, especially once 57 | we port the "loglevel" functionality that was available in Pd Extended. */ 58 | #console_bottom .error { 59 | color: blue; 60 | } 61 | 62 | #console_bottom .error a { 63 | color: red; 64 | } 65 | 66 | /* Find bar */ 67 | 68 | #console_find label, #canvas_find label { 69 | font-family: "DejaVu Sans", sans-serif; 70 | font-size: 10pt; 71 | } 72 | 73 | /* marks for matches to console_find */ 74 | mark { 75 | background: white !important; 76 | padding: 0 !important; 77 | } 78 | 79 | mark.console_find_current.console_find_highlighted, 80 | mark.console_find_current { 81 | background: yellow !important; 82 | } 83 | 84 | mark.console_find_highlighted { 85 | background: #6bd4e6 !important; 86 | } 87 | 88 | #console_find { 89 | width: 100%; 90 | height: 1em; 91 | padding: 0.2em; 92 | background: silver; 93 | position: fixed; 94 | bottom: 0; 95 | left: 0; 96 | } 97 | 98 | /* Pure Data Patch Window (aka canvas) */ 99 | 100 | /* canvas font and background color. (Note: margin needs to stay at zero.) */ 101 | .patch_body { 102 | background-color: black; 103 | } 104 | 105 | #selection_rectangle { 106 | stroke: white; 107 | } 108 | 109 | /* The outline to show the visible area for a Graph-On-Parent canvas, 110 | i.e., the "red rectangle" */ 111 | .gop_rect { 112 | fill: none; 113 | stroke: blue; 114 | stroke-opacity: 0.8; 115 | } 116 | 117 | .cord.signal { 118 | stroke-width: 2; 119 | stroke: white; 120 | } 121 | 122 | .cord.control { 123 | stroke-width: 1; 124 | stroke: white; 125 | } 126 | 127 | /* selected connection between objects */ 128 | .cord.signal.selected_line, 129 | .cord.control.selected_line { 130 | stroke: blue; 131 | } 132 | 133 | #cord_inspector_rect { 134 | fill: white; 135 | stroke: white; 136 | } 137 | 138 | #cord_inspector_text { 139 | fill: black; 140 | } 141 | 142 | #cord_inspector_text.flash { 143 | fill: #e87216; 144 | } 145 | 146 | /* text inside boxes: message boxes, object boxes, graphs, comments, etc. */ 147 | .box_text { 148 | fill: white; 149 | } 150 | 151 | /* hyperlinks: for now, just pddplink and helplink */ 152 | .pd_link text { 153 | fill: white; 154 | } 155 | 156 | .pd_link text:hover { 157 | fill: red; 158 | } 159 | 160 | .pd_link.selected text { 161 | fill: yellow; 162 | } 163 | 164 | #bubbles { 165 | stroke: red; 166 | } 167 | 168 | #new_object_textentry { 169 | /* max-width: 10ch; */ 170 | min-width: 3ch; 171 | position: absolute; 172 | display: table-cell; 173 | padding: 3px 2px 3px 2px; 174 | /* box-shadow: inset 1px 0px 0px 1px #000; */ 175 | color: white; /* text color */ 176 | background-color: transparent; 177 | white-space: pre-wrap; 178 | overflow-wrap: break-word; 179 | -webkit-margin-before: 0px; 180 | } 181 | 182 | #new_object_textentry.obj { 183 | outline: 1px solid yellow; 184 | } 185 | 186 | #new_object_textentry.msg { 187 | outline: 0px solid yellow; 188 | background-image: url(../msg-box.svg); 189 | } 190 | 191 | p.msg::after { 192 | content: ""; 193 | height: 100%; 194 | width: 5px; 195 | background-image: url(../msg-box-flag.svg); 196 | position: absolute; 197 | top: 0%; 198 | left: 100%; 199 | } 200 | 201 | /* not sure what this is doing here... */ 202 | text { 203 | // fill: red; 204 | //cursor: default; 205 | } 206 | 207 | /* not sure if this is still needed */ 208 | .selected_border { 209 | stroke: blue; 210 | stroke-dasharray: none; 211 | stroke-width: 1; 212 | } 213 | 214 | .msg .border { 215 | stroke: white; 216 | fill: none; 217 | } 218 | 219 | /* state of msg box when clicking it */ 220 | .msg.flashed .border { 221 | stroke-width: 4; 222 | } 223 | 224 | /* atom box */ 225 | .atom .border { 226 | stroke: white; 227 | fill: none; 228 | } 229 | 230 | /* for dropdown box we want to visually distinguish boxes that output 231 | the index from boxes that output the value. For now we do that by 232 | stroking the arrow for boxes that output an index. For boxes that 233 | output the value we don't need a CSS rule, as the arrow will be filled 234 | black by default */ 235 | .atom .index_arrow { 236 | stroke: white; 237 | stroke-width: 1; 238 | fill: none; 239 | } 240 | 241 | .atom .value_arrow { 242 | fill: white; 243 | } 244 | 245 | /* gatom "activated" text (i.e., when it has the keyboard focus) */ 246 | .atom.activated text { 247 | fill: red; 248 | } 249 | 250 | #dropdown_list { 251 | position: absolute; 252 | border-width: 1px; 253 | border-style: solid; 254 | border-color: white; 255 | cursor: pointer; 256 | color: white; 257 | overflow-y: auto; 258 | } 259 | 260 | #dropdown_list ol { 261 | list-style-position: inside; 262 | margin: 0; 263 | padding: 0; 264 | background: black; 265 | } 266 | 267 | #dropdown_list li { 268 | list-style-type: none; 269 | padding: 5px; 270 | } 271 | 272 | #dropdown_list li.highlighted { 273 | background: #c3c3c3; 274 | color: black; 275 | } 276 | 277 | .obj .border { 278 | fill: none; 279 | stroke: white; 280 | } 281 | 282 | .comment .border { 283 | fill: none; 284 | } 285 | 286 | svg[id^="patchsvg"].editmode .comment .border { 287 | stroke: white; 288 | stroke-dasharray: 8 4; 289 | } 290 | 291 | /* A little hack for special canvas of [cnv]. 292 | All other iemguis have a black border, but 293 | [cnv] sets its selection rectangle to the 294 | user-supplied fill color when the object 295 | isn't selected */ 296 | .iemgui .border:not(.mycanvas_border) { 297 | stroke: white; 298 | } 299 | 300 | /* text inside selected objects */ 301 | :not(.gop).selected text { 302 | fill: white; 303 | } 304 | 305 | .graph .border { 306 | stroke: white; 307 | fill: none; 308 | } 309 | 310 | /* Graph (or subpatch) that has been opened to inspect its contents */ 311 | .graph.has_window .border { 312 | stroke: white; 313 | fill: gray; 314 | } 315 | 316 | /* border color for selected objects 317 | * an element with the class "border" 318 | * the element is contained within a parent element of class "selected" 319 | * that parent element is not in class "gop" 320 | in plain English: 321 | This lets us highlight an object's border, unless it is inside a gop 322 | canvas. 323 | */ 324 | :not(.gop).selected .border { 325 | stroke: yellow; 326 | display: inline; 327 | } 328 | 329 | /* for an object that didn't create */ 330 | .obj .border.broken_border { 331 | fill: none; 332 | stroke: #f00; 333 | stroke-dasharray: 3 2; 334 | } 335 | 336 | /* control inlet */ 337 | .xlet_control { 338 | stroke: white; 339 | fill: white; 340 | // stroke-width: 1; 341 | } 342 | 343 | /* signal inlet */ 344 | .xlet_signal { 345 | stroke: white; 346 | fill: white; 347 | stroke-width: 1; 348 | } 349 | 350 | /* iemgui inlet or outlet */ 351 | .xlet_iemgui { 352 | stroke: white; 353 | fill: white; 354 | stroke-width: 1; 355 | } 356 | 357 | /* text label for an iemgui */ 358 | .iemgui_label_selected { 359 | fill: blue; 360 | } 361 | 362 | /* test of xlet hover animation... this should 363 | probably use the web animation API instead. That 364 | way the animation won't get cut off when you 365 | move off the object */ 366 | @-webkit-keyframes fizzle { 367 | 0% { 368 | stroke-width: 1; 369 | } 370 | 100% { 371 | stroke-width: 8; 372 | } 373 | } 374 | 375 | /* can't remember why this was tagged !important */ 376 | .xlet_selected { 377 | stroke: gray !important; 378 | fill: gray; 379 | -webkit-animation: fizzle 0.5s linear 1; 380 | } 381 | 382 | #canvas_find { 383 | width: 100%; 384 | height: 1em; 385 | padding: 3px; 386 | background: silver; 387 | position: fixed; 388 | bottom: 0; 389 | left: 0; 390 | } 391 | 392 | /* Dialog to ask to save the patch before quitting */ 393 | #save_before_quit { 394 | color: white; 395 | background-color: black; 396 | border:1px solid white; 397 | } 398 | 399 | /* Search dialog */ 400 | 401 | .search_body { 402 | font-family: "DejaVu Sans", sans-serif; 403 | font-size: 10pt; 404 | padding: 8px; 405 | } 406 | 407 | /* Common to all dialogs */ 408 | 409 | .dialog_body { 410 | font-family: "DejaVu Sans", sans-serif; 411 | font-size: 10pt; 412 | background-color: #f3f3f3; 413 | } 414 | 415 | .submit_buttons { 416 | text-align: center; 417 | padding: 8px; 418 | } 419 | 420 | fieldset { 421 | background-color:#eeeeee; 422 | border-radius:3px; 423 | border:2px solid black; 424 | margin-left:auto; 425 | margin-right:auto; 426 | padding: 10px; 427 | } 428 | 429 | .hidden { 430 | display: none; 431 | } 432 | 433 | .container{ 434 | display: none; 435 | } 436 | 437 | /* Iemgui dialog */ 438 | 439 | input[type="text"]{ 440 | width:3em; 441 | } 442 | 443 | input[type="number"]{ 444 | width:3em; 445 | } 446 | 447 | label { 448 | text-align: right; 449 | } 450 | 451 | /* Pair of properties that are related */ 452 | .pair { 453 | width: 75%; 454 | text-align: left; 455 | align: left; 456 | } 457 | 458 | .item1 { 459 | width: 50%; 460 | } 461 | 462 | .item2 { 463 | width: 50%; 464 | } 465 | 466 | input[name="x_offset"] { 467 | width: 2em; 468 | } 469 | 470 | input[name="y_offset"] { 471 | width: 2em; 472 | } 473 | 474 | input[name="send_symbol"] { 475 | width: 8em; 476 | } 477 | 478 | input[name="receive_symbol"] { 479 | width: 8em; 480 | } 481 | 482 | input[name="label"] { 483 | width: 8em; 484 | } 485 | 486 | input[name="font_size"] { 487 | width: 3em; 488 | } 489 | 490 | input[name="startup_flags"] { 491 | width: 16em; 492 | } 493 | 494 | /* Canvas dialog */ 495 | 496 | div.x-scale { 497 | padding: 3px; 498 | text-align: center; 499 | } 500 | 501 | div.gop-range { 502 | } 503 | 504 | div.y1 { 505 | text-align: center; 506 | padding: 3px; 507 | } 508 | 509 | div.x1 { 510 | text-align: center; 511 | padding: 3px; 512 | } 513 | 514 | div.y2 { 515 | text-align: center; 516 | padding: 3px; 517 | } 518 | 519 | .disabled { 520 | color: #aaa; 521 | } 522 | 523 | /* Preferences dialog */ 524 | 525 | #prefs_html_element { 526 | /* height: 100%; */ 527 | margin: 0px; 528 | padding: 0px; 529 | height: 100vh; 530 | } 531 | 532 | .prefs_body { 533 | padding: 0px; 534 | } 535 | 536 | #prefs_container { 537 | display: table; 538 | } 539 | 540 | /* Main tab widget */ 541 | 542 | /* All the display, width, and height settings below are a house of cards. 543 | I don't have the schooling to actually predict how all these CSS elements 544 | work together to create the whole. I just fudged around until I found a 545 | way to get the buttons anchored at the bottom of the dialog without 546 | triggering scrollbars to appear. If someone knows a way to do it "right" 547 | without becoming an order of magnitude more complex, do feel free... */ 548 | .prefs_tab_group { 549 | display: table; 550 | width: 90%; 551 | } 552 | 553 | /* Configure the radio buttons to hide off-screen */ 554 | .prefs_tab { 555 | position: absolute; 556 | left:-100px; 557 | top:-100px; 558 | } 559 | 560 | /* Configure labels to look like tabs */ 561 | .prefs_tab + label { 562 | /* inline-block such that the label can be given dimensions */ 563 | display: inline-block; 564 | /* A nice curved border around the tab */ 565 | border: 1px solid #bbb; 566 | border-top-left-radius: 5px; 567 | border-top-right-radius: 5px; 568 | /* the bottom border is handled by the tab content div */ 569 | border-bottom: 0; 570 | /* Padding around tab text */ 571 | padding: 5px 10px; 572 | /* put a small margin to the left to make the first tab clear */ 573 | margin-left: 4px; 574 | margin-top: 8px; 575 | margin-bottom: 0px; 576 | /* Set the background color to default gray (non-selected tab) */ 577 | background-color:#ececec; 578 | } 579 | 580 | /* Focused tabs */ 581 | .prefs_tab:focus + label { 582 | border: 1px dashed #bbb; 583 | } 584 | 585 | /* Checked tabs must be white with the bottom border removed */ 586 | .prefs_tab:checked + label { 587 | background-color: #f3f3f3; 588 | text-shadow: 1px 0px 0px; /* substitute for "bold" to retain div width */ 589 | border-bottom: 1px solid #f3f3f3; 590 | margin-bottom: -1px; 591 | } 592 | 593 | /* The tab content must fill the widgets size and have a nice border */ 594 | .prefs_tab_group > div { 595 | display: none; 596 | border-top: 1px solid #ddd; 597 | padding: 0px; 598 | margin: 0px; 599 | height: 100%; 600 | } 601 | 602 | /* This matches tabs displaying to their associated radio inputs */ 603 | .tab1:checked ~ .tab1, .tab2:checked ~ .tab2, .tab3:checked ~ .tab3, .tab4:checked ~ .tab4 { 604 | display: table; 605 | padding: 8px; 606 | line-height: 20px; 607 | width: 100%; 608 | height: 78vh; 609 | } 610 | 611 | .tab_settings { 612 | padding-top: 8px; 613 | } 614 | 615 | /* Sample rate input */ 616 | input[name="rate"] { 617 | width: 4em; 618 | } 619 | 620 | #prefs_buttons { 621 | display: table; 622 | height: 10vh; 623 | padding: 0px; 624 | margin: 0px; 625 | margin-top: -10px; 626 | margin-bottom: -10px; 627 | padding: 30px; 628 | } 629 | -------------------------------------------------------------------------------- /css/webapp/webapp.css: -------------------------------------------------------------------------------- 1 | .console-webapp { 2 | position: relative; 3 | top: 0px; 4 | left: 0px; 5 | right: 0px; 6 | bottom: 0px; 7 | overflow-y: scroll; 8 | } 9 | 10 | #container { 11 | overflow: hidden; 12 | } 13 | 14 | #console_bottom{ 15 | position: relative !important; 16 | top: 0px !important; 17 | } 18 | 19 | .console-find-webapp { 20 | position: relative !important; 21 | background-color: transparent !important; 22 | right: 0px; 23 | } 24 | 25 | /** Rotate */ 26 | .rotate{ 27 | transform: rotate(180deg); 28 | } 29 | 30 | .rotate-transition { 31 | transition: transform 0.3s linear; 32 | } 33 | 34 | .collapsing { 35 | visibility: hidden; 36 | } 37 | 38 | .highlight-find{ 39 | margin-left: 10px; 40 | } 41 | 42 | #canvas_container{ 43 | display: flex !important; 44 | background-color: red !important; 45 | } 46 | 47 | #sidebar-collapse{ 48 | position: absolute; 49 | top: 0px; 50 | left: 0px; 51 | z-index: 5; 52 | color: #007BFF; 53 | cursor: pointer; 54 | } 55 | 56 | #sidebar-files ul{ 57 | list-style-type: none; 58 | cursor: pointer; 59 | padding: 0; 60 | } 61 | 62 | #sidebar-files ul li{ 63 | padding-bottom: 10px; 64 | 65 | } 66 | 67 | #sidebar-files ul li a:hover { 68 | color: #007BFF; 69 | } 70 | 71 | #file-icons { 72 | display: none; 73 | } 74 | 75 | #list-item:hover > div { 76 | display: flex; 77 | display: inline-block; 78 | } 79 | 80 | #list-item > li { 81 | max-width: 150px; 82 | } 83 | 84 | #list-item:hover > li { 85 | max-width: 75px; 86 | } 87 | 88 | #content { 89 | position: relative; 90 | } 91 | 92 | .content-webapp { 93 | height: calc(100vh - 38px); 94 | width: 100%; 95 | } 96 | 97 | #content-canvas { 98 | position: relative; 99 | } 100 | 101 | /* Webapp Menu */ 102 | nav { 103 | position: relative; 104 | z-index: 999999; 105 | width: 100%; 106 | } 107 | 108 | .clearfix:after { 109 | content: '.'; 110 | display: block; 111 | clear: both; 112 | height: 0; 113 | line-height: 0; 114 | font-size: 0; 115 | visibility: hidden; 116 | overflow: hidden; 117 | } 118 | 119 | #patch-menu { 120 | width: 100%; 121 | } 122 | 123 | .menu, .menu li ul, .patch-menu, .patch-menu li ul{ 124 | background-color: #EFF0F1; 125 | margin: 0px; 126 | padding: 0px; 127 | list-style:none; 128 | float:left; 129 | font-size: 14px; 130 | width: 100%; 131 | border: 1px solid #C0C2C4; 132 | z-index: 1000000; 133 | } 134 | 135 | .menu li{ 136 | display: none; 137 | position: relative; 138 | padding: 7px 10px; 139 | cursor: pointer; 140 | } 141 | 142 | .patch-menu li{ 143 | position: relative; 144 | padding: 5px 10px; 145 | cursor: pointer; 146 | } 147 | 148 | .menu > li, .patch-menu > li { 149 | float: left; 150 | } 151 | 152 | .menu > li:hover, .patch-menu > li:hover { 153 | float: left; 154 | background-color: #6bd4e6; 155 | } 156 | 157 | .menu li ul, .patch-menu li ul{ 158 | display: none; 159 | position: absolute; 160 | min-width: 250px; 161 | } 162 | 163 | .menu li ul li:hover, .patch-menu li ul li:hover{ 164 | background-color: #6bd4e6; 165 | } 166 | 167 | .menu li ul li ul{ 168 | top: 0; 169 | left: 100%; 170 | } 171 | 172 | .menu > li > ul > li span, .menu > li > ul > label > li span, .patch-menu > li > ul > li span { 173 | float: right; 174 | font-size: small; 175 | color: #777; 176 | } 177 | 178 | /* Input file */ 179 | .menu label input[type="file"] { 180 | display: none; 181 | } 182 | .menu label { 183 | margin: 0px; 184 | width: 100%; 185 | text-align: left; 186 | } 187 | 188 | li .hr{ 189 | display: block !important; 190 | margin: 0px; 191 | padding: 0px; 192 | width: 100%; 193 | } 194 | 195 | .hr > hr{ 196 | margin: 0px; 197 | padding: 0px; 198 | } 199 | 200 | #pd-info{ 201 | display: block; 202 | font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", "Liberation Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; 203 | } 204 | 205 | #pd-info img{ 206 | height: 50px; 207 | } 208 | 209 | /* Popup */ 210 | #popup{ 211 | background-color: #EFF0F1; 212 | margin: 0px; 213 | padding: 0px; 214 | font-size: 12px; 215 | border: 1px solid #C0C2C4; 216 | z-index: 999999; 217 | position: absolute; 218 | list-style:none; 219 | border-radius: 4px; 220 | box-shadow: 0 4px 8px 0 rgba(49, 49, 49, 0.15), 0 6px 20px 0 rgba(0, 0, 0, 0.14); 221 | } 222 | 223 | #popup li{ 224 | position: relative; 225 | padding: 5px 10px; 226 | cursor: pointer; 227 | } 228 | 229 | #popup > li:hover{ 230 | background-color: #6bd4e6; 231 | } 232 | 233 | .popup-disabled{ 234 | color: #858688; 235 | } 236 | .popup-disabled:hover{ 237 | background-color: transparent !important; 238 | } 239 | 240 | /* Webapp Index layout */ 241 | #sidebar{ 242 | background-color: transparent; 243 | min-width: 200px; 244 | max-width: 200px; 245 | margin: 0px; 246 | margin-top: 10px; 247 | border-top-width: 0ch; 248 | } 249 | 250 | #windows{ 251 | max-height: 100vh !important; 252 | max-width: 100vw !important; 253 | } 254 | 255 | #canvas-content{ 256 | height: 70%; 257 | } 258 | 259 | #canvas-content > .card-body{ 260 | display: flex !important; 261 | } 262 | 263 | #canvas-container{ 264 | min-height: 100%; 265 | flex-direction: row; 266 | } 267 | 268 | #console_controls{ 269 | background-color: transparent; 270 | } 271 | 272 | #console-window{ 273 | background-color: transparent; 274 | max-height: 30%; 275 | } 276 | 277 | #console-window a{ 278 | text-decoration: none; 279 | } 280 | 281 | #console-header { 282 | height: 50px; 283 | } 284 | .patch{ 285 | flex-basis: 100%; 286 | background-color: #f6f6f6; 287 | border-right: 2px solid hsl(220, 1%, 53%); 288 | overflow: auto; 289 | } 290 | 291 | .patch_window_svg{ 292 | background-color: #f6f6f6; 293 | overflow: visible; 294 | margin-top: 35px; 295 | cursor: pointer; 296 | min-height: 100%; 297 | } 298 | 299 | .patch_window_svg > svg{ 300 | min-height: 100%; 301 | position: relative; 302 | margin-top: -1px; 303 | margin-left: -1px; 304 | overflow: visible; 305 | } 306 | 307 | .patch-holder{ 308 | height: 100%; 309 | font-family: Dejavu Sans Mono !important; 310 | } 311 | 312 | .patch-filename{ 313 | margin: 0; 314 | padding-top: 10px; 315 | padding-bottom: 5px; 316 | cursor: move; 317 | } 318 | 319 | #div-svg-p{ 320 | position: relative; 321 | z-index: 999999; 322 | } 323 | 324 | #sidebar-body { 325 | overflow: auto; 326 | } 327 | 328 | ::-webkit-scrollbar { 329 | width: 14px; 330 | height: 18px; 331 | } 332 | ::-webkit-scrollbar-thumb { 333 | height: 6px; 334 | border: 4px solid rgba(0, 0, 0, 0); 335 | background-clip: padding-box; 336 | -webkit-border-radius: 7px; 337 | background-color: rgba(0, 0, 0, 0.15); 338 | -webkit-box-shadow: inset -1px -1px 0px rgba(0, 0, 0, 0.05), inset 1px 1px 0px rgba(0, 0, 0, 0.05); 339 | } 340 | ::-webkit-scrollbar-button { 341 | width: 0; 342 | height: 0; 343 | display: none; 344 | } 345 | ::-webkit-scrollbar-corner { 346 | background-color: transparent; 347 | } 348 | *[unselectable="on"] { 349 | -moz-user-select: -moz-none; 350 | -khtml-user-select: none; 351 | -webkit-user-select: none; 352 | -ms-user-select: none; 353 | user-select: none; 354 | } 355 | 356 | /* Bootstrap */ 357 | .container-fluid{ 358 | background-color: transparent; 359 | padding: 0px !important; 360 | } 361 | 362 | .card { 363 | border-radius: 0px !important; 364 | } 365 | 366 | .card-body{ 367 | padding: 0px 5px !important; 368 | } 369 | 370 | .card-body > .side-card{ 371 | padding-top: 100px; 372 | } 373 | 374 | /* Fontawesome icons */ 375 | .fa{ 376 | font-size: 1.5em !important; 377 | margin-right: 20px; 378 | } 379 | 380 | #reload-i{ 381 | font-size: 1em !important; 382 | cursor: pointer; 383 | transition: transform 1s linear; 384 | } 385 | 386 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | // Defining create window 2 | function create_window(cid, type, width, height, xpos, ypos, attr_array) { 3 | // todo: make a separate way to format the title for OSX 4 | var my_title; 5 | if (type === "pd_canvas") { 6 | my_title = pdbundle.pdgui.format_window_title( 7 | attr_array.name, 8 | attr_array.dirty, 9 | attr_array.args, 10 | attr_array.dir); 11 | } else { 12 | my_title = type; 13 | } 14 | var my_file = 15 | type === "pd_canvas" ? "pd_canvas.html" : "dialog_" + type + ".html"; 16 | 17 | 18 | var eval_string = "register_window_id(" + 19 | JSON.stringify(cid) + ", " + 20 | JSON.stringify(attr_array) + ");"; 21 | 22 | var pdWindow = function(my_file, params, callback){ 23 | var new_window = {params} 24 | new_window.window = window 25 | new_window.window.on = function (event, callback, record) { 26 | if (event == "loaded"){ 27 | this.addEventListener('load', callback) 28 | } 29 | } 30 | callback(new_window) 31 | 32 | } 33 | 34 | function init_pd_window(f, new_win) { 35 | 36 | if (new_win === pdbundle.pdgui.get_patchwin(cid)) { 37 | // Add canvas html file 38 | $.get("./components/canvas/"+f, function(data){ 39 | $("#canvas-container").append(data) 40 | update_canvas_id(cid); 41 | add_canvas_name(cid, attr_array.name) 42 | register_canvas(cid, attr_array); 43 | }); 44 | 45 | // flag the window as loaded. We may want to wait until the 46 | // DOM window has finished loading for this. 47 | pdbundle.pdgui.set_window_finished_loading(cid); 48 | }else if(new_win === pdbundle.pdgui.get_dialogwin(cid)){ 49 | // Add menu html file 50 | $.get("./components/dialogs/"+f, function(data){ 51 | var dialog_div = new_win.window.document.getElementById("dialog-div"); 52 | 53 | if(dialog_div === null){ 54 | dialog_div = new_win.window.document.createElement('div') 55 | dialog_div.id = "dialog-div"; 56 | } 57 | 58 | // cleaning dialog div 59 | dialog_div.innerHTML = ""; 60 | 61 | $("#dialog-body").prepend(dialog_div.outerHTML) 62 | $("#dialog-div").prepend(data) 63 | var props_map = { 64 | "dialog_prefs.html": "Pd-L20rk", 65 | "dialog_canvas.html": "Canvas", 66 | "dialog_iemgui.html": "Iemgui", 67 | "dialog_gatom.html": "Atom", 68 | "dialog_font.html": "Font" 69 | }; 70 | $("#dialog-title").text(props_map[f] + " Properties"); 71 | 72 | $("#dialog-modal").modal("show"); 73 | // initialize the dialog window 74 | register_dialog(cid,attr_array); 75 | }); 76 | }else { 77 | // If the window is no longer loading, we need to go ahead 78 | // and remove the reference to it in the patchwin array. 79 | // Otherwise we get dangling references to closed windowsE vamo 80 | // and other bugs... 81 | if (!pdbundle.pdgui.window_is_loading(cid)) { 82 | if (type === "pd_canvas") { 83 | pdbundle.pdgui.set_patchwin(cid, undefined); 84 | } else { 85 | pdbundle.pdgui.set_dialogwin(cid, undefined); 86 | } 87 | } 88 | new_win.window.close(true); 89 | } 90 | } 91 | 92 | pdWindow(my_file, { 93 | title: my_title, 94 | position: "center", 95 | focus: true, 96 | width: width, 97 | // We add 23 as a kludge to account for the menubar at the top of 98 | // the window. Ideally we would just get rid of the canvas menu 99 | // altogether to simplify things. But we'd have to add some kind of 100 | // widget for the "Put" menu. 101 | height: height + 23, 102 | x: xpos, 103 | y: ypos 104 | }, function (new_win) { 105 | 106 | if (type === "pd_canvas") { 107 | pdbundle.pdgui.set_patchwin(cid, new_win); 108 | init_pd_window(my_file, new_win); 109 | } else { 110 | pdbundle.pdgui.set_dialogwin(cid, new_win); 111 | init_pd_window(my_file, new_win); 112 | } 113 | }); 114 | } 115 | 116 | function add_menu(){ 117 | // Add menu html file 118 | $.get("./components/menu/menu.html", function (data) { 119 | $("#menu").prepend(data) 120 | create_pd_window_menus(null, window) 121 | }); 122 | } 123 | 124 | function dsp_toggle(){ 125 | // DSP toggle 126 | document.getElementById("dsp_control").addEventListener("click", 127 | function(evt) { 128 | var dsp_state = evt.target.checked ? 1 : 0; 129 | pdbundle.pdgui.pdsend("pd dsp", dsp_state); 130 | } 131 | ); 132 | } 133 | 134 | function create_pd_window_menus(gui, w) { 135 | var type = "web"; 136 | var m = menu_options(type, w); 137 | add_shortcuts(); 138 | load_menu_actions(); 139 | } 140 | 141 | // Init Function 142 | function gui_init(win){ 143 | // Init vars 144 | pdbundle.pdgui.set_pd_window(win); 145 | pdbundle.pdgui.set_new_window_fn(create_window); 146 | add_menu(); 147 | dsp_toggle(); 148 | } 149 | 150 | function initialize_webapp() { 151 | gui_init(window); 152 | }; 153 | -------------------------------------------------------------------------------- /libs/fa/fontawesome_1b8a796d74.js: -------------------------------------------------------------------------------- 1 | window.FontAwesomeCdnConfig = { 2 | autoA11y: { 3 | enabled: false 4 | }, 5 | asyncLoading: { 6 | enabled: false 7 | }, 8 | reporting: { 9 | enabled: false 10 | }, 11 | useUrl: "use.fontawesome.com", 12 | faCdnUrl: "https://cdn.fontawesome.com:443", 13 | code: "1b8a796d74" 14 | }; 15 | !function(){function a(a){var b,c=[],d=document,e=d.documentElement.doScroll,f="DOMContentLoaded",g=(e?/^loaded|^c/:/^loaded|^i|^c/).test(d.readyState);g||d.addEventListener(f,b=function(){for(d.removeEventListener(f,b),g=1;b=c.shift();)b()}),g?setTimeout(a,0):c.push(a)}function b(a,b){var c=!1;return a.split(",").forEach(function(a){var d=new RegExp(a.trim().replace(".","\\.").replace("*","(.*)"));b.match(d)&&(c=!0)}),c}function c(a){"undefined"!=typeof MutationObserver&&new MutationObserver(a).observe(document,{childList:!0,subtree:!0})}function d(a){var b,c,d,e;a=a||"fa",b=document.querySelectorAll("."+a),Array.prototype.forEach.call(b,function(a){c=a.getAttribute("title"),a.setAttribute("aria-hidden","true"),d=a.nextElementSibling?!a.nextElementSibling.classList.contains("sr-only"):!0,c&&d&&(e=document.createElement("span"),e.innerHTML=c,e.classList.add("sr-only"),a.parentNode.insertBefore(e,a.nextSibling))})}!function(){"use strict";function a(a){l.push(a),1==l.length&&k()}function b(){for(;l.length;)l[0](),l.shift()}function c(a){this.a=m,this.b=void 0,this.f=[];var b=this;try{a(function(a){f(b,a)},function(a){g(b,a)})}catch(c){g(b,c)}}function d(a){return new c(function(b,c){c(a)})}function e(a){return new c(function(b){b(a)})}function f(a,b){if(a.a==m){if(b==a)throw new TypeError;var c=!1;try{var d=b&&b.then;if(null!=b&&"object"==typeof b&&"function"==typeof d)return void d.call(b,function(b){c||f(a,b),c=!0},function(b){c||g(a,b),c=!0})}catch(e){return void(c||g(a,e))}a.a=0,a.b=b,h(a)}}function g(a,b){if(a.a==m){if(b==a)throw new TypeError;a.a=1,a.b=b,h(a)}}function h(b){a(function(){if(b.a!=m)for(;b.f.length;){var a=b.f.shift(),c=a[0],d=a[1],e=a[2],a=a[3];try{0==b.a?e("function"==typeof c?c.call(void 0,b.b):b.b):1==b.a&&("function"==typeof d?e(d.call(void 0,b.b)):a(b.b))}catch(f){a(f)}}})}function i(a){return new c(function(b,c){function d(c){return function(d){g[c]=d,f+=1,f==a.length&&b(g)}}var f=0,g=[];0==a.length&&b(g);for(var h=0;h=i?b():document.fonts.load(j(f,f.family),h).then(function(b){1<=b.length?a():setTimeout(c,25)},function(){b()})}c()}),o=new Promise(function(a,b){setTimeout(b,i)});Promise.race([o,n]).then(function(){a(f)},function(){e(f)})}else b(function(){function b(){var b;(b=-1!=q&&-1!=r||-1!=q&&-1!=s||-1!=r&&-1!=s)&&((b=q!=r&&q!=s&&r!=s)||(null===k&&(b=/AppleWebKit\/([0-9]+)(?:\.([0-9]+))/.exec(window.navigator.userAgent),k=!!b&&(536>parseInt(b[1],10)||536===parseInt(b[1],10)&&11>=parseInt(b[2],10))),b=k&&(q==t&&r==t&&s==t||q==u&&r==u&&s==u||q==v&&r==v&&s==v)),b=!b),b&&(w.parentNode&&w.parentNode.removeChild(w),clearTimeout(x),a(f))}function m(){if((new Date).getTime()-l>=i)w.parentNode&&w.parentNode.removeChild(w),e(f);else{var a=document.hidden;!0!==a&&void 0!==a||(q=n.a.offsetWidth,r=o.a.offsetWidth,s=p.a.offsetWidth,b()),x=setTimeout(m,50)}}var n=new c(h),o=new c(h),p=new c(h),q=-1,r=-1,s=-1,t=-1,u=-1,v=-1,w=document.createElement("div"),x=0;w.dir="ltr",d(n,j(f,"sans-serif")),d(o,j(f,"serif")),d(p,j(f,"monospace")),w.appendChild(n.a),w.appendChild(o.a),w.appendChild(p.a),document.body.appendChild(w),t=n.a.offsetWidth,u=o.a.offsetWidth,v=p.a.offsetWidth,m(),g(n,function(a){q=a,b()}),d(n,j(f,'"'+f.family+'",sans-serif')),g(o,function(a){r=a,b()}),d(o,j(f,'"'+f.family+'",serif')),g(p,function(a){s=a,b()}),d(p,j(f,'"'+f.family+'",monospace'))})})},f=h}();var g={observe:function(a,b){for(var c=b.prefix,d=function(a){var b=a.weight?"-"+a.weight:"",d=a.style?"-"+a.style:"",e=a.className?"-"+a.className:"",g=a.className?"-"+a.className+b+d:"",h=document.getElementsByTagName("html")[0].classList,i=function(a){h.add(c+e+"-"+a),h.add(c+g+"-"+a)},j=function(a){h.remove(c+e+"-"+a),h.remove(c+g+"-"+a)};i("loading"),new f(a.familyName).load(a.testString).then(function(){i("ready"),j("loading")},function(){i("failed"),j("loading")})},e=0;e= 0; i--) { 84 | matches[i].classList.remove(highlight_tag); 85 | } 86 | if (state) { 87 | matches = document.getElementById("p1").getElementsByTagName("mark"); 88 | for (i = 0; i < matches.length; i++) { 89 | matches[i].classList.add(highlight_tag); 90 | } 91 | } 92 | } 93 | 94 | var console_find_traverse = (function () { 95 | var count = 0, 96 | console_text = document.getElementById("p1"), 97 | wrap_tag = "mark"; 98 | return { 99 | next: function () { 100 | var i, last, next, 101 | elements = console_text.getElementsByTagName(wrap_tag); 102 | count++; 103 | if (count >= elements.length) { 104 | count = 0; 105 | } else if (count < 0) { 106 | count = elements.length - 1; 107 | } 108 | if (elements.length > 0) { 109 | i = count % elements.length; 110 | elements[i].classList.add("console_find_current"); 111 | if (elements.length > 1) { 112 | last = i === 0 ? elements.length - 1 : i - 1; 113 | next = (i + 1) % elements.length; 114 | elements[last].classList.remove("console_find_current"); 115 | elements[next].classList.remove("console_find_current"); 116 | } 117 | // adjust the scrollbar to make sure the element is visible, 118 | // but only if necessary. 119 | var isFirefox = typeof InstallTrigger !== 'undefined'; // checks if browser is Firefox or not 120 | if (isFirefox) { 121 | elements[i].scrollIntoView(); 122 | } else { 123 | elements[i].scrollIntoViewIfNeeded(); 124 | } 125 | } 126 | }, 127 | previous: function () { 128 | var i, last, prev, 129 | elements = console_text.getElementsByTagName(wrap_tag); 130 | count--; 131 | if (count >= elements.length) { 132 | count = 0; 133 | } else if (count < 0) { 134 | count = elements.length - 1; 135 | } 136 | if (elements.length > 0) { 137 | i = count % elements.length; 138 | elements[i].classList.add("console_find_current"); 139 | if (elements.length > 1) { 140 | last = i === elements.length - 1 ? 0 : i + 1; 141 | prev = (i - 1 + elements.length) % elements.length; 142 | elements[last].classList.remove("console_find_current"); 143 | elements[prev].classList.remove("console_find_current"); 144 | } 145 | // adjust the scrollbar to make sure the element is visible, 146 | // but only if necessary. 147 | var isFirefox = typeof InstallTrigger !== 'undefined'; // checks if browser is Firefox or not 148 | if (isFirefox) { 149 | elements[i].scrollIntoView(); 150 | } else { 151 | elements[i].scrollIntoViewIfNeeded(); 152 | } 153 | } 154 | }, 155 | set_index: function(c) { 156 | count = c; 157 | }, 158 | set_first_match: function() { 159 | var elements = console_text.getElementsByTagName(wrap_tag); 160 | if (elements.length > 0) { 161 | elements[0].classList.add("console_find_current"); 162 | } 163 | // adjust the scrollbar to make sure the element is visible, 164 | // but only if necessary. 165 | var isFirefox = typeof InstallTrigger !== 'undefined'; // checks ifbrowser is Firefox or not 166 | if (isFirefox) { 167 | elements[0].scrollIntoView(); 168 | } else { 169 | elements[0].scrollIntoViewIfNeeded(); 170 | } 171 | } 172 | }; 173 | }()); 174 | 175 | function console_find_keydown(evt) { 176 | if (evt.keyCode === 13) { 177 | console_find_traverse.next(); 178 | evt.stopPropagation(); 179 | evt.preventDefault(); 180 | return false; 181 | } else if (evt.keyCode === 27) { // escape 182 | 183 | } else if (evt.keyCode === 8 || // backspace or delete 184 | evt.keyCode === 46) { 185 | console_find_text(evt, console_find_callback); 186 | } 187 | } 188 | 189 | function console_find_below() { 190 | console_find_traverse.next(); 191 | } 192 | 193 | function console_find_above() { 194 | console_find_traverse.previous(); 195 | } 196 | 197 | --------------------------------------------------------------------------------