// This module implements the "official" low-level API. // // 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. #ifdef HAVE_CONFIG_H # include "config.h" #endif #include "tqextscintillabase.moc" #include #include #include #include #include #include #include #include #include #include "tqextscintillabase.h" #include "ScintillaTQt.h" // The #defines in Scintilla.h and the enums in tqextscintillabase.h conflict // (because we want to use the same names) so we have to undefine those we use // in this file. #undef SCI_SETCARETPERIOD #undef SCK_DOWN #undef SCK_UP #undef SCK_LEFT #undef SCK_RIGHT #undef SCK_HOME #undef SCK_END #undef SCK_PRIOR #undef SCK_NEXT #undef SCK_DELETE #undef SCK_INSERT #undef SCK_ESCAPE #undef SCK_BACK #undef SCK_TAB #undef SCK_RETURN #undef SCK_ADD #undef SCK_SUBTRACT #undef SCK_DIVIDE // Remember if we have linked the lexers. static bool lexersLinked = FALSE; // The list of instances. static TQPtrList poolList; // The ctor. TQextScintillaBase::TQextScintillaBase(TQWidget *parent,const char *name,WFlags f) : TQWidget(parent,name,f) { sci = 0; TQGridLayout *layout = new TQGridLayout(this,2,2); txtarea = new TQWidget(this,0,WRepaintNoErase|WResizeNoErase); txtarea -> setSizePolicy(TQSizePolicy(TQSizePolicy::Expanding,TQSizePolicy::Expanding)); txtarea -> setMouseTracking(TRUE); txtarea -> setAcceptDrops(TRUE); txtarea -> setFocusPolicy(WheelFocus); txtarea -> setFocusProxy(this); layout -> addWidget(txtarea,0,0); vsb = new TQScrollBar(TQt::Vertical,this); layout -> addWidget(vsb,0,1); connect(vsb,TQ_SIGNAL(valueChanged(int)),TQ_SLOT(handleVSb(int))); hsb = new TQScrollBar(TQt::Horizontal,this); layout -> addWidget(hsb,1,0); connect(hsb,TQ_SIGNAL(valueChanged(int)),TQ_SLOT(handleHSb(int))); txtarea -> installEventFilter(this); setFocusPolicy(WheelFocus); sci = new ScintillaTQt(this); SendScintilla(SCI_SETCARETPERIOD,TQApplication::cursorFlashTime() / 2); // Make sure the lexers are linked in. if (!lexersLinked) { Scintilla_LinkLexers(); lexersLinked = TRUE; } TQClipboard *cb = TQApplication::clipboard(); if (cb -> supportsSelection()) connect(cb,TQ_SIGNAL(selectionChanged()),TQ_SLOT(handleSelection())); // Add it to the pool. poolList.append(this); } // The dtor. TQextScintillaBase::~TQextScintillaBase() { // Remove it from the pool. poolList.remove(this); delete sci; } // Return the viewport widget. TQWidget *TQextScintillaBase::viewport() const { return txtarea; } // Return an instance from the pool. TQextScintillaBase *TQextScintillaBase::pool() { return poolList.first(); } // Send a message to the real Scintilla widget using the low level Scintilla // API. long TQextScintillaBase::SendScintilla(unsigned int msg,unsigned long wParam, long lParam) { return sci -> WndProc(msg,wParam,lParam); } // Send a message to the real Scintilla widget that needs a TextRange // structure. long TQextScintillaBase::SendScintilla(unsigned int msg,long cpMin,long cpMax, char *lpstrText) { TextRange tr; tr.chrg.cpMin = cpMin; tr.chrg.cpMax = cpMax; tr.lpstrText = lpstrText; return sci -> WndProc(msg,0,reinterpret_cast(&tr)); } // Send a message to the real Scintilla widget that needs a RangeToFormat // structure. long TQextScintillaBase::SendScintilla(unsigned int msg,unsigned long wParam, TQPainter *hdc,const TQRect &rc, long cpMin,long cpMax) { RangeToFormat rf; rf.hdc = rf.hdcTarget = reinterpret_cast(hdc); rf.rc.left = rc.left(); rf.rc.top = rc.top(); rf.rc.right = rc.right() + 1; rf.rc.bottom = rc.bottom() + 1; rf.chrg.cpMin = cpMin; rf.chrg.cpMax = cpMax; return sci -> WndProc(msg,wParam,reinterpret_cast(&rf)); } // Send a message to the real Scintilla widget that needs a colour. long TQextScintillaBase::SendScintilla(unsigned int msg,unsigned long wParam, const TQColor &col) { long lParam = (col.blue() << 16) | (col.green() << 8) | col.red(); return sci -> WndProc(msg,wParam,lParam); } // Send a message to the real Scintilla widget that needs a colour. long TQextScintillaBase::SendScintilla(unsigned int msg,const TQColor &col) { unsigned long wParam = (col.blue() << 16) | (col.green() << 8) | col.red(); return sci -> WndProc(msg,wParam,0); } // Handle events on behalf of the text area. bool TQextScintillaBase::eventFilter(TQObject *o,TQEvent *e) { if (o != txtarea) return TQWidget::eventFilter(o,e); bool used = TRUE; switch (e -> type()) { case TQEvent::Paint: sci -> paintEvent(static_cast(e)); break; case TQEvent::Resize: sci -> ChangeSize(); break; case TQEvent::MouseButtonPress: mousePress(static_cast(e)); break; case TQEvent::MouseButtonRelease: mouseRelease(static_cast(e)); break; case TQEvent::MouseButtonDblClick: mouseDoubleClick(static_cast(e)); break; case TQEvent::MouseMove: mouseMove(static_cast(e)); break; case TQEvent::Wheel: mouseWheel(static_cast(e)); break; case TQEvent::ContextMenu: contextMenu(static_cast(e)); break; case TQEvent::DragEnter: sci -> dragEnterEvent(static_cast(e)); break; case TQEvent::DragMove: sci -> dragMoveEvent(static_cast(e)); break; case TQEvent::DragLeave: sci -> dragLeaveEvent(static_cast(e)); break; case TQEvent::Drop: sci -> dropEvent(static_cast(e)); break; default: used = FALSE; } return used; } // Handle the timer on behalf of the ScintillaTQt instance. void TQextScintillaBase::handleTimer() { sci -> Tick(); } // Handle the context menu on behalf of the ScintillaTQt instance. void TQextScintillaBase::handlePopUp(int cmd) { sci -> Command(cmd); } // Re-implemented to tell the widget it has the focus. void TQextScintillaBase::focusInEvent(TQFocusEvent *) { sci -> SetFocusState(true); } // Re-implemented to tell the widget it has lost the focus. void TQextScintillaBase::focusOutEvent(TQFocusEvent *) { sci -> SetFocusState(false); } // Handle a mouse button press. void TQextScintillaBase::mousePress(TQMouseEvent *me) { setFocus(); Point pt(me -> x(),me -> y()); switch (me -> button()) { case LeftButton: { unsigned clickTime; // It is a triple click if the timer is running and the // mouse hasn't moved too much. if (triple_click.isActive() && (me -> globalPos() - triple_click_at).manhattanLength() < TQApplication::startDragDistance()) clickTime = sci -> lastClickTime + Platform::DoubleClickTime() - 1; else clickTime = sci -> lastClickTime + Platform::DoubleClickTime() + 1; triple_click.stop(); bool shift = me -> state() & ShiftButton; bool ctrl = me -> state() & ControlButton; bool alt = me -> state() & AltButton; sci -> ButtonDown(pt,clickTime,shift,ctrl,alt); break; } case MidButton: { TQClipboard *cb = TQApplication::clipboard(); if (cb -> supportsSelection()) { cb -> setSelectionMode(TRUE); int pos = sci -> PositionFromLocation(pt); sci -> SetSelection(pos,pos); sci -> Paste(); cb -> setSelectionMode(FALSE); } break; } default: break; } } // Handle a context menu event. void TQextScintillaBase::contextMenu(TQContextMenuEvent *cme) { TQApplication::sendEvent(this,cme); if (!cme -> isConsumed()) sci -> ContextMenu(Point(cme -> globalX(),cme -> globalY())); } // Handle a mouse button releases. void TQextScintillaBase::mouseRelease(TQMouseEvent *me) { if (sci -> HaveMouseCapture() && me -> button() == LeftButton) { bool ctrl = me -> state() & ControlButton; sci -> ButtonUp(Point(me -> x(),me -> y()),0,ctrl); } } // Handle a mouse move. void TQextScintillaBase::mouseMove(TQMouseEvent *me) { sci -> ButtonMove(Point(me -> x(),me -> y())); } // Handle a mouse wheel event. void TQextScintillaBase::mouseWheel(TQWheelEvent *we) { setFocus(); if (we -> orientation() == TQt::Horizontal || we -> state() & ShiftButton) TQApplication::sendEvent(hsb,we); else if (we -> orientation() == TQt::Vertical) TQApplication::sendEvent(vsb,we); } // Handle a mouse button double click. void TQextScintillaBase::mouseDoubleClick(TQMouseEvent *me) { setFocus(); if (me -> button() == LeftButton) { // Make sure Scintilla will interpret this as a double-click. unsigned clickTime = sci -> lastClickTime + Platform::DoubleClickTime() - 1; bool shift = me -> state() & ShiftButton; bool ctrl = me -> state() & ControlButton; bool alt = me -> state() & AltButton; sci -> ButtonDown(Point(me -> x(),me -> y()),clickTime,shift,ctrl,alt); // Remember the current position and time in case it turns into a // triple click. triple_click_at = me -> globalPos(); triple_click.start(TQApplication::doubleClickInterval()); } } // Re-implemented to handle key press events. void TQextScintillaBase::keyPressEvent(TQKeyEvent *ke) { unsigned key; switch (ke -> key()) { case Key_Down: key = SCK_DOWN; break; case Key_Up: key = SCK_UP; break; case Key_Left: key = SCK_LEFT; break; case Key_Right: key = SCK_RIGHT; break; case Key_Home: key = SCK_HOME; break; case Key_End: key = SCK_END; break; case Key_Prior: key = SCK_PRIOR; break; case Key_Next: key = SCK_NEXT; break; case Key_Delete: key = SCK_DELETE; break; case Key_Insert: key = SCK_INSERT; break; case Key_Escape: key = SCK_ESCAPE; break; case Key_Backspace: key = SCK_BACK; break; case Key_Tab: key = SCK_TAB; break; case Key_Return: case Key_Enter: key = SCK_RETURN; break; default: if (sci -> IsUnicodeMode()) { // Work out if the original input was a single ASCII // key. if (ke -> text().length() == 1) { if ((key = ke -> text()[0].unicode()) >= 0x80) key = 0; } else key = 0; } else { key = ke -> ascii(); if (key >= 0x01 && key <= 0x1f) key += 0x40; } } bool consumed = FALSE; if (key) { bool shift = ke -> state() & ShiftButton; bool ctrl = ke -> state() & ControlButton; bool alt = ke -> state() & AltButton; // If the character is eventually added by KeyDefault() then // the return value of KeyDown() will be true, but consumed // will incorrectly be false. if (sci -> KeyDown(key,shift,ctrl,alt,&consumed) && !consumed) consumed = TRUE; } else if (sci -> IsUnicodeMode()) { if (ke -> text().length() > 0 && !ke -> text()[0].isNull()) { TQCString s = ke -> text().utf8(); sci -> AddCharUTF(s.data(),s.length()); consumed = TRUE; } } if (!consumed) ke -> ignore(); } // Re-implemented to make sure tabs are passed to the editor. bool TQextScintillaBase::focusNextPrevChild(bool) { return false; } // Start a drag and allow this to be re-implemented by an application. void TQextScintillaBase::startDrag() { sci -> StartDragImpl(); } // Handle the vertical scrollbar. void TQextScintillaBase::handleVSb(int val) { sci -> ScrollTo(val); } // Handle the horizontal scrollbar. void TQextScintillaBase::handleHSb(int val) { sci ->HorizontalScrollTo(val); } // Return the current prefered size. TQSize TQextScintillaBase::sizeHint() const { int height = sci -> vs.lineHeight * sci -> pdoc -> LinesTotal(); if (sci -> horizontalScrollBarVisible) height += hsb -> sizeHint().height(); return TQSize(sci -> scrollWidth,height); } // Handle the selection changing. void TQextScintillaBase::handleSelection() { if (!TQApplication::clipboard() -> ownsSelection()) sci -> UnclaimSelection(); }