Commit db2456e8 authored by Jean-Baptiste Mardelle's avatar Jean-Baptiste Mardelle
Browse files

Text editing: switch to custom text editor, allow inserting selection to timeline

parent 8672cec1
Pipeline #50947 passed with stage
in 10 minutes and 29 seconds
This diff is collapsed.
......@@ -27,8 +27,90 @@
#include <QProcess>
#include <QAction>
#include <QTextEdit>
#include <QMouseEvent>
/**
* @class VideoTextEdit: Video speech text editor
* @brief A dialog for editing markers and guides.
* @author Jean-Baptiste Mardelle
*/
class VideoTextEdit : public QTextEdit
{
Q_OBJECT
public:
explicit VideoTextEdit(QWidget *parent = nullptr);
void lineNumberAreaPaintEvent(QPaintEvent *event);
int lineNumberAreaWidth();
void repaintLines();
void checkHoverBlock(int yPos);
void blockClicked(Qt::KeyboardModifiers modifiers, bool play = false);
QVector<QPoint> getInsertZones(double offset);
QVector< QPair<double, double> > m_zones;
protected:
void mouseMoveEvent(QMouseEvent *e) override;
void mousePressEvent(QMouseEvent *e) override;
//void mouseReleaseEvent(QMouseEvent *e) override;
void keyPressEvent(QKeyEvent *e) override;
void resizeEvent(QResizeEvent *e) override;
private slots:
void updateLineNumberArea(const QRect &rect, int dy);
private:
QWidget *lineNumberArea;
int m_hoveredBlock;
int m_lastClickedBlock;
QVector <int> m_selectedBlocks;
int getFirstVisibleBlockId();
};
class LineNumberArea : public QWidget
{
public:
LineNumberArea(VideoTextEdit *editor) : QWidget(editor), codeEditor(editor)
{
setMouseTracking(true);
}
QSize sizeHint() const override
{
return QSize(codeEditor->lineNumberAreaWidth(), 0);
}
protected:
void paintEvent(QPaintEvent *event) override
{
codeEditor->lineNumberAreaPaintEvent(event);
}
void mouseMoveEvent(QMouseEvent *e) override
{
codeEditor->checkHoverBlock(e->pos().y());
QWidget::mouseMoveEvent(e);
}
void mousePressEvent(QMouseEvent *e) override
{
codeEditor->blockClicked(e->modifiers());
QWidget::mousePressEvent(e);
}
void mouseDoubleClickEvent(QMouseEvent *e) override
{
codeEditor->blockClicked(e->modifiers(), true);
QWidget::mouseDoubleClickEvent(e);
}
void leaveEvent(QEvent *e) override
{
codeEditor->checkHoverBlock(-1);
QWidget::leaveEvent(e);
}
private:
VideoTextEdit *codeEditor;
};
/**
* @class TextBasedEdit: Subtitle edit widget
......@@ -42,7 +124,7 @@ class TextBasedEdit : public QWidget, public Ui::TextBasedEdit_UI
public:
explicit TextBasedEdit(QWidget *parent = nullptr);
void deleteItem();
private slots:
void startRecognition();
......@@ -51,6 +133,11 @@ private slots:
void parseVoskDictionaries();
void slotProcessSpeechStatus(int, QProcess::ExitStatus status);
void updateAvailability();
/** @brief insert currently selected zones to timeline */
void insertToTimeline();
protected:
bool eventFilter(QObject *obj, QEvent *event) override;
private:
std::unique_ptr<QProcess> m_speechJob;
......@@ -61,6 +148,8 @@ private:
int m_lastPosition;
QString m_errorString;
QAction *m_logAction;
VideoTextEdit *m_visualEditor;
QTextDocument m_document;
};
#endif
......@@ -2528,10 +2528,11 @@ void MainWindow::slotShowTimelineTags()
void MainWindow::slotDeleteItem()
{
if ((QApplication::focusWidget() != nullptr) && (QApplication::focusWidget()->parentWidget() != nullptr) &&
QApplication::focusWidget()->parentWidget() == pCore->bin()) {
if (QApplication::focusWidget() != nullptr && pCore->bin()->isAncestorOf(QApplication::focusWidget())) {
pCore->bin()->slotDeleteClip();
} if (QApplication::focusWidget() != nullptr && pCore->textEditWidget()->isAncestorOf(QApplication::focusWidget())) {
qDebug()<<"===============\nDELETE TEXT BASED ITEM";
pCore->textEditWidget()->deleteItem();
} else {
QWidget *widget = QApplication::focusWidget();
while ((widget != nullptr) && widget != this) {
......
......@@ -6,25 +6,64 @@
<rect>
<x>0</x>
<y>0</y>
<width>572</width>
<height>631</height>
<width>457</width>
<height>422</height>
</rect>
</property>
<layout class="QGridLayout" name="gridLayout_2">
<item row="5" column="2">
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
<item row="0" column="0">
<widget class="QFrame" name="text_frame">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="MinimumExpanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>250</width>
<height>20</height>
</size>
<property name="frameShape">
<enum>QFrame::NoFrame</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Raised</enum>
</property>
</widget>
</item>
<item row="4" column="0">
<widget class="QFrame" name="search_frame">
<property name="frameShape">
<enum>QFrame::StyledPanel</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Raised</enum>
</property>
</spacer>
<layout class="QGridLayout" name="gridLayout_3">
<item row="0" column="1">
<widget class="QToolButton" name="search_prev">
<property name="text">
<string>...</string>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QLineEdit" name="search_line">
<property name="placeholderText">
<string>Search</string>
</property>
<property name="clearButtonEnabled">
<bool>true</bool>
</property>
</widget>
</item>
<item row="0" column="2">
<widget class="QToolButton" name="search_next">
<property name="text">
<string>...</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item row="2" column="0" colspan="4">
<item row="2" column="0">
<widget class="QFrame" name="frame_progress">
<property name="frameShape">
<enum>QFrame::NoFrame</enum>
......@@ -65,24 +104,37 @@
</layout>
</widget>
</item>
<item row="5" column="3">
<widget class="QPushButton" name="button_start">
<property name="text">
<string>Start recognition</string>
</property>
</widget>
<item row="5" column="0">
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<widget class="QComboBox" name="language_box"/>
</item>
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>250</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QPushButton" name="button_start">
<property name="text">
<string>Start recognition</string>
</property>
</widget>
</item>
</layout>
</item>
<item row="1" column="0" colspan="4">
<item row="1" column="0">
<widget class="KMessageWidget" name="info_message"/>
</item>
<item row="0" column="0" colspan="4">
<widget class="QListWidget" name="listWidget">
<property name="alternatingRowColors">
<bool>true</bool>
</property>
</widget>
</item>
<item row="3" column="0" colspan="4">
<item row="3" column="0">
<widget class="QFrame" name="edit_frame">
<property name="frameShape">
<enum>QFrame::NoFrame</enum>
......@@ -103,7 +155,14 @@
<property name="bottomMargin">
<number>0</number>
</property>
<item row="0" column="5">
<item row="0" column="8">
<widget class="QToolButton" name="vosk_config">
<property name="text">
<string>...</string>
</property>
</widget>
</item>
<item row="0" column="7">
<spacer name="horizontalSpacer_2">
<property name="orientation">
<enum>Qt::Horizontal</enum>
......@@ -116,17 +175,7 @@
</property>
</spacer>
</item>
<item row="0" column="3">
<widget class="QToolButton" name="button_search">
<property name="text">
<string>...</string>
</property>
<property name="checkable">
<bool>true</bool>
</property>
</widget>
</item>
<item row="0" column="1">
<item row="0" column="2">
<widget class="QToolButton" name="button_up">
<property name="text">
<string>...</string>
......@@ -134,64 +183,38 @@
</widget>
</item>
<item row="0" column="6">
<widget class="QToolButton" name="vosk_config">
<widget class="QCheckBox" name="speech_zone">
<property name="text">
<string>...</string>
<string>Selected zone only</string>
</property>
</widget>
</item>
<item row="0" column="2">
<widget class="QToolButton" name="button_down">
<item row="0" column="5">
<widget class="QToolButton" name="button_search">
<property name="text">
<string>...</string>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QToolButton" name="button_delete">
<property name="text">
<string>...</string>
<property name="checkable">
<bool>true</bool>
</property>
</widget>
</item>
<item row="0" column="4">
<widget class="QCheckBox" name="speech_zone">
<widget class="QToolButton" name="button_down">
<property name="text">
<string>Selected zone only</string>
<string>...</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item row="4" column="0" colspan="4">
<widget class="QFrame" name="search_frame">
<property name="frameShape">
<enum>QFrame::StyledPanel</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Raised</enum>
</property>
<layout class="QGridLayout" name="gridLayout_3">
<item row="0" column="1">
<widget class="QToolButton" name="search_prev">
<widget class="QToolButton" name="button_insert">
<property name="text">
<string>...</string>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QLineEdit" name="search_line">
<property name="placeholderText">
<string>Search</string>
</property>
<property name="clearButtonEnabled">
<bool>true</bool>
</property>
</widget>
</item>
<item row="0" column="2">
<widget class="QToolButton" name="search_next">
<item row="0" column="3">
<widget class="QToolButton" name="button_delete">
<property name="text">
<string>...</string>
</property>
......@@ -200,9 +223,6 @@
</layout>
</widget>
</item>
<item row="5" column="0" colspan="2">
<widget class="QComboBox" name="language_box"/>
</item>
</layout>
</widget>
<customwidgets>
......
  • Selected text inserting into the timeline is working.

    @mardelle "Text Edit" window: Now word searching by the arrow doesn't work anymore. Ones a word is found further search by the arrow doesn't work anymore.

  • These are great improvements. I tested it now and the text recognition works very well. I can't understand perfectly how this is supposed to work when fully implemented though. Could we have a transfer text to subtitles in the future? Adding multiple clips to the timeline (or all) doesn't seem to work at the moment, I only get the first added.

    Could there be a way to sync it to the timeline for subtitles like import subtitles does? We put the playhead on the clip, and the subtitle clips are populated in the subtitle tracks. This of course when the full clip is added to the timeline. This would even allow in the future for it to work like audio, where we can recover audio clips connected to the video clip (restore audio), and only the subtitles in the clip boundaries would be added to the subtitle track.

    Maybe some filter to remove "no speech" clips for this would be useful too.

    This is awesome nevertheless! :-)

Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment