Skip to content

feat(gui): add "Copy to sections" action for selected traces#103

Open
dustenhubbard wants to merge 2 commits into
mainfrom
feat/copy-to-sections
Open

feat(gui): add "Copy to sections" action for selected traces#103
dustenhubbard wants to merge 2 commits into
mainfrom
feat/copy-to-sections

Conversation

@dustenhubbard

Copy link
Copy Markdown
Member

Adds a "Copy to sections..." action to the field and trace-list context menus. Selected traces are copied onto the chosen sections (numbers or ranges) at the same field x-y, re-projected through each section's own transform. Records per-section undo state so one undo reverts the whole copy.

Closes #94. #91 is a duplicate of the same request.

Copying a trace today drops it only into the current section, so placing
the same trace at the same field location across several sections means
navigating to each one and pasting by hand. Add a "Copy to sections..."
action that copies the selected trace(s) onto multiple chosen sections
in one step.

Each trace's field coordinates are re-projected through every target
section's own inverse transform (computed once per section), so the
traces land at the identical field x-y regardless of how each section is
aligned. Sections whose transform is not invertible are skipped and
reported rather than written to. Trace attributes are preserved and the
source (current) section is left unchanged.

An alignment lock protects a section's transform, not its trace content,
so traces are copied onto every chosen section regardless of its lock
status, just as traces can be drawn on a locked section.

Target sections are chosen by number or inclusive range in a small
picker dialog. The parser validates tokens without materializing typed
ranges, so a huge upper bound cannot hang the UI, and it reports
requested sections that do not exist instead of silently dropping them.

The action is available at the field context-menu top level (next to
Copy) and in the trace list. Includes tests for the parser and the
data-model copy operation.

Closes #94. #91 is a duplicate of the same request.
Report the section numbers that actually received the trace(s) instead of
a bare count, so the message reflects what was done rather than what was
requested and surfaces any silently-skipped targets. Collapse long
contiguous runs to ranges (e.g. "2-5, 10") and use singular/plural grammar
("section 5" vs "sections 2, 3"). Preserve the existing non-invertible
"skipped" reporting. Move message building into a pure format_copy_result
helper.

@quasiTriestino quasiTriestino left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When R-clicking in the field, "copy" appears gray when no objects are currently selected. Could you also make this the case for copy-to-sections? Also, copy is ctrl-C. If ctrl-shift-C isn't yet taken, let's make this the shortcut key for copy-to-sections.

Comment on lines +1180 to +1184
The traces' points must be given in FIELD coordinates (i.e. already
mapped through a section transform, the same form the clipboard/paste
path uses). Each target section stores the points through its own
inverse transform, so the traces land at the identical field x-y on
every section regardless of how each section is aligned.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
The traces' points must be given in FIELD coordinates (i.e. already
mapped through a section transform, the same form the clipboard/paste
path uses). Each target section stores the points through its own
inverse transform, so the traces land at the identical field x-y on
every section regardless of how each section is aligned.
The traces' points must be given in FIELD (not SCREEN) coordinates.

Comment on lines +170 to +176
info = QLabel(self, text=(
"Copy the selected trace(s) onto other sections at the same "
"location.\n"
f"The current section ({current}) is left unchanged.\n"
f"Enter section numbers or ranges from {smin} to {smax}, "
"e.g. \"10-20\" or \"5, 8, 11\"."
))

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
info = QLabel(self, text=(
"Copy the selected trace(s) onto other sections at the same "
"location.\n"
f"The current section ({current}) is left unchanged.\n"
f"Enter section numbers or ranges from {smin} to {smax}, "
"e.g. \"10-20\" or \"5, 8, 11\"."
))
info = QLabel(self, text=(
"Copy selected trace(s) onto other sections.\n"
f"Enter section numbers or ranges from {smin} to {smax}, "
f"{section_placeholders}."
))


self.setLayout(vlayout)

def accept(self):

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These checks on section range are good and likely should be pulled out of this file and made into a more general request-sections-verification tool that is run anytime a user requests an operation on multiple sections.

def format_copy_result(copied_to, skipped, excluded_current=None) -> str:
"""Build the user-facing summary for a "Copy to sections" run.

Reports the sections that ACTUALLY received the trace(s) rather than a bare

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
Reports the sections that ACTUALLY received the trace(s) rather than a bare
Reports the sections that actually received the trace(s) rather than a bare

self.setWindowTitle("Copy to sections")

vlayout = QVBoxLayout()

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
random_sections = sorted(random.sample(range(smin, smax + 1), k=3) # get 3 random sections and sort
random_sections = ", ".join(str(s) for s in random_sections) # join into string
section_placeholders = f"e.g. \"{smin}-{smax}\" or \"{random_sections}\""

vlayout.addWidget(info)

self.spec_input = QLineEdit(self)
self.spec_input.setPlaceholderText("e.g. 10-20 or 5, 8, 11")

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
self.spec_input.setPlaceholderText("e.g. 10-20 or 5, 8, 11")
self.spec_input.setPlaceholderText(section_placeholders)

@@ -0,0 +1,221 @@
from PySide6.QtWidgets import (

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
from PySide6.QtWidgets import (
import random
from PySide6.QtWidgets import (

self.setWindowTitle("Copy to sections")

vlayout = QVBoxLayout()

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Creating a realistic placeholder for a given series.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

"Copy To": copy a trace to multiple chosen sections at the same x-y location

2 participants