aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--qt/README36
-rw-r--r--qt/ScintillaEdit/ScintillaDocument.cpp286
-rw-r--r--qt/ScintillaEdit/ScintillaDocument.h97
-rw-r--r--qt/ScintillaEdit/ScintillaEdit.cpp.template59
-rw-r--r--qt/ScintillaEdit/ScintillaEdit.h.template63
-rw-r--r--qt/ScintillaEdit/ScintillaEdit.pro72
-rw-r--r--qt/ScintillaEdit/WidgetGen.py275
-rw-r--r--qt/ScintillaEditBase/Notes.txt18
-rw-r--r--qt/ScintillaEditBase/PlatQt.cpp1282
-rw-r--r--qt/ScintillaEditBase/PlatQt.h127
-rw-r--r--qt/ScintillaEditBase/ScintillaEditBase.cpp635
-rw-r--r--qt/ScintillaEditBase/ScintillaEditBase.h151
-rw-r--r--qt/ScintillaEditBase/ScintillaEditBase.pro111
-rw-r--r--qt/ScintillaEditBase/ScintillaQt.cpp772
-rw-r--r--qt/ScintillaEditBase/ScintillaQt.h158
-rw-r--r--qt/ScintillaEditPy/README85
-rw-r--r--qt/ScintillaEditPy/ScintillaConstants.py.template6
-rw-r--r--qt/ScintillaEditPy/ScintillaEditPy.pro116
-rw-r--r--qt/ScintillaEditPy/global.h4
-rw-r--r--qt/ScintillaEditPy/sepbuild.py312
-rw-r--r--qt/ScintillaEditPy/testsepq.py157
-rw-r--r--qt/ScintillaEditPy/typesystem_ScintillaEdit.xml.template16
22 files changed, 4838 insertions, 0 deletions
diff --git a/qt/README b/qt/README
new file mode 100644
index 000000000..a39008b38
--- /dev/null
+++ b/qt/README
@@ -0,0 +1,36 @@
+README for building of Scintilla on Qt
+
+There are three different Scintilla libraries that can be produced:
+
+ ScintillaEditBase
+A basic widget callable from C++ which is small and can be used just as is
+or with higher level functionality added.
+
+ ScintillaEdit
+A more complete C++ widget with a method for every Scintilla API and a
+secondary API allowing direct access to document objects.
+
+ ScintillaEditPy
+A Python callable version of ScintillaEdit using the PySide bindings.
+
+ Building a library
+
+ScintillaEditBase can be built without performing any generation steps.
+The ScintillaEditBase/ScintillaEditBase.pro project can be loaded into
+Qt Creator and the "Build All" command performed.
+Alternatively, run "qmake" to build make files and then use the platform
+make to build. Most commonly, use "make" on Unix and "nmake"
+on Windows.
+
+ScintillaEdit requires a generation command be run first. From the
+ScintillaEdit directory:
+
+python WidgetGen.py
+
+After the generation command has run, the ScintillaEdit.h and
+ScintillaEdit.cpp files will have been populated with the Scintilla API
+methods.
+To build, use Qt Creator or qmake and make as for ScintillaEditBase.
+
+ScintillaEditPy is more complex and instructions are found in
+ScintillaEditPy/README.
diff --git a/qt/ScintillaEdit/ScintillaDocument.cpp b/qt/ScintillaEdit/ScintillaDocument.cpp
new file mode 100644
index 000000000..801f6a385
--- /dev/null
+++ b/qt/ScintillaEdit/ScintillaDocument.cpp
@@ -0,0 +1,286 @@
+// ScintillaDocument.cpp
+// Wrapper for Scintilla document object so it can be manipulated independently.
+// Copyright (c) 2011 Archaeopteryx Software, Inc. d/b/a Wingware
+
+#include <vector>
+#include <map>
+
+#include "ScintillaDocument.h"
+
+#include "Platform.h"
+
+#include "ILexer.h"
+#include "Scintilla.h"
+
+#include "SplitVector.h"
+#include "Partitioning.h"
+#include "RunStyles.h"
+#include "ContractionState.h"
+#include "CellBuffer.h"
+#include "KeyMap.h"
+#include "Indicator.h"
+#include "XPM.h"
+#include "LineMarker.h"
+#include "Style.h"
+#include "ViewStyle.h"
+#include "CharClassify.h"
+#include "Decoration.h"
+#include "Document.h"
+
+class WatcherHelper : public DocWatcher {
+ ScintillaDocument *owner;
+public:
+ WatcherHelper(ScintillaDocument *owner_);
+ virtual ~WatcherHelper();
+
+ void NotifyModifyAttempt(Document *doc, void *userData);
+ void NotifySavePoint(Document *doc, void *userData, bool atSavePoint);
+ void NotifyModified(Document *doc, DocModification mh, void *userData);
+ void NotifyDeleted(Document *doc, void *userData);
+ void NotifyStyleNeeded(Document *doc, void *userData, int endPos);
+ void NotifyLexerChanged(Document *doc, void *userData);
+ void NotifyErrorOccurred(Document *doc, void *userData, int status);
+};
+
+WatcherHelper::WatcherHelper(ScintillaDocument *owner_) : owner(owner_) {
+}
+
+WatcherHelper::~WatcherHelper() {
+}
+
+void WatcherHelper::NotifyModifyAttempt(Document *, void *) {
+ owner->emit_modify_attempt();
+}
+
+void WatcherHelper::NotifySavePoint(Document *, void *, bool atSavePoint) {
+ owner->emit_save_point(atSavePoint);
+}
+
+void WatcherHelper::NotifyModified(Document *, DocModification mh, void *) {
+ int length = mh.length;
+ if (!mh.text)
+ length = 0;
+ QByteArray ba = QByteArray::fromRawData(mh.text, length);
+ owner->emit_modified(mh.position, mh.modificationType, ba, length,
+ mh.linesAdded, mh.line, mh.foldLevelNow, mh.foldLevelPrev);
+}
+
+void WatcherHelper::NotifyDeleted(Document *, void *) {
+}
+
+void WatcherHelper::NotifyStyleNeeded(Document *, void *, int endPos) {
+ owner->emit_style_needed(endPos);
+}
+
+void WatcherHelper::NotifyLexerChanged(Document *, void *) {
+ owner->emit_lexer_changed();
+}
+
+void WatcherHelper::NotifyErrorOccurred(Document *, void *, int status) {
+ owner->emit_error_occurred(status);
+}
+
+ScintillaDocument::ScintillaDocument(QObject *parent, void *pdoc_) :
+ QObject(parent), pdoc(pdoc_), docWatcher(0) {
+ if (!pdoc) {
+ pdoc = new Document();
+ }
+ docWatcher = new WatcherHelper(this);
+ ((Document *)pdoc)->AddRef();
+ ((Document *)pdoc)->AddWatcher(docWatcher, pdoc);
+}
+
+ScintillaDocument::~ScintillaDocument() {
+ Document *doc = static_cast<Document *>(pdoc);
+ if (doc) {
+ doc->RemoveWatcher(docWatcher, doc);
+ doc->Release();
+ }
+ pdoc = NULL;
+ delete docWatcher;
+ docWatcher = NULL;
+}
+
+void *ScintillaDocument::pointer() {
+ return pdoc;
+}
+
+int ScintillaDocument::line_from_position(int pos) {
+ return ((Document *)pdoc)->LineFromPosition(pos);
+}
+
+bool ScintillaDocument::is_cr_lf(int pos) {
+ return ((Document *)pdoc)->IsCrLf(pos);
+}
+
+bool ScintillaDocument::delete_chars(int pos, int len) {
+ return ((Document *)pdoc)->DeleteChars(pos, len);
+}
+
+int ScintillaDocument::undo() {
+ return ((Document *)pdoc)->Undo();
+}
+
+int ScintillaDocument::redo() {
+ return ((Document *)pdoc)->Redo();
+}
+
+bool ScintillaDocument::can_undo() {
+ return ((Document *)pdoc)->CanUndo();
+}
+
+bool ScintillaDocument::can_redo() {
+ return ((Document *)pdoc)->CanRedo();
+}
+
+void ScintillaDocument::delete_undo_history() {
+ ((Document *)pdoc)->DeleteUndoHistory();
+}
+
+bool ScintillaDocument::set_undo_collection(bool collect_undo) {
+ return ((Document *)pdoc)->SetUndoCollection(collect_undo);
+}
+
+bool ScintillaDocument::is_collecting_undo() {
+ return ((Document *)pdoc)->IsCollectingUndo();
+}
+
+void ScintillaDocument::begin_undo_action() {
+ ((Document *)pdoc)->BeginUndoAction();
+}
+
+void ScintillaDocument::end_undo_action() {
+ ((Document *)pdoc)->EndUndoAction();
+}
+
+void ScintillaDocument::set_save_point() {
+ ((Document *)pdoc)->SetSavePoint();
+}
+
+bool ScintillaDocument::is_save_point() {
+ return ((Document *)pdoc)->IsSavePoint();
+}
+
+void ScintillaDocument::set_read_only(bool read_only) {
+ ((Document *)pdoc)->SetReadOnly(read_only);
+}
+
+bool ScintillaDocument::is_read_only() {
+ return ((Document *)pdoc)->IsReadOnly();
+}
+
+void ScintillaDocument::insert_string(int position, QByteArray &str) {
+ ((Document *)pdoc)->InsertString(position, str.data(), str.size());
+}
+
+QByteArray ScintillaDocument::get_char_range(int position, int length) {
+ Document *doc = (Document *)pdoc;
+
+ if (position < 0 || length <= 0 || position + length > doc->Length())
+ return QByteArray();
+
+ QByteArray ba(length, '\0');
+ doc->GetCharRange(ba.data(), position, length);
+ return ba;
+}
+
+char ScintillaDocument::style_at(int position) {
+ return ((Document *)pdoc)->StyleAt(position);
+}
+
+int ScintillaDocument::line_start(int lineno) {
+ return ((Document *)pdoc)->LineStart(lineno);
+}
+
+int ScintillaDocument::line_end(int lineno) {
+ return ((Document *)pdoc)->LineEnd(lineno);
+}
+
+int ScintillaDocument::line_end_position(int pos) {
+ return ((Document *)pdoc)->LineEndPosition(pos);
+}
+
+int ScintillaDocument::length() {
+ return ((Document *)pdoc)->Length();
+}
+
+int ScintillaDocument::lines_total() {
+ return ((Document *)pdoc)->LinesTotal();
+}
+
+void ScintillaDocument::start_styling(int position, char flags) {
+ ((Document *)pdoc)->StartStyling(position, flags);
+}
+
+bool ScintillaDocument::set_style_for(int length, char style) {
+ return ((Document *)pdoc)->SetStyleFor(length, style);
+}
+
+int ScintillaDocument::get_end_styled() {
+ return ((Document *)pdoc)->GetEndStyled();
+}
+
+void ScintillaDocument::ensure_styled_to(int position) {
+ ((Document *)pdoc)->EnsureStyledTo(position);
+}
+
+void ScintillaDocument::set_current_indicator(int indic) {
+ ((Document *)pdoc)->decorations.SetCurrentIndicator(indic);
+}
+
+void ScintillaDocument::decoration_fill_range(int position, int value, int fillLength) {
+ ((Document *)pdoc)->DecorationFillRange(position, value, fillLength);
+}
+
+int ScintillaDocument::decorations_value_at(int indic, int position) {
+ return ((Document *)pdoc)->decorations.ValueAt(indic, position);
+}
+
+int ScintillaDocument::decorations_start(int indic, int position) {
+ return ((Document *)pdoc)->decorations.Start(indic, position);
+}
+
+int ScintillaDocument::decorations_end(int indic, int position) {
+ return ((Document *)pdoc)->decorations.End(indic, position);
+}
+
+int ScintillaDocument::get_code_page() {
+ return ((Document *)pdoc)->CodePage();
+}
+
+void ScintillaDocument::set_code_page(int code_page) {
+ ((Document *)pdoc)->dbcsCodePage = code_page;
+}
+
+int ScintillaDocument::move_position_outside_char(int pos, int move_dir, bool check_line_end) {
+ return ((Document *)pdoc)->MovePositionOutsideChar(pos, move_dir, check_line_end);
+}
+
+// Signal emitters
+
+void ScintillaDocument::emit_modify_attempt() {
+ emit modify_attempt();
+}
+
+void ScintillaDocument::emit_save_point(bool atSavePoint) {
+ emit save_point(atSavePoint);
+}
+
+void ScintillaDocument::emit_modified(int position, int modification_type, const QByteArray& text, int length,
+ int linesAdded, int line, int foldLevelNow, int foldLevelPrev) {
+ emit modified(position, modification_type, text, length,
+ linesAdded, line, foldLevelNow, foldLevelPrev);
+}
+
+void ScintillaDocument::emit_style_needed(int pos) {
+ emit style_needed(pos);
+}
+
+void ScintillaDocument::emit_lexer_changed() {
+ emit lexer_changed();
+}
+
+void ScintillaDocument::emit_error_occurred(int status) {
+ emit error_occurred(status);
+}
+
diff --git a/qt/ScintillaEdit/ScintillaDocument.h b/qt/ScintillaEdit/ScintillaDocument.h
new file mode 100644
index 000000000..3cf16e334
--- /dev/null
+++ b/qt/ScintillaEdit/ScintillaDocument.h
@@ -0,0 +1,97 @@
+// ScintillaDocument.h
+// Wrapper for Scintilla document object so it can be manipulated independently.
+// Copyright (c) 2011 Archaeopteryx Software, Inc. d/b/a Wingware
+
+#ifndef SCINTILLADOCUMENT_H
+#define SCINTILLADOCUMENT_H
+
+#include <QObject>
+
+class WatcherHelper;
+
+#ifndef EXPORT_IMPORT_API
+#ifdef WIN32
+#ifdef MAKING_LIBRARY
+#define EXPORT_IMPORT_API __declspec(dllexport)
+#else
+// Defining dllimport upsets moc
+#define EXPORT_IMPORT_API __declspec(dllimport)
+//#define EXPORT_IMPORT_API
+#endif
+#else
+#define EXPORT_IMPORT_API
+#endif
+#endif
+
+class EXPORT_IMPORT_API ScintillaDocument : public QObject
+{
+ Q_OBJECT
+
+ void *pdoc;
+ WatcherHelper *docWatcher;
+
+public:
+ explicit ScintillaDocument(QObject *parent = 0, void *pdoc_=0);
+ virtual ~ScintillaDocument();
+ void *pointer();
+
+ int line_from_position(int pos);
+ bool is_cr_lf(int pos);
+ bool delete_chars(int pos, int len);
+ int undo();
+ int redo();
+ bool can_undo();
+ bool can_redo();
+ void delete_undo_history();
+ bool set_undo_collection(bool collect_undo);
+ bool is_collecting_undo();
+ void begin_undo_action();
+ void end_undo_action();
+ void set_save_point();
+ bool is_save_point();
+ void set_read_only(bool read_only);
+ bool is_read_only();
+ void insert_string(int position, QByteArray &str);
+ QByteArray get_char_range(int position, int length);
+ char style_at(int position);
+ int line_start(int lineno);
+ int line_end(int lineno);
+ int line_end_position(int pos);
+ int length();
+ int lines_total();
+ void start_styling(int position, char flags);
+ bool set_style_for(int length, char style);
+ int get_end_styled();
+ void ensure_styled_to(int position);
+ void set_current_indicator(int indic);
+ void decoration_fill_range(int position, int value, int fillLength);
+ int decorations_value_at(int indic, int position);
+ int decorations_start(int indic, int position);
+ int decorations_end(int indic, int position);
+ int get_code_page();
+ void set_code_page(int code_page);
+ int move_position_outside_char(int pos, int move_dir, bool check_line_end);
+
+private:
+ void emit_modify_attempt();
+ void emit_save_point(bool atSavePoint);
+ void emit_modified(int position, int modification_type, const QByteArray& text, int length,
+ int linesAdded, int line, int foldLevelNow, int foldLevelPrev);
+ void emit_style_needed(int pos);
+ void emit_lexer_changed();
+ void emit_error_occurred(int status);
+
+signals:
+ void modify_attempt();
+ void save_point(bool atSavePoint);
+ void modified(int position, int modification_type, const QByteArray& text, int length,
+ int linesAdded, int line, int foldLevelNow, int foldLevelPrev);
+ void style_needed(int pos);
+ void lexer_changed();
+ void error_occurred(int status);
+
+ friend class WatcherHelper;
+
+};
+
+#endif // SCINTILLADOCUMENT_H
diff --git a/qt/ScintillaEdit/ScintillaEdit.cpp.template b/qt/ScintillaEdit/ScintillaEdit.cpp.template
new file mode 100644
index 000000000..431e79c4e
--- /dev/null
+++ b/qt/ScintillaEdit/ScintillaEdit.cpp.template
@@ -0,0 +1,59 @@
+// ScintillaEdit.cpp
+// Extended version of ScintillaEditBase with a method for each API
+// Copyright (c) 2011 Archaeopteryx Software, Inc. d/b/a Wingware
+
+#include "ScintillaEdit.h"
+
+ScintillaEdit::ScintillaEdit(QWidget *parent) : ScintillaEditBase(parent) {
+}
+
+ScintillaEdit::~ScintillaEdit() {
+}
+
+QByteArray ScintillaEdit::TextReturner(int message, uptr_t wParam) const {
+ int length = send(message, wParam, 0);
+ QByteArray ba(length, '\0');
+ send(message, wParam, (sptr_t)ba.data());
+ // Remove extra NULs
+ if (ba.size() > 0 && ba.at(ba.size()-1) == 0)
+ ba.chop(1);
+ return ba;
+}
+
+QPair<int, int>ScintillaEdit::find_text(int flags, const char *text, int cpMin, int cpMax) {
+ struct TextToFind ft = {{0, 0}, 0, {0, 0}};
+ ft.chrg.cpMin = cpMin;
+ ft.chrg.cpMax = cpMax;
+ ft.chrgText.cpMin = cpMin;
+ ft.chrgText.cpMax = cpMax;
+ ft.lpstrText = const_cast<char *>(text);
+
+ send(SCI_FINDTEXT, flags, (uptr_t) (&ft));
+
+ return QPair<int,int>(ft.chrgText.cpMin, ft.chrgText.cpMax);
+}
+
+QByteArray ScintillaEdit::get_text_range(int start, int end) {
+ if (start > end)
+ start = end;
+
+ int length = end-start;
+ QByteArray ba(length+1, '\0');
+ struct TextRange tr = {{start, end}, ba.data()};
+
+ length = send(SCI_GETTEXTRANGE, 0, (sptr_t)&tr);
+ ba.chop(1); // Remove extra NUL
+
+ return ba;
+}
+
+ScintillaDocument *ScintillaEdit::get_doc() {
+ return new ScintillaDocument(0, (void *)send(SCI_GETDOCPOINTER, 0, 0));
+}
+
+void ScintillaEdit::set_doc(ScintillaDocument *pdoc_) {
+ send(SCI_SETDOCPOINTER, 0, (sptr_t)(pdoc_->pointer()));
+}
+
+/* ++Autogenerated -- start of section automatically generated from Scintilla.iface */
+/* --Autogenerated -- end of section automatically generated from Scintilla.iface */
diff --git a/qt/ScintillaEdit/ScintillaEdit.h.template b/qt/ScintillaEdit/ScintillaEdit.h.template
new file mode 100644
index 000000000..32c8a7726
--- /dev/null
+++ b/qt/ScintillaEdit/ScintillaEdit.h.template
@@ -0,0 +1,63 @@
+// ScintillaEdit.h
+// Extended version of ScintillaEditBase with a method for each API
+// Copyright (c) 2011 Archaeopteryx Software, Inc. d/b/a Wingware
+
+#ifndef SCINTILLAEDIT_H
+#define SCINTILLAEDIT_H
+
+#include <QPair>
+
+#include "ScintillaEditBase.h"
+#include "ScintillaDocument.h"
+
+#ifdef SCI_NAMESPACE
+namespace Scintilla {
+#endif
+
+#ifndef EXPORT_IMPORT_API
+#ifdef WIN32
+#ifdef MAKING_LIBRARY
+#define EXPORT_IMPORT_API __declspec(dllexport)
+#else
+// Defining dllimport upsets moc
+#define EXPORT_IMPORT_API __declspec(dllimport)
+//#define EXPORT_IMPORT_API
+#endif
+#else
+#define EXPORT_IMPORT_API
+#endif
+#endif
+
+class EXPORT_IMPORT_API ScintillaEdit : public ScintillaEditBase {
+ Q_OBJECT
+
+public:
+ ScintillaEdit(QWidget *parent = 0);
+ virtual ~ScintillaEdit();
+
+ QByteArray TextReturner(int message, uptr_t wParam) const;
+
+ QPair<int, int>find_text(int flags, const char *text, int cpMin, int cpMax);
+ QByteArray get_text_range(int start, int end);
+ ScintillaDocument *get_doc();
+ void set_doc(ScintillaDocument *pdoc_);
+
+ // Same as previous two methods but with Qt style names
+ QPair<int, int>findText(int flags, const char *text, int cpMin, int cpMax) {
+ return find_text(flags, text, cpMin, cpMax);
+ }
+
+ QByteArray textRange(int start, int end) {
+ return get_text_range(start, end);
+ }
+
+/* ++Autogenerated -- start of section automatically generated from Scintilla.iface */
+/* --Autogenerated -- end of section automatically generated from Scintilla.iface */
+
+};
+
+#ifdef SCI_NAMESPACE
+}
+#endif
+
+#endif /* SCINTILLAEDIT_H */
diff --git a/qt/ScintillaEdit/ScintillaEdit.pro b/qt/ScintillaEdit/ScintillaEdit.pro
new file mode 100644
index 000000000..d6422ac54
--- /dev/null
+++ b/qt/ScintillaEdit/ScintillaEdit.pro
@@ -0,0 +1,72 @@
+#-------------------------------------------------
+#
+# Project created by QtCreator 2011-05-05T12:41:23
+#
+#-------------------------------------------------
+
+QT += core gui
+
+TARGET = ScintillaEdit
+TEMPLATE = lib
+CONFIG += lib_bundle
+
+VERSION = 3.1.0
+
+SOURCES += \
+ ScintillaEdit.cpp \
+ ScintillaDocument.cpp \
+ ../ScintillaEditBase/PlatQt.cpp \
+ ../ScintillaEditBase/ScintillaQt.cpp \
+ ../ScintillaEditBase/ScintillaEditBase.cpp \
+ ../../src/XPM.cxx \
+ ../../src/ViewStyle.cxx \
+ ../../src/UniConversion.cxx \
+ ../../src/Style.cxx \
+ ../../src/Selection.cxx \
+ ../../src/ScintillaBase.cxx \
+ ../../src/RunStyles.cxx \
+ ../../src/RESearch.cxx \
+ ../../src/PositionCache.cxx \
+ ../../src/PerLine.cxx \
+ ../../src/LineMarker.cxx \
+ ../../src/KeyMap.cxx \
+ ../../src/Indicator.cxx \
+ ../../src/ExternalLexer.cxx \
+ ../../src/Editor.cxx \
+ ../../src/Document.cxx \
+ ../../src/Decoration.cxx \
+ ../../src/ContractionState.cxx \
+ ../../src/CharClassify.cxx \
+ ../../src/CellBuffer.cxx \
+ ../../src/Catalogue.cxx \
+ ../../src/CallTip.cxx \
+ ../../src/AutoComplete.cxx \
+ ../../lexlib/WordList.cxx \
+ ../../lexlib/StyleContext.cxx \
+ ../../lexlib/PropSetSimple.cxx \
+ ../../lexlib/LexerSimple.cxx \
+ ../../lexlib/LexerNoExceptions.cxx \
+ ../../lexlib/LexerModule.cxx \
+ ../../lexlib/LexerBase.cxx \
+ ../../lexlib/CharacterSet.cxx \
+ ../../lexlib/Accessor.cxx \
+ ../../lexers/*.cxx
+
+HEADERS += \
+ ScintillaEdit.h \
+ ScintillaDocument.h \
+ ../ScintillaEditBase/ScintillaEditBase.h \
+ ../ScintillaEditBase/ScintillaQt.h
+
+OTHER_FILES +=
+
+INCLUDEPATH += ../ScintillaEditBase ../../include ../../src ../../lexlib
+
+DEFINES += SCINTILLA_QT=1 MAKING_LIBRARY=1 SCI_LEXER=1 _CRT_SECURE_NO_DEPRECATE=1
+
+DESTDIR = ../../bin
+DLLDESTDIR = ../../bin
+
+macx {
+ QMAKE_LFLAGS_SONAME = -Wl,-install_name,@executable_path/../Frameworks/
+}
diff --git a/qt/ScintillaEdit/WidgetGen.py b/qt/ScintillaEdit/WidgetGen.py
new file mode 100644
index 000000000..8065b5f9d
--- /dev/null
+++ b/qt/ScintillaEdit/WidgetGen.py
@@ -0,0 +1,275 @@
+#!/usr/bin/env python
+# WidgetGen.py - regenerate the ScintillaWidgetCpp.cpp and ScintillaWidgetCpp.h files
+# Check that API includes all gtkscintilla2 functions
+
+import sys
+import os
+import getopt
+
+scintillaDirectory = "../.."
+scintillaIncludeDirectory = os.path.join(scintillaDirectory, "include")
+sys.path.append(scintillaIncludeDirectory)
+import Face
+
+def Contains(s,sub):
+ return s.find(sub) != -1
+
+def underscoreName(s):
+ # Name conversion fixes to match gtkscintilla2
+ irregular = ['WS', 'EOL', 'AutoC', 'KeyWords', 'BackSpace', 'UnIndents', 'RE', 'RGBA']
+ for word in irregular:
+ replacement = word[0] + word[1:].lower()
+ s = s.replace(word, replacement)
+
+ out = ""
+ for c in s:
+ if c.isupper():
+ if out:
+ out += "_"
+ out += c.lower()
+ else:
+ out += c
+ return out
+
+def normalisedName(s, options, role=None):
+ if options["qtStyle"]:
+ if role == "get":
+ s = s.replace("Get", "")
+ return s[0].lower() + s[1:]
+ else:
+ return underscoreName(s)
+
+typeAliases = {
+ "position": "int",
+ "colour": "int",
+ "keymod": "int",
+ "string": "const char *",
+ "stringresult": "const char *",
+ "cells": "const char *",
+}
+
+def cppAlias(s):
+ if s in typeAliases:
+ return typeAliases[s]
+ else:
+ return s
+
+understoodTypes = ["", "void", "int", "bool", "position",
+ "colour", "keymod", "string", "stringresult", "cells"]
+
+def checkTypes(name, v):
+ understandAllTypes = True
+ if v["ReturnType"] not in understoodTypes:
+ #~ print("Do not understand", v["ReturnType"], "for", name)
+ understandAllTypes = False
+ if v["Param1Type"] not in understoodTypes:
+ #~ print("Do not understand", v["Param1Type"], "for", name)
+ understandAllTypes = False
+ if v["Param2Type"] not in understoodTypes:
+ #~ print("Do not understand", v["Param2Type"], "for", name)
+ understandAllTypes = False
+ return understandAllTypes
+
+def arguments(v, stringResult, options):
+ ret = ""
+ p1Type = cppAlias(v["Param1Type"])
+ if p1Type:
+ ret = ret + p1Type + " " + normalisedName(v["Param1Name"], options)
+ p2Type = cppAlias(v["Param2Type"])
+ if p2Type and not stringResult:
+ if p1Type:
+ ret = ret + ", "
+ ret = ret + p2Type + " " + normalisedName(v["Param2Name"], options)
+ return ret
+
+def printPyFile(f,out, options):
+ for name in f.order:
+ v = f.features[name]
+ if v["Category"] != "Deprecated":
+ feat = v["FeatureType"]
+ if feat in ["val"]:
+ out.write(name + "=" + v["Value"] + "\n")
+ if feat in ["evt"]:
+ out.write("SCN_" + name.upper() + "=" + v["Value"] + "\n")
+
+def printHFile(f,out, options):
+ for name in f.order:
+ v = f.features[name]
+ if v["Category"] != "Deprecated":
+ feat = v["FeatureType"]
+ if feat in ["fun", "get", "set"]:
+ if checkTypes(name, v):
+ constDeclarator = " const" if feat == "get" else ""
+ returnType = cppAlias(v["ReturnType"])
+ stringResult = v["Param2Type"] == "stringresult"
+ if stringResult:
+ returnType = "QByteArray"
+ out.write("\t" + returnType + " " + normalisedName(name, options, feat) + "(")
+ out.write(arguments(v, stringResult, options))
+ out.write(")" + constDeclarator + ";\n")
+
+def methodNames(f, options):
+ for name in f.order:
+ v = f.features[name]
+ if v["Category"] != "Deprecated":
+ feat = v["FeatureType"]
+ if feat in ["fun", "get", "set"]:
+ if checkTypes(name, v):
+ yield normalisedName(name, options)
+
+def printCPPFile(f,out, options):
+ for name in f.order:
+ v = f.features[name]
+ if v["Category"] != "Deprecated":
+ feat = v["FeatureType"]
+ if feat in ["fun", "get", "set"]:
+ if checkTypes(name, v):
+ constDeclarator = " const" if feat == "get" else ""
+ featureDefineName = "SCI_" + name.upper()
+ returnType = cppAlias(v["ReturnType"])
+ stringResult = v["Param2Type"] == "stringresult"
+ if stringResult:
+ returnType = "QByteArray"
+ returnStatement = ""
+ if returnType != "void":
+ returnStatement = "return "
+ out.write(returnType + " ScintillaEdit::" + normalisedName(name, options, feat) + "(")
+ out.write(arguments(v, stringResult, options))
+ out.write(")" + constDeclarator + " {\n")
+ if stringResult:
+ out.write(" " + returnStatement + "TextReturner(" + featureDefineName + ", ")
+ if "*" in cppAlias(v["Param1Type"]):
+ out.write("(uptr_t)")
+ if v["Param1Name"]:
+ out.write(normalisedName(v["Param1Name"], options))
+ else:
+ out.write("0")
+ out.write(");\n")
+ else:
+ out.write(" " + returnStatement + "send(" + featureDefineName + ", ")
+ if "*" in cppAlias(v["Param1Type"]):
+ out.write("(uptr_t)")
+ if v["Param1Name"]:
+ out.write(normalisedName(v["Param1Name"], options))
+ else:
+ out.write("0")
+ out.write(", ")
+ if "*" in cppAlias(v["Param2Type"]):
+ out.write("(sptr_t)")
+ if v["Param2Name"]:
+ out.write(normalisedName(v["Param2Name"], options))
+ else:
+ out.write("0")
+ out.write(");\n")
+ out.write("}\n")
+ out.write("\n")
+
+def CopyWithInsertion(input, output, genfn, definition, options):
+ copying = 1
+ for line in input.readlines():
+ if copying:
+ output.write(line)
+ if "/* ++Autogenerated" in line or "# ++Autogenerated" in line or "<!-- ++Autogenerated" in line:
+ copying = 0
+ genfn(definition, output, options)
+ # ~~ form needed as XML comments can not contain --
+ if "/* --Autogenerated" in line or "# --Autogenerated" in line or "<!-- ~~Autogenerated" in line:
+ copying = 1
+ output.write(line)
+
+def contents(filename):
+ with open(filename, "U") as f:
+ t = f.read()
+ return t
+
+def Generate(templateFile, destinationFile, genfn, definition, options):
+ inText = contents(templateFile)
+ try:
+ currentText = contents(destinationFile)
+ except IOError:
+ currentText = ""
+ tempname = "WidgetGen.tmp"
+ with open(tempname, "w") as out:
+ with open(templateFile, "U") as hfile:
+ CopyWithInsertion(hfile, out, genfn, definition, options)
+ outText = contents(tempname)
+ if currentText == outText:
+ os.unlink(tempname)
+ else:
+ try:
+ os.unlink(destinationFile)
+ except OSError:
+ # Will see failure if file does not yet exist
+ pass
+ os.rename(tempname, destinationFile)
+
+def gtkNames():
+ # The full path on my machine: should be altered for anyone else
+ p = "C:/Users/Neil/Downloads/wingide-source-4.0.1-1/wingide-source-4.0.1-1/external/gtkscintilla2/gtkscintilla.c"
+ with open(p) as f:
+ for l in f.readlines():
+ if "gtk_scintilla_" in l:
+ name = l.split()[1][14:]
+ if '(' in name:
+ name = name.split('(')[0]
+ yield name
+
+def usage():
+ print("WidgetGen.py [-c|--clean][-h|--help][-u|--underscore-names]")
+ print("")
+ print("Generate full APIs for ScintillaEdit class and ScintillaConstants.py.")
+ print("")
+ print("options:")
+ print("")
+ print("-c --clean remove all generated code from files")
+ print("-h --help display this text")
+ print("-u --underscore-names use method_names consistent with GTK+ standards")
+
+def readInterface(cleanGenerated):
+ f = Face.Face()
+ if not cleanGenerated:
+ f.ReadFromFile("../../include/Scintilla.iface")
+ return f
+
+def main(argv):
+ # Using local path for gtkscintilla2 so don't default to checking
+ checkGTK = False
+ cleanGenerated = False
+ qtStyleInterface = True
+ # The --gtk-check option checks for full coverage of the gtkscintilla2 API but
+ # depends on a particular directory so is not mentioned in --help.
+ opts, args = getopt.getopt(argv, "hcgu", ["help", "clean", "gtk-check", "underscore-names"])
+ for opt, arg in opts:
+ if opt in ("-h", "--help"):
+ usage()
+ sys.exit()
+ elif opt in ("-c", "--clean"):
+ cleanGenerated = True
+ elif opt in ("-g", "--gtk-check"):
+ checkGTK = True
+ elif opt in ("-u", "--underscore-names"):
+ qtStyleInterface = False
+
+ options = {"qtStyle": qtStyleInterface}
+ f = readInterface(cleanGenerated)
+ try:
+ Generate("ScintillaEdit.cpp.template", "ScintillaEdit.cpp", printCPPFile, f, options)
+ Generate("ScintillaEdit.h.template", "ScintillaEdit.h", printHFile, f, options)
+ Generate("../ScintillaEditPy/ScintillaConstants.py.template",
+ "../ScintillaEditPy/ScintillaConstants.py",
+ printPyFile, f, options)
+ if checkGTK:
+ names = set(methodNames(f))
+ #~ print("\n".join(names))
+ namesGtk = set(gtkNames())
+ for name in namesGtk:
+ if name not in names:
+ print(name, "not found in Qt version")
+ for name in names:
+ if name not in namesGtk:
+ print(name, "not found in GTK+ version")
+ except:
+ raise
+
+if __name__ == "__main__":
+ main(sys.argv[1:])
diff --git a/qt/ScintillaEditBase/Notes.txt b/qt/ScintillaEditBase/Notes.txt
new file mode 100644
index 000000000..6658aaa7a
--- /dev/null
+++ b/qt/ScintillaEditBase/Notes.txt
@@ -0,0 +1,18 @@
+
+Issues with Scintilla for Qt
+
+Qt reports character descenders are 1 pixel shorter than they really are.
+There is a tweak in the code to add a pixel in. This may have to be reviewed for Qt 5.
+There's a comment in the Qt code for Windows:
+ // ### we substract 1 to even out the historical +1 in QFontMetrics's
+ // ### height=asc+desc+1 equation. Fix in Qt5.
+
+The clocks used aren't great. QTime is a time since midnight clock so wraps around and
+is only accurate to, at best, milliseconds.
+
+On OS X drawing text into a pixmap moves it around 1 pixel to the right compared to drawing
+it directly onto a window. Buffered drawing turned off by default to avoid this.
+Reported as QTBUG-19483.
+
+Only one QPainter can be active on any widget at a time. Scintilla only draws into one
+widget but reenters for measurement.
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
diff --git a/qt/ScintillaEditBase/PlatQt.h b/qt/ScintillaEditBase/PlatQt.h
new file mode 100644
index 000000000..60a7e7300
--- /dev/null
+++ b/qt/ScintillaEditBase/PlatQt.h
@@ -0,0 +1,127 @@
+//
+// Copyright (c) 1990-2011, Scientific Toolworks, Inc.
+//
+// The License.txt file describes the conditions under which this software may be distributed.
+//
+// Author: Jason Haslam
+//
+// Additions Copyright (c) 2011 Archaeopteryx Software, Inc. d/b/a Wingware
+// Scintilla platform layer for Qt
+
+#ifndef PLATQT_H
+#define PLATQT_H
+
+#include "Platform.h"
+
+#include <QPaintDevice>
+#include <QPainter>
+#include <QHash>
+
+#ifdef SCI_NAMESPACE
+namespace Scintilla {
+#endif
+
+const char *CharacterSetID(int characterSet);
+
+inline QColor QColorFromCA(ColourDesired ca)
+{
+ long c = ca.AsLong();
+ return QColor(c & 0xff, (c >> 8) & 0xff, (c >> 16) & 0xff);
+}
+
+inline QRect QRectFromPRect(PRectangle pr)
+{
+ return QRect(pr.left, pr.top, pr.Width(), pr.Height());
+}
+
+inline PRectangle PRectFromQRect(QRect qr)
+{
+ return PRectangle(qr.x(), qr.y(), qr.x() + qr.width(), qr.y() + qr.height());
+}
+
+inline Point PointFromQPoint(QPoint qp)
+{
+ return Point(qp.x(), qp.y());
+}
+
+class SurfaceImpl : public Surface {
+private:
+ QPaintDevice *device;
+ QPainter *painter;
+ bool deviceOwned;
+ bool painterOwned;
+ float x, y;
+ bool unicodeMode;
+ int codePage;
+ const char *codecName;
+ QTextCodec *codec;
+
+public:
+ SurfaceImpl();
+ virtual ~SurfaceImpl();
+
+ virtual void Init(WindowID wid);
+ virtual void Init(SurfaceID sid, WindowID wid);
+ virtual void InitPixMap(int width, int height,
+ Surface *surface, WindowID wid);
+
+ virtual void Release();
+ virtual bool Initialised();
+ virtual void PenColour(ColourDesired fore);
+ virtual int LogPixelsY();
+ virtual int DeviceHeightFont(int points);
+ virtual void MoveTo(int x, int y);
+ virtual void LineTo(int x, int y);
+ virtual void Polygon(Point *pts, int npts, ColourDesired fore,
+ ColourDesired back);
+ virtual void RectangleDraw(PRectangle rc, ColourDesired fore,
+ ColourDesired back);
+ virtual void FillRectangle(PRectangle rc, ColourDesired back);
+ virtual void FillRectangle(PRectangle rc, Surface &surfacePattern);
+ virtual void RoundedRectangle(PRectangle rc, ColourDesired fore,
+ ColourDesired back);
+ virtual void AlphaRectangle(PRectangle rc, int corner, ColourDesired fill,
+ int alphaFill, ColourDesired outline, int alphaOutline, int flags);
+ virtual void DrawRGBAImage(PRectangle rc, int width, int height,
+ const unsigned char *pixelsImage);
+ virtual void Ellipse(PRectangle rc, ColourDesired fore,
+ ColourDesired back);
+ virtual void Copy(PRectangle rc, Point from, Surface &surfaceSource);
+
+ virtual void DrawTextNoClip(PRectangle rc, Font &font, XYPOSITION ybase,
+ const char *s, int len, ColourDesired fore, ColourDesired back);
+ virtual void DrawTextClipped(PRectangle rc, Font &font, XYPOSITION ybase,
+ const char *s, int len, ColourDesired fore, ColourDesired back);
+ virtual void DrawTextTransparent(PRectangle rc, Font &font, XYPOSITION ybase,
+ const char *s, int len, ColourDesired fore);
+ virtual void MeasureWidths(Font &font, const char *s, int len,
+ XYPOSITION *positions);
+ virtual XYPOSITION WidthText(Font &font, const char *s, int len);
+ virtual XYPOSITION WidthChar(Font &font, char ch);
+ virtual XYPOSITION Ascent(Font &font);
+ virtual XYPOSITION Descent(Font &font);
+ virtual XYPOSITION InternalLeading(Font &font);
+ virtual XYPOSITION ExternalLeading(Font &font);
+ virtual XYPOSITION Height(Font &font);
+ virtual XYPOSITION AverageCharWidth(Font &font);
+
+ virtual void SetClip(PRectangle rc);
+ virtual void FlushCachedState();
+
+ virtual void SetUnicodeMode(bool unicodeMode);
+ virtual void SetDBCSMode(int codePage);
+
+ void BrushColour(ColourDesired back);
+ void SetCodec(Font &font);
+ void SetFont(Font &font);
+
+ QPaintDevice *GetPaintDevice();
+ void SetPainter(QPainter *painter);
+ QPainter *GetPainter();
+};
+
+#ifdef SCI_NAMESPACE
+}
+#endif
+
+#endif
diff --git a/qt/ScintillaEditBase/ScintillaEditBase.cpp b/qt/ScintillaEditBase/ScintillaEditBase.cpp
new file mode 100644
index 000000000..b6cca8166
--- /dev/null
+++ b/qt/ScintillaEditBase/ScintillaEditBase.cpp
@@ -0,0 +1,635 @@
+//
+// 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
+// ScintillaEditBase.cpp - Qt widget that wraps ScintillaQt and provides events and scrolling
+
+#include "ScintillaEditBase.h"
+#include "ScintillaQt.h"
+#include "PlatQt.h"
+
+#include <QApplication>
+#include <QInputContext>
+#include <QPainter>
+#include <QScrollBar>
+#include <QTextFormat>
+#include <QVarLengthArray>
+
+#define INDIC_INPUTMETHOD 24
+
+#ifdef SCI_NAMESPACE
+using namespace Scintilla;
+#endif
+
+ScintillaEditBase::ScintillaEditBase(QWidget *parent)
+: QAbstractScrollArea(parent), sqt(0), preeditPos(-1), wheelDelta(0)
+{
+ sqt = new ScintillaQt(this);
+
+ time.start();
+
+ // Set Qt defaults.
+ setAcceptDrops(true);
+ setMouseTracking(true);
+ setAutoFillBackground(false);
+ setFrameStyle(QFrame::NoFrame);
+ setFocusPolicy(Qt::StrongFocus);
+ setAttribute(Qt::WA_StaticContents);
+ setAttribute(Qt::WA_OpaquePaintEvent);
+ setAttribute(Qt::WA_KeyCompression);
+ setAttribute(Qt::WA_InputMethodEnabled);
+
+ connect(sqt, SIGNAL(notifyParent(SCNotification)),
+ this, SLOT(notifyParent(SCNotification)));
+
+ // Connect scroll bars.
+ connect(verticalScrollBar(), SIGNAL(valueChanged(int)),
+ this, SLOT(scrollVertical(int)));
+ connect(horizontalScrollBar(), SIGNAL(valueChanged(int)),
+ this, SLOT(scrollHorizontal(int)));
+
+ // Connect pass-through signals.
+ connect(sqt, SIGNAL(horizontalRangeChanged(int,int)),
+ this, SIGNAL(horizontalRangeChanged(int,int)));
+ connect(sqt, SIGNAL(verticalRangeChanged(int,int)),
+ this, SIGNAL(verticalRangeChanged(int,int)));
+ connect(sqt, SIGNAL(horizontalScrolled(int)),
+ this, SIGNAL(horizontalScrolled(int)));
+ connect(sqt, SIGNAL(verticalScrolled(int)),
+ this, SIGNAL(verticalScrolled(int)));
+
+ connect(sqt, SIGNAL(notifyChange()),
+ this, SIGNAL(notifyChange()));
+
+ connect(sqt, SIGNAL(command(uptr_t, sptr_t)),
+ this, SLOT(event_command(uptr_t, sptr_t)));
+
+ connect(sqt, SIGNAL(aboutToCopy(QMimeData *)),
+ this, SIGNAL(aboutToCopy(QMimeData *)));
+}
+
+ScintillaEditBase::~ScintillaEditBase() {}
+
+sptr_t ScintillaEditBase::send(
+ unsigned int iMessage,
+ uptr_t wParam,
+ sptr_t lParam) const
+{
+ return sqt->WndProc(iMessage, wParam, lParam);
+}
+
+sptr_t ScintillaEditBase::sends(
+ unsigned int iMessage,
+ uptr_t wParam,
+ const char *s) const
+{
+ return sqt->WndProc(iMessage, wParam, (sptr_t)s);
+}
+
+void ScintillaEditBase::scrollHorizontal(int value)
+{
+ sqt->HorizontalScrollTo(value);
+}
+
+void ScintillaEditBase::scrollVertical(int value)
+{
+ sqt->ScrollTo(value);
+}
+
+bool ScintillaEditBase::event(QEvent *event)
+{
+ bool result = false;
+
+ if (event->type() == QEvent::KeyPress) {
+ // Circumvent the tab focus convention.
+ keyPressEvent(static_cast<QKeyEvent *>(event));
+ result = event->isAccepted();
+ } else {
+ result = QAbstractScrollArea::event(event);
+ }
+
+ return result;
+}
+
+void ScintillaEditBase::paintEvent(QPaintEvent *event)
+{
+ sqt->PartialPaint(PRectFromQRect(event->rect()));
+}
+
+void ScintillaEditBase::wheelEvent(QWheelEvent *event)
+{
+ if (event->orientation() == Qt::Horizontal) {
+ if (horizontalScrollBarPolicy() == Qt::ScrollBarAlwaysOff)
+ event->ignore();
+ else
+ QAbstractScrollArea::wheelEvent(event);
+ } else {
+ if (event->modifiers() & Qt::ControlModifier) {
+ // Zoom! We play with the font sizes in the styles.
+ // Number of steps/line is ignored, we just care if sizing up or down
+ if (event->delta() > 0) {
+ sqt->KeyCommand(SCI_ZOOMIN);
+ } else {
+ sqt->KeyCommand(SCI_ZOOMOUT);
+ }
+ } else {
+ // Ignore wheel events when the scroll bars are disabled.
+ if (verticalScrollBarPolicy() == Qt::ScrollBarAlwaysOff) {
+ event->ignore();
+ } else {
+ // Scroll
+ QAbstractScrollArea::wheelEvent(event);
+ }
+ }
+ }
+}
+
+void ScintillaEditBase::focusInEvent(QFocusEvent *event)
+{
+ sqt->SetFocusState(true);
+ emit updateUi();
+
+ QAbstractScrollArea::focusInEvent(event);
+}
+
+void ScintillaEditBase::focusOutEvent(QFocusEvent *event)
+{
+ sqt->SetFocusState(false);
+
+ QAbstractScrollArea::focusOutEvent(event);
+}
+
+void ScintillaEditBase::resizeEvent(QResizeEvent *)
+{
+ sqt->ChangeSize();
+ emit resized();
+}
+
+void ScintillaEditBase::keyPressEvent(QKeyEvent *event)
+{
+ // All keystrokes containing the meta modifier are
+ // assumed to be shortcuts not handled by scintilla.
+ if (event->modifiers() & Qt::MetaModifier) {
+ QAbstractScrollArea::keyPressEvent(event);
+ emit keyPressed(event);
+ return;
+ }
+
+ int key = 0;
+ switch (event->key()) {
+ case Qt::Key_Down: key = SCK_DOWN; break;
+ case Qt::Key_Up: key = SCK_UP; break;
+ case Qt::Key_Left: key = SCK_LEFT; break;
+ case Qt::Key_Right: key = SCK_RIGHT; break;
+ case Qt::Key_Home: key = SCK_HOME; break;
+ case Qt::Key_End: key = SCK_END; break;
+ case Qt::Key_PageUp: key = SCK_PRIOR; break;
+ case Qt::Key_PageDown: key = SCK_NEXT; break;
+ case Qt::Key_Delete: key = SCK_DELETE; break;
+ case Qt::Key_Insert: key = SCK_INSERT; break;
+ case Qt::Key_Escape: key = SCK_ESCAPE; break;
+ case Qt::Key_Backspace: key = SCK_BACK; break;
+ case Qt::Key_Plus: key = SCK_ADD; break;
+ case Qt::Key_Minus: key = SCK_SUBTRACT; break;
+ case Qt::Key_Backtab: // fall through
+ case Qt::Key_Tab: key = SCK_TAB; break;
+ case Qt::Key_Enter: // fall through
+ case Qt::Key_Return: key = SCK_RETURN; break;
+ case Qt::Key_Control: key = 0; break;
+ case Qt::Key_Alt: key = 0; break;
+ case Qt::Key_Shift: key = 0; break;
+ case Qt::Key_Meta: key = 0; break;
+ default: key = event->key(); break;
+ }
+
+ bool shift = event->modifiers() & Qt::ShiftModifier;
+ bool ctrl = event->modifiers() & Qt::ControlModifier;
+ bool alt = event->modifiers() & Qt::AltModifier;
+
+ bool consumed = false;
+ bool added = sqt->KeyDown(key, shift, ctrl, alt, &consumed) != 0;
+ if (!consumed)
+ consumed = added;
+
+ if (!consumed) {
+ // Don't insert text if the control key was pressed unless
+ // it was pressed in conjunction with alt for AltGr emulation.
+ bool input = (!ctrl || alt);
+
+ // Additionally, on non-mac platforms, don't insert text
+ // if the alt key was pressed unless control is also present.
+ // On mac alt can be used to insert special characters.
+#ifndef Q_WS_MAC
+ input &= (!alt || ctrl);
+#endif
+
+ QString text = event->text();
+ if (input && !text.isEmpty() && text[0].isPrint()) {
+ QByteArray utext = sqt->BytesForDocument(text);
+ sqt->AddCharUTF(utext.data(), utext.size());
+ } else {
+ event->ignore();
+ }
+ }
+
+ emit keyPressed(event);
+}
+
+static int modifierTranslated(int sciModifier)
+{
+ switch (sciModifier) {
+ case SCMOD_SHIFT:
+ return Qt::ShiftModifier;
+ case SCMOD_CTRL:
+ return Qt::ControlModifier;
+ case SCMOD_ALT:
+ return Qt::AltModifier;
+ case SCMOD_SUPER:
+ return Qt::MetaModifier;
+ default:
+ return 0;
+ }
+}
+
+void ScintillaEditBase::mousePressEvent(QMouseEvent *event)
+{
+ Point pos = PointFromQPoint(event->pos());
+
+ emit buttonPressed(event);
+
+ if (event->button() == Qt::MidButton &&
+ QApplication::clipboard()->supportsSelection()) {
+ SelectionPosition selPos = sqt->SPositionFromLocation(
+ pos, false, false, sqt->UserVirtualSpace());
+ sqt->sel.Clear();
+ sqt->SetSelection(selPos, selPos);
+ sqt->PasteFromMode(QClipboard::Selection);
+ return;
+ }
+
+ bool button = event->button() == Qt::LeftButton;
+
+ if (button) {
+ bool shift = event->modifiers() & Qt::ShiftModifier;
+ bool ctrl = event->modifiers() & Qt::ControlModifier;
+#ifdef Q_WS_X11
+ // On X allow choice of rectangular modifier since most window
+ // managers grab alt + click for moving windows.
+ bool alt = event->modifiers() & modifierTranslated(sqt->rectangularSelectionModifier);
+#else
+ bool alt = event->modifiers() & Qt::AltModifier;
+#endif
+
+ sqt->ButtonDown(pos, time.elapsed(), shift, ctrl, alt);
+ }
+}
+
+void ScintillaEditBase::mouseReleaseEvent(QMouseEvent *event)
+{
+ Point point = PointFromQPoint(event->pos());
+ bool ctrl = event->modifiers() & Qt::ControlModifier;
+ if (event->button() == Qt::LeftButton)
+ sqt->ButtonUp(point, time.elapsed(), ctrl);
+
+ int pos = send(SCI_POSITIONFROMPOINT, point.x, point.y);
+ int line = send(SCI_LINEFROMPOSITION, pos);
+ int modifiers = event->modifiers();
+
+ emit textAreaClicked(line, modifiers);
+ emit buttonReleased(event);
+}
+
+void ScintillaEditBase::mouseDoubleClickEvent(QMouseEvent *event)
+{
+ // Scintilla does its own double-click detection.
+ mousePressEvent(event);
+}
+
+void ScintillaEditBase::mouseMoveEvent(QMouseEvent *event)
+{
+ Point pos = PointFromQPoint(event->pos());
+ sqt->ButtonMove(pos);
+}
+
+void ScintillaEditBase::contextMenuEvent(QContextMenuEvent *event)
+{
+ Point pos = PointFromQPoint(event->globalPos());
+ Point pt = PointFromQPoint(event->pos());
+ if (!sqt->PointInSelection(pt))
+ sqt->SetEmptySelection(sqt->PositionFromLocation(pt));
+ sqt->ContextMenu(pos);
+}
+
+void ScintillaEditBase::dragEnterEvent(QDragEnterEvent *event)
+{
+ if (event->mimeData()->hasText()) {
+ event->acceptProposedAction();
+
+ Point point = PointFromQPoint(event->pos());
+ sqt->DragEnter(point);
+ } else {
+ event->ignore();
+ }
+}
+
+void ScintillaEditBase::dragLeaveEvent(QDragLeaveEvent * /* event */)
+{
+ sqt->DragLeave();
+}
+
+void ScintillaEditBase::dragMoveEvent(QDragMoveEvent *event)
+{
+ if (event->mimeData()->hasText()) {
+ event->acceptProposedAction();
+
+ Point point = PointFromQPoint(event->pos());
+ sqt->DragMove(point);
+ } else {
+ event->ignore();
+ }
+}
+
+void ScintillaEditBase::dropEvent(QDropEvent *event)
+{
+ if (event->mimeData()->hasText()) {
+ event->acceptProposedAction();
+
+ Point point = PointFromQPoint(event->pos());
+ bool move = (event->source() == this &&
+ event->proposedAction() == Qt::MoveAction);
+ sqt->Drop(point, event->mimeData(), move);
+ } else {
+ event->ignore();
+ }
+}
+
+void ScintillaEditBase::inputMethodEvent(QInputMethodEvent *event)
+{
+ // Clear the current selection.
+ sqt->ClearSelection();
+ if (preeditPos >= 0)
+ sqt->SetSelection(preeditPos, preeditPos);
+
+ // Insert the commit string.
+ if (!event->commitString().isEmpty() || event->replacementLength()) {
+ // Select the text to be removed.
+ int commitPos = send(SCI_GETCURRENTPOS);
+ int start = commitPos + event->replacementStart();
+ int end = start + event->replacementLength();
+ sqt->SetSelection(start, end);
+
+ // Replace the selection with the commit string.
+ QByteArray commitBytes = sqt->BytesForDocument(event->commitString());
+ char *commitData = commitBytes.data();
+ sqt->AddCharUTF(commitData, strlen(commitData));
+ }
+
+ // Select the previous preedit string.
+ int pos = send(SCI_GETCURRENTPOS);
+ int length = sqt->BytesForDocument(preeditString).length();
+ sqt->SetSelection(pos, pos + length);
+
+ // Replace the selection with the new preedit string.
+ QByteArray bytes = sqt->BytesForDocument(event->preeditString());
+ char *data = bytes.data();
+ bool recording = sqt->recordingMacro;
+ sqt->recordingMacro = false;
+ send(SCI_SETUNDOCOLLECTION, false);
+ sqt->AddCharUTF(data, strlen(data));
+ send(SCI_SETUNDOCOLLECTION, true);
+ sqt->recordingMacro = recording;
+ sqt->SetSelection(pos, pos);
+
+ // Store the state of the current preedit string.
+ preeditString = event->preeditString();
+ preeditPos = !preeditString.isEmpty() ? send(SCI_GETCURRENTPOS) : -1;
+
+ if (!preeditString.isEmpty()) {
+ // Apply attributes to the preedit string.
+ int indicNum = 0;
+ sqt->ShowCaretAtCurrentPosition();
+ foreach (QInputMethodEvent::Attribute a, event->attributes()) {
+ QString prefix = preeditString.left(a.start);
+ QByteArray prefixBytes = sqt->BytesForDocument(prefix);
+ int prefixLength = prefixBytes.length();
+ int caretPos = preeditPos + prefixLength;
+
+ if (a.type == QInputMethodEvent::Cursor) {
+ sqt->SetSelection(caretPos, caretPos);
+ if (!a.length)
+ sqt->DropCaret();
+
+ } else if (a.type == QInputMethodEvent::TextFormat) {
+ Q_ASSERT(a.value.canConvert(QVariant::TextFormat));
+ QTextFormat format = a.value.value<QTextFormat>();
+ Q_ASSERT(format.isCharFormat());
+ QTextCharFormat charFormat = format.toCharFormat();
+
+ QString sub = preeditString.mid(a.start, a.length);
+ QByteArray subBytes = sqt->BytesForDocument(sub);
+ int subLength = subBytes.length();
+
+ if (charFormat.underlineStyle() != QTextCharFormat::NoUnderline) {
+ // Set temporary indicator for underline style.
+ QColor uc = charFormat.underlineColor();
+ int style = INDIC_PLAIN;
+ if (charFormat.underlineStyle() == QTextCharFormat::DashUnderline)
+ style = INDIC_DASH;
+ send(SCI_INDICSETSTYLE, INDIC_INPUTMETHOD + indicNum, style);
+ send(SCI_INDICSETFORE, INDIC_INPUTMETHOD + indicNum, uc.rgb());
+ send(SCI_SETINDICATORCURRENT, INDIC_INPUTMETHOD + indicNum);
+ send(SCI_INDICATORFILLRANGE, caretPos, subLength);
+ indicNum++;
+ }
+ }
+ }
+ }
+}
+
+QVariant ScintillaEditBase::inputMethodQuery(Qt::InputMethodQuery query) const
+{
+ int pos = send(SCI_GETCURRENTPOS);
+ int line = send(SCI_LINEFROMPOSITION, pos);
+
+ switch (query) {
+ case Qt::ImMicroFocus:
+ {
+ int startPos = (preeditPos >= 0) ? preeditPos : pos;
+ Point pt = sqt->LocationFromPosition(startPos);
+ int width = send(SCI_GETCARETWIDTH);
+ int height = send(SCI_TEXTHEIGHT, line);
+ return QRect(pt.x, pt.y, width, height);
+ }
+
+ case Qt::ImFont:
+ {
+ char fontName[64];
+ int style = send(SCI_GETSTYLEAT, pos);
+ int len = send(SCI_STYLEGETFONT, style, (long)fontName);
+ int size = send(SCI_STYLEGETSIZE, style);
+ bool italic = send(SCI_STYLEGETITALIC, style);
+ int weight = send(SCI_STYLEGETBOLD, style) ? QFont::Bold : -1;
+ return QFont(QString::fromUtf8(fontName, len), size, weight, italic);
+ }
+
+ case Qt::ImCursorPosition:
+ {
+ int paraStart = sqt->pdoc->ParaUp(pos);
+ return pos - paraStart;
+ }
+
+ case Qt::ImSurroundingText:
+ {
+ int paraStart = sqt->pdoc->ParaUp(pos);
+ int paraEnd = sqt->pdoc->ParaDown(pos);
+ QVarLengthArray<char,1024> buffer(paraEnd - paraStart + 1);
+
+ Sci_CharacterRange charRange;
+ charRange.cpMin = paraStart;
+ charRange.cpMax = paraEnd;
+
+ Sci_TextRange textRange;
+ textRange.chrg = charRange;
+ textRange.lpstrText = buffer.data();
+
+ send(SCI_GETTEXTRANGE, 0, (long)&textRange);
+
+ return sqt->StringFromDocument(buffer.constData());
+ }
+
+ case Qt::ImCurrentSelection:
+ {
+ QVarLengthArray<char,1024> buffer(send(SCI_GETSELTEXT));
+ send(SCI_GETSELTEXT, 0, (long)buffer.data());
+
+ return sqt->StringFromDocument(buffer.constData());
+ }
+
+ default:
+ return QVariant();
+ }
+}
+
+void ScintillaEditBase::notifyParent(SCNotification scn)
+{
+ emit notify(&scn);
+ switch (scn.nmhdr.code) {
+ case SCN_STYLENEEDED:
+ emit styleNeeded(scn.position);
+ break;
+
+ case SCN_CHARADDED:
+ emit charAdded(scn.ch);
+ break;
+
+ case SCN_SAVEPOINTREACHED:
+ emit savePointChanged(false);
+ break;
+
+ case SCN_SAVEPOINTLEFT:
+ emit savePointChanged(true);
+ break;
+
+ case SCN_MODIFYATTEMPTRO:
+ emit modifyAttemptReadOnly();
+ break;
+
+ case SCN_KEY:
+ emit key(scn.ch);
+ break;
+
+ case SCN_DOUBLECLICK:
+ emit doubleClick(scn.position, scn.line);
+ break;
+
+ case SCN_UPDATEUI:
+ emit updateUi();
+ break;
+
+ case SCN_MODIFIED:
+ {
+ bool added = scn.modificationType & SC_MOD_INSERTTEXT;
+ bool deleted = scn.modificationType & SC_MOD_DELETETEXT;
+
+ int length = send(SCI_GETTEXTLENGTH);
+ bool firstLineAdded = (added && length == 1) ||
+ (deleted && length == 0);
+
+ if (scn.linesAdded != 0) {
+ emit linesAdded(scn.linesAdded);
+ } else if (firstLineAdded) {
+ emit linesAdded(added ? 1 : -1);
+ }
+
+ const QByteArray bytes = QByteArray::fromRawData(scn.text, scn.length);
+ emit modified(scn.modificationType, scn.position, scn.length,
+ scn.linesAdded, bytes, scn.line,
+ scn.foldLevelNow, scn.foldLevelPrev);
+ break;
+ }
+
+ case SCN_MACRORECORD:
+ emit macroRecord(scn.message, scn.wParam, scn.lParam);
+ break;
+
+ case SCN_MARGINCLICK:
+ emit marginClicked(scn.position, scn.modifiers, scn.margin);
+ break;
+
+ case SCN_NEEDSHOWN:
+ emit needShown(scn.position, scn.length);
+ break;
+
+ case SCN_PAINTED:
+ emit painted();
+ break;
+
+ case SCN_USERLISTSELECTION:
+ emit userListSelection();
+ break;
+
+ case SCN_URIDROPPED:
+ emit uriDropped();
+ break;
+
+ case SCN_DWELLSTART:
+ emit dwellStart(scn.x, scn.y);
+ break;
+
+ case SCN_DWELLEND:
+ emit dwellEnd(scn.x, scn.y);
+ break;
+
+ case SCN_ZOOM:
+ emit zoom(send(SCI_GETZOOM));
+ break;
+
+ case SCN_HOTSPOTCLICK:
+ emit hotSpotClick(scn.position, scn.modifiers);
+ break;
+
+ case SCN_HOTSPOTDOUBLECLICK:
+ emit hotSpotDoubleClick(scn.position, scn.modifiers);
+ break;
+
+ case SCN_CALLTIPCLICK:
+ emit callTipClick();
+ break;
+
+ case SCN_AUTOCSELECTION:
+ emit autoCompleteSelection(scn.lParam, QString::fromUtf8(scn.text));
+ break;
+
+ default:
+ return;
+ }
+}
+
+void ScintillaEditBase::event_command(uptr_t wParam, sptr_t lParam)
+{
+ emit command(wParam, lParam);
+}
diff --git a/qt/ScintillaEditBase/ScintillaEditBase.h b/qt/ScintillaEditBase/ScintillaEditBase.h
new file mode 100644
index 000000000..0f625eba3
--- /dev/null
+++ b/qt/ScintillaEditBase/ScintillaEditBase.h
@@ -0,0 +1,151 @@
+//
+// 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
+// ScintillaWidget.h - Qt widget that wraps ScintillaQt and provides events and scrolling
+
+
+#ifndef SCINTILLAEDITBASE_H
+#define SCINTILLAEDITBASE_H
+
+#include "Platform.h"
+#include "Scintilla.h"
+
+#include <QAbstractScrollArea>
+#include <QMimeData>
+#include <QTime>
+
+#ifdef SCI_NAMESPACE
+namespace Scintilla {
+#endif
+
+class ScintillaQt;
+class SurfaceImpl;
+struct SCNotification;
+
+#ifdef WIN32
+#ifdef MAKING_LIBRARY
+#define EXPORT_IMPORT_API __declspec(dllexport)
+#else
+// Defining dllimport upsets moc
+#define EXPORT_IMPORT_API __declspec(dllimport)
+//#define EXPORT_IMPORT_API
+#endif
+#else
+#define EXPORT_IMPORT_API
+#endif
+
+class EXPORT_IMPORT_API ScintillaEditBase : public QAbstractScrollArea {
+ Q_OBJECT
+
+public:
+ ScintillaEditBase(QWidget *parent = 0);
+ virtual ~ScintillaEditBase();
+
+ virtual sptr_t send(
+ unsigned int iMessage,
+ uptr_t wParam = 0,
+ sptr_t lParam = 0) const;
+
+ virtual sptr_t sends(
+ unsigned int iMessage,
+ uptr_t wParam = 0,
+ const char *s = 0) const;
+
+public slots:
+ // Scroll events coming from GUI to be sent to Scintilla.
+ void scrollHorizontal(int value);
+ void scrollVertical(int value);
+
+ // Emit Scintilla notifications as signals.
+ void notifyParent(SCNotification scn);
+ void event_command(uptr_t wParam, sptr_t lParam);
+
+signals:
+ void horizontalScrolled(int value);
+ void verticalScrolled(int value);
+ void horizontalRangeChanged(int max, int page);
+ void verticalRangeChanged(int max, int page);
+ void notifyChange();
+ void linesAdded(int linesAdded);
+
+ // Clients can use this hook to add additional
+ // formats (e.g. rich text) to the MIME data.
+ void aboutToCopy(QMimeData *data);
+
+ // Scintilla Notifications
+ void styleNeeded(int position);
+ void charAdded(int ch);
+ void savePointChanged(bool dirty);
+ void modifyAttemptReadOnly();
+ void key(int key);
+ void doubleClick(int position, int line);
+ void updateUi();
+ void modified(int type, int position, int length, int linesAdded,
+ const QByteArray &text, int line, int foldNow, int foldPrev);
+ void macroRecord(int message, uptr_t wParam, sptr_t lParam);
+ void marginClicked(int position, int modifiers, int margin);
+ void textAreaClicked(int line, int modifiers);
+ void needShown(int position, int length);
+ void painted();
+ void userListSelection(); // Wants some args.
+ void uriDropped(); // Wants some args.
+ void dwellStart(int x, int y);
+ void dwellEnd(int x, int y);
+ void zoom(int zoom);
+ void hotSpotClick(int position, int modifiers);
+ void hotSpotDoubleClick(int position, int modifiers);
+ void callTipClick();
+ void autoCompleteSelection(int position, const QString &text);
+
+ // Base notifications for compatibility with other Scintilla implementations
+ void notify(SCNotification *pscn);
+ void command(uptr_t wParam, sptr_t lParam);
+
+ // GUI event notifications needed under Qt
+ void buttonPressed(QMouseEvent *event);
+ void buttonReleased(QMouseEvent *event);
+ void keyPressed(QKeyEvent *event);
+ void resized();
+
+protected:
+ virtual bool event(QEvent *event);
+ virtual void paintEvent(QPaintEvent *event);
+ virtual void wheelEvent(QWheelEvent *event);
+ virtual void focusInEvent(QFocusEvent *event);
+ virtual void focusOutEvent(QFocusEvent *event);
+ virtual void resizeEvent(QResizeEvent *event);
+ virtual void keyPressEvent(QKeyEvent *event);
+ virtual void mousePressEvent(QMouseEvent *event);
+ virtual void mouseReleaseEvent(QMouseEvent *event);
+ virtual void mouseDoubleClickEvent(QMouseEvent *event);
+ virtual void mouseMoveEvent(QMouseEvent *event);
+ virtual void contextMenuEvent(QContextMenuEvent *event);
+ virtual void dragEnterEvent(QDragEnterEvent *event);
+ virtual void dragLeaveEvent(QDragLeaveEvent *event);
+ virtual void dragMoveEvent(QDragMoveEvent *event);
+ virtual void dropEvent(QDropEvent *event);
+ virtual void inputMethodEvent(QInputMethodEvent *event);
+ virtual QVariant inputMethodQuery(Qt::InputMethodQuery query) const;
+ virtual void scrollContentsBy(int, int) {}
+
+private:
+ ScintillaQt *sqt;
+
+ QTime time;
+
+ int preeditPos;
+ QString preeditString;
+
+ int wheelDelta;
+};
+
+#ifdef SCI_NAMESPACE
+}
+#endif
+
+#endif /* SCINTILLAEDITBASE_H */
diff --git a/qt/ScintillaEditBase/ScintillaEditBase.pro b/qt/ScintillaEditBase/ScintillaEditBase.pro
new file mode 100644
index 000000000..cdf0b685e
--- /dev/null
+++ b/qt/ScintillaEditBase/ScintillaEditBase.pro
@@ -0,0 +1,111 @@
+#-------------------------------------------------
+#
+# Project created by QtCreator 2011-05-05T12:41:23
+#
+#-------------------------------------------------
+
+QT += core gui
+
+TARGET = ScintillaEditBase
+TEMPLATE = lib
+CONFIG += lib_bundle
+
+VERSION = 3.1.0
+
+SOURCES += \
+ PlatQt.cpp \
+ ScintillaQt.cpp \
+ ScintillaEditBase.cpp \
+ ../../src/XPM.cxx \
+ ../../src/ViewStyle.cxx \
+ ../../src/UniConversion.cxx \
+ ../../src/Style.cxx \
+ ../../src/Selection.cxx \
+ ../../src/ScintillaBase.cxx \
+ ../../src/RunStyles.cxx \
+ ../../src/RESearch.cxx \
+ ../../src/PositionCache.cxx \
+ ../../src/PerLine.cxx \
+ ../../src/LineMarker.cxx \
+ ../../src/KeyMap.cxx \
+ ../../src/Indicator.cxx \
+ ../../src/ExternalLexer.cxx \
+ ../../src/Editor.cxx \
+ ../../src/Document.cxx \
+ ../../src/Decoration.cxx \
+ ../../src/ContractionState.cxx \
+ ../../src/CharClassify.cxx \
+ ../../src/CellBuffer.cxx \
+ ../../src/Catalogue.cxx \
+ ../../src/CallTip.cxx \
+ ../../src/AutoComplete.cxx \
+ ../../lexlib/WordList.cxx \
+ ../../lexlib/StyleContext.cxx \
+ ../../lexlib/PropSetSimple.cxx \
+ ../../lexlib/LexerSimple.cxx \
+ ../../lexlib/LexerNoExceptions.cxx \
+ ../../lexlib/LexerModule.cxx \
+ ../../lexlib/LexerBase.cxx \
+ ../../lexlib/CharacterSet.cxx \
+ ../../lexlib/Accessor.cxx \
+ ../../lexers/*.cxx
+
+HEADERS += \
+ PlatQt.h \
+ ScintillaQt.h \
+ ScintillaEditBase.h \
+ ../../src/XPM.h \
+ ../../src/ViewStyle.h \
+ ../../src/UniConversion.h \
+ ../../src/SVector.h \
+ ../../src/Style.h \
+ ../../src/SplitVector.h \
+ ../../src/Selection.h \
+ ../../src/ScintillaBase.h \
+ ../../src/RunStyles.h \
+ ../../src/RESearch.h \
+ ../../src/PositionCache.h \
+ ../../src/PerLine.h \
+ ../../src/Partitioning.h \
+ ../../src/LineMarker.h \
+ ../../src/KeyMap.h \
+ ../../src/Indicator.h \
+ ../../src/FontQuality.h \
+ ../../src/ExternalLexer.h \
+ ../../src/Editor.h \
+ ../../src/Document.h \
+ ../../src/Decoration.h \
+ ../../src/ContractionState.h \
+ ../../src/CharClassify.h \
+ ../../src/CellBuffer.h \
+ ../../src/Catalogue.h \
+ ../../src/CallTip.h \
+ ../../src/AutoComplete.h \
+ ../../include/Scintilla.h \
+ ../../include/SciLexer.h \
+ ../../include/Platform.h \
+ ../../include/ILexer.h \
+ ../../lexlib/WordList.h \
+ ../../lexlib/StyleContext.h \
+ ../../lexlib/SparseState.h \
+ ../../lexlib/PropSetSimple.h \
+ ../../lexlib/OptionSet.h \
+ ../../lexlib/LexerSimple.h \
+ ../../lexlib/LexerNoExceptions.h \
+ ../../lexlib/LexerModule.h \
+ ../../lexlib/LexerBase.h \
+ ../../lexlib/LexAccessor.h \
+ ../../lexlib/CharacterSet.h \
+ ../../lexlib/Accessor.h
+
+OTHER_FILES +=
+
+INCLUDEPATH += ../../include ../../src ../../lexlib
+
+DEFINES += SCINTILLA_QT=1 MAKING_LIBRARY=1 SCI_LEXER=1 _CRT_SECURE_NO_DEPRECATE=1
+
+DESTDIR = ../../bin
+
+macx {
+ QMAKE_LFLAGS_SONAME = -Wl,-install_name,@executable_path/../Frameworks/
+}
diff --git a/qt/ScintillaEditBase/ScintillaQt.cpp b/qt/ScintillaEditBase/ScintillaQt.cpp
new file mode 100644
index 000000000..e65390f4a
--- /dev/null
+++ b/qt/ScintillaEditBase/ScintillaQt.cpp
@@ -0,0 +1,772 @@
+//
+// 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
+// ScintillaQt.cpp - Qt specific subclass of ScintillaBase
+
+#include "PlatQt.h"
+#include "ScintillaQt.h"
+#ifdef SCI_LEXER
+#include "LexerModule.h"
+#include "ExternalLexer.h"
+#endif
+
+#include <QApplication>
+#include <QDrag>
+#include <QInputContext>
+#include <QMimeData>
+#include <QMenu>
+#include <QScrollBar>
+#include <QTimer>
+#include <QTextCodec>
+
+#ifdef SCI_NAMESPACE
+using namespace Scintilla;
+#endif
+
+
+ScintillaQt::ScintillaQt(QAbstractScrollArea *parent)
+: QObject(parent), scrollArea(parent), vMax(0), hMax(0), vPage(0), hPage(0),
+ haveMouseCapture(false), dragWasDropped(false)
+{
+
+ wMain = scrollArea->viewport();
+
+ // On OS X drawing text into a pixmap moves it around 1 pixel to
+ // the right compared to drawing it directly onto a window.
+ // Buffered drawing turned off by default to avoid this.
+ WndProc(SCI_SETBUFFEREDDRAW, false, 0);
+
+ Initialise();
+}
+
+ScintillaQt::~ScintillaQt()
+{
+ SetTicking(false);
+}
+
+void ScintillaQt::tick()
+{
+ Tick();
+}
+
+void ScintillaQt::execCommand(QAction *action)
+{
+ int command = action->data().toInt();
+ Command(command);
+}
+
+#if defined(Q_OS_WIN)
+static const QString sMSDEVColumnSelect("MSDEVColumnSelect");
+static const QString sWrappedMSDEVColumnSelect("application/x-qt-windows-mime;value=\"MSDEVColumnSelect\"");
+#elif defined(Q_OS_MAC)
+static const QString sScintillaRecPboardType("com.scintilla.utf16-plain-text.rectangular");
+static const QString sScintillaRecMimeType("text/x-scintilla.utf16-plain-text.rectangular");
+#else
+// Linux
+static const QString sMimeRectangularMarker("text/x-rectangular-marker");
+#endif
+
+#ifdef Q_OS_MAC
+
+class ScintillaRectangularMime : public QMacPasteboardMime {
+public:
+ ScintillaRectangularMime() : QMacPasteboardMime(MIME_ALL) {
+ }
+
+ QString convertorName() {
+ return QString("ScintillaRectangularMime");
+ }
+
+ bool canConvert(const QString &mime, QString flav) {
+ return mimeFor(flav) == mime;
+ }
+
+ QString mimeFor(QString flav) {
+ if (flav == sScintillaRecPboardType)
+ return sScintillaRecMimeType;
+ return QString();
+ }
+
+ QString flavorFor(const QString &mime) {
+ if (mime == sScintillaRecMimeType)
+ return sScintillaRecPboardType;
+ return QString();
+ }
+
+ QVariant convertToMime(const QString & /* mime */, QList<QByteArray> data, QString /* flav */) {
+ QByteArray all;
+ foreach (QByteArray i, data) {
+ all += i;
+ }
+ return QVariant(all);
+ }
+
+ QList<QByteArray> convertFromMime(const QString & /* mime */, QVariant data, QString /* flav */) {
+ QByteArray a = data.toByteArray();
+ QList<QByteArray> l;
+ l.append(a);
+ return l;
+ }
+
+};
+
+// The Mime object registers itself but only want one for all Scintilla instances.
+// Should delete at exit to help memory leak detection but that would be extra work
+// and, since the clipboard exists after last Scintilla instance, may be complex.
+static ScintillaRectangularMime *singletonMime = 0;
+
+#endif
+
+void ScintillaQt::Initialise()
+{
+#if defined(Q_OS_WIN) || defined(Q_OS_MAC)
+ rectangularSelectionModifier = SCMOD_ALT;
+#else
+ rectangularSelectionModifier = SCMOD_CTRL;
+#endif
+
+#ifdef Q_OS_MAC
+ if (!singletonMime) {
+ singletonMime = new ScintillaRectangularMime();
+
+ QStringList slTypes(sScintillaRecPboardType);
+ qRegisterDraggedTypes(slTypes);
+ }
+#endif
+
+ connect(QApplication::clipboard(), SIGNAL(selectionChanged()),
+ this, SLOT(SelectionChanged()));
+}
+
+void ScintillaQt::Finalise()
+{
+ SetTicking(false);
+ ScintillaBase::Finalise();
+}
+
+void ScintillaQt::SelectionChanged()
+{
+ bool nowPrimary = QApplication::clipboard()->ownsSelection();
+ if (nowPrimary != primarySelection) {
+ primarySelection = nowPrimary;
+ Redraw();
+ }
+}
+
+bool ScintillaQt::DragThreshold(Point ptStart, Point ptNow)
+{
+ int xMove = abs(ptStart.x - ptNow.x);
+ int yMove = abs(ptStart.y - ptNow.y);
+ return (xMove > QApplication::startDragDistance()) ||
+ (yMove > QApplication::startDragDistance());
+}
+
+static QString StringFromSelectedText(const SelectionText &selectedText)
+{
+ if (selectedText.codePage == SC_CP_UTF8) {
+ return QString::fromUtf8(selectedText.s, selectedText.len-1);
+ } else {
+ QTextCodec *codec = QTextCodec::codecForName(
+ CharacterSetID(selectedText.characterSet));
+ return codec->toUnicode(selectedText.s, selectedText.len-1);
+ }
+}
+
+static void AddRectangularToMime(QMimeData *mimeData, QString su)
+{
+#if defined(Q_OS_WIN)
+ // Add an empty marker
+ mimeData->setData(sMSDEVColumnSelect, QByteArray());
+#elif defined(Q_OS_MAC)
+ // OS X gets marker + data to work with other implementations.
+ // Don't understand how this works but it does - the
+ // clipboard format is supposed to be UTF-16, not UTF-8.
+ mimeData->setData(sScintillaRecMimeType, su.toUtf8());
+#else
+ Q_UNUSED(su);
+ // Linux
+ // Add an empty marker
+ mimeData->setData(sMimeRectangularMarker, QByteArray());
+#endif
+}
+
+static bool IsRectangularInMime(const QMimeData *mimeData)
+{
+ QStringList formats = mimeData->formats();
+ for (int i = 0; i < formats.size(); ++i) {
+#if defined(Q_OS_WIN)
+ // Windows rectangular markers
+ // If rectangular copies made by this application, see base name.
+ if (formats[i] == sMSDEVColumnSelect)
+ return true;
+ // Otherwise see wrapped name.
+ if (formats[i] == sWrappedMSDEVColumnSelect)
+ return true;
+#elif defined(Q_OS_MAC)
+ if (formats[i] == sScintillaRecMimeType)
+ return true;
+#else
+ // Linux
+ if (formats[i] == sMimeRectangularMarker)
+ return true;
+#endif
+ }
+ return false;
+}
+
+bool ScintillaQt::ValidCodePage(int codePage) const
+{
+ return codePage == 0
+ || codePage == SC_CP_UTF8
+ || codePage == 932
+ || codePage == 936
+ || codePage == 949
+ || codePage == 950
+ || codePage == 1361;
+}
+
+
+void ScintillaQt::ScrollText(int linesToMove)
+{
+ int dy = vs.lineHeight * (linesToMove);
+ scrollArea->viewport()->scroll(0, dy);
+}
+
+void ScintillaQt::SetVerticalScrollPos()
+{
+ scrollArea->verticalScrollBar()->setValue(topLine);
+ emit verticalScrolled(topLine);
+}
+
+void ScintillaQt::SetHorizontalScrollPos()
+{
+ scrollArea->horizontalScrollBar()->setValue(xOffset);
+ emit horizontalScrolled(xOffset);
+}
+
+bool ScintillaQt::ModifyScrollBars(int nMax, int nPage)
+{
+ bool modified = false;
+
+ int vNewPage = nPage;
+ int vNewMax = nMax - vNewPage + 1;
+ if (vMax != vNewMax || vPage != vNewPage) {
+ vMax = vNewMax;
+ vPage = vNewPage;
+ modified = true;
+
+ scrollArea->verticalScrollBar()->setMaximum(vMax);
+ scrollArea->verticalScrollBar()->setPageStep(vPage);
+ emit verticalRangeChanged(vMax, vPage);
+ }
+
+ int hNewPage = GetTextRectangle().Width();
+ int hNewMax = (scrollWidth > hNewPage) ? scrollWidth - hNewPage : 0;
+ int charWidth = vs.styles[STYLE_DEFAULT].aveCharWidth;
+ if (hMax != hNewMax || hPage != hNewPage ||
+ scrollArea->horizontalScrollBar()->singleStep() != charWidth) {
+ hMax = hNewMax;
+ hPage = hNewPage;
+ modified = true;
+
+ scrollArea->horizontalScrollBar()->setMaximum(hMax);
+ scrollArea->horizontalScrollBar()->setPageStep(hPage);
+ scrollArea->horizontalScrollBar()->setSingleStep(charWidth);
+ emit horizontalRangeChanged(hMax, hPage);
+ }
+
+ return modified;
+}
+
+void ScintillaQt::ReconfigureScrollBars()
+{
+ if (verticalScrollBarVisible) {
+ scrollArea->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded);
+ } else {
+ scrollArea->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
+ }
+
+ if (horizontalScrollBarVisible && (wrapState == eWrapNone)) {
+ scrollArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded);
+ } else {
+ scrollArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
+ }
+}
+
+void ScintillaQt::CopyToModeClipboard(const SelectionText &selectedText, QClipboard::Mode clipboardMode_)
+{
+ QClipboard *clipboard = QApplication::clipboard();
+ clipboard->clear(clipboardMode_);
+ QString su = StringFromSelectedText(selectedText);
+ QMimeData *mimeData = new QMimeData();
+ mimeData->setText(su);
+ if (selectedText.rectangular) {
+ AddRectangularToMime(mimeData, su);
+ }
+
+ // Allow client code to add additional data (e.g rich text).
+ emit aboutToCopy(mimeData);
+
+ clipboard->setMimeData(mimeData, clipboardMode_);
+}
+
+void ScintillaQt::Copy()
+{
+ if (!sel.Empty()) {
+ SelectionText st;
+ CopySelectionRange(&st);
+ CopyToClipboard(st);
+ }
+}
+
+void ScintillaQt::CopyToClipboard(const SelectionText &selectedText)
+{
+ CopyToModeClipboard(selectedText, QClipboard::Clipboard);
+}
+
+void ScintillaQt::PasteFromMode(QClipboard::Mode clipboardMode_)
+{
+ QClipboard *clipboard = QApplication::clipboard();
+ const QMimeData *mimeData = clipboard->mimeData(clipboardMode_);
+ bool isRectangular = IsRectangularInMime(mimeData);
+ QString text = clipboard->text(clipboardMode_);
+ QByteArray utext = BytesForDocument(text);
+ int len = utext.length();
+ char *dest = Document::TransformLineEnds(&len, utext, len, pdoc->eolMode);
+ SelectionText selText;
+ selText.Set(dest, len, pdoc->dbcsCodePage, CharacterSetOfDocument(), isRectangular, false);
+
+ UndoGroup ug(pdoc);
+ ClearSelection(multiPasteMode == SC_MULTIPASTE_EACH);
+ SelectionPosition selStart = sel.IsRectangular() ?
+ sel.Rectangular().Start() :
+ sel.Range(sel.Main()).Start();
+ if (selText.rectangular) {
+ PasteRectangular(selStart, selText.s, selText.len);
+ } else {
+ InsertPaste(selStart, selText.s, selText.len);
+ }
+ EnsureCaretVisible();
+}
+
+void ScintillaQt::Paste()
+{
+ PasteFromMode(QClipboard::Clipboard);
+}
+
+void ScintillaQt::ClaimSelection()
+{
+ if (QApplication::clipboard()->supportsSelection()) {
+ // X Windows has a 'primary selection' as well as the clipboard.
+ // Whenever the user selects some text, we become the primary selection
+ if (!sel.Empty()) {
+ primarySelection = true;
+ SelectionText st;
+ CopySelectionRange(&st);
+ CopyToModeClipboard(st, QClipboard::Selection);
+ } else {
+ primarySelection = false;
+ }
+ }
+}
+
+void ScintillaQt::NotifyChange()
+{
+ emit notifyChange();
+ emit command(
+ Platform::LongFromTwoShorts(GetCtrlID(), SCEN_CHANGE),
+ reinterpret_cast<sptr_t>(wMain.GetID()));
+}
+
+void ScintillaQt::NotifyFocus(bool focus)
+{
+ emit command(
+ Platform::LongFromTwoShorts
+ (GetCtrlID(), focus ? SCEN_SETFOCUS : SCEN_KILLFOCUS),
+ reinterpret_cast<sptr_t>(wMain.GetID()));
+}
+
+void ScintillaQt::NotifyParent(SCNotification scn)
+{
+ scn.nmhdr.hwndFrom = wMain.GetID();
+ scn.nmhdr.idFrom = GetCtrlID();
+ emit notifyParent(scn);
+}
+
+void ScintillaQt::SetTicking(bool on)
+{
+ QTimer *qTimer;
+ if (timer.ticking != on) {
+ timer.ticking = on;
+ if (timer.ticking) {
+ qTimer = new QTimer;
+ connect(qTimer, SIGNAL(timeout()), this, SLOT(tick()));
+ qTimer->start(timer.tickSize);
+ timer.tickerID = qTimer;
+ } else {
+ qTimer = static_cast<QTimer *>(timer.tickerID);
+ qTimer->stop();
+ disconnect(qTimer, SIGNAL(timeout()), 0, 0);
+ delete qTimer;
+ timer.tickerID = 0;
+ }
+ }
+ timer.ticksToWait = caret.period;
+}
+
+void ScintillaQt::onIdle()
+{
+ bool continueIdling = Idle();
+ if (!continueIdling) {
+ SetIdle(false);
+ }
+}
+
+bool ScintillaQt::SetIdle(bool on)
+{
+ QTimer *qIdle;
+ if (on) {
+ // Start idler, if it's not running.
+ if (!idler.state) {
+ idler.state = true;
+ qIdle = new QTimer;
+ connect(qIdle, SIGNAL(timeout()), this, SLOT(onIdle()));
+ qIdle->start(0);
+ idler.idlerID = qIdle;
+ }
+ } else {
+ // Stop idler, if it's running
+ if (idler.state) {
+ idler.state = false;
+ qIdle = static_cast<QTimer *>(idler.idlerID);
+ qIdle->stop();
+ disconnect(qIdle, SIGNAL(timeout()), 0, 0);
+ delete qIdle;
+ idler.idlerID = 0;
+ }
+ }
+ return true;
+}
+
+int ScintillaQt::CharacterSetOfDocument() const
+{
+ return vs.styles[STYLE_DEFAULT].characterSet;
+}
+
+const char *ScintillaQt::CharacterSetIDOfDocument() const
+{
+ return CharacterSetID(CharacterSetOfDocument());
+}
+
+QString ScintillaQt::StringFromDocument(const char *s) const
+{
+ if (IsUnicodeMode()) {
+ return QString::fromUtf8(s);
+ } else {
+ QTextCodec *codec = QTextCodec::codecForName(
+ CharacterSetID(CharacterSetOfDocument()));
+ return codec->toUnicode(s);
+ }
+}
+
+QByteArray ScintillaQt::BytesForDocument(const QString &text) const
+{
+ if (IsUnicodeMode()) {
+ return text.toUtf8();
+ } else {
+ QTextCodec *codec = QTextCodec::codecForName(
+ CharacterSetID(CharacterSetOfDocument()));
+ return codec->fromUnicode(text);
+ }
+}
+
+
+class CaseFolderUTF8 : public CaseFolderTable {
+public:
+ CaseFolderUTF8() {
+ StandardASCII();
+ }
+ virtual size_t Fold(char *folded, size_t sizeFolded, const char *mixed, size_t lenMixed) {
+ if ((lenMixed == 1) && (sizeFolded > 0)) {
+ folded[0] = mapping[static_cast<unsigned char>(mixed[0])];
+ return 1;
+ } else {
+ QString su = QString::fromUtf8(mixed, lenMixed);
+ QString suFolded = su.toCaseFolded();
+ QByteArray bytesFolded = suFolded.toUtf8();
+ if (bytesFolded.length() < static_cast<int>(sizeFolded)) {
+ memcpy(folded, bytesFolded, bytesFolded.length());
+ return bytesFolded.length();
+ } else {
+ folded[0] = '\0';
+ return 0;
+ }
+ }
+ }
+};
+
+class CaseFolderDBCS : public CaseFolderTable {
+ QTextCodec *codec;
+public:
+ CaseFolderDBCS(QTextCodec *codec_) : codec(codec_) {
+ StandardASCII();
+ }
+ virtual size_t Fold(char *folded, size_t sizeFolded, const char *mixed, size_t lenMixed) {
+ if ((lenMixed == 1) && (sizeFolded > 0)) {
+ folded[0] = mapping[static_cast<unsigned char>(mixed[0])];
+ return 1;
+ } else if (codec) {
+ QString su = codec->toUnicode(mixed, lenMixed);
+ QString suFolded = su.toCaseFolded();
+ QByteArray bytesFolded = codec->fromUnicode(suFolded);
+
+ if (bytesFolded.length() < static_cast<int>(sizeFolded)) {
+ memcpy(folded, bytesFolded, bytesFolded.length());
+ return bytesFolded.length();
+ }
+ }
+ // Something failed so return a single NUL byte
+ folded[0] = '\0';
+ return 1;
+ }
+};
+
+CaseFolder *ScintillaQt::CaseFolderForEncoding()
+{
+ if (pdoc->dbcsCodePage == SC_CP_UTF8) {
+ return new CaseFolderUTF8();
+ } else {
+ const char *charSetBuffer = CharacterSetIDOfDocument();
+ if (charSetBuffer) {
+ if (pdoc->dbcsCodePage == 0) {
+ CaseFolderTable *pcf = new CaseFolderTable();
+ pcf->StandardASCII();
+ QTextCodec *codec = QTextCodec::codecForName(charSetBuffer);
+ // Only for single byte encodings
+ for (int i=0x80; i<0x100; i++) {
+ char sCharacter[2] = "A";
+ sCharacter[0] = i;
+ QString su = codec->toUnicode(sCharacter, 1);
+ QString suFolded = su.toCaseFolded();
+ QByteArray bytesFolded = codec->fromUnicode(suFolded);
+ if (bytesFolded.length() == 1) {
+ pcf->SetTranslation(sCharacter[0], bytesFolded[0]);
+ }
+ }
+ return pcf;
+ } else {
+ return new CaseFolderDBCS(QTextCodec::codecForName(charSetBuffer));
+ }
+ }
+ return 0;
+ }
+}
+
+std::string ScintillaQt::CaseMapString(const std::string &s, int caseMapping)
+{
+ if (s.size() == 0)
+ return std::string();
+
+ if (caseMapping == cmSame)
+ return s;
+
+ QTextCodec *codec = 0;
+ QString text;
+ if (IsUnicodeMode()) {
+ text = QString::fromUtf8(s.c_str(), s.length());
+ } else {
+ codec = QTextCodec::codecForName(CharacterSetIDOfDocument());
+ text = codec->toUnicode(s.c_str(), s.length());
+ }
+
+ if (caseMapping == cmUpper) {
+ text = text.toUpper();
+ } else {
+ text = text.toLower();
+ }
+
+ QByteArray bytes = BytesForDocument(text);
+ return std::string(bytes.data(), bytes.length());
+}
+
+void ScintillaQt::SetMouseCapture(bool on)
+{
+ // This is handled automatically by Qt
+ if (mouseDownCaptures) {
+ haveMouseCapture = on;
+ }
+}
+
+bool ScintillaQt::HaveMouseCapture()
+{
+ return haveMouseCapture;
+}
+
+void ScintillaQt::StartDrag()
+{
+ inDragDrop = ddDragging;
+ dropWentOutside = true;
+ if (drag.len) {
+ QMimeData *mimeData = new QMimeData;
+ QString sText = StringFromSelectedText(drag);
+ mimeData->setText(sText);
+ if (drag.rectangular) {
+ AddRectangularToMime(mimeData, sText);
+ }
+ // This QDrag is not freed as that causes a crash on Linux
+ QDrag *dragon = new QDrag(scrollArea);
+ dragon->setMimeData(mimeData);
+
+ Qt::DropAction dropAction = dragon->exec(Qt::CopyAction|Qt::MoveAction);
+ if ((dropAction == Qt::MoveAction) && dropWentOutside) {
+ // Remove dragged out text
+ ClearSelection();
+ }
+ }
+ inDragDrop = ddNone;
+ SetDragPosition(SelectionPosition(invalidPosition));
+}
+
+void ScintillaQt::CreateCallTipWindow(PRectangle rc)
+{
+
+ if (!ct.wCallTip.Created()) {
+ QWidget *pCallTip = new QWidget(0, Qt::ToolTip);
+ ct.wCallTip = pCallTip;
+ pCallTip->move(rc.left, rc.top);
+ pCallTip->resize(rc.Width(), rc.Height());
+ }
+}
+
+void ScintillaQt::AddToPopUp(const char *label,
+ int cmd,
+ bool enabled)
+{
+ QMenu *menu = static_cast<QMenu *>(popup.GetID());
+ QString text(label);
+
+ if (text.isEmpty()) {
+ menu->addSeparator();
+ } else {
+ QAction *action = menu->addAction(text);
+ action->setData(cmd);
+ action->setEnabled(enabled);
+ }
+
+ // Make sure the menu's signal is connected only once.
+ menu->disconnect();
+ connect(menu, SIGNAL(triggered(QAction *)),
+ this, SLOT(execCommand(QAction *)));
+}
+
+sptr_t ScintillaQt::WndProc(unsigned int message, uptr_t wParam, sptr_t lParam)
+{
+ try {
+ switch (message) {
+
+ case SCI_GRABFOCUS:
+ scrollArea->setFocus(Qt::OtherFocusReason);
+ break;
+
+ case SCI_GETDIRECTFUNCTION:
+ return reinterpret_cast<sptr_t>(DirectFunction);
+
+ case SCI_GETDIRECTPOINTER:
+ return reinterpret_cast<sptr_t>(this);
+
+#ifdef SCI_LEXER
+ case SCI_LOADLEXERLIBRARY:
+ LexerManager::GetInstance()->Load(reinterpret_cast<const char *>(lParam));
+ break;
+#endif
+
+ default:
+ return ScintillaBase::WndProc(message, wParam, lParam);
+ }
+ } catch (std::bad_alloc &) {
+ errorStatus = SC_STATUS_BADALLOC;
+ } catch (...) {
+ errorStatus = SC_STATUS_FAILURE;
+ }
+ return 0l;
+}
+
+sptr_t ScintillaQt::DefWndProc(unsigned int, uptr_t, sptr_t)
+{
+ return 0;
+}
+
+sptr_t ScintillaQt::DirectFunction(
+ ScintillaQt *sciThis, unsigned int iMessage, uptr_t wParam, sptr_t lParam)
+{
+ return sciThis->WndProc(iMessage, wParam, lParam);
+}
+
+// Additions to merge in Scientific Toolworks widget structure
+
+void ScintillaQt::PartialPaint(const PRectangle &rect)
+{
+ rcPaint = rect;
+ paintState = painting;
+ PRectangle rcClient = GetClientRectangle();
+ paintingAllText = rcPaint.Contains(rcClient);
+
+ AutoSurface surface(this);
+ Paint(surface, rcPaint);
+ surface->Release();
+
+ if (paintState == paintAbandoned) {
+ // FIXME: Failure to paint the requested rectangle in each
+ // paint event causes flicker on some platforms (Mac?)
+ // Paint rect immediately.
+ paintState = painting;
+ paintingAllText = true;
+
+ AutoSurface surface(this);
+ Paint(surface, rcPaint);
+ surface->Release();
+
+ // Queue a full repaint.
+ scrollArea->viewport()->update();
+ }
+
+ paintState = notPainting;
+}
+
+void ScintillaQt::DragEnter(const Point &point)
+{
+ SetDragPosition(SPositionFromLocation(point,
+ false, false, UserVirtualSpace()));
+}
+
+void ScintillaQt::DragMove(const Point &point)
+{
+ SetDragPosition(SPositionFromLocation(point,
+ false, false, UserVirtualSpace()));
+}
+
+void ScintillaQt::DragLeave()
+{
+ SetDragPosition(SelectionPosition(invalidPosition));
+}
+
+void ScintillaQt::Drop(const Point &point, const QMimeData *data, bool move)
+{
+ QString text = data->text();
+ bool rectangular = IsRectangularInMime(data);
+ QByteArray bytes = BytesForDocument(text);
+ int len = bytes.length();
+ char *dest = Document::TransformLineEnds(&len, bytes, len, pdoc->eolMode);
+
+ SelectionPosition movePos = SPositionFromLocation(point,
+ false, false, UserVirtualSpace());
+
+ DropAt(movePos, dest, move, rectangular);
+
+ delete []dest;
+}
diff --git a/qt/ScintillaEditBase/ScintillaQt.h b/qt/ScintillaEditBase/ScintillaQt.h
new file mode 100644
index 000000000..61e24290d
--- /dev/null
+++ b/qt/ScintillaEditBase/ScintillaQt.h
@@ -0,0 +1,158 @@
+//
+// 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
+// ScintillaQt.h - Qt specific subclass of ScintillaBase
+
+#ifndef SCINTILLAQT_H
+#define SCINTILLAQT_H
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <time.h>
+#include <string>
+#include <vector>
+#include <map>
+
+#include "Scintilla.h"
+#include "Platform.h"
+#include "ILexer.h"
+#include "SVector.h"
+#include "SplitVector.h"
+#include "Partitioning.h"
+#include "RunStyles.h"
+#include "ContractionState.h"
+#include "CellBuffer.h"
+#include "CallTip.h"
+#include "KeyMap.h"
+#include "Indicator.h"
+#include "XPM.h"
+#include "LineMarker.h"
+#include "Style.h"
+#include "AutoComplete.h"
+#include "ViewStyle.h"
+#include "CharClassify.h"
+#include "Decoration.h"
+#include "Document.h"
+#include "Selection.h"
+#include "PositionCache.h"
+#include "Editor.h"
+#include "ScintillaBase.h"
+
+#ifdef SCI_LEXER
+#include "SciLexer.h"
+#include "PropSetSimple.h"
+#endif
+
+#include <QObject>
+#include <QAbstractScrollArea>
+#include <QAction>
+#include <QClipboard>
+#include <QPaintEvent>
+
+#ifdef SCI_NAMESPACE
+namespace Scintilla {
+#endif
+
+class ScintillaQt : public QObject, public ScintillaBase {
+ Q_OBJECT
+
+public:
+ ScintillaQt(QAbstractScrollArea *parent);
+ virtual ~ScintillaQt();
+
+signals:
+ void horizontalScrolled(int value);
+ void verticalScrolled(int value);
+ void horizontalRangeChanged(int max, int page);
+ void verticalRangeChanged(int max, int page);
+
+ void notifyParent(SCNotification scn);
+ void notifyChange();
+
+ // Clients can use this hook to add additional
+ // formats (e.g. rich text) to the MIME data.
+ void aboutToCopy(QMimeData *data);
+
+ void command(uptr_t wParam, sptr_t lParam);
+
+private slots:
+ void tick();
+ void onIdle();
+ void execCommand(QAction *action);
+ void SelectionChanged();
+
+private:
+ virtual void Initialise();
+ virtual void Finalise();
+ virtual bool DragThreshold(Point ptStart, Point ptNow);
+ virtual bool ValidCodePage(int codePage) const;
+
+private:
+ virtual void ScrollText(int linesToMove);
+ virtual void SetVerticalScrollPos();
+ virtual void SetHorizontalScrollPos();
+ virtual bool ModifyScrollBars(int nMax, int nPage);
+ virtual void ReconfigureScrollBars();
+ void CopyToModeClipboard(const SelectionText &selectedText, QClipboard::Mode clipboardMode_);
+ virtual void Copy();
+ virtual void CopyToClipboard(const SelectionText &selectedText);
+ void PasteFromMode(QClipboard::Mode clipboardMode_);
+ virtual void Paste();
+ virtual void ClaimSelection();
+ virtual void NotifyChange();
+ virtual void NotifyFocus(bool focus);
+ virtual void NotifyParent(SCNotification scn);
+ virtual void SetTicking(bool on);
+ virtual bool SetIdle(bool on);
+ virtual void SetMouseCapture(bool on);
+ virtual bool HaveMouseCapture();
+ virtual void StartDrag();
+ int CharacterSetOfDocument() const;
+ const char *CharacterSetIDOfDocument() const;
+ QString StringFromDocument(const char *s) const;
+ QByteArray BytesForDocument(const QString &text) const;
+ virtual CaseFolder *CaseFolderForEncoding();
+ virtual std::string CaseMapString(const std::string &s, int caseMapping);
+
+ virtual void CreateCallTipWindow(PRectangle rc);
+ virtual void AddToPopUp(const char *label, int cmd = 0, bool enabled = true);
+ virtual sptr_t WndProc(unsigned int iMessage, uptr_t wParam, sptr_t lParam);
+ virtual sptr_t DefWndProc(unsigned int iMessage, uptr_t wParam, sptr_t lParam);
+
+ static sptr_t DirectFunction(ScintillaQt *sciThis,
+ unsigned int iMessage, uptr_t wParam, sptr_t lParam);
+
+protected:
+
+ void PartialPaint(const PRectangle &rect);
+
+ void DragEnter(const Point &point);
+ void DragMove(const Point &point);
+ void DragLeave();
+ void Drop(const Point &point, const QMimeData *data, bool move);
+
+private:
+ QAbstractScrollArea *scrollArea;
+
+ int vMax, hMax; // Scroll bar maximums.
+ int vPage, hPage; // Scroll bar page sizes.
+
+ bool haveMouseCapture;
+ bool dragWasDropped;
+ int rectangularSelectionModifier;
+
+ friend class ScintillaEditBase;
+};
+
+#ifdef SCI_NAMESPACE
+}
+#endif
+
+#endif // SCINTILLAQT_H
diff --git a/qt/ScintillaEditPy/README b/qt/ScintillaEditPy/README
new file mode 100644
index 000000000..c07397031
--- /dev/null
+++ b/qt/ScintillaEditPy/README
@@ -0,0 +1,85 @@
+README for building of ScintillaEditPy on Qt with PySide
+
+This directory is for building a Python encapsulation of Scintilla for use
+with PySide. For C++ libraries see the README in the parent directory.
+
+ Prerequisites
+
+PySide and ScintillaEditPy currently only support Python 2.x.
+
+CMake may be used to rebuild PySide and is required on Windows.
+It can be downloaded from
+http://www.cmake.org/cmake/resources/software.html
+
+On Windows, PySide only supports Visual C++ 2008. The "Visual Studio 2008
+Command Prompt" should be used to run all build commands.
+Visual C++ 2008 Express Edition can be downloaded from
+http://msdn.microsoft.com/en-us/express/future/bb421473
+
+Download and install PySide. Instructions are on the PySide web site
+http://developer.qt.nokia.com/wiki/Category:LanguageBindings::PySide::Downloads
+
+For Linux, there may be both PySide library packages and PySide development
+files. Both should be installed as ScintillaEditPy needs the headers and
+libraries from the development package and runs with the normal library package.
+On apt-based systems, the packages are libshiboken-dev, shiboken, libpyside-dev,
+and python-pyside. python-dev is also needed for Python language headers.
+On yum-based systems the libpyside-dev package is called python-pyside-devel.
+The qmake program may not be in the path and can be found with
+"find /usr -name qmake".
+
+On Windows, the PySide library packages can be downloaded from
+http://developer.qt.nokia.com/wiki/PySide_Binaries_Windows
+The PySide development files must be built from source using CMake as
+described on the PySide site. This will create a Unix-style set of [bin, include,
+lib, and share] directories in packaging\setuptools\install-py<ver>-qt<qver>.
+There is no standard place for the PySide development files so copy them
+to "\usr", creating it if needed.
+
+On OS X, a combined package with PySide libraries and PySide development
+files can be downloaded from
+http://developer.qt.nokia.com/wiki/PySide_Binaries_MacOSX
+This package works best in combination with the Qt libraries for Mac from
+http://qt.nokia.com/downloads/downloads#qt-lib
+
+The path should be modified so that a Python 2.x interpreter and Qt's "qmake"
+program can be run by typing "python" or "qmake".
+
+ Building
+
+There are several steps to building and they are encapsulated in the sepbuild.py
+script which is run:
+
+python sepbuild.py
+
+This script first runs the WidgetGen.py script to fill out the ScintillaEdit.h,
+ScintillaEdit.cpp and ScintillaConstants.py files.
+
+A short file "sepbuild.pri" is written out which contains a series of version and
+path properties discovered by sepbuild.py which are used by qmake.
+
+Then it runs PySide's "shiboken" program to create C++ code that will act as a
+bridge between Python and the C++ libraries. This code goes into the
+ScintillaEditPy/ScintillaEditPy directory. Several log files are produced which can
+help uncover problems in the bridge if it fails to build.
+
+The qmake program is run to produce make files from ScintillaEditPy.pro.
+
+The system make program is then run to build the library. The library is located in
+the scintilla/bin directory as ScintillaEditPy.so for Unix systems and
+ScintillaEditPy.pyd for Windows.
+
+A demonstration program can be run:
+
+python testswp.py
+
+The individual steps in the script can be run manually if wanted although the
+shiboken program has complex arguments and differs between systems so run
+sepbuild.py and copy the section starting with a line containing "generatorrunner"
+and continuing to "typesystem_ScintillaEdit.xml".
+
+On Windows, it is more difficult to set up an environment to debug ScintillaEditPy
+since all the libraries have to be debug or all have to be release. The easy path
+is to always build for release with "nmake release".
+
+To remove generated code, run "python sepbuild.py --clean".
diff --git a/qt/ScintillaEditPy/ScintillaConstants.py.template b/qt/ScintillaEditPy/ScintillaConstants.py.template
new file mode 100644
index 000000000..31b82398d
--- /dev/null
+++ b/qt/ScintillaEditPy/ScintillaConstants.py.template
@@ -0,0 +1,6 @@
+# ScintillaConstants.py
+# Define all the symbolic constants from Scintilla.iface so Python code can use them
+# Copyright (c) 2011 Archaeopteryx Software, Inc. d/b/a Wingware
+
+# ++Autogenerated -- start of section automatically generated from Scintilla.iface */
+# --Autogenerated -- end of section automatically generated from Scintilla.iface */
diff --git a/qt/ScintillaEditPy/ScintillaEditPy.pro b/qt/ScintillaEditPy/ScintillaEditPy.pro
new file mode 100644
index 000000000..c578a314c
--- /dev/null
+++ b/qt/ScintillaEditPy/ScintillaEditPy.pro
@@ -0,0 +1,116 @@
+TEMPLATE = lib
+QT += core gui
+
+TARGET = ScintillaEditPy
+
+# Clear debug & release so that sepbuild.pri can set one or the other
+CONFIG -= debug release
+
+include(sepbuild.pri)
+
+VERSION = $$SCINTILLA_VERSION
+
+win32 {
+ DebugBuild {
+ TARGET_EXT = _d.pyd
+ }
+ else {
+ TARGET_EXT = .pyd
+ }
+}
+
+INCLUDEPATH += ../ScintillaEdit
+INCLUDEPATH += ../ScintillaEditBase
+INCLUDEPATH += ../../include ../../lexlib ../../src
+
+INCLUDEPATH += $$PY_INCLUDES
+
+INCLUDEPATH += $$SHIBOKEN_INCLUDES
+INCLUDEPATH += $$PYSIDE_INCLUDES
+INCLUDEPATH += $$PYSIDE_INCLUDES/QtCore
+INCLUDEPATH += $$PYSIDE_INCLUDES/QtGui
+
+unix:!mac {
+ LIBS += -ldl
+ LIBS += `pkg-config pyside --libs`
+}
+
+macx {
+ # Only build for x64 for now
+ # QMAKE_CFLAGS = -arch i386 -arch x86_64
+ # QMAKE_CXXFLAGS = -arch i386 -arch x86_64
+ # QMAKE_LFLAGS = -arch i386 -arch x86_64
+ LIBS += -L$$PY_LIBDIR -lpython$$PY_VERSION_SUFFIX
+ LIBS += -L$$PYSIDE_LIB
+ debug {
+ LIBS += -lshiboken-python$$PY_VERSION_SUFFIX-dbg
+ LIBS += -lpyside-python$$PY_VERSION_SUFFIX-dbg
+ }
+ else {
+ LIBS += -lshiboken-python$$PY_VERSION_SUFFIX
+ LIBS += -lpyside-python$$PY_VERSION_SUFFIX
+ }
+}
+
+win32 {
+ DebugBuild {
+ DEFINES += DEBUG
+ LIBS += -lQtCored4
+ }
+ else {
+ LIBS += -lQtCore
+ }
+ LIBS += -L$$PY_PREFIX/libs # Note python lib is pulled in via a #pragma
+ LIBS += -L$$PYSIDE_LIB
+ # PySide uses x.y suffix on Windows even though Python uses xy
+ DebugBuild {
+ LIBS += -lshiboken-python$${PY_VERSION}_d
+ LIBS += -lpyside-python$${PY_VERSION}_d
+ }
+ else {
+ LIBS += -lshiboken-python$${PY_VERSION}
+ LIBS += -lpyside-python$${PY_VERSION}
+ }
+}
+
+# Wrapper sources; notifyheader commented out due to shiboken bug
+SOURCES += \
+ ScintillaEditPy/scintillaeditpy_module_wrapper.cpp \
+ ScintillaEditPy/sci_notifyheader_wrapper.cpp \
+ ScintillaEditPy/scnotification_wrapper.cpp \
+ ScintillaEditPy/scintillaeditbase_wrapper.cpp \
+ ScintillaEditPy/scintillaedit_wrapper.cpp \
+ ScintillaEditPy/scintilladocument_wrapper.cpp
+
+# ScintillaEdit sources
+
+SOURCES += \
+ ../ScintillaEdit/ScintillaEdit.cpp \
+ ../ScintillaEdit/ScintillaDocument.cpp \
+ ../ScintillaEditBase/PlatQt.cpp \
+ ../ScintillaEditBase/ScintillaQt.cpp \
+ ../ScintillaEditBase/ScintillaEditBase.cpp \
+ ../../src/*.cxx \
+ ../../lexlib/*.cxx \
+ ../../lexers/*.cxx
+
+# HEADERS is used to find what needs to be run through moc
+HEADERS += \
+ ../ScintillaEdit/ScintillaEdit.h \
+ ../ScintillaEdit/ScintillaDocument.h \
+ ../ScintillaEditBase/ScintillaQt.h \
+ ../ScintillaEditBase/ScintillaEditBase.h
+
+DEFINES += SCINTILLA_QT=1 MAKING_LIBRARY=1 SCI_LEXER=1 _CRT_SECURE_NO_DEPRECATE=1
+
+DESTDIR = ../../bin
+
+unix:!mac {
+ # Rename to not have 'lib' at start
+ QMAKE_POST_LINK += rm -rf ../../bin/ScintillaEditPy.so && ln -s libScintillaEditPy.so ../../bin/ScintillaEditPy.so
+}
+
+macx {
+ # Rename to .so and not have 'lib' at start
+ QMAKE_POST_LINK += rm -rf ../../bin/ScintillaEditPy.so && ln -s libScintillaEditPy.dylib ../../bin/ScintillaEditPy.so
+}
diff --git a/qt/ScintillaEditPy/global.h b/qt/ScintillaEditPy/global.h
new file mode 100644
index 000000000..8b4be843a
--- /dev/null
+++ b/qt/ScintillaEditPy/global.h
@@ -0,0 +1,4 @@
+#include "pyside_global.h"
+
+#include "ScintillaEditBase.h"
+#include "ScintillaEdit.h"
diff --git a/qt/ScintillaEditPy/sepbuild.py b/qt/ScintillaEditPy/sepbuild.py
new file mode 100644
index 000000000..b694f15b0
--- /dev/null
+++ b/qt/ScintillaEditPy/sepbuild.py
@@ -0,0 +1,312 @@
+import distutils.sysconfig
+import getopt
+import glob
+import os
+import platform
+import shutil
+import subprocess
+import stat
+import sys
+
+sys.path.append(os.path.join("..", "ScintillaEdit"))
+import WidgetGen
+
+# Decide up front which platform, treat anything other than Windows or OS X as Linux
+PLAT_WINDOWS = platform.system() == "Windows"
+PLAT_DARWIN = platform.system() == "Darwin"
+PLAT_LINUX = not (PLAT_DARWIN or PLAT_WINDOWS)
+
+def IsFileNewer(name1, name2):
+ """ Returns whether file with name1 is newer than file with name2. Returns 1
+ if name2 doesn't exist. """
+
+ if not os.path.exists(name1):
+ return 0
+
+ if not os.path.exists(name2):
+ return 1
+
+ mod_time1 = os.stat(name1)[stat.ST_MTIME]
+ mod_time2 = os.stat(name2)[stat.ST_MTIME]
+ return (mod_time1 > mod_time2)
+
+def textFromRun(args):
+ (stdoutdata, stderrdata) = subprocess.Popen(args, shell=True, stdout=subprocess.PIPE).communicate()
+ return stdoutdata
+
+def runProgram(args, exitOnFailure):
+ print(" ".join(args))
+ retcode = subprocess.call(" ".join(args), shell=True, stderr=subprocess.STDOUT)
+ if retcode:
+ print("Failed in " + " ".join(args) + " return code = " + str(retcode))
+ if exitOnFailure:
+ sys.exit()
+
+def usage():
+ print("sepbuild.py [-h|--help][-c|--clean][-u|--underscore-names]")
+ print("")
+ print("Generate PySide wappers and build them.")
+ print("")
+ print("options:")
+ print("")
+ print("-c --clean remove all object and generated files")
+ print("-b --pyside-base Location of the PySide+Qt4 sandbox to use")
+ print("-h --help display this text")
+ print("-d --debug=yes|no force debug build (or non-debug build)")
+ print("-u --underscore-names use method_names consistent with GTK+ standards")
+
+modifyFunctionElement = """ <modify-function signature="%s">%s
+ </modify-function>
+"""
+
+injectCode = """
+ <inject-code class="target" position="beginning">%s
+ </inject-code>"""
+
+injectCheckN = """
+ if (!cppArg%d) {
+ PyErr_SetString(PyExc_ValueError, "Null string argument");
+ return 0;
+ }"""
+
+def methodSignature(name, v, options):
+ argTypes = ""
+ p1Type = WidgetGen.cppAlias(v["Param1Type"])
+ if p1Type:
+ argTypes = argTypes + p1Type
+ p2Type = WidgetGen.cppAlias(v["Param2Type"])
+ if p2Type and v["Param2Type"] != "stringresult":
+ if p1Type:
+ argTypes = argTypes + ", "
+ argTypes = argTypes + p2Type
+ methodName = WidgetGen.normalisedName(name, options, v["FeatureType"])
+ constDeclarator = " const" if v["FeatureType"] == "get" else ""
+ return methodName + "(" + argTypes + ")" + constDeclarator
+
+def printTypeSystemFile(f,out, options):
+ for name in f.order:
+ v = f.features[name]
+ if v["Category"] != "Deprecated":
+ feat = v["FeatureType"]
+ if feat in ["fun", "get", "set"]:
+ checks = ""
+ if v["Param1Type"] == "string":
+ checks = checks + (injectCheckN % 0)
+ if v["Param2Type"] == "string":
+ if v["Param1Type"] == "": # Only arg 2 -> treat as first
+ checks = checks + (injectCheckN % 0)
+ else:
+ checks = checks + (injectCheckN % 1)
+ if checks:
+ inject = injectCode % checks
+ out.write(modifyFunctionElement % (methodSignature(name, v, options), inject))
+ #if v["Param1Type"] == "string":
+ # out.write("<string-xml>" + name + "</string-xml>\n")
+
+def doubleBackSlashes(s):
+ # Quote backslashes so qmake does not produce warnings
+ return s.replace("\\", "\\\\")
+
+class SepBuilder:
+ def __init__(self):
+ # Discover configuration parameters
+ self.ScintillaEditIncludes = [".", "../ScintillaEdit", "../ScintillaEditBase", "../../include"]
+ if PLAT_WINDOWS:
+ self.MakeCommand = "nmake"
+ self.MakeTarget = "release"
+ else:
+ self.MakeCommand = "make"
+ self.MakeTarget = ""
+
+ if PLAT_DARWIN:
+ self.QMakeOptions = "-spec macx-g++"
+ else:
+ self.QMakeOptions = ""
+
+ # Default to debug build if running in a debug build interpreter
+ self.DebugBuild = hasattr(sys, 'getobjects')
+
+ # Python
+ self.PyVersion = "%d.%d" % sys.version_info[:2]
+ self.PyVersionSuffix = distutils.sysconfig.get_config_var("VERSION")
+ self.PyIncludes = distutils.sysconfig.get_python_inc()
+ self.PyPrefix = distutils.sysconfig.get_config_var("prefix")
+ self.PyLibDir = distutils.sysconfig.get_config_var(
+ ("LIBDEST" if sys.platform == 'win32' else "LIBDIR"))
+
+ # Scintilla
+ with open("../../version.txt") as f:
+ version = f.read()
+ self.ScintillaVersion = version[0] + '.' + version[1] + '.' + version[2]
+
+ # Qt default location from qmake
+ self._SetQtIncludeBase(textFromRun("qmake -query QT_INSTALL_HEADERS").rstrip())
+
+ # PySide default location
+ # No standard for installing PySide development headers and libs on Windows so
+ # choose /usr to be like Linux
+ self._setPySideBase('\\usr' if PLAT_WINDOWS else '/usr')
+
+ self.ProInclude = "sepbuild.pri"
+
+ self.qtStyleInterface = True
+
+ def _setPySideBase(self, base):
+
+ self.PySideBase = base
+ if PLAT_LINUX:
+ self.PySideTypeSystem = textFromRun("pkg-config --variable=typesystemdir pyside").rstrip()
+ self.PySideIncludeBase = textFromRun("pkg-config --variable=includedir pyside").rstrip()
+ self.ShibokenIncludeBase = textFromRun("pkg-config --variable=includedir shiboken").rstrip()
+ else:
+ self.PySideTypeSystem = os.path.join(self.PySideBase, "share", "PySide", "typesystems")
+ self.ShibokenIncludeBase = os.path.join(self.PySideBase, "include", "shiboken")
+ self.PySideIncludeBase = os.path.join(self.PySideBase, "include", "PySide")
+
+ self.PySideIncludes = [
+ self.ShibokenIncludeBase,
+ self.PySideIncludeBase,
+ os.path.join(self.PySideIncludeBase, "QtCore"),
+ os.path.join(self.PySideIncludeBase, "QtGui")]
+
+ self.PySideLibDir = os.path.join(self.PySideBase, "lib")
+ self.AllIncludes = os.pathsep.join(self.QtIncludes + self.ScintillaEditIncludes + self.PySideIncludes)
+
+ self.ShibokenGenerator = "shiboken"
+ # Is this still needed? It doesn't work with latest shiboken sources
+ #if PLAT_DARWIN:
+ # # On OS X, can not automatically find Shiboken dylib so provide a full path
+ # self.ShibokenGenerator = os.path.join(self.PySideLibDir, "generatorrunner", "shiboken")
+
+ def generateAPI(self, args):
+ os.chdir(os.path.join("..", "ScintillaEdit"))
+ if not self.qtStyleInterface:
+ args.insert(0, '--underscore-names')
+ WidgetGen.main(args)
+ f = WidgetGen.readInterface(False)
+ os.chdir(os.path.join("..", "ScintillaEditPy"))
+ options = {"qtStyle": self.qtStyleInterface}
+ WidgetGen.Generate("typesystem_ScintillaEdit.xml.template", "typesystem_ScintillaEdit.xml", printTypeSystemFile, f, options)
+
+ def runGenerator(self):
+ generatorrunner = "shiboken"
+ for name in ('shiboken', 'generatorrunner'):
+ if PLAT_WINDOWS:
+ name += '.exe'
+ name = os.path.join(self.PySideBase, "bin", name)
+ if os.path.exists(name):
+ generatorrunner = name
+ break
+
+ args = [
+ generatorrunner,
+ "--generator-set=" + self.ShibokenGenerator,
+ "global.h ",
+ "--avoid-protected-hack",
+ "--enable-pyside-extensions",
+ "--include-paths=" + self.AllIncludes,
+ "--typesystem-paths=" + self.PySideTypeSystem,
+ "--output-directory=.",
+ "typesystem_ScintillaEdit.xml"]
+ print(" ".join(args))
+ retcode = subprocess.call(" ".join(args), shell=True, stderr=subprocess.STDOUT)
+ if retcode:
+ print("Failed in generatorrunner", retcode)
+ sys.exit()
+
+ def writeVariables(self):
+ # Write variables needed into file to be included from project so it does not have to discover much
+ with open(self.ProInclude, "w") as f:
+ f.write("SCINTILLA_VERSION=" + self.ScintillaVersion + "\n")
+ f.write("PY_VERSION=" + self.PyVersion + "\n")
+ f.write("PY_VERSION_SUFFIX=" + self.PyVersionSuffix + "\n")
+ f.write("PY_PREFIX=" + doubleBackSlashes(self.PyPrefix) + "\n")
+ f.write("PY_INCLUDES=" + doubleBackSlashes(self.PyIncludes) + "\n")
+ f.write("PY_LIBDIR=" + doubleBackSlashes(self.PyLibDir) + "\n")
+ f.write("PYSIDE_INCLUDES=" + doubleBackSlashes(self.PySideIncludeBase) + "\n")
+ f.write("PYSIDE_LIB=" + doubleBackSlashes(self.PySideLibDir) + "\n")
+ f.write("SHIBOKEN_INCLUDES=" + doubleBackSlashes(self.ShibokenIncludeBase) + "\n")
+ if self.DebugBuild:
+ f.write("CONFIG += debug\n")
+ else:
+ f.write("CONFIG += release\n")
+
+ def make(self):
+ runProgram(["qmake", self.QMakeOptions], exitOnFailure=True)
+ runProgram([self.MakeCommand, self.MakeTarget], exitOnFailure=True)
+
+ def cleanEverything(self):
+ self.generateAPI(["--clean"])
+ runProgram([self.MakeCommand, "distclean"], exitOnFailure=False)
+ try:
+ os.remove(self.ProInclude)
+ except OSError:
+ pass
+ for logFile in glob.glob("*.log"):
+ try:
+ os.remove(logFile)
+ except OSError:
+ pass
+ shutil.rmtree("debug", ignore_errors=True)
+ shutil.rmtree("release", ignore_errors=True)
+ shutil.rmtree("ScintillaEditPy", ignore_errors=True)
+
+ def buildEverything(self):
+ cleanGenerated = False
+ opts, args = getopt.getopt(sys.argv[1:], "hcdub",
+ ["help", "clean", "debug=",
+ "underscore-names", "pyside-base="])
+ for opt, arg in opts:
+ if opt in ("-h", "--help"):
+ usage()
+ sys.exit()
+ elif opt in ("-c", "--clean"):
+ cleanGenerated = True
+ elif opt in ("-d", "--debug"):
+ self.DebugBuild = (arg == '' or arg.lower() == 'yes')
+ if self.DebugBuild and sys.platform == 'win32':
+ self.MakeTarget = 'debug'
+ elif opt in ("-b", '--pyside-base'):
+ self._SetQtIncludeBase(os.path.join(os.path.normpath(arg), 'include'))
+ self._setPySideBase(os.path.normpath(arg))
+ elif opt in ("-u", "--underscore-names"):
+ self.qtStyleInterface = False
+
+ if cleanGenerated:
+ self.cleanEverything()
+ else:
+ self.writeVariables()
+ self.generateAPI([""])
+ self.runGenerator()
+ self.make()
+ self.copyScintillaConstants()
+
+ def copyScintillaConstants(self):
+
+ orig = 'ScintillaConstants.py'
+ dest = '../../bin/' + orig
+ if IsFileNewer(dest, orig):
+ return
+
+ f = open(orig, 'r')
+ contents = f.read()
+ f.close()
+
+ f = open(dest, 'w')
+ f.write(contents)
+ f.close()
+
+ def _SetQtIncludeBase(self, base):
+
+ self.QtIncludeBase = base
+ self.QtIncludes = [self.QtIncludeBase] + [os.path.join(self.QtIncludeBase, sub) for sub in ["QtCore", "QtGui"]]
+ # Set path so correct qmake is found
+ path = os.environ.get('PATH', '').split(os.pathsep)
+ qt_bin_dir = os.path.join(os.path.dirname(base), 'bin')
+ if qt_bin_dir not in path:
+ path.insert(0, qt_bin_dir)
+ os.environ['PATH'] = os.pathsep.join(path)
+
+if __name__ == "__main__":
+ sepBuild = SepBuilder()
+ sepBuild.buildEverything()
diff --git a/qt/ScintillaEditPy/testsepq.py b/qt/ScintillaEditPy/testsepq.py
new file mode 100644
index 000000000..a3849295d
--- /dev/null
+++ b/qt/ScintillaEditPy/testsepq.py
@@ -0,0 +1,157 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
+import sys
+
+from PySide.QtCore import *
+from PySide.QtGui import *
+
+import ScintillaConstants as sci
+
+sys.path.append("../..")
+from bin import ScintillaEditPy
+
+txtInit = "int main(int argc, char **argv) {\n" \
+ " // Start up the gnome\n" \
+ " gnome_init(\"stest\", \"1.0\", argc, argv);\n}\n";
+
+keywords = \
+ "and and_eq asm auto bitand bitor bool break " \
+ "case catch char class compl const const_cast continue " \
+ "default delete do double dynamic_cast else enum explicit export extern false float for " \
+ "friend goto if inline int long mutable namespace new not not_eq " \
+ "operator or or_eq private protected public " \
+ "register reinterpret_cast return short signed sizeof static static_cast struct switch " \
+ "template this throw true try typedef typeid typename union unsigned using " \
+ "virtual void volatile wchar_t while xor xor_eq";
+
+def uriDropped():
+ print "uriDropped"
+
+class Form(QDialog):
+
+ def __init__(self, parent=None):
+ super(Form, self).__init__(parent)
+ self.resize(460,300)
+ # Create widgets
+ self.edit = ScintillaEditPy.ScintillaEdit(self)
+ self.edit.uriDropped.connect(uriDropped)
+ self.edit.command.connect(self.receive_command)
+ self.edit.notify.connect(self.receive_notification)
+
+ self.edit.styleClearAll()
+ self.edit.setMarginWidthN(0, 35)
+ self.edit.setScrollWidth(200)
+ self.edit.setScrollWidthTracking(1)
+ self.edit.setLexer(sci.SCLEX_CPP)
+ self.edit.styleSetFore(sci.SCE_C_COMMENT, 0x008000)
+ self.edit.styleSetFore(sci.SCE_C_COMMENTLINE, 0x008000)
+ self.edit.styleSetFore(sci.SCE_C_COMMENTDOC, 0x008040)
+ self.edit.styleSetItalic(sci.SCE_C_COMMENTDOC, 1)
+ self.edit.styleSetFore(sci.SCE_C_NUMBER, 0x808000)
+ self.edit.styleSetFore(sci.SCE_C_WORD, 0x800000)
+ self.edit.styleSetBold(sci.SCE_C_WORD, True)
+ self.edit.styleSetFore(sci.SCE_C_STRING, 0x800080)
+ self.edit.styleSetFore(sci.SCE_C_PREPROCESSOR, 0x008080)
+ self.edit.styleSetBold(sci.SCE_C_OPERATOR, True)
+ self.edit.setMultipleSelection(1)
+ self.edit.setVirtualSpaceOptions(
+ sci.SCVS_RECTANGULARSELECTION | sci.SCVS_USERACCESSIBLE)
+ self.edit.setAdditionalSelectionTyping(1)
+
+ self.edit.styleSetFore(sci.STYLE_INDENTGUIDE, 0x808080)
+ self.edit.setIndentationGuides(sci.SC_IV_LOOKBOTH)
+
+ self.edit.setKeyWords(0, keywords)
+ self.edit.addText(len(txtInit), txtInit)
+ self.edit.setSel(1,10)
+ retriever = str(self.edit.getLine(1))
+ print(type(retriever), len(retriever))
+ print('[' + retriever + ']')
+ someText = str(self.edit.textRange(2,5))
+ print(len(someText), '[' + someText + ']')
+ someText = self.edit.getCurLine(100)
+ print(len(someText), '[' + someText + ']')
+ someText = self.edit.styleGetFont(1)
+ print(len(someText), '[' + someText + ']')
+ someText = self.edit.getSelText()
+ print(len(someText), '[' + someText + ']')
+ someText = self.edit.getTag(1)
+ print(len(someText), '[' + someText + ']')
+ someText = self.edit.autoCGetCurrentText()
+ print(len(someText), '[' + someText + ']')
+ someText = self.edit.annotationText(1)
+ print(len(someText), '[' + someText + ']')
+ someText = self.edit.annotationStyles(1)
+ print(len(someText), '[' + someText + ']')
+ someText = self.edit.describeKeyWordSets()
+ print(len(someText), '[' + someText + ']')
+ someText = self.edit.propertyNames()
+ print(len(someText), '[' + someText + ']')
+ self.edit.setProperty("fold", "1")
+ someText = self.edit.getProperty("fold")
+ print(len(someText), '[' + someText + ']')
+ someText = self.edit.getPropertyExpanded("fold")
+ print(len(someText), '[' + someText + ']')
+ someText = self.edit.lexerLanguage()
+ print(len(someText), '[' + someText + ']')
+ someText = self.edit.describeProperty("styling.within.preprocessor")
+ print(len(someText), '[' + someText + ']')
+
+ xx = self.edit.findText(0, "main", 0, 25)
+ print(type(xx), xx)
+ print("isBold", self.edit.styleBold(sci.SCE_C_WORD))
+
+ # Retrieve the document and write into it
+ doc = self.edit.get_doc()
+ doc.insert_string(40, "***")
+ stars = doc.get_char_range(40,3)
+ assert stars == "***"
+
+ # Create a new independent document and attach it to the editor
+ doc = ScintillaEditPy.ScintillaDocument()
+ doc.insert_string(0, "/***/\nif(a)\n")
+ self.edit.set_doc(doc)
+ self.edit.setLexer(sci.SCLEX_CPP)
+
+ def Call(self, message, wParam=0, lParam=0):
+ return self.edit.send(message, wParam, lParam)
+
+ def resizeEvent(self, e):
+ self.edit.resize(e.size().width(), e.size().height())
+
+ def receive_command(self, wParam, lParam):
+ # Show underline at start when focussed
+ notifyCode = wParam >> 16
+ if (notifyCode == sci.SCEN_SETFOCUS) or (notifyCode == sci.SCEN_KILLFOCUS):
+ self.edit.setIndicatorCurrent(sci.INDIC_CONTAINER);
+ self.edit.indicatorClearRange(0, self.edit.length())
+ if notifyCode == sci.SCEN_SETFOCUS:
+ self.edit.indicatorFillRange(0, 2);
+
+ def receive_notification(self, scn):
+ if scn.nmhdr.code == sci.SCN_CHARADDED:
+ print "Char %02X" % scn.ch
+ elif scn.nmhdr.code == sci.SCN_SAVEPOINTREACHED:
+ print "Saved"
+ elif scn.nmhdr.code == sci.SCN_SAVEPOINTLEFT:
+ print "Unsaved"
+ elif scn.nmhdr.code == sci.SCN_MODIFIED:
+ print "Modified"
+ elif scn.nmhdr.code == sci.SCN_UPDATEUI:
+ print "Update UI"
+ elif scn.nmhdr.code == sci.SCN_PAINTED:
+ #print "Painted"
+ pass
+ else:
+ print "Notification", scn.nmhdr.code
+ pass
+
+if __name__ == '__main__':
+ # Create the Qt Application
+ app = QApplication(sys.argv)
+ # Create and show the form
+ form = Form()
+ form.show()
+ # Run the main Qt loop
+ sys.exit(app.exec_())
diff --git a/qt/ScintillaEditPy/typesystem_ScintillaEdit.xml.template b/qt/ScintillaEditPy/typesystem_ScintillaEdit.xml.template
new file mode 100644
index 000000000..4c2c897a2
--- /dev/null
+++ b/qt/ScintillaEditPy/typesystem_ScintillaEdit.xml.template
@@ -0,0 +1,16 @@
+<?xml version="1.0"?>
+<typesystem package="ScintillaEditPy">
+ <load-typesystem name="typesystem_core.xml" generate="no" />
+ <load-typesystem name="typesystem_gui_common.xml" generate="no"/>
+ <primitive-type name="sptr_t"/>
+ <primitive-type name="uptr_t"/>
+ <value-type name="Sci_NotifyHeader" />
+ <rejection class="Sci_NotifyHeader" field-name="hwndFrom" />
+ <value-type name="SCNotification" />
+ <object-type name="ScintillaEditBase" />
+ <object-type name="ScintillaEdit">
+ <!-- ++Autogenerated start of section automatically generated from Scintilla.iface -->
+ <!-- ~~Autogenerated end of section automatically generated from Scintilla.iface -->
+ </object-type>
+ <object-type name="ScintillaDocument" />
+</typesystem>