Menu

#1548 calltip can not work on qt

Bug
closed-fixed
4
2019-03-07
2013-11-08
cubetan
No

Calltip can not work on Qt.

CustomSciEdit derived from ScintillaEdit.

// .h file
class CustomSciEdit : public ScintillaEdit
{
Q_OBJECT
public:
CustomSciEdit(QWidget *parent = 0);

private slots:
void charAdded(int ch);
};

//.cpp file
CustomSciEdit::CustomSciEdit(QWidget *parent) : ScintillaEdit(parent)
{
connect(this, SIGNAL(charAdded(int)), SLOT(charAdded(int)));
}

void CustomSciEdit::charAdded(int ch)
{
if (ch == '(') {
callTipSetBack(0xffffff);
callTipSetFore(0);
if (!callTipActive()) {
callTipShow(currentPos(), "abc");
}
}
}

when type '(' in edit window, can only get a blank popup window.

Related

Bugs: #2076

Discussion

  • Neil Hodgson

    Neil Hodgson - 2013-11-08

    Calltips are not implemented on Qt.

     
  • Neil Hodgson

    Neil Hodgson - 2013-12-20
    • status: open --> open-accepted
    • Priority: 5 --> 4
     
  • Alexander Tuzhik

    I tried to implement myself. It's look like working well.
    Check it out:

    class CallTipImpl : public QWidget
    {
    public:
        CallTipImpl(ScintillaQt* sc)
            : QWidget(0, Qt::ToolTip)
        {
            this->sc = sc;
            surface = Surface::Allocate(0);
            surface->Init(this);
        }
    
        ~CallTipImpl()
        {
            delete surface;
        }
    
        virtual void mousePressEvent(QMouseEvent *) override
        {
            sc->TipClick();
            sc->GetCallTip()->CallTipCancel();
        }
    
        void paintEvent(QPaintEvent *event) override
        {
            auto ct = sc->GetCallTip();
            if (ct->inCallTipMode)
            {
                ct->PaintCT(surface);
            }
        }
    
    private:
        ScintillaQt* sc;
        Surface* surface;
    };
    
    CallTip* ScintillaQt::GetCallTip()
    {
        return &ct;
    }
    
    void ScintillaQt::TipClick()
    {
        CallTipClick();
    }
    
    void ScintillaQt::CreateCallTipWindow(PRectangle rc)
    {
        if (!ct.wCallTip.Created())
        {
            CallTipImpl* pCallTip = new CallTipImpl(this);
            ct.wCallTip = pCallTip;
            pCallTip->move(rc.left, rc.top);
            pCallTip->resize(rc.Width(), rc.Height());
        }
    }
    
     

    Last edit: Alexander Tuzhik 2015-09-13
  • Neil Hodgson

    Neil Hodgson - 2015-09-15

    It draws once and then dies. A new surface should be created for each repaint similar to PartialPaint.

     
    • Andrea Ricchi

      Andrea Ricchi - 2019-01-20

      I have modified the Alexander Tuzhik implementation to adapt and work in Qt environment.

      // Patch: Calltip on Qt
      // Author: Andrea Ricchi
      
      class CallTipImpl : public QWidget
      {
      public:
          CallTipImpl(CallTip* ct)
              : QWidget(nullptr, Qt::ToolTip),
                m_ct(ct)
          {
              m_surface = Surface::Allocate(0);
              m_surface->Init(this);
          }
      
          ~CallTipImpl() override
          {
              delete m_surface;
          }
      
          virtual void mousePressEvent(QMouseEvent *) override 
          {
              m_ct->CallTipCancel();
          }
      
          void paintEvent(QPaintEvent *) override
          {
              if (m_ct->inCallTipMode) {
                  m_surface->Init(this);
                  m_ct->PaintCT(m_surface);
              }
          }
      
      private:
          CallTip* m_ct;
          Surface* m_surface;
      };
      
      
      void ScintillaQt::CreateCallTipWindow(PRectangle rc)
      {
      
          if (!ct.wCallTip.Created()) {
              QWidget *pCallTip =  new CallTipImpl(&ct);
              ct.wCallTip = pCallTip;
              pCallTip->move(rc.left, rc.top);
              pCallTip->resize(rc.Width(), rc.Height());
          }
      }
      

      I have tested this patch in different project and os, and works properly.

       

      Last edit: Andrea Ricchi 2019-01-20
      • Neil Hodgson

        Neil Hodgson - 2019-01-20

        That works a lot better!

        However, the border appears wrong on Windows.
        Showing wrong size

         
        • Andrea Ricchi

          Andrea Ricchi - 2019-01-21

          I've reworked the implementation since there was a bug with the mouse click management; here's the code:

          // Patch: Calltip on Qt
          // Author: Andrea Ricchi
          
          class CallTipImpl : public QWidget
          {
          public:
              CallTipImpl(CallTip* ct)
                  : QWidget(nullptr, Qt::ToolTip),
                    m_ct(ct)
              {
                  setWindowFlag(Qt::WindowTransparentForInput);
                  m_surface = Surface::Allocate(0);
                  m_surface->Init(this);
              }
          
              ~CallTipImpl() override
              {
                  delete m_surface;
              }
          
              void paintEvent(QPaintEvent *) override
              {
                  if (m_ct->inCallTipMode) {
                      m_surface->Init(this);
                      m_ct->PaintCT(m_surface);
                  }
              }
          
          private:
              CallTip* m_ct;
              Surface* m_surface;
          };
          

          About the border issue I've seen a strange behavior:

          • with Qt 5.12.1 or Qt 5.12.0 and MinGW 7.3 on Windows the bug is present;
          • with Qt 5.11.2 and MSVC 2017 on Windows the bug is missing;
          • with Qt 5.11.1 and GCC 7.3 on Linux the bug is missing.

          Currently I don't know if the problem is about Qt or the compiler.
          As soon as I can I'll run test with same Qt version and different compilers.

          I only ask you if you know about graphic problem like this related to compilers or Qt version.

           

          Last edit: Andrea Ricchi 2019-01-21
  • Neil Hodgson

    Neil Hodgson - 2019-01-22

    Its safer to create a new Surface for each paint in case the underlying graphics environment changes such as a video mode change or scaling change. This is the technique used for the main area of Scintilla. The surface should also be initialized further to ensure correct behaviour with different encodings.

    The coding style should match other parts of the Qt platform layer which do not use "m_" member prefixes.

    A version with these changes:

    class CallTipImpl : public QWidget
    {
    public:
        CallTipImpl(CallTip *pct_)
        : QWidget(nullptr, Qt::ToolTip),
          pct(pct_)
        {
            setWindowFlag(Qt::WindowTransparentForInput);
        }
    
        ~CallTipImpl() override
        {
        }
    
        virtual void mousePressEvent(QMouseEvent *) override
        {
            pct->CallTipCancel();
        }
    
        void paintEvent(QPaintEvent *) override
        {
            if (pct->inCallTipMode) {
                Surface *surfaceWindow = Surface::Allocate(0);
                surfaceWindow->Init(this);
                surfaceWindow->SetUnicodeMode(SC_CP_UTF8 == pct->codePage);
                surfaceWindow->SetDBCSMode(pct->codePage);
                pct->PaintCT(surfaceWindow);
                delete surfaceWindow;
            }
        }
    
    private:
        CallTip *pct;
    };
    

    The visual problem is more likely to be a change from Qt 5.11 to 5.12 than a compiler issue.

    It looks good on macOS.
    Calltip on macOS

     
    • Andrea Ricchi

      Andrea Ricchi - 2019-01-23

      So I have some new info.

      First of all, I updated your code, since the QWidget is transparent for input, the mousePressEvent is useless; and since we are now allocating a new surface, the constructor override is useless too; so I've cleaned a bit the implementation for some tests.

      class CallTipImpl : public QWidget
      {
      public:
          CallTipImpl(CallTip *pct_)
          : QWidget(nullptr, Qt::ToolTip),
            pct(pct_)
          {
              setWindowFlag(Qt::WindowTransparentForInput);
          }
      
          void paintEvent(QPaintEvent *) override
          {
              if (pct->inCallTipMode) {
                  Surface *surfaceWindow = Surface::Allocate(0);
                  surfaceWindow->Init(this);
                  surfaceWindow->SetUnicodeMode(SC_CP_UTF8 == pct->codePage);
                  surfaceWindow->SetDBCSMode(pct->codePage);
                  pct->PaintCT(surfaceWindow);
                  delete surfaceWindow;
              }
          }
      
      private:
          CallTip *pct;
      };
      

      About the border issue. I've tested on Linux and Windows with Qt 5.12.0 and Qt 5.11.3:

      • On Linux both 5.12.0 and 5.11.3 with GCC/G++ 7.3.0 works correctly.
      • On Windows with MSVC2017 Qt 5.11.3 works and Qt 5.12.0 doesn't.
        So I've done some research hoping to find some big difference, but I've found nothing. Until the end of the ScintillaBase::CallTipShow the size and position values are the same. After that, I jumped to the CallTipImpl::paintEvent wherein the CallTip::PaintCT I found that the positions acquired from wCallTip.GetClientPosition() are now different. Take a look at the attachments.

      At the moment I don't really have any ideas about the problem if you can doublecheck maybe you will be able to find out something.
      As soon as I can I'll try to do some more tests.

       

      Last edit: Andrea Ricchi 2019-01-23
  • Neil Hodgson

    Neil Hodgson - 2019-01-24
    • labels: Qt ScintillaEdit, calltip --> Qt ScintillaEdit, calltip, scintilla, qt
    • status: open-accepted --> open-fixed
     
  • Neil Hodgson

    Neil Hodgson - 2019-01-24

    Since this change improves behaviour on all operating systems it has been committed with minor whitespace reformatting as [a82b87].

    A separate bug [#2076] was added for the problem with Qt 5.12 on Win32.

     

    Related

    Bugs: #2076
    Commit: [a82b87]

  • Neil Hodgson

    Neil Hodgson - 2019-01-29

    setWindowFlag is only available from Qt 5.9 so added an #if with [ba336a] to avoid this call when building against earlier versions of Qt.

     

    Related

    Commit: [ba336a]

  • Neil Hodgson

    Neil Hodgson - 2019-03-07
    • status: open-fixed --> closed-fixed
     

Log in to post a comment.

MongoDB Logo MongoDB