diff --git a/pd/nw/css/default.css b/pd/nw/css/default.css index b58290b90e7d76f6f8dc1d771f21e7c3182b807b..a29812f32c6e38daa73038a5b33d465d30baed14 100644 --- a/pd/nw/css/default.css +++ b/pd/nw/css/default.css @@ -27,6 +27,17 @@ body { background: transparent; } +#hscroll:hover, #vscroll:hover { + background-color: rgba(0, 0, 0, 0.39) !important; +} +#hscroll, #vscroll { + background-color: rgba(0, 0, 0, 0.267); +} + +#hscroll, #vscroll { + cursor: -webkit-grabbing; +} + .noselect { -webkit-touch-callout: none; -webkit-user-select: none; @@ -279,7 +290,7 @@ mark.console_find_highlighted { min-width: 3ch; position: absolute; display: table-cell; - padding: 3px 1.5px 3px 1.5px; + padding: 1px 0px 3px 1.5px; margin-left: 1px; /* box-shadow: inset 1px 0px 0px 1px #000; */ color: black; /* text color */ @@ -513,7 +524,7 @@ text { stroke: #e87216; fill: #e87216; stroke-width: 5; - -webkit-animation: fizzle 0.2s ease-in 1; + -webkit-animation: fizzle 0.1s ease-in 1; } .xlet_disabled { @@ -525,8 +536,8 @@ text { width: 100%; height: 1em; padding-top: 2px; - padding-left: 2px; - padding-bottom: 8px; + padding-left: 3px; + padding-bottom: 9px; background: silver; position: fixed; bottom: 0; @@ -537,8 +548,8 @@ text { width: 100%; height: 1em; padding-top: 2px; - padding-left: 2px; - padding-bottom: 8px; + padding-left: 3px; + padding-bottom: 9px; background: silver; position: fixed; bottom: 0; @@ -554,7 +565,7 @@ text { /*box-shadow: 7px 7px 5px grey;*/ left: 50%; top: 50%; - width: 40%; + width: 70%; transform: translate(-50%, -50%); } @@ -575,7 +586,7 @@ dialog::backdrop { .dialog_body { font-family: "DejaVu Sans", sans-serif; font-size: 10pt; - background-color: #f3f3f3; + background: rgba(243, 243, 243, 0.941); /* #f3f3f3f0; */ } .submit_buttons { @@ -583,9 +594,14 @@ dialog::backdrop { padding: 8px; } +form { + margin-left: 4px; + margin-right: 4px; +} + fieldset { /* font-family:Georgia; */ - background-color:#f3f3f3; + background-color: rgba(243, 243, 243, 0.627); /* #f3f3f3a0; */ border-radius:3px; border:1px solid #ddd; margin-left:auto; @@ -651,7 +667,7 @@ input[name="receive_symbol"] { } input[name="label"] { - width: 8em; + width: 9em; } input[name="font_size"] { @@ -662,6 +678,18 @@ input[name="startup_flags"] { width: 16em; } +/* All radios */ +input[type="radio"] { + position: relative; + top: 2px; +} + +/* All checkboxes */ +input[type=checkbox] { + position: relative; + top: 2px; +} + /* Canvas dialog */ div.x-scale { @@ -731,13 +759,13 @@ div.y2 { without becoming an order of magnitude more complex, do feel free... */ .prefs_tab_group { display: table; - width: 90%; + width: 96%; } /* Configure the radio buttons to hide off-screen */ .prefs_tab { position: absolute; - left:-100px; + left:-500px; top:-100px; } @@ -792,6 +820,13 @@ div.y2 { height: 78vh; } +#midi_in1, #midi_in2, #midi_in3, #midi_in4, #midi_in5, + #midi_in6, #midi_in7, #midi_in8, #midi_in9, #midi_in10, + #midi_out1, #midi_out2, #midi_out3, #midi_out4, #midi_out5, + #midi_out6, #midi_out7, #midi_out8, #midi_out9, #midi_out10 { + width: 205px; +} + .tab_settings { padding-top: 8px; } @@ -810,3 +845,68 @@ input[name="rate"] { margin-bottom: -10px; padding: 30px; } + +/* used for the custom dialog titlebar */ +#titlebar { + width: 100%; + height: 20px; + margin-bottom: 4px; + -webkit-app-region: drag; + background-color: gray; + cursor: grab; +} + +#titlebar_buttons { + top: 2px; + right: 2px; + text-align: right; + background-color: gray; +} + +#titlebar_title { + color: white; + position: relative; + left: 1px; + top: 1px; + background-color: gray; +} + +#titlebar_close_button { + width: 16px; + height: 16px; + background: #a2a2a2; + -webkit-app-region: no-drag; + color: #FFF; + font-size: 18px; + text-align: center; + line-height: 16px; + cursor: default; +} + +/*#titlebar_close_button:after { + position: absolute; + right: 6px; + top: 1px; + content: "\d7"; + font-size: 20px; + color: #FFF; +}*/ + +#titlebar_close_button:hover { + background: #b2b2b2; +} + +#titlebar_close_button:active { + background: #e2e2e2; +} + +input[type="color"] { + margin-bottom: 2px; +} + +.foreground_color span, +.background_color span, +.label_color span { + position: relative; + bottom: 2px; +} \ No newline at end of file diff --git a/pd/nw/dialog_canvas.html b/pd/nw/dialog_canvas.html index ed9a8b1068975b4e0e72cca6ef1017828b3168da..fdc41dfb0924005d8385aa5f71e97ff7c2e6f14c 100644 --- a/pd/nw/dialog_canvas.html +++ b/pd/nw/dialog_canvas.html @@ -5,10 +5,21 @@ <link id="page_style" rel="stylesheet" type="text/css" href="css/default.css"> <title>Canvas Dialog</title> </head> - <body class="dialog_body"> + <body class="dialog_body" style="overflow: hidden;"> <div class="container noselect"> + <table id="titlebar"> + <tr> + <td style="width: 100%;"> + <div id="titlebar_title">Canvas Properties</div> + </td> + <td> + <div class="titlebar_buttons"> + <div id="titlebar_close_button" onclick="cancel(false);">×</div> + </div> + </td> + </tr> + </table> <form> - <fieldset class="canvas"> <legend data-i18n="canvas.prop.heading.gop"></legend> @@ -96,7 +107,7 @@ <fieldset class="canvas"> <legend data-i18n="canvas.prop.heading.data_scaling"></legend> -<div style="display: inline-block; align: left;"> +<div style="display: inline-block; margin-right: -5px; width: 100%;"> <div class="x_scale prop hidden"> <nobr> <label class="no_gop_opt" data-i18n="[title]canvas.prop.x_scale_tt"> @@ -140,7 +151,6 @@ </label> </div> </div> -</div> </fieldset> @@ -151,7 +161,7 @@ <select id="arrays_select" class="hidden"></select> </label> - <div class="array-name prop"> + <div class="array-name prop" style="margin-right: -5px;"> <label class="array-name" data-i18n="[title]canvas.prop.array_name_tt"> <span data-i18n="canvas.prop.array_name"></span> @@ -187,7 +197,7 @@ </label> <br/> - <span data-i18n="canvas.prop.array_style"></span> + <span style="position: relative; top: 4px;" data-i18n="canvas.prop.array_style"></span> <br/> <table class="array_style"> <tr> @@ -245,7 +255,7 @@ </table> </div> - <div class="array-fill"> + <div class="array-fill" style="margin-top: 2px;"> <label data-i18n="[title]canvas.prop.array_fill_tt"> <input onchange="update_array_attr(this);" type="color" @@ -289,6 +299,7 @@ </label> </div> </fieldset> +</div> <div class="submit_buttons"> <button type="button" id="ok_button" onClick="ok()" data-i18n="[title]iem.prop.ok_tt"> @@ -620,9 +631,11 @@ function populate_array_form(objects) { a_field = document.getElementById("arrays"), opt, i; a_field.classList.remove("hidden"); + a_field.style.setProperty("height", "240px"); if (objects.length > 1) { // show the select element if there's more than one array arrays_select.classList.remove("hidden"); + arrays_select.style.setProperty("margin", "0px 0px 5px 0px"); } for (i = 0; i < objects.length; i++) { opt = document.createElement("option"); @@ -669,6 +682,7 @@ function register_window_id(gfxstub, attr_objects) { // attr_objects[0]: canvas properties // attr_objects[1...n-1]: array properties add_events(gfxstub); + pdgui.gui_check_for_dialog_appearance_inconsistencies(gfxstub); // not sure that we need this for properties windows... // pdgui.canvas_map(gfxstub); translate_form(); @@ -690,7 +704,7 @@ function register_window_id(gfxstub, attr_objects) { new_array_dialog = false; // this is a canvas/array props dialog populate_form(attr_objects[0]); } - init_arrays(pd_garray_attrs); + init_arrays(pd_garray_attrs); // Disabling the menus does not yet work, so we hide that button for // the moment diff --git a/pd/nw/dialog_data.html b/pd/nw/dialog_data.html index 15f09ae4bbe482adfbed32182e3951dcdce5ecba..aa39420aff0ac23715e18b95e3a30f9f8fc54786 100644 --- a/pd/nw/dialog_data.html +++ b/pd/nw/dialog_data.html @@ -3,14 +3,67 @@ <head> <link id="page_style" rel="stylesheet" type="text/css" href="css/default.css"> </head> - <body class="dialog_body"> + <style> +/* width */ +::-webkit-scrollbar { + width: 5px; +} + +/* Track */ +::-webkit-scrollbar-track { + background: rgba(0,0,0,0); +} + +/* Handle */ +::-webkit-scrollbar-thumb { + background: rgba(0, 0, 0, 0.267); +} + +/* Handle on hover */ +::-webkit-scrollbar-thumb:hover { + background: #888; +} + +input[type=checkbox] { + margin: 2px 0px 8px 0px; +} + +input[type="text"] { + margin-bottom: 3px; +} + +label { + margin-left: 0px; + margin-bottom: 1px; + +} + </style> + <body class="dialog_body" style="overflow: hidden;"> <div class="container"> + <table id="titlebar"> + <tr> + <td style="width: 100%;"> + <div id="titlebar_title">Data Object Properties</div> + </td> + <td> + <div class="titlebar_buttons"> + <div id="titlebar_close_button" onclick="cancel(false);">×</div> + </div> + </td> + </tr> + </table> <form> - <fieldset id="data_container"> - <legend id="legend"></legend> + <fieldset id="data_container" style="height: 267px;"> + <legend id="legend"></legend> + <div id="scrollable_data" style="overflow: auto; height: 250px;"> + <table id="pairs" style="margin-right: 5px;"> + </table> </fieldset> - <div class="submit_buttons"> + <div class="submit_buttons" style=" + text-align: center; + padding: 8px 0px 8px 0px;" + > <button type="button" onClick="ok()" data-i18n="[title]iem.prop.ok_tt"> <span data-i18n="iem.prop.ok"></span> </button> @@ -27,6 +80,8 @@ var gui = require("nw.gui"); var pdgui = require("./pdgui.js"); +//gui.Window.get().setResizable(false); + // For translations var l = pdgui.get_local_string; @@ -146,12 +201,15 @@ function add_textarea_input(first_row) { textarea = document.createElement("textarea"), check_label = document.createElement("label"), check = document.createElement("input"), - outer_container = document.getElementById("data_container"), + outer_container = document.getElementById("pairs"), inner_container = document.createElement("div"), br = document.createElement("br"); label.textContent = "vector fields"; + inner_container.style.setProperty("display", "inline-block"); + inner_container.style.setProperty("width", "100%"); + label.style.setProperty("display", "block"); label.style.setProperty("text-align", "left"); textarea.style.setProperty("display", "block"); @@ -159,7 +217,8 @@ function add_textarea_input(first_row) { textarea.setAttribute("id", "vector_textarea"); textarea.setAttribute("rows", "4"); textarea.setAttribute("col", "5"); - textarea.style.setProperty("width", "11.3em"); + textarea.style.setProperty("width", "97.5%"); + textarea.style.setProperty("resize", "none"); textarea.disabled = true; check.type = "checkbox"; @@ -181,7 +240,7 @@ function add_textarea_input(first_row) { function add_text_input(field, left_column, first_row) { var label = document.createElement("label"), text_input = document.createElement("input"), - outer_container = document.getElementById("data_container"), + outer_container = document.getElementById("pairs"), inner_container = document.createElement("div"), br; inner_container.style.setProperty("float", "left"); @@ -190,6 +249,9 @@ function add_text_input(field, left_column, first_row) { if (left_column && field.type !== "symbol") { inner_container.style.setProperty("margin-right", "1em"); } + if (!left_column) { + inner_container.style.setProperty("float", "right"); + } label.textContent = field["var"]; text_input.type = "text"; text_input.classList.add("scalar_value"); @@ -204,7 +266,7 @@ function add_text_input(field, left_column, first_row) { text_input.style.setProperty("display", "block"); // Also in opposition to iemgui dialogs text_input.style.setProperty("width", - field.type === "float" ? "5em" : "11.3em"); + field.type === "float" ? "5em" : "97.5%"); // Some bottom margin inner_container.style.setProperty("margin-bottom", "8px"); @@ -301,6 +363,7 @@ function register_window_id(gfxstub, data_string) { var head, tail, templates, data, data_separator; pd_object_callback = gfxstub; add_events(gfxstub); + pdgui.gui_check_for_dialog_appearance_inconsistencies(gfxstub); // slice off the head of the message. This is where the templates // for the data-- plus any templates for (nested) arrays-- are kept. // We will keep the head intact for sending back to Pd since the user diff --git a/pd/nw/dialog_dropdown.html b/pd/nw/dialog_dropdown.html new file mode 100644 index 0000000000000000000000000000000000000000..a06e7da2c9e80adf07d6d256b8b5a96c54c8d436 --- /dev/null +++ b/pd/nw/dialog_dropdown.html @@ -0,0 +1,403 @@ +<!DOCTYPE html> +<html> + <head> + <link id="page_style" rel="stylesheet" type="text/css" href="css/default.css"> + </head> + <body class="dialog_body"> + <div class="container noselect"> + <table id="titlebar"> + <tr> + <td style="width: 100%;"> + <div id="titlebar_title">Dropdown Properties</div> + </td> + <td> + <div class="titlebar_buttons"> + <div id="titlebar_close_button" onclick="cancel(false);">×</div> + </div> + </td> + </tr> + </table> + <form> + <fieldset> + <legend id="dialog_header"></legend> + + <table class="pairs"> + <tr class="width prop"> + <td> + <label data-i18n="[title]gatom.prop.width_tt"> + <span data-i18n="gatom.prop.width"></span> + </label> + </td> + <td data-i18n="[title]gatom.prop.width_tt"> + <input type="text" id="width" name="width" + onchange="update_attr(this)"> + </td> + <td> + </td> + <td> + </td> + </tr> + <tr class="draglo prop pair"> + <td> + <label data-i18n="[title]iem.prop.minimum_tt"> + <span data-i18n="iem.prop.minimum"></span> + </label> + </td> + <td data-i18n="[title]iem.prop.minimum_tt"> + <input type="text" id="draglo" name="draglo" + onchange="update_attr(this)"> + </td> + <td> + <label data-i18n="[title]iem.prop.maximum_tt"> + <span data-i18n="iem.prop.maximum"></span> + </label> + </td> + <td data-i18n="[title]iem.prop.maximum_tt"> + <input type="text" id="draghi" name="draghi" + onchange="update_attr(this)"> + </td> + </tr> + + <tr class="outtype prop"> + <td> + <label data-i18n="[title]gatom.prop.dropdown_outtype_tt"> + <span data-i18n="gatom.prop.dropdown_outtype"></span> + </label> + </td> + <td colspan="3" + data-i18n="[title]gatom.prop.dropdown_outtype_tt"> + <select id="outtype_select" + onchange="update_dropdown_outtype(this);"> + <option>index</option> + <option>value</option> + </select> + </td> + </tr> + <tr> + <td> + <label data-i18n="[title]iem.prop.send_tt"> + <span data-i18n="iem.prop.send"></span> + </label> + </td> + <td colspan="3" + data-i18n="[title]iem.prop.send_tt"> + <input type="text" id="send_symbol" name="send_symbol" + onchange="update_attr(this);"> + </td> + </tr> + <tr> + <td> + <label data-i18n="[title]iem.prop.receive_tt"> + <span data-i18n="iem.prop.receive"></span> + </label> + </td> + <td colspan="3" + data-i18n="[title]iem.prop.receive_tt"> + <input type="text" id="receive_symbol" name="receive_symbol" + onchange="update_attr(this);"> + </td> + </tr> + <tr> + <td> + <label data-i18n="[title]gatom.prop.label_tt"> + <span data-i18n="gatom.prop.label"></span> + </label> + </td> + <td colspan="3" + data-i18n="[title]gatom.prop.label_tt"> + <input type="text" id="label" name="label" + onchange="update_attr(this)"> + </td> + </tr> + <tr> + <td> + <label data-i18n="[title]gatom.prop.labelpos_tt"> + <span data-i18n="gatom.prop.labelpos"></span> + </label> + </td> + <td colspan="3"> + <label class="points" + data-i18n="[title]gatom.prop.labelpos_tt"> + + <input class="label-pos" + type="radio" + id="labelpos_top" + value="2" + name="labelpos" + style="margin-left: 27px;" + onchange="update_attr(this)"> + <span data-i18n="gatom.prop.label_top"></span> + + <br/> + + <input class="label-pos" + type="radio" + id="labelpos_left" + value="0" + name="labelpos" + onchange="update_attr(this)"> + <span data-i18n="gatom.prop.label_left"></span> + + <input class="label-pos" + type="radio" + id="labelpos_right" + value="1" + name="labelpos" + onchange="update_attr(this)"> + <span data-i18n="gatom.prop.label_right"></span> + + <br/> + + <input class="label-pos" + type="radio" + id="labelpos_bottom" + value="3" + name="labelpos" + style="margin-left: 27px;" + onchange="update_attr(this)"> + <span data-i18n="gatom.prop.label_bottom"></span> + + </label> + + </table> + + </fieldset> + + <div class="submit_buttons"> + <button type="button" onClick="ok()" data-i18n="[title]iem.prop.ok_tt"> + <span data-i18n="iem.prop.ok"></span> + </button> + <button type="button" onClick="apply()" data-i18n="[title]iem.prop.apply_tt"> + <span data-i18n="iem.prop.apply"></span> + </button> + <button type="button" onClick="cancel(true)" data-i18n="[title]iem.prop.cancel_tt"> + <span data-i18n="iem.prop.cancel"></span> + </button> + </div> + + </form> + </div> + + <script> +"use strict"; +var gui = require("nw.gui"); +var pdgui = require("./pdgui.js"); + +// For translations +var l = pdgui.get_local_string; + +pdgui.skin.apply(window); + +var pd_object_callback, + old_attrs = {}, // original state. Used if we cancel the dialog + new_attrs = {}; // changed state. Used if we apply or click "Ok" + +function substitute_space(arg) { + var fake_space = String.fromCharCode(11); + return arg.split(" ").join(fake_space); +} + +function strip_problem_chars(arg) { + var problem_chars = [";", ",", "\\"]; + var ret = arg; + for(var i = 0; i < problem_chars.length; i++) { + ret = ret.split(problem_chars[i]).join(""); + } + return ret; +} + +function gatom_escape(str) { + var ret; + if (str.length === 0) { + ret = "-"; + } else if (str.slice(0,1) === "-") { + ret = "-" + str; + } else { + var arr = str.split(""); + for (var i = 0; i < arr.length; i++) { + if (arr[i] === "$" && i+1 < arr.length && + arr[i+1] >= "0" && arr[i+1] <= "9") { + arr[i] = "#"; + } + } + ret = arr.join(""); + } + return strip_problem_chars(ret); +} + +function gatom_unescape(str) { + if (str.slice(0,1) === "-") { + str = str.slice(1); + } else { + var arr = str.split(""); + for (var i = 0; i < arr.length; i++) { + if (arr[i] === "#" && i+1 < arr.length && + arr[i+1] >= "0" && arr[i+1] <= "9") { + arr[i] = "$"; + } + } + str = arr.join(""); + } + return str; +} + +function update_attr(elem) { + new_attrs[elem.name] = elem.value; +} + +function update_dropdown_outtype(elem) { + new_attrs.outtype = elem.selectedIndex; +} + +function send_params(attrs, create_undo_point) { + //pdgui.post("we're applying gatom changes!"); + var gatom = attrs.name === "atom"; + pdgui.pdsend(pd_object_callback, "param", + +attrs.width, + gatom ? +attrs.draglo : +attrs.outtype, + gatom ? +attrs.draghi : 0, + gatom_escape(attrs.label), + +attrs.labelpos, + gatom_escape(attrs.receive_symbol), + gatom_escape(attrs.send_symbol), + create_undo_point ? 1 : 0 + ); +} + +function cancel(revert_changes) { + var dirty = false, attr; + //window.close(true); + if (revert_changes) { + for (attr in old_attrs) { + if (old_attrs[attr] !== new_attrs[attr]) { + dirty = true; + } + } + if (dirty) { + send_params(old_attrs, false); + } + } + pdgui.pdsend(pd_object_callback, "cancel"); +} + +function apply() { + send_params(new_attrs, false); +} + +function ok() { + // Steal focus from any active input to make sure it triggers an + // onchange event + document.querySelector("button").focus(); + // send the old attrs first so we can set an undo point on them + send_params(old_attrs, false); + send_params(new_attrs, true); + cancel(false); +} + +// This gets called from the nw_create_window function in index.html +// It provides us with our window id from the C side. Once we have it +// we can create the menu and register event callbacks +function register_window_id(gfxstub, attributes) { + var attr; + pd_object_callback = gfxstub; + add_events(gfxstub); + + // before translating, set the header based on class name: + document.querySelector("#dialog_header") + .setAttribute("data-i18n", "gatom.prop." + + (attributes.name === "dropdown" ? "dropdown" : "gatom")); + + translate_form(); + populate_form(attributes); + + // hide outtype select for "dropdown", or draglo/hi for "gatom" + document.querySelector(attributes.name === "atom" ? ".outtype" : ".draglo") + .style.setProperty("display", "none"); + + + // Hack... change incoming "-" to empty string + if (attributes.label === "-") { attributes.label = ""; } + if (attributes.send_symbol === "-") { attributes.send_symbol= ""; } + if (attributes.receive_symbol === "-") { attributes.receive_symbol = ""; } + + // Initialize the new_attrs to the current ones + for (attr in attributes) { + if (attributes.hasOwnProperty(attr)) { + new_attrs[attr] = attributes[attr]; + } + } + + old_attrs = attributes; + // We don't turn on rendering of the "container" div until + // We've finished displaying all the spans and populating the + // labels and form elements. That makes it more efficient and + // snappier, at least on older machines. + document.getElementsByClassName("container")[0] + .style.setProperty("display", "inline"); + pdgui.resize_window(pd_object_callback); +} + +function tr_text(id) { + var elem = document.getElementById("iem.prop." + id); + elem.textContent = l("iem.prop." + id); +} + +// Stop-gap translator +function translate_form() { + var i + var elements = document.querySelectorAll("[data-i18n]"); + for (i = 0; i < elements.length; i++) { + var data = elements[i].dataset.i18n; + if (data.slice(0,7) === "[title]") { + elements[i].title = l(data.slice(7)); + } else { + elements[i].textContent = l(data); + } + } +} + +function get_attr(name, attrs) { + return attrs[attrs.indexOf(name)+1]; +} + +function get_elem(name) { + return document.getElementById(name); +} + +function populate_form(attributes) { + var label, snd, rcv, labelpos, i, radios; + get_elem("width").value = attributes.width; + if (attributes.name === "atom") { + get_elem("draglo").value = attributes.draglo; + get_elem("draghi").value = attributes.draghi; + } else { + get_elem("outtype_select").selectedIndex = attributes.outtype; + } + label = attributes.label; + get_elem("label").value = gatom_unescape(label); + snd = attributes.send_symbol; + get_elem("send_symbol").value = gatom_unescape(snd); + rcv = attributes.receive_symbol; + get_elem("receive_symbol").value = gatom_unescape(rcv); + + labelpos = attributes.labelpos; + radios = document.getElementsByName("labelpos"); + for (i = 0; i < radios.length; i++) { + if (+radios[i].value === labelpos) { + radios[i].checked = true; + } + } +} + +function add_events(name) { + // closing the Window + gui.Window.get().on("close", function() { + // this needs to do whatever the "cancel" button does + cancel(false); + }); + pdgui.dialog_bindings(name); +} + + </script> + </body> +</html> diff --git a/pd/nw/dialog_external.html b/pd/nw/dialog_external.html index 63b31d643d8e713b56802b9a5f53548e48f4c92c..a2c73209e580af27df4470b6774cb6c448b0308c 100644 --- a/pd/nw/dialog_external.html +++ b/pd/nw/dialog_external.html @@ -3,13 +3,66 @@ <head> <link id="page_style" rel="stylesheet" type="text/css" href="css/default.css"> </head> - <body class="dialog_body"> + <style> +/* width */ +::-webkit-scrollbar { + width: 5px; +} + +/* Track */ +::-webkit-scrollbar-track { + background: rgba(0,0,0,0); +} + +/* Handle */ +::-webkit-scrollbar-thumb { + background: rgba(0, 0, 0, 0.267); +} + +/* Handle on hover */ +::-webkit-scrollbar-thumb:hover { + background: #888; +} + +input[type=checkbox] { + margin: 2px 0px 8px 0px; +} + +input[type="text"] { + margin-bottom: 3px; +} + +label { + margin-left: 5px; +} + </style> + <body class="dialog_body" style="overflow: hidden;"> <div class="container"> + <table id="titlebar"> + <tr> + <td style="width: 100%; margin: 7px;"> + <div id="titlebar_title">External Object Properties</div> + </td> + <td> + <div class="titlebar_buttons"> + <div id="titlebar_close_button" onclick="cancel(false);">×</div> + </div> + </td> + </tr> + </table> + <form> - <fieldset> - <legend></legend> + <fieldset id="data_container" style="height: 267px;"> + <legend></legend> + <div id="scrollable_data" style="overflow: auto; height: 250px;"> + <table id="pairs"> + </table> + </div> </fieldset> - <div class="submit_buttons"> + <div class="submit_buttons" style=" + text-align: center; + padding: 8px 0px 8px 0px;" + > <button type="button" onClick="ok();" id="ok_button" @@ -35,6 +88,8 @@ var gui = require("nw.gui"); var pdgui = require("./pdgui.js"); +//gui.Window.get().setResizable(false); + // For translations var l = pdgui.get_local_string; @@ -122,6 +177,7 @@ function register_window_id(gfxstub, args) { var external_name = args.name, array_of_objects; pd_object_callback = gfxstub; + pdgui.gui_check_for_dialog_appearance_inconsistencies(gfxstub); array_of_objects = parse_attrs(args.attributes); // Store our array for later use new_properties = array_of_objects; @@ -166,7 +222,7 @@ function get_input_type(t) { } function build_form(external_name, array_of_objects) { - var fieldset = document.querySelector("fieldset"); + var fieldset = document.getElementById("pairs"); document.querySelector("legend").textContent = external_name; array_of_objects.forEach(function(elem) { var input_elem = document.createElement("input"), @@ -184,11 +240,15 @@ function build_form(external_name, array_of_objects) { } } label.textContent = elem.label; - label.appendChild(input_elem); - fieldset.appendChild(label); + fieldset.appendChild(input_elem); + fieldset.appendChild(label); // stop-gap until we make this prettier through css: insert a break fieldset.appendChild(document.createElement("br")); }); + // update scrollbars + var parent_fieldset = document.getElementById("data_container"); + fieldset.style.setProperty("height", (parseInt(parent_fieldset.style.getPropertyValue("height")) - 10) + "px"); + } function add_events(name) { diff --git a/pd/nw/dialog_font.html b/pd/nw/dialog_font.html index 2b162ced19386b58393531b64a8c00983da0aa57..ae3de3ce19cd8d0d6d11dd9cca7b0e14c1fdb53b 100644 --- a/pd/nw/dialog_font.html +++ b/pd/nw/dialog_font.html @@ -3,8 +3,20 @@ <head> <link id="page_style" rel="stylesheet" type="text/css" href="css/default.css"> </head> - <body class="dialog_body"> + <body class="dialog_body" style="overflow: hidden;"> <div class="container"> + <table id="titlebar"> + <tr> + <td style="width: 100%;"> + <div id="titlebar_title">Font Size</div> + </td> + <td> + <div class="titlebar_buttons"> + <div id="titlebar_close_button" onclick="cancel(false);">×</div> + </div> + </td> + </tr> + </table> <form> <fieldset> <legend data-i18n="font.prop.size"></legend> diff --git a/pd/nw/dialog_gatom.html b/pd/nw/dialog_gatom.html index 5d0e9fba4c197f45f6fd282d1e4ae39fb2a54e2c..f02bfb3b7d4a9a1cf8c1783e7c025458a5988cf1 100644 --- a/pd/nw/dialog_gatom.html +++ b/pd/nw/dialog_gatom.html @@ -3,13 +3,25 @@ <head> <link id="page_style" rel="stylesheet" type="text/css" href="css/default.css"> </head> - <body class="dialog_body"> - <div class="container"> + <body class="dialog_body" style="overflow: hidden;"> + <div class="container noselect"> + <table id="titlebar"> + <tr> + <td style="width: 100%;"> + <div id="titlebar_title">Atom Properties</div> + </td> + <td> + <div class="titlebar_buttons"> + <div id="titlebar_close_button" onclick="cancel(false);">×</div> + </div> + </td> + </tr> + </table> <form> - <fieldset> + <fieldset style="display: inline-block; margin-right: 4px;"> <legend id="dialog_header"></legend> - <table class="pairs"> + <table class="pairs" style="display: inline-block; width: 232px;"> <tr class="width prop"> <td> <label data-i18n="[title]gatom.prop.width_tt"> @@ -109,15 +121,16 @@ <input class="label-pos" type="radio" - id="labelpos_left" + id="labelpos_top" value="2" name="labelpos" + style="margin-left: 27px;" onchange="update_attr(this)"> <span data-i18n="gatom.prop.label_top"></span> <br/> - <input class="array-style" + <input class="label-pos" type="radio" id="labelpos_left" value="0" @@ -125,7 +138,7 @@ onchange="update_attr(this)"> <span data-i18n="gatom.prop.label_left"></span> - <input class="array-style" + <input class="label-pos" type="radio" id="labelpos_right" value="1" @@ -135,11 +148,12 @@ <br/> - <input class="array-style" + <input class="label-pos" type="radio" id="labelpos_bottom" value="3" name="labelpos" + style="margin-left: 27px;" onchange="update_attr(this)"> <span data-i18n="gatom.prop.label_bottom"></span> @@ -287,6 +301,7 @@ function register_window_id(gfxstub, attributes) { var attr; pd_object_callback = gfxstub; add_events(gfxstub); + pdgui.gui_check_for_dialog_appearance_inconsistencies(gfxstub); // before translating, set the header based on class name: document.querySelector("#dialog_header") diff --git a/pd/nw/dialog_iemgui.html b/pd/nw/dialog_iemgui.html index cd39e492a573f96af0cc09bfca8e87ee0b73e7b3..c176b772200649a4dae064287a3ed96c489e79ac 100644 --- a/pd/nw/dialog_iemgui.html +++ b/pd/nw/dialog_iemgui.html @@ -4,8 +4,20 @@ <link id="page_style" rel="stylesheet" type="text/css" href="css/default.css"> </head> - <body class="dialog_body"> + <body class="dialog_body" style="overflow: hidden;"> <div class="container"> + <table id="titlebar"> + <tr> + <td style="width: 100%;"> + <div id="titlebar_title">Iemgui Properties</div> + </td> + <td> + <div class="titlebar_buttons"> + <div id="titlebar_close_button" onclick="cancel(false);">×</div> + </div> + </td> + </tr> + </table> <form> <fieldset> <legend data-i18n="iem.prop.heading.size"></legend> @@ -24,7 +36,7 @@ </tr> <tr class="selection_size prop hidden"> <td> - <label data-i18n="[title]iem.select_size_tt"> + <label data-i18n="[title]iem.prop.select_size_tt"> <span data-i18n="iem.prop.select_size"></span> </label> </td> @@ -86,7 +98,7 @@ onchange="update_attr(this);"> </td> <td> - <label data-i18n="iem.prop.visible_height"> + <label data-i18n="[title]iem.prop.visible_height_tt"> <span data-i18n="iem.prop.visible_height"></span> </label> </td> @@ -198,7 +210,8 @@ </td> <td data-i18n="[title]iem.prop.send_tt"> <input type="text" name="send_symbol" - onchange="update_attr(this, true);"> + onchange="update_attr(this, true);" + style="width: 12em;"> </td> <td> <tr class="receive_symbol prop hidden"> @@ -209,7 +222,8 @@ </td> <td data-i18n="[title]iem.prop.receive_tt"> <input type="text" name="receive_symbol" - onchange="update_attr(this, true);"> + onchange="update_attr(this, true);" + style="width: 12em;"> </td> <td> </tr> @@ -228,7 +242,8 @@ </td> <td data-i18n="[title]iem.prop.label_tt"> <input type="text" name="label" - onchange="update_attr(this, true);"> + onchange="update_attr(this, true);" + style="width: 131px;"> </td> <td> <label data-i18n="[title]iem.prop.xoffset_tt"> @@ -577,8 +592,10 @@ function register_window_id(gfxstub, attr_object) { new_attrs[attr] = old_attrs[attr]; } } - console.log("attr object is " + attr_object.toString()); + console.log("attr object is " + attr_object.toString() + + " and its type is " + attr_object.type); add_events(gfxstub); + pdgui.gui_check_for_dialog_appearance_inconsistencies(gfxstub); // Special case for [moonlib/mknob] which leverages the iemgui dialog-- // change the label for "height" to "steps" @@ -586,6 +603,11 @@ function register_window_id(gfxstub, attr_object) { change_width_and_height_labels(); } + // ico@vt.edu TODO: translate the window title + // for the timebeing we just give it english version + document.getElementById("titlebar_title").textContent = "[" + + attr_object.type + "] Iemgui Properties"; + translate_form(); populate_form(attr_object); // We don't turn on rendering of the "container" div until diff --git a/pd/nw/dialog_prefs.html b/pd/nw/dialog_prefs.html index 63b18f48859fe1e8cecccd50d62ce24b1ce859e8..d92a02242c4f7e899911f19b5529897130f2fe74 100644 --- a/pd/nw/dialog_prefs.html +++ b/pd/nw/dialog_prefs.html @@ -3,8 +3,25 @@ <head> <link id="page_style" rel="stylesheet" type="text/css" href="css/default.css"> </head> - <body class="dialog_body prefs_body"> + <style> +td { + padding-right: 0px; +} + </style> + <body class="dialog_body prefs_body" style="overflow: hidden;"> <div class="container noselect prefs_container"> + <table id="titlebar"> + <tr> + <td style="width: 100%;"> + <div id="titlebar_title">Pd-L2Ork Properties</div> + </td> + <td> + <div class="titlebar_buttons"> + <div id="titlebar_close_button" onclick="cancel(false);">×</div> + </div> + </td> + </tr> + </table> <div class="prefs_tab_group"> <input type="radio" name="prefs_radio_group" @@ -259,7 +276,7 @@ <span data-i18n="[title]prefs.midi.input_title_tt"> <span data-i18n="prefs.midi.input_title"></span> </span> - <table class="tab_settings"> + <table class="tab_settings" style="width: 100%;"> <tr> <td>1</td><td> <select id="midi_in1" onchange="dev_change(this);"></select> @@ -421,7 +438,8 @@ <label data-i18n="[title]prefs.startup.paths_tt"> <span data-i18n="prefs.startup.paths"></span> </label> - <div style="height:24vh; width:89vw; background:white; border: 1px solid #bbb; overflow-y:auto; overflow-x:auto; padding:0px;"> + <div style="height:24vh; background:white; border: 1px solid #bbb; + margin-right: -4px; overflow-y:auto; overflow-x:auto; padding:0px;"> <table id="startup_paths" style="width:100%; background:white;"> </table> </div> @@ -439,7 +457,8 @@ <label data-i18n="[title]prefs.startup.libs_tt"> <span data-i18n="prefs.startup.libs"></span> </label> - <div style="height:24vh; width:89vw; background:white; border: 1px solid #bbb; overflow-y:auto; overflow-x:auto; padding:0px;"> + <div style="height:24vh; background:white; border: 1px solid #bbb; + margin-right: -4px; overflow-y:auto; overflow-x:auto; padding:0px;"> <table id="startup_libs" style="width:100%; background:white;"> </table> </div> @@ -460,7 +479,7 @@ <input type="text" id="startup_flags" name="startup_flags" - style="width:89vw"> + style="width:100%"> </label> </div> </div> @@ -1240,6 +1259,7 @@ function startup_path_delete() { function register_window_id(gfxstub, attr_arrays) { pd_object_callback = gfxstub; add_events(gfxstub); + pdgui.gui_check_for_dialog_appearance_inconsistencies(gfxstub); translate_form(); // We don't turn on rendering of the "container" div until diff --git a/pd/nw/dialog_search.html b/pd/nw/dialog_search.html index 282bb2610dae14910b0d97b1e65b0ac9139b63fc..6727ce498cfce3e7b2d64eaf6b3a77e6833bcd35 100644 --- a/pd/nw/dialog_search.html +++ b/pd/nw/dialog_search.html @@ -383,14 +383,22 @@ function find_bar_shortcut(evt) { return (evt.keyCode === 70 && evt[modifier]) // <ctrl-f> } +function window_close_shortcut(evt) { + var osx = process.platform === "darwin", + modifier = osx ? "metaKey" : "ctrlKey"; + return (evt.keyCode === 87 && evt[modifier]) // <ctrl-w> +} + function toggle_find_bar() { // this is copied from index.js m.edit.find... var find_div = document.getElementById("console_find"), find_bar_text = document.getElementById("console_find_text"), state = find_div.style.getPropertyValue("display"); if (state !== "inline") { - find_div.style.setProperty("height", "1.4em"); + find_div.style.setProperty("height", "1.2em"); find_div.style.setProperty("display", "inline"); + find_div.style.setProperty("padding-left", "3px"); + find_div.style.setProperty("padding-bottom", "9px"); window.setTimeout(function() { find_bar_text.focus(); find_bar_text.select(); @@ -419,6 +427,10 @@ function add_events() { if (find_bar_shortcut(evt)) { toggle_find_bar(); evt.stopPropagation(); + } else if (window_close_shortcut(evt)) { + evt.stopPropagation(); + pdgui.remove_dialogwin("search"); + nw.Window.get().close(true); } else { evt.stopPropagation(); return console_find_keydown(this, evt); @@ -448,10 +460,15 @@ function add_events() { evt.keyCode === 10 || evt.keyCode === 13) { } else if (evt.target !== input_elem) { input_elem.focus(); + } else if (window_close_shortcut(evt)) { + evt.stopPropagation(); + pdgui.remove_dialogwin("search"); + nw.Window.get().close(true); } else { // If we want to trigger a search on each keystroke we can do it // here. } + }); document.getElementById("search_text").addEventListener("search", function() { @@ -571,11 +588,12 @@ function doc_search() { defaultValue="Search in Console" style="width:10em;"/> </label> - <label>Highlight All + <label style="margin-left: 7px;">Highlight All <input type="checkbox" id="console_find_highlight" name="console_find_highlight" - onchange="console_find_highlight_all(this);"/> + onchange="console_find_highlight_all(this);" + style="left: -3px;"/> </label> </div> </div> diff --git a/pd/nw/dialog_text.html b/pd/nw/dialog_text.html index 500e76badbcc685fea650d7f68ecf63eafda3aee..71e5feaa70c1716e153ea48702bf984f92fd3724 100644 --- a/pd/nw/dialog_text.html +++ b/pd/nw/dialog_text.html @@ -3,12 +3,13 @@ <head> <link id="page_style" rel="stylesheet" type="text/css" href="css/default.css"> </head> - <body class="dialog_body"> + <body class="dialog_body" onload="resize_textarea();" onresize="resize_textarea();" + style="overflow: hidden;"> <div class="container"> - <textarea id="text" style="width: 100%; box-sizing: border-box; height: 85vh; resize: none;"> + <textarea id="text" style="margin: 5px 5px 4px 5px; box-sizing: border-box; resize: none;"> </textarea> </div> - <div class="submit_buttons"> + <div class="submit_buttons" style="padding: 0px;"> <button type="button" onClick="ok()" data-i18n="[title]iem.prop.ok_tt"> <span data-i18n="iem.prop.ok"></span> </button> @@ -54,6 +55,8 @@ pdgui.skin.apply(window); var pd_object_callback; var dirty = false; +gui.Window.get().setMinimumSize(260, 70); + function apply() { var text_array = document.getElementById("text").value.split("\n"); // clear out Pd's binbuf for our text object @@ -132,7 +135,7 @@ function register_window_id(gfxstub, attr) { // nwjs window, so you'll see a flicker to the title set here if it's // not "text". We need to change this so that the title can be different // from the dialog type in nw_create_window. - document.title = attr.title; + document.title = "[" + attr.title + "] Text Editor"; } // Stop-gap translator @@ -185,6 +188,14 @@ function add_events(name) { // We leave off those bindings since Enter starts a new line in the textarea //pdgui.dialog_bindings(name); } + +function resize_textarea() { + var text = document.getElementById("text"); + var textwidth = (window.innerWidth - 10 > 200 ? (window.innerWidth - 10) : 200); + var textheight = (window.innerHeight - 40 > 21 ? (window.innerHeight - 40) : 21); + text.style.setProperty("width", textwidth + "px"); + text.style.setProperty("height", textheight + "px"); +} </script> </body> </html> diff --git a/pd/nw/index.html b/pd/nw/index.html index d96e25ef000800b9d94428955fe8ec156131db85..7b8b9c7b14947f688236d817340e4828389505f3 100644 --- a/pd/nw/index.html +++ b/pd/nw/index.html @@ -36,12 +36,12 @@ defaultValue="Search in Console" style="width:10em"/> </label> - <label style="margin-left: 7px; margin-right: -3px;">Highlight All + <label style="margin-left: 7px;">Highlight All <input type="checkbox" id="console_find_highlight" name="console_find_highlight" onchange="console_find_highlight_all(this);" - style="position: relative; top: 2px; margin-right: 5px;"/> + style="position: relative; top: 2px; margin-right: 5px; left: -3px;"/> </label> </div> <script src="./console_search.js"></script> diff --git a/pd/nw/index.js b/pd/nw/index.js index b71105f1a1be88a948fc4db1f310a17269dd2ec7..30ee7736150d91b633dbe567dcf766c3f7c14e6b 100644 --- a/pd/nw/index.js +++ b/pd/nw/index.js @@ -386,16 +386,29 @@ function nw_close_window(window) { var null_pos = pdgui.check_nw_version("0.46") ? "null" : "center"; function nw_create_window(cid, type, width, height, xpos, ypos, attr_array) { - // todo: make a separate way to format the title for OSX + // todo: make a separate way to format the title for OSX var my_title; + var win_frame = true; + var win_transparent = false; if (type === "pd_canvas") { my_title = pdgui.format_window_title( attr_array.name, attr_array.dirty, attr_array.args, attr_array.dir); + + // ico@vt.edu 2020-08-13: + // why does Windows have different innerWidth and innerHeight from other OSs? + // See pdgui.js' canvas_params for the explanation... + // ico@vt.edu 2020-08-21: this should only apply to patch windows + width -= 16 * pdgui.nw_os_is_windows; + height -= 8 * pdgui.nw_os_is_windows; } else { my_title = type; + if (type !== "search" && type !== "text") { + win_frame = false; + win_transparent = true; + } } var my_file = type === "pd_canvas" ? "pd_canvas.html" : "dialog_" + type + ".html"; @@ -417,12 +430,24 @@ function nw_create_window(cid, type, width, height, xpos, ypos, attr_array) { //pdgui.post("nw_create_window w=" + width + " h=" + height); - // ico@vt.edu 2020-08-13: - // why does Windows have different innerWidth and innerHeight from other OSs? - // See pdgui.js' canvas_params for the explanation... - width -= 16 * pdgui.nw_os_is_windows; - height -= 8 * pdgui.nw_os_is_windows; - + /* + // ico@vt.edu: instantiate default options for the window behavior + // the first two vars (transparent is currently disabled) are options + // to be passed to the window at creation time, while second two are + // activated via a function call after the window has been created + var frame_val = true, + //transparent_val = true, + resize_val = true, + topmost_val = false, + menu_val = true; + + if (frame_option !== undefined) { + pdgui.post("window_options have content"); + process_window_options(window_options, + frame_val, transparent_val, + resize_val, topmost_val); + // TODO: do stuff here + }*/ gui.Window.open(my_file, { title: my_title, // ico@vt.edu: position in 0.46.2 overrides x and y below @@ -436,7 +461,9 @@ function nw_create_window(cid, type, width, height, xpos, ypos, attr_array) { // ico@vt.edu: on 0.46.2 this is now 25, go figure... height: height + (pdgui.nw_menu_offset * !pdgui.nw_os_is_osx), x: xpos, - y: ypos + y: ypos, + frame: win_frame, + transparent: win_transparent }, function (new_win) { if (type === "pd_canvas") { pdgui.set_patchwin(cid, new_win); diff --git a/pd/nw/locales/en/translation.json b/pd/nw/locales/en/translation.json index 1427ac9040be5410da688473fc989e3673a1ea08..213156285b68f039f8e56b0db848b872e7b94139 100644 --- a/pd/nw/locales/en/translation.json +++ b/pd/nw/locales/en/translation.json @@ -3,7 +3,7 @@ "prop": { "heading": { "size": "size and behavior", - "messages": "messages", + "messages": "messaging", "label": "label", "colors": "colors" }, @@ -154,8 +154,8 @@ "tofront_tt": "Bring the selected object visually in front of all other objects", "toback": "Send to Back", "toback_tt": "Send the selected object visually behind all other objects", - "font": "Font", - "font_tt": "Font settings for this patch", + "font": "Font Size", + "font_tt": "Font size settings for this patch", "cordinspector": "Cord Inspector", "cordinspector_tt": "Move the mouse over cords to inspect the data moving between objects", "find": "Find", @@ -319,9 +319,9 @@ "viewbox_offsets": "viewbox offsets", "arrays": "array options" }, - "no_scroll": "hide scrollbars (experimental)", + "no_scroll": "hide scrollbars", "no_scroll_tt": "hide window scrollbars", - "no_menu": "hide menu (experimental)", + "no_menu": "hide menu", "no_menu_tt": "hide window menu", "gop": "graph on parent", "gop_tt": "show the inner contents of this canvas in a rectangle on the containing canvas", diff --git a/pd/nw/pd_canvas.html b/pd/nw/pd_canvas.html index cfd6665b715e65ee5b85d1e226082ad3ad2f4e46..7ba063a2740a95b6116765e9385176ee7b61b4ac 100644 --- a/pd/nw/pd_canvas.html +++ b/pd/nw/pd_canvas.html @@ -102,8 +102,8 @@ </button> </div> </dialog> - <div id="hscroll" style="background-color: rgba(0, 0, 0, 0.267); position: fixed; left: 0px; bottom: 0px; border-radius: 0px; width: 10px; height: 5px; visibility: hidden;"></div> - <div id="vscroll" style="background-color: rgba(0, 0, 0, 0.267); position: fixed; right: 0px; top: 0px; border-radius: 0px; width: 5px; height: 10px; visibility: hidden;"></div> + <div id="hscroll" style="position: fixed; left: 0px; bottom: 0px; border-radius: 0px; width: 10px; height: 5px; visibility: hidden;"></div> + <div id="vscroll" style="position: fixed; right: 0px; top: 0px; border-radius: 0px; width: 5px; height: 10px; visibility: hidden;"></div> <script type="text/javascript" src="./pd_canvas.js"></script> </body> </html> diff --git a/pd/nw/pd_canvas.js b/pd/nw/pd_canvas.js index a0490f56a90498686d65059df14b562e8f305e2f..55c3c8ada412d4f70b7be14b8e0a6f4a9237978c 100644 --- a/pd/nw/pd_canvas.js +++ b/pd/nw/pd_canvas.js @@ -614,6 +614,8 @@ var canvas_events = (function() { canvas_events[canvas_events.get_previous_state()](); }, hscroll_mouseup: function(evt) { + document.getElementById("hscroll").style.setProperty("background-color", "rgba(0, 0, 0, 0.267)"); + document.getElementById("patchsvg").style.cursor = "default"; canvas_events[canvas_events.get_previous_state()](); }, hscroll_mousemove: function(evt) { @@ -643,6 +645,8 @@ var canvas_events = (function() { } }, vscroll_mouseup: function(evt) { + document.getElementById("vscroll").style.setProperty("background-color", "rgba(0, 0, 0, 0.267)"); + document.getElementById("patchsvg").style.cursor = "default"; canvas_events[canvas_events.get_previous_state()](); }, vscroll_mousemove: function(evt) { @@ -915,11 +919,15 @@ var canvas_events = (function() { }, hscroll_drag: function() { canvas_events.none(); + document.getElementById("hscroll").style.cssText += "background-color: rgba(0, 0, 0, 0.5) !important"; + document.getElementById("patchsvg").style.cursor = "-webkit-grabbing"; document.addEventListener("mouseup", events.hscroll_mouseup, false); document.addEventListener("mousemove", events.hscroll_mousemove, false); }, vscroll_drag: function() { canvas_events.none(); + document.getElementById("vscroll").style.cssText += "background-color: rgba(0, 0, 0, 0.5) !important"; + document.getElementById("patchsvg").style.cursor = "-webkit-grabbing"; document.addEventListener("mouseup", events.vscroll_mouseup, false); document.addEventListener("mousemove", events.vscroll_mousemove, false); }, @@ -1337,6 +1345,7 @@ function register_window_id(cid, attr_array) { nw.Window.get().title = kludge_title; } pdgui.free_title_queue(cid); + document.body.addEventListener("load", update_menu_items(cid), false); } function create_popup_menu(name) { @@ -1443,6 +1452,7 @@ function set_edit_menu_modals(state) { canvas_menu.edit.copy.enabled = state; canvas_menu.edit.paste.enabled = state; canvas_menu.edit.selectall.enabled = state; + canvas_menu.edit.font.enabled = state; } function set_editmode_checkbox(state) { @@ -1477,9 +1487,12 @@ function minit(menu_item, options) { } } +// used, so that we can reference menu later +var m = null; + function nw_create_patch_window_menus(gui, w, name) { // if we're on GNU/Linux or Windows, create the menus: - var m = canvas_menu = pd_menus.create_menu(gui); + m = canvas_menu = pd_menus.create_menu(gui); // File sub-entries // We explicitly enable these menu items because on OSX @@ -1641,7 +1654,79 @@ function nw_create_patch_window_menus(gui, w, name) { }); minit(m.edit.font, { enabled: true, - click: function () { pdgui.pdsend(name, "menufont"); } + /*click: function () { pdgui.pdsend(name, "menufont"); } */ + }); + minit(m.font.s8, { + enabled: true, + click: function () { + m.font.s8.checked = true; + m.font.s10.checked = false; + m.font.s12.checked = false; + m.font.s16.checked = false; + m.font.s24.checked = false; + m.font.s36.checked = false; + pdgui.gui_menu_font_change_size(name, 8); + } + }); + minit(m.font.s10, { + enabled: true, + click: function () { + m.font.s8.checked = false; + m.font.s10.checked = true; + m.font.s12.checked = false; + m.font.s16.checked = false; + m.font.s24.checked = false; + m.font.s36.checked = false; + pdgui.gui_menu_font_change_size(name, 10); + } + }); + minit(m.font.s12, { + enabled: true, + click: function () { + m.font.s8.checked = false; + m.font.s10.checked = false; + m.font.s12.checked = true; + m.font.s16.checked = false; + m.font.s24.checked = false; + m.font.s36.checked = false; + pdgui.gui_menu_font_change_size(name, 12); + } + }); + minit(m.font.s16, { + enabled: true, + click: function () { + m.font.s8.checked = false; + m.font.s10.checked = false; + m.font.s12.checked = false; + m.font.s16.checked = true; + m.font.s24.checked = false; + m.font.s36.checked = false; + pdgui.gui_menu_font_change_size(name, 16); + } + }); + minit(m.font.s24, { + enabled: true, + click: function () { + m.font.s8.checked = false; + m.font.s10.checked = false; + m.font.s12.checked = false; + m.font.s16.checked = false; + m.font.s24.checked = false; + m.font.s36.checked = false; + pdgui.gui_menu_font_change_size(name, 24); + } + }); + minit(m.font.s36, { + enabled: true, + click: function () { + m.font.s8.checked = false; + m.font.s10.checked = false; + m.font.s12.checked = false; + m.font.s16.checked = false; + m.font.s24.checked = false; + m.font.s36.checked = true; + pdgui.gui_menu_font_change_size(name, 36); + } }); minit(m.edit.cordinspector, { enabled: true, @@ -1984,3 +2069,42 @@ function nw_create_patch_window_menus(gui, w, name) { } }); } + +function init_menu_font_size(size) { + //pdgui.post("init_menu_font_size " + size); + m.font.s8.checked = false; + m.font.s10.checked = false; + m.font.s12.checked = false; + m.font.s16.checked = false; + m.font.s24.checked = false; + m.font.s36.checked = false; + + switch(size) + { + case 8: + m.font.s8.checked = true; + break; + case 10: + m.font.s10.checked = true; + break; + case 12: + m.font.s12.checked = true; + break; + case 16: + m.font.s16.checked = true; + break; + case 24: + m.font.s24.checked = true; + break; + case 36: + m.font.s36.checked = true; + break; + } +} + +// ico@vt.edu 2020-08-24: this is called when the window is finally +// loaded and then asks libpd to tell us what is the font state +// LATER: we can use this to also update the undo state appropriately +function update_menu_items(cid) { + pdgui.pdsend(cid, "updatemenu"); +} \ No newline at end of file diff --git a/pd/nw/pd_menus.js b/pd/nw/pd_menus.js index 79e031410c527e0e21d64c1247574ad8dc01f15a..a9dd9e69d189c98ec4f18a408af1a1c9f66b4489 100644 --- a/pd/nw/pd_menus.js +++ b/pd/nw/pd_menus.js @@ -25,7 +25,8 @@ function create_menu(gui, type) { put_menu, winman_menu, media_menu, - help_menu; + help_menu, + font_submenu; // We only maintain a single instance of the recent files submenu which // gets updated in pdgui.js via a callback from the engine. @@ -37,6 +38,41 @@ function create_menu(gui, type) { pdgui.populate_recent_files(recent_files_submenu); } + // File sub-entries + m.font = {}; + font_submenu = new gui.Menu(); + + font_submenu.append(m.font.s8 = new gui.MenuItem({ + label: 8, + tooltip: 8, + type: "checkbox" + })); + font_submenu.append(m.font.s10 = new gui.MenuItem({ + label: 10, + tooltip: 10, + type: "checkbox" + })); + font_submenu.append(m.font.s12 = new gui.MenuItem({ + label: 12, + tooltip: 12, + type: "checkbox" + })); + font_submenu.append(m.font.s16 = new gui.MenuItem({ + label: 16, + tooltip: 16, + type: "checkbox" + })); + font_submenu.append(m.font.s24 = new gui.MenuItem({ + label: 24, + tooltip: 24, + type: "checkbox" + })); + font_submenu.append(m.font.s36 = new gui.MenuItem({ + label: 36, + tooltip: 36, + type: "checkbox" + })); + // OSX just spawns a single canvas menu and then enables/disables // the various menu items as needed. canvas_menu = osx || (type !== "console"); @@ -290,10 +326,14 @@ function create_menu(gui, type) { modifiers: shortcuts.menu.tidyup.modifiers, tooltip: l("menu.tidyup_tt") })); + edit_menu.append(m.edit.font = new gui.MenuItem({ label: l("menu.font"), - tooltip: l("menu.font_tt") + tooltip: l("menu.font_tt"), + submenu: font_submenu })); + + edit_menu.append(m.edit.cordinspector = new gui.MenuItem({ type: "checkbox", label: l("menu.cordinspector"), diff --git a/pd/nw/pdgui.js b/pd/nw/pdgui.js index 6f4f9f38f5939da9898b618598172bccb98ef7be..e62f16b4b7289bf155945b1cda8e8c471ba3015d 100644 --- a/pd/nw/pdgui.js +++ b/pd/nw/pdgui.js @@ -1628,6 +1628,8 @@ function gui_canvas_cursor(cid, pd_event_type) { function canvas_sendkey(cid, state, evt, char_code, repeat) { var shift = evt.shiftKey ? 1 : 0, repeat_number = repeat ? 1 : 0; + //post("canvas_sendkey state=" + state + " evt=" + evt + + // " char_code=<" + char_code + "> repeat=" + repeat); pdsend(cid, "key", state, char_code, shift, 1, repeat_number); } @@ -1732,6 +1734,8 @@ function gui_canvas_new(cid, width, height, geometry, zoom, editmode, name, dir, last_loaded = cid; // Not sure why resize and topmost are here-- but we'll pass them on for // the time being... + // ico@vt.edu 2020-08-24: this is because in 1.x we can change these window + // properties via scripting. We should add this to 2.x soon... create_window(cid, "pd_canvas", width, height, xpos, ypos, { menu_flag: menu_flag, @@ -2466,7 +2470,9 @@ function gui_atom_redraw_border(cid, tag, type, width, height) { } // draw a patch cord -function gui_canvas_line(cid,tag,type,p1,p2,p3,p4,p5,p6,p7,p8,p9,p10) { +// ico@vt.edu: p11 added to provide different color for when the cord is +// being created vs when it is being finished +function gui_canvas_line(cid,tag,type,p1,p2,p3,p4,p5,p6,p7,p8,p9,p10,p11) { gui(cid).get_elem("patchsvg") .append(function(frag) { var svg = get_item(cid, "patchsvg"), @@ -2484,8 +2490,8 @@ function gui_canvas_line(cid,tag,type,p1,p2,p3,p4,p5,p6,p7,p8,p9,p10) { d: d_array.join(" "), fill: "none", //"shape-rendering": "optimizeSpeed", - id: tag, - "class": "cord " + type + id: tag, + "class": "cord " + type + (p11 == 1 ? " new" : "") }); frag.appendChild(path); return frag; @@ -3010,6 +3016,8 @@ function gui_numbox_draw_text(cid,tag,text,font_size,color,xpos,ypos,basex,basey // below. But it works for most font sizes. gui(cid).get_gobj(tag) .append(function(frag, w) { + //post("ypos=" + ypos + " int=" + Math.floor(ypos)); + //ypos = Math.floor(ypos); var svg_text = create_item(cid, "text", { transform: "translate(" + (xpos - basex) + "," + @@ -3679,7 +3687,7 @@ function gui_scalar_new(cid, tag, isselected, t1, t2, t3, t4, t5, t6, //matrix = [t1,t2,t3,t4+1,t5+0.5,t6+0.5]; matrix = 0; transform_string = "translate(" + (t5+(t1 < 1 ? 0.5 : 1.5)) + - "," + (t6+1) + ") scale(" + t1 + "," + t4 + ")"; + "," + (t6+1.5) + ") scale(" + t1 + "," + t4 + ")"; //post("transform_string = " + transform_string); break; default: @@ -4083,9 +4091,11 @@ function img_size_setter(cid, svg_image_tag, type, data, tk_anchor) { img.onload = function() { w = this.width, h = this.height; + // ico@vt.edu here we subtract one from the svg interpretation + // of the anchor to keep it 1.x and K12 mode compatible configure_item(get_item(cid, svg_image_tag), { - width: w, - height: h, + width: w + 1, + height: h + 1, x: tk_anchor === "center" ? 0 - w/2 : 0, y: tk_anchor === "center" ? 0 - h/2 : 0 }); @@ -4233,31 +4243,38 @@ function gui_image_size_callback(cid, key, callback) { ";base64," + pd_cache.get(key).data; } -function gui_image_draw_border(cid, tag, x, y, w, h) { - gui(cid).get_gobj(tag) - .append(function(frag) { - var b = create_item(cid, "path", { - "stroke-width": "1", - fill: "none", - d: ["m", x, y, w, 0, - "m", 0, 0, 0, h, - "m", 0, 0, -w, 0, - "m", 0, 0, 0, -h - ].join(" "), - visibility: "hidden", - class: "border" +function gui_image_toggle_border(cid, tag, x, y, w, h, onoff) { + if (onoff == 0) { + gui(cid).get_gobj(tag) + .q("path", function(border) { + border.parentNode.removeChild(border); }); - frag.appendChild(b); - return frag; - }); + } else { + gui(cid).get_gobj(tag) + .append(function(frag) { + var b = create_item(cid, "path", { + "stroke-width": "1", + fill: "none", + d: ["m", x, y, w, 0, + "m", 0, 0, 0, h, + "m", 0, 0, -w, 0, + "m", 0, 0, 0, -h + ].join(" "), + visibility: "visible", + class: "border" + }); + frag.appendChild(b); + return frag; + }); + } } -function gui_image_toggle_border(cid, tag, state) { +/*function gui_image_toggle_border(cid, tag, state) { gui(cid).get_gobj(tag) .q(".border", { visibility: state === 0 ? "hidden" : "visible" }); -} +}*/ // Switch the data for an existing svg image function gui_image_configure(cid, tag, image_key, tk_anchor) { @@ -5410,7 +5427,7 @@ function attr_array_to_object(attr_array) { } function gui_gatom_dialog(did, attr_array) { - dialogwin[did] = create_window(did, "gatom", 265, 300, + dialogwin[did] = create_window(did, "gatom", 259, 278-5, popup_coords[2], popup_coords[3], attr_array_to_object(attr_array)); } @@ -5426,10 +5443,14 @@ function gui_gatom_activate(cid, tag, state) { } function gui_dropdown_dialog(did, attr_array) { - // Just reuse the "gatom" dialog - dialogwin[did] = create_window(did, "gatom", 265, 300, + // Just reuse the "gatom" dialog (this is not true anymore, see below) + // ico@vt.edu 2020-08-21: made this into a separate dialog due to inability to easily retitle + // the window + dialogwin[did] = create_window(did, "dropdown", 222, 268-5, popup_coords[2], popup_coords[3], attr_array_to_object(attr_array)); + // ico@vt.edu 2020-08-21: the following does not work because the window is not created yet? + //dialogwin[did].window.document.getElementById("titlebar_title").innerHTML = "dropdown properties"; } function dropdown_populate(w, label_array, current_index) { @@ -5522,8 +5543,12 @@ function gui_iemgui_dialog(did, attr_array) { //for (var i = 0; i < attr_array.length; i++) { // attr_array[i] = '"' + attr_array[i] + '"'; //} - create_window(did, "iemgui", 265, 450, - popup_coords[2], popup_coords[3], + // ico@vt.edu: updated window size to match actual, thereby minimizing the flicker + // We are subtracting 25 for the menu + // ico@vt.edu: since adding frameless window, we use top 20px for draggable titlebar, + // so now we subtract only 5 (25-20) + create_window(did, "iemgui", 298, 414-5, + popup_coords[2] + 10, popup_coords[3] + 60, attr_array_to_object(attr_array)); } @@ -5544,6 +5569,28 @@ function gui_font_dialog_change_size(did, font_size) { } } +function gui_menu_font_change_size(canvas, newsize) { + pdsend(canvas, "menufont", newsize); + // ico@vt.edu 2020-08-24: changed to use submenu + // this was the following + /*+document.querySelector('input[name="font_size"]:checked').value, + current_size, + 100, + 0 // "$noundo" from pd.tk-- not sure what it does*/ +} + +exports.gui_menu_font_change_size = gui_menu_font_change_size; + +function gui_menu_font_set_initial_size(cid, size) { + //post("gui_menu_font_set_initial_size " + cid + " " + size); + gui(cid).get_nw_window(function(nw_win) { + if (cid !== "nobody") { + nw_win.window.init_menu_font_size(size); + //post("this should work"); + } + }); +} + function gui_array_new(did, count) { var attr_array = [{ array_gfxstub: did, @@ -5554,11 +5601,13 @@ function gui_array_new(did, count) { array_outline: "black", array_in_existing_graph: 0 }]; - dialogwin[did] = create_window(did, "canvas", 265, 340, 20, 20, + dialogwin[did] = create_window(did, "canvas", + 240 + (5 * nw_os_is_linux) - (30 * nw_os_is_osx), 268-25, 20, 20, attr_array); } function gui_canvas_dialog(did, attr_arrays) { + //post("gui_canvas_dialog"); var i, j, inner_array, prop; // Convert array of arrays to an array of objects for (i = 0; i < attr_arrays.length; i++) { @@ -5569,13 +5618,26 @@ function gui_canvas_dialog(did, attr_arrays) { } } } - dialogwin[did] = create_window(did, "canvas", 300, 100, + var has_array = (attr_arrays.length > 1 ? 1 : 0); + /* + post("array.length=" + attr_arrays.length + " has_array=" + has_array +" width=" + + (230 - (8 * has_array)) + " height=" + + (attr_arrays.length > 1 ? 494-25+(attr_arrays.length > 2 ? 38 : 0) : 392-25)); + */ + dialogwin[did] = create_window(did, "canvas", + // ico@vt.edu: property dialog size is larger when one has + // arrays inside the canvas. + // 1 for regular canvas and 2 for a canvas with 1 array, + // 3 for canvas with 2 arrays, etc. + // We also substract here 5 for the smaller top bar... + 238 + (8 * has_array), + (attr_arrays.length > 1 ? 535-25 : 392-25), popup_coords[2], popup_coords[3], attr_arrays); } function gui_data_dialog(did, data_string) { - dialogwin[did] = create_window(did, "data", 250, 300, + dialogwin[did] = create_window(did, "data", 195, 323 + (22 * nw_os_is_osx), popup_coords[2], popup_coords[3], data_string); } @@ -5631,14 +5693,16 @@ function gui_remove_gfxstub(did) { } } -function gui_font_dialog(cid, gfxstub, font_size) { - var attrs = { canvas: cid, font_size: font_size }; - dialogwin[gfxstub] = create_window(gfxstub, "font", 265, 200, 0, 0, - attrs); +function gui_font_dialog(cid, font_size) { + //var attrs = { canvas: cid, font_size: font_size }; + //dialogwin[gfxstub] = create_window(gfxstub, "font", 136, 187, 0, 0, + // attrs); + // ico@vt.edu: 2020-08-24: we don't need this anymore since everything + // is now inside the menu } function gui_external_dialog(did, external_name, attr_array) { - create_window(did, "external", 265, 450, + create_window(did, "external", 202, 323 + (22 * nw_os_is_osx), popup_coords[2], popup_coords[3], { name: external_name, @@ -5656,7 +5720,7 @@ function gui_pd_dsp(state) { function open_prefs() { if (!dialogwin["prefs"]) { - create_window("prefs", "prefs", 370, 470, 0, 0, null); + create_window("prefs", "prefs", 486, 532, 0, 0, null); } else { dialog_raise("prefs"); } @@ -5672,7 +5736,7 @@ function open_search() { } } -exports.open_search= open_search; +exports.open_search = open_search; // This is the same for all windows (initialization is in pd_menus.js). var recent_files_submenu = null; @@ -5881,8 +5945,12 @@ exports.get_style_by_selector = get_style_by_selector; // the user clicks a box in edit mode. One set of points for // the "head", or main box, and the other for the "tail", or // message flag at the right. -function generate_msg_box_bg_data(type, stroke) { - return 'url(\"data:image/svg+xml;utf8,' + +// ico@vt.edu 2020-08-31: if you thought the original hack was +// ugly, wait until you see this new version. Hold onto your +// binary barf bags... +function generate_msg_box_bg_data(type, stroke, height) { + //post("height="+height); + var header = 'url(\"data:image/svg+xml;utf8,' + '<svg ' + "xmlns:svg='http://www.w3.org/2000/svg' " + "xmlns='http://www.w3.org/2000/svg' " + @@ -5890,20 +5958,43 @@ function generate_msg_box_bg_data(type, stroke) { "version='1.0' " + "viewBox='0 0 10 10' " + "preserveAspectRatio='none'" + - ">" + - "<polyline vector-effect='non-scaling-stroke' " + + ">"; + + var line_header = "<polyline vector-effect='non-scaling-stroke' " + "id='bubbles' " + "fill='none' " + "stroke=' " + stroke + // Here's our stroke color - "' " + - "stroke-width='1' " + - (type === "head" ? - "points='10 0 0 0 0 10 10 10' " : // box - "points='0 0 10 0 0 2 0 8 10 10 0 10' ") + // flag - "/>" + - "</svg>" + + "' "; + + var line_ender = "</svg>" + '")'; + + if (type === "head") + { + return header + line_header + "stroke-width='2' points='10 0 0 0 0 10 10 10' />" + line_ender; + } + else { + // testing scaling of the flags with the increasing number of lines, top_flag, then bottom_flag + // 1 line: 2.5 7.5 + // 2 lines: 1.5 8.5 + // 3 lines: 1 9 + // 4 lines: 0.75 9.25 + var top_flag = 2.5; + var decrement = 1; + while(height > 1) + { + top_flag -= decrement; + decrement /= 2; + height--; + } + var bottom_flag = 10 - top_flag; + return header + + line_header + "stroke-width='2' points='0 0 10 0' />" + + line_header + "stroke-width='2' points='0 10 10 10' />" + + line_header + "stroke-width='1' points='10 0 1 " + top_flag + " 1 " + bottom_flag + " 10 10' />" + + line_ender; + } } // Big problem here-- CSS fails miserably at something as simple as the @@ -5918,12 +6009,47 @@ function generate_msg_box_bg_data(type, stroke) { // more and more apparent. // Anyhow, this enormous workaround makes it possible to just specify the // edit box color in CSS for the presets. -function shove_svg_background_data_into_css(w) { +function shove_svg_background_data_into_css(w, height) { var head_style = get_style_by_selector(w, "#new_object_textentry.msg"), tail_style = get_style_by_selector(w, "p.msg::after"), stroke = head_style.outlineColor; - head_style.backgroundImage = generate_msg_box_bg_data("head", stroke); - tail_style.backgroundImage = generate_msg_box_bg_data("tail", stroke); + head_style.backgroundImage = generate_msg_box_bg_data("head", stroke, height); + tail_style.backgroundImage = generate_msg_box_bg_data("tail", stroke, height); +} + +function textarea_line_height_kludge(font_size) { + switch(font_size) { + case 8: return "133%"; + case 10: return "133%"; + case 12: return "140%"; + case 16: return "120%"; + case 24: return "128%"; + case 36: return "122%"; + } +} + +function textarea_y_offset_kludge(font_size) { + switch(font_size) { + case 8: return 1.5; + case 10: return 0.5; + case 12: return 1.5; + case 16: return 1.5; + case 24: return 1.5; + case 36: return 1.5; + } +} + +function textarea_msg_kludge(zoom) { + switch(zoom) { + case 0: return -1; + case 1: return -0.5; + case 2: return -0.5; + case 3: return -0.5; + case 4: return -0.5; + case 5: return -0.5; + case 6: return -0.5; + case 7: return -0.5; + } } function gui_textarea(cid, tag, type, x, y, width_spec, height_spec, text, @@ -5954,8 +6080,6 @@ function gui_textarea(cid, tag, type, x, y, width_spec, height_spec, text, svg_view = patchwin[cid].window.document.getElementById("patchsvg") .viewBox.baseVal; p.classList.add(type); - // ico@vt.edu: is there a better way to monitor vars inside nw? - // p.classList.add("zoom=" + zoom); p.contentEditable = "true"; if (is_gop == 0) { @@ -5976,27 +6100,39 @@ function gui_textarea(cid, tag, type, x, y, width_spec, height_spec, text, */ } - p.style.setProperty("left", (x - svg_view.x) + "px"); - p.style.setProperty("top", (y - svg_view.y) + "px"); + p.style.setProperty("left", (x - svg_view.x - 0.5) + "px"); + p.style.setProperty("top", (y - svg_view.y + textarea_y_offset_kludge(font_size)) + "px"); p.style.setProperty("font-size", pd_fontsize_to_gui_fontsize(font_size) + "px"); p.style.setProperty("line-height", - pd_fontsize_to_gui_fontsize(font_size) + 1 + "px"); + textarea_line_height_kludge(font_size)); + //pd_fontsize_to_gui_fontsize(font_size) + 1 + "px"); p.style.setProperty("transform", "translate(0px, " + (zoom > 0 ? 0.5 : 0) + "px)"); p.style.setProperty("max-width", width_spec > 0 ? width_spec + "ch" : "60ch"); + //p.style.setProperty("width", -width_spec - 2 + "px"); + p.style.setProperty("-webkit-padding-after", "1px"); p.style.setProperty("min-width", width_spec == 0 ? "3ch" : - (is_gop == 1 ? width_spec + "px" : - (width_spec < 0 ? (-width_spec) + "px" : width_spec + "ch"))); + (is_gop == 1 ? width_spec - 3 + "px" : + (width_spec < 0 ? (-width_spec) - 2 + "px" : width_spec + "ch"))); if (is_gop == 1) { - p.style.setProperty("min-height", height_spec + "px"); + p.style.setProperty("min-height", height_spec - 4 + "px"); } // set backgroundimage for message box if (type === "msg") { - shove_svg_background_data_into_css(patchwin[cid].window); + // ico@vt.edu: 2020-08-31: message boxes are uniquely borked + // so, we do our best to address that here + p.style.setProperty("-webkit-padding-before", "2px"); + p.style.setProperty("-webkit-padding-after", "3px"); + p.style.setProperty("transform", "translate(0px, " + + textarea_msg_kludge(zoom) + "px)"); + //post("line-height="+ parseInt(p.style.lineHeight) / 100 * font_size); + shove_svg_background_data_into_css(patchwin[cid].window, + parseInt(get_gobj(cid, tag).getBoundingClientRect().height / + (parseInt(p.style.lineHeight) / 100 * font_size))); } // remove leading/trailing whitespace text = text.trim(); @@ -6005,6 +6141,13 @@ function gui_textarea(cid, tag, type, x, y, width_spec, height_spec, text, patchwin[cid].window.document.body.appendChild(p); p.focus(); select_text(cid, p, sel_start, sel_end); + if (font_size === 36) { + if (is_gop) { + p.style.setProperty("padding", "2px 0px 2px 2.5px"); + } else { + p.style.setProperty("padding", "2px 0px 2px 1.5px"); + } + } if (state === 1) { patchwin[cid].window.canvas_events.text(); } else { @@ -6480,8 +6623,20 @@ exports.dialog_bindings = function(did) { exports.resize_window = function(did) { var w = dialogwin[did].window.document.body.scrollWidth, h = dialogwin[did].window.document.body.scrollHeight; - dialogwin[did].width = w; - dialogwin[did].height = h; + // ico@vt.edu: the following is a change needed for the nw.js 0.47 + // for the dialog window to be properly resized + //dialogwin[did].width = w; + //dialogwin[did].height = h; + //dialogwin[did].window.document.body.titlebar_close_button.style.setProperty + // ("font-size", (process.platform === "win32" ? "21px" : "15px")); + /*post(did + " body: w=" + dialogwin[did].window.document.body.clientWidth + + " h=" + dialogwin[did].window.document.body.clientHeight + " scroll: w=" + + w + " h=" + h);*/ + dialogwin[did].resizeTo(w,h); + //ico@vt.edu: comment the following line when working on dialog sizes... + dialogwin[did].setResizable(false); + //post("dialog set always on top"); + //dialogwin[did].setAlwaysOnTop(true); } // External GUI classes @@ -6572,3 +6727,21 @@ function gui_update_scrollbars(cid) { } exports.gui_update_scrollbars = gui_update_scrollbars; + +// ico@vt.edu 2020-08-29: fine-tune appearance of various +// css elements because, consistency in HTML font rendering +// across different OSs is a joke +function gui_check_for_dialog_appearance_inconsistencies(id) +{ + if (nw_os_is_osx) + gui_osx_dialog_appearance(id); +} + +exports.gui_check_for_dialog_appearance_inconsistencies = gui_check_for_dialog_appearance_inconsistencies; + +function gui_osx_dialog_appearance(id) +{ + var close_button = dialogwin[id].window.document.getElementById("titlebar_close_button"); + close_button.style.setProperty("line-height", "14px"); + close_button.style.setProperty("border-radius", "10px"); +} \ No newline at end of file diff --git a/pd/src/g_canvas.c b/pd/src/g_canvas.c index e29d802d7a92cac7aa11515eabde57056edd7efd..279a69ae86570616cb12366adfedc8edce742c9f 100644 --- a/pd/src/g_canvas.c +++ b/pd/src/g_canvas.c @@ -618,6 +618,8 @@ void glist_glist(t_glist *g, t_symbol *s, int argc, t_atom *argv) { if (canvas_hasarray(g)) return; pd_vmess(&g->gl_pd, gensym("editmode"), "i", 1); + // disallow creation of new objects in scalars only window + if (canvas_has_scalars_only(g) == 2) return; t_symbol *sym = atom_getsymbolarg(0, argc, argv); /* if we wish to put a graph where the mouse is we need to replace bogus name */ if (!strcmp(sym->s_name, "NULL")) sym = &s_; @@ -728,14 +730,15 @@ void canvas_args_to_string(char *namebuf, t_canvas *x) { namebuf[0] = 0; t_gobj *g = NULL; + t_garray *a = NULL; t_symbol *arrayname; - int found = 0; + int found = 0, res; for (g = x->gl_list; g; g = g->g_next) { if (pd_class(&g->g_pd) == garray_class) { - garray_getname((t_garray *)g, &arrayname); + res = garray_getname((t_garray *)g, &arrayname); if (found) { strcat(namebuf, " "); @@ -2445,7 +2448,16 @@ void canvasgop__motionhook(t_scalehandle *sh, t_floatarg mouse_x, t_glist *owner = glist_getcanvas(x); /* Just unvis the object, then vis it once we've done our mutation and checks */ - gobj_vis((t_gobj *)x, owner, 0); + /* ico@vt.edu 2020-08-26: this was owner instead of x->gl_owner However, + there is a special case where this causes consistency check error + in canvas_vis because a gop patch size is being manipulated on the + parent window and its window is also visible, glist_getcanvas() will + return its own window even though the user is manipulating the size + on the parent window. So, here we ensure that we are always getting + the parent window, and then we update the red rectangle on its own + window below (see if (x->gl_havewindow)). The same is true for vising + towards the bottom of this function. */ + gobj_vis((t_gobj *)x, x->gl_owner, 0); /* struct _glist has its own member e_xnew for storing our offset. At some point we need to refactor since our t_scalehandle has members for storing offsets already. */ @@ -2481,9 +2493,22 @@ void canvasgop__motionhook(t_scalehandle *sh, t_floatarg mouse_x, owner->gl_editor->e_xnew = mouse_x; owner->gl_editor->e_ynew = mouse_y; canvas_fixlinesfor(owner, (t_text *)x); - gobj_vis((t_gobj *)x, owner, 1); + gobj_vis((t_gobj *)x, x->gl_owner, 1); canvas_dirty(owner, 1); + /* ico@vt.edu 2020-08-26: if we are changing the gop size + on the parent window with our own window open, updated the + red rectangle on our own window */ + if (x->gl_havewindow) + { + gui_vmess("gui_canvas_redrect_coords", "xiiii", + x, + x->gl_xmargin, + x->gl_ymargin, + x->gl_xmargin + x->gl_pixwidth, + x->gl_ymargin + x->gl_pixheight); + } + int properties = gfxstub_haveproperties((void *)x); if (properties) { @@ -2517,6 +2542,14 @@ void canvasgop__motionhook(t_scalehandle *sh, t_floatarg mouse_x, properties_set_field_int(properties, "y_pix",x->gl_pixheight + sh->h_dragy); } + /* ico@vt.edu: resize parent window gop rectangle if visible + as an added bonus, this also works even if it is only + visible inside another gop (gop within a gop within a gop) */ + if (x->gl_owner && glist_isvisible(x->gl_owner)) + { + gobj_vis(&x->gl_gobj, x->gl_owner, 0); + gobj_vis(&x->gl_gobj, x->gl_owner, 1); + } } else /* move_gop hook */ { diff --git a/pd/src/g_canvas.h b/pd/src/g_canvas.h index 964d8fab820992ae09b20e49af661c5d8f472645..af31d80f1e000ba10e4837b2f43792dd27b54c37 100644 --- a/pd/src/g_canvas.h +++ b/pd/src/g_canvas.h @@ -572,6 +572,8 @@ EXTERN t_gobj *canvas_findhitbox(t_canvas *x, int xpos, int ypos, int *x1p, int *y1p, int *x2p, int *y2p); EXTERN int canvas_setdeleting(t_canvas *x, int flag); EXTERN int canvas_hasarray(t_canvas *x); +EXTERN int canvas_has_scalars_only(t_canvas *x); + #define LB_LOAD 0 /* "loadbang" actions - 0 for original meaning */ #define LB_INIT 1 /* loaded but not yet connected to parent patch */ diff --git a/pd/src/g_editor.c b/pd/src/g_editor.c index ecec351057873f5664ce0de70d38f7569c7e406e..5e30db534613c65e74e9f73fd82fb8c96fb41fe1 100644 --- a/pd/src/g_editor.c +++ b/pd/src/g_editor.c @@ -2674,6 +2674,14 @@ void canvas_map(t_canvas *x, t_floatarg f); //extern t_rtext *glist_findrtext(t_glist *gl, t_text *who); //extern void rtext_gettext(t_rtext *x, char **buf, int *bufsize); +// ico@vt.edu 2020-08-24: update initial menu settings +void canvas_init_menu(t_canvas *x) +{ + //post("g_editor.c canvas_init_menu %d", x->gl_font); + // ico@vt.edu 2020-08-24: we now need this to init the menu font size + gui_vmess("gui_menu_font_set_initial_size", "xi", x, x->gl_font); +} + void canvas_vis(t_canvas *x, t_floatarg f) { //fprintf(stderr,"canvas_vis .x%lx %f\n", (t_int)x, f); @@ -2757,6 +2765,7 @@ void canvas_vis(t_canvas *x, t_floatarg f) /* It looks like this font size call is no longer needed, but I'm not sure why it was needed in the first place... */ //sys_vgui("pdtk_canvas_set_font .x%lx %d\n", x, x->gl_font); + //canvas_reflecttitle(x); x->gl_havewindow = 1; @@ -3457,7 +3466,7 @@ static int text_resizing_hotspot(t_canvas *x, t_object *ob, int xpos, int ypos, /* gop canvases, gop red rectangle, scope, grid, iemguis except [cnv] */ if ((ob->te_iemgui && ob->ob_pd != my_canvas_class) || - ob->ob_pd == canvas_class || + (ob->ob_pd == canvas_class && ((t_canvas *)ob)->gl_isgraph) || ob->ob_pd->c_name == gensym("Scope~") || ob->ob_pd->c_name == gensym("grid")) { @@ -3805,7 +3814,7 @@ void canvas_doclick(t_canvas *x, int xpos, int ypos, int which, x->gl_editor->e_xwas = hotspot + IOWIDTH / 2; x->gl_editor->e_ywas = y2 - 2; /* This repetition of args needs to be pruned below */ - gui_vmess("gui_canvas_line", "xssiiiiiiiiii", + gui_vmess("gui_canvas_line", "xssiiiiiiiiiii", x, "newcord", (issignal ? "signal" : "control"), @@ -4309,7 +4318,7 @@ void canvas_drawconnection(t_canvas *x, int lx1, int ly1, int lx2, int ly2, } if (yoff > ymax) yoff = ymax; sprintf(tagbuf, "l%lx", (long unsigned int)tag); - gui_vmess("gui_canvas_line", "xssiiiiiiiiii", + gui_vmess("gui_canvas_line", "xssiiiiiiiiiii", x, tagbuf, (issignal ? "signal" : "control"), @@ -4322,7 +4331,8 @@ void canvas_drawconnection(t_canvas *x, int lx1, int ly1, int lx2, int ly2, lx2, ly2 - yoff, lx2, - ly2); + ly2, + 0); } void canvas_updateconnection(t_canvas *x, int lx1, int ly1, int lx2, int ly2, @@ -6005,15 +6015,22 @@ void canvas_menuclose(t_canvas *x, t_floatarg fforce) } /* put up a dialog which may call canvas_font back to do the work */ -static void canvas_menufont(t_canvas *x) +static void canvas_menufont(t_canvas *x, t_floatarg newsize) { t_canvas *x2 = canvas_getrootfor(x); - gfxstub_deleteforkey(x2); - char *gfxstub = gfxstub_new2(&x2->gl_pd, &x2->gl_pd); - gui_vmess("gui_font_dialog", "xsi", - x2, - gfxstub, - x2->gl_font); + //gfxstub_deleteforkey(x2); + //char *gfxstub = gfxstub_new2(&x2->gl_pd, &x2->gl_pd); + if (newsize != x2->gl_font) + { + // additional args copied from dialog_font.html + canvas_font(x2, newsize, x2->gl_font, 100.0, 0.0); + } + /*{ + gui_vmess("gui_font_dialog", "xi", + x2, + //gfxstub, + x2->gl_font); + }*/ } static int canvas_find_index1, canvas_find_index2, canvas_find_wholeword; @@ -7948,7 +7965,10 @@ void canvas_editmode(t_canvas *x, t_floatarg fyesplease) //fprintf(stderr,"canvas_editmode %f\n", fyesplease); /* first check if this is a canvas hosting an array and if so - refuse to add any further objects */ + refuse to add any further objects. we allow edit mode on the + subpatches that have only scalars, as that allows for their + repositioning/deletion/etc. + */ if (canvas_hasarray(x)) return; int yesplease = fyesplease; @@ -8067,11 +8087,11 @@ static void canvas_dofont(t_canvas *x, t_floatarg font, t_floatarg xresize, { t_gobj *y; x->gl_font = font; - if (x->gl_isgraph && !canvas_isabstraction(x) && + /*if (x->gl_isgraph && !canvas_isabstraction(x) && (xresize != 1 || yresize != 1) && !glist_istoplevel(x)) { vmess(&x->gl_pd, gensym("menu-open"), ""); - } + }*/ if (xresize != 1 || yresize != 1) { for (y = x->gl_list; y; y = y->g_next) @@ -8335,7 +8355,9 @@ void g_editor_setup(void) class_addmethod(canvas_class, (t_method)canvas_print, gensym("print"), A_SYMBOL, A_NULL); class_addmethod(canvas_class, (t_method)canvas_menufont, - gensym("menufont"), A_NULL); + gensym("menufont"), A_FLOAT, A_NULL); + class_addmethod(canvas_class, (t_method)canvas_init_menu, + gensym("updatemenu"), A_NULL); class_addmethod(canvas_class, (t_method)canvas_font, gensym("font"), A_FLOAT, A_FLOAT, A_FLOAT, A_FLOAT, A_NULL); class_addmethod(canvas_class, (t_method)canvas_zoom, diff --git a/pd/src/g_graph.c b/pd/src/g_graph.c index 7f806a721942d12811177f6bdba77f15b2e558a6..7c1bf59e92c7257e98b22dc206fea99e14be3237 100644 --- a/pd/src/g_graph.c +++ b/pd/src/g_graph.c @@ -60,6 +60,79 @@ int canvas_isgroup(t_canvas *x) extern t_template *canvas_findtemplate(t_canvas *c); extern t_canvas *canvas_templatecanvas_forgroup(t_canvas *c); + +/* ico@vt.edu 2020-08-24: +check if canvas consists of only scalars and returns 2. if the canvas only +has the last object as a non-scalar (e.g. a new object has just been created, +then we return 1, otherwise return 0. this is used to prevent creation of new +objects in an GOP window that only has scalars inside it or scalars with one +newly created object that is yet to be typed into and therefore properly +instantiated */ +int canvas_has_scalars_only(t_canvas *x) +{ + t_gobj *g = x->gl_list; + int hasonlyscalars = 2; + while (g) + { + //post("g..."); + if (pd_class(&g->g_pd) != scalar_class) + { + /* + post("...scalar=NO %s %s", + (pd_class(&g->g_pd) == text_class ? "text_class" : "NOT_text_class"), + (((t_text *)g)->te_type == T_TEXT) ? "T_TEXT" : "NOT_T_TEXT"); + */ + + /* ico@vt.edu 2020-08-24: + if we have one more object or the last object is not newly + instantiated text object + to distinguish between a comment and a text object that is + yet to be instantiated we use: + 1) comment is text_class and its te_type is T_TEXT + 2) blank object one is typing into is text_class but is NOT T_TEXT + 3) instantiated object is something other than text_class (unless) + it is a comment + 4) object that has failed to create is same as blank object + */ + if (g->g_next || (pd_class(&g->g_pd) != text_class || ((t_text *)g)->te_type == T_TEXT)) + hasonlyscalars = 0; + else + hasonlyscalars = 1; + break; + } + //post("...scalar, comment, or uninitialized object=yes"); + g = g->g_next; + } + //post("has scalars only=%d", hasonlyscalars); + return(hasonlyscalars); +} + +/* ico@vt.edu 2020-08-24: this draws or erases redrect on a gop window + and is being refactored due to complex logic involving subpatches with + scalars only that should not have a redrect until a non-scalar object + has been instantiated (this does not include empty objects that are + yet to be typed into, as this is one way how one can instantiate new + scalar inside a subpatch) +*/ +void glist_update_redrect(t_glist *x) +{ + t_gobj *y = x->gl_list; + while(y->g_next) y = y->g_next; + + if (x->gl_editor && x->gl_isgraph && !x->gl_goprect + && pd_checkobject(&y->g_pd) && !canvas_has_scalars_only(x)) + { + //post("glist_add drawredrect %d", canvas_has_scalars_only(x)); + x->gl_goprect = 1; + canvas_drawredrect(x, 1); + } + else if (canvas_has_scalars_only(x) && x->gl_goprect) + { + x->gl_goprect = 0; + canvas_drawredrect(x, 0); + } +} + void glist_add(t_glist *x, t_gobj *y) { //fprintf(stderr,"glist_add %lx %d\n", (t_int)x, (x->gl_editor ? 1 : 0)); @@ -84,12 +157,7 @@ void glist_add(t_glist *x, t_gobj *y) // canvas_undo_set_create(x, index), "create"); //glist_noselect(x); } - if (x->gl_editor && x->gl_isgraph && !x->gl_goprect - && pd_checkobject(&y->g_pd)) - { - x->gl_goprect = 1; - canvas_drawredrect(x, 1); - } + glist_update_redrect(x); if (glist_isvisible(x)) gobj_vis(y, x, 1); if (class_isdrawcommand(y->g_pd)) @@ -257,6 +325,8 @@ void glist_delete(t_glist *x, t_gobj *y) //fprintf(stderr,"glist_delete late_rtext_free\n"); rtext_free(rt); } + + if (x->gl_list) glist_update_redrect(x); } } @@ -962,6 +1032,7 @@ static void graph_vis(t_gobj *gr, t_glist *parent_glist, int vis) } /* Sanity check */ + //post("parent_glist=%lx x->gl_obj=%lx", parent_glist, &x->gl_obj); rtext = glist_findrtext(parent_glist, &x->gl_obj); if (!rtext) { @@ -1028,6 +1099,16 @@ static void graph_vis(t_gobj *gr, t_glist *parent_glist, int vis) gui_vmess("gui_graph_fill_border", "xsi", glist_getcanvas(x->gl_owner), tag); + /* ico@vt.edu: do we need to redraw scalars here? */ + for (g = x->gl_list; g; g = g->g_next) + { + gop_redraw = 1; + //fprintf(stderr,"drawing gop objects\n"); + if (g->g_pd == scalar_class) + gobj_vis(g, x, 1); + //fprintf(stderr,"done\n"); + gop_redraw = 0; + } } else if (gobj_shouldvis(gr, parent_glist)) { @@ -1089,7 +1170,7 @@ static void graph_vis(t_gobj *gr, t_glist *parent_glist, int vis) gui_end_array(); } } - /* Finally, end the final array as wel as the call to the GUI */ + /* Finally, end the final array as well as the call to the GUI */ gui_end_array(); gui_end_vmess(); diff --git a/pd/src/g_numbox.c b/pd/src/g_numbox.c index 80d3a66f9514376bbb8f97dc086d4404749b2a3c..63dd1bfd1cf0d55009de50699e6dc9b0b8ede853 100644 --- a/pd/src/g_numbox.c +++ b/pd/src/g_numbox.c @@ -166,7 +166,11 @@ static void my_numbox_draw_new(t_my_numbox *x, t_glist *glist) t_canvas *canvas=glist_getcanvas(glist); char cbuf[8]; sprintf(cbuf, "#%6.6x", x->x_gui.x_bcol); - int half=x->x_gui.x_h/2, d=1+x->x_gui.x_h/34; + int half=x->x_gui.x_h/2; + // ico@vt.edu 2020-08-24: this offset is better as float to ensure + // that the vertical positioning of the number is as close to the center + // as nw.js allows + t_float d=0.5+x->x_gui.x_h/34.0; int x1=text_xpix(&x->x_gui.x_obj, glist), x2=x1+x->x_numwidth; int y1=text_ypix(&x->x_gui.x_obj, glist), y2=y1+x->x_gui.x_h; @@ -190,7 +194,7 @@ static void my_numbox_draw_new(t_my_numbox *x, t_glist *glist) } my_numbox_ftoa(x); sprintf(cbuf, "#%6.6x", x->x_gui.x_fcol); - gui_vmess("gui_numbox_draw_text", "xxsisiiii", + gui_vmess("gui_numbox_draw_text", "xxsisifii", canvas, x, x->x_buf, diff --git a/pd/src/g_scalar.c b/pd/src/g_scalar.c index 73c944ab5a00d108a6f3739ca979c0c4023a4c5a..2017535c27330d2b6c71a5182247bd82d49bb57a 100644 --- a/pd/src/g_scalar.c +++ b/pd/src/g_scalar.c @@ -148,7 +148,7 @@ void word_restore(t_word *wp, t_template *template, argv++, argc--; } else f = 0; - wp->w_float = f; + wp->w_float = f; } else if (type == DT_SYMBOL) { diff --git a/pd/src/m_pd.h b/pd/src/m_pd.h index bc8ee7fd33c93ab2e16b4876b023b6dbec0ebfb5..021f8493f7cce4c31d67a4048a3bef0fc4d10434 100644 --- a/pd/src/m_pd.h +++ b/pd/src/m_pd.h @@ -692,6 +692,7 @@ EXTERN void garray_setsaveit(t_garray *x, int saveit); EXTERN t_glist *garray_getglist(t_garray *x); EXTERN t_array *garray_getarray(t_garray *x); EXTERN t_class *scalar_class; +EXTERN t_class *text_class; EXTERN t_float *value_get(t_symbol *s); EXTERN void value_release(t_symbol *s); diff --git a/pd/src/x_text.c b/pd/src/x_text.c index 333433a86c1e76c9dc863cc585dd197b3fb44937..4e5fe060e3758b3f00092ec17da895c212a53bac 100644 --- a/pd/src/x_text.c +++ b/pd/src/x_text.c @@ -131,8 +131,8 @@ static void textbuf_open(t_textbuf *x) gui_vmess("gui_text_dialog", "xsiii", x, x->b_sym->s_name, - 600, - 340, + 480, + 550, sys_hostfontsize(glist_getfont(x->b_canvas))); //textbuf_senditup(x); }