changeset 31072:5261a81765b0

merge input and output of exp. terminal widget into one widget * command-widget.cc (command_widget): remove obsolete elements, use new class console as terminal, update initializations; (init_command_prompt): display the first prompt, this function is called when the interpreter is ready (via main_window); (update_prompt): prompt is a QString now; (insert_interpreter_output): use m_console instead of m_output_display; (accept_input_line): moved to console; (process_input_line): string of input line is passed as argument, a new prompt is provided when interpreter is ready (notice_settings): update for m_console, remove color and configuration of obsolete line edit (console::console): initializations, create and set QTextDocument; (console::new_command_line): Prepare a new command line with prompt; (console::accept_command_line): get input string and pass it to m_command_widget for processing; (console::append_block): append a text block to the document; (console::keyPressEvent): re-implement key event for filtering return, on which accept_input_line is called * command-widget.h: new class console, update some function arguments * main-window.cc (handle_octave_ready) call init_command_prompt of terminal_dock_widget * terminal-dock-widget.cc (init_command_prompt): new function calling related function of the command widget * terminal-dock-widget.h: new function init_command_prompt
author Torsten Lilge <ttl-octave@mailbox.org>
date Sat, 04 Jun 2022 21:52:20 +0200
parents 74d97efb7573
children 0b402f523f09
files libgui/src/command-widget.cc libgui/src/command-widget.h libgui/src/main-window.cc libgui/src/terminal-dock-widget.cc libgui/src/terminal-dock-widget.h
diffstat 5 files changed, 162 insertions(+), 56 deletions(-) [+]
line wrap: on
line diff
--- a/libgui/src/command-widget.cc	Sat Jun 04 00:12:55 2022 +0200
+++ b/libgui/src/command-widget.cc	Sat Jun 04 21:52:20 2022 +0200
@@ -32,7 +32,8 @@
 #include <QLabel>
 #include <QLineEdit>
 #include <QPushButton>
-#include <QTextBrowser>
+#include <QTextEdit>
+#include <QTextBlock>
 #include <QVBoxLayout>
 
 #include "command-widget.h"
@@ -49,42 +50,27 @@
 {
   command_widget::command_widget (base_qobject&, QWidget *p)
     : QWidget (p), m_incomplete_parse (false),
-      m_prompt (new QLabel ("", this)),
-      m_line_edit (new QLineEdit (this)),
-      m_output_display (new QTextBrowser (this)),
-      m_input_color (QColor ())
+      m_prompt (QString ()),
+      m_console (new console (this))
   {
     QPushButton *pause_button = new QPushButton (tr("Pause"), this);
     QPushButton *stop_button = new QPushButton (tr("Stop"), this);
     QPushButton *resume_button = new QPushButton (tr("Continue"), this);
 
-    QGroupBox *input_group_box = new QGroupBox (tr("Command Input"));
+    QGroupBox *input_group_box = new QGroupBox ();
     QHBoxLayout *input_layout = new QHBoxLayout;
-    input_layout->addWidget (m_prompt);
-    input_layout->addWidget (m_line_edit);
     input_layout->addWidget (pause_button);
     input_layout->addWidget (stop_button);
     input_layout->addWidget (resume_button);
     input_group_box->setLayout (input_layout);
 
-    QGroupBox *output_group_box = new QGroupBox (tr("Command Output"));
-    QHBoxLayout *output_layout = new QHBoxLayout ();
-    output_layout->addWidget (m_output_display);
-    output_group_box->setLayout (output_layout);
-
     QVBoxLayout *main_layout = new QVBoxLayout ();
-    main_layout->addWidget (output_group_box);
+    main_layout->addWidget (m_console);
     main_layout->addWidget (input_group_box);
 
     setLayout (main_layout);
 
-    setFocusProxy (m_line_edit);
-
-    connect (m_line_edit, &QLineEdit::returnPressed,
-             this, &command_widget::accept_input_line);
-
-    connect (this, &command_widget::clear_line_edit,
-             m_line_edit, &QLineEdit::clear);
+    setFocusProxy (m_console);
 
     connect (pause_button, &QPushButton::clicked,
              this, &command_widget::interpreter_pause);
@@ -94,39 +80,51 @@
 
     connect (stop_button, &QPushButton::clicked,
              this, &command_widget::interpreter_stop);
+
+    connect (this, &command_widget::new_command_line_signal,
+             m_console, &console::new_command_line);
+
+    insert_interpreter_output ("\n\n    Welcome to Octave\n\n");
+
+  }
+
+  void command_widget::init_command_prompt ()
+  {
+    emit interpreter_event
+      ([=] (interpreter& interp)
+       {
+         // INTERPRETER THREAD
+
+         event_manager& evmgr = interp.get_event_manager ();
+         input_system& input_sys = interp.get_input_system ();
+         std::string prompt = input_sys.PS1 ();
+         evmgr.update_prompt (command_editor::decode_prompt_string (prompt));
+
+         emit new_command_line_signal ();
+       });
   }
 
   void command_widget::update_prompt (const QString& prompt)
   {
-    m_prompt->setText (prompt);
+    m_prompt = prompt;
+  }
+
+  QString command_widget::prompt ()
+  {
+    return m_prompt;
   }
 
   void command_widget::insert_interpreter_output (const QString& msg)
   {
-    QTextCursor cursor = m_output_display->textCursor ();
+    QTextCursor cursor = m_console->textCursor ();
 
     cursor.insertText (msg);
 
-    m_output_display->setTextCursor (cursor);
+    m_console->setTextCursor (cursor);
   }
 
-  void command_widget::accept_input_line (void)
+  void command_widget::process_input_line (const QString& input_line)
   {
-    QTextCursor cursor = m_output_display->textCursor ();
-
-    QString input_line = m_line_edit->text ();
-
-    QString style;
-    if (! m_incomplete_parse)
-      {
-        style = QString ("<div style=\"color:%1; font-weight:bold;\">[in]:</div> ")
-                .arg (m_input_color.name ());
-        m_output_display->insertHtml (style);
-      }
-    style = QString ("<div style=\"color:%1\">%2</div><br>")
-            .arg (m_input_color.name ()).arg (input_line);
-    m_output_display->insertHtml (style);
-
     emit interpreter_event
       ([=] (interpreter& interp)
        {
@@ -142,9 +140,10 @@
            = m_incomplete_parse ? input_sys.PS2 () : input_sys.PS1 ();
 
          evmgr.update_prompt (command_editor::decode_prompt_string (prompt));
+
+         emit new_command_line_signal ();
        });
 
-    emit clear_line_edit ();
   }
 
   void command_widget::notice_settings (const gui_settings *settings)
@@ -158,20 +157,83 @@
     term_font.setPointSize
       (settings->value (cs_font_size).toInt ());
 
-    m_line_edit->setFont (term_font);
-    m_output_display->setFont (term_font);
+    m_console->setFont (term_font);
 
     // Colors
     int mode = settings->value (cs_color_mode).toInt ();
     QColor fgc = settings->color_value (cs_colors[0], mode);
     QColor bgc = settings->color_value (cs_colors[1], mode);
 
-    m_output_display->setStyleSheet (QString ("color: %1; background-color:%2;")
+    m_console->setStyleSheet (QString ("color: %1; background-color:%2;")
                                      .arg (fgc.name ()).arg (bgc.name ()));
-    m_line_edit->setStyleSheet (QString ("color: %1; background-color:%2;")
-                                .arg (fgc.name ()).arg (bgc.name ()));
+  }
+
+
+  // The console itself using QTextEdit with QTextBlock and QTextCursor.
+  // This implementation is based on the basic concept of "qpconsole" as
+  // proposed by user "DerManu" in the Qt-forum thread
+  // https://forum.qt.io/topic/28765/command-terminal-using-qtextedit
+
+  console::console (command_widget *p)
+    : QTextEdit (p),
+      m_command_block_number (-1),
+      m_command_widget (p),
+      m_document (new QTextDocument (this))
+  {
+    setDocument (m_document);
+  }
+
+  // Prepare a new command line with the current prompt
+  void console::new_command_line ()
+  {
+    QTextCursor cursor (m_document->lastBlock ());
+
+    if (! m_document->lastBlock ().text ().isEmpty ())
+      {
+        cursor.movePosition (QTextCursor::EndOfBlock);
+        cursor.insertBlock ();
+      }
+
+    cursor.insertText (m_command_widget->prompt ());
+    setTextCursor (cursor);
+  }
 
-    m_input_color = interpolate_color (fgc, bgc, 0.75, 0.5);
+  // Accept the current command line (or block)
+  void console::accept_command_line ()
+  {
+    QString input_line = m_document->lastBlock().text();
+
+    if (input_line.startsWith (m_command_widget->prompt ()))
+      input_line.remove(0, m_command_widget->prompt ().length ());
+
+    input_line = input_line.trimmed ();
+  
+    append_block ();
+
+    if (input_line.isEmpty ())
+      new_command_line ();
+    else
+      m_command_widget->process_input_line (input_line);
+  }
+
+  // Append a block to the document
+  void console::append_block ()
+  {
+    QTextCursor cursor (m_document->lastBlock ());
+    cursor.movePosition (QTextCursor::EndOfBlock);
+    cursor.insertBlock ();
+    setTextCursor (cursor);
+  }
+
+  // Re-implement key event
+  void console::keyPressEvent (QKeyEvent *e)
+  {
+    if (e->key () == Qt::Key_Return)
+      // On "return", accept the current command line
+      accept_command_line ();
+    else
+      // Otherwise, process the expected event
+      QTextEdit::keyPressEvent(e);                          
   }
 
 }
--- a/libgui/src/command-widget.h	Sat Jun 04 00:12:55 2022 +0200
+++ b/libgui/src/command-widget.h	Sat Jun 04 21:52:20 2022 +0200
@@ -27,6 +27,7 @@
 #define octave_command_widget_h 1
 
 #include <QWidget>
+#include <QTextEdit>
 
 #include "octave-qobject.h"
 #include "gui-settings.h"
@@ -34,11 +35,40 @@
 class QLabel;
 class QLineEdit;
 class QStrung;
-class QTextBrowser;
+class QTextEdit;
 
 namespace octave
 {
   class base_qobject;
+  class command_widget;
+
+  class console : public QTextEdit
+  {
+    Q_OBJECT
+
+  public:
+
+    console (command_widget *p);
+
+  public slots:
+
+    void new_command_line (void);
+
+  protected:
+
+    void keyPressEvent (QKeyEvent *e);
+
+  private:
+
+    void accept_command_line (void);
+
+    void append_block (void);
+
+    int m_command_block_number;
+    command_widget *m_command_widget;
+    QTextDocument *m_document;
+
+  };
 
   class command_widget : public QWidget
   {
@@ -48,6 +78,10 @@
 
     command_widget (base_qobject& oct_qobj, QWidget *p);
 
+    void init_command_prompt ();
+
+    QString prompt (void);
+
   signals:
 
     void clear_line_edit (void);
@@ -59,25 +93,23 @@
     void interpreter_event (const fcn_callback& fcn);
     void interpreter_event (const meth_callback& meth);
 
+    void new_command_line_signal (void);
+
   public slots:
 
+    void process_input_line (const QString& input_line);
+
     void update_prompt (const QString& prompt);
 
     void insert_interpreter_output (const QString& msg);
 
     void notice_settings (const gui_settings *settings);
 
-  protected slots:
-
-    void accept_input_line (void);
-
   private:
 
     bool m_incomplete_parse;
-    QLabel *m_prompt;
-    QLineEdit *m_line_edit;
-    QTextBrowser *m_output_display;
-    QColor m_input_color;
+    QString m_prompt;
+    console *m_console;
   };
 }
 
--- a/libgui/src/main-window.cc	Sat Jun 04 00:12:55 2022 +0200
+++ b/libgui/src/main-window.cc	Sat Jun 04 21:52:20 2022 +0200
@@ -1806,6 +1806,7 @@
           });
       }
 
+    m_command_window->init_command_prompt ();
     focus_command_window ();  // make sure that the command window has focus
   }
 
--- a/libgui/src/terminal-dock-widget.cc	Sat Jun 04 00:12:55 2022 +0200
+++ b/libgui/src/terminal-dock-widget.cc	Sat Jun 04 21:52:20 2022 +0200
@@ -155,4 +155,13 @@
       emit update_prompt_signal (prompt);
   }
 
+  void terminal_dock_widget::init_command_prompt ()
+  {
+    if (m_experimental_terminal_widget)
+      {
+        command_widget *cmd = get_command_widget ();
+        if (cmd)
+          cmd->init_command_prompt ();
+      }
+  }
 }
--- a/libgui/src/terminal-dock-widget.h	Sat Jun 04 00:12:55 2022 +0200
+++ b/libgui/src/terminal-dock-widget.h	Sat Jun 04 21:52:20 2022 +0200
@@ -49,6 +49,8 @@
 
     bool has_focus (void) const;
 
+    void init_command_prompt ();
+
     // FIXME: The next two functions could be eliminated (or combined)
     // if we had a common interface for the old and new terminal
     // widgets.