1 // This module implements the portability layer for the Qt port of Scintilla.
2 //
3 // Copyright (c) 2019 Riverbank Computing Limited <info@riverbankcomputing.com>
4 //
5 // This file is part of QScintilla.
6 //
7 // This file may be used under the terms of the GNU General Public License
8 // version 3.0 as published by the Free Software Foundation and appearing in
9 // the file LICENSE included in the packaging of this file. Please review the
10 // following information to ensure the GNU General Public License version 3.0
11 // requirements will be met: http://www.gnu.org/copyleft/gpl.html.
12 //
13 // If you do not wish to use this file under the terms of the GPL version 3.0
14 // then you may purchase a commercial license. For more information contact
15 // info@riverbankcomputing.com.
16 //
17 // This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
18 // WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
19
20
21 #include <stdio.h>
22 #include <stdarg.h>
23 #include <string.h>
24
25 #include <qapplication.h>
26 #include <qcursor.h>
27 #include <qdatetime.h>
28 #include <qdesktopwidget.h>
29 #include <qfont.h>
30 #include <qimage.h>
31 #include <qlibrary.h>
32 #include <qpainter.h>
33 #include <qpixmap.h>
34 #include <qpolygon.h>
35 #include <qstring.h>
36 #include <qtextlayout.h>
37 #include <qwidget.h>
38
39 #include "Platform.h"
40 #include "XPM.h"
41
42 #include "Qsci/qsciscintillabase.h"
43 #include "SciClasses.h"
44
45 #include "FontQuality.h"
46
47
48 namespace Scintilla {
49
50 // Type convertors.
PFont(FontID fid)51 static QFont *PFont(FontID fid)
52 {
53 return reinterpret_cast<QFont *>(fid);
54 }
55
PWindow(WindowID wid)56 static QWidget *PWindow(WindowID wid)
57 {
58 return reinterpret_cast<QWidget *>(wid);
59 }
60
PMenu(MenuID mid)61 static QsciSciPopup *PMenu(MenuID mid)
62 {
63 return reinterpret_cast<QsciSciPopup *>(mid);
64 }
65
66
67 // Font management.
Font()68 Font::Font() noexcept : fid(0)
69 {
70 }
71
~Font()72 Font::~Font()
73 {
74 }
75
Create(const FontParameters & fp)76 void Font::Create(const FontParameters &fp)
77 {
78 Release();
79
80 QFont *f = new QFont();
81
82 QFont::StyleStrategy strategy;
83
84 switch (fp.extraFontFlag & SC_EFF_QUALITY_MASK)
85 {
86 case SC_EFF_QUALITY_NON_ANTIALIASED:
87 strategy = QFont::NoAntialias;
88 break;
89
90 case SC_EFF_QUALITY_ANTIALIASED:
91 strategy = QFont::PreferAntialias;
92 break;
93
94 default:
95 strategy = QFont::PreferDefault;
96 }
97
98 #if defined(Q_OS_MAC) && QT_VERSION < 0x050000
99 #if QT_VERSION >= 0x040700
100 strategy = static_cast<QFont::StyleStrategy>(strategy | QFont::ForceIntegerMetrics);
101 #else
102 #warning "Correct handling of QFont metrics requires Qt v4.7.0 or later"
103 #endif
104 #endif
105
106 f->setStyleStrategy(strategy);
107
108 // If name of the font begins with a '-', assume, that it is an XLFD.
109 if (fp.faceName[0] == '-')
110 {
111 f->setRawName(fp.faceName);
112 }
113 else
114 {
115 f->setFamily(fp.faceName);
116 f->setPointSizeF(fp.size);
117
118 // See if the Qt weight has been passed via the back door. Otherwise
119 // map Scintilla weights to Qt weights ensuring that the SC_WEIGHT_*
120 // values get mapped to the correct QFont::Weight values.
121 int qt_weight;
122
123 if (fp.weight < 0)
124 qt_weight = -fp.weight;
125 else if (fp.weight <= 200)
126 qt_weight = QFont::Light;
127 else if (fp.weight <= QsciScintillaBase::SC_WEIGHT_NORMAL)
128 qt_weight = QFont::Normal;
129 else if (fp.weight <= 600)
130 qt_weight = QFont::DemiBold;
131 else if (fp.weight <= 850)
132 qt_weight = QFont::Bold;
133 else
134 qt_weight = QFont::Black;
135
136 f->setWeight(qt_weight);
137
138 f->setItalic(fp.italic);
139 }
140
141 fid = f;
142 }
143
Release()144 void Font::Release()
145 {
146 if (fid)
147 {
148 delete PFont(fid);
149 fid = 0;
150 }
151 }
152
153
154 // A surface abstracts a place to draw.
155 class SurfaceImpl : public Surface
156 {
157 public:
158 SurfaceImpl();
159 virtual ~SurfaceImpl();
160
161 void Init(WindowID wid);
162 void Init(SurfaceID sid, WindowID);
163 void Init(QPainter *p);
164 void InitPixMap(int width, int height, Surface *sid, WindowID wid);
165
166 void Release();
Initialised()167 bool Initialised() {return painter;}
168 void PenColour(ColourDesired fore);
LogPixelsY()169 int LogPixelsY() {return pd->logicalDpiY();}
DeviceHeightFont(int points)170 int DeviceHeightFont(int points) {return points;}
171 void MoveTo(int x_,int y_);
172 void LineTo(int x_,int y_);
173 void Polygon(Point *pts, size_t npts, ColourDesired fore,
174 ColourDesired back);
175 void RectangleDraw(PRectangle rc, ColourDesired fore,
176 ColourDesired back);
177 void FillRectangle(PRectangle rc, ColourDesired back);
178 void FillRectangle(PRectangle rc, Surface &surfacePattern);
179 void RoundedRectangle(PRectangle rc, ColourDesired fore,
180 ColourDesired back);
181 void AlphaRectangle(PRectangle rc, int cornerSize, ColourDesired fill,
182 int alphaFill, ColourDesired outline, int alphaOutline,
183 int flags);
184 void GradientRectangle(PRectangle rc, const std::vector<ColourStop> &stops,
185 GradientOptions options);
186 void DrawRGBAImage(PRectangle rc, int width, int height, const unsigned char *pixelsImage);
187 void Ellipse(PRectangle rc, ColourDesired fore, ColourDesired back);
188 void Copy(PRectangle rc, Point from, Surface &surfaceSource);
189
190 void DrawTextNoClip(PRectangle rc, Font &font_, XYPOSITION ybase,
191 const char *s, int len, ColourDesired fore, ColourDesired back);
192 void DrawTextClipped(PRectangle rc, Font &font_, XYPOSITION ybase,
193 const char *s, int len, ColourDesired fore, ColourDesired back);
194 void DrawTextTransparent(PRectangle rc, Font &font_, XYPOSITION ybase,
195 const char *s, int len, ColourDesired fore);
196 void MeasureWidths(Font &font_, const char *s, int len,
197 XYPOSITION *positions);
198 XYPOSITION WidthText(Font &font_, const char *s, int len);
199 XYPOSITION Ascent(Font &font_);
200 XYPOSITION Descent(Font &font_);
InternalLeading(Font & font_)201 XYPOSITION InternalLeading(Font &font_) {Q_UNUSED(font_); return 0;}
202 XYPOSITION Height(Font &font_);
203 XYPOSITION AverageCharWidth(Font &font_);
204
205 void SetClip(PRectangle rc);
206 void FlushCachedState();
207
SetUnicodeMode(bool unicodeMode_)208 void SetUnicodeMode(bool unicodeMode_) {unicodeMode = unicodeMode_;}
SetDBCSMode(int codePage)209 void SetDBCSMode(int codePage) {Q_UNUSED(codePage);}
210
211 void DrawXPM(PRectangle rc, const XPM *xpm);
212
213 private:
214 void drawRect(const PRectangle &rc);
215 void drawText(const PRectangle &rc, Font &font_, XYPOSITION ybase,
216 const char *s, int len, ColourDesired fore);
217 static QFont convertQFont(Font &font);
218 QFontMetricsF metrics(Font &font_);
219 QString convertText(const char *s, int len);
220 static QColor convertQColor(const ColourDesired &col,
221 unsigned alpha = 255);
222
223 bool unicodeMode;
224 QPaintDevice *pd;
225 QPainter *painter;
226 bool my_resources;
227 int pen_x, pen_y;
228 };
229
Allocate(int)230 Surface *Surface::Allocate(int)
231 {
232 return new SurfaceImpl;
233 }
234
SurfaceImpl()235 SurfaceImpl::SurfaceImpl()
236 : unicodeMode(false), pd(0), painter(0), my_resources(false), pen_x(0),
237 pen_y(0)
238 {
239 }
240
~SurfaceImpl()241 SurfaceImpl::~SurfaceImpl()
242 {
243 Release();
244 }
245
Init(WindowID wid)246 void SurfaceImpl::Init(WindowID wid)
247 {
248 Release();
249
250 pd = reinterpret_cast<QWidget *>(wid);
251 }
252
Init(SurfaceID sid,WindowID)253 void SurfaceImpl::Init(SurfaceID sid, WindowID)
254 {
255 Release();
256
257 // This method, and the SurfaceID type, is only used when printing. As it
258 // is actually a void * we pass (when using SCI_FORMATRANGE) a pointer to a
259 // QPainter rather than a pointer to a SurfaceImpl as might be expected.
260 QPainter *p = reinterpret_cast<QPainter *>(sid);
261
262 pd = p->device();
263 painter = p;
264 }
265
Init(QPainter * p)266 void SurfaceImpl::Init(QPainter *p)
267 {
268 Release();
269
270 pd = p->device();
271 painter = p;
272 }
273
InitPixMap(int width,int height,Surface * sid,WindowID wid)274 void SurfaceImpl::InitPixMap(int width, int height, Surface *sid, WindowID wid)
275 {
276 Release();
277
278 #if QT_VERSION >= 0x050100
279 int dpr = PWindow(wid)->devicePixelRatio();
280 QPixmap *pixmap = new QPixmap(width * dpr, height * dpr);
281 pixmap->setDevicePixelRatio(dpr);
282 #else
283 QPixmap *pixmap = new QPixmap(width, height);
284 Q_UNUSED(wid);
285 #endif
286
287 pd = pixmap;
288
289 painter = new QPainter(pd);
290 my_resources = true;
291
292 SetUnicodeMode(static_cast<SurfaceImpl *>(sid)->unicodeMode);
293 }
294
Release()295 void SurfaceImpl::Release()
296 {
297 if (my_resources)
298 {
299 if (painter)
300 delete painter;
301
302 if (pd)
303 delete pd;
304
305 my_resources = false;
306 }
307
308 painter = 0;
309 pd = 0;
310 }
311
MoveTo(int x_,int y_)312 void SurfaceImpl::MoveTo(int x_, int y_)
313 {
314 Q_ASSERT(painter);
315
316 pen_x = x_;
317 pen_y = y_;
318 }
319
LineTo(int x_,int y_)320 void SurfaceImpl::LineTo(int x_, int y_)
321 {
322 Q_ASSERT(painter);
323
324 painter->drawLine(pen_x, pen_y, x_, y_);
325
326 pen_x = x_;
327 pen_y = y_;
328 }
329
PenColour(ColourDesired fore)330 void SurfaceImpl::PenColour(ColourDesired fore)
331 {
332 Q_ASSERT(painter);
333
334 painter->setPen(convertQColor(fore));
335 }
336
Polygon(Point * pts,size_t npts,ColourDesired fore,ColourDesired back)337 void SurfaceImpl::Polygon(Point *pts, size_t npts, ColourDesired fore,
338 ColourDesired back)
339 {
340 Q_ASSERT(painter);
341
342 QPolygonF qpts(npts);
343
344 for (size_t i = 0; i < npts; ++i)
345 qpts[i] = QPointF(pts[i].x, pts[i].y);
346
347 painter->setPen(convertQColor(fore));
348 painter->setBrush(convertQColor(back));
349 painter->drawPolygon(qpts);
350 }
351
RectangleDraw(PRectangle rc,ColourDesired fore,ColourDesired back)352 void SurfaceImpl::RectangleDraw(PRectangle rc, ColourDesired fore,
353 ColourDesired back)
354 {
355 Q_ASSERT(painter);
356
357 painter->setPen(convertQColor(fore));
358 painter->setBrush(convertQColor(back));
359 drawRect(rc);
360 }
361
FillRectangle(PRectangle rc,ColourDesired back)362 void SurfaceImpl::FillRectangle(PRectangle rc, ColourDesired back)
363 {
364 Q_ASSERT(painter);
365
366 painter->setPen(Qt::NoPen);
367 painter->setBrush(convertQColor(back));
368 drawRect(rc);
369 }
370
FillRectangle(PRectangle rc,Surface & surfacePattern)371 void SurfaceImpl::FillRectangle(PRectangle rc, Surface &surfacePattern)
372 {
373 Q_ASSERT(painter);
374
375 SurfaceImpl &si = static_cast<SurfaceImpl &>(surfacePattern);
376 QPixmap *pm = static_cast<QPixmap *>(si.pd);
377
378 if (pm)
379 {
380 QBrush brsh(Qt::black, *pm);
381
382 painter->setPen(Qt::NoPen);
383 painter->setBrush(brsh);
384 drawRect(rc);
385 }
386 else
387 {
388 FillRectangle(rc, ColourDesired(0));
389 }
390 }
391
RoundedRectangle(PRectangle rc,ColourDesired fore,ColourDesired back)392 void SurfaceImpl::RoundedRectangle(PRectangle rc, ColourDesired fore,
393 ColourDesired back)
394 {
395 Q_ASSERT(painter);
396
397 painter->setPen(convertQColor(fore));
398 painter->setBrush(convertQColor(back));
399 painter->drawRoundRect(
400 QRectF(rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top));
401 }
402
AlphaRectangle(PRectangle rc,int cornerSize,ColourDesired fill,int alphaFill,ColourDesired outline,int alphaOutline,int)403 void SurfaceImpl::AlphaRectangle(PRectangle rc, int cornerSize,
404 ColourDesired fill, int alphaFill, ColourDesired outline,
405 int alphaOutline, int)
406 {
407 Q_ASSERT(painter);
408
409 QColor outline_colour = convertQColor(outline, alphaOutline);
410 QColor fill_colour = convertQColor(fill, alphaFill);
411
412 // There was a report of Qt seeming to ignore the alpha value of the pen so
413 // so we disable the pen if the outline and fill colours are the same.
414 if (outline_colour == fill_colour)
415 painter->setPen(Qt::NoPen);
416 else
417 painter->setPen(outline_colour);
418
419 painter->setBrush(fill_colour);
420
421 const int radius = (cornerSize ? 25 : 0);
422
423 painter->drawRoundRect(
424 QRectF(rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top),
425 radius, radius);
426 }
427
GradientRectangle(PRectangle rc,const std::vector<ColourStop> & stops,GradientOptions options)428 void SurfaceImpl::GradientRectangle(PRectangle rc,
429 const std::vector<ColourStop> &stops, GradientOptions options)
430 {
431 Q_ASSERT(painter);
432
433 QLinearGradient gradient;
434
435 switch (options)
436 {
437 case GradientOptions::leftToRight:
438 gradient = QLinearGradient(rc.left, rc.top, rc.right, rc.top);
439 break;
440
441 case GradientOptions::topToBottom:
442 default:
443 gradient = QLinearGradient(rc.left, rc.top, rc.left, rc.bottom);
444 }
445
446 gradient.setSpread(QGradient::RepeatSpread);
447
448 for (const ColourStop &stop : stops)
449 gradient.setColorAt(stop.position,
450 convertQColor(stop.colour, stop.colour.GetAlpha()));
451
452 painter->fillRect(
453 QRectF(rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top),
454 QBrush(gradient));
455 }
456
drawRect(const PRectangle & rc)457 void SurfaceImpl::drawRect(const PRectangle &rc)
458 {
459 painter->drawRect(
460 QRectF(rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top));
461 }
462
Ellipse(PRectangle rc,ColourDesired fore,ColourDesired back)463 void SurfaceImpl::Ellipse(PRectangle rc, ColourDesired fore,
464 ColourDesired back)
465 {
466 Q_ASSERT(painter);
467
468 painter->setPen(convertQColor(fore));
469 painter->setBrush(convertQColor(back));
470 painter->drawEllipse(
471 QRectF(rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top));
472 }
473
Copy(PRectangle rc,Point from,Surface & surfaceSource)474 void SurfaceImpl::Copy(PRectangle rc, Point from, Surface &surfaceSource)
475 {
476 Q_ASSERT(painter);
477
478 SurfaceImpl &si = static_cast<SurfaceImpl &>(surfaceSource);
479
480 if (si.pd)
481 {
482 QPixmap *pm = static_cast<QPixmap *>(si.pd);
483 qreal x = from.x;
484 qreal y = from.y;
485 qreal width = rc.right - rc.left;
486 qreal height = rc.bottom - rc.top;
487
488 #if QT_VERSION >= 0x050100
489 qreal dpr = pm->devicePixelRatio();
490
491 x *= dpr;
492 y *= dpr;
493 width *= dpr;
494 height *= dpr;
495 #endif
496
497 painter->drawPixmap(QPointF(rc.left, rc.top), *pm,
498 QRectF(x, y, width, height));
499 }
500 }
501
DrawTextNoClip(PRectangle rc,Font & font_,XYPOSITION ybase,const char * s,int len,ColourDesired fore,ColourDesired back)502 void SurfaceImpl::DrawTextNoClip(PRectangle rc, Font &font_, XYPOSITION ybase,
503 const char *s, int len, ColourDesired fore, ColourDesired back)
504 {
505 Q_ASSERT(painter);
506
507 FillRectangle(rc, back);
508 drawText(rc, font_, ybase, s, len, fore);
509 }
510
DrawTextClipped(PRectangle rc,Font & font_,XYPOSITION ybase,const char * s,int len,ColourDesired fore,ColourDesired back)511 void SurfaceImpl::DrawTextClipped(PRectangle rc, Font &font_, XYPOSITION ybase,
512 const char *s, int len, ColourDesired fore, ColourDesired back)
513 {
514 Q_ASSERT(painter);
515
516 SetClip(rc);
517 DrawTextNoClip(rc, font_, ybase, s, len, fore, back);
518 painter->setClipping(false);
519 }
520
DrawTextTransparent(PRectangle rc,Font & font_,XYPOSITION ybase,const char * s,int len,ColourDesired fore)521 void SurfaceImpl::DrawTextTransparent(PRectangle rc, Font &font_,
522 XYPOSITION ybase, const char *s, int len, ColourDesired fore)
523 {
524 // Only draw if there is a non-space.
525 for (int i = 0; i < len; ++i)
526 if (s[i] != ' ')
527 {
528 drawText(rc, font_, ybase, s, len, fore);
529 return;
530 }
531 }
532
drawText(const PRectangle & rc,Font & font_,XYPOSITION ybase,const char * s,int len,ColourDesired fore)533 void SurfaceImpl::drawText(const PRectangle &rc, Font &font_, XYPOSITION ybase,
534 const char *s, int len, ColourDesired fore)
535 {
536 QString qs = convertText(s, len);
537
538 QFont *f = PFont(font_.GetID());
539
540 if (f)
541 painter->setFont(*f);
542
543 painter->setPen(convertQColor(fore));
544 painter->drawText(QPointF(rc.left, ybase), qs);
545 }
546
DrawXPM(PRectangle rc,const XPM * xpm)547 void SurfaceImpl::DrawXPM(PRectangle rc, const XPM *xpm)
548 {
549 Q_ASSERT(painter);
550
551 XYPOSITION x, y;
552 const QPixmap &qpm = xpm->Pixmap();
553
554 x = rc.left + (rc.Width() - qpm.width()) / 2.0;
555 y = rc.top + (rc.Height() - qpm.height()) / 2.0;
556
557 painter->drawPixmap(QPointF(x, y), qpm);
558 }
559
DrawRGBAImage(PRectangle rc,int width,int height,const unsigned char * pixelsImage)560 void SurfaceImpl::DrawRGBAImage(PRectangle rc, int width, int height,
561 const unsigned char *pixelsImage)
562 {
563 Q_UNUSED(width);
564 Q_UNUSED(height);
565 Q_ASSERT(painter);
566
567 const QImage *qim = reinterpret_cast<const QImage *>(pixelsImage);
568
569 painter->drawImage(QPointF(rc.left, rc.top), *qim);
570 }
571
MeasureWidths(Font & font_,const char * s,int len,XYPOSITION * positions)572 void SurfaceImpl::MeasureWidths(Font &font_, const char *s, int len,
573 XYPOSITION *positions)
574 {
575 QString qs = convertText(s, len);
576 QTextLayout text_layout(qs, convertQFont(font_), pd);
577
578 text_layout.beginLayout();
579 QTextLine text_line = text_layout.createLine();
580 text_layout.endLayout();
581
582 if (unicodeMode)
583 {
584 int i_char = 0, i_byte = 0;;
585
586 while (i_char < qs.size())
587 {
588 unsigned char byte = s[i_byte];
589 int nbytes, code_units;
590
591 // Work out character sizes by looking at the byte stream.
592 if (byte >= 0xf0)
593 {
594 nbytes = 4;
595 code_units = 2;
596 }
597 else
598 {
599 if (byte >= 0xe0)
600 nbytes = 3;
601 else if (byte >= 0x80)
602 nbytes = 2;
603 else
604 nbytes = 1;
605
606 code_units = 1;
607 }
608
609 XYPOSITION position = text_line.cursorToX(i_char + code_units);
610
611 // Set the same position for each byte of the character.
612 for (int i = 0; i < nbytes && i_byte < len; ++i)
613 positions[i_byte++] = position;
614
615 i_char += code_units;
616 }
617
618 // This shouldn't be necessary...
619 XYPOSITION last_position = ((i_byte > 0) ? positions[i_byte - 1] : 0);
620
621 while (i_byte < len)
622 positions[i_byte++] = last_position;
623 }
624 else
625 {
626 for (int i = 0; i < len; ++i)
627 positions[i] = text_line.cursorToX(i + 1);
628 }
629 }
630
WidthText(Font & font_,const char * s,int len)631 XYPOSITION SurfaceImpl::WidthText(Font &font_, const char *s, int len)
632 {
633 return metrics(font_).width(convertText(s, len));
634
635 }
636
Ascent(Font & font_)637 XYPOSITION SurfaceImpl::Ascent(Font &font_)
638 {
639 return metrics(font_).ascent();
640 }
641
Descent(Font & font_)642 XYPOSITION SurfaceImpl::Descent(Font &font_)
643 {
644 // Qt doesn't include the baseline in the descent, so add it. Note that
645 // a descent from Qt4 always seems to be 2 pixels larger (irrespective of
646 // font or size) than the same descent from Qt3. This means that text is a
647 // little more spaced out with Qt4 - and will be more noticeable with
648 // smaller fonts.
649 return metrics(font_).descent() + 1;
650 }
651
Height(Font & font_)652 XYPOSITION SurfaceImpl::Height(Font &font_)
653 {
654 return metrics(font_).height();
655 }
656
AverageCharWidth(Font & font_)657 XYPOSITION SurfaceImpl::AverageCharWidth(Font &font_)
658 {
659 #if QT_VERSION >= 0x040200
660 return metrics(font_).averageCharWidth();
661 #else
662 return metrics(font_).width('n');
663 #endif
664 }
665
SetClip(PRectangle rc)666 void SurfaceImpl::SetClip(PRectangle rc)
667 {
668 Q_ASSERT(painter);
669
670 painter->setClipRect(
671 QRectF(rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top));
672 }
673
FlushCachedState()674 void SurfaceImpl::FlushCachedState()
675 {
676 }
677
678 // Return the QFont for a Font.
convertQFont(Font & font)679 QFont SurfaceImpl::convertQFont(Font &font)
680 {
681 QFont *f = PFont(font.GetID());
682
683 if (f)
684 return *f;
685
686 return QApplication::font();
687 }
688
689 // Get the metrics for a font.
metrics(Font & font_)690 QFontMetricsF SurfaceImpl::metrics(Font &font_)
691 {
692 QFont fnt = convertQFont(font_);
693
694 return QFontMetricsF(fnt, pd);
695 }
696
697 // Convert a Scintilla string to a Qt Unicode string.
convertText(const char * s,int len)698 QString SurfaceImpl::convertText(const char *s, int len)
699 {
700 if (unicodeMode)
701 return QString::fromUtf8(s, len);
702
703 return QString::fromLatin1(s, len);
704 }
705
706
707 // Convert a Scintilla colour, and alpha component, to a Qt QColor.
convertQColor(const ColourDesired & col,unsigned alpha)708 QColor SurfaceImpl::convertQColor(const ColourDesired &col, unsigned alpha)
709 {
710 int c = col.AsInteger();
711
712 unsigned r = c & 0xff;
713 unsigned g = (c >> 8) & 0xff;
714 unsigned b = (c >> 16) & 0xff;
715
716 return QColor(r, g, b, alpha);
717 }
718
719
720 // Window (widget) management.
~Window()721 Window::~Window()
722 {
723 }
724
Destroy()725 void Window::Destroy()
726 {
727 QWidget *w = PWindow(wid);
728
729 if (w)
730 {
731 // Delete the widget next time round the event loop rather than
732 // straight away. This gets round a problem when auto-completion lists
733 // are cancelled after an entry has been double-clicked, ie. the list's
734 // dtor is called from one of the list's slots. There are other ways
735 // around the problem but this is the simplest and doesn't seem to
736 // cause problems of its own.
737 w->deleteLater();
738 wid = 0;
739 }
740 }
741
GetPosition() const742 PRectangle Window::GetPosition() const
743 {
744 QWidget *w = PWindow(wid);
745
746 // Before any size allocated pretend its big enough not to be scrolled.
747 PRectangle rc(0,0,5000,5000);
748
749 if (w)
750 {
751 const QRect &r = w->geometry();
752
753 rc.right = r.right() - r.left() + 1;
754 rc.bottom = r.bottom() - r.top() + 1;
755 }
756
757 return rc;
758 }
759
SetPosition(PRectangle rc)760 void Window::SetPosition(PRectangle rc)
761 {
762 PWindow(wid)->setGeometry(rc.left, rc.top, rc.right - rc.left,
763 rc.bottom - rc.top);
764 }
765
SetPositionRelative(PRectangle rc,const Window * relativeTo)766 void Window::SetPositionRelative(PRectangle rc, const Window *relativeTo)
767 {
768 QWidget *rel = PWindow(relativeTo->wid);
769 QPoint pos = rel->mapToGlobal(rel->pos());
770
771 int x = pos.x() + rc.left;
772 int y = pos.y() + rc.top;
773
774 PWindow(wid)->setGeometry(x, y, rc.right - rc.left, rc.bottom - rc.top);
775 }
776
GetClientPosition() const777 PRectangle Window::GetClientPosition() const
778 {
779 return GetPosition();
780 }
781
Show(bool show)782 void Window::Show(bool show)
783 {
784 QWidget *w = PWindow(wid);
785
786 if (show)
787 w->show();
788 else
789 w->hide();
790 }
791
InvalidateAll()792 void Window::InvalidateAll()
793 {
794 QWidget *w = PWindow(wid);
795
796 if (w)
797 w->update();
798 }
799
InvalidateRectangle(PRectangle rc)800 void Window::InvalidateRectangle(PRectangle rc)
801 {
802 QWidget *w = PWindow(wid);
803
804 if (w)
805 w->update(rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top);
806 }
807
SetFont(Font & font)808 void Window::SetFont(Font &font)
809 {
810 PWindow(wid)->setFont(*PFont(font.GetID()));
811 }
812
SetCursor(Cursor curs)813 void Window::SetCursor(Cursor curs)
814 {
815 Qt::CursorShape qc;
816
817 switch (curs)
818 {
819 case cursorText:
820 qc = Qt::IBeamCursor;
821 break;
822
823 case cursorUp:
824 qc = Qt::UpArrowCursor;
825 break;
826
827 case cursorWait:
828 qc = Qt::WaitCursor;
829 break;
830
831 case cursorHoriz:
832 qc = Qt::SizeHorCursor;
833 break;
834
835 case cursorVert:
836 qc = Qt::SizeVerCursor;
837 break;
838
839 case cursorHand:
840 qc = Qt::PointingHandCursor;
841 break;
842
843 default:
844 // Note that Qt doesn't have a standard cursor that could be used to
845 // implement cursorReverseArrow.
846 qc = Qt::ArrowCursor;
847 }
848
849 PWindow(wid)->setCursor(qc);
850 }
851
GetMonitorRect(Point pt)852 PRectangle Window::GetMonitorRect(Point pt)
853 {
854 QPoint qpt = PWindow(wid)->mapToGlobal(QPoint(pt.x, pt.y));
855 QRect qr = QApplication::desktop()->availableGeometry(qpt);
856 qpt = PWindow(wid)->mapFromGlobal(qr.topLeft());
857
858 return PRectangle(qpt.x(), qpt.y(), qpt.x() + qr.width(), qpt.y() + qr.height());
859 }
860
861
862 // Menu management.
Menu()863 Menu::Menu() noexcept : mid(0)
864 {
865 }
866
CreatePopUp()867 void Menu::CreatePopUp()
868 {
869 Destroy();
870 mid = new QsciSciPopup();
871 }
872
Destroy()873 void Menu::Destroy()
874 {
875 QsciSciPopup *m = PMenu(mid);
876
877 if (m)
878 {
879 delete m;
880 mid = 0;
881 }
882 }
883
Show(Point pt,Window &)884 void Menu::Show(Point pt, Window &)
885 {
886 PMenu(mid)->popup(QPoint(pt.x, pt.y));
887 }
888
889
890 class DynamicLibraryImpl : public DynamicLibrary
891 {
892 public:
DynamicLibraryImpl(const char * modulePath)893 DynamicLibraryImpl(const char *modulePath)
894 {
895 m = new QLibrary(modulePath);
896 m->load();
897 }
898
~DynamicLibraryImpl()899 virtual ~DynamicLibraryImpl()
900 {
901 if (m)
902 delete m;
903 }
904
FindFunction(const char * name)905 virtual Function FindFunction(const char *name)
906 {
907 if (m)
908 return (Function)m->resolve(name);
909
910 return 0;
911 }
912
IsValid()913 virtual bool IsValid()
914 {
915 return m && m->isLoaded();
916 }
917
918 private:
919 QLibrary* m;
920 };
921
Load(const char * modulePath)922 DynamicLibrary *DynamicLibrary::Load(const char *modulePath)
923 {
924 return new DynamicLibraryImpl(modulePath);
925 }
926
927
928 // Manage system wide parameters.
Chrome()929 ColourDesired Platform::Chrome()
930 {
931 return ColourDesired(0xe0,0xe0,0xe0);
932 }
933
ChromeHighlight()934 ColourDesired Platform::ChromeHighlight()
935 {
936 return ColourDesired(0xff,0xff,0xff);
937 }
938
DefaultFont()939 const char *Platform::DefaultFont()
940 {
941 static QByteArray def_font;
942
943 def_font = QApplication::font().family().toLatin1();
944
945 return def_font.constData();
946 }
947
DefaultFontSize()948 int Platform::DefaultFontSize()
949 {
950 return QApplication::font().pointSize();
951 }
952
DoubleClickTime()953 unsigned int Platform::DoubleClickTime()
954 {
955 return QApplication::doubleClickInterval();
956 }
957
DebugDisplay(const char * s)958 void Platform::DebugDisplay(const char *s)
959 {
960 qDebug("%s", s);
961 }
962
963 //#define TRACE
964
965 #ifdef TRACE
DebugPrintf(const char * format,...)966 void Platform::DebugPrintf(const char *format, ...)
967 {
968 char buffer[2000];
969 va_list pArguments;
970
971 va_start(pArguments, format);
972 vsprintf(buffer, format, pArguments);
973 va_end(pArguments);
974
975 DebugDisplay(buffer);
976 }
977 #else
DebugPrintf(const char *,...)978 void Platform::DebugPrintf(const char *, ...)
979 {
980 }
981 #endif
982
983 static bool assertionPopUps = true;
984
ShowAssertionPopUps(bool assertionPopUps_)985 bool Platform::ShowAssertionPopUps(bool assertionPopUps_)
986 {
987 bool ret = assertionPopUps;
988
989 assertionPopUps = assertionPopUps_;
990
991 return ret;
992 }
993
Assert(const char * c,const char * file,int line)994 void Platform::Assert(const char *c, const char *file, int line)
995 {
996 qFatal("Assertion [%s] failed at %s %d\n", c, file, line);
997 }
998
999 }
1000