diff --git a/release.md b/release.md index 9d9ce01c..8b1f8e36 100644 --- a/release.md +++ b/release.md @@ -25,6 +25,7 @@ Full docs @ https://docs.grid.space/projects/kiri-moto * 10x speedup for true shadow generation * add FDM gcode feature macros for transitions * add FDM option to alternate shell winding direction +* add FDM print time estimate fudge factor for devices ## Mesh:Tool (1.2.0) diff --git a/src/kiri-mode/fdm/export.js b/src/kiri-mode/fdm/export.js index 220975ad..5f7a6806 100644 --- a/src/kiri-mode/fdm/export.js +++ b/src/kiri-mode/fdm/export.js @@ -25,6 +25,7 @@ FDM.export = function(print, online, ondone, ondebug) { extras = device.extras || {}, { extrudeAbs } = device, extused = Object.keys(print.extruders).map(v => parseInt(v)), + timeFactor = (device.gcodeTime || 1) * 1.5, decimals = config.gcode_decimals || 4, zMoveMax = device.deviceZMax || 0, isBelt = bedBelt, @@ -788,7 +789,7 @@ FDM.export = function(print, online, ondone, ondebug) { } // update time and distance (should calc in moveTo() instead) - time += (dist / speedMMM) * 60 * 1.5; + time += (dist / speedMMM) * 60 * timeFactor; distance += dist; subst.progress = progress = Math.round((distance / totaldistance) * 100); diff --git a/src/kiri/conf.js b/src/kiri/conf.js index f63f51a1..7bcb69cb 100644 --- a/src/kiri/conf.js +++ b/src/kiri/conf.js @@ -120,6 +120,7 @@ function device_from_code(code,mode) { resolutionX: valueOf(set.resolution_x, 1600), resolutionY: valueOf(set.resolution_y, 900), deviceZMax: valueOf(set.z_move_max, 0), + gcodeTime: valueOf(set.time_factor, 1), maxHeight: valueOf(set.build_height, 150), originCenter: valueOf(set.origin_center, false), extrudeAbs: valueOf(set.extrude_abs, false), @@ -273,6 +274,7 @@ const conf = exports({ originCenter: false, deviceZMax: 0, maxHeight: 150, + gcodeTime: 1, gcodePre: [], gcodePost: [], gcodeProc: "", diff --git a/src/kiri/init.js b/src/kiri/init.js index ac2e32ed..505b42a9 100644 --- a/src/kiri/init.js +++ b/src/kiri/init.js @@ -1672,14 +1672,23 @@ gapp.register("kiri.init", [], (root, exports) => { stockHeight: $('stock-width'), device: uc.newGroup(LANG.dv_gr_dev, $('device1'), {group:"ddev", inline:true, class:"noshow"}), - deviceName: uc.newInput(LANG.dv_name_s, {title:LANG.dv_name_l, size:"65%", text:true, action:updateDeviceName}), - bedWidth: uc.newInput(LANG.dv_bedw_s, {title:LANG.dv_bedw_l, convert:uc.toFloat, size:6, units:true, round:2, action:updateDeviceSize}), - bedDepth: uc.newInput(LANG.dv_bedd_s, {title:LANG.dv_bedd_l, convert:uc.toFloat, size:6, units:true, round:2, action:updateDeviceSize}), - maxHeight: uc.newInput(LANG.dv_bedh_s, {title:LANG.dv_bedh_l, convert:uc.toFloat, size:6, modes:FDM_SLA, action:updateDeviceSize}), - resolutionX: uc.newInput(LANG.dv_rezx_s, {title:LANG.dv_rezx_l, convert:uc.toInt, size:6, modes:SLA}), - resolutionY: uc.newInput(LANG.dv_rezy_s, {title:LANG.dv_rezy_l, convert:uc.toInt, size:6, modes:SLA}), - spindleMax: uc.newInput(LANG.dv_spmx_s, {title:LANG.dv_spmx_l, convert:uc.toInt, size: 6, modes:CAM}), - deviceZMax: uc.newInput(LANG.dv_zmax_s, {title:LANG.dv_zmax_l, convert:uc.toInt, size: 6, modes:FDM}), + deviceName: uc.newInput(LANG.dv_name_s, {title:LANG.dv_name_l, size:"70%", text:true, action:updateDeviceName}), + + devbed: uc.newRow([ + uc.newLabel(LANG.volume, { class: "grow" }), + uc.newLabel('X'), + ui.bedWidth = uc.newInput2({title:LANG.dv_bedw_l, convert:uc.toFloat, size:5, units:true, round:2, action:updateDeviceSize}), + uc.newLabel('Y'), + ui.bedDepth = uc.newInput2({title:LANG.dv_bedd_l, convert:uc.toFloat, size:5, units:true, round:2, action:updateDeviceSize}), + uc.newLabel('Z'), + ui.maxHeight = uc.newInput2({title:LANG.dv_bedh_l, convert:uc.toFloat, size:5, modes:FDM_SLA, action:updateDeviceSize}), + ], { class: "var-area" }), + + resolutionX: uc.newInput(LANG.dv_rezx_s, {title:LANG.dv_rezx_l, convert:uc.toInt, size:5, modes:SLA}), + resolutionY: uc.newInput(LANG.dv_rezy_s, {title:LANG.dv_rezy_l, convert:uc.toInt, size:5, modes:SLA}), + spindleMax: uc.newInput(LANG.dv_spmx_s, {title:LANG.dv_spmx_l, convert:uc.toInt, size:5, modes:CAM}), + deviceZMax: uc.newInput(LANG.dv_zmax_s, {title:LANG.dv_zmax_l, convert:uc.toInt, size:5, modes:FDM}), + gcodeTime: uc.newInput(LANG.dv_time_s, {title:LANG.dv_time_l, convert:uc.toFloat, size:5, modes:FDM}), fdmSep: uc.newBlank({class:"pop-sep", modes:FDM}), filamentSource: uc.newSelect(LANG.dv_fsrc_s, {title: LANG.dv_fsrc_l, action: filamentSourceSave, modes:FDM}, "filasrc"), fwRetract: uc.newBoolean(LANG.dv_retr_s, onBooleanClick, {title:LANG.dv_retr_l, modes:FDM}), diff --git a/src/kiri/ui.js b/src/kiri/ui.js index ab2d0df4..6cd83b5a 100644 --- a/src/kiri/ui.js +++ b/src/kiri/ui.js @@ -63,8 +63,9 @@ gapp.register("kiri.ui", [], (root, exports) => { newBlank, newGCode, newGroup, - newInput, newLabel, + newInput, + newInput2, newRange, newRow, newSelect, @@ -633,7 +634,7 @@ gapp.register("kiri.ui", [], (root, exports) => { row.appendChild(newLabel(label)); row.appendChild(ip); - row.setAttribute("class", "var-row"); + row.setAttribute("class", opt.class || "var-row"); if (height > 1) { ip.setAttribute("cols", size); ip.setAttribute("rows", height); @@ -704,6 +705,78 @@ gapp.register("kiri.ui", [], (root, exports) => { return ip; } + function newInput2(options) { + let opt = options || {}, + hide = opt && opt.hide, + size = opt ? opt.size || 5 : 5, + height = opt ? opt.height : 0, + ip = height > 1 ? DOC.createElement('textarea') : DOC.createElement('input'), + action = opt.action || bindTo || inputAction; + + ip.setAttribute("class", "var-input"); + if (Number.isInteger(size)) { + ip.setAttribute("size", size); + } else { + ip.setAttribute("style", `width:${size}`); + } + ip.setAttribute("type", "text"); + ip.setAttribute("spellcheck", "false"); + if (opt) { + if (opt.disabled) ip.setAttribute("disabled", "true"); + if (opt.title) ip.setAttribute("title", opt.title); + if (opt.convert) ip.convert = opt.convert.bind(ip); + if (opt.bound) ip.bound = opt.bound; + if (opt.action) action = opt.action; + } + ip.addEventListener('focus', function(event) { + hidePop(); + setSticky(true); + }); + if (action) { + ip.addEventListener('keydown', function(event) { + let key = event.key; + if ( + opt.text || + (key >= '0' && key <= '9') || + key === '.' || + key === '-' || + key === 'Backspace' || + key === 'Delete' || + key === 'ArrowLeft' || + key === 'ArrowRight' || + key === 'Tab' || + event.metaKey || + event.ctrlKey || + (key === ',' && options.comma) + ) { + return; + } + event.preventDefault(); + event.stopPropagation(); + }); + ip.addEventListener('keyup', function(event) { + if (event.keyCode === 13) { + ip.blur(); + } + }); + ip.addEventListener('blur', function(event) { + setSticky(false); + lastChange = ip; + action(event); + if (opt.trigger) { + refresh(); + } + }); + if (opt.units) { + addUnits(ip, opt.round || 3); + } + } + if (!ip.convert) ip.convert = raw.bind(ip); + // addModeControls(ip); + + return ip; + } + function addUnits(input, round) { setters.push(input); input.setv = function(value) { diff --git a/web/kiri/index.css b/web/kiri/index.css index 00dc4d3d..8b8a336d 100644 --- a/web/kiri/index.css +++ b/web/kiri/index.css @@ -1739,7 +1739,14 @@ th, tr, td, label { flex-grow: 1; font-size: smaller; } -.var-row input { +.var-area { + gap: 3px; +} +.var-area label { + padding: 2px 0 2px 0; + font-size: smaller; +} +.var-row input, .var-area input { margin-right: 0; margin-bottom: 1px; padding-bottom: 1px; diff --git a/web/kiri/lang/en.js b/web/kiri/lang/en.js index 89f676ca..c00d6d36 100644 --- a/web/kiri/lang/en.js +++ b/web/kiri/lang/en.js @@ -46,6 +46,7 @@ self.kiri.lang['en-us'] = { version: "version", view: "view", // left view pop menu wire: "wire", // left render pop menu + volume: "volume", // device build area acct_xpo: ["make a backup of your device","and device profiles with the","option to include workspace","objects and positions"], @@ -106,6 +107,8 @@ self.kiri.lang['en-us'] = { dv_rezy_l: ["y resolution"], dv_zmax_s: "Z axis speed limit", dv_zmax_l: ["maximum Z axis speed","in millimeters / second","0 to disable"], + dv_time_s: "output time factor", + dv_time_l: ["modifier to print time estimates","in the gcode export dialog.","raise or lower value based on your","predicted vs observed print times"], dv_spmx_s: "max spindle", dv_spmx_l: ["max spindle rpm speed","0 to disable"], dv_xtab_s: "absolute positioning",