add/edit tag to ui

click-textual
Maveno 1 year ago
parent 7d7e43c6f0
commit a03449a32b

@ -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()

@ -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.screen import Screen
from textual.widgets import Header, Footer, Placeholder, Label, ListView, ListItem, Static, DataTable, Button, Input, Checkbox, SelectionList, Select 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.containers import Grid, Horizontal
from textual.coordinate import Coordinate
from ffx.model.show import Show from ffx.model.show import Show
from ffx.model.pattern import Pattern from ffx.model.pattern import Pattern
@ -22,6 +22,76 @@ from .audio_layout import AudioLayout
from .track_descriptor import TrackDescriptor 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]] # Screen[dict[int, str, int]]
class TrackDetailsScreen(Screen): class TrackDetailsScreen(Screen):
@ -87,23 +157,6 @@ class TrackDetailsScreen(Screen):
self.__tc = TrackController(context = self.context) self.__tc = TrackController(context = self.context)
self.__pc = PatternController(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 self.__isNew = trackDescriptor is None
if self.__isNew: if self.__isNew:
self.__trackType = trackType self.__trackType = trackType
@ -144,7 +197,7 @@ class TrackDetailsScreen(Screen):
def compose(self): def compose(self):
self.trackTagsTable = DataTable(classes="five") self.trackTagsTable = EditableDataTable(classes="five")
# Define the columns with headers # Define the columns with headers
self.column_key_track_tag_key = self.trackTagsTable.add_column("Key", width=10) self.column_key_track_tag_key = self.trackTagsTable.add_column("Key", width=10)
@ -193,8 +246,9 @@ class TrackDetailsScreen(Screen):
# 11 # 11
yield Static("Stream tags") yield Static("Stream tags")
yield Static(" ", classes="two") yield Static(" ")
yield Button("Add", id="button_add_stream_tag") yield Button("Add", id="button_add_stream_tag")
yield Button("Edit", id="button_edit_stream_tag")
yield Button("Delete", id="button_delete_stream_tag") yield Button("Delete", id="button_delete_stream_tag")
# 12 # 12
yield self.trackTagsTable yield self.trackTagsTable
@ -259,6 +313,31 @@ class TrackDetailsScreen(Screen):
return TrackDescriptor(**kwargs) 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 # Event handler for button press
def on_button_pressed(self, event: Button.Pressed) -> None: def on_button_pressed(self, event: Button.Pressed) -> None:
@ -308,3 +387,64 @@ class TrackDetailsScreen(Screen):
if event.button.id == "cancel_button": if event.button.id == "cancel_button":
self.app.pop_screen() 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

Loading…
Cancel
Save