Files
onefinity-firmware/src/pug/templates/control-view.pug
Claude 7d5949f5fc UI: add W jog row (W- / W Origin / W+ / Home W) under the XYZ jog grid
Mirrors the 4-column rotary A row that appears when 2an==3, so the same
fine/small/medium/large increment selector that drives XYZ jogging now
also drives W jogging. New control-view methods:

- aux_jog_incr(sign) - PUTs aux/jog with the current jog_incr amount
  converted to mm (handles imperial display units)
- aux_move_zero() - PUTs aux/move {mm:0}, the absolute counterpart to
  aux_set_zero (which redefines the current pos as zero without moving)

Row is hidden when w.enabled is false, so users without the auxcnc
controller see no change.
2026-04-30 17:37:49 +02:00

534 lines
23 KiB
Plaintext

script#control-view-template(type="text/x-template")
#control
message(:show.sync="showGcodeMessage")
h3(slot="header") Processing New File
div(slot="body")
h3 Please wait..
p Simulating GCode to check for errors, calculate ETA and generate 3D view.
div(slot="footer")
label Simulating {{(toolpath_progress || 0) | percent}}
message(:show.sync="showNoGcodeMessage")
h3(slot="header") GCode Not Set
div(slot="body")
p Configure the GCode for the selected macro to use it
div(slot="footer")
button.pure-button(@click="showNoGcodeMessage=false") OK
message(:show.sync="macrosLoading")
h3(slot="header") Run Macro?
div(slot="body")
p
| The macro file
strong {{state.selected}}
| is being loaded.
div(slot="footer")
button.pure-button(@click="macrosLoading=false") Cancel
button.pure-button.pure-button-primary(@click="start_pause") Run
message(:show.sync="GCodeNotFound")
h3(slot="header") File not found
div(slot="body")
p It seems like the file you selected cannot be found. Try uploading again.
div(slot="footer")
button.pure-button.button-error(@click="GCodeNotFound=false")
| OK
message(:show.sync="show_probe_dialog")
h3(slot="header") Probe Rotary
div(slot="body")
button.pure-button(:class="state['pw'] ? '' : 'load-on'", @click="showProbeDialog('xyz')") Probe XYZ
button.pure-button(:class="state['pw'] ? '' : 'load-on'", @click="showProbeDialog('z')") Probe Z
div(slot="footer")
button.pure-button(@click="show_probe_dialog=false") Cancel
table(style="table-layout: fixed; width: 100%;")
tr(style="height: fit-content;")
td(style="white-space: nowrap; width: 410px;", rowspan="2")
table.control-buttons(table-layout="fixed")
colgroup
col(style="width:100px")
col(style="width:100px")
col(style="width:100px")
col(style="width:100px")
tr
td(style="height:100px",align="center")
button(@click="jog_fn(-1,1,0,0)")
.fa.fa-arrow-right(style="transform: rotate(-135deg);")
td(style="height:100px",align="center")
button(@click="jog_fn(0,1,0,0)") Y+
td(style="height:100px",align="center")
button(@click="jog_fn(1,1,0,0)")
.fa.fa-arrow-right(style="transform: rotate(-45deg);")
td(style="height:100px",align="center")
button(,@click="jog_fn(0,0,1,0)") Z+
tr
td(style="height:100px",align="center")
button(@click="jog_fn(-1,0,0,0)") X-
td(style="height:100px",align="center")
button(@click="showMoveToZeroDialog('xy')")
| XY
br
| Origin
td(style="height:100px",align="center")
button(@click="jog_fn(1,0,0,0)") X+
td(style="height:100px",align="center")
button(@click="showMoveToZeroDialog('z')")
| Z
br
| Origin
tr
td(style="height:100px",align="center")
button(@click="jog_fn(-1,-1,0,0)")
.fa.fa-arrow-right(style="transform: rotate(135deg);")
td(style="height:100px",align="center")
button(@click="jog_fn(0,-1,0,0)") Y-
td(style="height:100px",align="center")
button(@click="jog_fn(1,-1,0,0)")
.fa.fa-arrow-right(style="transform: rotate(45deg);")
td(style="height:100px",align="center")
button(@click="jog_fn(0,0,-1,0)") Z-
tr
td(style="height:100px",align="center")
button(:style="getJogIncrStyle('fine')", @click="jog_incr = 'fine'")
span {{jog_incr_amounts[display_units].fine}}#[span.jog-units {{metric ? 'mm' : 'in'}}]
td(style="height:100px",align="center")
button(:style="getJogIncrStyle('small')", @click="jog_incr = 'small'")
span {{jog_incr_amounts[display_units].small}}#[span.jog-units {{metric ? 'mm' : 'in'}}]
td(style="height:100px",align="center")
button(:style="getJogIncrStyle('medium')", @click="jog_incr = 'medium'")
span {{jog_incr_amounts[display_units].medium}}#[span.jog-units {{metric ? 'mm' : 'in'}}]
td(style="height:100px",align="center")
button(:style="getJogIncrStyle('large')", @click="jog_incr = 'large'")
span {{jog_incr_amounts[display_units].large}}#[span.jog-units {{metric ? 'mm' : 'in'}}]
// W axis jog row (auxcnc). Only shown when the aux controller
// is enabled in aux.json.
tr(v-if="w.enabled")
td(style="height:100px", align="center", colspan="1")
button(@click="aux_jog_incr(-1)",
:disabled="!w.enabled",
style="display:grid;justify-content:center;align-items:center;padding:14px;")
| W-
.fa.fa-arrow-down
td(style="height:100px", align="center", colspan="1")
button(@click="aux_move_zero()", :disabled="!w.enabled")
| W
br
| Origin
td(style="height:100px", align="center", colspan="1")
button(@click="aux_jog_incr(+1)",
:disabled="!w.enabled",
style="display:grid;justify-content:center;align-items:center;padding:14px;")
| W+
.fa.fa-arrow-up
td(style="height:100px", align="center", colspan="1")
button(@click="aux_home()", :disabled="!w.enabled")
| Home
br
| W
tr(v-if="state['2an'] == 3")
td(style="height:100px", align="center", colspan="1")
button(@click="show_probe_dialog=true")
| Probe
br
| Rotary
td(style="height:100px", align="center", colspan="1")
button(@click="jog_fn(0,0,0,-1)", style="display: grid;justify-content: center;align-items: center;padding: 14px;")
| A-
.fa.fa-rotate-left
td(style="height:100px", align="center", colspan="1")
button(@click="showMoveToZeroDialog('a')")
| A
br
| Origin
td(style="height:100px", align="center", colspan="1")
button(@click="jog_fn(0,0,0,1)", style="display: grid;justify-content: center;align-items: center;padding: 14px;")
| A+
.fa.fa-rotate-right
tr(v-else)
td(style="height:100px", align="center", colspan="2")
button(:class="state['pw'] ? '' : 'load-on'",
style="height:100px;width:200px",
@click="showProbeDialog('xyz')")
| Probe XYZ
td(style="height:100px", align="center", colspan="2")
button(:class="state['pw'] ? '' : 'load-on'",
style="height:100px;width:200px",
@click="showProbeDialog('z')")
| Probe Z
td(style="vertical-align: top;")
table.axes
tr(:class="axes.klass")
th.name Axis
th.position Position
th.absolute Absolute
th.offset Offset
th.state State
th.tstate Toolpath
th.actions
button.pure-button(disabled, style="height:60px;width:60px;display:none;")
button.pure-button(:disabled="!can_set_axis",
title="Zero all axis offsets.", @click="zero()",style="height:60px;width:60px")
.fa.fa-map-marker
button.pure-button(title="Home all axes.", @click="home()",
:disabled="!is_idle",style="height:60px;width:60px")
.fa.fa-home
each axis in 'xyzabc'
tr.axis(:class=`${axis}.klass`, v-if=`${axis}.enabled`,
:title=`${axis}.title`)
th.name= axis
td.position: unit-value(:value=`${axis}.pos`, precision=4)
td.absolute: unit-value(:value=`${axis}.abs`, precision=3)
td.offset: unit-value(:value=`${axis}.off`, precision=3)
td.state
.fa(:class=`'fa-' + ${axis}.icon`)
| {{#{axis}.state}}
td.tstate(:class=`${axis}.tklass`, :title=`${axis}.toolmsg`, @click=`showToolpathMessageDialog('${axis}')`)
.fa(:class=`'fa-' + ${axis}.ticon`)
| {{#{axis}.tstate}}
th.actions
button.pure-button(:disabled="!can_set_axis",
title=`Set {{'${axis}' | upper}} axis position.`,
@click=`show_set_position('${axis}')`, style="height:60px;width:60px")
.fa.fa-cog
button.pure-button(:disabled="!can_set_axis",
title=`Zero {{'${axis}' | upper}} axis offset.`,
@click=`zero('${axis}')`, style="height:60px;width:60px")
.fa.fa-map-marker
button.pure-button(:disabled="!is_idle", @click=`home('${axis}')`,
title=`Home {{'${axis}' | upper}} axis.`, style="height:60px;width:60px")
.fa.fa-home
// Auxiliary W axis (auxcnc ESP32 over /dev/ttyUSB0)
tr.axis(:class="w.klass", v-if="w.enabled", :title="w.title")
th.name w
td.position: unit-value(:value="w.pos", precision=4)
td.absolute: unit-value(:value="w.abs", precision=3)
td.offset —
td.state
.fa(:class="'fa-' + w.icon")
| {{w.state}}
td.tstate(:class="w.tklass", :title="w.toolmsg")
.fa(:class="'fa-' + w.ticon")
| {{w.tstate}}
th.actions
// Invisible placeholder so the W marker/home buttons line
// up under the same columns as the X/Y/Z buttons above
// (which have a third "set position" cog).
button.pure-button(disabled,
style="height:60px;width:60px;visibility:hidden")
.fa.fa-cog
button.pure-button(title="Set W axis position to 0.",
@click="aux_set_zero()", style="height:60px;width:60px")
.fa.fa-map-marker
button.pure-button(:disabled="!w.enabled", @click="aux_home()",
title="Home W axis.", style="height:60px;width:60px")
.fa.fa-home
tr(style="vertical-align: top;")
td
table(width="100%")
tr
td(style="text-align:center")
table.info
tr
th State
td(:class="{attention: highlight_state}") {{mach_state}}
tr
th Message
td.message(:class="{attention: highlight_state}")
| {{message.replace(/^#/, '')}}
tr
th Display Units
td.units
select(v-model="display_units")
option(value="METRIC") METRIC
option(value="IMPERIAL") IMPERIAL
tr(title="Active tool")
th Tool
td {{state.tool || 0}}
td
table.info
tr(
title="Current velocity in {{metric ? 'meters' : 'inches'}} per minute")
th Velocity
td
unit-value(:value="state.v", precision="2", unit="", iunit="",
scale="0.0254")
| {{metric ? ' m/min' : ' IPM'}}
tr(title="Programmed feed rate.")
th Feed
td
unit-value(:value="state.feed", precision="2", unit="", iunit="")
| {{metric ? ' mm/min' : ' IPM'}}
tr(title="Programed and actual speed.")
th Speed
td
| {{state.speed || 0 | fixed 0}}
span(v-if="!isNaN(state.s)")  ({{state.s | fixed 0}})
= ' RPM'
tr(title="Load switch states.")
th Loads
td
span(:class="state['1oa'] ? 'load-on' : ''")
| 1:{{state['1oa'] ? 'On' : 'Off'}}
|  
span(:class="state['2oa'] ? 'load-on' : ''")
| 2:{{state['2oa'] ? 'On' : 'Off'}}
td
table.info
tr
th Remaining
td(title="Total run time (days:hours:mins:secs)").
#[span(v-if="plan_time_remaining") {{plan_time_remaining | time}} of]
{{toolpath.time | time}}
tr
th ETA
td.eta {{eta}}
tr
th Line
td
| {{0 <= state.line ? state.line : 0 | number}}
span(v-if="toolpath.lines")
| &nbsp;of {{toolpath.lines | number}}
tr
th Progress
td.progress
label {{(progress || 0) | percent}}
.bar(:style="'width:' + (progress || 0) * 100 + '%'")
.macros-div(class="present")
button.macros-button(title="Click to run Macros",v-for="(index,macros) in state.macros",
@click="run_macro(index)",:disabled="!is_ready",v-bind:style="{ backgroundColor: macros.color }") {{macros.name}}
.tabs
input#tab1(type="radio", name="tabs",checked="" @click="tab = 'auto'")
label(for="tab1", title="Run GCode programs",style="height:50px;width:100px") Auto
input#tab2(type="radio", name="tabs", @click="tab = 'mdi'")
label(for="tab2", title="Manual GCode entry",style="height:50px;width:100px") MDI
input#tab3(type="radio", name="tabs", @click="tab = 'messages'")
label(for="tab3",style="height:50px;width:100px") Messages
input#tab4(type="radio", name="tabs", @click="tab = 'indicators'")
label(for="tab4",style="height:50px;width:100px") Indicators
section#content1.tab-content.pure-form
.toolbar.pure-control-group
button.pure-button(:class="{'attention': is_holding}",
title="{{is_running ? 'Pause' : 'Start'}} program.",
@click="start_pause", :disabled="!state.selected",
style="height:100px;width:100px;font-weight:normal")
img(v-if="is_running" src="images/pause_gcode.png" style="height: 55px;")
img(v-else src="images/play_gcode.png" style="height: 55px;")
button.pure-button(title="Stop program.", @click="stop", style="height:100px;width:100px;font-weight:normal")
img(src="images/stop.png" style="height: 55px;")
button.pure-button(title="Pause program at next optional stop (M1).",
@click="optional_pause", v-if="false", style="height:100px;width:100px;font-weight:normal")
.fa.fa-stop-circle-o
message(:show.sync="uploading_files")
h3(slot="header") Files uploading
div(slot="body")
h3 Please wait...
p
p The files are currently being uploaded.
p Do not close the window.
div(slot="footer")
button.pure-button(title="Execute one program step.", @click="step",
:disabled="(!is_ready && !is_holding) || !state.selected",
v-if="false", style="height:100px;width:100px;font-weight:normal")
.fa.fa-step-forward
button.pure-button(title="Upload a new GCode folder.", @click="open_folder",
:disabled="!is_ready",style="height:100px;width:100px;font-weight:normal")
img(src="images/upload_folder.png" style="height: 65px;")
form.gcode-folder-input.file-upload
input#folderInput(type="file", @change="upload_folder", :disabled="!is_ready",
webkitdirectory, directory)
button.pure-button(title="Upload a new GCode program.", @click="open_file",
:disabled="!is_ready",style="height:100px;width:100px;font-weight:normal")
img(src="images/upload_gcode.png" style="height: 65px;")
form.gcode-file-input.file-upload
input(type="file", @change="upload_file", :disabled="!is_ready",
accept=".nc,.ngc,.gcode,.gc", multiple)
a(:disabled="!state.selected", download,
:href="'/api/file/' + state.selected",
title="Download the selected GCode program.")
button.pure-button(:disabled="!state.selected", style="height:100px;width:100px")
img(src="images/download_gcode.png" style="height: 65px;")
button.pure-button(title="Delete current GCode program.",
@click="deleteGCode = true",
:disabled="!state.selected || !is_ready",style="height:100px;width:100px;font-weight:normal")
img(src="images/delete_gcode.png" style="height: 55px;")
message.error-message(:show.sync="deleteGCode")
h3(slot="header") Select files to delete:
div(slot="body")
input.search-bar(type="text", v-model="search_query", placeholder="Search Files...")
.container
.folders
h3 Folders
div(v-for="(index, folder) in state.gcode_list", :key="index", @click="populateFiles(index)",
class="folder-item", :class="{ selected: index === selected_folder_index }") {{ folder.name }}
.files
h3 Files
label.file-item(v-for="item in gcode_filtered_files" :key="item")
input(type="checkbox" :value="item" v-model="selected_items_to_delete")
| {{ item }}
div(slot="footer")
button.pure-button(@click="cancel_delete",style="height:50px") Cancel
//- button.pure-button.button-error(@click="delete_all_except_macros")
//- .fa.fa-trash
//- | &nbsp;All
button.pure-button.button-success(@click="delete_current",style="height:50px")
.fa.fa-trash
| &nbsp;Selected
.drop-down-container
message(:show.sync="create_folder")
h3(slot="header") Enter folder name:
div(slot="body")
input.input-name(type="text",minlength='1',maxlength='15',style ="margin-top:1rem;margin-bottom:2rem;",
id="folder-name" ,v-model="folder_name",@keypress="edited_folder_name")
div(slot="footer")
button.pure-button(@click="cancel_new_folder") Cancel
button.pure-button.button-success(@click="create_new_folder",:disabled="!edited")
| Create
message(:show.sync="confirmDelete")
h3(slot="header") Delete Folder?
div(slot="body")
p Are you sure to delete the folder?
div(slot="footer")
button.pure-button(@click="confirmDelete=false") Cancel
button.pure-button.button-error(@click="delete_folder") Folder only
button.pure-button.button-success(@click="delete_folder_and_files") Folder and files
button.pure-button(title="Create a new folder.", @click="create_folder=true",
:disabled="!is_ready",style="height:100%")
| Create Folder
button.pure-button(title="Delete a folder.", @click="confirmDelete=true",
:disabled="!is_ready",style="height:100%;margin-left:5px")
| Delete Folder
select(title="Select previously uploaded GCode folder.",
v-model="state.folder", @change="reset_gcode", :disabled="!is_ready",
style="max-width:100%;margin-left:5px")
option( selected='' value='default') Default folder
option(v-for="file in gcode_folders", :value="file") {{file}}
select(title="Select previously uploaded GCode programs.",
v-model="state.selected", @change="load", :disabled="!is_ready",
style="max-width:300px;margin-left:5px")
option(v-for="file in gcode_files", :value="file") {{file}}
button.pure-button(@click="toggle_sorting", :disabled="!is_ready",
style="height:75%")
| {{files_sortby}}
.progress(v-if="toolpath_progress && toolpath_progress < 1",
title="Simulating GCode to check for errors, calculate ETA and " +
"generate 3D view. You can run GCode before the simulation " +
"finishes.")
div(:style="'width:' + (toolpath_progress || 0) * 100 + '%'")
label Simulating {{(toolpath_progress || 0) | percent}}
path-viewer(:toolpath="toolpath", :state="state", :config="config")
gcode-viewer
section#content2.tab-content
.mdi.pure-form(title="Manual GCode entry.")
button.pure-button(:disabled="!can_mdi",
:class="{'attention': is_holding}",
title="{{is_running ? 'Pause' : 'Start'}} command.",
@click="mdi_start_pause",style="height:100px;width:100px")
.fa(:class="is_running ? 'fa-pause' : 'fa-play'")
button.pure-button(title="Stop command.", @click="stop",style="height:100px;width:100px")
.fa.fa-stop
input(v-model="mdi", :disabled="!can_mdi", @keyup.enter="submit_mdi")
div
em The machine is currently operating in #[strong {{mach_units}}] units. Use G20/G21 to switch units.
.history(:class="{placeholder: !history}")
span(v-if="!history.length") MDI history displays here.
ul
li(v-for="item in history", @click="load_history($index)",
track-by="$index")
| {{item}}
section#content3.tab-content
console
section#content4.tab-content
indicators(:state="state", :template="template")
.override(title="Feed rate override.")
label Feed
input(type="range", min="0", max="2", step="0.01",
v-model="feed_override", @change="override_feed")
span.percent {{feed_override | percent 0}}
.override(title="Spindle speed override.")
label Speed
input(type="range", min="0", max="2", step="0.01",
v-model="speed_override", @change="override_speed")
span.percent {{speed_override | percent 0}}