play around with Scintilla and Lexilla

This commit is contained in:
2024-07-02 23:47:26 +08:00
parent d7c71f41b2
commit 727a2ec214
992 changed files with 281111 additions and 195 deletions

View File

@ -0,0 +1,18 @@
Issues with Scintilla for Qt
Qt reports character descenders are 1 pixel shorter than they really are.
There is a tweak in the code to add a pixel in. This may have to be reviewed for Qt 5.
There's a comment in the Qt code for Windows:
// ### we subtract 1 to even out the historical +1 in QFontMetrics's
// ### height=asc+desc+1 equation. Fix in Qt5.
The clocks used aren't great. QTime is a time since midnight clock so wraps around and
is only accurate to, at best, milliseconds.
On macOS drawing text into a pixmap moves it around 1 pixel to the right compared to drawing
it directly onto a window. Buffered drawing turned off by default to avoid this.
Reported as QTBUG-19483.
Only one QPainter can be active on any widget at a time. Scintilla only draws into one
widget but reenters for measurement.

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,163 @@
// @file PlatQt.h
// Copyright (c) 1990-2011, Scientific Toolworks, Inc.
//
// The License.txt file describes the conditions under which this software may be distributed.
//
// Author: Jason Haslam
//
// Additions Copyright (c) 2011 Archaeopteryx Software, Inc. d/b/a Wingware
// Scintilla platform layer for Qt
#ifndef PLATQT_H
#define PLATQT_H
#include <cstddef>
#include <string_view>
#include <vector>
#include <optional>
#include <memory>
#include "Debugging.h"
#include "Geometry.h"
#include "ScintillaTypes.h"
#include "ScintillaMessages.h"
#include "Platform.h"
#include <QUrl>
#include <QPaintDevice>
#include <QPainter>
#include <QHash>
#include <QTextCodec>
namespace Scintilla::Internal {
const char *CharacterSetID(Scintilla::CharacterSet characterSet);
inline QColor QColorFromColourRGBA(ColourRGBA ca)
{
return QColor(ca.GetRed(), ca.GetGreen(), ca.GetBlue(), ca.GetAlpha());
}
inline QRect QRectFromPRect(PRectangle pr)
{
return QRect(pr.left, pr.top, pr.Width(), pr.Height());
}
inline QRectF QRectFFromPRect(PRectangle pr)
{
return QRectF(pr.left, pr.top, pr.Width(), pr.Height());
}
inline PRectangle PRectFromQRect(QRect qr)
{
return PRectangle(qr.x(), qr.y(), qr.x() + qr.width(), qr.y() + qr.height());
}
inline Point PointFromQPoint(QPoint qp)
{
return Point(qp.x(), qp.y());
}
inline QPointF QPointFFromPoint(Point qp)
{
return QPointF(qp.x, qp.y);
}
constexpr PRectangle RectangleInset(PRectangle rc, XYPOSITION delta) noexcept {
return PRectangle(rc.left + delta, rc.top + delta, rc.right - delta, rc.bottom - delta);
}
class SurfaceImpl : public Surface {
private:
QPaintDevice *device = nullptr;
QPainter *painter = nullptr;
bool deviceOwned = false;
bool painterOwned = false;
SurfaceMode mode;
const char *codecName = nullptr;
QTextCodec *codec = nullptr;
void Clear();
public:
SurfaceImpl();
SurfaceImpl(int width, int height, SurfaceMode mode_);
virtual ~SurfaceImpl();
void Init(WindowID wid) override;
void Init(SurfaceID sid, WindowID wid) override;
std::unique_ptr<Surface> AllocatePixMap(int width, int height) override;
void SetMode(SurfaceMode mode) override;
void Release() noexcept override;
int SupportsFeature(Scintilla::Supports feature) noexcept override;
bool Initialised() override;
void PenColour(ColourRGBA fore);
void PenColourWidth(ColourRGBA fore, XYPOSITION strokeWidth);
int LogPixelsY() override;
int PixelDivisions() override;
int DeviceHeightFont(int points) override;
void LineDraw(Point start, Point end, Stroke stroke) override;
void PolyLine(const Point *pts, size_t npts, Stroke stroke) override;
void Polygon(const Point *pts, size_t npts, FillStroke fillStroke) override;
void RectangleDraw(PRectangle rc, FillStroke fillStroke) override;
void RectangleFrame(PRectangle rc, Stroke stroke) override;
void FillRectangle(PRectangle rc, Fill fill) override;
void FillRectangleAligned(PRectangle rc, Fill fill) override;
void FillRectangle(PRectangle rc, Surface &surfacePattern) override;
void RoundedRectangle(PRectangle rc, FillStroke fillStroke) override;
void AlphaRectangle(PRectangle rc, XYPOSITION cornerSize, FillStroke fillStroke) override;
void GradientRectangle(PRectangle rc, const std::vector<ColourStop> &stops, GradientOptions options) override;
void DrawRGBAImage(PRectangle rc, int width, int height,
const unsigned char *pixelsImage) override;
void Ellipse(PRectangle rc, FillStroke fillStroke) override;
void Stadium(PRectangle rc, FillStroke fillStroke, Ends ends) override;
void Copy(PRectangle rc, Point from, Surface &surfaceSource) override;
std::unique_ptr<IScreenLineLayout> Layout(const IScreenLine *screenLine) override;
void DrawTextNoClip(PRectangle rc, const Font *font, XYPOSITION ybase,
std::string_view text, ColourRGBA fore, ColourRGBA back) override;
void DrawTextClipped(PRectangle rc, const Font *font, XYPOSITION ybase,
std::string_view text, ColourRGBA fore, ColourRGBA back) override;
void DrawTextTransparent(PRectangle rc, const Font *font, XYPOSITION ybase,
std::string_view text, ColourRGBA fore) override;
void MeasureWidths(const Font *font, std::string_view text,
XYPOSITION *positions) override;
XYPOSITION WidthText(const Font *font, std::string_view text) override;
void DrawTextNoClipUTF8(PRectangle rc, const Font *font_, XYPOSITION ybase,
std::string_view text, ColourRGBA fore, ColourRGBA back) override;
void DrawTextClippedUTF8(PRectangle rc, const Font *font_, XYPOSITION ybase,
std::string_view text, ColourRGBA fore, ColourRGBA back) override;
void DrawTextTransparentUTF8(PRectangle rc, const Font *font_, XYPOSITION ybase,
std::string_view text, ColourRGBA fore) override;
void MeasureWidthsUTF8(const Font *font_, std::string_view text,
XYPOSITION *positions) override;
XYPOSITION WidthTextUTF8(const Font *font_, std::string_view text) override;
XYPOSITION Ascent(const Font *font) override;
XYPOSITION Descent(const Font *font) override;
XYPOSITION InternalLeading(const Font *font) override;
XYPOSITION Height(const Font *font) override;
XYPOSITION AverageCharWidth(const Font *font) override;
void SetClip(PRectangle rc) override;
void PopClip() override;
void FlushCachedState() override;
void FlushDrawing() override;
void BrushColour(ColourRGBA back);
void SetCodec(const Font *font);
void SetFont(const Font *font);
QPaintDevice *GetPaintDevice();
void SetPainter(QPainter *painter);
QPainter *GetPainter();
};
}
#endif

View File

@ -0,0 +1,828 @@
//
// Copyright (c) 1990-2011, Scientific Toolworks, Inc.
//
// The License.txt file describes the conditions under which this software may be distributed.
//
// Author: Jason Haslam
//
// Additions Copyright (c) 2011 Archaeopteryx Software, Inc. d/b/a Wingware
// @file ScintillaEditBase.cpp - Qt widget that wraps ScintillaQt and provides events and scrolling
#include "ScintillaEditBase.h"
#include "ScintillaQt.h"
#include "PlatQt.h"
#include <QApplication>
#if QT_VERSION < QT_VERSION_CHECK(5, 0, 0)
#include <QInputContext>
#endif
#include <QPainter>
#include <QVarLengthArray>
#include <QScrollBar>
#include <QTextFormat>
constexpr int IndicatorInput = static_cast<int>(Scintilla::IndicatorNumbers::Ime);
constexpr int IndicatorTarget = IndicatorInput + 1;
constexpr int IndicatorConverted = IndicatorInput + 2;
constexpr int IndicatorUnknown = IndicatorInput + 3;
// Q_WS_MAC and Q_WS_X11 aren't defined in Qt5
#if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)
#ifdef Q_OS_MAC
#define Q_WS_MAC 1
#endif
#if !defined(Q_OS_MAC) && !defined(Q_OS_WIN)
#define Q_WS_X11 1
#endif
#endif // QT_VERSION >= 5.0.0
using namespace Scintilla;
using namespace Scintilla::Internal;
ScintillaEditBase::ScintillaEditBase(QWidget *parent)
: QAbstractScrollArea(parent), sqt(new ScintillaQt(this)), preeditPos(-1), wheelDelta(0)
{
time.start();
// Set Qt defaults.
setAcceptDrops(true);
setMouseTracking(true);
setAutoFillBackground(false);
setFrameStyle(QFrame::NoFrame);
setFocusPolicy(Qt::StrongFocus);
setAttribute(Qt::WA_StaticContents);
viewport()->setAutoFillBackground(false);
setAttribute(Qt::WA_KeyCompression);
setAttribute(Qt::WA_InputMethodEnabled);
sqt->vs.indicators[IndicatorUnknown] = Indicator(IndicatorStyle::Hidden, colourIME);
sqt->vs.indicators[IndicatorInput] = Indicator(IndicatorStyle::Dots, colourIME);
sqt->vs.indicators[IndicatorConverted] = Indicator(IndicatorStyle::CompositionThick, colourIME);
sqt->vs.indicators[IndicatorTarget] = Indicator(IndicatorStyle::StraightBox, colourIME);
connect(sqt, SIGNAL(notifyParent(Scintilla::NotificationData)),
this, SLOT(notifyParent(Scintilla::NotificationData)));
// Connect scroll bars.
connect(verticalScrollBar(), SIGNAL(valueChanged(int)),
this, SLOT(scrollVertical(int)));
connect(horizontalScrollBar(), SIGNAL(valueChanged(int)),
this, SLOT(scrollHorizontal(int)));
// Connect pass-through signals.
connect(sqt, SIGNAL(horizontalRangeChanged(int,int)),
this, SIGNAL(horizontalRangeChanged(int,int)));
connect(sqt, SIGNAL(verticalRangeChanged(int,int)),
this, SIGNAL(verticalRangeChanged(int,int)));
connect(sqt, SIGNAL(horizontalScrolled(int)),
this, SIGNAL(horizontalScrolled(int)));
connect(sqt, SIGNAL(verticalScrolled(int)),
this, SIGNAL(verticalScrolled(int)));
connect(sqt, SIGNAL(notifyChange()),
this, SIGNAL(notifyChange()));
connect(sqt, SIGNAL(command(Scintilla::uptr_t,Scintilla::sptr_t)),
this, SLOT(event_command(Scintilla::uptr_t,Scintilla::sptr_t)));
connect(sqt, SIGNAL(aboutToCopy(QMimeData*)),
this, SIGNAL(aboutToCopy(QMimeData*)));
}
ScintillaEditBase::~ScintillaEditBase() = default;
sptr_t ScintillaEditBase::send(
unsigned int iMessage,
uptr_t wParam,
sptr_t lParam) const
{
return sqt->WndProc(static_cast<Message>(iMessage), wParam, lParam);
}
sptr_t ScintillaEditBase::sends(
unsigned int iMessage,
uptr_t wParam,
const char *s) const
{
return sqt->WndProc(static_cast<Message>(iMessage), wParam, reinterpret_cast<sptr_t>(s));
}
void ScintillaEditBase::scrollHorizontal(int value)
{
sqt->HorizontalScrollTo(value);
}
void ScintillaEditBase::scrollVertical(int value)
{
sqt->ScrollTo(value);
}
bool ScintillaEditBase::event(QEvent *event)
{
bool result = false;
if (event->type() == QEvent::KeyPress) {
// Circumvent the tab focus convention.
keyPressEvent(static_cast<QKeyEvent *>(event));
result = event->isAccepted();
} else if (event->type() == QEvent::Show) {
setMouseTracking(true);
result = QAbstractScrollArea::event(event);
} else if (event->type() == QEvent::Hide) {
setMouseTracking(false);
result = QAbstractScrollArea::event(event);
} else {
result = QAbstractScrollArea::event(event);
}
return result;
}
void ScintillaEditBase::paintEvent(QPaintEvent *event)
{
sqt->PartialPaint(PRectFromQRect(event->rect()));
}
namespace {
bool isWheelEventHorizontal(QWheelEvent *event) {
#if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0)
return event->angleDelta().y() == 0;
#else
return event->orientation() == Qt::Horizontal;
#endif
}
int wheelEventYDelta(QWheelEvent *event) {
#if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0)
return event->angleDelta().y();
#else
return event->delta();
#endif
}
}
void ScintillaEditBase::wheelEvent(QWheelEvent *event)
{
if (isWheelEventHorizontal(event)) {
QAbstractScrollArea::wheelEvent(event);
} else {
if (QApplication::keyboardModifiers() & Qt::ControlModifier) {
// Zoom! We play with the font sizes in the styles.
// Number of steps/line is ignored, we just care if sizing up or down
if (wheelEventYDelta(event) > 0) {
sqt->KeyCommand(Message::ZoomIn);
} else {
sqt->KeyCommand(Message::ZoomOut);
}
} else {
// Scroll
QAbstractScrollArea::wheelEvent(event);
}
}
}
void ScintillaEditBase::focusInEvent(QFocusEvent *event)
{
sqt->SetFocusState(true);
QAbstractScrollArea::focusInEvent(event);
}
void ScintillaEditBase::focusOutEvent(QFocusEvent *event)
{
sqt->SetFocusState(false);
QAbstractScrollArea::focusOutEvent(event);
}
void ScintillaEditBase::resizeEvent(QResizeEvent *)
{
sqt->ChangeSize();
emit resized();
}
void ScintillaEditBase::keyPressEvent(QKeyEvent *event)
{
// All keystrokes containing the meta modifier are
// assumed to be shortcuts not handled by scintilla.
if (QApplication::keyboardModifiers() & Qt::MetaModifier) {
QAbstractScrollArea::keyPressEvent(event);
emit keyPressed(event);
return;
}
int key = 0;
switch (event->key()) {
case Qt::Key_Down: key = SCK_DOWN; break;
case Qt::Key_Up: key = SCK_UP; break;
case Qt::Key_Left: key = SCK_LEFT; break;
case Qt::Key_Right: key = SCK_RIGHT; break;
case Qt::Key_Home: key = SCK_HOME; break;
case Qt::Key_End: key = SCK_END; break;
case Qt::Key_PageUp: key = SCK_PRIOR; break;
case Qt::Key_PageDown: key = SCK_NEXT; break;
case Qt::Key_Delete: key = SCK_DELETE; break;
case Qt::Key_Insert: key = SCK_INSERT; break;
case Qt::Key_Escape: key = SCK_ESCAPE; break;
case Qt::Key_Backspace: key = SCK_BACK; break;
case Qt::Key_Plus: key = SCK_ADD; break;
case Qt::Key_Minus: key = SCK_SUBTRACT; break;
case Qt::Key_Backtab: // fall through
case Qt::Key_Tab: key = SCK_TAB; break;
case Qt::Key_Enter: // fall through
case Qt::Key_Return: key = SCK_RETURN; break;
case Qt::Key_Control: key = 0; break;
case Qt::Key_Alt: key = 0; break;
case Qt::Key_Shift: key = 0; break;
case Qt::Key_Meta: key = 0; break;
default: key = event->key(); break;
}
bool shift = QApplication::keyboardModifiers() & Qt::ShiftModifier;
bool ctrl = QApplication::keyboardModifiers() & Qt::ControlModifier;
bool alt = QApplication::keyboardModifiers() & Qt::AltModifier;
bool consumed = false;
bool added = sqt->KeyDownWithModifiers(static_cast<Keys>(key),
ModifierFlags(shift, ctrl, alt),
&consumed) != 0;
if (!consumed)
consumed = added;
if (!consumed) {
// Don't insert text if the control key was pressed unless
// it was pressed in conjunction with alt for AltGr emulation.
bool input = (!ctrl || alt);
// Additionally, on non-mac platforms, don't insert text
// if the alt key was pressed unless control is also present.
// On mac alt can be used to insert special characters.
#ifndef Q_WS_MAC
input &= (!alt || ctrl);
#endif
QString text = event->text();
if (input && !text.isEmpty() && text[0].isPrint()) {
const int strLen = text.length();
for (int i = 0; i < strLen;) {
const int ucWidth = text.at(i).isHighSurrogate() ? 2 : 1;
const QString oneCharUTF16 = text.mid(i, ucWidth);
const QByteArray oneChar = sqt->BytesForDocument(oneCharUTF16);
sqt->InsertCharacter(std::string_view(oneChar.data(), oneChar.length()), CharacterSource::DirectInput);
i += ucWidth;
}
} else {
event->ignore();
}
}
emit keyPressed(event);
}
static int modifierTranslated(int sciModifier)
{
switch (sciModifier) {
case SCMOD_SHIFT:
return Qt::ShiftModifier;
case SCMOD_CTRL:
return Qt::ControlModifier;
case SCMOD_ALT:
return Qt::AltModifier;
case SCMOD_SUPER:
return Qt::MetaModifier;
default:
return 0;
}
}
void ScintillaEditBase::mousePressEvent(QMouseEvent *event)
{
Point pos = PointFromQPoint(event->pos());
emit buttonPressed(event);
if (event->button() == Qt::MiddleButton &&
QApplication::clipboard()->supportsSelection()) {
SelectionPosition selPos = sqt->SPositionFromLocation(
pos, false, false, sqt->UserVirtualSpace());
sqt->sel.Clear();
sqt->SetSelection(selPos, selPos);
sqt->PasteFromMode(QClipboard::Selection);
return;
}
if (event->button() == Qt::LeftButton) {
bool shift = QApplication::keyboardModifiers() & Qt::ShiftModifier;
bool ctrl = QApplication::keyboardModifiers() & Qt::ControlModifier;
bool alt = QApplication::keyboardModifiers() & modifierTranslated(sqt->rectangularSelectionModifier);
sqt->ButtonDownWithModifiers(pos, time.elapsed(), ModifierFlags(shift, ctrl, alt));
}
if (event->button() == Qt::RightButton) {
sqt->RightButtonDownWithModifiers(pos, time.elapsed(), ModifiersOfKeyboard());
}
}
void ScintillaEditBase::mouseReleaseEvent(QMouseEvent *event)
{
const QPoint point = event->pos();
if (event->button() == Qt::LeftButton)
sqt->ButtonUpWithModifiers(PointFromQPoint(point), time.elapsed(), ModifiersOfKeyboard());
const sptr_t pos = send(SCI_POSITIONFROMPOINT, point.x(), point.y());
const sptr_t line = send(SCI_LINEFROMPOSITION, pos);
int modifiers = QApplication::keyboardModifiers();
emit textAreaClicked(line, modifiers);
emit buttonReleased(event);
}
void ScintillaEditBase::mouseDoubleClickEvent(QMouseEvent *event)
{
// Scintilla does its own double-click detection.
mousePressEvent(event);
}
void ScintillaEditBase::mouseMoveEvent(QMouseEvent *event)
{
Point pos = PointFromQPoint(event->pos());
bool shift = QApplication::keyboardModifiers() & Qt::ShiftModifier;
bool ctrl = QApplication::keyboardModifiers() & Qt::ControlModifier;
bool alt = QApplication::keyboardModifiers() & modifierTranslated(sqt->rectangularSelectionModifier);
const KeyMod modifiers = ModifierFlags(shift, ctrl, alt);
sqt->ButtonMoveWithModifiers(pos, time.elapsed(), modifiers);
}
void ScintillaEditBase::contextMenuEvent(QContextMenuEvent *event)
{
Point pos = PointFromQPoint(event->globalPos());
Point pt = PointFromQPoint(event->pos());
if (!sqt->PointInSelection(pt)) {
sqt->SetEmptySelection(sqt->PositionFromLocation(pt));
}
if (sqt->ShouldDisplayPopup(pt)) {
sqt->ContextMenu(pos);
event->accept();
} else {
event->ignore();
}
}
void ScintillaEditBase::dragEnterEvent(QDragEnterEvent *event)
{
if (event->mimeData()->hasUrls()) {
event->acceptProposedAction();
} else if (event->mimeData()->hasText()) {
event->acceptProposedAction();
Point point = PointFromQPoint(event->pos());
sqt->DragEnter(point);
} else {
event->ignore();
}
}
void ScintillaEditBase::dragLeaveEvent(QDragLeaveEvent * /* event */)
{
sqt->DragLeave();
}
void ScintillaEditBase::dragMoveEvent(QDragMoveEvent *event)
{
if (event->mimeData()->hasUrls()) {
event->acceptProposedAction();
} else if (event->mimeData()->hasText()) {
event->acceptProposedAction();
Point point = PointFromQPoint(event->pos());
sqt->DragMove(point);
} else {
event->ignore();
}
}
void ScintillaEditBase::dropEvent(QDropEvent *event)
{
if (event->mimeData()->hasUrls()) {
event->acceptProposedAction();
sqt->DropUrls(event->mimeData());
} else if (event->mimeData()->hasText()) {
event->acceptProposedAction();
Point point = PointFromQPoint(event->pos());
bool move = (event->source() == this &&
event->proposedAction() == Qt::MoveAction);
sqt->Drop(point, event->mimeData(), move);
} else {
event->ignore();
}
}
bool ScintillaEditBase::IsHangul(const QChar qchar)
{
unsigned int unicode = qchar.unicode();
// Korean character ranges used for preedit chars.
// http://www.programminginkorean.com/programming/hangul-in-unicode/
const bool HangulJamo = (0x1100 <= unicode && unicode <= 0x11FF);
const bool HangulCompatibleJamo = (0x3130 <= unicode && unicode <= 0x318F);
const bool HangulJamoExtendedA = (0xA960 <= unicode && unicode <= 0xA97F);
const bool HangulJamoExtendedB = (0xD7B0 <= unicode && unicode <= 0xD7FF);
const bool HangulSyllable = (0xAC00 <= unicode && unicode <= 0xD7A3);
return HangulJamo || HangulCompatibleJamo || HangulSyllable ||
HangulJamoExtendedA || HangulJamoExtendedB;
}
void ScintillaEditBase::MoveImeCarets(Scintilla::Position offset)
{
// Move carets relatively by bytes
for (size_t r=0; r < sqt->sel.Count(); r++) {
const Sci::Position positionInsert = sqt->sel.Range(r).Start().Position();
sqt->sel.Range(r).caret.SetPosition(positionInsert + offset);
sqt->sel.Range(r).anchor.SetPosition(positionInsert + offset);
}
}
void ScintillaEditBase::DrawImeIndicator(int indicator, int len)
{
// Emulate the visual style of IME characters with indicators.
// Draw an indicator on the character before caret by the character bytes of len
// so it should be called after InsertCharacter().
// It does not affect caret positions.
if (indicator < INDICATOR_CONTAINER || indicator > INDICATOR_MAX) {
return;
}
sqt->pdoc->DecorationSetCurrentIndicator(indicator);
for (size_t r=0; r< sqt-> sel.Count(); r++) {
const Sci::Position positionInsert = sqt->sel.Range(r).Start().Position();
sqt->pdoc->DecorationFillRange(positionInsert - len, 1, len);
}
}
static int GetImeCaretPos(QInputMethodEvent *event)
{
foreach (QInputMethodEvent::Attribute attr, event->attributes()) {
if (attr.type == QInputMethodEvent::Cursor)
return attr.start;
}
return 0;
}
static std::vector<int> MapImeIndicators(QInputMethodEvent *event)
{
std::vector<int> imeIndicator(event->preeditString().size(), IndicatorUnknown);
foreach (QInputMethodEvent::Attribute attr, event->attributes()) {
if (attr.type == QInputMethodEvent::TextFormat) {
QTextFormat format = attr.value.value<QTextFormat>();
QTextCharFormat charFormat = format.toCharFormat();
int indicator = IndicatorUnknown;
switch (charFormat.underlineStyle()) {
case QTextCharFormat::NoUnderline: // win32, linux
case QTextCharFormat::SingleUnderline: // osx
case QTextCharFormat::DashUnderline: // win32, linux
indicator = IndicatorInput;
break;
case QTextCharFormat::DotLine:
case QTextCharFormat::DashDotLine:
case QTextCharFormat::WaveUnderline:
case QTextCharFormat::SpellCheckUnderline:
indicator = IndicatorConverted;
break;
default:
indicator = IndicatorUnknown;
}
if (format.hasProperty(QTextFormat::BackgroundBrush)) // win32, linux
indicator = IndicatorTarget;
#ifdef Q_OS_OSX
if (charFormat.underlineStyle() == QTextCharFormat::SingleUnderline) {
QColor uc = charFormat.underlineColor();
if (uc.lightness() < 2) { // osx
indicator = IndicatorTarget;
}
}
#endif
for (int i = attr.start; i < attr.start+attr.length; i++) {
imeIndicator[i] = indicator;
}
}
}
return imeIndicator;
}
void ScintillaEditBase::inputMethodEvent(QInputMethodEvent *event)
{
// Copy & paste by johnsonj with a lot of helps of Neil
// Great thanks for my forerunners, jiniya and BLUEnLIVE
if (sqt->pdoc->IsReadOnly() || sqt->SelectionContainsProtected()) {
// Here, a canceling and/or completing composition function is needed.
return;
}
bool initialCompose = false;
if (sqt->pdoc->TentativeActive()) {
sqt->pdoc->TentativeUndo();
} else {
// No tentative undo means start of this composition so
// Fill in any virtual spaces.
initialCompose = true;
}
sqt->view.imeCaretBlockOverride = false;
preeditPos = -1; // reset not to interrupt Qt::ImCursorRectangle.
const int rpLength = event->replacementLength();
if (rpLength != 0) {
// Qt has called setCommitString().
// Make room for the string to sit in.
const int rpStart = event->replacementStart();
const Scintilla::Position rpBase = sqt->CurrentPosition();
const Scintilla::Position start = sqt->pdoc->GetRelativePositionUTF16(rpBase, rpStart);
const Scintilla::Position end = sqt->pdoc->GetRelativePositionUTF16(start, rpLength);
sqt->pdoc->DeleteChars(start, end - start);
}
if (!event->commitString().isEmpty()) {
const QString &commitStr = event->commitString();
const int commitStrLen = commitStr.length();
for (int i = 0; i < commitStrLen;) {
const int ucWidth = commitStr.at(i).isHighSurrogate() ? 2 : 1;
const QString oneCharUTF16 = commitStr.mid(i, ucWidth);
const QByteArray oneChar = sqt->BytesForDocument(oneCharUTF16);
sqt->InsertCharacter(std::string_view(oneChar.data(), oneChar.length()), CharacterSource::DirectInput);
i += ucWidth;
}
} else if (!event->preeditString().isEmpty()) {
const QString preeditStr = event->preeditString();
const int preeditStrLen = preeditStr.length();
if (preeditStrLen == 0) {
sqt->ShowCaretAtCurrentPosition();
return;
}
if (initialCompose)
sqt->ClearBeforeTentativeStart();
sqt->pdoc->TentativeStart(); // TentativeActive() from now on.
// Fix candidate window position at the start of preeditString.
preeditPos = sqt->CurrentPosition();
std::vector<int> imeIndicator = MapImeIndicators(event);
for (int i = 0; i < preeditStrLen;) {
const int ucWidth = preeditStr.at(i).isHighSurrogate() ? 2 : 1;
const QString oneCharUTF16 = preeditStr.mid(i, ucWidth);
const QByteArray oneChar = sqt->BytesForDocument(oneCharUTF16);
const int oneCharLen = oneChar.length();
sqt->InsertCharacter(std::string_view(oneChar.data(), oneCharLen), CharacterSource::TentativeInput);
DrawImeIndicator(imeIndicator[i], oneCharLen);
i += ucWidth;
}
// Move IME carets.
int imeCaretPos = GetImeCaretPos(event);
int imeEndToImeCaretU16 = imeCaretPos - preeditStrLen;
const Sci::Position imeCaretPosDoc = sqt->pdoc->GetRelativePositionUTF16(sqt->CurrentPosition(), imeEndToImeCaretU16);
MoveImeCarets(- sqt->CurrentPosition() + imeCaretPosDoc);
if (IsHangul(preeditStr.at(0))) {
#ifndef Q_OS_WIN
if (imeCaretPos > 0) {
int oneCharBefore = sqt->pdoc->GetRelativePosition(sqt->CurrentPosition(), -1);
MoveImeCarets(- sqt->CurrentPosition() + oneCharBefore);
}
#endif
sqt->view.imeCaretBlockOverride = true;
}
sqt->EnsureCaretVisible();
}
sqt->ShowCaretAtCurrentPosition();
}
QVariant ScintillaEditBase::inputMethodQuery(Qt::InputMethodQuery query) const
{
const Scintilla::Position pos = send(SCI_GETCURRENTPOS);
const Scintilla::Position line = send(SCI_LINEFROMPOSITION, pos);
switch (query) {
#if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)
// Qt 5 renamed ImMicroFocus to ImCursorRectangle then deprecated
// ImMicroFocus. Its the same value (2) and same description.
case Qt::ImCursorRectangle:
{
const Scintilla::Position startPos = (preeditPos >= 0) ? preeditPos : pos;
const Point pt = sqt->LocationFromPosition(startPos);
const int width = static_cast<int>(send(SCI_GETCARETWIDTH));
const int height = static_cast<int>(send(SCI_TEXTHEIGHT, line));
return QRectF(pt.x, pt.y, width, height).toRect();
}
#else
case Qt::ImMicroFocus:
{
const Scintilla::Position startPos = (preeditPos >= 0) ? preeditPos : pos;
const Point pt = sqt->LocationFromPosition(startPos);
const int width = static_cast<int>(send(SCI_GETCARETWIDTH));
const int height = static_cast<int>(send(SCI_TEXTHEIGHT, line));
return QRect(pt.x, pt.y, width, height);
}
#endif
case Qt::ImFont:
{
char fontName[64];
const sptr_t style = send(SCI_GETSTYLEAT, pos);
const int len = static_cast<int>(sends(SCI_STYLEGETFONT, style, fontName));
const int size = static_cast<int>(send(SCI_STYLEGETSIZE, style));
const bool italic = send(SCI_STYLEGETITALIC, style);
const int weight = send(SCI_STYLEGETBOLD, style) ? QFont::Bold : -1;
return QFont(QString::fromUtf8(fontName, len), size, weight, italic);
}
case Qt::ImCursorPosition:
{
const Scintilla::Position paraStart = sqt->pdoc->ParaUp(pos);
return static_cast<int>(sqt->pdoc->CountUTF16(paraStart, pos));
}
case Qt::ImSurroundingText:
{
const Scintilla::Position paraStart = sqt->pdoc->ParaUp(pos);
const Scintilla::Position paraEnd = sqt->pdoc->ParaDown(pos);
const std::string buffer = sqt->RangeText(paraStart, paraEnd);
return sqt->StringFromDocument(buffer.c_str());
}
case Qt::ImCurrentSelection:
{
QVarLengthArray<char,1024> buffer(send(SCI_GETSELTEXT)+1);
sends(SCI_GETSELTEXT, 0, buffer.data());
return sqt->StringFromDocument(buffer.constData());
}
default:
return QVariant();
}
}
void ScintillaEditBase::notifyParent(NotificationData scn)
{
emit notify(&scn);
switch (scn.nmhdr.code) {
case Notification::StyleNeeded:
emit styleNeeded(scn.position);
break;
case Notification::CharAdded:
emit charAdded(scn.ch);
break;
case Notification::SavePointReached:
emit savePointChanged(false);
break;
case Notification::SavePointLeft:
emit savePointChanged(true);
break;
case Notification::ModifyAttemptRO:
emit modifyAttemptReadOnly();
break;
case Notification::Key:
emit key(scn.ch);
break;
case Notification::DoubleClick:
emit doubleClick(scn.position, scn.line);
break;
case Notification::UpdateUI:
if (FlagSet(scn.updated, Update::Selection)) {
updateMicroFocus();
}
emit updateUi(scn.updated);
break;
case Notification::Modified:
{
const bool added = FlagSet(scn.modificationType, ModificationFlags::InsertText);
const bool deleted = FlagSet(scn.modificationType, ModificationFlags::DeleteText);
const Scintilla::Position length = send(SCI_GETTEXTLENGTH);
bool firstLineAdded = (added && length == 1) ||
(deleted && length == 0);
if (scn.linesAdded != 0) {
emit linesAdded(scn.linesAdded);
} else if (firstLineAdded) {
emit linesAdded(added ? 1 : -1);
}
const QByteArray bytes = QByteArray::fromRawData(scn.text, scn.text ? scn.length : 0);
emit modified(scn.modificationType, scn.position, scn.length,
scn.linesAdded, bytes, scn.line,
scn.foldLevelNow, scn.foldLevelPrev);
break;
}
case Notification::MacroRecord:
emit macroRecord(scn.message, scn.wParam, scn.lParam);
break;
case Notification::MarginClick:
emit marginClicked(scn.position, scn.modifiers, scn.margin);
break;
case Notification::NeedShown:
emit needShown(scn.position, scn.length);
break;
case Notification::Painted:
emit painted();
break;
case Notification::UserListSelection:
emit userListSelection();
break;
case Notification::URIDropped:
emit uriDropped(QString::fromUtf8(scn.text));
break;
case Notification::DwellStart:
emit dwellStart(scn.x, scn.y);
break;
case Notification::DwellEnd:
emit dwellEnd(scn.x, scn.y);
break;
case Notification::Zoom:
emit zoom(send(SCI_GETZOOM));
break;
case Notification::HotSpotClick:
emit hotSpotClick(scn.position, scn.modifiers);
break;
case Notification::HotSpotDoubleClick:
emit hotSpotDoubleClick(scn.position, scn.modifiers);
break;
case Notification::CallTipClick:
emit callTipClick();
break;
case Notification::AutoCSelection:
emit autoCompleteSelection(scn.lParam, QString::fromUtf8(scn.text));
break;
case Notification::AutoCCancelled:
emit autoCompleteCancelled();
break;
case Notification::FocusIn:
emit focusChanged(true);
break;
case Notification::FocusOut:
emit focusChanged(false);
break;
default:
return;
}
}
void ScintillaEditBase::event_command(uptr_t wParam, sptr_t lParam)
{
emit command(wParam, lParam);
}
KeyMod ScintillaEditBase::ModifiersOfKeyboard()
{
const bool shift = QApplication::keyboardModifiers() & Qt::ShiftModifier;
const bool ctrl = QApplication::keyboardModifiers() & Qt::ControlModifier;
const bool alt = QApplication::keyboardModifiers() & Qt::AltModifier;
return ModifierFlags(shift, ctrl, alt);
}

View File

@ -0,0 +1,167 @@
//
// Copyright (c) 1990-2011, Scientific Toolworks, Inc.
//
// The License.txt file describes the conditions under which this software may be distributed.
//
// Author: Jason Haslam
//
// Additions Copyright (c) 2011 Archaeopteryx Software, Inc. d/b/a Wingware
// @file ScintillaEditBase.h - Qt widget that wraps ScintillaQt and provides events and scrolling
#ifndef SCINTILLAEDITBASE_H
#define SCINTILLAEDITBASE_H
#include <cstddef>
#include <string_view>
#include <vector>
#include <optional>
#include <memory>
#include "Debugging.h"
#include "Geometry.h"
#include "ScintillaTypes.h"
#include "ScintillaMessages.h"
#include "ScintillaStructures.h"
#include "Platform.h"
#include "Scintilla.h"
#include <QAbstractScrollArea>
#include <QMimeData>
#include <QElapsedTimer>
namespace Scintilla::Internal {
class ScintillaQt;
class SurfaceImpl;
}
#ifndef EXPORT_IMPORT_API
#ifdef WIN32
#ifdef MAKING_LIBRARY
#define EXPORT_IMPORT_API __declspec(dllexport)
#else
// Defining dllimport upsets moc
#define EXPORT_IMPORT_API __declspec(dllimport)
//#define EXPORT_IMPORT_API
#endif
#else
#define EXPORT_IMPORT_API
#endif
#endif
class EXPORT_IMPORT_API ScintillaEditBase : public QAbstractScrollArea {
Q_OBJECT
public:
explicit ScintillaEditBase(QWidget *parent = 0);
virtual ~ScintillaEditBase();
virtual sptr_t send(
unsigned int iMessage,
uptr_t wParam = 0,
sptr_t lParam = 0) const;
virtual sptr_t sends(
unsigned int iMessage,
uptr_t wParam = 0,
const char *s = 0) const;
public slots:
// Scroll events coming from GUI to be sent to Scintilla.
void scrollHorizontal(int value);
void scrollVertical(int value);
// Emit Scintilla notifications as signals.
void notifyParent(Scintilla::NotificationData scn);
void event_command(Scintilla::uptr_t wParam, Scintilla::sptr_t lParam);
signals:
void horizontalScrolled(int value);
void verticalScrolled(int value);
void horizontalRangeChanged(int max, int page);
void verticalRangeChanged(int max, int page);
void notifyChange();
void linesAdded(Scintilla::Position linesAdded);
// Clients can use this hook to add additional
// formats (e.g. rich text) to the MIME data.
void aboutToCopy(QMimeData *data);
// Scintilla Notifications
void styleNeeded(Scintilla::Position position);
void charAdded(int ch);
void savePointChanged(bool dirty);
void modifyAttemptReadOnly();
void key(int key);
void doubleClick(Scintilla::Position position, Scintilla::Position line);
void updateUi(Scintilla::Update updated);
void modified(Scintilla::ModificationFlags type, Scintilla::Position position, Scintilla::Position length, Scintilla::Position linesAdded,
const QByteArray &text, Scintilla::Position line, Scintilla::FoldLevel foldNow, Scintilla::FoldLevel foldPrev);
void macroRecord(Scintilla::Message message, Scintilla::uptr_t wParam, Scintilla::sptr_t lParam);
void marginClicked(Scintilla::Position position, Scintilla::KeyMod modifiers, int margin);
void textAreaClicked(Scintilla::Position line, int modifiers);
void needShown(Scintilla::Position position, Scintilla::Position length);
void painted();
void userListSelection(); // Wants some args.
void uriDropped(const QString &uri);
void dwellStart(int x, int y);
void dwellEnd(int x, int y);
void zoom(int zoom);
void hotSpotClick(Scintilla::Position position, Scintilla::KeyMod modifiers);
void hotSpotDoubleClick(Scintilla::Position position, Scintilla::KeyMod modifiers);
void callTipClick();
void autoCompleteSelection(Scintilla::Position position, const QString &text);
void autoCompleteCancelled();
void focusChanged(bool focused);
// Base notifications for compatibility with other Scintilla implementations
void notify(Scintilla::NotificationData *pscn);
void command(Scintilla::uptr_t wParam, Scintilla::sptr_t lParam);
// GUI event notifications needed under Qt
void buttonPressed(QMouseEvent *event);
void buttonReleased(QMouseEvent *event);
void keyPressed(QKeyEvent *event);
void resized();
protected:
bool event(QEvent *event) override;
void paintEvent(QPaintEvent *event) override;
void wheelEvent(QWheelEvent *event) override;
void focusInEvent(QFocusEvent *event) override;
void focusOutEvent(QFocusEvent *event) override;
void resizeEvent(QResizeEvent *event) override;
void keyPressEvent(QKeyEvent *event) override;
void mousePressEvent(QMouseEvent *event) override;
void mouseReleaseEvent(QMouseEvent *event) override;
void mouseDoubleClickEvent(QMouseEvent *event) override;
void mouseMoveEvent(QMouseEvent *event) override;
void contextMenuEvent(QContextMenuEvent *event) override;
void dragEnterEvent(QDragEnterEvent *event) override;
void dragLeaveEvent(QDragLeaveEvent *event) override;
void dragMoveEvent(QDragMoveEvent *event) override;
void dropEvent(QDropEvent *event) override;
void inputMethodEvent(QInputMethodEvent *event) override;
QVariant inputMethodQuery(Qt::InputMethodQuery query) const override;
void scrollContentsBy(int, int) override {}
private:
Scintilla::Internal::ScintillaQt *sqt;
QElapsedTimer time;
Scintilla::Position preeditPos;
QString preeditString;
int wheelDelta;
static bool IsHangul(const QChar qchar);
void MoveImeCarets(Scintilla::Position offset);
void DrawImeIndicator(int indicator, int len);
static Scintilla::KeyMod ModifiersOfKeyboard();
};
#endif /* SCINTILLAEDITBASE_H */

View File

@ -0,0 +1,107 @@
#-------------------------------------------------
#
# Project created by QtCreator 2011-05-05T12:41:23
#
#-------------------------------------------------
QT += core gui
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
equals(QT_MAJOR_VERSION, 6): QT += core5compat
TARGET = ScintillaEditBase
TEMPLATE = lib
CONFIG += lib_bundle
CONFIG += c++1z
VERSION = 5.5.0
SOURCES += \
PlatQt.cpp \
ScintillaQt.cpp \
ScintillaEditBase.cpp \
../../src/XPM.cxx \
../../src/ViewStyle.cxx \
../../src/UniqueString.cxx \
../../src/UniConversion.cxx \
../../src/UndoHistory.cxx \
../../src/Style.cxx \
../../src/Selection.cxx \
../../src/ScintillaBase.cxx \
../../src/RunStyles.cxx \
../../src/RESearch.cxx \
../../src/PositionCache.cxx \
../../src/PerLine.cxx \
../../src/MarginView.cxx \
../../src/LineMarker.cxx \
../../src/KeyMap.cxx \
../../src/Indicator.cxx \
../../src/Geometry.cxx \
../../src/EditView.cxx \
../../src/Editor.cxx \
../../src/EditModel.cxx \
../../src/Document.cxx \
../../src/Decoration.cxx \
../../src/DBCS.cxx \
../../src/ContractionState.cxx \
../../src/CharClassify.cxx \
../../src/CharacterType.cxx \
../../src/CharacterCategoryMap.cxx \
../../src/ChangeHistory.cxx \
../../src/CellBuffer.cxx \
../../src/CaseFolder.cxx \
../../src/CaseConvert.cxx \
../../src/CallTip.cxx \
../../src/AutoComplete.cxx
HEADERS += \
PlatQt.h \
ScintillaQt.h \
ScintillaEditBase.h \
../../src/XPM.h \
../../src/ViewStyle.h \
../../src/UndoHistory.h \
../../src/UniConversion.h \
../../src/Style.h \
../../src/SplitVector.h \
../../src/Selection.h \
../../src/ScintillaBase.h \
../../src/RunStyles.h \
../../src/RESearch.h \
../../src/PositionCache.h \
../../src/Platform.h \
../../src/PerLine.h \
../../src/Partitioning.h \
../../src/LineMarker.h \
../../src/KeyMap.h \
../../src/Indicator.h \
../../src/Geometry.h \
../../src/Editor.h \
../../src/Document.h \
../../src/Decoration.h \
../../src/ContractionState.h \
../../src/CharClassify.h \
../../src/CharacterType.h \
../../src/CharacterCategoryMap.h \
../../src/ChangeHistory.h \
../../src/CellBuffer.h \
../../src/CaseFolder.h \
../../src/CaseConvert.h \
../../src/CallTip.h \
../../src/AutoComplete.h \
../../include/Scintilla.h \
../../include/ILexer.h
OTHER_FILES +=
INCLUDEPATH += ../../include ../../src
DEFINES += SCINTILLA_QT=1 MAKING_LIBRARY=1
CONFIG(release, debug|release) {
DEFINES += NDEBUG=1
}
DESTDIR = ../../bin
macx {
QMAKE_LFLAGS_SONAME = -Wl,-install_name,@executable_path/../Frameworks/
}

View File

@ -0,0 +1,872 @@
//
// Copyright (c) 1990-2011, Scientific Toolworks, Inc.
//
// The License.txt file describes the conditions under which this software may be distributed.
//
// Author: Jason Haslam
//
// Additions Copyright (c) 2011 Archaeopteryx Software, Inc. d/b/a Wingware
// @file ScintillaQt.cpp - Qt specific subclass of ScintillaBase
#include "ScintillaQt.h"
#include "PlatQt.h"
#include <QApplication>
#include <QDrag>
#if QT_VERSION < QT_VERSION_CHECK(5, 0, 0)
#include <QInputContext>
#endif
#include <QMimeData>
#include <QMenu>
#include <QTextCodec>
#include <QScrollBar>
#include <QTimer>
using namespace Scintilla;
using namespace Scintilla::Internal;
ScintillaQt::ScintillaQt(QAbstractScrollArea *parent)
: QObject(parent), scrollArea(parent), vMax(0), hMax(0), vPage(0), hPage(0),
haveMouseCapture(false), dragWasDropped(false),
rectangularSelectionModifier(SCMOD_ALT)
{
wMain = scrollArea->viewport();
imeInteraction = IMEInteraction::Inline;
// On macOS drawing text into a pixmap moves it around 1 pixel to
// the right compared to drawing it directly onto a window.
// Buffered drawing turned off by default to avoid this.
view.bufferedDraw = false;
Init();
std::fill(timers, std::end(timers), 0);
}
ScintillaQt::~ScintillaQt()
{
CancelTimers();
ChangeIdle(false);
}
void ScintillaQt::execCommand(QAction *action)
{
const int commandNum = action->data().toInt();
Command(commandNum);
}
#if defined(Q_OS_WIN)
static const QString sMSDEVColumnSelect("MSDEVColumnSelect");
static const QString sWrappedMSDEVColumnSelect("application/x-qt-windows-mime;value=\"MSDEVColumnSelect\"");
static const QString sVSEditorLineCutCopy("VisualStudioEditorOperationsLineCutCopyClipboardTag");
static const QString sWrappedVSEditorLineCutCopy("application/x-qt-windows-mime;value=\"VisualStudioEditorOperationsLineCutCopyClipboardTag\"");
#elif defined(Q_OS_MAC)
static const QString sScintillaRecPboardType("com.scintilla.utf16-plain-text.rectangular");
static const QString sScintillaRecMimeType("text/x-scintilla.utf16-plain-text.rectangular");
#else
// Linux
static const QString sMimeRectangularMarker("text/x-rectangular-marker");
#endif
#if defined(Q_OS_MAC) && QT_VERSION < QT_VERSION_CHECK(5, 0, 0)
class ScintillaRectangularMime : public QMacPasteboardMime {
public:
ScintillaRectangularMime() : QMacPasteboardMime(MIME_ALL) {
}
QString convertorName() {
return QString("ScintillaRectangularMime");
}
bool canConvert(const QString &mime, QString flav) {
return mimeFor(flav) == mime;
}
QString mimeFor(QString flav) {
if (flav == sScintillaRecPboardType)
return sScintillaRecMimeType;
return QString();
}
QString flavorFor(const QString &mime) {
if (mime == sScintillaRecMimeType)
return sScintillaRecPboardType;
return QString();
}
QVariant convertToMime(const QString & /* mime */, QList<QByteArray> data, QString /* flav */) {
QByteArray all;
foreach (QByteArray i, data) {
all += i;
}
return QVariant(all);
}
QList<QByteArray> convertFromMime(const QString & /* mime */, QVariant data, QString /* flav */) {
QByteArray a = data.toByteArray();
QList<QByteArray> l;
l.append(a);
return l;
}
};
// The Mime object registers itself but only want one for all Scintilla instances.
// Should delete at exit to help memory leak detection but that would be extra work
// and, since the clipboard exists after last Scintilla instance, may be complex.
static ScintillaRectangularMime *singletonMime = 0;
#endif
void ScintillaQt::Init()
{
rectangularSelectionModifier = SCMOD_ALT;
#if defined(Q_OS_MAC) && QT_VERSION < QT_VERSION_CHECK(5, 0, 0)
if (!singletonMime) {
singletonMime = new ScintillaRectangularMime();
QStringList slTypes(sScintillaRecPboardType);
qRegisterDraggedTypes(slTypes);
}
#endif
connect(QApplication::clipboard(), SIGNAL(selectionChanged()),
this, SLOT(SelectionChanged()));
}
void ScintillaQt::Finalise()
{
CancelTimers();
ScintillaBase::Finalise();
}
void ScintillaQt::SelectionChanged()
{
bool nowPrimary = QApplication::clipboard()->ownsSelection();
if (nowPrimary != primarySelection) {
primarySelection = nowPrimary;
Redraw();
}
}
bool ScintillaQt::DragThreshold(Point ptStart, Point ptNow)
{
int xMove = std::abs(ptStart.x - ptNow.x);
int yMove = std::abs(ptStart.y - ptNow.y);
return (xMove > QApplication::startDragDistance()) ||
(yMove > QApplication::startDragDistance());
}
static QString StringFromSelectedText(const SelectionText &selectedText)
{
if (selectedText.codePage == SC_CP_UTF8) {
return QString::fromUtf8(selectedText.Data(), static_cast<int>(selectedText.Length()));
} else {
QTextCodec *codec = QTextCodec::codecForName(
CharacterSetID(selectedText.characterSet));
return codec->toUnicode(selectedText.Data(), static_cast<int>(selectedText.Length()));
}
}
static void AddRectangularToMime(QMimeData *mimeData, [[maybe_unused]] const QString &su)
{
#if defined(Q_OS_WIN)
// Add an empty marker
mimeData->setData(sMSDEVColumnSelect, QByteArray());
#elif defined(Q_OS_MAC)
// macOS gets marker + data to work with other implementations.
// Don't understand how this works but it does - the
// clipboard format is supposed to be UTF-16, not UTF-8.
mimeData->setData(sScintillaRecMimeType, su.toUtf8());
#else
// Linux
// Add an empty marker
mimeData->setData(sMimeRectangularMarker, QByteArray());
#endif
}
static void AddLineCutCopyToMime([[maybe_unused]] QMimeData *mimeData)
{
#if defined(Q_OS_WIN)
// Add an empty marker
mimeData->setData(sVSEditorLineCutCopy, QByteArray());
#endif
}
static bool IsRectangularInMime(const QMimeData *mimeData)
{
QStringList formats = mimeData->formats();
for (int i = 0; i < formats.size(); ++i) {
#if defined(Q_OS_WIN)
// Windows rectangular markers
// If rectangular copies made by this application, see base name.
if (formats[i] == sMSDEVColumnSelect)
return true;
// Otherwise see wrapped name.
if (formats[i] == sWrappedMSDEVColumnSelect)
return true;
#elif defined(Q_OS_MAC)
if (formats[i] == sScintillaRecMimeType)
return true;
#else
// Linux
if (formats[i] == sMimeRectangularMarker)
return true;
#endif
}
return false;
}
static bool IsLineCutCopyInMime(const QMimeData *mimeData)
{
QStringList formats = mimeData->formats();
for (int i = 0; i < formats.size(); ++i) {
#if defined(Q_OS_WIN)
// Visual Studio Line Cut/Copy markers
// If line cut/copy made by this application, see base name.
if (formats[i] == sVSEditorLineCutCopy)
return true;
// Otherwise see wrapped name.
if (formats[i] == sWrappedVSEditorLineCutCopy)
return true;
#endif
}
return false;
}
bool ScintillaQt::ValidCodePage(int codePage) const
{
return codePage == 0
|| codePage == SC_CP_UTF8
|| codePage == 932
|| codePage == 936
|| codePage == 949
|| codePage == 950
|| codePage == 1361;
}
std::string ScintillaQt::UTF8FromEncoded(std::string_view encoded) const {
if (IsUnicodeMode()) {
return std::string(encoded);
} else {
QTextCodec *codec = QTextCodec::codecForName(
CharacterSetID(CharacterSetOfDocument()));
QString text = codec->toUnicode(encoded.data(), static_cast<int>(encoded.length()));
return text.toStdString();
}
}
std::string ScintillaQt::EncodedFromUTF8(std::string_view utf8) const {
if (IsUnicodeMode()) {
return std::string(utf8);
} else {
QString text = QString::fromUtf8(utf8.data(), static_cast<int>(utf8.length()));
QTextCodec *codec = QTextCodec::codecForName(
CharacterSetID(CharacterSetOfDocument()));
QByteArray ba = codec->fromUnicode(text);
return std::string(ba.data(), ba.length());
}
}
void ScintillaQt::ScrollText(Sci::Line linesToMove)
{
int dy = vs.lineHeight * (linesToMove);
scrollArea->viewport()->scroll(0, dy);
}
void ScintillaQt::SetVerticalScrollPos()
{
scrollArea->verticalScrollBar()->setValue(topLine);
emit verticalScrolled(topLine);
}
void ScintillaQt::SetHorizontalScrollPos()
{
scrollArea->horizontalScrollBar()->setValue(xOffset);
emit horizontalScrolled(xOffset);
}
bool ScintillaQt::ModifyScrollBars(Sci::Line nMax, Sci::Line nPage)
{
bool modified = false;
int vNewPage = nPage;
int vNewMax = nMax - vNewPage + 1;
if (vMax != vNewMax || vPage != vNewPage) {
vMax = vNewMax;
vPage = vNewPage;
modified = true;
scrollArea->verticalScrollBar()->setMaximum(vMax);
scrollArea->verticalScrollBar()->setPageStep(vPage);
emit verticalRangeChanged(vMax, vPage);
}
int hNewPage = GetTextRectangle().Width();
int hNewMax = (scrollWidth > hNewPage) ? scrollWidth - hNewPage : 0;
int charWidth = vs.styles[STYLE_DEFAULT].aveCharWidth;
if (hMax != hNewMax || hPage != hNewPage ||
scrollArea->horizontalScrollBar()->singleStep() != charWidth) {
hMax = hNewMax;
hPage = hNewPage;
modified = true;
scrollArea->horizontalScrollBar()->setMaximum(hMax);
scrollArea->horizontalScrollBar()->setPageStep(hPage);
scrollArea->horizontalScrollBar()->setSingleStep(charWidth);
emit horizontalRangeChanged(hMax, hPage);
}
return modified;
}
void ScintillaQt::ReconfigureScrollBars()
{
if (verticalScrollBarVisible) {
scrollArea->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded);
} else {
scrollArea->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
}
if (horizontalScrollBarVisible && !Wrapping()) {
scrollArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded);
} else {
scrollArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
}
}
void ScintillaQt::CopyToModeClipboard(const SelectionText &selectedText, QClipboard::Mode clipboardMode_)
{
QClipboard *clipboard = QApplication::clipboard();
QString su = StringFromSelectedText(selectedText);
QMimeData *mimeData = new QMimeData();
mimeData->setText(su);
if (selectedText.rectangular) {
AddRectangularToMime(mimeData, su);
}
if (selectedText.lineCopy) {
AddLineCutCopyToMime(mimeData);
}
// Allow client code to add additional data (e.g rich text).
emit aboutToCopy(mimeData);
clipboard->setMimeData(mimeData, clipboardMode_);
}
void ScintillaQt::Copy()
{
if (!sel.Empty()) {
SelectionText st;
CopySelectionRange(&st);
CopyToClipboard(st);
}
}
void ScintillaQt::CopyToClipboard(const SelectionText &selectedText)
{
CopyToModeClipboard(selectedText, QClipboard::Clipboard);
}
void ScintillaQt::PasteFromMode(QClipboard::Mode clipboardMode_)
{
QClipboard *clipboard = QApplication::clipboard();
const QMimeData *mimeData = clipboard->mimeData(clipboardMode_);
bool isRectangular = IsRectangularInMime(mimeData);
bool isLine = SelectionEmpty() && IsLineCutCopyInMime(mimeData);
QString text = clipboard->text(clipboardMode_);
QByteArray utext = BytesForDocument(text);
std::string dest(utext.constData(), utext.length());
SelectionText selText;
selText.Copy(dest, pdoc->dbcsCodePage, CharacterSetOfDocument(), isRectangular, false);
UndoGroup ug(pdoc);
ClearSelection(multiPasteMode == MultiPaste::Each);
InsertPasteShape(selText.Data(), selText.Length(),
isRectangular ? PasteShape::rectangular : (isLine ? PasteShape::line : PasteShape::stream));
EnsureCaretVisible();
}
void ScintillaQt::Paste()
{
PasteFromMode(QClipboard::Clipboard);
}
void ScintillaQt::ClaimSelection()
{
if (QApplication::clipboard()->supportsSelection()) {
// X Windows has a 'primary selection' as well as the clipboard.
// Whenever the user selects some text, we become the primary selection
if (!sel.Empty()) {
primarySelection = true;
SelectionText st;
CopySelectionRange(&st);
CopyToModeClipboard(st, QClipboard::Selection);
} else {
primarySelection = false;
}
}
}
void ScintillaQt::NotifyChange()
{
emit notifyChange();
emit command(
Platform::LongFromTwoShorts(GetCtrlID(), SCEN_CHANGE),
reinterpret_cast<sptr_t>(wMain.GetID()));
}
void ScintillaQt::NotifyFocus(bool focus)
{
if (commandEvents) {
emit command(
Platform::LongFromTwoShorts
(GetCtrlID(), focus ? SCEN_SETFOCUS : SCEN_KILLFOCUS),
reinterpret_cast<sptr_t>(wMain.GetID()));
}
Editor::NotifyFocus(focus);
}
void ScintillaQt::NotifyParent(NotificationData scn)
{
scn.nmhdr.hwndFrom = wMain.GetID();
scn.nmhdr.idFrom = GetCtrlID();
emit notifyParent(scn);
}
void ScintillaQt::NotifyURIDropped(const char *uri)
{
NotificationData scn = {};
scn.nmhdr.code = Notification::URIDropped;
scn.text = uri;
NotifyParent(scn);
}
bool ScintillaQt::FineTickerRunning(TickReason reason)
{
return timers[static_cast<size_t>(reason)] != 0;
}
void ScintillaQt::FineTickerStart(TickReason reason, int millis, int /* tolerance */)
{
FineTickerCancel(reason);
timers[static_cast<size_t>(reason)] = startTimer(millis);
}
// CancelTimers cleans up all fine-ticker timers and is non-virtual to avoid warnings when
// called during destruction.
void ScintillaQt::CancelTimers()
{
for (size_t tr = static_cast<size_t>(TickReason::caret); tr <= static_cast<size_t>(TickReason::dwell); tr++) {
if (timers[tr]) {
killTimer(timers[tr]);
timers[tr] = 0;
}
}
}
void ScintillaQt::FineTickerCancel(TickReason reason)
{
const size_t reasonIndex = static_cast<size_t>(reason);
if (timers[reasonIndex]) {
killTimer(timers[reasonIndex]);
timers[reasonIndex] = 0;
}
}
void ScintillaQt::onIdle()
{
bool continueIdling = Idle();
if (!continueIdling) {
SetIdle(false);
}
}
bool ScintillaQt::ChangeIdle(bool on)
{
if (on) {
// Start idler, if it's not running.
if (!idler.state) {
idler.state = true;
QTimer *qIdle = new QTimer;
connect(qIdle, SIGNAL(timeout()), this, SLOT(onIdle()));
qIdle->start(0);
idler.idlerID = qIdle;
}
} else {
// Stop idler, if it's running
if (idler.state) {
idler.state = false;
QTimer *qIdle = static_cast<QTimer *>(idler.idlerID);
qIdle->stop();
disconnect(qIdle, SIGNAL(timeout()), nullptr, nullptr);
delete qIdle;
idler.idlerID = {};
}
}
return true;
}
bool ScintillaQt::SetIdle(bool on)
{
return ChangeIdle(on);
}
CharacterSet ScintillaQt::CharacterSetOfDocument() const
{
return vs.styles[STYLE_DEFAULT].characterSet;
}
const char *ScintillaQt::CharacterSetIDOfDocument() const
{
return CharacterSetID(CharacterSetOfDocument());
}
QString ScintillaQt::StringFromDocument(const char *s) const
{
if (IsUnicodeMode()) {
return QString::fromUtf8(s);
} else {
QTextCodec *codec = QTextCodec::codecForName(
CharacterSetID(CharacterSetOfDocument()));
return codec->toUnicode(s);
}
}
QByteArray ScintillaQt::BytesForDocument(const QString &text) const
{
if (IsUnicodeMode()) {
return text.toUtf8();
} else {
QTextCodec *codec = QTextCodec::codecForName(
CharacterSetID(CharacterSetOfDocument()));
return codec->fromUnicode(text);
}
}
namespace {
class CaseFolderDBCS : public CaseFolderTable {
QTextCodec *codec;
public:
explicit CaseFolderDBCS(QTextCodec *codec_) : codec(codec_) {
}
size_t Fold(char *folded, size_t sizeFolded, const char *mixed, size_t lenMixed) override {
if ((lenMixed == 1) && (sizeFolded > 0)) {
folded[0] = mapping[static_cast<unsigned char>(mixed[0])];
return 1;
} else if (codec) {
QString su = codec->toUnicode(mixed, static_cast<int>(lenMixed));
QString suFolded = su.toCaseFolded();
QByteArray bytesFolded = codec->fromUnicode(suFolded);
if (bytesFolded.length() < static_cast<int>(sizeFolded)) {
memcpy(folded, bytesFolded, bytesFolded.length());
return bytesFolded.length();
}
}
// Something failed so return a single NUL byte
folded[0] = '\0';
return 1;
}
};
}
std::unique_ptr<CaseFolder> ScintillaQt::CaseFolderForEncoding()
{
if (pdoc->dbcsCodePage == SC_CP_UTF8) {
return std::make_unique<CaseFolderUnicode>();
} else {
const char *charSetBuffer = CharacterSetIDOfDocument();
if (charSetBuffer) {
if (pdoc->dbcsCodePage == 0) {
std::unique_ptr<CaseFolderTable> pcf = std::make_unique<CaseFolderTable>();
QTextCodec *codec = QTextCodec::codecForName(charSetBuffer);
// Only for single byte encodings
for (int i=0x80; i<0x100; i++) {
char sCharacter[2] = "A";
sCharacter[0] = static_cast<char>(i);
QString su = codec->toUnicode(sCharacter, 1);
QString suFolded = su.toCaseFolded();
if (codec->canEncode(suFolded)) {
QByteArray bytesFolded = codec->fromUnicode(suFolded);
if (bytesFolded.length() == 1) {
pcf->SetTranslation(sCharacter[0], bytesFolded[0]);
}
}
}
return pcf;
} else {
return std::make_unique<CaseFolderDBCS>(QTextCodec::codecForName(charSetBuffer));
}
}
return nullptr;
}
}
std::string ScintillaQt::CaseMapString(const std::string &s, CaseMapping caseMapping)
{
if (s.empty() || (caseMapping == CaseMapping::same))
return s;
if (IsUnicodeMode()) {
std::string retMapped(s.length() * maxExpansionCaseConversion, 0);
size_t lenMapped = CaseConvertString(&retMapped[0], retMapped.length(), s.c_str(), s.length(),
(caseMapping == CaseMapping::upper) ? CaseConversion::upper : CaseConversion::lower);
retMapped.resize(lenMapped);
return retMapped;
}
QTextCodec *codec = QTextCodec::codecForName(CharacterSetIDOfDocument());
QString text = codec->toUnicode(s.c_str(), static_cast<int>(s.length()));
if (caseMapping == CaseMapping::upper) {
text = text.toUpper();
} else {
text = text.toLower();
}
QByteArray bytes = BytesForDocument(text);
return std::string(bytes.data(), bytes.length());
}
void ScintillaQt::SetMouseCapture(bool on)
{
// This is handled automatically by Qt
if (mouseDownCaptures) {
haveMouseCapture = on;
}
}
bool ScintillaQt::HaveMouseCapture()
{
return haveMouseCapture;
}
void ScintillaQt::StartDrag()
{
inDragDrop = DragDrop::dragging;
dropWentOutside = true;
if (drag.Length()) {
QMimeData *mimeData = new QMimeData;
QString sText = StringFromSelectedText(drag);
mimeData->setText(sText);
if (drag.rectangular) {
AddRectangularToMime(mimeData, sText);
}
// This QDrag is not freed as that causes a crash on Linux
QDrag *dragon = new QDrag(scrollArea);
dragon->setMimeData(mimeData);
Qt::DropAction dropAction = dragon->exec(static_cast<Qt::DropActions>(Qt::CopyAction|Qt::MoveAction));
if ((dropAction == Qt::MoveAction) && dropWentOutside) {
// Remove dragged out text
ClearSelection();
}
}
inDragDrop = DragDrop::none;
SetDragPosition(SelectionPosition(Sci::invalidPosition));
}
class CallTipImpl : public QWidget {
public:
explicit CallTipImpl(CallTip *pct_)
: QWidget(nullptr, Qt::ToolTip),
pct(pct_)
{
#if QT_VERSION >= QT_VERSION_CHECK(5, 9, 0)
setWindowFlag(Qt::WindowTransparentForInput);
#endif
}
void paintEvent(QPaintEvent *) override
{
if (pct->inCallTipMode) {
std::unique_ptr<Surface> surfaceWindow = Surface::Allocate(Technology::Default);
surfaceWindow->Init(this);
surfaceWindow->SetMode(SurfaceMode(pct->codePage, false));
pct->PaintCT(surfaceWindow.get());
}
}
private:
CallTip *pct;
};
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());
}
}
void ScintillaQt::AddToPopUp(const char *label,
int cmd,
bool enabled)
{
QMenu *menu = static_cast<QMenu *>(popup.GetID());
QString text(label);
if (text.isEmpty()) {
menu->addSeparator();
} else {
QAction *action = menu->addAction(text);
action->setData(cmd);
action->setEnabled(enabled);
}
// Make sure the menu's signal is connected only once.
menu->disconnect();
connect(menu, SIGNAL(triggered(QAction*)),
this, SLOT(execCommand(QAction*)));
}
sptr_t ScintillaQt::WndProc(Message iMessage, uptr_t wParam, sptr_t lParam)
{
try {
switch (iMessage) {
case Message::SetIMEInteraction:
// Only inline IME supported on Qt
break;
case Message::GrabFocus:
scrollArea->setFocus(Qt::OtherFocusReason);
break;
case Message::GetDirectFunction:
return reinterpret_cast<sptr_t>(DirectFunction);
case Message::GetDirectStatusFunction:
return reinterpret_cast<sptr_t>(DirectStatusFunction);
case Message::GetDirectPointer:
return reinterpret_cast<sptr_t>(this);
case Message::SetRectangularSelectionModifier:
rectangularSelectionModifier = static_cast<int>(wParam);
break;
case Message::GetRectangularSelectionModifier:
return rectangularSelectionModifier;
default:
return ScintillaBase::WndProc(iMessage, wParam, lParam);
}
} catch (std::bad_alloc &) {
errorStatus = Status::BadAlloc;
} catch (...) {
errorStatus = Status::Failure;
}
return 0;
}
sptr_t ScintillaQt::DefWndProc(Message, uptr_t, sptr_t)
{
return 0;
}
sptr_t ScintillaQt::DirectFunction(
sptr_t ptr, unsigned int iMessage, uptr_t wParam, sptr_t lParam)
{
ScintillaQt *sci = reinterpret_cast<ScintillaQt *>(ptr);
return sci->WndProc(static_cast<Message>(iMessage), wParam, lParam);
}
sptr_t ScintillaQt::DirectStatusFunction(
sptr_t ptr, unsigned int iMessage, uptr_t wParam, sptr_t lParam, int *pStatus)
{
ScintillaQt *sci = reinterpret_cast<ScintillaQt *>(ptr);
const sptr_t returnValue = sci->WndProc(static_cast<Message>(iMessage), wParam, lParam);
*pStatus = static_cast<int>(sci->errorStatus);
return returnValue;
}
// Additions to merge in Scientific Toolworks widget structure
void ScintillaQt::PartialPaint(const PRectangle &rect)
{
rcPaint = rect;
paintState = PaintState::painting;
PRectangle rcClient = GetClientRectangle();
paintingAllText = rcPaint.Contains(rcClient);
AutoSurface surfacePaint(this);
Paint(surfacePaint, rcPaint);
surfacePaint->Release();
if (paintState == PaintState::abandoned) {
// FIXME: Failure to paint the requested rectangle in each
// paint event causes flicker on some platforms (Mac?)
// Paint rect immediately.
paintState = PaintState::painting;
paintingAllText = true;
AutoSurface surface(this);
Paint(surface, rcPaint);
surface->Release();
// Queue a full repaint.
scrollArea->viewport()->update();
}
paintState = PaintState::notPainting;
}
void ScintillaQt::DragEnter(const Point &point)
{
SetDragPosition(SPositionFromLocation(point,
false, false, UserVirtualSpace()));
}
void ScintillaQt::DragMove(const Point &point)
{
SetDragPosition(SPositionFromLocation(point,
false, false, UserVirtualSpace()));
}
void ScintillaQt::DragLeave()
{
SetDragPosition(SelectionPosition(Sci::invalidPosition));
}
void ScintillaQt::Drop(const Point &point, const QMimeData *data, bool move)
{
QString text = data->text();
bool rectangular = IsRectangularInMime(data);
QByteArray bytes = BytesForDocument(text);
int len = bytes.length();
SelectionPosition movePos = SPositionFromLocation(point,
false, false, UserVirtualSpace());
DropAt(movePos, bytes, len, move, rectangular);
}
void ScintillaQt::DropUrls(const QMimeData *data)
{
foreach(const QUrl &url, data->urls()) {
NotifyURIDropped(url.toString().toUtf8().constData());
}
}
void ScintillaQt::timerEvent(QTimerEvent *event)
{
for (size_t tr=static_cast<size_t>(TickReason::caret); tr<=static_cast<size_t>(TickReason::dwell); tr++) {
if (timers[tr] == event->timerId()) {
TickFor(static_cast<TickReason>(tr));
}
}
}

View File

@ -0,0 +1,185 @@
//
// Copyright (c) 1990-2011, Scientific Toolworks, Inc.
//
// The License.txt file describes the conditions under which this software may be distributed.
//
// Author: Jason Haslam
//
// Additions Copyright (c) 2011 Archaeopteryx Software, Inc. d/b/a Wingware
// @file ScintillaQt.h - Qt specific subclass of ScintillaBase
#ifndef SCINTILLAQT_H
#define SCINTILLAQT_H
#include <cstddef>
#include <cstdlib>
#include <cstdint>
#include <cassert>
#include <cstring>
#include <cctype>
#include <cstdio>
#include <ctime>
#include <cmath>
#include <stdexcept>
#include <string>
#include <string_view>
#include <vector>
#include <map>
#include <set>
#include <optional>
#include <algorithm>
#include <memory>
#include "ScintillaTypes.h"
#include "ScintillaMessages.h"
#include "ScintillaStructures.h"
#include "Scintilla.h"
#include "Debugging.h"
#include "Geometry.h"
#include "Platform.h"
#include "ILoader.h"
#include "ILexer.h"
#include "CharacterCategoryMap.h"
#include "Position.h"
#include "UniqueString.h"
#include "SplitVector.h"
#include "Partitioning.h"
#include "RunStyles.h"
#include "ContractionState.h"
#include "CellBuffer.h"
#include "CallTip.h"
#include "KeyMap.h"
#include "Indicator.h"
#include "LineMarker.h"
#include "Style.h"
#include "AutoComplete.h"
#include "ViewStyle.h"
#include "CharClassify.h"
#include "Decoration.h"
#include "CaseFolder.h"
#include "Document.h"
#include "Selection.h"
#include "PositionCache.h"
#include "EditModel.h"
#include "MarginView.h"
#include "EditView.h"
#include "Editor.h"
#include "ScintillaBase.h"
#include "CaseConvert.h"
#include <QObject>
#include <QAbstractScrollArea>
#include <QAction>
#include <QClipboard>
#include <QPaintEvent>
class ScintillaEditBase;
namespace Scintilla::Internal {
class ScintillaQt : public QObject, public ScintillaBase {
Q_OBJECT
public:
explicit ScintillaQt(QAbstractScrollArea *parent);
virtual ~ScintillaQt();
signals:
void horizontalScrolled(int value);
void verticalScrolled(int value);
void horizontalRangeChanged(int max, int page);
void verticalRangeChanged(int max, int page);
void notifyParent(Scintilla::NotificationData scn);
void notifyChange();
// Clients can use this hook to add additional
// formats (e.g. rich text) to the MIME data.
void aboutToCopy(QMimeData *data);
void command(Scintilla::uptr_t wParam, Scintilla::sptr_t lParam);
private slots:
void onIdle();
void execCommand(QAction *action);
void SelectionChanged();
private:
void Init();
void Finalise() override;
bool DragThreshold(Point ptStart, Point ptNow) override;
bool ValidCodePage(int codePage) const override;
std::string UTF8FromEncoded(std::string_view encoded) const override;
std::string EncodedFromUTF8(std::string_view utf8) const override;
private:
void ScrollText(Sci::Line linesToMove) override;
void SetVerticalScrollPos() override;
void SetHorizontalScrollPos() override;
bool ModifyScrollBars(Sci::Line nMax, Sci::Line nPage) override;
void ReconfigureScrollBars() override;
void CopyToModeClipboard(const SelectionText &selectedText, QClipboard::Mode clipboardMode_);
void Copy() override;
void CopyToClipboard(const SelectionText &selectedText) override;
void PasteFromMode(QClipboard::Mode clipboardMode_);
void Paste() override;
void ClaimSelection() override;
void NotifyChange() override;
void NotifyFocus(bool focus) override;
void NotifyParent(Scintilla::NotificationData scn) override;
void NotifyURIDropped(const char *uri);
int timers[static_cast<size_t>(TickReason::dwell)+1]{};
bool FineTickerRunning(TickReason reason) override;
void FineTickerStart(TickReason reason, int millis, int tolerance) override;
void CancelTimers();
void FineTickerCancel(TickReason reason) override;
bool ChangeIdle(bool on);
bool SetIdle(bool on) override;
void SetMouseCapture(bool on) override;
bool HaveMouseCapture() override;
void StartDrag() override;
Scintilla::CharacterSet CharacterSetOfDocument() const;
const char *CharacterSetIDOfDocument() const;
QString StringFromDocument(const char *s) const;
QByteArray BytesForDocument(const QString &text) const;
std::unique_ptr<CaseFolder> CaseFolderForEncoding() override;
std::string CaseMapString(const std::string &s, CaseMapping caseMapping) override;
void CreateCallTipWindow(PRectangle rc) override;
void AddToPopUp(const char *label, int cmd, bool enabled) override;
sptr_t WndProc(Scintilla::Message iMessage, uptr_t wParam, sptr_t lParam) override;
sptr_t DefWndProc(Scintilla::Message iMessage, uptr_t wParam, sptr_t lParam) override;
static sptr_t DirectFunction(sptr_t ptr,
unsigned int iMessage, uptr_t wParam, sptr_t lParam);
static sptr_t DirectStatusFunction(sptr_t ptr,
unsigned int iMessage, uptr_t wParam, sptr_t lParam, int *pStatus);
protected:
void PartialPaint(const PRectangle &rect);
void DragEnter(const Point &point);
void DragMove(const Point &point);
void DragLeave();
void Drop(const Point &point, const QMimeData *data, bool move);
void DropUrls(const QMimeData *data);
void timerEvent(QTimerEvent *event) override;
private:
QAbstractScrollArea *scrollArea;
int vMax, hMax; // Scroll bar maximums.
int vPage, hPage; // Scroll bar page sizes.
bool haveMouseCapture;
bool dragWasDropped;
int rectangularSelectionModifier;
friend class ::ScintillaEditBase;
};
}
#endif /* SCINTILLAQT_H */