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.
tqscintilla/qt/qextscintillabase.cpp

587 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.
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include "qextscintillabase.moc"
#include <tqapplication.h>
#include <tqclipboard.h>
#include <tqscrollbar.h>
#include <tqlayout.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();
}