You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
583 lines
12 KiB
583 lines
12 KiB
// This module implements the "official" low-level API.
|
|
//
|
|
// Copyright (c) 2006
|
|
// Riverbank Computing Limited <info@riverbankcomputing.co.uk>
|
|
//
|
|
// 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 <tqapplication.h>
|
|
#include <clipboard.h>
|
|
#include <tqscrollbar.h>
|
|
#include <layout.h>
|
|
#include <tqcolor.h>
|
|
#include <tqevent.h>
|
|
#include <tqdragobject.h>
|
|
#include <tqpainter.h>
|
|
#include <tqptrlist.h>
|
|
|
|
#include "qextscintillabase.h"
|
|
#include "ScintillaQt.h"
|
|
|
|
|
|
// The #defines in Scintilla.h and the enums in qextscintillabase.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<QextScintillaBase> poolList;
|
|
|
|
|
|
// The ctor.
|
|
QextScintillaBase::QextScintillaBase(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(Qt::Vertical,this);
|
|
layout -> addWidget(vsb,0,1);
|
|
connect(vsb,TQT_SIGNAL(valueChanged(int)),TQT_SLOT(handleVSb(int)));
|
|
|
|
hsb = new TQScrollBar(Qt::Horizontal,this);
|
|
layout -> addWidget(hsb,1,0);
|
|
connect(hsb,TQT_SIGNAL(valueChanged(int)),TQT_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,TQT_SIGNAL(selectionChanged()),TQT_SLOT(handleSelection()));
|
|
|
|
// Add it to the pool.
|
|
poolList.append(this);
|
|
}
|
|
|
|
|
|
// The dtor.
|
|
QextScintillaBase::~QextScintillaBase()
|
|
{
|
|
// Remove it from the pool.
|
|
poolList.remove(this);
|
|
|
|
delete sci;
|
|
}
|
|
|
|
|
|
// Return the viewport widget.
|
|
TQWidget *QextScintillaBase::viewport() const
|
|
{
|
|
return txtarea;
|
|
}
|
|
|
|
|
|
// Return an instance from the pool.
|
|
QextScintillaBase *QextScintillaBase::pool()
|
|
{
|
|
return poolList.first();
|
|
}
|
|
|
|
|
|
// Send a message to the real Scintilla widget using the low level Scintilla
|
|
// API.
|
|
long QextScintillaBase::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 QextScintillaBase::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<long>(&tr));
|
|
}
|
|
|
|
|
|
// Send a message to the real Scintilla widget that needs a RangeToFormat
|
|
// structure.
|
|
long QextScintillaBase::SendScintilla(unsigned int msg,unsigned long wParam,
|
|
TQPainter *hdc,const TQRect &rc,
|
|
long cpMin,long cpMax)
|
|
{
|
|
RangeToFormat rf;
|
|
|
|
rf.hdc = rf.hdcTarget = reinterpret_cast<SurfaceID>(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<long>(&rf));
|
|
}
|
|
|
|
|
|
// Send a message to the real Scintilla widget that needs a colour.
|
|
long QextScintillaBase::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 QextScintillaBase::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 QextScintillaBase::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<TQPaintEvent *>(e));
|
|
break;
|
|
|
|
case TQEvent::Resize:
|
|
sci -> ChangeSize();
|
|
break;
|
|
|
|
case TQEvent::MouseButtonPress:
|
|
mousePress(static_cast<TQMouseEvent *>(e));
|
|
break;
|
|
|
|
case TQEvent::MouseButtonRelease:
|
|
mouseRelease(static_cast<TQMouseEvent *>(e));
|
|
break;
|
|
|
|
case TQEvent::MouseButtonDblClick:
|
|
mouseDoubleClick(static_cast<TQMouseEvent *>(e));
|
|
break;
|
|
|
|
case TQEvent::MouseMove:
|
|
mouseMove(static_cast<TQMouseEvent *>(e));
|
|
break;
|
|
|
|
case TQEvent::Wheel:
|
|
mouseWheel(static_cast<TQWheelEvent *>(e));
|
|
break;
|
|
|
|
case TQEvent::ContextMenu:
|
|
contextMenu(static_cast<TQContextMenuEvent *>(e));
|
|
break;
|
|
|
|
case TQEvent::DragEnter:
|
|
sci -> dragEnterEvent(static_cast<TQDragEnterEvent *>(e));
|
|
break;
|
|
|
|
case TQEvent::DragMove:
|
|
sci -> dragMoveEvent(static_cast<TQDragMoveEvent *>(e));
|
|
break;
|
|
|
|
case TQEvent::DragLeave:
|
|
sci -> dragLeaveEvent(static_cast<TQDragLeaveEvent *>(e));
|
|
break;
|
|
|
|
case TQEvent::Drop:
|
|
sci -> dropEvent(static_cast<TQDropEvent *>(e));
|
|
break;
|
|
|
|
default:
|
|
used = FALSE;
|
|
}
|
|
|
|
return used;
|
|
}
|
|
|
|
|
|
// Handle the timer on behalf of the ScintillaTQt instance.
|
|
void QextScintillaBase::handleTimer()
|
|
{
|
|
sci -> Tick();
|
|
}
|
|
|
|
|
|
// Handle the context menu on behalf of the ScintillaTQt instance.
|
|
void QextScintillaBase::handlePopUp(int cmd)
|
|
{
|
|
sci -> Command(cmd);
|
|
}
|
|
|
|
|
|
// Re-implemented to tell the widget it has the focus.
|
|
void QextScintillaBase::focusInEvent(TQFocusEvent *)
|
|
{
|
|
sci -> SetFocusState(true);
|
|
}
|
|
|
|
|
|
// Re-implemented to tell the widget it has lost the focus.
|
|
void QextScintillaBase::focusOutEvent(TQFocusEvent *)
|
|
{
|
|
sci -> SetFocusState(false);
|
|
}
|
|
|
|
|
|
// Handle a mouse button press.
|
|
void QextScintillaBase::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 QextScintillaBase::contextMenu(TQContextMenuEvent *cme)
|
|
{
|
|
TQApplication::sendEvent(this,cme);
|
|
|
|
if (!cme -> isConsumed())
|
|
sci -> ContextMenu(Point(cme -> globalX(),cme -> globalY()));
|
|
}
|
|
|
|
|
|
// Handle a mouse button releases.
|
|
void QextScintillaBase::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 QextScintillaBase::mouseMove(TQMouseEvent *me)
|
|
{
|
|
sci -> ButtonMove(Point(me -> x(),me -> y()));
|
|
}
|
|
|
|
|
|
// Handle a mouse wheel event.
|
|
void QextScintillaBase::mouseWheel(TQWheelEvent *we)
|
|
{
|
|
setFocus();
|
|
|
|
if (we -> orientation() == Qt::Horizontal || we -> state() & ShiftButton)
|
|
TQApplication::sendEvent(hsb,we);
|
|
else if (we -> orientation() == Qt::Vertical)
|
|
TQApplication::sendEvent(vsb,we);
|
|
}
|
|
|
|
|
|
// Handle a mouse button double click.
|
|
void QextScintillaBase::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 QextScintillaBase::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 QextScintillaBase::focusNextPrevChild(bool)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
|
|
// Start a drag and allow this to be re-implemented by an application.
|
|
void QextScintillaBase::startDrag()
|
|
{
|
|
sci -> StartDragImpl();
|
|
}
|
|
|
|
|
|
// Handle the vertical scrollbar.
|
|
void QextScintillaBase::handleVSb(int val)
|
|
{
|
|
sci -> ScrollTo(val);
|
|
}
|
|
|
|
|
|
// Handle the horizontal scrollbar.
|
|
void QextScintillaBase::handleHSb(int val)
|
|
{
|
|
sci ->HorizontalScrollTo(val);
|
|
}
|
|
|
|
|
|
// Return the current prefered size.
|
|
TQSize QextScintillaBase::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 QextScintillaBase::handleSelection()
|
|
{
|
|
if (!TQApplication::clipboard() -> ownsSelection())
|
|
sci -> UnclaimSelection();
|
|
}
|