Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Exclude Objects #754

Merged
merged 40 commits into from
Jul 10, 2022
Merged
Show file tree
Hide file tree
Changes from 29 commits
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
aa98f75
Initial hack at cancel object UI
troy-jacobson Aug 5, 2021
a3bf1ce
Cleanup
troy-jacobson Aug 5, 2021
5656b4b
Refactor out of gcode preview
troy-jacobson Aug 14, 2021
6c7bdde
Refactoring snapshot
troy-jacobson Aug 19, 2021
4fb0587
Refactoring snapshot
troy-jacobson Aug 19, 2021
70243ea
Nicer UI with list reset
troy-jacobson Aug 19, 2021
9d9adbd
Cleanup
troy-jacobson Aug 19, 2021
19a2d13
Cleanup
troy-jacobson Aug 19, 2021
258bf35
Adding new widget to git
troy-jacobson Aug 25, 2021
cfeb15c
parser cleanup
troy-jacobson Sep 9, 2021
788d2e7
Using preprocessed gcode with markers already inserted
troy-jacobson Sep 9, 2021
ccfad3d
get_status() and outline support from klipper
troy-jacobson Sep 10, 2021
6c53657
Working implementation using klipper get_status()
troy-jacobson Sep 15, 2021
f445dcc
Typo fix
troy-jacobson Sep 15, 2021
b5e4c30
Add current object tracking
Sep 17, 2021
4903108
hardening and other cleanup tasks
troy-jacobson Sep 17, 2021
61619f5
Fix types
Sep 22, 2021
4bc1a97
fix: apply eslint fixes
matmen Jul 8, 2022
03d4bc8
chore: clean up code
matmen Jul 8, 2022
780e6a3
style: adjust styling for better visibility and intuition
matmen Jul 8, 2022
cc87239
fix: don't open modal if part is already excluded
matmen Jul 8, 2022
b172fb4
style: switch to cancel icon with larger hitbox
matmen Jul 8, 2022
70283e9
feat(i18n): add exclude object specific message
matmen Jul 8, 2022
30993dd
feat: add exclude objects modal/dialog
matmen Jul 8, 2022
76c3c2f
chore: make gcode viewer auto load opt-in to match latest FluiddPi ch…
matmen Jul 8, 2022
22359ad
fix: disable modal button when no parts present
matmen Jul 8, 2022
ec235ad
fix: modal button disabling
matmen Jul 9, 2022
2b2786f
Update src/store/parts/mutations.ts
matmen Jul 9, 2022
2c21cb3
fix: modal max width
matmen Jul 9, 2022
f924759
Update src/components/widgets/gcode-preview/GcodePreviewCard.vue
matmen Jul 9, 2022
4b674ed
Update src/components/widgets/gcode-preview/GcodePreview.vue
matmen Jul 9, 2022
1b58509
Revert "Update src/components/widgets/gcode-preview/GcodePreview.vue"
matmen Jul 9, 2022
7c1c9ca
fix: refactor display conditions
matmen Jul 9, 2022
6077826
fix: refactor display conditions
matmen Jul 9, 2022
14034df
fix: display current part
matmen Jul 9, 2022
8224370
fix: auto following race condition
matmen Jul 9, 2022
75dacf9
fix(style): exclude object modal wrapping
matmen Jul 9, 2022
8fbb0f6
fix(style): properly size modal actions
matmen Jul 9, 2022
193a58e
Merge branch 'develop' into feat/cancel-object
matmen Jul 9, 2022
d1649af
Update src/components/widgets/exclude-objects/ExcludeObjectsDialog.vue
matmen Jul 10, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
151 changes: 151 additions & 0 deletions src/components/widgets/exclude-objects/ExcludeObjects.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
<template>
<g
id="parts"
class="layer"
>
<path
v-for="name in outlineNames"
:key="`${name}bounds`"
:class="isPartExcluded(name) ? 'partOutline partExcluded' : 'partOutline'"
:d="partSVG(name)"
/>
<svg
v-for="name in iconNames"
:key="`${name}icon`"
width="7"
height="7"
viewBox="0 0 24 24"
class="partIcon"
:x="partPos(name).x - 7/2"
:y="partPos(name).y - 7/2"
>
<path
:class="iconClasses(name)"
:d="iconCancelled"
/>
<path
v-if="!isPartExcluded(name)"
:class="iconClasses(name)"
:d="iconCircle"
class="hitarea"
@click="$emit('cancel', name)"
/>
</svg>
</g>
</template>

<script lang="ts">
import { Component, Mixins } from 'vue-property-decorator'
import StateMixin from '@/mixins/state'
import { Icons } from '@/globals'

@Component({})
export default class ExcludeObjects extends Mixins(StateMixin) {
get outlineNames () {
const parts = this.$store.getters['parts/getParts']
const names = []
for (const name in parts) {
if (parts[name].outline.length >= 3) {
names.push(name)
}
}
return names
}

get iconNames () {
const parts = this.$store.getters['parts/getParts']
const state = this.$store.getters['parts/getPrintState']
const names = []
for (const name in parts) {
const excluded = this.isPartExcluded(name)
if (parts[name].target &&
((state === 'printing' || state === 'paused') ||
((state === 'complete' || state === 'cancelled' || state === 'error') && excluded))) {
names.push(name)
}
}
return names
}

iconClasses (name: string) {
return this.isPartExcluded(name) ? 'partExcluded' : 'partIncluded'
}

partSVG (name: string) {
return this.$store.getters['parts/getPartSVG'](name)
}

get iconCancelled () {
return Icons.cancelled
}

get iconCircle () {
return Icons.circle
}

partPos (name: string) {
return this.$store.getters['parts/getPartPos'](name)
}

isPartCurrent (name: string) {
return this.$store.getters['parts/getIsPartCurrent'](name)
}

isPartExcluded (name: string) {
return this.$store.getters['parts/getIsPartExcluded'](name)
}
}
</script>

<style lang="scss" scoped>
.layer > path {
fill: none;
stroke: var(--v-success-base);
stroke-linecap: round;
stroke-linejoin: round;
}

.layer .partIcon {
filter: brightness(150%);
fill-opacity: 15%;
}

.layer .partIcon .hitarea {
pointer-events: all;
z-index: -1;
stroke-width: 0;
}

.layer .partIcon .partIncluded:hover {
fill-opacity: 50%;
}

.layer .partIcon.partCurrent {
fill: var(--v-info-base);
fill-opacity: 30%;
}

.layer .partIcon .partIncluded {
pointer-events: all;
fill: var(--v-success-base);
stroke: var(--v-success-base);
stroke-width: .5;
}

.layer .partIcon.partExcluded {
filter: brightness(75%);
pointer-events: none;
}

.layer .partOutline {
filter: opacity(60%);
stroke-width: .5;
}

.layer .partExcluded {
filter: opacity(100%);
fill: var(--v-error-base);
stroke: var(--v-error-base);
fill-opacity: 35%;
}
</style>
75 changes: 75 additions & 0 deletions src/components/widgets/exclude-objects/ExcludeObjectsDialog.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
<template>
<v-dialog
:value="value"
max-width="50vw"
persistent
>
<v-card>
<v-card-title class="card-heading py-2 px-5">
<v-icon left>
$cancelled
</v-icon>
<span class="focus--text">
{{ $t('app.gcode.label.exclude_object') }}
</span>
</v-card-title>

<v-card-text class="py-3 px-5">
<v-simple-table>
<tbody>
<tr
v-for="part in parts"
:key="part.name"
>
<td>{{ part.name }}</td>
<td>
<app-btn
x-small
fab
:disabled="isPartExcluded(part.name)"
@click="$emit('cancelObject', part.name)"
>
<v-icon color="error">
$cancelled
</v-icon>
</app-btn>
</td>
</tr>
</tbody>
</v-simple-table>
</v-card-text>

<v-divider />

<v-card-actions class="py-2 px-5">
<v-spacer />
<app-btn
color="primary"
text
@click="$emit('close')"
>
{{ $t('app.general.btn.close') }}
</app-btn>
</v-card-actions>
</v-card>
</v-dialog>
</template>

<script lang="ts">
import { Component, Prop, Mixins } from 'vue-property-decorator'
import StateMixin from '@/mixins/state'

@Component({})
export default class ExcludeObjectDialog extends Mixins(StateMixin) {
@Prop({ type: Boolean, default: false })
public value!: boolean

get parts () {
return this.$store.getters['parts/getParts']
}

isPartExcluded (name: string) {
return this.$store.getters['parts/getIsPartExcluded'](name)
}
}
</script>
24 changes: 23 additions & 1 deletion src/components/widgets/gcode-preview/GcodePreview.vue
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,10 @@
:stroke-width="extrusionLineWidth"
/>
</g>
<exclude-objects
v-if="showExcludeObjects"
@cancel="$emit('cancelObject', $event)"
/>
</g>
</svg>
</div>
Expand All @@ -204,8 +208,13 @@ import StateMixin from '@/mixins/state'
import panzoom, { PanZoom } from 'panzoom'
import { BBox, LayerNr, LayerPaths } from '@/store/gcodePreview/types'
import { GcodePreviewConfig } from '@/store/config/types'
import ExcludeObjects from '@/components/widgets/exclude-objects/ExcludeObjects.vue'

@Component({})
@Component({
components: {
ExcludeObjects
}
})
export default class GcodePreview extends Mixins(StateMixin) {
@Prop({ type: Boolean, default: true })
public disabled!: boolean
Expand Down Expand Up @@ -276,6 +285,19 @@ export default class GcodePreview extends Mixins(StateMixin) {
return this.panning ? 'optimizeSpeed' : 'geometricPrecision'
}

get showExcludeObjects () {
const file = this.$store.getters['gcodePreview/getFile']
if (!file) {
return true
matmen marked this conversation as resolved.
Show resolved Hide resolved
}
const printerFile = this.$store.state.printer.printer.current_file

if (printerFile.filename) {
return (file.path + '/' + file.filename) === (printerFile.path + '/' + printerFile.filename)
}
return false
}

get flipX (): boolean {
return this.$store.state.config.uiSettings.gcodePreview.flip.horizontal
}
Expand Down
42 changes: 41 additions & 1 deletion src/components/widgets/gcode-preview/GcodePreviewCard.vue
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,18 @@
</app-btn>
</app-btn-collapse-group>

<app-btn
color=""
class="ml-1"
fab
x-small
text
:disabled="!parts.length"
matmen marked this conversation as resolved.
Show resolved Hide resolved
matmen marked this conversation as resolved.
Show resolved Hide resolved
@click="excludeObjectDialog = true"
>
<v-icon>$cancelled</v-icon>
</app-btn>

<app-btn-collapse-group
:collapsed="true"
menu-icon="$cog"
Expand All @@ -40,6 +52,13 @@
@cancel="abortParser"
/>

<ExcludeObjectsDialog
v-if="excludeObjectDialog"
:value="excludeObjectDialog"
@close="excludeObjectDialog = false"
@cancelObject="cancelObject($event)"
/>

<v-row>
<v-col
cols="12"
Expand Down Expand Up @@ -123,6 +142,7 @@
:layer="currentLayer"
:progress="moveProgress"
:disabled="!fileLoaded"
@cancelObject="cancelObject($event)"
/>
</v-col>
</v-row>
Expand All @@ -141,13 +161,15 @@ import GcodePreviewParserProgressDialog from '@/components/widgets/gcode-preview
import { MinMax } from '@/store/gcodePreview/types'
import AppBtnCollapseGroup from '@/components/ui/AppBtnCollapseGroup.vue'
import { AxiosResponse } from 'axios'
import ExcludeObjectsDialog from '@/components/widgets/exclude-objects/ExcludeObjectsDialog.vue'

@Component({
components: {
AppBtnCollapseGroup,
GcodePreviewParserProgressDialog,
GcodePreview,
GcodePreviewControls
GcodePreviewControls,
ExcludeObjectsDialog
}
})
export default class GcodePreviewCard extends Mixins(StateMixin, FilesMixin) {
Expand All @@ -159,6 +181,7 @@ export default class GcodePreviewCard extends Mixins(StateMixin, FilesMixin) {

currentLayer = 0
moveProgress = 0
excludeObjectDialog = false

get visibleLayer () {
return this.currentLayer + 1
Expand Down Expand Up @@ -350,5 +373,22 @@ export default class GcodePreviewCard extends Mixins(StateMixin, FilesMixin) {
get autoLoadOnPrintStart () {
return this.$store.state.config.uiSettings.gcodePreview.autoLoadOnPrintStart
}

async cancelObject (id: string) {
const reqId = id.toUpperCase().replace(/\s/g, '_')

const res = await this.$confirm(
this.$tc('app.general.simple_form.msg.confirm_exclude_object'),
{ title: this.$tc('app.general.label.confirm'), color: 'card-heading', icon: '$error' }
)

if (res) {
this.sendGcode(`EXCLUDE_OBJECT NAME=${reqId}`)
}
}

get parts () {
return Object.values(this.$store.getters['parts/getParts'])
}
}
</script>
2 changes: 2 additions & 0 deletions src/locales/de.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,7 @@ app:
load_current_file: Aktuelle Datei laden
label:
current_layer_height: Aktuelle Schichthöhe
exclude_object: Objekt ausschließen
follow_progress: Fortschritt folgen
layer: Schicht
layers: Schichten
Expand Down Expand Up @@ -292,6 +293,7 @@ app:
Probe/Bltouch Z-Offset wird aus dem aktuellen Z-Offset berechnet und
aktualisiert.
confirm: Sind Sie sicher?
confirm_exclude_object: Sind Sie sicher, dass Sie dieses Objekt vom Druck ausschließen wollen?
confirm_power_device_toggle: Sind Sie sicher? Dies wird das Gerät ein- bzw. ausschalten.
confirm_reboot_host: Sind Sie sicher? Das Host-System wird neu gestartet.
confirm_service_restart: Möchten Sie den Dienst %{name} wirklich neu starten?
Expand Down
2 changes: 2 additions & 0 deletions src/locales/en.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,7 @@ app:
load_current_file: Load Current File
label:
current_layer_height: Current Layer Height
exclude_object: Exclude Object
follow_progress: Follow progress
layer: Layer
layers: Layers
Expand Down Expand Up @@ -296,6 +297,7 @@ app:
required: Required
msg:
confirm: Are you sure?
confirm_exclude_object: Are you sure you want to exclude this object from printing?
confirm_reboot_host: Are you sure? This will reboot your host system.
confirm_shutdown_host: Are you sure? This will shutdown your host system.
confirm_service_restart: Are you sure you want to restart the %{name} service?
Expand Down
Loading