editor: added configurable actions unite threshold #898

This commit is contained in:
Alex Andres 2024-06-20 17:28:23 +02:00
parent 1972952701
commit 20773b5165
No known key found for this signature in database
GPG key ID: 340764C7851D7041
20 changed files with 438 additions and 67 deletions

View file

@ -42,6 +42,7 @@ public class DefaultConfiguration extends EditorConfiguration {
setAdvancedUIMode(false);
setExtendedFullscreen(false);
setVideoExportPath(new File(System.getProperty("user.home"), "Desktop").getAbsolutePath());
setActionsUniteThreshold(700);
getWhiteboardConfig().setBackgroundColor(Color.WHITE);
getWhiteboardConfig().setVerticalLinesVisible(false);

View file

@ -19,6 +19,7 @@
package org.lecturestudio.editor.api.config;
import org.lecturestudio.core.app.configuration.Configuration;
import org.lecturestudio.core.beans.IntegerProperty;
import org.lecturestudio.core.beans.StringProperty;
public class EditorConfiguration extends Configuration {
@ -26,6 +27,9 @@ public class EditorConfiguration extends Configuration {
/** The path where the video export files are stored at. */
private final StringProperty videoExportPath = new StringProperty();
/** The threshold value in milliseconds for merging annotations. */
private final IntegerProperty actionsUniteThreshold = new IntegerProperty(700);
/**
* Get the path where the video export files are stored at.
@ -53,4 +57,31 @@ public class EditorConfiguration extends Configuration {
public StringProperty videoExportPathProperty() {
return videoExportPath;
}
/**
* Get the actions unite threshold in milliseconds.
*
* @return the unite threshold.
*/
public int getActionsUniteThreshold() {
return actionsUniteThreshold.get();
}
/**
* Set the actions unite threshold in milliseconds.
*
* @param threshold the unite threshold.
*/
public void setActionsUniteThreshold(int threshold) {
this.actionsUniteThreshold.set(threshold);
}
/**
* Get the actions unite threshold property.
*
* @return the unite threshold property.
*/
public IntegerProperty actionsUniteThresholdProperty() {
return actionsUniteThreshold;
}
}

View file

@ -0,0 +1,138 @@
/*
* Copyright (C) 2020 TU Darmstadt, Department of Computer Science,
* Embedded Systems and Applications Group.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.lecturestudio.editor.api.edit;
import java.util.ArrayList;
import java.util.List;
import java.util.ListIterator;
import org.lecturestudio.core.recording.RecordedEvents;
import org.lecturestudio.core.recording.RecordedPage;
import org.lecturestudio.core.recording.RecordingEditException;
import org.lecturestudio.core.recording.action.ActionType;
import org.lecturestudio.core.recording.action.PlaybackAction;
import org.lecturestudio.core.recording.action.ZoomAction;
import org.lecturestudio.core.recording.edit.RecordedObjectAction;
public class DeleteCompositeEventsAction extends RecordedObjectAction<RecordedEvents> {
private final List<PlaybackAction> actions;
private final int pageNumber;
private List<PlaybackAction> savedActions;
public DeleteCompositeEventsAction(RecordedEvents lectureObject,
List<PlaybackAction> actions, int pageNumber) {
super(lectureObject);
this.actions = actions;
this.pageNumber = pageNumber;
}
@Override
public void execute() throws RecordingEditException {
List<PlaybackAction> pageActions = getPageActions();
savedActions = new ArrayList<>(pageActions);
for (PlaybackAction action : actions) {
int actionIndex = pageActions.indexOf(action);
if (actionIndex < 0) {
throw new RecordingEditException("RecordedPage does not contain any action to delete");
}
ListIterator<PlaybackAction> iterator = pageActions.listIterator(actionIndex);
deleteAction(action, iterator);
if (action instanceof ZoomAction) {
deleteZoomAction(iterator);
}
}
}
@Override
public void undo() {
List<PlaybackAction> actions = getPageActions();
actions.clear();
actions.addAll(savedActions);
}
@Override
public void redo() throws RecordingEditException {
execute();
}
private List<PlaybackAction> getPageActions() {
RecordedEvents lecturePages = getRecordedObject();
RecordedPage recordedPage = lecturePages.getRecordedPage(pageNumber);
return recordedPage.getPlaybackActions();
}
private void deleteAction(PlaybackAction action,
ListIterator<PlaybackAction> iterator) {
while (iterator.hasNext()) {
var iterAction = iterator.next();
var actionType = iterAction.getType();
if (!iterAction.equals(action)
&& iterAction.hasHandle()
&& action.hasHandle()
&& iterAction.getHandle() != action.getHandle()) {
// End the deletion, if and only if both actions contain handles,
// which do not match.
break;
}
iterator.remove();
if (actionType == ActionType.TOOL_END || actionType == ActionType.ZOOM_OUT) {
break;
}
}
}
private void deleteZoomAction(ListIterator<PlaybackAction> iterator) {
while (iterator.hasNext()) {
var action = iterator.next();
var actionType = action.getType();
switch (actionType) {
case ZOOM -> {
// Ran into a separate zoom action, keep it intact.
return;
}
case ZOOM_OUT -> {
// Done here removing connected actions.
iterator.remove();
return;
}
case PANNING -> {
// Remove pan action belonging to the zoomed state action.
iterator.remove();
deleteAction(action, iterator);
}
}
}
}
}

View file

@ -18,7 +18,6 @@
package org.lecturestudio.editor.api.edit;
import java.util.ArrayList;
import java.util.List;
import org.lecturestudio.core.model.Interval;
@ -54,14 +53,7 @@ public class DeletePageActions extends RecordingAction {
List<PlaybackAction> actions, int pageNumber) {
RecordedEvents lectureEvents = recording.getRecordedEvents();
List<EditAction> deletions = new ArrayList<>();
for (var action : actions) {
deletions.add(new DeleteEventAction(lectureEvents, action,
pageNumber));
}
return deletions;
return List.of(new DeleteCompositeEventsAction(lectureEvents, actions, pageNumber));
}
@Override

View file

@ -0,0 +1,52 @@
/*
* Copyright (C) 2020 TU Darmstadt, Department of Computer Science,
* Embedded Systems and Applications Group.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.lecturestudio.editor.api.presenter;
import java.io.IOException;
import javax.inject.Inject;
import org.lecturestudio.core.app.ApplicationContext;
import org.lecturestudio.core.presenter.Presenter;
import org.lecturestudio.editor.api.config.DefaultConfiguration;
import org.lecturestudio.editor.api.config.EditorConfiguration;
import org.lecturestudio.editor.api.view.ActionsSettingsView;
public class ActionsSettingsPresenter extends Presenter<ActionsSettingsView> {
@Inject
ActionsSettingsPresenter(ApplicationContext context, ActionsSettingsView view) {
super(context, view);
}
@Override
public void initialize() throws IOException {
EditorConfiguration config = (EditorConfiguration) context.getConfiguration();
view.bindUniteThreshold(config.actionsUniteThresholdProperty());
view.setOnReset(this::reset);
}
private void reset() {
EditorConfiguration config = (EditorConfiguration) context.getConfiguration();
DefaultConfiguration defaultConfig = new DefaultConfiguration();
config.setActionsUniteThreshold(defaultConfig.getActionsUniteThreshold());
}
}

View file

@ -45,6 +45,7 @@ import org.lecturestudio.core.recording.action.ActionType;
import org.lecturestudio.core.recording.action.PlaybackAction;
import org.lecturestudio.core.recording.edit.EditAction;
import org.lecturestudio.core.service.DocumentService;
import org.lecturestudio.editor.api.config.EditorConfiguration;
import org.lecturestudio.editor.api.context.EditorContext;
import org.lecturestudio.editor.api.edit.DeletePageActions;
import org.lecturestudio.editor.api.service.RecordingFileService;
@ -176,6 +177,11 @@ public class PageEventsPresenter extends Presenter<PageEventsView> {
PlaybackAction previousAction = null;
Integer previousEndTs = null;
EditorConfiguration config = (EditorConfiguration) context.getConfiguration();
int uniteThreshold = config.getActionsUniteThreshold();
// Fail-safe if the value is not configured and/or is not present.
uniteThreshold = uniteThreshold == 0 ? Integer.MIN_VALUE : uniteThreshold;
for (var action : recordedPage.getPlaybackActions()) {
ActionType actionType = action.getType();
@ -200,7 +206,7 @@ public class PageEventsPresenter extends Presenter<PageEventsView> {
|| !previousAction.hasHandle()
|| action.getHandle() != previousAction.getHandle()) {
if (nonNull(previousAction) && nonNull(previousEndTs)
&& Math.abs(action.getTimestamp() - previousEndTs) < -1000
&& Math.abs(action.getTimestamp() - previousEndTs) < uniteThreshold
&& action.getClass().equals(previousAction.getClass())) {
// This is a composite action.
PageEvent initEvent = eventList.get(eventList.size() - 1);

View file

@ -0,0 +1,27 @@
/*
* Copyright (C) 2020 TU Darmstadt, Department of Computer Science,
* Embedded Systems and Applications Group.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.lecturestudio.editor.api.view;
import org.lecturestudio.core.beans.IntegerProperty;
public interface ActionsSettingsView extends SettingsBaseView {
void bindUniteThreshold(IntegerProperty property);
}

View file

@ -26,10 +26,10 @@ import javafx.scene.control.TableCell;
import javafx.scene.control.TableColumn;
import javafx.util.Callback;
import org.lecturestudio.core.recording.action.ActionType;
import org.lecturestudio.editor.api.view.model.PageEvent;
import org.lecturestudio.javafx.control.SvgIcon;
public class EventTypeCellFactory implements Callback<TableColumn<Object, ActionType>, TableCell<Object, ActionType>> {
public class EventTypeCellFactory implements Callback<TableColumn<Object, PageEvent>, TableCell<Object, PageEvent>> {
private final ResourceBundle resources;
@ -40,20 +40,20 @@ public class EventTypeCellFactory implements Callback<TableColumn<Object, Action
}
@Override
public TableCell<Object, ActionType> call(TableColumn<Object, ActionType> param) {
public TableCell<Object, PageEvent> call(TableColumn<Object, PageEvent> param) {
return new EventTypeCell();
}
private class EventTypeCell extends TableCell<Object, ActionType> {
private class EventTypeCell extends TableCell<Object, PageEvent> {
@Override
protected void updateItem(ActionType item, boolean empty) {
protected void updateItem(PageEvent item, boolean empty) {
super.updateItem(item, empty);
if (!empty) {
String typeName = item.toString().toLowerCase();
String typeName = item.getActionType().toString().toLowerCase();
String eventName = "page.events." + typeName.replace("_", ".");
String iconName = typeName.replace("_", "-") + "-icon";
@ -61,7 +61,14 @@ public class EventTypeCellFactory implements Callback<TableColumn<Object, Action
SvgIcon icon = new SvgIcon();
icon.getStyleClass().add(iconName);
setText(resources.getString(eventName));
int compositeCount = item.getCompositeActions().size();
if (compositeCount > 1) {
setText(resources.getString(eventName) + String.format(" (%d)", compositeCount));
}
else {
setText(resources.getString(eventName));
}
setGraphic(icon);
}
}

View file

@ -0,0 +1,35 @@
/*
* Copyright (C) 2020 TU Darmstadt, Department of Computer Science,
* Embedded Systems and Applications Group.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.lecturestudio.editor.javafx.factory;
import javafx.beans.property.ReadOnlyObjectWrapper;
import javafx.beans.value.ObservableValue;
import javafx.scene.control.TableColumn;
import javafx.util.Callback;
import org.lecturestudio.editor.api.view.model.PageEvent;
public class EventTypeCellValueFactory implements Callback<TableColumn.CellDataFeatures<PageEvent, PageEvent>, ObservableValue<PageEvent>> {
@Override
public ObservableValue<PageEvent> call(TableColumn.CellDataFeatures<PageEvent, PageEvent> pageEventStringCellDataFeatures) {
return new ReadOnlyObjectWrapper<>(pageEventStringCellDataFeatures.getValue());
}
}

View file

@ -43,55 +43,8 @@ import org.lecturestudio.core.view.ProgressDialogView;
import org.lecturestudio.core.view.ProgressView;
import org.lecturestudio.core.view.TextBoxView;
import org.lecturestudio.core.view.ViewContextFactory;
import org.lecturestudio.editor.api.view.AudioEffectsView;
import org.lecturestudio.editor.api.view.GeneralSettingsView;
import org.lecturestudio.editor.api.view.ImportRecordingView;
import org.lecturestudio.editor.api.view.LoudnessNormalizeView;
import org.lecturestudio.editor.api.view.MainView;
import org.lecturestudio.editor.api.view.MediaControlsView;
import org.lecturestudio.editor.api.view.MediaTrackControlsView;
import org.lecturestudio.editor.api.view.MediaTracksView;
import org.lecturestudio.editor.api.view.MenuView;
import org.lecturestudio.editor.api.view.NoiseReductionProgressView;
import org.lecturestudio.editor.api.view.NoiseReductionSettingsView;
import org.lecturestudio.editor.api.view.PageEventsView;
import org.lecturestudio.editor.api.view.QuitSaveRecordingView;
import org.lecturestudio.editor.api.view.ReplacePageView;
import org.lecturestudio.editor.api.view.SettingsView;
import org.lecturestudio.editor.api.view.SlidesView;
import org.lecturestudio.editor.api.view.SoundSettingsView;
import org.lecturestudio.editor.api.view.SplitRecordingView;
import org.lecturestudio.editor.api.view.StartView;
import org.lecturestudio.editor.api.view.ToolbarView;
import org.lecturestudio.editor.api.view.VideoExportProgressView;
import org.lecturestudio.editor.api.view.VideoExportSettingsView;
import org.lecturestudio.editor.api.view.VideoExportView;
import org.lecturestudio.editor.api.view.VideoSettingsView;
import org.lecturestudio.editor.javafx.view.FxAboutView;
import org.lecturestudio.editor.javafx.view.FxAudioEffectsView;
import org.lecturestudio.editor.javafx.view.FxGeneralSettingsView;
import org.lecturestudio.editor.javafx.view.FxImportRecordingView;
import org.lecturestudio.editor.javafx.view.FxLoudnessNormalizeView;
import org.lecturestudio.editor.javafx.view.FxMainView;
import org.lecturestudio.editor.javafx.view.FxMediaControlsView;
import org.lecturestudio.editor.javafx.view.FxMediaTrackControlsView;
import org.lecturestudio.editor.javafx.view.FxMediaTracksView;
import org.lecturestudio.editor.javafx.view.FxMenuView;
import org.lecturestudio.editor.javafx.view.FxNoiseReductionProgressView;
import org.lecturestudio.editor.javafx.view.FxNoiseReductionSettingsView;
import org.lecturestudio.editor.javafx.view.FxPageEventsView;
import org.lecturestudio.editor.javafx.view.FxQuitSaveRecordingView;
import org.lecturestudio.editor.javafx.view.FxReplacePageView;
import org.lecturestudio.editor.javafx.view.FxSettingsView;
import org.lecturestudio.editor.javafx.view.FxSlidesView;
import org.lecturestudio.editor.javafx.view.FxSoundSettingsView;
import org.lecturestudio.editor.javafx.view.FxSplitRecordingView;
import org.lecturestudio.editor.javafx.view.FxStartView;
import org.lecturestudio.editor.javafx.view.FxToolbarView;
import org.lecturestudio.editor.javafx.view.FxVideoExportProgressView;
import org.lecturestudio.editor.javafx.view.FxVideoExportSettingsView;
import org.lecturestudio.editor.javafx.view.FxVideoExportView;
import org.lecturestudio.editor.javafx.view.FxVideoSettingsView;
import org.lecturestudio.editor.api.view.*;
import org.lecturestudio.editor.javafx.view.*;
import org.lecturestudio.javafx.control.TextBox;
import org.lecturestudio.javafx.guice.FxmlViewLoader;
import org.lecturestudio.javafx.guice.FxmlViewMatcher;
@ -128,6 +81,7 @@ public class ViewModule extends AbstractModule {
bind(NotificationPopupManager.class).to(FxNotificationPopupManager.class);
bind(AboutView.class).to(FxAboutView.class);
bind(ActionsSettingsView.class).to(FxActionsSettingsView.class);
bind(AudioEffectsView.class).to(FxAudioEffectsView.class);
bind(GeneralSettingsView.class).to(FxGeneralSettingsView.class);
bind(ImportRecordingView.class).to(FxImportRecordingView.class);

View file

@ -0,0 +1,71 @@
/*
* Copyright (C) 2020 TU Darmstadt, Department of Computer Science,
* Embedded Systems and Applications Group.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.lecturestudio.editor.javafx.view;
import java.util.ResourceBundle;
import javafx.fxml.FXML;
import javafx.scene.control.Button;
import javafx.scene.control.TextField;
import javafx.scene.layout.GridPane;
import javafx.util.converter.NumberStringConverter;
import org.lecturestudio.core.beans.IntegerProperty;
import org.lecturestudio.core.view.Action;
import org.lecturestudio.editor.api.view.ActionsSettingsView;
import org.lecturestudio.javafx.beans.LectIntegerProperty;
import org.lecturestudio.javafx.util.FxUtils;
import org.lecturestudio.javafx.view.FxmlView;
@FxmlView(name = "actions-settings", presenter = org.lecturestudio.editor.api.presenter.ActionsSettingsPresenter.class)
public class FxActionsSettingsView extends GridPane implements ActionsSettingsView {
@FXML
private ResourceBundle resources;
@FXML
private TextField uniteThresholdField;
@FXML
private Button closeButton;
@FXML
private Button resetButton;
public FxActionsSettingsView() {
super();
}
@Override
public void setOnClose(Action action) {
FxUtils.bindAction(closeButton, action);
}
@Override
public void setOnReset(Action action) {
FxUtils.bindAction(resetButton, action);
}
@Override
public void bindUniteThreshold(IntegerProperty property) {
uniteThresholdField.textProperty().bindBidirectional(new LectIntegerProperty(property),
new NumberStringConverter());
}
}

View file

@ -0,0 +1,7 @@
.actions-settings {
-fx-hgap: 10;
-fx-padding: 2em;
}
.actions-settings > .label {
-fx-padding: 0 0 0.425em 0;
}

View file

@ -0,0 +1,35 @@
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.geometry.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<?import org.lecturestudio.javafx.util.TextIntegerFormatter?>
<fx:root styleClass="actions-settings" type="GridPane" xmlns="http://javafx.com/javafx/10.0.2-internal" xmlns:fx="http://javafx.com/fxml/1">
<columnConstraints>
<ColumnConstraints hgrow="ALWAYS" />
</columnConstraints>
<rowConstraints>
<RowConstraints />
<RowConstraints />
<RowConstraints vgrow="ALWAYS" />
</rowConstraints>
<Label text="%actions.settings.unite.threshold" />
<HBox alignment="CENTER_LEFT" spacing="5.0" GridPane.rowIndex="1" GridPane.hgrow="NEVER">
<TextField fx:id="uniteThresholdField" prefColumnCount="5" maxWidth="-Infinity">
<GridPane.margin>
<Insets />
</GridPane.margin>
<textFormatter>
<TextIntegerFormatter />
</textFormatter>
</TextField>
<Label text="%actions.settings.unite.threshold.ms" />
</HBox>
<HBox alignment="BOTTOM_RIGHT" spacing="5" GridPane.rowIndex="2">
<Button fx:id="resetButton" text="%button.reset" />
<Button fx:id="closeButton" text="%button.close" />
</HBox>
</fx:root>

View file

@ -0,0 +1,2 @@
actions.settings.unite.threshold = Schwellwert in Millisekunden für das Zusammenf\u00fchren von Annotationen
actions.settings.unite.threshold.ms = ms

View file

@ -0,0 +1,2 @@
actions.settings.unite.threshold = Threshold value in milliseconds for merging annotations
actions.settings.unite.threshold.ms = ms

View file

@ -60,6 +60,9 @@
* *
******************************************************************************/
.settings-actions-icon {
-fx-icon-content: "M992 896q13 0 22.5 9.25t9.5 22.75q0 12-8.5 22-15 17.5-34.5 31.25t-41.5 23.25-45.5 14.5-46 5q-49.5 0-91.5-19.25t-76-54.75q-24.5-25.5-54.5-39.75t-66-14.25q-35 0-65.75 14.25t-54.75 39.75l-4.75 4.5-11.5 11.25-14.75 14.75-15.25 15-12.5 12.5-6.25 6.5q-9.5 9.5-22.5 9.5t-22.5-9.5-9.5-22.5 9.5-22.5q27-27 51-52t50-44 57-30.25 72.5-11.25q49.5 0 91.5 19.25t76 54.75q24.5 25.5 54.5 39.75t66 14.25q38 0 66-14.25t54.5-39.75q5.5-5 10.75-7.5t12.75-2.5zm-374.5-751q7 4 11.5 11.5t4.5 16q0 4-1 7.5t-2.5 7l-353.5 707.5q-4.5 9.5-14 14l-86.5 43.5q-16 8-34.5 8h-4.75l-4.75-.5-23.5 47q-4 8-11.75 12.75t-16.75 4.75q-13 0-22.5-9.5t-9.5-22.5q0-6 3.5-15t8.25-18.75 9.75-18.25 7.5-14q-13-20-13-43.5v-82.5q0-8 3.5-14.5l288-576-32.5-16-118.5 237q-4 8-11.75 12.75t-16.75 4.75q-13 0-22.5-9.5t-9.5-22.5q0-6.5 3.5-14.5l119.5-239q8-16 21.5-25.25t31.5-9.25q17.5 0 33.25 8.5t30.75 16l35.5-71q4-8.5 11.75-13t16.75-4.5q6.5 0 11 2 6-12 11.75-23.75t13-21.25 17.75-15.25 26.5-5.75 30.5 7.5l47 23.5q16 8 25.25 21.25t9.25 31.75q0 17-7.75 31.75t-14.75 29.25zm-101-50.5l43.5 21.5 14.5-29-43.5-21.5zm42 92.5l-96-48-334.5 668.5v75q0 5.5 4 9.5t9.5 4q2 0 8.25-2.5t14.5-6.5 17.5-8.75 17.75-9.25 15-8 9.5-5z";
}
.settings-general-icon {
-fx-icon-content: "M32,376h283.35c6.186-14.112,20.281-24,36.65-24s30.465,9.888,36.65,24H480v32h-91.35c-6.186,14.112-20.281,24-36.65,24 s-30.465-9.888-36.65-24H32 M32,240h91.35c6.186-14.112,20.281-24,36.65-24s30.465,9.888,36.65,24H480v32H196.65c-6.186,14.112-20.281,24-36.65,24 s-30.465-9.888-36.65-24H32 M32,104h283.35c6.186-14.112,20.281-24,36.65-24s30.465,9.888,36.65,24H480v32h-91.35c-6.186,14.112-20.281,24-36.65,24 s-30.465-9.888-36.65-24H32";
}

View file

@ -11,6 +11,12 @@
<SvgIcon styleClass="settings-general-icon" />
</graphic>
</Tab>
<Tab id="actions" text="%settings.actions">
<FxActionsSettingsView />
<graphic>
<SvgIcon styleClass="settings-actions-icon" />
</graphic>
</Tab>
<Tab id="video" text="%settings.sound">
<FxSoundSettingsView />
<graphic>

View file

@ -1,3 +1,4 @@
settings.actions = Annotationen
settings.general = Allgemein
settings.sound = Sound
settings.video = Video

View file

@ -1,3 +1,4 @@
settings.actions = Annotations
settings.general = General
settings.sound = Sound
settings.video = Video

View file

@ -27,7 +27,7 @@
<EventTypeCellFactory />
</cellFactory>
<cellValueFactory>
<PropertyValueFactory property="actionType"/>
<EventTypeCellValueFactory />
</cellValueFactory>
</TableColumn>
<TableColumn text="%page.events.time">