diff options
| author | nyamatongwe <unknown> | 2012-05-17 12:46:29 +1000 | 
|---|---|---|
| committer | nyamatongwe <unknown> | 2012-05-17 12:46:29 +1000 | 
| commit | bf8b35542c4be4b8eebb71ca2ad518da2e12b850 (patch) | |
| tree | eab094df23f84c33c7ed03f3412a63a060d31eac /qt/ScintillaEditBase/PlatQt.cpp | |
| parent | 29c92749f25f24795ecd9fec2b6705129ebbd654 (diff) | |
| download | scintilla-mirror-bf8b35542c4be4b8eebb71ca2ad518da2e12b850.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 | 
