Two-column VACE layout, inline mode reference button
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
135
tab_batch_ng.py
135
tab_batch_ng.py
@@ -530,49 +530,10 @@ def _render_sequence_card(i, seq, batch_list, data, file_path, state,
|
|||||||
# ======================================================================
|
# ======================================================================
|
||||||
|
|
||||||
def _render_vace_settings(i, seq, batch_list, data, file_path, refresh_list):
|
def _render_vace_settings(i, seq, batch_list, data, file_path, refresh_list):
|
||||||
# Frame to Skip + shift
|
# VACE Schedule (needed early for both columns)
|
||||||
with ui.row().classes('w-full items-end'):
|
|
||||||
fts_input = dict_number('Frame to Skip', seq, 'frame_to_skip').classes('col').props(
|
|
||||||
'outlined')
|
|
||||||
|
|
||||||
# Capture original at render time; blur updates seq before click fires
|
|
||||||
_original_fts = int(seq.get('frame_to_skip', FRAME_TO_SKIP_DEFAULT))
|
|
||||||
|
|
||||||
def shift_fts(idx=i, orig=_original_fts):
|
|
||||||
new_fts = int(fts_input.value) if fts_input.value is not None else orig
|
|
||||||
delta = new_fts - orig
|
|
||||||
if delta == 0:
|
|
||||||
ui.notify('No change to shift', type='info')
|
|
||||||
return
|
|
||||||
shifted = 0
|
|
||||||
for j in range(idx + 1, len(batch_list)):
|
|
||||||
batch_list[j]['frame_to_skip'] = int(
|
|
||||||
batch_list[j].get('frame_to_skip', FRAME_TO_SKIP_DEFAULT)) + delta
|
|
||||||
shifted += 1
|
|
||||||
data[KEY_BATCH_DATA] = batch_list
|
|
||||||
save_json(file_path, data)
|
|
||||||
ui.notify(f'Shifted {shifted} sequences by {delta:+d}', type='positive')
|
|
||||||
refresh_list.refresh()
|
|
||||||
|
|
||||||
ui.button('Shift', icon='arrow_downward', on_click=shift_fts).props('dense')
|
|
||||||
|
|
||||||
dict_input(ui.input, 'Transition', seq, 'transition').props('outlined').classes('q-mt-sm')
|
|
||||||
|
|
||||||
# VACE Schedule
|
|
||||||
sched_val = max(0, min(int(seq.get('vace schedule', 1)), len(VACE_MODES) - 1))
|
sched_val = max(0, min(int(seq.get('vace schedule', 1)), len(VACE_MODES) - 1))
|
||||||
with ui.row().classes('w-full items-center q-mt-sm'):
|
|
||||||
vs_input = dict_number('VACE Schedule', seq, 'vace schedule', default=1,
|
|
||||||
min=0, max=len(VACE_MODES) - 1).classes('col').props('outlined')
|
|
||||||
mode_label = ui.label(VACE_MODES[sched_val]).classes('text-caption')
|
|
||||||
|
|
||||||
def update_mode_label(e):
|
# Mode reference dialog
|
||||||
idx = int(e.sender.value) if e.sender.value is not None else 0
|
|
||||||
idx = max(0, min(idx, len(VACE_MODES) - 1))
|
|
||||||
mode_label.set_text(VACE_MODES[idx])
|
|
||||||
|
|
||||||
vs_input.on('update:model-value', update_mode_label)
|
|
||||||
|
|
||||||
# Mode reference
|
|
||||||
with ui.dialog() as ref_dlg, ui.card():
|
with ui.dialog() as ref_dlg, ui.card():
|
||||||
table_md = (
|
table_md = (
|
||||||
'| # | Mode | Formula |\n|:--|:-----|:--------|\n'
|
'| # | Mode | Formula |\n|:--|:-----|:--------|\n'
|
||||||
@@ -582,30 +543,82 @@ def _render_vace_settings(i, seq, batch_list, data, file_path, refresh_list):
|
|||||||
+ '\n\n*All totals snapped to 4n+1 (1,5,9,...,49,...,81,...)*'
|
+ '\n\n*All totals snapped to 4n+1 (1,5,9,...,49,...,81,...)*'
|
||||||
)
|
)
|
||||||
ui.markdown(table_md)
|
ui.markdown(table_md)
|
||||||
ui.button('Mode Reference', icon='help', on_click=ref_dlg.open).props('flat dense')
|
|
||||||
|
|
||||||
# Input A / B frames
|
with ui.row().classes('w-full q-gutter-md'):
|
||||||
ia_input = dict_number('Input A Frames', seq, 'input_a_frames').props('outlined').classes('q-mt-sm')
|
# --- Left column ---
|
||||||
ib_input = dict_number('Input B Frames', seq, 'input_b_frames').props('outlined').classes('q-mt-sm')
|
with ui.column().classes('col'):
|
||||||
|
# Frame to Skip + shift
|
||||||
|
with ui.row().classes('w-full items-end'):
|
||||||
|
fts_input = dict_number('Frame to Skip', seq, 'frame_to_skip').classes(
|
||||||
|
'col').props('outlined')
|
||||||
|
|
||||||
# VACE Length + output calculation
|
_original_fts = int(seq.get('frame_to_skip', FRAME_TO_SKIP_DEFAULT))
|
||||||
input_a = int(seq.get('input_a_frames', 16))
|
|
||||||
input_b = int(seq.get('input_b_frames', 16))
|
|
||||||
stored_total = int(seq.get('vace_length', 49))
|
|
||||||
mode_idx = int(seq.get('vace schedule', 1))
|
|
||||||
|
|
||||||
if mode_idx == 0:
|
def shift_fts(idx=i, orig=_original_fts):
|
||||||
base_length = max(stored_total - input_a, 1)
|
new_fts = int(fts_input.value) if fts_input.value is not None else orig
|
||||||
elif mode_idx == 1:
|
delta = new_fts - orig
|
||||||
base_length = max(stored_total - input_b, 1)
|
if delta == 0:
|
||||||
else:
|
ui.notify('No change to shift', type='info')
|
||||||
base_length = max(stored_total - input_a - input_b, 1)
|
return
|
||||||
|
shifted = 0
|
||||||
|
for j in range(idx + 1, len(batch_list)):
|
||||||
|
batch_list[j]['frame_to_skip'] = int(
|
||||||
|
batch_list[j].get('frame_to_skip', FRAME_TO_SKIP_DEFAULT)) + delta
|
||||||
|
shifted += 1
|
||||||
|
data[KEY_BATCH_DATA] = batch_list
|
||||||
|
save_json(file_path, data)
|
||||||
|
ui.notify(f'Shifted {shifted} sequences by {delta:+d}', type='positive')
|
||||||
|
refresh_list.refresh()
|
||||||
|
|
||||||
with ui.row().classes('w-full items-center q-mt-sm'):
|
ui.button('Shift', icon='arrow_downward', on_click=shift_fts).props('dense')
|
||||||
vl_input = ui.number('VACE Length', value=base_length, min=1).classes('col').props(
|
|
||||||
'outlined')
|
|
||||||
output_label = ui.label(f'Output: {stored_total}').classes('text-bold')
|
|
||||||
|
|
||||||
|
dict_input(ui.input, 'Transition', seq, 'transition').props('outlined').classes(
|
||||||
|
'w-full q-mt-sm')
|
||||||
|
|
||||||
|
# VACE Schedule
|
||||||
|
with ui.row().classes('w-full items-center q-mt-sm'):
|
||||||
|
vs_input = dict_number('VACE Schedule', seq, 'vace schedule', default=1,
|
||||||
|
min=0, max=len(VACE_MODES) - 1).classes('col').props(
|
||||||
|
'outlined')
|
||||||
|
mode_label = ui.label(VACE_MODES[sched_val]).classes('text-caption')
|
||||||
|
ui.button(icon='help', on_click=ref_dlg.open).props('flat dense round')
|
||||||
|
|
||||||
|
def update_mode_label(e):
|
||||||
|
idx = int(e.sender.value) if e.sender.value is not None else 0
|
||||||
|
idx = max(0, min(idx, len(VACE_MODES) - 1))
|
||||||
|
mode_label.set_text(VACE_MODES[idx])
|
||||||
|
|
||||||
|
vs_input.on('update:model-value', update_mode_label)
|
||||||
|
|
||||||
|
# --- Right column ---
|
||||||
|
with ui.column().classes('col'):
|
||||||
|
ia_input = dict_number('Input A Frames', seq, 'input_a_frames').props(
|
||||||
|
'outlined').classes('w-full')
|
||||||
|
ib_input = dict_number('Input B Frames', seq, 'input_b_frames').props(
|
||||||
|
'outlined').classes('w-full q-mt-sm')
|
||||||
|
|
||||||
|
# VACE Length + output calculation
|
||||||
|
input_a = int(seq.get('input_a_frames', 16))
|
||||||
|
input_b = int(seq.get('input_b_frames', 16))
|
||||||
|
stored_total = int(seq.get('vace_length', 49))
|
||||||
|
mode_idx = int(seq.get('vace schedule', 1))
|
||||||
|
|
||||||
|
if mode_idx == 0:
|
||||||
|
base_length = max(stored_total - input_a, 1)
|
||||||
|
elif mode_idx == 1:
|
||||||
|
base_length = max(stored_total - input_b, 1)
|
||||||
|
else:
|
||||||
|
base_length = max(stored_total - input_a - input_b, 1)
|
||||||
|
|
||||||
|
with ui.row().classes('w-full items-center q-mt-sm'):
|
||||||
|
vl_input = ui.number('VACE Length', value=base_length, min=1).classes(
|
||||||
|
'col').props('outlined')
|
||||||
|
output_label = ui.label(f'Output: {stored_total}').classes('text-bold')
|
||||||
|
|
||||||
|
dict_number('Reference Switch', seq, 'reference switch').props(
|
||||||
|
'outlined').classes('w-full q-mt-sm')
|
||||||
|
|
||||||
|
# Recalculate VACE output when any input changes
|
||||||
def recalc_vace(*_args):
|
def recalc_vace(*_args):
|
||||||
mi = int(vs_input.value) if vs_input.value is not None else 0
|
mi = int(vs_input.value) if vs_input.value is not None else 0
|
||||||
ia = int(ia_input.value) if ia_input.value is not None else 16
|
ia = int(ia_input.value) if ia_input.value is not None else 16
|
||||||
@@ -626,8 +639,6 @@ def _render_vace_settings(i, seq, batch_list, data, file_path, refresh_list):
|
|||||||
for inp in (vs_input, ia_input, ib_input, vl_input):
|
for inp in (vs_input, ia_input, ib_input, vl_input):
|
||||||
inp.on('update:model-value', recalc_vace)
|
inp.on('update:model-value', recalc_vace)
|
||||||
|
|
||||||
dict_number('Reference Switch', seq, 'reference switch').props('outlined').classes('q-mt-sm')
|
|
||||||
|
|
||||||
|
|
||||||
# ======================================================================
|
# ======================================================================
|
||||||
# Mass Update
|
# Mass Update
|
||||||
|
|||||||
Reference in New Issue
Block a user