Skip to content

Commit

Permalink
- Added support for | delimiter between keyboard shortcuts, so a user…
Browse files Browse the repository at this point in the history
… can easily add alternate key-presses to various actions. Combined alternates into single settings entries.

- Fixed nudge to use +/- 1 frame
- Added nudgeBig to use +/1 5 frames
- Added Cut (Ctrl+X) to copy and remove selection
  • Loading branch information
jonoomph committed Sep 13, 2024
1 parent 0141091 commit dd8bcea
Show file tree
Hide file tree
Showing 3 changed files with 103 additions and 203 deletions.
116 changes: 10 additions & 106 deletions src/settings/_default.settings
Original file line number Diff line number Diff line change
Expand Up @@ -578,47 +578,23 @@
"title": "Toggle Razor",
"restart": false,
"setting": "actionRazorTool",
"value": "C",
"type": "text"
},
{
"category": "Keyboard",
"title": "Toggle Razor (Alternate 1)",
"restart": false,
"setting": "actionRazorTool",
"value": "B",
"value": "C | B | R",
"type": "text"
},
{
"category": "Keyboard",
"title": "Previous Marker",
"restart": false,
"setting": "actionPreviousMarker",
"value": "Ctrl+Shift+M",
"type": "text"
},
{
"category": "Keyboard",
"title": "Previous Marker (Alternate 1)",
"restart": false,
"setting": "actionPreviousMarker",
"value": "Ctrl+Left",
"value": "Ctrl+Shift+M | Alt+Left",
"type": "text"
},
{
"category": "Keyboard",
"title": "Next Marker",
"restart": false,
"setting": "actionNextMarker",
"value": "Shift+M",
"type": "text"
},
{
"category": "Keyboard",
"title": "Next Marker (Alternate 1)",
"restart": false,
"setting": "actionNextMarker",
"value": "Ctrl+Right",
"value": "Shift+M | Alt+Right",
"type": "text"
},
{
Expand Down Expand Up @@ -666,15 +642,7 @@
"title": "Export Video",
"restart": false,
"setting": "actionExportVideo",
"value": "Ctrl+E",
"type": "text"
},
{
"category": "Keyboard",
"title": "Export Video (Alternate 1)",
"restart": false,
"setting": "actionExportVideo",
"value": "Ctrl+M",
"value": "Ctrl+E | Ctrl+M",
"type": "text"
},
{
Expand Down Expand Up @@ -770,63 +738,31 @@
"title": "Zoom In",
"restart": false,
"setting": "actionTimelineZoomIn",
"value": "=",
"type": "text"
},
{
"category": "Keyboard",
"title": "Zoom In (Alternate 1)",
"restart": false,
"setting": "actionTimelineZoomIn",
"value": "Ctrl+=",
"value": "= | Ctrl+=",
"type": "text"
},
{
"category": "Keyboard",
"title": "Zoom Out",
"restart": false,
"setting": "actionTimelineZoomOut",
"value": "-",
"type": "text"
},
{
"category": "Keyboard",
"title": "Zoom Out (Alternate 1)",
"restart": false,
"setting": "actionTimelineZoomOut",
"value": "Ctrl+-",
"value": "- | Ctrl+-",
"type": "text"
},
{
"category": "Keyboard",
"title": "Previous Frame",
"restart": false,
"setting": "seekPreviousFrame",
"value": "Left",
"type": "text"
},
{
"category": "Keyboard",
"title": "Previous Frame (Alternate 1)",
"restart": false,
"setting": "seekPreviousFrame",
"value": ",",
"value": "Left | ,",
"type": "text"
},
{
"category": "Keyboard",
"title": "Next Frame",
"restart": false,
"setting": "seekNextFrame",
"value": "Right",
"type": "text"
},
{
"category": "Keyboard",
"title": "Next Frame (Alternate 1)",
"restart": false,
"setting": "seekNextFrame",
"value": ".",
"value": "Right | .",
"type": "text"
},
{
Expand All @@ -850,47 +786,15 @@
"title": "Play/Pause Toggle",
"restart": false,
"setting": "playToggle",
"value": "Space",
"type": "text"
},
{
"category": "Keyboard",
"title": "Play/Pause Toggle (Alternate 1)",
"restart": false,
"setting": "playToggle1",
"value": "Up",
"type": "text"
},
{
"category": "Keyboard",
"title": "Play/Pause Toggle (Alternate 2)",
"restart": false,
"setting": "playToggle2",
"value": "Down",
"type": "text"
},
{
"category": "Keyboard",
"title": "Play/Pause Toggle (Alternate 3)",
"restart": false,
"setting": "playToggle3",
"value": "K",
"value": "Space | Up | Down | K",
"type": "text"
},
{
"category": "Keyboard",
"title": "Delete Item",
"restart": false,
"setting": "deleteItem",
"value": "Delete",
"type": "text"
},
{
"category": "Keyboard",
"title": "Delete Item (Alternate 1)",
"restart": false,
"setting": "deleteItem1",
"value": "Backspace",
"value": "Delete | Backspace",
"type": "text"
},
{
Expand Down
109 changes: 81 additions & 28 deletions src/windows/main_window.py
Original file line number Diff line number Diff line change
Expand Up @@ -1571,7 +1571,7 @@ def actionPreviousMarker_trigger(self, checked=True):
all_marker_positions = self.findAllMarkerPositions()

# Loop through all markers, and find the closest one to the left
closest_position = Non
closest_position = None
for marker_position in sorted(all_marker_positions):
# Is marker smaller than position?
if marker_position < current_position and (abs(marker_position - current_position) > 0.001):
Expand Down Expand Up @@ -1682,43 +1682,53 @@ def getAllKeyboardShortcuts(self):
return keyboard_shortcuts

def initShortcuts(self):
""" Initialize / update QShortcuts for the main window actions """
# Clear all existing shortcuts for QAction objects
for action in self.findChildren(QAction):
action.setShortcut(QKeySequence()) # Clear any default shortcuts
"""Initialize / update QShortcuts for the main window actions."""

# Dictionary to store all shortcut objects so they don't go out of scope
# Store all QShortcuts so they don't go out of scope
if not hasattr(self, 'shortcuts'):
self.shortcuts = {}
self.shortcuts = []

# Clear previous QShortcuts
for shortcut in self.shortcuts:
shortcut.setParent(None) # Remove shortcuts by clearing parent

self.shortcuts.clear() # Clear list of previous shortcuts

# Automatically create shortcuts that follow the pattern self.SHORTCUTNAME or self.SHORTCUTNAME.trigger
# Set to track all key sequences and prevent duplication
used_shortcuts = set()

# Automatically create shortcuts that follow the pattern self.SHORTCUTNAME
for shortcut in self.getAllKeyboardShortcuts():
method_name = shortcut.get('setting')
shortcut_value = shortcut.get('value')

# Remove any trailing numbers from the method name
# Split the shortcut values by the pipe '|' and strip any surrounding whitespace
shortcut_sequences = [s.strip() for s in shortcut_value.split('|')]

# Remove any trailing numbers from the method name (i.e., strip suffix for alternates)
base_method_name = re.sub(r'\d+$', '', method_name)

# Check if this method_name refers to a QAction or a method
# Apply the shortcuts to the corresponding QAction or method
if hasattr(self, base_method_name):
obj = getattr(self, base_method_name)

key_sequences = [QKeySequence(seq) for seq in shortcut_sequences if seq] # Create QKeySequence list

if isinstance(obj, QAction):
# If it's a QAction, set its shortcut
obj.setShortcut(QKeySequence(shortcut_value))
# Handle QAction with multiple key sequences using setShortcuts()
obj.setShortcuts(key_sequences)
else:
# If it's a method or has a trigger, create or update the QShortcut
try:
method = obj.trigger # Check for self.SHORTCUT.trigger
except AttributeError:
method = obj # If no .trigger, assume it's a method

if method_name in self.shortcuts:
self.shortcuts[method_name].setKey(QKeySequence(shortcut_value))
else:
self.shortcuts[method_name] = QShortcut(QKeySequence(shortcut_value), self, activated=method, context=Qt.WindowShortcut)
# If it's a method, create QShortcuts for each key sequence
for key_seq_obj in key_sequences:
if key_seq_obj not in used_shortcuts: # Avoid assigning duplicate shortcuts
qshortcut = QShortcut(key_seq_obj, self, activated=obj, context=Qt.WindowShortcut)
self.shortcuts.append(qshortcut) # Keep reference to avoid garbage collection
used_shortcuts.add(key_seq_obj) # Track the shortcut as used
else:
log.warning(
f"Duplicate shortcut {key_seq_obj.toString()} detected for {base_method_name}. Skipping.")
else:
log.warning(f"Shortcut {method_name} does not have a matching method or QAction.")
log.warning(f"Shortcut {base_method_name} does not have a matching method or QAction.")

# Log shortcut initialization completion
log.debug("Shortcuts initialized or updated.")
Expand Down Expand Up @@ -1879,6 +1889,38 @@ def actionRemoveClip_trigger(self):
# Refresh preview
get_app().window.refreshFrameSignal.emit()

# def actionInsertKeyframePosition_Triggered(self):
# """Insert a 'Location' / 'Position' keyframe"""
# log.info("Inserting keyframe for position")
#
# def actionInsertKeyframeScale_Triggered(self):
# """Insert a 'Scale' keyframe"""
# log.info("Inserting keyframe for scale")
#
# def actionInsertKeyframeRotation_Triggered(self):
# """Insert a 'Rotation' keyframe"""
# log.info("Inserting keyframe for rotation")
#
# def actionInsertKeyframeAlpha_Triggered(self):
# """Insert an 'Alpha' keyframe"""
# log.info("Inserting keyframe for alpha (opacity)")
#
# def actionRippleDelete_Triggered(self):
# """Removes a clip or transition and shifts the timeline accordingly"""
# log.info("Performing ripple delete")
#
# def actionRippleSelect_Triggered(self):
# """Selects ALL clips or transitions to the right of the current selected item"""
# log.info("Selecting clips for ripple editing")
#
# def actionRippleSliceKeepLeft_Triggered(self):
# """Slice and keep the left side of a clip/transition, and then ripple the position change to the right."""
# log.info("Slicing timeline and keeping the left side")
#
# def actionRippleSliceKeepRight_Triggered(self):
# """Slice and keep the right side of a clip/transition, and then ripple the position change to the right."""
# log.info("Slicing timeline and keeping the right side")

def actionProperties_trigger(self):
log.debug('actionProperties_trigger')

Expand Down Expand Up @@ -3103,19 +3145,30 @@ def copyAll(self):
"""Handle Copy QShortcut (selected clips / transitions)"""
self.timeline.Copy_Triggered(MenuCopy.ALL, self.selected_clips, self.selected_transitions, [])

def cutAll(self):
"""Copy and remove the currently selected clip/transition"""
self.copyAll()
self.deleteItem()

def pasteAll(self):
"""Handle Paste QShortcut (at timeline position, same track as original clip)"""
self.timeline.Paste_Triggered(MenuCopy.PASTE, self.selected_clips, self.selected_transitions)

def nudgeLeft(self):
"""Nudge the selected clips to the left"""
self.timeline.Nudge_Triggered(-1, self.selected_clips, self.selected_transitions)

def nudgeLeftBig(self):
"""Nudge the selected clip/transition to the left (5 pixels)"""
self.timeline.Nudge_Triggered(-5, self.selected_clips, self.selected_transitions)

def nudgeRight(self):
"""Nudge the selected clips to the right"""
self.timeline.Nudge_Triggered(1, self.selected_clips, self.selected_transitions)

def pasteAll(self):
"""Handle Paste QShortcut (at timeline position, same track as original clip)"""
fps = get_app().project.get("fps")
fps_float = float(fps["num"]) / float(fps["den"])
self.timeline.Paste_Triggered(MenuCopy.PASTE, self.selected_clips, self.selected_transitions)
def nudgeRightBig(self):
"""Nudge the selected clip/transition to the right (5 pixels)"""
self.timeline.Nudge_Triggered(5, self.selected_clips, self.selected_transitions)

def eventFilter(self, obj, event):
"""Filter out certain QShortcuts - for example, arrow keys used
Expand Down
Loading

0 comments on commit dd8bcea

Please sign in to comment.