notepad-plus-plus/scintilla/qt/ScintillaEditBase/PlatQt.cpp

1387 lines
38 KiB
C++
Raw Normal View History

// @file PlatQt.cpp
// 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
2019-05-04 20:14:48 +02:00
#include <cstdio>
#include "PlatQt.h"
#include "Scintilla.h"
Update to Scintilla 5.3.2 and Lexilla 5.2.1 update to https://www.scintilla.org/scintilla532.zip with: Released 6 December 2022. Add SCI_REPLACETARGETMINIMAL to change text without causing unchanged prefix and suffix to be marked as modified in change history. Draw background colour for EOL annotations with standard and boxed visuals. Add SCI_GETSTYLEDTEXTFULL to support 64-bit document positions on Win32 replacing SCI_GETSTYLEDTEXT which is not safe for huge documents. Feature #1455. Send SCN_AUTOCCOMPLETED for SCI_AUTOCSHOW triggering insertion because of SCI_AUTOCSETCHOOSESINGLE mode. Feature #1459. Change 'paragraph up' commands SCI_PARAUP and SCI_PARAUPEXTEND to go to the start position of the paragraph containing the caret. Only if the caret is already at the start of the paragraph will it go to the start of the previous paragraph. Bug #2363. Change release compilation optimization option to favour speed over space. -O2 for MSVC and -O3 for gcc and clang. On Win32, avoid blurry display with DirectWrite in GDI scaling mode. Bug #2344. On Win32, use the top-level window to find the monitor for DirectWrite rendering parameters. Temporarily switch DPI awareness to find correct monitor in GDI scaling mode. Bug #2344. On Qt, implement SCI_SETRECTANGULARSELECTIONMODIFIER for all platforms. On Qt, allow string form XPM images for SCI_REGISTERIMAGE. and https://www.scintilla.org/lexilla521.zip with Released 6 December 2022. Update to Unicode 14. Feature #1461. Change default compilation optimization option to favour speed over space. -O2 for MSVC and -O3 for gcc and clang. Batch: Fix comments starting inside strings. Issue #115. F#: Lex signed numeric literals more accurately. Issue #110, Issue #111. F#: Add specifiers for 64-bit integer and floating point literals. Issue #112. Markdown: Stop styling numbers at line start in PRECHAR style. Issue #117. PowerShell: Recognise numeric literals more accurately. Issue #118. Close #12624
2022-12-10 13:35:16 +01:00
#include "XPM.h"
2019-05-04 20:14:48 +02:00
#include "UniConversion.h"
#include "DBCS.h"
#include <QApplication>
#if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)
#include <QScreen>
#endif
#include <QFont>
#include <QColor>
#include <QRect>
#include <QPaintDevice>
#include <QPaintEngine>
#include <QWidget>
#include <QPixmap>
#include <QPainter>
#include <QPainterPath>
#include <QMenu>
#include <QAction>
#include <QTime>
#include <QMessageBox>
#include <QTextCodec>
#include <QListWidget>
#include <QVarLengthArray>
#include <QScrollBar>
#include <QTextLayout>
#include <QTextLine>
#include <QLibrary>
using namespace Scintilla;
namespace Scintilla::Internal {
//----------------------------------------------------------------------
// Convert from a Scintilla characterSet value to a Qt codec name.
const char *CharacterSetID(CharacterSet characterSet)
{
switch (characterSet) {
//case CharacterSet::Ansi:
// return "";
case CharacterSet::Default:
return "ISO 8859-1";
case CharacterSet::Baltic:
return "ISO 8859-13";
case CharacterSet::ChineseBig5:
return "Big5";
case CharacterSet::EastEurope:
return "ISO 8859-2";
case CharacterSet::GB2312:
return "GB18030-0";
case CharacterSet::Greek:
return "ISO 8859-7";
case CharacterSet::Hangul:
return "CP949";
case CharacterSet::Mac:
return "Apple Roman";
//case SC_CHARSET_OEM:
// return "ASCII";
case CharacterSet::Russian:
return "KOI8-R";
case CharacterSet::Cyrillic:
return "Windows-1251";
case CharacterSet::ShiftJis:
return "Shift-JIS";
//case SC_CHARSET_SYMBOL:
// return "";
case CharacterSet::Turkish:
return "ISO 8859-9";
//case SC_CHARSET_JOHAB:
// return "CP1361";
case CharacterSet::Hebrew:
return "ISO 8859-8";
case CharacterSet::Arabic:
return "ISO 8859-6";
case CharacterSet::Vietnamese:
return "Windows-1258";
case CharacterSet::Thai:
return "TIS-620";
case CharacterSet::Iso8859_15:
return "ISO 8859-15";
default:
return "ISO 8859-1";
}
}
2019-05-04 20:14:48 +02:00
QString UnicodeFromText(QTextCodec *codec, std::string_view text) {
return codec->toUnicode(text.data(), static_cast<int>(text.length()));
}
static QFont::StyleStrategy ChooseStrategy(FontQuality eff)
{
switch (eff) {
case FontQuality::QualityDefault: return QFont::PreferDefault;
case FontQuality::QualityNonAntialiased: return QFont::NoAntialias;
case FontQuality::QualityAntialiased: return QFont::PreferAntialias;
case FontQuality::QualityLcdOptimized: return QFont::PreferAntialias;
default: return QFont::PreferDefault;
}
}
static QFont::Stretch QStretchFromFontStretch(Scintilla::FontStretch stretch)
{
switch (stretch) {
case FontStretch::UltraCondensed:
return QFont::Stretch::UltraCondensed;
case FontStretch::ExtraCondensed:
return QFont::Stretch::ExtraCondensed;
case FontStretch::Condensed:
return QFont::Stretch::Condensed;
case FontStretch::SemiCondensed:
return QFont::Stretch::SemiCondensed;
case FontStretch::Normal:
return QFont::Stretch::Unstretched;
case FontStretch::SemiExpanded:
return QFont::Stretch::SemiExpanded;
case FontStretch::Expanded:
return QFont::Stretch::Expanded;
case FontStretch::ExtraExpanded:
return QFont::Stretch::ExtraExpanded;
case FontStretch::UltraExpanded:
return QFont::Stretch::UltraExpanded;
default:
return QFont::Stretch::Unstretched;
}
}
class FontAndCharacterSet : public Font {
public:
CharacterSet characterSet = CharacterSet::Ansi;
std::unique_ptr<QFont> pfont;
explicit FontAndCharacterSet(const FontParameters &fp) : characterSet(fp.characterSet) {
pfont = std::make_unique<QFont>();
pfont->setStyleStrategy(ChooseStrategy(fp.extraFontFlag));
pfont->setFamily(QString::fromUtf8(fp.faceName));
pfont->setPointSizeF(fp.size);
pfont->setBold(static_cast<int>(fp.weight) > 500);
pfont->setStretch(QStretchFromFontStretch(fp.stretch));
pfont->setItalic(fp.italic);
}
};
namespace {
const Supports SupportsQt[] = {
Supports::LineDrawsFinal,
Supports::FractionalStrokeWidth,
Supports::TranslucentStroke,
Supports::PixelModification,
};
const FontAndCharacterSet *AsFontAndCharacterSet(const Font *f) {
return dynamic_cast<const FontAndCharacterSet *>(f);
}
QFont *FontPointer(const Font *f)
{
return AsFontAndCharacterSet(f)->pfont.get();
}
}
std::shared_ptr<Font> Font::Allocate(const FontParameters &fp)
{
return std::make_shared<FontAndCharacterSet>(fp);
}
SurfaceImpl::SurfaceImpl() = default;
SurfaceImpl::SurfaceImpl(int width, int height, SurfaceMode mode_)
{
if (width < 1) width = 1;
if (height < 1) height = 1;
deviceOwned = true;
device = new QPixmap(width, height);
mode = mode_;
}
SurfaceImpl::~SurfaceImpl()
{
2019-05-04 20:14:48 +02:00
Clear();
}
void SurfaceImpl::Clear()
{
if (painterOwned && painter) {
delete painter;
}
if (deviceOwned && device) {
delete device;
}
device = nullptr;
painter = nullptr;
deviceOwned = false;
painterOwned = false;
}
void SurfaceImpl::Init(WindowID wid)
{
Release();
device = static_cast<QWidget *>(wid);
}
void SurfaceImpl::Init(SurfaceID sid, WindowID /*wid*/)
{
Release();
device = static_cast<QPaintDevice *>(sid);
}
std::unique_ptr<Surface> SurfaceImpl::AllocatePixMap(int width, int height)
{
return std::make_unique<SurfaceImpl>(width, height, mode);
}
void SurfaceImpl::SetMode(SurfaceMode mode_)
{
mode = mode_;
}
void SurfaceImpl::Release() noexcept
{
2019-05-04 20:14:48 +02:00
Clear();
}
int SurfaceImpl::SupportsFeature(Supports feature) noexcept
{
for (const Supports f : SupportsQt) {
if (f == feature)
return 1;
}
return 0;
}
bool SurfaceImpl::Initialised()
{
return device != nullptr;
}
void SurfaceImpl::PenColour(ColourRGBA fore)
{
QPen penOutline(QColorFromColourRGBA(fore));
penOutline.setCapStyle(Qt::FlatCap);
GetPainter()->setPen(penOutline);
}
void SurfaceImpl::PenColourWidth(ColourRGBA fore, XYPOSITION strokeWidth) {
QPen penOutline(QColorFromColourRGBA(fore));
penOutline.setCapStyle(Qt::FlatCap);
penOutline.setJoinStyle(Qt::MiterJoin);
penOutline.setWidthF(strokeWidth);
GetPainter()->setPen(penOutline);
}
void SurfaceImpl::BrushColour(ColourRGBA back)
{
GetPainter()->setBrush(QBrush(QColorFromColourRGBA(back)));
}
void SurfaceImpl::SetCodec(const Font *font)
{
const FontAndCharacterSet *pfacs = AsFontAndCharacterSet(font);
if (pfacs && pfacs->pfont) {
const char *csid = "UTF-8";
if (!(mode.codePage == SC_CP_UTF8))
csid = CharacterSetID(pfacs->characterSet);
if (csid != codecName) {
codecName = csid;
codec = QTextCodec::codecForName(csid);
}
}
}
void SurfaceImpl::SetFont(const Font *font)
{
const FontAndCharacterSet *pfacs = AsFontAndCharacterSet(font);
if (pfacs && pfacs->pfont) {
GetPainter()->setFont(*(pfacs->pfont));
SetCodec(font);
}
}
int SurfaceImpl::LogPixelsY()
{
return device->logicalDpiY();
}
int SurfaceImpl::PixelDivisions()
{
// Qt uses device pixels.
return 1;
}
int SurfaceImpl::DeviceHeightFont(int points)
{
return points;
}
void SurfaceImpl::LineDraw(Point start, Point end, Stroke stroke)
{
PenColourWidth(stroke.colour, stroke.width);
QLineF line(start.x, start.y, end.x, end.y);
GetPainter()->drawLine(line);
}
void SurfaceImpl::PolyLine(const Point *pts, size_t npts, Stroke stroke)
{
// TODO: set line joins and caps
PenColourWidth(stroke.colour, stroke.width);
std::vector<QPointF> qpts;
std::transform(pts, pts + npts, std::back_inserter(qpts), QPointFFromPoint);
GetPainter()->drawPolyline(&qpts[0], static_cast<int>(npts));
}
void SurfaceImpl::Polygon(const Point *pts, size_t npts, FillStroke fillStroke)
{
PenColourWidth(fillStroke.stroke.colour, fillStroke.stroke.width);
BrushColour(fillStroke.fill.colour);
std::vector<QPointF> qpts;
std::transform(pts, pts + npts, std::back_inserter(qpts), QPointFFromPoint);
2019-05-04 20:14:48 +02:00
GetPainter()->drawPolygon(&qpts[0], static_cast<int>(npts));
}
void SurfaceImpl::RectangleDraw(PRectangle rc, FillStroke fillStroke)
{
PenColourWidth(fillStroke.stroke.colour, fillStroke.stroke.width);
BrushColour(fillStroke.fill.colour);
const QRectF rect = QRectFFromPRect(rc.Inset(fillStroke.stroke.width / 2));
GetPainter()->drawRect(rect);
}
void SurfaceImpl::RectangleFrame(PRectangle rc, Stroke stroke) {
PenColourWidth(stroke.colour, stroke.width);
// Default QBrush is Qt::NoBrush so does not fill
GetPainter()->setBrush(QBrush());
const QRectF rect = QRectFFromPRect(rc.Inset(stroke.width / 2));
GetPainter()->drawRect(rect);
}
void SurfaceImpl::FillRectangle(PRectangle rc, Fill fill)
{
GetPainter()->fillRect(QRectFFromPRect(rc), QColorFromColourRGBA(fill.colour));
}
void SurfaceImpl::FillRectangleAligned(PRectangle rc, Fill fill)
{
FillRectangle(PixelAlign(rc, 1), fill);
}
void SurfaceImpl::FillRectangle(PRectangle rc, Surface &surfacePattern)
{
// Tile pattern over rectangle
SurfaceImpl *surface = dynamic_cast<SurfaceImpl *>(&surfacePattern);
const QPixmap *pixmap = static_cast<QPixmap *>(surface->GetPaintDevice());
GetPainter()->drawTiledPixmap(QRectFromPRect(rc), *pixmap);
}
void SurfaceImpl::RoundedRectangle(PRectangle rc, FillStroke fillStroke)
{
PenColourWidth(fillStroke.stroke.colour, fillStroke.stroke.width);
BrushColour(fillStroke.fill.colour);
GetPainter()->drawRoundedRect(QRectFFromPRect(rc), 3.0f, 3.0f);
}
void SurfaceImpl::AlphaRectangle(PRectangle rc, XYPOSITION cornerSize, FillStroke fillStroke)
{
QColor qFill = QColorFromColourRGBA(fillStroke.fill.colour);
QBrush brushFill(qFill);
GetPainter()->setBrush(brushFill);
if (fillStroke.fill.colour == fillStroke.stroke.colour) {
painter->setPen(Qt::NoPen);
QRectF rect = QRectFFromPRect(rc);
if (cornerSize > 0.0f) {
// A radius of 1 shows no curve so add 1
qreal radius = cornerSize+1;
GetPainter()->drawRoundedRect(rect, radius, radius);
} else {
GetPainter()->fillRect(rect, brushFill);
}
} else {
QColor qOutline = QColorFromColourRGBA(fillStroke.stroke.colour);
QPen penOutline(qOutline);
penOutline.setWidthF(fillStroke.stroke.width);
GetPainter()->setPen(penOutline);
QRectF rect = QRectFFromPRect(rc.Inset(fillStroke.stroke.width / 2));
if (cornerSize > 0.0f) {
// A radius of 1 shows no curve so add 1
qreal radius = cornerSize+1;
GetPainter()->drawRoundedRect(rect, radius, radius);
} else {
GetPainter()->drawRect(rect);
}
}
}
2019-05-04 20:14:48 +02:00
void SurfaceImpl::GradientRectangle(PRectangle rc, const std::vector<ColourStop> &stops, GradientOptions options) {
QRectF rect = QRectFFromPRect(rc);
QLinearGradient linearGradient;
switch (options) {
case GradientOptions::leftToRight:
linearGradient = QLinearGradient(rc.left, rc.top, rc.right, rc.top);
break;
case GradientOptions::topToBottom:
default:
linearGradient = QLinearGradient(rc.left, rc.top, rc.left, rc.bottom);
break;
}
linearGradient.setSpread(QGradient::RepeatSpread);
for (const ColourStop &stop : stops) {
linearGradient.setColorAt(stop.position, QColorFromColourRGBA(stop.colour));
2019-05-04 20:14:48 +02:00
}
QBrush brush = QBrush(linearGradient);
GetPainter()->fillRect(rect, brush);
}
static std::vector<unsigned char> ImageByteSwapped(int width, int height, const unsigned char *pixelsImage)
{
// Input is RGBA, but Format_ARGB32 is BGRA, so swap the red bytes and blue bytes
size_t bytes = width * height * 4;
std::vector<unsigned char> imageBytes(pixelsImage, pixelsImage+bytes);
for (size_t i=0; i<bytes; i+=4)
std::swap(imageBytes[i], imageBytes[i+2]);
return imageBytes;
}
void SurfaceImpl::DrawRGBAImage(PRectangle rc, int width, int height, const unsigned char *pixelsImage)
{
std::vector<unsigned char> imageBytes = ImageByteSwapped(width, height, pixelsImage);
QImage image(&imageBytes[0], width, height, QImage::Format_ARGB32);
QPoint pt(rc.left, rc.top);
GetPainter()->drawImage(pt, image);
}
void SurfaceImpl::Ellipse(PRectangle rc, FillStroke fillStroke)
{
PenColourWidth(fillStroke.stroke.colour, fillStroke.stroke.width);
BrushColour(fillStroke.fill.colour);
const QRectF rect = QRectFFromPRect(rc.Inset(fillStroke.stroke.width / 2));
GetPainter()->drawEllipse(rect);
}
void SurfaceImpl::Stadium(PRectangle rc, FillStroke fillStroke, Ends ends) {
const XYPOSITION halfStroke = fillStroke.stroke.width / 2.0f;
const XYPOSITION radius = rc.Height() / 2.0f - halfStroke;
PRectangle rcInner = rc;
rcInner.left += radius;
rcInner.right -= radius;
const XYPOSITION arcHeight = rc.Height() - fillStroke.stroke.width;
PenColourWidth(fillStroke.stroke.colour, fillStroke.stroke.width);
BrushColour(fillStroke.fill.colour);
QPainterPath path;
const Ends leftSide = static_cast<Ends>(static_cast<unsigned int>(ends) & 0xfu);
const Ends rightSide = static_cast<Ends>(static_cast<unsigned int>(ends) & 0xf0u);
switch (leftSide) {
case Ends::leftFlat:
path.moveTo(rc.left + halfStroke, rc.top + halfStroke);
path.lineTo(rc.left + halfStroke, rc.bottom - halfStroke);
break;
case Ends::leftAngle:
path.moveTo(rcInner.left + halfStroke, rc.top + halfStroke);
path.lineTo(rc.left + halfStroke, rc.Centre().y);
path.lineTo(rcInner.left + halfStroke, rc.bottom - halfStroke);
break;
case Ends::semiCircles:
default:
path.moveTo(rcInner.left + halfStroke, rc.top + halfStroke);
QRectF rectangleArc(rc.left + halfStroke, rc.top + halfStroke,
arcHeight, arcHeight);
path.arcTo(rectangleArc, 90, 180);
break;
}
switch (rightSide) {
case Ends::rightFlat:
path.lineTo(rc.right - halfStroke, rc.bottom - halfStroke);
path.lineTo(rc.right - halfStroke, rc.top + halfStroke);
break;
case Ends::rightAngle:
path.lineTo(rcInner.right - halfStroke, rc.bottom - halfStroke);
path.lineTo(rc.right - halfStroke, rc.Centre().y);
path.lineTo(rcInner.right - halfStroke, rc.top + halfStroke);
break;
case Ends::semiCircles:
default:
path.lineTo(rcInner.right - halfStroke, rc.bottom - halfStroke);
QRectF rectangleArc(rc.right - arcHeight - halfStroke, rc.top + halfStroke,
arcHeight, arcHeight);
path.arcTo(rectangleArc, 270, 180);
break;
}
// Close the path to enclose it for stroking and for filling, then draw it
path.closeSubpath();
GetPainter()->drawPath(path);
}
void SurfaceImpl::Copy(PRectangle rc, Point from, Surface &surfaceSource)
{
SurfaceImpl *source = dynamic_cast<SurfaceImpl *>(&surfaceSource);
QPixmap *pixmap = static_cast<QPixmap *>(source->GetPaintDevice());
GetPainter()->drawPixmap(rc.left, rc.top, *pixmap, from.x, from.y, -1, -1);
}
2019-05-04 20:14:48 +02:00
std::unique_ptr<IScreenLineLayout> SurfaceImpl::Layout(const IScreenLine *)
{
return {};
}
void SurfaceImpl::DrawTextNoClip(PRectangle rc,
const Font *font,
XYPOSITION ybase,
2019-05-04 20:14:48 +02:00
std::string_view text,
ColourRGBA fore,
ColourRGBA back)
{
SetFont(font);
PenColour(fore);
GetPainter()->setBackground(QColorFromColourRGBA(back));
GetPainter()->setBackgroundMode(Qt::OpaqueMode);
2019-05-04 20:14:48 +02:00
QString su = UnicodeFromText(codec, text);
GetPainter()->drawText(QPointF(rc.left, ybase), su);
}
void SurfaceImpl::DrawTextClipped(PRectangle rc,
const Font *font,
XYPOSITION ybase,
2019-05-04 20:14:48 +02:00
std::string_view text,
ColourRGBA fore,
ColourRGBA back)
{
SetClip(rc);
2019-05-04 20:14:48 +02:00
DrawTextNoClip(rc, font, ybase, text, fore, back);
PopClip();
}
void SurfaceImpl::DrawTextTransparent(PRectangle rc,
const Font *font,
XYPOSITION ybase,
2019-05-04 20:14:48 +02:00
std::string_view text,
ColourRGBA fore)
{
SetFont(font);
PenColour(fore);
GetPainter()->setBackgroundMode(Qt::TransparentMode);
2019-05-04 20:14:48 +02:00
QString su = UnicodeFromText(codec, text);
GetPainter()->drawText(QPointF(rc.left, ybase), su);
}
void SurfaceImpl::SetClip(PRectangle rc)
{
GetPainter()->save();
Update to Scintilla 5.3.3 and Lexilla 5.2.2 update to https://www.scintilla.org/scintilla533.zip with: 1. Released 8 February 2023. 2. Fix SCI_LINESJOIN bug where carriage returns were incorrectly retained. Bug #2372. 3. Fix SCI_VERTICALCENTRECARET to update the vertical scroll position. 4. When an autocompletion list is shown in response to SCN_CHARADDED, do not process character as fill-up or stop. This avoids closing immediately when a character may both trigger and finish autocompletion. 5. On Cocoa fix character input bug where dotless 'i' and some other extended Latin characters could not be entered. The change also stops SCI_ASSIGNCMDKEY from working with these characters on Cocoa. Bug #2374. 6. On GTK, support IME context. Feature #1476. 7. On GTK on Win32, fix scrolling speed to not be too fast. Bug #2375. 8. On Qt, fix indicator drawing past left of text pane over margin. Bug #2373, Bug #1956. 9. On Qt, allow scrolling with mouse wheel when scroll bar hidden. and https://www.scintilla.org/lexilla522.zip with 1. Released 8 February 2023. 2. C++: Fix keywords that start with non-ASCII. Also affects other lexers. Issue #130. 3. Matlab: Include more prefix and suffix characters in numeric literals. Issue #120. 4. Matlab: More accurate treatment of line ends inside strings. Matlab and Octave are different here. Issue #18. 5. Modula-3: Don't treat identifier suffix that matches keyword as keyword. Issue #129. 6. Modula-3: Fix endless loop in folder. Issue #128. 7. Modula-3: Fix access to lines beyond document end in folder. Issue #131. 8. Python: Don't highlight match and case as keywords in contexts where they probably aren't used as keywords. Pull request #122. 9. X12: Support empty envelopes. Bug #2369. update CMakeLists.txt to latest changes within vcxproj file Close #13082
2023-02-09 17:57:24 +01:00
GetPainter()->setClipRect(QRectFFromPRect(rc), Qt::IntersectClip);
}
void SurfaceImpl::PopClip()
{
GetPainter()->restore();
}
void SurfaceImpl::MeasureWidths(const Font *font,
2019-05-04 20:14:48 +02:00
std::string_view text,
XYPOSITION *positions)
{
if (!font)
return;
SetCodec(font);
2019-05-04 20:14:48 +02:00
QString su = UnicodeFromText(codec, text);
QTextLayout tlay(su, *FontPointer(font), GetPaintDevice());
tlay.beginLayout();
QTextLine tl = tlay.createLine();
tlay.endLayout();
if (mode.codePage == SC_CP_UTF8) {
int fit = su.size();
int ui=0;
2019-05-04 20:14:48 +02:00
size_t i=0;
while (ui<fit) {
2019-05-04 20:14:48 +02:00
const unsigned char uch = text[i];
const unsigned int byteCount = UTF8BytesOfLead[uch];
const int codeUnits = UTF16LengthFromUTF8ByteCount(byteCount);
qreal xPosition = tl.cursorToX(ui+codeUnits);
2019-05-04 20:14:48 +02:00
for (size_t bytePos=0; (bytePos<byteCount) && (i<text.length()); bytePos++) {
positions[i++] = xPosition;
}
ui += codeUnits;
}
XYPOSITION lastPos = 0;
if (i > 0)
lastPos = positions[i-1];
2019-05-04 20:14:48 +02:00
while (i<text.length()) {
positions[i++] = lastPos;
}
} else if (mode.codePage) {
// DBCS
int ui = 0;
2019-05-04 20:14:48 +02:00
for (size_t i=0; i<text.length();) {
size_t lenChar = DBCSIsLeadByte(mode.codePage, text[i]) ? 2 : 1;
qreal xPosition = tl.cursorToX(ui+1);
2019-05-04 20:14:48 +02:00
for (unsigned int bytePos=0; (bytePos<lenChar) && (i<text.length()); bytePos++) {
positions[i++] = xPosition;
}
ui++;
}
} else {
// Single byte encoding
2019-05-04 20:14:48 +02:00
for (int i=0; i<static_cast<int>(text.length()); i++) {
positions[i] = tl.cursorToX(i+1);
}
}
}
XYPOSITION SurfaceImpl::WidthText(const Font *font, std::string_view text)
{
QFontMetricsF metrics(*FontPointer(font), device);
SetCodec(font);
2019-05-04 20:14:48 +02:00
QString su = UnicodeFromText(codec, text);
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
return metrics.horizontalAdvance(su);
#else
return metrics.width(su);
#endif
}
void SurfaceImpl::DrawTextNoClipUTF8(PRectangle rc,
const Font *font,
XYPOSITION ybase,
std::string_view text,
ColourRGBA fore,
ColourRGBA back)
{
SetFont(font);
PenColour(fore);
GetPainter()->setBackground(QColorFromColourRGBA(back));
GetPainter()->setBackgroundMode(Qt::OpaqueMode);
QString su = QString::fromUtf8(text.data(), static_cast<int>(text.length()));
GetPainter()->drawText(QPointF(rc.left, ybase), su);
}
void SurfaceImpl::DrawTextClippedUTF8(PRectangle rc,
const Font *font,
XYPOSITION ybase,
std::string_view text,
ColourRGBA fore,
ColourRGBA back)
{
SetClip(rc);
DrawTextNoClip(rc, font, ybase, text, fore, back);
PopClip();
}
void SurfaceImpl::DrawTextTransparentUTF8(PRectangle rc,
const Font *font,
XYPOSITION ybase,
std::string_view text,
ColourRGBA fore)
{
SetFont(font);
PenColour(fore);
GetPainter()->setBackgroundMode(Qt::TransparentMode);
QString su = QString::fromUtf8(text.data(), static_cast<int>(text.length()));
GetPainter()->drawText(QPointF(rc.left, ybase), su);
}
void SurfaceImpl::MeasureWidthsUTF8(const Font *font,
std::string_view text,
XYPOSITION *positions)
{
if (!font)
return;
QString su = QString::fromUtf8(text.data(), static_cast<int>(text.length()));
QTextLayout tlay(su, *FontPointer(font), GetPaintDevice());
tlay.beginLayout();
QTextLine tl = tlay.createLine();
tlay.endLayout();
int fit = su.size();
int ui=0;
size_t i=0;
while (ui<fit) {
const unsigned char uch = text[i];
const unsigned int byteCount = UTF8BytesOfLead[uch];
const int codeUnits = UTF16LengthFromUTF8ByteCount(byteCount);
qreal xPosition = tl.cursorToX(ui+codeUnits);
for (size_t bytePos=0; (bytePos<byteCount) && (i<text.length()); bytePos++) {
positions[i++] = xPosition;
}
ui += codeUnits;
}
XYPOSITION lastPos = 0;
if (i > 0)
lastPos = positions[i-1];
while (i<text.length()) {
positions[i++] = lastPos;
}
}
XYPOSITION SurfaceImpl::WidthTextUTF8(const Font *font, std::string_view text)
{
QFontMetricsF metrics(*FontPointer(font), device);
QString su = QString::fromUtf8(text.data(), static_cast<int>(text.length()));
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
return metrics.horizontalAdvance(su);
#else
2019-05-04 20:14:48 +02:00
return metrics.width(su);
#endif
}
XYPOSITION SurfaceImpl::Ascent(const Font *font)
{
QFontMetricsF metrics(*FontPointer(font), device);
return metrics.ascent();
}
XYPOSITION SurfaceImpl::Descent(const Font *font)
{
QFontMetricsF metrics(*FontPointer(font), device);
// Qt returns 1 less than true descent
// See: QFontEngineWin::descent which says:
// ### we subtract 1 to even out the historical +1 in QFontMetrics's
// ### height=asc+desc+1 equation. Fix in Qt5.
return metrics.descent() + 1;
}
XYPOSITION SurfaceImpl::InternalLeading(const Font * /* font */)
{
return 0;
}
XYPOSITION SurfaceImpl::Height(const Font *font)
{
QFontMetricsF metrics(*FontPointer(font), device);
return metrics.height();
}
XYPOSITION SurfaceImpl::AverageCharWidth(const Font *font)
{
QFontMetricsF metrics(*FontPointer(font), device);
return metrics.averageCharWidth();
}
void SurfaceImpl::FlushCachedState()
{
if (device->paintingActive()) {
GetPainter()->setPen(QPen());
GetPainter()->setBrush(QBrush());
}
}
void SurfaceImpl::FlushDrawing()
2019-05-04 20:14:48 +02:00
{
}
QPaintDevice *SurfaceImpl::GetPaintDevice()
{
return device;
}
QPainter *SurfaceImpl::GetPainter()
{
Q_ASSERT(device);
2019-05-04 20:14:48 +02:00
if (!painter) {
if (device->paintingActive()) {
painter = device->paintEngine()->painter();
} else {
painterOwned = true;
painter = new QPainter(device);
}
// Set text antialiasing unconditionally.
// The font's style strategy will override.
painter->setRenderHint(QPainter::TextAntialiasing, true);
painter->setRenderHint(QPainter::Antialiasing, true);
}
return painter;
}
std::unique_ptr<Surface> Surface::Allocate(Technology)
{
return std::make_unique<SurfaceImpl>();
}
//----------------------------------------------------------------------
namespace {
2019-05-04 20:14:48 +02:00
QWidget *window(WindowID wid) noexcept
{
return static_cast<QWidget *>(wid);
}
QRect ScreenRectangleForPoint(QPoint posGlobal)
{
#if QT_VERSION >= QT_VERSION_CHECK(5, 10, 0)
const QScreen *screen = QGuiApplication::screenAt(posGlobal);
if (!screen) {
screen = QGuiApplication::primaryScreen();
}
return screen->availableGeometry();
#else
const QDesktopWidget *desktop = QApplication::desktop();
return desktop->availableGeometry(posGlobal);
#endif
}
}
Window::~Window() noexcept = default;
void Window::Destroy() noexcept
{
if (wid)
delete window(wid);
2019-05-04 20:14:48 +02:00
wid = nullptr;
}
2019-05-04 20:14:48 +02:00
PRectangle Window::GetPosition() const
{
// Before any size allocated pretend its 1000 wide so not scrolled
return wid ? PRectFromQRect(window(wid)->frameGeometry()) : PRectangle(0, 0, 1000, 1000);
}
void Window::SetPosition(PRectangle rc)
{
if (wid)
window(wid)->setGeometry(QRectFromPRect(rc));
}
2019-05-04 20:14:48 +02:00
void Window::SetPositionRelative(PRectangle rc, const Window *relativeTo)
{
2019-05-04 20:14:48 +02:00
QPoint oPos = window(relativeTo->wid)->mapToGlobal(QPoint(0,0));
int ox = oPos.x();
int oy = oPos.y();
ox += rc.left;
oy += rc.top;
const QRect rectDesk = ScreenRectangleForPoint(QPoint(ox, oy));
/* do some corrections to fit into screen */
int sizex = rc.right - rc.left;
int sizey = rc.bottom - rc.top;
int screenWidth = rectDesk.width();
if (ox < rectDesk.x())
ox = rectDesk.x();
if (sizex > screenWidth)
ox = rectDesk.x(); /* the best we can do */
else if (ox + sizex > rectDesk.right())
ox = rectDesk.right() - sizex;
if (oy + sizey > rectDesk.bottom())
oy = rectDesk.bottom() - sizey;
if (oy < rectDesk.top())
oy = rectDesk.top();
Q_ASSERT(wid);
window(wid)->move(ox, oy);
window(wid)->resize(sizex, sizey);
}
2019-05-04 20:14:48 +02:00
PRectangle Window::GetClientPosition() const
{
// The client position is the window position
return GetPosition();
}
void Window::Show(bool show)
{
if (wid)
window(wid)->setVisible(show);
}
void Window::InvalidateAll()
{
if (wid)
window(wid)->update();
}
void Window::InvalidateRectangle(PRectangle rc)
{
if (wid)
window(wid)->update(QRectFromPRect(rc));
}
void Window::SetCursor(Cursor curs)
{
if (wid) {
Qt::CursorShape shape;
switch (curs) {
case Cursor::text: shape = Qt::IBeamCursor; break;
case Cursor::arrow: shape = Qt::ArrowCursor; break;
case Cursor::up: shape = Qt::UpArrowCursor; break;
case Cursor::wait: shape = Qt::WaitCursor; break;
case Cursor::horizontal: shape = Qt::SizeHorCursor; break;
case Cursor::vertical: shape = Qt::SizeVerCursor; break;
case Cursor::hand: shape = Qt::PointingHandCursor; break;
default: shape = Qt::ArrowCursor; break;
}
QCursor cursor = QCursor(shape);
if (curs != cursorLast) {
window(wid)->setCursor(cursor);
cursorLast = curs;
}
}
}
/* Returns rectangle of monitor pt is on, both rect and pt are in Window's
window coordinates */
PRectangle Window::GetMonitorRect(Point pt)
{
const QPoint posGlobal = window(wid)->mapToGlobal(QPoint(pt.x, pt.y));
const QPoint originGlobal = window(wid)->mapToGlobal(QPoint(0, 0));
QRect rectScreen = ScreenRectangleForPoint(posGlobal);
rectScreen.translate(-originGlobal.x(), -originGlobal.y());
return PRectFromQRect(rectScreen);
}
//----------------------------------------------------------------------
class ListWidget : public QListWidget {
public:
explicit ListWidget(QWidget *parent);
2019-05-04 20:14:48 +02:00
void setDelegate(IListBoxDelegate *lbDelegate);
int currentSelection();
protected:
void selectionChanged(const QItemSelection &selected, const QItemSelection &deselected) override;
2019-05-04 20:14:48 +02:00
void mouseDoubleClickEvent(QMouseEvent *event) override;
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
void initViewItemOption(QStyleOptionViewItem *option) const override;
#else
2019-05-04 20:14:48 +02:00
QStyleOptionViewItem viewOptions() const override;
#endif
private:
2019-05-04 20:14:48 +02:00
IListBoxDelegate *delegate;
};
2019-05-04 20:14:48 +02:00
class ListBoxImpl : public ListBox {
public:
ListBoxImpl() noexcept;
void SetFont(const Font *font) override;
2019-05-04 20:14:48 +02:00
void Create(Window &parent, int ctrlID, Point location,
int lineHeight, bool unicodeMode_, Technology technology) override;
2019-05-04 20:14:48 +02:00
void SetAverageCharWidth(int width) override;
void SetVisibleRows(int rows) override;
int GetVisibleRows() const override;
PRectangle GetDesiredRect() override;
int CaretFromEdge() override;
void Clear() noexcept override;
void Append(char *s, int type) override;
2019-05-04 20:14:48 +02:00
int Length() override;
void Select(int n) override;
int GetSelection() override;
int Find(const char *prefix) override;
std::string GetValue(int n) override;
2019-05-04 20:14:48 +02:00
void RegisterImage(int type, const char *xpmData) override;
void RegisterRGBAImage(int type, int width, int height,
const unsigned char *pixelsImage) override;
virtual void RegisterQPixmapImage(int type, const QPixmap& pm);
void ClearRegisteredImages() override;
void SetDelegate(IListBoxDelegate *lbDelegate) override;
void SetList(const char *list, char separator, char typesep) override;
void SetOptions(ListOptions options_) override;
2019-05-04 20:14:48 +02:00
[[nodiscard]] ListWidget *GetWidget() const noexcept;
2019-05-04 20:14:48 +02:00
private:
bool unicodeMode{false};
int visibleRows{5};
2019-05-04 20:14:48 +02:00
QMap<int,QPixmap> images;
};
ListBoxImpl::ListBoxImpl() noexcept = default;
void ListBoxImpl::Create(Window &parent,
int /*ctrlID*/,
Point location,
int /*lineHeight*/,
bool unicodeMode_,
Technology)
{
unicodeMode = unicodeMode_;
QWidget *qparent = static_cast<QWidget *>(parent.GetID());
ListWidget *list = new ListWidget(qparent);
#if defined(Q_OS_WIN)
// On Windows, Qt::ToolTip causes a crash when the list is clicked on
// so Qt::Tool is used.
2019-05-04 20:14:48 +02:00
list->setParent(nullptr, Qt::Tool | Qt::FramelessWindowHint | Qt::WindowStaysOnTopHint
#if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)
| Qt::WindowDoesNotAcceptFocus
#endif
);
#else
// On macOS, Qt::Tool takes focus so main window loses focus so
// keyboard stops working. Qt::ToolTip works but its only really
// documented for tooltips.
// On Linux / X this setting allows clicking on list items.
list->setParent(nullptr, static_cast<Qt::WindowFlags>(Qt::ToolTip | Qt::FramelessWindowHint));
#endif
list->setAttribute(Qt::WA_ShowWithoutActivating);
list->setFocusPolicy(Qt::NoFocus);
list->setUniformItemSizes(true);
list->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded);
list->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
list->move(location.x, location.y);
int maxIconWidth = 0;
int maxIconHeight = 0;
foreach (QPixmap im, images) {
if (maxIconWidth < im.width())
maxIconWidth = im.width();
if (maxIconHeight < im.height())
maxIconHeight = im.height();
}
list->setIconSize(QSize(maxIconWidth, maxIconHeight));
wid = list;
}
void ListBoxImpl::SetFont(const Font *font)
{
2019-05-04 20:14:48 +02:00
ListWidget *list = GetWidget();
const FontAndCharacterSet *pfacs = AsFontAndCharacterSet(font);
if (pfacs && pfacs->pfont) {
list->setFont(*(pfacs->pfont));
}
}
void ListBoxImpl::SetAverageCharWidth(int /*width*/) {}
void ListBoxImpl::SetVisibleRows(int rows)
{
visibleRows = rows;
}
int ListBoxImpl::GetVisibleRows() const
{
return visibleRows;
}
PRectangle ListBoxImpl::GetDesiredRect()
{
2019-05-04 20:14:48 +02:00
ListWidget *list = GetWidget();
int rows = Length();
if (rows == 0 || rows > visibleRows) {
rows = visibleRows;
}
int rowHeight = list->sizeHintForRow(0);
int height = (rows * rowHeight) + (2 * list->frameWidth());
QStyle *style = QApplication::style();
int width = list->sizeHintForColumn(0) + (2 * list->frameWidth());
if (Length() > rows) {
width += style->pixelMetric(QStyle::PM_ScrollBarExtent);
}
return PRectangle(0, 0, width, height);
}
int ListBoxImpl::CaretFromEdge()
{
2019-05-04 20:14:48 +02:00
ListWidget *list = GetWidget();
int maxIconWidth = 0;
foreach (QPixmap im, images) {
if (maxIconWidth < im.width())
maxIconWidth = im.width();
}
int extra;
// The 12 is from trial and error on macOS and the 7
// is from trial and error on Windows - there may be
// a better programmatic way to find any padding factors.
#ifdef Q_OS_DARWIN
extra = 12;
#else
extra = 7;
#endif
return maxIconWidth + (2 * list->frameWidth()) + extra;
}
void ListBoxImpl::Clear() noexcept
{
2019-05-04 20:14:48 +02:00
ListWidget *list = GetWidget();
list->clear();
}
void ListBoxImpl::Append(char *s, int type)
{
2019-05-04 20:14:48 +02:00
ListWidget *list = GetWidget();
QString str = unicodeMode ? QString::fromUtf8(s) : QString::fromLocal8Bit(s);
QIcon icon;
if (type >= 0) {
Q_ASSERT(images.contains(type));
icon = images.value(type);
}
new QListWidgetItem(icon, str, list);
}
int ListBoxImpl::Length()
{
2019-05-04 20:14:48 +02:00
ListWidget *list = GetWidget();
return list->count();
}
void ListBoxImpl::Select(int n)
{
2019-05-04 20:14:48 +02:00
ListWidget *list = GetWidget();
QModelIndex index = list->model()->index(n, 0);
if (index.isValid()) {
QRect row_rect = list->visualRect(index);
if (!list->viewport()->rect().contains(row_rect)) {
list->scrollTo(index, QAbstractItemView::PositionAtTop);
}
}
list->setCurrentRow(n);
}
int ListBoxImpl::GetSelection()
{
2019-05-04 20:14:48 +02:00
ListWidget *list = GetWidget();
return list->currentSelection();
}
int ListBoxImpl::Find(const char *prefix)
{
2019-05-04 20:14:48 +02:00
ListWidget *list = GetWidget();
QString sPrefix = unicodeMode ? QString::fromUtf8(prefix) : QString::fromLocal8Bit(prefix);
QList<QListWidgetItem *> ms = list->findItems(sPrefix, Qt::MatchStartsWith);
int result = -1;
if (!ms.isEmpty()) {
result = list->row(ms.first());
}
return result;
}
std::string ListBoxImpl::GetValue(int n)
{
2019-05-04 20:14:48 +02:00
ListWidget *list = GetWidget();
QListWidgetItem *item = list->item(n);
QString str = item->data(Qt::DisplayRole).toString();
QByteArray bytes = unicodeMode ? str.toUtf8() : str.toLocal8Bit();
return std::string(bytes.constData());
}
void ListBoxImpl::RegisterQPixmapImage(int type, const QPixmap& pm)
{
images[type] = pm;
2019-05-04 20:14:48 +02:00
ListWidget *list = GetWidget();
if (list) {
QSize iconSize = list->iconSize();
if (pm.width() > iconSize.width() || pm.height() > iconSize.height())
2019-05-04 20:14:48 +02:00
list->setIconSize(QSize(qMax(pm.width(), iconSize.width()),
qMax(pm.height(), iconSize.height())));
}
}
void ListBoxImpl::RegisterImage(int type, const char *xpmData)
{
Update to Scintilla 5.3.2 and Lexilla 5.2.1 update to https://www.scintilla.org/scintilla532.zip with: Released 6 December 2022. Add SCI_REPLACETARGETMINIMAL to change text without causing unchanged prefix and suffix to be marked as modified in change history. Draw background colour for EOL annotations with standard and boxed visuals. Add SCI_GETSTYLEDTEXTFULL to support 64-bit document positions on Win32 replacing SCI_GETSTYLEDTEXT which is not safe for huge documents. Feature #1455. Send SCN_AUTOCCOMPLETED for SCI_AUTOCSHOW triggering insertion because of SCI_AUTOCSETCHOOSESINGLE mode. Feature #1459. Change 'paragraph up' commands SCI_PARAUP and SCI_PARAUPEXTEND to go to the start position of the paragraph containing the caret. Only if the caret is already at the start of the paragraph will it go to the start of the previous paragraph. Bug #2363. Change release compilation optimization option to favour speed over space. -O2 for MSVC and -O3 for gcc and clang. On Win32, avoid blurry display with DirectWrite in GDI scaling mode. Bug #2344. On Win32, use the top-level window to find the monitor for DirectWrite rendering parameters. Temporarily switch DPI awareness to find correct monitor in GDI scaling mode. Bug #2344. On Qt, implement SCI_SETRECTANGULARSELECTIONMODIFIER for all platforms. On Qt, allow string form XPM images for SCI_REGISTERIMAGE. and https://www.scintilla.org/lexilla521.zip with Released 6 December 2022. Update to Unicode 14. Feature #1461. Change default compilation optimization option to favour speed over space. -O2 for MSVC and -O3 for gcc and clang. Batch: Fix comments starting inside strings. Issue #115. F#: Lex signed numeric literals more accurately. Issue #110, Issue #111. F#: Add specifiers for 64-bit integer and floating point literals. Issue #112. Markdown: Stop styling numbers at line start in PRECHAR style. Issue #117. PowerShell: Recognise numeric literals more accurately. Issue #118. Close #12624
2022-12-10 13:35:16 +01:00
XPM xpmImage(xpmData);
RGBAImage rgbaImage(xpmImage);
RegisterRGBAImage(type, rgbaImage.GetWidth(), rgbaImage.GetHeight(), rgbaImage.Pixels());
}
void ListBoxImpl::RegisterRGBAImage(int type, int width, int height, const unsigned char *pixelsImage)
{
std::vector<unsigned char> imageBytes = ImageByteSwapped(width, height, pixelsImage);
QImage image(&imageBytes[0], width, height, QImage::Format_ARGB32);
RegisterQPixmapImage(type, QPixmap::fromImage(image));
}
void ListBoxImpl::ClearRegisteredImages()
{
images.clear();
2019-05-04 20:14:48 +02:00
ListWidget *list = GetWidget();
if (list)
list->setIconSize(QSize(0, 0));
}
2019-05-04 20:14:48 +02:00
void ListBoxImpl::SetDelegate(IListBoxDelegate *lbDelegate)
{
2019-05-04 20:14:48 +02:00
ListWidget *list = GetWidget();
list->setDelegate(lbDelegate);
}
void ListBoxImpl::SetList(const char *list, char separator, char typesep)
{
// This method is *not* platform dependent.
// It is borrowed from the GTK implementation.
Clear();
size_t count = strlen(list) + 1;
std::vector<char> words(list, list+count);
char *startword = &words[0];
2019-05-04 20:14:48 +02:00
char *numword = nullptr;
int i = 0;
for (; words[i]; i++) {
if (words[i] == separator) {
words[i] = '\0';
if (numword)
*numword = '\0';
Append(startword, numword?atoi(numword + 1):-1);
startword = &words[0] + i + 1;
2019-05-04 20:14:48 +02:00
numword = nullptr;
} else if (words[i] == typesep) {
numword = &words[0] + i;
}
}
if (startword) {
if (numword)
*numword = '\0';
Append(startword, numword?atoi(numword + 1):-1);
}
}
void ListBoxImpl::SetOptions(ListOptions)
{
}
ListWidget *ListBoxImpl::GetWidget() const noexcept
2019-05-04 20:14:48 +02:00
{
return static_cast<ListWidget *>(wid);
}
ListBox::ListBox() noexcept = default;
ListBox::~ListBox() noexcept = default;
std::unique_ptr<ListBox> ListBox::Allocate()
{
return std::make_unique<ListBoxImpl>();
}
ListWidget::ListWidget(QWidget *parent)
2019-05-04 20:14:48 +02:00
: QListWidget(parent), delegate(nullptr)
{}
2019-05-04 20:14:48 +02:00
void ListWidget::setDelegate(IListBoxDelegate *lbDelegate)
{
2019-05-04 20:14:48 +02:00
delegate = lbDelegate;
}
void ListWidget::selectionChanged(const QItemSelection &selected, const QItemSelection &deselected) {
QListWidget::selectionChanged(selected, deselected);
2019-05-04 20:14:48 +02:00
if (delegate) {
const int selection = currentSelection();
if (selection >= 0) {
ListBoxEvent event(ListBoxEvent::EventType::selectionChange);
delegate->ListNotify(&event);
}
}
}
int ListWidget::currentSelection() {
const QModelIndexList indices = selectionModel()->selectedRows();
foreach (const QModelIndex ind, indices) {
return ind.row();
2019-05-04 20:14:48 +02:00
}
return -1;
}
void ListWidget::mouseDoubleClickEvent(QMouseEvent * /* event */)
{
2019-05-04 20:14:48 +02:00
if (delegate) {
ListBoxEvent event(ListBoxEvent::EventType::doubleClick);
delegate->ListNotify(&event);
}
}
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
void ListWidget::initViewItemOption(QStyleOptionViewItem *option) const
{
QListWidget::initViewItemOption(option);
option->state |= QStyle::State_Active;
}
#else
QStyleOptionViewItem ListWidget::viewOptions() const
{
QStyleOptionViewItem result = QListWidget::viewOptions();
result.state |= QStyle::State_Active;
return result;
}
#endif
//----------------------------------------------------------------------
2019-05-04 20:14:48 +02:00
Menu::Menu() noexcept : mid(nullptr) {}
void Menu::CreatePopUp()
{
Destroy();
mid = new QMenu();
}
void Menu::Destroy() noexcept
{
if (mid) {
QMenu *menu = static_cast<QMenu *>(mid);
delete menu;
}
2019-05-04 20:14:48 +02:00
mid = nullptr;
}
void Menu::Show(Point pt, const Window & /*w*/)
{
QMenu *menu = static_cast<QMenu *>(mid);
menu->exec(QPoint(pt.x, pt.y));
Destroy();
}
//----------------------------------------------------------------------
ColourRGBA Platform::Chrome()
{
QColor c(Qt::gray);
return ColourRGBA(c.red(), c.green(), c.blue());
}
ColourRGBA Platform::ChromeHighlight()
{
QColor c(Qt::lightGray);
return ColourRGBA(c.red(), c.green(), c.blue());
}
const char *Platform::DefaultFont()
{
static char fontNameDefault[200] = "";
if (!fontNameDefault[0]) {
QFont font = QApplication::font();
strcpy(fontNameDefault, font.family().toUtf8());
}
return fontNameDefault;
}
int Platform::DefaultFontSize()
{
QFont font = QApplication::font();
return font.pointSize();
}
unsigned int Platform::DoubleClickTime()
{
return QApplication::doubleClickInterval();
}
void Platform::DebugDisplay(const char *s) noexcept
{
qWarning("Scintilla: %s", s);
}
void Platform::DebugPrintf(const char *format, ...) noexcept
{
char buffer[2000];
va_list pArguments{};
va_start(pArguments, format);
Update scintilla 5.3.4 and lexilla 5.2.4 with: https://www.scintilla.org/scintilla534.zip Released 8 March 2023. Add multithreaded wrap to significantly improve performance of wrapping large files. More typesafe bindings of *Full APIs in ScintillaCall. Feature #1477. Fix overlapping of text with line end wrap marker. Bug #2378. Fix clipping of line end wrap symbol for SC_WRAPVISUALFLAGLOC_END_BY_TEXT. Where a multi-byte character contains multiple styles, display each byte as a representation. This makes it easier to see and fix lexers that change styles mid-character, commonly because they use fixed size buffers. Fix a potential crash with autocompletion list fill-ups where a SCN_CHARADDED handler retriggered an autocompletion list, but with no items that match the typed character. lexilla523 Released 8 March 2023. Add scripts/PromoteNew.bat script to promote .new files after checking. Makefile: Remove 1024-byte line length limit.. Ruby: Add new lexical classes for % literals SCE_RB_STRING_W (%w non-interpolable string array), SCE_RB_STRING_I (%i non-interpolable symbol array), SCE_RB_STRING_QI (%I interpolable symbol array), and SCE_RB_STRING_QS (%s symbol). Issue #124. Ruby: Disambiguate %= which may be a quote or modulo assignment. Issue #124, Bug #1255, Bug #2182. Ruby: Fix additional fold level for single character in SCE_RB_STRING_QW. Issue #132. Ruby: Set SCE_RB_HERE_QQ for unquoted and double-quoted heredocs and SCE_RB_HERE_QX for backticks-quoted heredocs. Issue #134. Ruby: Recognise #{} inside SCE_RB_HERE_QQ and SCE_RB_HERE_QX. Issue #134. Ruby: Improve regex and heredoc recognition. Issue #136. Ruby: Highlight #@, #@@ and #$ style interpolation. Issue #140. Ruby: Fix folding for multiple heredocs started on one line. Fix folding when there is a space after heredoc opening delimiter. Issue #135. YAML: Remove 1024-byte line length limit. https://www.scintilla.org/lexilla524.zip Released 13 March 2023. C++: Fix failure to recognize keywords containing upper case. Issue #149. GDScript: Support % and $ node paths. Issue #145, Pull request #146. Close #13338
2023-03-10 03:37:21 +01:00
vsnprintf(buffer, std::size(buffer), format, pArguments);
va_end(pArguments);
Platform::DebugDisplay(buffer);
}
bool Platform::ShowAssertionPopUps(bool /*assertionPopUps*/) noexcept
{
return false;
}
void Platform::Assert(const char *c, const char *file, int line) noexcept
{
char buffer[2000];
Update scintilla 5.3.4 and lexilla 5.2.4 with: https://www.scintilla.org/scintilla534.zip Released 8 March 2023. Add multithreaded wrap to significantly improve performance of wrapping large files. More typesafe bindings of *Full APIs in ScintillaCall. Feature #1477. Fix overlapping of text with line end wrap marker. Bug #2378. Fix clipping of line end wrap symbol for SC_WRAPVISUALFLAGLOC_END_BY_TEXT. Where a multi-byte character contains multiple styles, display each byte as a representation. This makes it easier to see and fix lexers that change styles mid-character, commonly because they use fixed size buffers. Fix a potential crash with autocompletion list fill-ups where a SCN_CHARADDED handler retriggered an autocompletion list, but with no items that match the typed character. lexilla523 Released 8 March 2023. Add scripts/PromoteNew.bat script to promote .new files after checking. Makefile: Remove 1024-byte line length limit.. Ruby: Add new lexical classes for % literals SCE_RB_STRING_W (%w non-interpolable string array), SCE_RB_STRING_I (%i non-interpolable symbol array), SCE_RB_STRING_QI (%I interpolable symbol array), and SCE_RB_STRING_QS (%s symbol). Issue #124. Ruby: Disambiguate %= which may be a quote or modulo assignment. Issue #124, Bug #1255, Bug #2182. Ruby: Fix additional fold level for single character in SCE_RB_STRING_QW. Issue #132. Ruby: Set SCE_RB_HERE_QQ for unquoted and double-quoted heredocs and SCE_RB_HERE_QX for backticks-quoted heredocs. Issue #134. Ruby: Recognise #{} inside SCE_RB_HERE_QQ and SCE_RB_HERE_QX. Issue #134. Ruby: Improve regex and heredoc recognition. Issue #136. Ruby: Highlight #@, #@@ and #$ style interpolation. Issue #140. Ruby: Fix folding for multiple heredocs started on one line. Fix folding when there is a space after heredoc opening delimiter. Issue #135. YAML: Remove 1024-byte line length limit. https://www.scintilla.org/lexilla524.zip Released 13 March 2023. C++: Fix failure to recognize keywords containing upper case. Issue #149. GDScript: Support % and $ node paths. Issue #145, Pull request #146. Close #13338
2023-03-10 03:37:21 +01:00
snprintf(buffer, std::size(buffer), "Assertion [%s] failed at %s %d", c, file, line);
if (Platform::ShowAssertionPopUps(false)) {
QMessageBox mb("Assertion Failure", buffer, QMessageBox::NoIcon,
QMessageBox::Ok, QMessageBox::NoButton, QMessageBox::NoButton);
mb.exec();
} else {
strcat(buffer, "\n");
Platform::DebugDisplay(buffer);
}
}
}