diff options
author | nyamatongwe <devnull@localhost> | 2012-05-17 12:46:29 +1000 |
---|---|---|
committer | nyamatongwe <devnull@localhost> | 2012-05-17 12:46:29 +1000 |
commit | d283c373e28ddab911c5b8ec1ee0940421f63c2f (patch) | |
tree | 996535793ef6a2eecc148bea808ae3a59cf25928 /qt/ScintillaEditBase/PlatQt.cpp | |
parent | 6f94e41af0007250738f79d1b478c003d3af0b5b (diff) | |
download | scintilla-mirror-d283c373e28ddab911c5b8ec1ee0940421f63c2f.tar.gz |
Qt platform layer added. Based on an implementation from Jason Haslam
at Scientific Toolworks, Inc. with additions performed for Wingware.
Diffstat (limited to 'qt/ScintillaEditBase/PlatQt.cpp')
-rw-r--r-- | qt/ScintillaEditBase/PlatQt.cpp | 1282 |
1 files changed, 1282 insertions, 0 deletions
diff --git a/qt/ScintillaEditBase/PlatQt.cpp b/qt/ScintillaEditBase/PlatQt.cpp new file mode 100644 index 000000000..b386df5a0 --- /dev/null +++ b/qt/ScintillaEditBase/PlatQt.cpp @@ -0,0 +1,1282 @@ +// +// 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 + +#include "PlatQt.h" +#include "Scintilla.h" +#include "FontQuality.h" + +#include <QApplication> +#include <QFont> +#include <QColor> +#include <QRect> +#include <QPaintDevice> +#include <QPaintEngine> +#include <QWidget> +#include <QPixmap> +#include <QPainter> +#include <QMenu> +#include <QAction> +#include <QTime> +#include <QMessageBox> +#include <QTextCodec> +#include <QListWidget> +#include <QVarLengthArray> +#include <QScrollBar> +#include <QDesktopWidget> +#include <QTextLayout> +#include <QTextLine> +#include <QLibrary> +#include <cstdio> + +#ifdef SCI_NAMESPACE +namespace Scintilla { +#endif + +//---------------------------------------------------------------------- + +// Convert from a Scintilla characterSet value to a Qt codec name. +const char *CharacterSetID(int characterSet) +{ + switch (characterSet) { + //case SC_CHARSET_ANSI: + // return ""; + case SC_CHARSET_DEFAULT: + return "ISO 8859-1"; + case SC_CHARSET_BALTIC: + return "ISO 8859-13"; + case SC_CHARSET_CHINESEBIG5: + return "Big5"; + case SC_CHARSET_EASTEUROPE: + return "ISO 8859-2"; + case SC_CHARSET_GB2312: + return "GB18030-0"; + case SC_CHARSET_GREEK: + return "ISO 8859-7"; + case SC_CHARSET_HANGUL: + return "CP949"; + case SC_CHARSET_MAC: + return "Apple Roman"; + //case SC_CHARSET_OEM: + // return "ASCII"; + case SC_CHARSET_RUSSIAN: + return "KOI8-R"; + case SC_CHARSET_CYRILLIC: + return "Windows-1251"; + case SC_CHARSET_SHIFTJIS: + return "Shift-JIS"; + //case SC_CHARSET_SYMBOL: + // return ""; + case SC_CHARSET_TURKISH: + return "ISO 8859-9"; + //case SC_CHARSET_JOHAB: + // return "CP1361"; + case SC_CHARSET_HEBREW: + return "ISO 8859-8"; + case SC_CHARSET_ARABIC: + return "ISO 8859-6"; + case SC_CHARSET_VIETNAMESE: + return "Windows-1258"; + case SC_CHARSET_THAI: + return "TIS-620"; + case SC_CHARSET_8859_15: + return "ISO 8859-15"; + default: + return "ISO 8859-1"; + } +} + +class FontAndCharacterSet { +public: + int characterSet; + QFont *pfont; + FontAndCharacterSet(int characterSet_, QFont *pfont): + characterSet(characterSet_), pfont(pfont) { + } + ~FontAndCharacterSet() { + delete pfont; + pfont = 0; + } +}; + +static int FontCharacterSet(Font &f) +{ + return reinterpret_cast<FontAndCharacterSet *>(f.GetID())->characterSet; +} + +static QFont *FontPointer(Font &f) +{ + return reinterpret_cast<FontAndCharacterSet *>(f.GetID())->pfont; +} + +Font::Font() : fid(0) {} + +Font::~Font() +{ + delete reinterpret_cast<FontAndCharacterSet *>(fid); + fid = 0; +} + +static QFont::StyleStrategy ChooseStrategy(int eff) +{ + switch (eff) { + case SC_EFF_QUALITY_DEFAULT: return QFont::PreferDefault; + case SC_EFF_QUALITY_NON_ANTIALIASED: return QFont::NoAntialias; + case SC_EFF_QUALITY_ANTIALIASED: return QFont::PreferAntialias; + case SC_EFF_QUALITY_LCD_OPTIMIZED: return QFont::PreferAntialias; + default: return QFont::PreferDefault; + } +} + +void Font::Create(const FontParameters &fp) +{ + Release(); + + QFont *font = new QFont; + font->setStyleStrategy(ChooseStrategy(fp.extraFontFlag)); + font->setFamily(QString::fromUtf8(fp.faceName)); + font->setPointSize(fp.size); + font->setBold(fp.weight > 500); + font->setItalic(fp.italic); + + fid = new FontAndCharacterSet(fp.characterSet, font); +} + +void Font::Release() +{ + if (fid) + delete reinterpret_cast<FontAndCharacterSet *>(fid); + + fid = 0; +} + + +SurfaceImpl::SurfaceImpl() +: device(0), painter(0), deviceOwned(false), painterOwned(false), x(0), y(0), + unicodeMode(false), codePage(0), codecName(0), codec(0) +{} + +SurfaceImpl::~SurfaceImpl() +{ + Release(); +} + +void SurfaceImpl::Init(WindowID wid) +{ + Release(); + device = static_cast<QWidget *>(wid); +} + +void SurfaceImpl::Init(SurfaceID sid, WindowID /*wid*/) +{ + Release(); + device = static_cast<QPaintDevice *>(sid); +} + +void SurfaceImpl::InitPixMap(int width, + int height, + Surface * /*surface*/, + WindowID /*wid*/) +{ + Release(); + if (width < 1) width = 1; + if (height < 1) height = 1; + deviceOwned = true; + device = new QPixmap(width, height); +} + +void SurfaceImpl::Release() +{ + if (painterOwned && painter) { + delete painter; + } + + if (deviceOwned && device) { + delete device; + } + + device = 0; + painter = 0; + deviceOwned = false; + painterOwned = false; +} + +bool SurfaceImpl::Initialised() +{ + return device != 0; +} + +void SurfaceImpl::PenColour(ColourDesired fore) +{ + QPen penOutline(QColorFromCA(fore)); + penOutline.setCapStyle(Qt::FlatCap); + GetPainter()->setPen(penOutline); +} + +void SurfaceImpl::BrushColour(ColourDesired back) +{ + GetPainter()->setBrush(QBrush(QColorFromCA(back))); +} + +void SurfaceImpl::SetCodec(Font &font) +{ + if (font.GetID()) { + const char *csid = "UTF-8"; + if (!unicodeMode) + csid = CharacterSetID(FontCharacterSet(font)); + if (csid != codecName) { + codecName = csid; + codec = QTextCodec::codecForName(csid); + } + } +} + +void SurfaceImpl::SetFont(Font &font) +{ + if (font.GetID()) { + GetPainter()->setFont(*FontPointer(font)); + SetCodec(font); + } +} + +int SurfaceImpl::LogPixelsY() +{ + return device->logicalDpiY(); +} + +int SurfaceImpl::DeviceHeightFont(int points) +{ + return points; +} + +void SurfaceImpl::MoveTo(int x_, int y_) +{ + x = x_; + y = y_; +} + +void SurfaceImpl::LineTo(int x_, int y_) +{ + QLineF line(x, y, x_, y_); + GetPainter()->drawLine(line); + x = x_; + y = y_; +} + +void SurfaceImpl::Polygon(Point *pts, + int npts, + ColourDesired fore, + ColourDesired back) +{ + PenColour(fore); + BrushColour(back); + + QPoint *qpts = new QPoint[npts]; + for (int i = 0; i < npts; i++) { + qpts[i] = QPoint(pts[i].x, pts[i].y); + } + + GetPainter()->drawPolygon(qpts, npts); + delete [] qpts; +} + +void SurfaceImpl::RectangleDraw(PRectangle rc, + ColourDesired fore, + ColourDesired back) +{ + PenColour(fore); + BrushColour(back); + QRect rect = QRect(rc.left, rc.top, rc.Width() - 1, rc.Height() - 1); + GetPainter()->drawRect(rect); +} + +void SurfaceImpl::FillRectangle(PRectangle rc, ColourDesired back) +{ + BrushColour(back); + GetPainter()->setPen(Qt::NoPen); + GetPainter()->drawRect(QRectFromPRect(rc)); +} + +void SurfaceImpl::FillRectangle(PRectangle rc, Surface &surfacePattern) +{ + // Tile pattern over rectangle + SurfaceImpl *surface = static_cast<SurfaceImpl *>(&surfacePattern); + // Currently assumes 8x8 pattern + int widthPat = 8; + int heightPat = 8; + for (int xTile = rc.left; xTile < rc.right; xTile += widthPat) { + int widthx = (xTile + widthPat > rc.right) ? rc.right - xTile : widthPat; + for (int yTile = rc.top; yTile < rc.bottom; yTile += heightPat) { + int heighty = (yTile + heightPat > rc.bottom) ? rc.bottom - yTile : heightPat; + QRect source(0, 0, widthx, heighty); + QRect target(xTile, yTile, widthx, heighty); + QPixmap *pixmap = static_cast<QPixmap *>(surface->GetPaintDevice()); + GetPainter()->drawPixmap(target, *pixmap, source); + } + } +} + +void SurfaceImpl::RoundedRectangle(PRectangle rc, + ColourDesired fore, + ColourDesired back) +{ + PenColour(fore); + BrushColour(back); + GetPainter()->drawRoundRect(QRectFromPRect(rc)); +} + +void SurfaceImpl::AlphaRectangle(PRectangle rc, + int cornerSize, + ColourDesired fill, + int alphaFill, + ColourDesired outline, + int alphaOutline, + int /*flags*/) +{ + QColor qOutline = QColorFromCA(outline); + qOutline.setAlpha(alphaOutline); + GetPainter()->setPen(QPen(qOutline)); + + QColor qFill = QColorFromCA(fill); + qFill.setAlpha(alphaFill); + GetPainter()->setBrush(QBrush(qFill)); + + // A radius of 1 shows no curve so add 1 + qreal radius = cornerSize+1; + QRect rect(rc.left, rc.top, rc.Width() - 1, rc.Height() - 1); + GetPainter()->drawRoundedRect(rect, radius, radius); +} + +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, + ColourDesired fore, + ColourDesired back) +{ + PenColour(fore); + BrushColour(back); + GetPainter()->drawEllipse(QRectFromPRect(rc)); +} + +void SurfaceImpl::Copy(PRectangle rc, Point from, Surface &surfaceSource) +{ + SurfaceImpl *source = static_cast<SurfaceImpl *>(&surfaceSource); + QPixmap *pixmap = static_cast<QPixmap *>(source->GetPaintDevice()); + + GetPainter()->drawPixmap(rc.left, rc.top, *pixmap, from.x, from.y, -1, -1); +} + +void SurfaceImpl::DrawTextNoClip(PRectangle rc, + Font &font, + XYPOSITION ybase, + const char *s, + int len, + ColourDesired fore, + ColourDesired back) +{ + SetFont(font); + PenColour(fore); + + GetPainter()->setBackground(QColorFromCA(back)); + GetPainter()->setBackgroundMode(Qt::OpaqueMode); + QString su = codec->toUnicode(s, len); + GetPainter()->drawText(QPointF(rc.left, ybase), su); +} + +void SurfaceImpl::DrawTextClipped(PRectangle rc, + Font &font, + XYPOSITION ybase, + const char *s, + int len, + ColourDesired fore, + ColourDesired back) +{ + SetClip(rc); + DrawTextNoClip(rc, font, ybase, s, len, fore, back); + GetPainter()->setClipping(false); +} + +void SurfaceImpl::DrawTextTransparent(PRectangle rc, + Font &font, + XYPOSITION ybase, + const char *s, + int len, + ColourDesired fore) +{ + SetFont(font); + PenColour(fore); + + GetPainter()->setBackgroundMode(Qt::TransparentMode); + QString su = codec->toUnicode(s, len); + GetPainter()->drawText(QPointF(rc.left, ybase), su); +} + +void SurfaceImpl::SetClip(PRectangle rc) +{ + GetPainter()->setClipRect(QRectFromPRect(rc)); +} + +static size_t utf8LengthFromLead(unsigned char uch) +{ + if (uch >= (0x80 + 0x40 + 0x20 + 0x10)) { + return 4; + } else if (uch >= (0x80 + 0x40 + 0x20)) { + return 3; + } else if (uch >= (0x80)) { + return 2; + } else { + return 1; + } +} + +void SurfaceImpl::MeasureWidths(Font &font, + const char *s, + int len, + XYPOSITION *positions) +{ + if (!font.GetID()) + return; + SetCodec(font); + QString su = codec->toUnicode(s, len); + QTextLayout tlay(su, *FontPointer(font)); + tlay.beginLayout(); + QTextLine tl = tlay.createLine(); + tlay.endLayout(); + if (unicodeMode) { + int fit = su.size(); + int ui=0; + const unsigned char *us = reinterpret_cast<const unsigned char *>(s); + int i=0; + while (ui<fit) { + size_t lenChar = utf8LengthFromLead(us[i]); + size_t codeUnits = (lenChar < 4) ? 1 : 2; + qreal xPosition = tl.cursorToX(ui+codeUnits); + for (unsigned int bytePos=0; (bytePos<lenChar) && (i<len); bytePos++) { + positions[i++] = qRound(xPosition); + } + ui += codeUnits; + } + int lastPos = 0; + if (i > 0) + lastPos = positions[i-1]; + while (i<len) { + positions[i++] = lastPos; + } + } else if (codePage) { + // DBCS + int ui = 0; + for (int i=0; i<len;) { + size_t lenChar = Platform::IsDBCSLeadByte(codePage, s[i]) ? 2 : 1; + qreal xPosition = tl.cursorToX(ui+1); + for (unsigned int bytePos=0; (bytePos<lenChar) && (i<len); bytePos++) { + positions[i++] = qRound(xPosition); + } + ui++; + } + } else { + // Single byte encoding + for (int i=0; i<len; i++) { + positions[i] = qRound(tl.cursorToX(i+1)); + } + } +} + +XYPOSITION SurfaceImpl::WidthText(Font &font, const char *s, int len) +{ + QFontMetrics metrics(*FontPointer(font), device); + SetCodec(font); + QString string = codec->toUnicode(s, len); + return metrics.width(string); +} + +XYPOSITION SurfaceImpl::WidthChar(Font &font, char ch) +{ + QFontMetrics metrics(*FontPointer(font), device); + return metrics.width(ch); +} + +XYPOSITION SurfaceImpl::Ascent(Font &font) +{ + QFontMetrics metrics(*FontPointer(font), device); + return metrics.ascent(); +} + +XYPOSITION SurfaceImpl::Descent(Font &font) +{ + QFontMetrics metrics(*FontPointer(font), device); + // Qt returns 1 less than true descent + // See: QFontEngineWin::descent which says: + // ### we substract 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(Font & /* font */) +{ + return 0; +} + +XYPOSITION SurfaceImpl::ExternalLeading(Font &font) +{ + QFontMetrics metrics(*FontPointer(font), device); + return metrics.leading(); +} + +XYPOSITION SurfaceImpl::Height(Font &font) +{ + QFontMetrics metrics(*FontPointer(font), device); + return metrics.height(); +} + +XYPOSITION SurfaceImpl::AverageCharWidth(Font &font) +{ + QFontMetrics metrics(*FontPointer(font), device); + return metrics.averageCharWidth(); +} + +void SurfaceImpl::FlushCachedState() +{ + if (device->paintingActive()) { + GetPainter()->setPen(QPen()); + GetPainter()->setBrush(QBrush()); + } +} + +void SurfaceImpl::SetUnicodeMode(bool unicodeMode_) +{ + unicodeMode=unicodeMode_; +} + +void SurfaceImpl::SetDBCSMode(int codePage_) +{ + codePage = codePage_; +} + +QPaintDevice *SurfaceImpl::GetPaintDevice() +{ + return device; +} + +QPainter *SurfaceImpl::GetPainter() +{ + Q_ASSERT(device); + + if (painter == 0) { + 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); + } + + return painter; +} + +Surface *Surface::Allocate(int) +{ + return new SurfaceImpl; +} + + +//---------------------------------------------------------------------- + +namespace { +QWidget *window(WindowID wid) +{ + return static_cast<QWidget *>(wid); +} +} + +Window::~Window() {} + +void Window::Destroy() +{ + if (wid) + delete window(wid); + + wid = 0; +} + +bool Window::HasFocus() +{ + return wid ? window(wid)->hasFocus() : false; +} + +PRectangle Window::GetPosition() +{ + // 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)); +} + +void Window::SetPositionRelative(PRectangle rc, Window relativeTo) +{ + QPoint oPos = window(relativeTo.wid)->mapToGlobal(QPoint(0,0)); + int ox = oPos.x(); + int oy = oPos.y(); + ox += rc.left; + if (ox < 0) + ox = 0; + oy += rc.top; + if (oy < 0) + oy = 0; + + QDesktopWidget *desktop = QApplication::desktop(); + QRect rectDesk = desktop->availableGeometry(window(wid)); + /* do some corrections to fit into screen */ + int sizex = rc.right - rc.left; + int sizey = rc.bottom - rc.top; + int screenWidth = rectDesk.width(); + int screenHeight = rectDesk.height(); + if (sizex > screenWidth) + ox = 0; /* the best we can do */ + else if (ox + sizex > screenWidth) + ox = screenWidth - sizex; + if (oy + sizey > screenHeight) + oy = screenHeight - sizey; + + Q_ASSERT(wid); + window(wid)->move(ox, oy); + window(wid)->resize(sizex, sizey); +} + +PRectangle Window::GetClientPosition() +{ + // 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::SetFont(Font &font) +{ + if (wid) + window(wid)->setFont(*FontPointer(font)); +} + +void Window::SetCursor(Cursor curs) +{ + if (wid) { + Qt::CursorShape shape; + + switch (curs) { + case cursorText: shape = Qt::IBeamCursor; break; + case cursorArrow: shape = Qt::ArrowCursor; break; + case cursorUp: shape = Qt::UpArrowCursor; break; + case cursorWait: shape = Qt::WaitCursor; break; + case cursorHoriz: shape = Qt::SizeHorCursor; break; + case cursorVert: shape = Qt::SizeVerCursor; break; + case cursorHand: shape = Qt::PointingHandCursor; break; + default: shape = Qt::ArrowCursor; break; + } + + QCursor cursor = QCursor(shape); + + if (curs != cursorLast) { + window(wid)->setCursor(cursor); + cursorLast = curs; + } + } +} + +void Window::SetTitle(const char *s) +{ + if (wid) + window(wid)->setWindowTitle(s); +} + +/* Returns rectangle of monitor pt is on, both rect and pt are in Window's + window coordinates */ +PRectangle Window::GetMonitorRect(Point pt) +{ + QPoint originGlobal = window(wid)->mapToGlobal(QPoint(0, 0)); + QPoint posGlobal = window(wid)->mapToGlobal(QPoint(pt.x, pt.y)); + QDesktopWidget *desktop = QApplication::desktop(); + QRect rectScreen = desktop->availableGeometry(posGlobal); + rectScreen.moveLeft(-originGlobal.x()); + rectScreen.moveTop(-originGlobal.y()); + return PRectangle(rectScreen.left(), rectScreen.top(), + rectScreen.right(), rectScreen.bottom()); +} + + +//---------------------------------------------------------------------- + +class ListBoxImpl : public ListBox { +public: + ListBoxImpl(); + ~ListBoxImpl(); + + virtual void SetFont(Font &font); + virtual void Create(Window &parent, int ctrlID, Point location, + int lineHeight, bool unicodeMode, int technology); + virtual void SetAverageCharWidth(int width); + virtual void SetVisibleRows(int rows); + virtual int GetVisibleRows() const; + virtual PRectangle GetDesiredRect(); + virtual int CaretFromEdge(); + virtual void Clear(); + virtual void Append(char *s, int type = -1); + virtual int Length(); + virtual void Select(int n); + virtual int GetSelection(); + virtual int Find(const char *prefix); + virtual void GetValue(int n, char *value, int len); + virtual void RegisterImage(int type, const char *xpmData); + virtual void RegisterRGBAImage(int type, int width, int height, + const unsigned char *pixelsImage); + virtual void ClearRegisteredImages(); + virtual void SetDoubleClickAction(CallBackAction action, void *data); + virtual void SetList(const char *list, char separator, char typesep); +private: + bool unicodeMode; + int visibleRows; + QMap<int,QPixmap> images; +}; + +class ListWidget : public QListWidget { +public: + ListWidget(QWidget *parent); + virtual ~ListWidget(); + + void setDoubleClickAction(CallBackAction action, void *data); + +protected: + virtual void mouseDoubleClickEvent(QMouseEvent *event); + virtual QStyleOptionViewItem viewOptions() const; + +private: + CallBackAction doubleClickAction; + void *doubleClickActionData; +}; + + +ListBoxImpl::ListBoxImpl() +: unicodeMode(false), visibleRows(5) +{} + +ListBoxImpl::~ListBoxImpl() {} + +void ListBoxImpl::Create(Window &parent, + int /*ctrlID*/, + Point location, + int /*lineHeight*/, + bool unicodeMode_, + int) +{ + 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. + list->setParent(0, Qt::Tool | Qt::FramelessWindowHint | Qt::WindowStaysOnTopHint); +#else + // On OS X, 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(0, 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); + + wid = list; +} + +void ListBoxImpl::SetFont(Font &font) +{ + ListWidget *list = static_cast<ListWidget *>(wid); + list->setFont(*FontPointer(font)); +} + +void ListBoxImpl::SetAverageCharWidth(int /*width*/) {} + +void ListBoxImpl::SetVisibleRows(int rows) +{ + visibleRows = rows; +} + +int ListBoxImpl::GetVisibleRows() const +{ + return visibleRows; +} + +PRectangle ListBoxImpl::GetDesiredRect() +{ + ListWidget *list = static_cast<ListWidget *>(wid); + + 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() +{ + ListWidget *list = static_cast<ListWidget *>(wid); + + int maxIconWidth = 0; + foreach (QPixmap im, images) { + if (maxIconWidth < im.width()) + maxIconWidth = im.width(); + } + + // The '7' is from trial and error on Windows - there may be + // a better programmatic way to find any padding factors. + return maxIconWidth + (2 * list->frameWidth()) + 7; +} + +void ListBoxImpl::Clear() +{ + ListWidget *list = static_cast<ListWidget *>(wid); + list->clear(); +} + +void ListBoxImpl::Append(char *s, int type) +{ + ListWidget *list = static_cast<ListWidget *>(wid); + + 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() +{ + ListWidget *list = static_cast<ListWidget *>(wid); + return list->count(); +} + +void ListBoxImpl::Select(int n) +{ + ListWidget *list = static_cast<ListWidget *>(wid); + list->setCurrentRow(n); +} + +int ListBoxImpl::GetSelection() +{ + ListWidget *list = static_cast<ListWidget *>(wid); + return list->currentRow(); +} + +int ListBoxImpl::Find(const char *prefix) +{ + ListWidget *list = static_cast<ListWidget *>(wid); + 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; +} + +void ListBoxImpl::GetValue(int n, char *value, int len) +{ + ListWidget *list = static_cast<ListWidget *>(wid); + QListWidgetItem *item = list->item(n); + QString str = item->data(Qt::DisplayRole).toString(); + QByteArray bytes = unicodeMode ? str.toUtf8() : str.toLocal8Bit(); + + strncpy(value, bytes.constData(), len); + value[len-1] = '\0'; +} + +void ListBoxImpl::RegisterImage(int type, const char *xpmData) +{ + images[type] = QPixmap(reinterpret_cast<const char * const *>(xpmData)); +} + +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); + images[type] = QPixmap::fromImage(image); +} + +void ListBoxImpl::ClearRegisteredImages() +{ + images.clear(); +} + +void ListBoxImpl::SetDoubleClickAction(CallBackAction action, void *data) +{ + ListWidget *list = static_cast<ListWidget *>(wid); + list->setDoubleClickAction(action, data); +} + +void ListBoxImpl::SetList(const char *list, char separator, char typesep) +{ + // This method is *not* platform dependent. + // It is borrowed from the GTK implementation. + Clear(); + int count = strlen(list) + 1; + char *words = new char[count]; + if (words) { + memcpy(words, list, count); + char *startword = words; + char *numword = NULL; + 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 + i + 1; + numword = NULL; + } else if (words[i] == typesep) { + numword = words + i; + } + } + if (startword) { + if (numword) + *numword = '\0'; + Append(startword, numword?atoi(numword + 1):-1); + } + delete []words; + } +} + +ListBox::ListBox() {} + +ListBox::~ListBox() {} + +ListBox *ListBox::Allocate() +{ + return new ListBoxImpl(); +} + +ListWidget::ListWidget(QWidget *parent) +: QListWidget(parent), doubleClickActionData(0) +{} + +ListWidget::~ListWidget() {} + +void ListWidget::setDoubleClickAction(CallBackAction action, void *data) +{ + doubleClickAction = action; + doubleClickActionData = data; +} + +void ListWidget::mouseDoubleClickEvent(QMouseEvent * /* event */) +{ + if (doubleClickAction != 0) { + doubleClickAction(doubleClickActionData); + } +} + +QStyleOptionViewItem ListWidget::viewOptions() const +{ + QStyleOptionViewItem result = QListWidget::viewOptions(); + result.state |= QStyle::State_Active; + return result; +} + +//---------------------------------------------------------------------- + +Menu::Menu() : mid(0) {} + +void Menu::CreatePopUp() +{ + Destroy(); + mid = new QMenu(); +} + +void Menu::Destroy() +{ + if (mid) { + QMenu *menu = static_cast<QMenu *>(mid); + delete menu; + } + mid = 0; +} + +void Menu::Show(Point pt, Window & /*w*/) +{ + QMenu *menu = static_cast<QMenu *>(mid); + menu->exec(QPoint(pt.x, pt.y)); + Destroy(); +} + +//---------------------------------------------------------------------- + +class DynamicLibraryImpl : public DynamicLibrary { +protected: + QLibrary *lib; +public: + DynamicLibraryImpl(const char *modulePath) { + QString path = QString::fromUtf8(modulePath); + lib = new QLibrary(path); + } + + virtual ~DynamicLibraryImpl() { + if (lib) + lib->unload(); + lib = 0; + } + + virtual Function FindFunction(const char *name) { + if (lib) { + void *fnAddress = lib->resolve(name); + return static_cast<Function>(fnAddress); + } + return NULL; + } + + virtual bool IsValid() { + return lib != NULL; + } +}; + +DynamicLibrary *DynamicLibrary::Load(const char *modulePath) +{ + return static_cast<DynamicLibrary *>(new DynamicLibraryImpl(modulePath)); +} + +ColourDesired Platform::Chrome() +{ + QColor c(Qt::gray); + return ColourDesired(c.red(), c.green(), c.blue()); +} + +ColourDesired Platform::ChromeHighlight() +{ + QColor c(Qt::lightGray); + return ColourDesired(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().toAscii()); + } + return fontNameDefault; +} + +int Platform::DefaultFontSize() +{ + QFont font = QApplication::font(); + return font.pointSize(); +} + +unsigned int Platform::DoubleClickTime() +{ + return QApplication::doubleClickInterval(); +} + +bool Platform::MouseButtonBounce() +{ + return false; +} + +bool Platform::IsKeyDown(int /*key*/) +{ + return false; +} + +long Platform::SendScintilla(WindowID /*w*/, + unsigned int /*msg*/, + unsigned long /*wParam*/, + long /*lParam*/) +{ + return 0; +} + +long Platform::SendScintillaPointer(WindowID /*w*/, + unsigned int /*msg*/, + unsigned long /*wParam*/, + void * /*lParam*/) +{ + return 0; +} + +int Platform::Minimum(int a, int b) +{ + return qMin(a, b); +} + +int Platform::Maximum(int a, int b) +{ + return qMax(a, b); +} + +int Platform::Clamp(int val, int minVal, int maxVal) +{ + return qBound(minVal, val, maxVal); +} + +void Platform::DebugDisplay(const char *s) +{ + qWarning("Scintilla: %s", s); +} + +void Platform::DebugPrintf(const char *format, ...) +{ + char buffer[2000]; + va_list pArguments; + va_start(pArguments, format); + vsprintf(buffer, format, pArguments); + va_end(pArguments); + Platform::DebugDisplay(buffer); +} + +bool Platform::ShowAssertionPopUps(bool /*assertionPopUps*/) +{ + return false; +} + +void Platform::Assert(const char *c, const char *file, int line) +{ + char buffer[2000]; + sprintf(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); + } +} + + +bool Platform::IsDBCSLeadByte(int codePage, char ch) +{ + // Byte ranges found in Wikipedia articles with relevant search strings in each case + unsigned char uch = static_cast<unsigned char>(ch); + switch (codePage) { + case 932: + // Shift_jis + return ((uch >= 0x81) && (uch <= 0x9F)) || + ((uch >= 0xE0) && (uch <= 0xEF)); + case 936: + // GBK + return (uch >= 0x81) && (uch <= 0xFE); + case 949: + // Korean Wansung KS C-5601-1987 + return (uch >= 0x81) && (uch <= 0xFE); + case 950: + // Big5 + return (uch >= 0x81) && (uch <= 0xFE); + case 1361: + // Korean Johab KS C-5601-1992 + return + ((uch >= 0x84) && (uch <= 0xD3)) || + ((uch >= 0xD8) && (uch <= 0xDE)) || + ((uch >= 0xE0) && (uch <= 0xF9)); + } + return false; +} + +int Platform::DBCSCharLength(int codePage, const char *s) +{ + if (codePage == 932 || codePage == 936 || codePage == 949 || + codePage == 950 || codePage == 1361) { + return IsDBCSLeadByte(codePage, s[0]) ? 2 : 1; + } else { + return 1; + } +} + +int Platform::DBCSCharMaxLength() +{ + return 2; +} + + +//---------------------------------------------------------------------- + +static QTime timer; + +ElapsedTime::ElapsedTime() +{ + timer.start(); +} + +double ElapsedTime::Duration(bool reset) +{ + double result = timer.elapsed(); + if (reset) { + timer.restart(); + } + result /= 1000.0; + return result; +} + +#ifdef SCI_NAMESPACE +} +#endif |