// The implementation of the TQt specific subclass of ScintillaBase. // // Copyright (c) 2006 // Riverbank Computing Limited // // This file is part of TQScintilla. // // This copy of TQScintilla 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 2, or (at your option) any // later version. // // TQScintilla is supplied 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 // TQScintilla; see the file LICENSE. If not, write to the Free Software // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include #include #include #include #include #include #include #include #include "qextscintillabase.h" #include "ScintillaQt.h" // We want to use the Scintilla notification names as TQt signal names. #undef SCEN_CHANGE #undef SCN_AUTOCSELECTION #undef SCN_CALLTIPCLICK #undef SCN_CHARADDED #undef SCN_DOUBLECLICK #undef SCN_DWELLEND #undef SCN_DWELLSTART #undef SCN_HOTSPOTCLICK #undef SCN_HOTSPOTDOUBLECLICK #undef SCN_MACRORECORD #undef SCN_MARGINCLICK #undef SCN_MODIFIED #undef SCN_MODIFYATTEMPTRO #undef SCN_NEEDSHOWN #undef SCN_PAINTED #undef SCN_SAVEPOINTLEFT #undef SCN_SAVEPOINTREACHED #undef SCN_STYLENEEDED #undef SCN_UPDATEUI #undef SCN_USERLISTSELECTION #undef SCN_ZOOM enum { SCEN_CHANGE = 768, SCN_AUTOCSELECTION = 2022, SCN_CALLTIPCLICK = 2021, SCN_CHARADDED = 2001, SCN_DOUBLECLICK = 2006, SCN_DWELLEND = 2017, SCN_DWELLSTART = 2016, SCN_HOTSPOTCLICK = 2019, SCN_HOTSPOTDOUBLECLICK = 2020, SCN_MACRORECORD = 2009, SCN_MARGINCLICK = 2010, SCN_MODIFIED = 2008, SCN_MODIFYATTEMPTRO = 2004, SCN_NEEDSHOWN = 2011, SCN_PAINTED = 2013, SCN_SAVEPOINTLEFT = 2003, SCN_SAVEPOINTREACHED = 2002, SCN_STYLENEEDED = 2000, SCN_UPDATEUI = 2007, SCN_USERLISTSELECTION = 2014, SCN_ZOOM = 2018 }; // The ctor. ScintillaTQt::ScintillaTQt(QextScintillaBase *qsb_) : capturedMouse(false), qsb(qsb_) { wMain = qsb -> txtarea; // We aren't a TQObject so we use the API class to do TQObject related // things for us. qsb -> connect(&qtimer,TQT_SIGNAL(timeout()),TQT_SLOT(handleTimer())); Initialise(); } // The dtor. ScintillaTQt::~ScintillaTQt() { Finalise(); } // Initialise the instance. void ScintillaTQt::Initialise() { SetTicking(true); } // Tidy up the instance. void ScintillaTQt::Finalise() { SetTicking(false); ScintillaBase::Finalise(); } // Start a drag. void ScintillaTQt::StartDrag() { // Allow applications to re-implement the drag start. qsb -> startDrag(); } // Do the real drag start. void ScintillaTQt::StartDragImpl() { TQDragObject *dobj = new TQTextDrag(textRange(&drag),qsb -> txtarea); // Remove the dragged text if it was a move to another widget or // application. if (dobj -> drag() && dobj -> target() != qsb -> txtarea) ClearSelection(); inDragDrop = false; SetDragPosition(invalidPosition); } // Handle a drag enter event. void ScintillaTQt::dragEnterEvent(TQDragEnterEvent *dee) { dragMoveEvent(dee); } // Handle a drag move event. void ScintillaTQt::dragMoveEvent(TQDragMoveEvent *dme) { dme -> acceptAction(TQTextDrag::canDecode(dme)); SetDragPosition(PositionFromLocation(Point(dme -> pos().x(),dme -> pos().y()))); } // Handle a drag leave event. void ScintillaTQt::dragLeaveEvent(TQDragLeaveEvent *dle) { SetDragPosition(invalidPosition); } // Handle a drop event. void ScintillaTQt::dropEvent(TQDropEvent *de) { TQString text; if (TQTextDrag::decode(de,text)) { bool moving = (de -> source() == qsb -> txtarea && de -> action() == TQDropEvent::Move); de -> acceptAction(); const char *s; TQCString us; if (IsUnicodeMode()) { us = text.utf8(); s = us.data(); } else s = text.latin1(); DropAt(posDrop,s,moving,false); SetDragPosition(invalidPosition); Redraw(); } } // Re-implement to trap certain messages. sptr_t ScintillaTQt::WndProc(unsigned int iMessage,uptr_t wParam,sptr_t lParam) { switch (iMessage) { case SCI_GRABFOCUS: PWindow(wMain) -> setFocus(); return 0; case SCI_GETDIRECTFUNCTION: return reinterpret_cast(DirectFunction); case SCI_GETDIRECTPOINTER: return reinterpret_cast(this); } return ScintillaBase::WndProc(iMessage,wParam,lParam); } // Windows nonsense. sptr_t ScintillaTQt::DefWndProc(unsigned int,uptr_t,sptr_t) { return 0; } // Manage the timer. void ScintillaTQt::SetTicking(bool on) { if (timer.ticking != on) { timer.ticking = on; if (timer.ticking) qtimer.start(timer.tickSize); else qtimer.stop(); } timer.ticksToWait = caret.period; } // Grab or release the mouse (and keyboard). void ScintillaTQt::SetMouseCapture(bool on) { if (mouseDownCaptures) if (on) PWindow(wMain) -> grabMouse(); else PWindow(wMain) -> releaseMouse(); capturedMouse = on; } // Return true if the mouse/keyboard are currently grabbed. bool ScintillaTQt::HaveMouseCapture() { return capturedMouse; } // Set the position of the vertical scrollbar. void ScintillaTQt::SetVerticalScrollPos() { qsb -> vsb -> setValue(topLine); } // Set the position of the horizontal scrollbar. void ScintillaTQt::SetHorizontalScrollPos() { qsb -> hsb -> setValue(xOffset); } // Set the extent of the vertical and horizontal scrollbars and return true if // the view needs re-drawing. bool ScintillaTQt::ModifyScrollBars(int nMax,int nPage) { qsb -> vsb -> setMinValue(0); qsb -> vsb -> setMaxValue(nMax - nPage + 1); qsb -> vsb -> setLineStep(1); qsb -> vsb -> setPageStep(nPage); qsb -> hsb -> setMinValue(0); qsb -> hsb -> setMaxValue(scrollWidth); qsb -> hsb -> setPageStep(scrollWidth / 10); return true; } // Called after SCI_SETWRAPMODE and SCI_SETHSCROLLBAR. void ScintillaTQt::ReconfigureScrollBars() { // Hide or show the scrollbars if needed. if (horizontalScrollBarVisible && wrapState == eWrapNone) qsb->hsb->show(); else qsb->hsb->hide(); if (verticalScrollBarVisible) qsb->vsb->show(); else qsb->vsb->hide(); } // Notify interested parties of any change in the document. void ScintillaTQt::NotifyChange() { emit qsb -> SCEN_CHANGE(); } // Notify interested parties of various events. This is the main mapping // between Scintilla notifications and TQt signals. void ScintillaTQt::NotifyParent(SCNotification scn) { switch (scn.nmhdr.code) { case SCN_CALLTIPCLICK: emit qsb -> SCN_CALLTIPCLICK(scn.position); break; case SCN_AUTOCSELECTION: emit qsb -> SCN_AUTOCSELECTION(scn.text,scn.lParam); break; case SCN_CHARADDED: emit qsb -> SCN_CHARADDED(scn.ch); break; case SCN_DOUBLECLICK: emit qsb -> SCN_DOUBLECLICK(); break; case SCN_DWELLEND: emit qsb -> SCN_DWELLEND(scn.position,scn.x,scn.y); break; case SCN_DWELLSTART: emit qsb -> SCN_DWELLSTART(scn.position,scn.x,scn.y); break; case SCN_HOTSPOTCLICK: emit qsb -> SCN_HOTSPOTCLICK(scn.position,scn.modifiers); break; case SCN_HOTSPOTDOUBLECLICK: emit qsb -> SCN_HOTSPOTDOUBLECLICK(scn.position,scn.modifiers); break; case SCN_MACRORECORD: emit qsb -> SCN_MACRORECORD(scn.message,scn.wParam,scn.lParam); break; case SCN_MARGINCLICK: emit qsb -> SCN_MARGINCLICK(scn.position,scn.modifiers, scn.margin); break; case SCN_MODIFIED: emit qsb -> SCN_MODIFIED(scn.position,scn.modificationType, scn.text,scn.length,scn.linesAdded, scn.line,scn.foldLevelNow, scn.foldLevelPrev); break; case SCN_MODIFYATTEMPTRO: emit qsb -> SCN_MODIFYATTEMPTRO(); break; case SCN_NEEDSHOWN: emit qsb -> SCN_NEEDSHOWN(scn.position,scn.length); break; case SCN_PAINTED: emit qsb -> SCN_PAINTED(); break; case SCN_SAVEPOINTLEFT: emit qsb -> SCN_SAVEPOINTLEFT(); break; case SCN_SAVEPOINTREACHED: emit qsb -> SCN_SAVEPOINTREACHED(); break; case SCN_STYLENEEDED: emit qsb -> SCN_STYLENEEDED(scn.position); break; case SCN_UPDATEUI: emit qsb -> SCN_UPDATEUI(); break; case SCN_USERLISTSELECTION: emit qsb -> SCN_USERLISTSELECTION(scn.text,scn.wParam); break; case SCN_ZOOM: emit qsb -> SCN_ZOOM(); break; default: tqWarning("Unknown notification: %u",scn.nmhdr.code); } } // Handle a key that hasn't been filtered out as a command key. Return 0 if we // haven't handled it. int ScintillaTQt::KeyDefault(int key,int modifiers) { // On Windows Alt Gr is returned as Ctrl-Alt (on X11 it seems to be the // Meta key). We therefore ignore that combination. #if defined(Q_OS_WIN) modifiers &= (SCI_CTRL | SCI_ALT); if (modifiers == SCI_CTRL || modifiers == SCI_ALT) return 0; #else if (modifiers & (SCI_CTRL | SCI_ALT)) return 0; #endif AddChar(key); return 1; } // Convert a text range to a TQString. TQString ScintillaTQt::textRange(const SelectionText *text) { TQString qs; if (text -> s) if (IsUnicodeMode()) qs = TQString::fromUtf8(text -> s); else qs.setLatin1(text -> s); return qs; } // Copy the selected text to the clipboard. void ScintillaTQt::CopyToClipboard(const SelectionText &selectedText) { TQApplication::clipboard() -> setText(textRange(&selectedText)); } // Implement copy. void ScintillaTQt::Copy() { if (currentPos != anchor) { SelectionText text; CopySelectionRange(&text); CopyToClipboard(text); } } // Implement paste. void ScintillaTQt::Paste() { TQString str = TQApplication::clipboard() -> text(); if (str.isEmpty()) return; pdoc -> BeginUndoAction(); ClearSelection(); int len; if (IsUnicodeMode()) { TQCString s = str.utf8(); len = s.length(); if (len) pdoc -> InsertString(currentPos,s.data(),len); } else { const char *s = str.latin1(); len = (s ? strlen(s) : 0); if (len) pdoc -> InsertString(currentPos,s,len); } SetEmptySelection(currentPos + len); pdoc -> EndUndoAction(); NotifyChange(); Redraw(); } // A simple TQWidget sub-class to implement a call tip. No need to bother with // all the tqmoc stuff. class TQtCallTip : public TQWidget { public: TQtCallTip(TQWidget *parent,ScintillaTQt *sci_); ~TQtCallTip(); protected: void paintEvent(TQPaintEvent *); void mousePressEvent(TQMouseEvent *me); private: ScintillaTQt *sci; }; // Create a call tip. TQtCallTip::TQtCallTip(TQWidget *parent,ScintillaTQt *sci_) : TQWidget(parent,0,WType_Popup|WStyle_Customize|WStyle_NoBorder), sci(sci_) { // Ensure that the main window keeps the focus (and the caret flashing) // when this is displayed. setFocusProxy(parent); } // Destroy a call tip. TQtCallTip::~TQtCallTip() { // Ensure that the main window doesn't receive a focus out event when // this is destroyed. setFocusProxy(0); } // Paint a call tip. void TQtCallTip::paintEvent(TQPaintEvent *) { Surface *surfaceWindow = Surface::Allocate(); if (surfaceWindow) { TQPainter p(this); surfaceWindow -> Init(&p,0); sci -> ct.PaintCT(surfaceWindow); surfaceWindow -> Release(); delete surfaceWindow; } } // Handle a mouse press in a call tip. void TQtCallTip::mousePressEvent(TQMouseEvent *me) { Point pt; pt.x = me -> x(); pt.y = me -> y(); sci -> ct.MouseClick(pt); sci -> CallTipClick(); } // Create a call tip window. void ScintillaTQt::CreateCallTipWindow(PRectangle rc) { if (!ct.wCallTip.Created()) ct.wCallTip = ct.wDraw = new TQtCallTip(qsb,this); PWindow(ct.wCallTip) -> resize(rc.right - rc.left,rc.bottom - rc.top); ct.wCallTip.Show(); } // Add an item to the right button menu. void ScintillaTQt::AddToPopUp(const char *label,int cmd,bool enabled) { TQPopupMenu *pm = static_cast(popup.GetID()); if (label[0] != '\0') { TQString tr_label = tqApp -> translate("ContextMenu",label); pm -> insertItem(tr_label,qsb,TQT_SLOT(handlePopUp(int)),0,cmd); pm -> setItemEnabled(cmd,enabled); } else pm -> insertSeparator(); } // Claim the selection. void ScintillaTQt::ClaimSelection() { bool isSel = (currentPos != anchor); if (isSel) { TQClipboard *cb = TQApplication::clipboard(); // If we support X11 style selection then make it available // now. if (cb -> supportsSelection()) { SelectionText text; CopySelectionRange(&text); if (text.s) { cb -> setSelectionMode(TRUE); cb -> setText(text.s); cb -> setSelectionMode(FALSE); } } primarySelection = true; } else primarySelection = false; emit qsb -> TQSCN_SELCHANGED(isSel); } // Unclaim the selection. void ScintillaTQt::UnclaimSelection() { if (primarySelection) { primarySelection = false; qsb -> txtarea -> update(); } } // Implemented to provide compatibility with the Windows version. sptr_t ScintillaTQt::DirectFunction(ScintillaTQt *sciThis,unsigned int iMessage, uptr_t wParam,sptr_t lParam) { return sciThis -> WndProc(iMessage,wParam,lParam); } // Draw the contents of the widget. void ScintillaTQt::paintEvent(TQPaintEvent *pe) { bool isUnicodeMode = (pdoc && pdoc -> dbcsCodePage == SC_CP_UTF8); paintState = painting; const TQRect &qr = pe -> rect(); rcPaint.left = qr.left(); rcPaint.top = qr.top(); rcPaint.right = qr.right() + 1; rcPaint.bottom = qr.bottom() + 1; PRectangle rcText = GetTextRectangle(); paintingAllText = rcPaint.Contains(rcText); Surface *sw = Surface::Allocate(); if (sw) { TQPainter painter(PWindow(wMain)); sw -> Init(&painter,0); sw -> SetUnicodeMode(isUnicodeMode); Paint(sw,rcPaint); sw -> Release(); delete sw; // If the painting area was insufficient to cover the new style // or brace highlight positions then repaint the whole thing. if (paintState == paintAbandoned) PWindow(wMain) -> update(); } paintState = notPainting; }