Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -94,3 +94,5 @@ test_image*
**/*fail*.txt
**/*final*.txt
green.txt

OpenFocus/
7 changes: 3 additions & 4 deletions faststack/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,6 @@
UIStateRestoration,
)


# AWB thresholds on the -1..+1 normalised slider range.
# NOOP: skip applying correction entirely (≈ 0.64 Lab units — below perceptible).
# LABEL: below this the direction word becomes "neutral" in the status message.
Expand Down Expand Up @@ -5347,9 +5346,9 @@ def undo_delete(self):

if action_type == "delete":
try:
(jpg_pair, raw_pair) = action_data
(jpg_src, jpg_bin) = jpg_pair
(raw_src, raw_bin) = raw_pair
jpg_pair, raw_pair = action_data
jpg_src, jpg_bin = jpg_pair
raw_src, raw_bin = raw_pair
except Exception:
self.update_status_message("Undo failed: unexpected undo record format")
log.exception("Unexpected undo record format: %r", action_data)
Expand Down
177 changes: 121 additions & 56 deletions faststack/qml/Main.qml
Original file line number Diff line number Diff line change
Expand Up @@ -732,6 +732,7 @@ ApplicationWindow {
id: actionsMenu
parent: Overlay.overlay
implicitWidth: 220
onClosed: sortSubMenu.close()

background: Rectangle {
implicitWidth: 220
Expand All @@ -755,7 +756,7 @@ ApplicationWindow {
actionsMenu.close()
}
background: Rectangle {
color: parent.hovered ? (root.isDarkTheme ? "#555555" : "#e0e0e0") : "transparent"
color: (parent.enabled && parent.hovered) ? (root.isDarkTheme ? "#555555" : "#e0e0e0") : "transparent"
}
contentItem: Text {
text: parent.text
Expand Down Expand Up @@ -908,80 +909,109 @@ ApplicationWindow {
color: root.isDarkTheme ? "#666666" : "#cccccc"
}

ItemDelegate {
id: sortPhotosLauncher
width: 220
height: 36
hoverEnabled: true
background: Rectangle {
color: parent.hovered ? (root.isDarkTheme ? "#555555" : "#e0e0e0") : "transparent"
}
contentItem: Item {
Text {
anchors.left: parent.left
anchors.leftMargin: 10
anchors.verticalCenter: parent.verticalCenter
text: "Sort Photos"
color: root.currentTextColor
verticalAlignment: Text.AlignVCenter
}
Text {
anchors.right: parent.right
anchors.rightMargin: 10
anchors.verticalCenter: parent.verticalCenter
text: "\u25B6" // Right-pointing triangle
font.pixelSize: 10
color: root.currentTextColor
opacity: 0.6
verticalAlignment: Text.AlignVCenter
}
}
onHoveredChanged: {
if (hovered) {
sortSubMenu.popup(sortPhotosLauncher, sortPhotosLauncher.width - 4, 0)
}
Comment on lines +940 to +943
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Support click to open sort submenu

The new sortPhotosLauncher only opens sortSubMenu from onHoveredChanged, so users on non-hover inputs (touchscreens, pen-only devices, and keyboard activation) cannot reach any sort mode at all. Since this commit also removed the direct sort actions from the main menu, sorting becomes inaccessible in those environments; adding an onClicked (or equivalent focus/keyboard trigger) is needed to preserve functionality.

Useful? React with 👍 / 👎.

}
onClicked: {
sortSubMenu.popup(sortPhotosLauncher, sortPhotosLauncher.width - 4, 0)
}
// Ensure keyboard activation works reliably
Keys.onReturnPressed: clicked()
Keys.onEnterPressed: clicked()
Keys.onSpacePressed: clicked()
}
Comment thread
coderabbitai[bot] marked this conversation as resolved.

// Clear Filename Filter (from old Main.qml)
ItemDelegate {
width: 220
height: 36
text: "Sort: Default"
text: "Clear Filename Filter"
onClicked: {
if (controller) controller.set_sort_mode("default")
if (controller) controller.clear_filter()
actionsMenu.close()
}
background: Rectangle {
color: parent.hovered ? (root.isDarkTheme ? "#555555" : "#e0e0e0")
: ((uiState && uiState.sortMode === "default")
? (root.isDarkTheme ? "#505050" : "#d0ffd0")
: "transparent")
color: parent.hovered ? (root.isDarkTheme ? "#555555" : "#e0e0e0") : "transparent"
}
contentItem: Text {
text: parent.text
color: root.currentTextColor
font.bold: uiState && uiState.sortMode === "default"
verticalAlignment: Text.AlignVCenter
leftPadding: 10
}
}
ItemDelegate {
width: 220
height: 36
text: "Sort: By Filename"
text: "Add Favorites to Batch"
onClicked: {
if (controller) controller.set_sort_mode("filename")
if (uiState) uiState.addFavoritesToBatch()
actionsMenu.close()
}
background: Rectangle {
color: parent.hovered ? (root.isDarkTheme ? "#555555" : "#e0e0e0")
: ((uiState && uiState.sortMode === "filename")
? (root.isDarkTheme ? "#505050" : "#d0ffd0")
: "transparent")
color: parent.hovered ? (root.isDarkTheme ? "#555555" : "#e0e0e0") : "transparent"
}
contentItem: Text {
text: parent.text
color: root.currentTextColor
font.bold: uiState && uiState.sortMode === "filename"
verticalAlignment: Text.AlignVCenter
leftPadding: 10
}
}
ItemDelegate {
width: 220
height: 36
text: "Sort: By Date (Newest)"
text: "Add Uploaded to Batch"
onClicked: {
if (controller) controller.set_sort_mode("date")
if (uiState) uiState.addUploadedToBatch()
actionsMenu.close()
}
background: Rectangle {
color: parent.hovered ? (root.isDarkTheme ? "#555555" : "#e0e0e0")
: ((uiState && uiState.sortMode === "date")
? (root.isDarkTheme ? "#505050" : "#d0ffd0")
: "transparent")
color: parent.hovered ? (root.isDarkTheme ? "#555555" : "#e0e0e0") : "transparent"
}
contentItem: Text {
text: parent.text
color: root.currentTextColor
font.bold: uiState && uiState.sortMode === "date"
verticalAlignment: Text.AlignVCenter
leftPadding: 10
}
}

// Clear Filename Filter (from old Main.qml)
ItemDelegate {
width: 220
height: 36
text: "Clear Filename Filter"
text: "Jump to Last Uploaded"
onClicked: {
if (controller) controller.clear_filter()
if (uiState) uiState.jumpToLastUploaded()
actionsMenu.close()
}
background: Rectangle {
Expand All @@ -997,9 +1027,9 @@ ApplicationWindow {
ItemDelegate {
width: 220
height: 36
text: "Add Favorites to Batch"
text: "Auto-Level Batch"
onClicked: {
if (uiState) uiState.addFavoritesToBatch()
if (uiState) uiState.batchAutoLevels()
actionsMenu.close()
}
background: Rectangle {
Expand All @@ -1015,27 +1045,38 @@ ApplicationWindow {
ItemDelegate {
width: 220
height: 36
text: "Add Uploaded to Batch"
text: "Stack Source RAWs"
enabled: uiState ? uiState.isStackedJpg : false
onClicked: {
if (uiState) uiState.addUploadedToBatch()
if (uiState) uiState.stack_source_raws();
actionsMenu.close()
}
background: Rectangle {
color: parent.hovered ? (root.isDarkTheme ? "#555555" : "#e0e0e0") : "transparent"
color: (parent.enabled && parent.hovered) ? (root.isDarkTheme ? "#555555" : "#e0e0e0") : "transparent"
}
contentItem: Text {
text: parent.text
color: root.currentTextColor
color: parent.enabled ? root.currentTextColor : (root.isDarkTheme ? "#666666" : "#999999")
opacity: parent.enabled ? 1.0 : 0.6
verticalAlignment: Text.AlignVCenter
leftPadding: 10
}
}

// Separator before grid view toggle
Rectangle {
width: 220
height: 1
color: root.isDarkTheme ? "#666666" : "#cccccc"
}

// Toggle Grid/Loupe View
ItemDelegate {
width: 220
height: 36
text: "Jump to Last Uploaded"
text: uiState && uiState.isGridViewActive ? "Single Image View" : "Thumbnail View"
onClicked: {
if (uiState) uiState.jumpToLastUploaded()
if (uiState) uiState.toggleGridView();
actionsMenu.close()
}
background: Rectangle {
Expand All @@ -1048,66 +1089,90 @@ ApplicationWindow {
leftPadding: 10
}
}
}
}

Menu {
id: sortSubMenu
parent: Overlay.overlay
implicitWidth: 180

background: Rectangle {
implicitWidth: 180
implicitHeight: sortSubMenuColumn.implicitHeight
color: root.currentBackgroundColor
border.color: root.isDarkTheme ? "#666666" : "#cccccc"
radius: 4
}

contentItem: Column {
id: sortSubMenuColumn

ItemDelegate {
width: 220
width: 180
height: 36
text: "Auto-Level Batch"
text: "Default"
onClicked: {
if (uiState) uiState.batchAutoLevels()
if (controller) controller.set_sort_mode("default")
sortSubMenu.close()
actionsMenu.close()
}
background: Rectangle {
color: parent.hovered ? (root.isDarkTheme ? "#555555" : "#e0e0e0") : "transparent"
color: parent.hovered ? (root.isDarkTheme ? "#555555" : "#e0e0e0")
: ((uiState && uiState.sortMode === "default")
? (root.isDarkTheme ? "#505050" : "#d0ffd0")
: "transparent")
}
contentItem: Text {
text: parent.text
color: root.currentTextColor
font.bold: uiState && uiState.sortMode === "default"
verticalAlignment: Text.AlignVCenter
leftPadding: 10
}
}
ItemDelegate {
width: 220
width: 180
height: 36
text: "Stack Source RAWs"
enabled: uiState ? uiState.isStackedJpg : false
text: "By Filename"
onClicked: {
if (uiState) uiState.stack_source_raws();
if (controller) controller.set_sort_mode("filename")
sortSubMenu.close()
actionsMenu.close()
}
background: Rectangle {
color: parent.hovered ? (root.isDarkTheme ? "#555555" : "#e0e0e0") : "transparent"
color: parent.hovered ? (root.isDarkTheme ? "#555555" : "#e0e0e0")
: ((uiState && uiState.sortMode === "filename")
? (root.isDarkTheme ? "#505050" : "#d0ffd0")
: "transparent")
}
contentItem: Text {
text: parent.text
color: root.currentTextColor
font.bold: uiState && uiState.sortMode === "filename"
verticalAlignment: Text.AlignVCenter
leftPadding: 10
}
}

// Separator before grid view toggle
Rectangle {
width: 220
height: 1
color: root.isDarkTheme ? "#666666" : "#cccccc"
}

// Toggle Grid/Loupe View
ItemDelegate {
width: 220
width: 180
height: 36
text: uiState && uiState.isGridViewActive ? "Single Image View" : "Thumbnail View"
text: "By Date"
onClicked: {
if (uiState) uiState.toggleGridView();
if (controller) controller.set_sort_mode("date")
sortSubMenu.close()
actionsMenu.close()
}
background: Rectangle {
color: parent.hovered ? (root.isDarkTheme ? "#555555" : "#e0e0e0") : "transparent"
color: parent.hovered ? (root.isDarkTheme ? "#555555" : "#e0e0e0")
: ((uiState && uiState.sortMode === "date")
? (root.isDarkTheme ? "#505050" : "#d0ffd0")
: "transparent")
}
contentItem: Text {
text: parent.text
color: root.currentTextColor
font.bold: uiState && uiState.sortMode === "date"
verticalAlignment: Text.AlignVCenter
leftPadding: 10
}
Expand Down
6 changes: 2 additions & 4 deletions lightroom-catalog-import/inspect_lrcat_photo.py
Original file line number Diff line number Diff line change
Expand Up @@ -69,15 +69,13 @@ def connect_ro(path: str) -> sqlite3.Connection:

def get_tables(conn: sqlite3.Connection) -> list[str]:
"""Return all user table names in the database, sorted."""
rows = conn.execute(
"""
rows = conn.execute("""
SELECT name
FROM sqlite_master
WHERE type='table'
AND name NOT LIKE 'sqlite_%'
ORDER BY name
"""
).fetchall()
""").fetchall()
return [row["name"] for row in rows]


Expand Down
6 changes: 2 additions & 4 deletions lightroom-catalog-import/lrcat_diff.py
Original file line number Diff line number Diff line change
Expand Up @@ -81,14 +81,12 @@ def connect_ro(path: str) -> sqlite3.Connection:

def get_tables(conn: sqlite3.Connection) -> set[str]:
"""Return all user table names in the database."""
rows = conn.execute(
"""
rows = conn.execute("""
SELECT name
FROM sqlite_master
WHERE type = 'table'
AND name NOT LIKE 'sqlite_%'
"""
).fetchall()
""").fetchall()
return {row["name"] for row in rows}


Expand Down
Loading