add/edit tag to ui
This commit is contained in:
142
bin/ffx/tag_delete_screen.py
Normal file
142
bin/ffx/tag_delete_screen.py
Normal file
@@ -0,0 +1,142 @@
|
||||
import click
|
||||
|
||||
from textual import events
|
||||
from textual.app import App, ComposeResult
|
||||
from textual.screen import Screen
|
||||
from textual.widgets import Header, Footer, Placeholder, Label, ListView, ListItem, Static, DataTable, Button, Input
|
||||
from textual.containers import Grid, Horizontal
|
||||
|
||||
from ffx.model.pattern import Pattern
|
||||
from ffx.track_descriptor import TrackDescriptor
|
||||
|
||||
# from .show_controller import ShowController
|
||||
# from .pattern_controller import PatternController
|
||||
from .track_controller import TrackController
|
||||
|
||||
from .track_type import TrackType
|
||||
|
||||
# Screen[dict[int, str, int]]
|
||||
class TrackDeleteScreen(Screen):
|
||||
|
||||
CSS = """
|
||||
|
||||
Grid {
|
||||
grid-size: 4 9;
|
||||
grid-rows: 2 2 2 2 2 2 2 2 2;
|
||||
grid-columns: 30 30 30 30;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
padding: 1;
|
||||
}
|
||||
|
||||
Input {
|
||||
border: none;
|
||||
}
|
||||
Button {
|
||||
border: none;
|
||||
}
|
||||
#toplabel {
|
||||
height: 1;
|
||||
}
|
||||
|
||||
.two {
|
||||
column-span: 2;
|
||||
}
|
||||
.three {
|
||||
column-span: 3;
|
||||
}
|
||||
.four {
|
||||
column-span: 4;
|
||||
}
|
||||
|
||||
.box {
|
||||
height: 100%;
|
||||
border: solid green;
|
||||
}
|
||||
"""
|
||||
|
||||
def __init__(self, trackDescriptor : TrackDescriptor):
|
||||
super().__init__()
|
||||
|
||||
self.context = self.app.getContext()
|
||||
self.Session = self.context['database']['session'] # convenience
|
||||
|
||||
if type(trackDescriptor) is not TrackDescriptor:
|
||||
raise click.ClickException('TrackDeleteScreen.init(): trackDescriptor is required to be of type TrackDescriptor')
|
||||
|
||||
self.__tc = TrackController(context = self.context)
|
||||
|
||||
self.__trackDescriptor = trackDescriptor
|
||||
|
||||
|
||||
def on_mount(self):
|
||||
|
||||
self.query_one("#subindexlabel", Static).update(str(self.__trackDescriptor.getSubIndex()))
|
||||
self.query_one("#patternlabel", Static).update(str(self.__trackDescriptor.getPatternId()))
|
||||
self.query_one("#languagelabel", Static).update(str(self.__trackDescriptor.getLanguage().label()))
|
||||
self.query_one("#titlelabel", Static).update(str(str(self.__trackDescriptor.getTitle())))
|
||||
|
||||
|
||||
def compose(self):
|
||||
|
||||
yield Header()
|
||||
|
||||
with Grid():
|
||||
|
||||
#1
|
||||
yield Static(f"Are you sure to delete the following {self.__trackDescriptor.getType().label()} track?", id="toplabel", classes="four")
|
||||
|
||||
#2
|
||||
yield Static("sub index")
|
||||
yield Static(" ", id="subindexlabel", classes="three")
|
||||
|
||||
#3
|
||||
yield Static("from pattern")
|
||||
yield Static(" ", id="patternlabel", classes="three")
|
||||
|
||||
#4
|
||||
yield Static(" ", classes="four")
|
||||
|
||||
#5
|
||||
yield Static("Language")
|
||||
yield Static(" ", id="languagelabel", classes="three")
|
||||
|
||||
#6
|
||||
yield Static("Title")
|
||||
yield Static(" ", id="titlelabel", classes="three")
|
||||
|
||||
#7
|
||||
yield Static(" ", classes="four")
|
||||
|
||||
#8
|
||||
yield Static(" ", classes="four")
|
||||
|
||||
#9
|
||||
yield Button("Delete", id="delete_button")
|
||||
yield Button("Cancel", id="cancel_button")
|
||||
|
||||
yield Footer()
|
||||
|
||||
|
||||
# Event handler for button press
|
||||
def on_button_pressed(self, event: Button.Pressed) -> None:
|
||||
|
||||
if event.button.id == "delete_button":
|
||||
|
||||
track = self.__tc.findTrack(self.__trackDescriptor.getPatternId(), self.__trackDescriptor.getType(), self.__trackDescriptor.getSubIndex())
|
||||
|
||||
if track is None:
|
||||
raise click.ClickException(f"Track is none: patternId={self.__trackDescriptor.getPatternId()} type={self.__trackDescriptor.getType()} subIndex={self.__trackDescriptor.getSubIndex()}")
|
||||
|
||||
if track is not None:
|
||||
|
||||
if self.__tc.deleteTrack(track.getId()):
|
||||
self.dismiss(self.__trackDescriptor)
|
||||
|
||||
else:
|
||||
#TODO: Meldung
|
||||
self.app.pop_screen()
|
||||
|
||||
if event.button.id == "cancel_button":
|
||||
self.app.pop_screen()
|
||||
|
||||
125
bin/ffx/tag_details_screen.py
Normal file
125
bin/ffx/tag_details_screen.py
Normal file
@@ -0,0 +1,125 @@
|
||||
import click, time
|
||||
|
||||
from textual import events
|
||||
from textual.app import App, ComposeResult
|
||||
from textual.screen import Screen
|
||||
from textual.widgets import Header, Footer, Placeholder, Label, ListView, ListItem, Static, DataTable, Button, Input, Checkbox, SelectionList, Select
|
||||
from textual.containers import Grid, Horizontal
|
||||
|
||||
# Screen[dict[int, str, int]]
|
||||
class TagDetailsScreen(Screen):
|
||||
|
||||
CSS = """
|
||||
|
||||
Grid {
|
||||
grid-size: 5 20;
|
||||
grid-rows: 2 2 2 2 2 3 2 2 2 2 2 6 2 2 6 2 2 2 2 6;
|
||||
grid-columns: 25 25 25 25 225;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
padding: 1;
|
||||
}
|
||||
|
||||
Input {
|
||||
border: none;
|
||||
}
|
||||
Button {
|
||||
border: none;
|
||||
}
|
||||
SelectionList {
|
||||
border: none;
|
||||
min-height: 6;
|
||||
}
|
||||
Select {
|
||||
border: none;
|
||||
}
|
||||
DataTable {
|
||||
min-height: 6;
|
||||
}
|
||||
|
||||
#toplabel {
|
||||
height: 1;
|
||||
}
|
||||
|
||||
.two {
|
||||
column-span: 2;
|
||||
}
|
||||
.three {
|
||||
column-span: 3;
|
||||
}
|
||||
|
||||
.four {
|
||||
column-span: 4;
|
||||
}
|
||||
.five {
|
||||
column-span: 5;
|
||||
}
|
||||
|
||||
.box {
|
||||
height: 100%;
|
||||
border: solid green;
|
||||
}
|
||||
"""
|
||||
|
||||
def __init__(self, key=None, value=None):
|
||||
super().__init__()
|
||||
self.__key = key
|
||||
self.__value = value
|
||||
|
||||
|
||||
|
||||
def on_mount(self):
|
||||
|
||||
if self.__key is not None:
|
||||
self.query_one("#key_input", Input).value = str(self.__key)
|
||||
|
||||
if self.__value is not None:
|
||||
self.query_one("#value_input", Input).value = str(self.__value)
|
||||
|
||||
|
||||
def compose(self):
|
||||
|
||||
yield Header()
|
||||
|
||||
with Grid():
|
||||
|
||||
# 8
|
||||
yield Static("Key")
|
||||
yield Input(id="key_input", classes="four")
|
||||
|
||||
yield Static("Value")
|
||||
yield Input(id="value_input", classes="four")
|
||||
|
||||
# 17
|
||||
yield Static(" ", classes="five")
|
||||
|
||||
# 18
|
||||
yield Button("Save", id="save_button")
|
||||
yield Button("Cancel", id="cancel_button")
|
||||
|
||||
# 19
|
||||
yield Static(" ", classes="five")
|
||||
|
||||
# 20
|
||||
yield Static(" ", classes="five", id="messagestatic")
|
||||
|
||||
yield Footer(id="footer")
|
||||
|
||||
|
||||
def getTagFromInput(self):
|
||||
|
||||
tagKey = self.query_one("#key_input", Input).value
|
||||
tagValue = self.query_one("#value_input", Input).value
|
||||
|
||||
return (tagKey, tagValue)
|
||||
|
||||
|
||||
# Event handler for button press
|
||||
def on_button_pressed(self, event: Button.Pressed) -> None:
|
||||
|
||||
# Check if the button pressed is the one we are interested in
|
||||
if event.button.id == "save_button":
|
||||
self.dismiss(self.getTagFromInput())
|
||||
|
||||
if event.button.id == "cancel_button":
|
||||
self.app.pop_screen()
|
||||
@@ -5,7 +5,7 @@ from textual.app import App, ComposeResult
|
||||
from textual.screen import Screen
|
||||
from textual.widgets import Header, Footer, Placeholder, Label, ListView, ListItem, Static, DataTable, Button, Input, Checkbox, SelectionList, Select
|
||||
from textual.containers import Grid, Horizontal
|
||||
|
||||
from textual.coordinate import Coordinate
|
||||
|
||||
from ffx.model.show import Show
|
||||
from ffx.model.pattern import Pattern
|
||||
@@ -22,6 +22,76 @@ from .audio_layout import AudioLayout
|
||||
|
||||
from .track_descriptor import TrackDescriptor
|
||||
|
||||
from .tag_details_screen import TagDetailsScreen
|
||||
|
||||
from textual.widgets._data_table import CellDoesNotExist
|
||||
|
||||
|
||||
class EditableDataTable(DataTable):
|
||||
"""Custom DataTable that allows editing cells upon mouse click."""
|
||||
|
||||
def on_click(self, event: events.Click) -> None:
|
||||
"""Handle mouse clicks on the table."""
|
||||
|
||||
# raise click.ClickException(f"event={event}")
|
||||
|
||||
#event.x und event.y sind koordinaten im Datatable
|
||||
|
||||
#clicked_cell = self.coordinate_to_cell_key(self.cursor_coordinate)
|
||||
#raise click.ClickException(f"x={event.x} y={event.y} clicked_cell={clicked_cell}")
|
||||
|
||||
|
||||
#raise click.ClickException(f"cuco={self.cursor_coordinate}")
|
||||
|
||||
#clickCoordinates = Coordinate(row = event.y, column=event.x)
|
||||
|
||||
#clicked_cell = self.get_cell_at(event.x, event.y)
|
||||
#row_key, col_key = self.coordinate_to_cell_key(self.cursor_coordinate)
|
||||
|
||||
#raise click.ClickException(f"x={event.x} y={event.y} row={row_key} col={col_key}")
|
||||
|
||||
|
||||
#if clicked_cell:
|
||||
# if row_key is not None and col_key is not None:
|
||||
#row, column = clicked_cell
|
||||
# Get the current cell value and activate editing.
|
||||
#current_value = self.get_cell(row_key, col_key)
|
||||
current_value = self.get_cell_at(self.cursor_coordinate)
|
||||
|
||||
region = self._get_cell_region(self.cursor_coordinate)
|
||||
|
||||
raise click.ClickException(f"region={region}")
|
||||
|
||||
#current_value = self.get_cell(row_key, col_key)
|
||||
#self.activate_cell_edit(row_key, col_key, current_value)
|
||||
|
||||
raise click.ClickException(f"val={current_value}")
|
||||
|
||||
def activate_cell_edit(self, row: int, column: int, value: str) -> None:
|
||||
# """Method to activate cell editing."""
|
||||
# # Create a new input box with the value of the cell to be edited.
|
||||
input_box = Input(value=value, classes="cell-editor")
|
||||
input_box.styles.width = len(value) + 2 # Adjust the width of the input box
|
||||
input_box.styles.padding = (0, 1)
|
||||
#
|
||||
# # Position the input box over the cell to be edited.
|
||||
input_box.styles.position = "absolute"
|
||||
input_box.styles.left = self.get_cell_position(row, column)[0]
|
||||
input_box.styles.top = self.get_cell_position(row, column)[1]
|
||||
|
||||
# # Add the input box to the parent widget for editing.
|
||||
# self.app.mount(input_box)
|
||||
# input_box.focus()
|
||||
#
|
||||
# # Listen to when the user completes editing.
|
||||
# input_box.on_blur = lambda event: self.save_cell_value(row, column, input_box.value)
|
||||
#
|
||||
# def save_cell_value(self, row: int, column: int, value: str) -> None:
|
||||
# """Save the new value to the table and remove the input box."""
|
||||
# self.update_cell(row, column, value)
|
||||
# self.app.query_one(".cell-editor").remove() # Remove the input box after saving.
|
||||
|
||||
|
||||
|
||||
# Screen[dict[int, str, int]]
|
||||
class TrackDetailsScreen(Screen):
|
||||
@@ -87,23 +157,6 @@ class TrackDetailsScreen(Screen):
|
||||
self.__tc = TrackController(context = self.context)
|
||||
self.__pc = PatternController(context = self.context)
|
||||
|
||||
|
||||
INDEX_KEY = 'index'
|
||||
SUB_INDEX_KEY = 'sub_index'
|
||||
PATTERN_ID_KEY = 'pattern_id'
|
||||
|
||||
TRACK_TYPE_KEY = 'track_type'
|
||||
DISPOSITION_SET_KEY = 'disposition_set'
|
||||
TAGS_KEY = 'tags'
|
||||
AUDIO_LAYOUT_KEY = 'audio_layout'
|
||||
|
||||
# if trackDescriptor is None:
|
||||
# self.__trackDescriptor = TrackDescriptor(index=,
|
||||
# sub_index=
|
||||
# pattern_id=patternId,
|
||||
# track_type=trackType)
|
||||
# else:
|
||||
|
||||
self.__isNew = trackDescriptor is None
|
||||
if self.__isNew:
|
||||
self.__trackType = trackType
|
||||
@@ -144,7 +197,7 @@ class TrackDetailsScreen(Screen):
|
||||
|
||||
def compose(self):
|
||||
|
||||
self.trackTagsTable = DataTable(classes="five")
|
||||
self.trackTagsTable = EditableDataTable(classes="five")
|
||||
|
||||
# Define the columns with headers
|
||||
self.column_key_track_tag_key = self.trackTagsTable.add_column("Key", width=10)
|
||||
@@ -193,8 +246,9 @@ class TrackDetailsScreen(Screen):
|
||||
|
||||
# 11
|
||||
yield Static("Stream tags")
|
||||
yield Static(" ", classes="two")
|
||||
yield Static(" ")
|
||||
yield Button("Add", id="button_add_stream_tag")
|
||||
yield Button("Edit", id="button_edit_stream_tag")
|
||||
yield Button("Delete", id="button_delete_stream_tag")
|
||||
# 12
|
||||
yield self.trackTagsTable
|
||||
@@ -259,6 +313,31 @@ class TrackDetailsScreen(Screen):
|
||||
return TrackDescriptor(**kwargs)
|
||||
|
||||
|
||||
|
||||
def getSelectedTag(self):
|
||||
|
||||
try:
|
||||
|
||||
# Fetch the currently selected row when 'Enter' is pressed
|
||||
#selected_row_index = self.table.cursor_row
|
||||
row_key, col_key = self.trackTagsTable.coordinate_to_cell_key(self.trackTagsTable.cursor_coordinate)
|
||||
|
||||
if row_key is not None:
|
||||
selected_tag_data = self.trackTagsTable.get_row(row_key)
|
||||
|
||||
tagKey = str(selected_tag_data[0])
|
||||
tagValue = str(selected_tag_data[1])
|
||||
|
||||
return tagKey, tagValue
|
||||
|
||||
else:
|
||||
return None
|
||||
|
||||
except CellDoesNotExist:
|
||||
return None
|
||||
|
||||
|
||||
|
||||
# Event handler for button press
|
||||
def on_button_pressed(self, event: Button.Pressed) -> None:
|
||||
|
||||
@@ -308,3 +387,64 @@ class TrackDetailsScreen(Screen):
|
||||
|
||||
if event.button.id == "cancel_button":
|
||||
self.app.pop_screen()
|
||||
|
||||
|
||||
|
||||
if event.button.id == "button_add_stream_tag":
|
||||
self.app.push_screen(TagDetailsScreen(), self.handle_add_tag)
|
||||
|
||||
#row = ('<key>','<value>')
|
||||
#self.trackTagsTable.add_row(*map(str, row))
|
||||
|
||||
if event.button.id == "button_edit_stream_tag":
|
||||
tagKey, tagValue = self.getSelectedTag()
|
||||
self.app.push_screen(TagDetailsScreen(key=tagKey, value=tagValue), self.handle_add_tag)
|
||||
|
||||
if event.button.id == "button_delete_stream_tag":
|
||||
pass
|
||||
|
||||
|
||||
|
||||
def handle_add_tag(self, tag):
|
||||
|
||||
row = (tag[0], tag[1])
|
||||
self.trackTagsTable.add_row(*map(str, row))
|
||||
|
||||
|
||||
def handle_edit_tag(self, trackDescriptor : TrackDescriptor):
|
||||
pass
|
||||
# try:
|
||||
# if trackDescriptor.getType() == TrackType.AUDIO:
|
||||
#
|
||||
# row_key, col_key = self.audioStreamsTable.coordinate_to_cell_key(self.audioStreamsTable.cursor_coordinate)
|
||||
#
|
||||
# self.audioStreamsTable.update_cell(row_key, self.column_key_audio_language, trackDescriptor.getLanguage().label())
|
||||
# self.audioStreamsTable.update_cell(row_key, self.column_key_audio_title, trackDescriptor.getTitle())
|
||||
# self.audioStreamsTable.update_cell(row_key, self.column_key_audio_default, 'Yes' if TrackDisposition.DEFAULT in trackDescriptor.getDispositionSet() else 'No')
|
||||
# self.audioStreamsTable.update_cell(row_key, self.column_key_audio_forced, 'Yes' if TrackDisposition.FORCED in trackDescriptor.getDispositionSet() else 'No')
|
||||
#
|
||||
# if trackDescriptor.getType() == TrackType.SUBTITLE:
|
||||
#
|
||||
# row_key, col_key = self.subtitleStreamsTable.coordinate_to_cell_key(self.subtitleStreamsTable.cursor_coordinate)
|
||||
#
|
||||
# self.subtitleStreamsTable.update_cell(row_key, self.column_key_subtitle_language, trackDescriptor.getLanguage().label())
|
||||
# self.subtitleStreamsTable.update_cell(row_key, self.column_key_subtitle_title, trackDescriptor.getTitle())
|
||||
# self.subtitleStreamsTable.update_cell(row_key, self.column_key_subtitle_default, 'Yes' if TrackDisposition.DEFAULT in trackDescriptor.getDispositionSet() else 'No')
|
||||
# self.subtitleStreamsTable.update_cell(row_key, self.column_key_subtitle_forced, 'Yes' if TrackDisposition.FORCED in trackDescriptor.getDispositionSet() else 'No')
|
||||
#
|
||||
# except CellDoesNotExist:
|
||||
# pass
|
||||
|
||||
|
||||
def handle_delete_tag(self, trackDescriptor : TrackDescriptor):
|
||||
pass
|
||||
# try:
|
||||
# if trackDescriptor.getType() == TrackType.AUDIO:
|
||||
# self.updateAudioTracks()
|
||||
#
|
||||
# if trackDescriptor.getType() == TrackType.SUBTITLE:
|
||||
# self.updateSubtitleTracks()
|
||||
#
|
||||
# except CellDoesNotExist:
|
||||
# pass
|
||||
|
||||
|
||||
Reference in New Issue
Block a user