mirror of
https://github.com/Wan-Video/Wan2.1.git
synced 2025-11-04 14:16:57 +00:00
implemented drag and drop queue reordering
This commit is contained in:
parent
a10d8f9004
commit
7d0eb942b9
173
wgp.py
173
wgp.py
@ -888,6 +888,29 @@ def update_task_thumbnails(task, inputs):
|
|||||||
"end_image_data_base64": [pil_to_base64_uri(img, format="jpeg", quality=70) for img in end_image_data] if end_image_data != None else None
|
"end_image_data_base64": [pil_to_base64_uri(img, format="jpeg", quality=70) for img in end_image_data] if end_image_data != None else None
|
||||||
})
|
})
|
||||||
|
|
||||||
|
def move_task(queue, old_index_str, new_index_str):
|
||||||
|
try:
|
||||||
|
old_idx = int(old_index_str)
|
||||||
|
new_idx = int(new_index_str)
|
||||||
|
except (ValueError, IndexError):
|
||||||
|
return update_queue_data(queue)
|
||||||
|
|
||||||
|
with lock:
|
||||||
|
old_idx += 1
|
||||||
|
new_idx += 1
|
||||||
|
|
||||||
|
if not (0 < old_idx < len(queue)):
|
||||||
|
return update_queue_data(queue)
|
||||||
|
|
||||||
|
item_to_move = queue.pop(old_idx)
|
||||||
|
if old_idx < new_idx:
|
||||||
|
new_idx -= 1
|
||||||
|
clamped_new_idx = max(1, min(new_idx, len(queue)))
|
||||||
|
|
||||||
|
queue.insert(clamped_new_idx, item_to_move)
|
||||||
|
|
||||||
|
return update_queue_data(queue)
|
||||||
|
|
||||||
def move_up(queue, selected_indices):
|
def move_up(queue, selected_indices):
|
||||||
if not selected_indices or len(selected_indices) == 0:
|
if not selected_indices or len(selected_indices) == 0:
|
||||||
return update_queue_data(queue)
|
return update_queue_data(queue)
|
||||||
@ -1462,14 +1485,13 @@ def generate_queue_html(queue):
|
|||||||
<table>
|
<table>
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
|
<th style="width:4%;" class="center-align" title="Drag to reorder">Drag</th>
|
||||||
<th style="width:5%;" class="center-align">Qty</th>
|
<th style="width:5%;" class="center-align">Qty</th>
|
||||||
<th style="width:auto;" class="text-left">Prompt</th>
|
<th style="width:auto;" class="text-left">Prompt</th>
|
||||||
<th style="width:7%;" class="center-align">Length</th>
|
<th style="width:7%;" class="center-align">Length</th>
|
||||||
<th style="width:7%;" class="center-align">Steps</th>
|
<th style="width:7%;" class="center-align">Steps</th>
|
||||||
<th style="width:10%;" class="center-align">Start/Ref</th>
|
<th style="width:10%;" class="center-align">Start/Ref</th>
|
||||||
<th style="width:10%;" class="center-align">End</th>
|
<th style="width:10%;" class="center-align">End</th>
|
||||||
<th style="width:4%;" class="center-align" title="Move Up"></th>
|
|
||||||
<th style="width:4%;" class="center-align" title="Move Down"></th>
|
|
||||||
<th style="width:4%;" class="center-align" title="Edit"></th>
|
<th style="width:4%;" class="center-align" title="Edit"></th>
|
||||||
<th style="width:4%;" class="center-align" title="Remove"></th>
|
<th style="width:4%;" class="center-align" title="Remove"></th>
|
||||||
</tr>
|
</tr>
|
||||||
@ -1506,21 +1528,19 @@ def generate_queue_html(queue):
|
|||||||
if end_img_uri:
|
if end_img_uri:
|
||||||
end_img_md = f'<div class="hover-image" onclick="showImageModal(\'end_{row_index}\')"><img src="{end_img_uri}" alt="{end_img_labels[0]}" /></div>'
|
end_img_md = f'<div class="hover-image" onclick="showImageModal(\'end_{row_index}\')"><img src="{end_img_uri}" alt="{end_img_labels[0]}" /></div>'
|
||||||
|
|
||||||
up_btn = f"""<button onclick="updateAndTrigger('up_{row_index}')" class="action-button" title="Move Up">↑</button>"""
|
drag_handle = f'<td draggable="true" class="drag-handle center-align" title="Drag to reorder">☰</td>'
|
||||||
down_btn = f"""<button onclick="updateAndTrigger('down_{row_index}')" class="action-button" title="Move Down">↓</button>"""
|
|
||||||
edit_btn = f"""<button onclick="updateAndTrigger('edit_{row_index}')" class="action-button" title="Edit">✏️</button>"""
|
edit_btn = f"""<button onclick="updateAndTrigger('edit_{row_index}')" class="action-button" title="Edit">✏️</button>"""
|
||||||
remove_btn = f"""<button onclick="updateAndTrigger('remove_{row_index}')" class="action-button" title="Remove">✖️</button>"""
|
remove_btn = f"""<button onclick="updateAndTrigger('remove_{row_index}')" class="action-button" title="Remove">✖️</button>"""
|
||||||
|
|
||||||
row_html = f"""
|
row_html = f"""
|
||||||
<tr>
|
<tr class="draggable-row" data-index="{row_index}">
|
||||||
|
{drag_handle}
|
||||||
<td class="center-align">{item.get('repeats', "1")}</td>
|
<td class="center-align">{item.get('repeats', "1")}</td>
|
||||||
<td>{prompt_cell}</td>
|
<td>{prompt_cell}</td>
|
||||||
<td class="center-align">{length}</td>
|
<td class="center-align">{length}</td>
|
||||||
<td class="center-align">{num_steps}</td>
|
<td class="center-align">{num_steps}</td>
|
||||||
<td class="center-align">{start_img_md}</td>
|
<td class="center-align">{start_img_md}</td>
|
||||||
<td class="center-align">{end_img_md}</td>
|
<td class="center-align">{end_img_md}</td>
|
||||||
<td class="center-align">{up_btn}</td>
|
|
||||||
<td class="center-align">{down_btn}</td>
|
|
||||||
<td class="center-align">{edit_btn}</td>
|
<td class="center-align">{edit_btn}</td>
|
||||||
<td class="center-align">{remove_btn}</td>
|
<td class="center-align">{remove_btn}</td>
|
||||||
</tr>
|
</tr>
|
||||||
@ -6954,12 +6974,14 @@ def handle_queue_action(state, action_string):
|
|||||||
queue = gen.get("queue", [])
|
queue = gen.get("queue", [])
|
||||||
|
|
||||||
try:
|
try:
|
||||||
action, row_index_str = action_string.split('_')
|
parts = action_string.split('_')
|
||||||
row_index = int(row_index_str)
|
action = parts[0]
|
||||||
|
params = parts[1:]
|
||||||
except (IndexError, ValueError):
|
except (IndexError, ValueError):
|
||||||
return gr.HTML(), gr.Tabs()
|
return gr.HTML(), gr.Tabs()
|
||||||
|
|
||||||
if action == "edit":
|
if action == "edit":
|
||||||
|
row_index = int(params[0])
|
||||||
state["editing_task_index"] = row_index
|
state["editing_task_index"] = row_index
|
||||||
task_to_edit_index = row_index + 1
|
task_to_edit_index = row_index + 1
|
||||||
|
|
||||||
@ -6971,11 +6993,12 @@ def handle_queue_action(state, action_string):
|
|||||||
gr.Warning("Task index out of bounds.")
|
gr.Warning("Task index out of bounds.")
|
||||||
return update_queue_data(queue), gr.Tabs()
|
return update_queue_data(queue), gr.Tabs()
|
||||||
|
|
||||||
elif action == "up":
|
elif action == "move" and len(params) == 3 and params[1] == "to":
|
||||||
return move_up(queue, [row_index]), gr.Tabs()
|
old_index_str, new_index_str = params[0], params[2]
|
||||||
elif action == "down":
|
return move_task(queue, old_index_str, new_index_str), gr.Tabs()
|
||||||
return move_down(queue, [row_index]), gr.Tabs()
|
|
||||||
elif action == "remove":
|
elif action == "remove":
|
||||||
|
row_index = int(params[0])
|
||||||
new_queue_data = remove_task(queue, [row_index])
|
new_queue_data = remove_task(queue, [row_index])
|
||||||
gen["prompts_max"] = gen.get("prompts_max", 0) - 1
|
gen["prompts_max"] = gen.get("prompts_max", 0) - 1
|
||||||
update_status(state)
|
update_status(state)
|
||||||
@ -9582,6 +9605,20 @@ def create_ui():
|
|||||||
display: block;
|
display: block;
|
||||||
margin: auto;
|
margin: auto;
|
||||||
}
|
}
|
||||||
|
#queue_html_container .drag-handle {
|
||||||
|
cursor: grab;
|
||||||
|
user-select: none;
|
||||||
|
}
|
||||||
|
#queue_html_container tr.dragging {
|
||||||
|
opacity: 0.5;
|
||||||
|
background: #2d3748;
|
||||||
|
}
|
||||||
|
#queue_html_container tr.drag-over-top {
|
||||||
|
border-top: 2px solid #4299e1;
|
||||||
|
}
|
||||||
|
#queue_html_container tr.drag-over-bottom {
|
||||||
|
border-bottom: 2px solid #4299e1;
|
||||||
|
}
|
||||||
#image-modal-container {
|
#image-modal-container {
|
||||||
position: fixed;
|
position: fixed;
|
||||||
top: 0;
|
top: 0;
|
||||||
@ -9771,6 +9808,116 @@ def create_ui():
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let draggedItem = null;
|
||||||
|
|
||||||
|
function initializeQueueDragAndDrop() {
|
||||||
|
const queueTbody = document.querySelector('#queue_html_container table > tbody');
|
||||||
|
if (!queueTbody || queueTbody.dataset.dndInitialized) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
queueTbody.dataset.dndInitialized = 'true';
|
||||||
|
|
||||||
|
queueTbody.addEventListener('dragstart', (e) => {
|
||||||
|
if (e.target.classList.contains('drag-handle')) {
|
||||||
|
draggedItem = e.target.closest('.draggable-row');
|
||||||
|
if (draggedItem) {
|
||||||
|
setTimeout(() => {
|
||||||
|
draggedItem.classList.add('dragging');
|
||||||
|
}, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
queueTbody.addEventListener('dragend', (e) => {
|
||||||
|
if (draggedItem) {
|
||||||
|
draggedItem.classList.remove('dragging');
|
||||||
|
draggedItem = null;
|
||||||
|
document.querySelectorAll('.drag-over-top, .drag-over-bottom').forEach(el => {
|
||||||
|
el.classList.remove('drag-over-top', 'drag-over-bottom');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
queueTbody.addEventListener('dragover', (e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
const targetRow = e.target.closest('.draggable-row');
|
||||||
|
|
||||||
|
// Clear previous indicators
|
||||||
|
document.querySelectorAll('.drag-over-top, .drag-over-bottom').forEach(el => {
|
||||||
|
el.classList.remove('drag-over-top', 'drag-over-bottom');
|
||||||
|
});
|
||||||
|
|
||||||
|
if (targetRow && draggedItem && targetRow !== draggedItem) {
|
||||||
|
const rect = targetRow.getBoundingClientRect();
|
||||||
|
const midpoint = rect.top + rect.height / 2;
|
||||||
|
|
||||||
|
if (e.clientY < midpoint) {
|
||||||
|
targetRow.classList.add('drag-over-top');
|
||||||
|
} else {
|
||||||
|
targetRow.classList.add('drag-over-bottom');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
queueTbody.addEventListener('dragleave', (e) => {
|
||||||
|
const relatedTarget = e.relatedTarget;
|
||||||
|
const queueTable = e.currentTarget.closest('table');
|
||||||
|
if (queueTable && !queueTable.contains(relatedTarget)) {
|
||||||
|
document.querySelectorAll('.drag-over-top, .drag-over-bottom').forEach(el => {
|
||||||
|
el.classList.remove('drag-over-top', 'drag-over-bottom');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
queueTbody.addEventListener('drop', (e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
const targetRow = e.target.closest('.draggable-row');
|
||||||
|
|
||||||
|
if (draggedItem && targetRow && targetRow !== draggedItem) {
|
||||||
|
const oldIndex = draggedItem.dataset.index;
|
||||||
|
let newIndex = parseInt(targetRow.dataset.index);
|
||||||
|
|
||||||
|
// If dropping on the bottom half, the new index is after the target row
|
||||||
|
if (targetRow.classList.contains('drag-over-bottom')) {
|
||||||
|
newIndex++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (oldIndex != newIndex) {
|
||||||
|
const action = `move_${oldIndex}_to_${newIndex}`;
|
||||||
|
window.updateAndTrigger(action);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cleanup visual styles
|
||||||
|
document.querySelectorAll('.drag-over-top, .drag-over-bottom').forEach(el => {
|
||||||
|
el.classList.remove('drag-over-top', 'drag-over-bottom');
|
||||||
|
});
|
||||||
|
if (draggedItem) {
|
||||||
|
draggedItem.classList.remove('dragging');
|
||||||
|
draggedItem = null;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const observer = new MutationObserver((mutationsList, observer) => {
|
||||||
|
for(const mutation of mutationsList) {
|
||||||
|
if (mutation.type === 'childList') {
|
||||||
|
const queueContainer = document.querySelector('#queue_html_container');
|
||||||
|
if (queueContainer && queueContainer.querySelector('table > tbody')) {
|
||||||
|
initializeQueueDragAndDrop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const targetNode = document.querySelector('gradio-app');
|
||||||
|
if (targetNode) {
|
||||||
|
observer.observe(targetNode, { childList: true, subtree: true });
|
||||||
|
}
|
||||||
|
|
||||||
|
setTimeout(initializeQueueDragAndDrop, 500);
|
||||||
|
|
||||||
// cancel wheel usage inside image editor
|
// cancel wheel usage inside image editor
|
||||||
const hit = n => n?.id === "img_editor" || n?.classList?.contains("wheel-pass");
|
const hit = n => n?.id === "img_editor" || n?.classList?.contains("wheel-pass");
|
||||||
addEventListener("wheel", e => {
|
addEventListener("wheel", e => {
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user