Finish 0.4.5
This commit is contained in:
commit
719dceef69
|
@ -18,12 +18,6 @@ install:
|
|||
- wget http://www.cmake.org/files/v3.3/cmake-3.3.1-Linux-x86_64.tar.gz
|
||||
- tar xf cmake-3.3.1-Linux-x86_64.tar.gz
|
||||
- export CMAKE_EXECUTABLE=/tmp/cmake-3.3.1-Linux-x86_64/bin/cmake
|
||||
- wget http://downloads.dlang.org/releases/2015/dmd_2.068.0-0_amd64.deb
|
||||
- echo "Installing D"
|
||||
- sudo dpkg -i dmd_2.068.0-0_amd64.deb
|
||||
- echo "Installing Nim"
|
||||
- wget http://cz.archive.ubuntu.com/ubuntu/pool/universe/n/nim/nim_0.11.2+dfsg1-4_amd64.deb
|
||||
- sudo dpkg -i nim_0.11.2+dfsg1-4_amd64.deb
|
||||
- cd -
|
||||
|
||||
before_script:
|
||||
|
|
|
@ -1,3 +1,7 @@
|
|||
# Version 0.4.5
|
||||
* Removed the D bindings
|
||||
* Removed the Nim bindings
|
||||
|
||||
# Version 0.4.2
|
||||
* [DOtherSide] Code cleanup and little refactoring
|
||||
* [NimQml] Made nim compiles with the "cpp" option by default. This should fix C/C++ interop problems
|
||||
|
|
|
@ -1,4 +1,2 @@
|
|||
cmake_minimum_required(VERSION 3.0)
|
||||
add_subdirectory(DOtherSide)
|
||||
add_subdirectory(Nim)
|
||||
add_subdirectory(D)
|
||||
add_subdirectory(src)
|
||||
|
|
|
@ -1,3 +0,0 @@
|
|||
list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake/D)
|
||||
add_subdirectory(DQml)
|
||||
add_subdirectory(Examples)
|
|
@ -1,17 +0,0 @@
|
|||
cmake_minimum_required(VERSION 3.0)
|
||||
project (DQml C D )
|
||||
add_library(${PROJECT_NAME} STATIC
|
||||
dqml.d
|
||||
qobject.d
|
||||
qvariant.d
|
||||
qmetatype.d
|
||||
qquickview.d
|
||||
qqmlapplicationengine.d
|
||||
qqmlcontext.d
|
||||
qguiapplication.d
|
||||
qapplication.d
|
||||
qmodelindex.d
|
||||
qabstractlistmodel.d
|
||||
qobjectgenerators.d
|
||||
)
|
||||
target_include_directories(${PROJECT_NAME} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
|
|
@ -1,126 +0,0 @@
|
|||
extern(C)
|
||||
{
|
||||
// QApplication
|
||||
void dos_qapplication_create();
|
||||
void dos_qapplication_exec();
|
||||
void dos_qapplication_delete();
|
||||
void dos_qapplication_quit();
|
||||
|
||||
// QGuiApplication
|
||||
void dos_qguiapplication_create();
|
||||
void dos_qguiapplication_exec();
|
||||
void dos_qguiapplication_delete();
|
||||
void dos_qguiapplication_quit();
|
||||
|
||||
// QQmlApplicationEngine
|
||||
void dos_qqmlapplicationengine_create(ref void*);
|
||||
void dos_qqmlapplicationengine_load(void*, immutable (char)* filename);
|
||||
void dos_qqmlapplicationengine_context(void*, ref void*);
|
||||
void dos_qqmlapplicationengine_delete(void*);
|
||||
|
||||
// QQuickView
|
||||
void dos_qquickview_create(ref void*);
|
||||
void dos_qquickview_show(void*);
|
||||
void dos_qquickview_source(void*, ref char *);
|
||||
void dos_qquickview_set_source(void*, immutable (char)* filename);
|
||||
void dos_qquickview_rootContext(void*, ref void*);
|
||||
void dos_qquickview_delete(void*);
|
||||
|
||||
// CharArray
|
||||
void dos_chararray_delete(char*);
|
||||
|
||||
// QQmlContext
|
||||
void dos_qqmlcontext_baseUrl(void*, ref char*);
|
||||
void dos_qqmlcontext_setcontextproperty(void*, immutable (char)*, void*);
|
||||
|
||||
// QVariant
|
||||
void dos_qvariant_create(ref void*);
|
||||
void dos_qvariant_create_int(ref void*, int);
|
||||
void dos_qvariant_create_bool(ref void*, bool);
|
||||
void dos_qvariant_create_string(ref void*, immutable(char)*);
|
||||
void dos_qvariant_create_qobject(ref void*, void*);
|
||||
void dos_qvariant_create_float(ref void*, float);
|
||||
void dos_qvariant_create_double(ref void*, double);
|
||||
void dos_qvariant_toInt(void*, ref int);
|
||||
void dos_qvariant_setInt(void*, int);
|
||||
void dos_qvariant_toBool(void*, ref bool);
|
||||
void dos_qvariant_setBool(void*, bool);
|
||||
void dos_qvariant_toString(void*, ref char*);
|
||||
void dos_qvariant_setString(void*, immutable(char)*);
|
||||
void dos_qvariant_toFloat(void*, ref float);
|
||||
void dos_qvariant_setFloat(void*, float);
|
||||
void dos_qvariant_toDouble(void*, ref double);
|
||||
void dos_qvariant_setDouble(void*, double);
|
||||
void dos_qvariant_isnull(void*, ref bool);
|
||||
void dos_qvariant_delete(void*);
|
||||
void dos_qvariant_assign(void*, void*);
|
||||
void dos_qvariant_setQObject(void*, void*);
|
||||
|
||||
// QObject
|
||||
void dos_qobject_create(ref void*,
|
||||
void* dobject,
|
||||
void function (void*, void*, int , void**));
|
||||
|
||||
void dos_qobject_slot_create(void*,
|
||||
immutable (char)* name,
|
||||
int parametersCount,
|
||||
int* parametersMetaTypes,
|
||||
ref int slotIndex);
|
||||
|
||||
void dos_qobject_signal_create(void*,
|
||||
immutable(char)* name,
|
||||
int parametersCount,
|
||||
int* parametersMetaTypes,
|
||||
ref int signalIndex);
|
||||
|
||||
void dos_qobject_signal_emit(void*, immutable(char)* name,
|
||||
int parametersCount,
|
||||
void** parameters);
|
||||
|
||||
void dos_qobject_property_create(void*,
|
||||
immutable(char)* name,
|
||||
int propertyMetaType,
|
||||
immutable(char)* readSlot,
|
||||
immutable(char)* writeSlot,
|
||||
immutable(char)* notifySignal);
|
||||
|
||||
void dos_qobject_delete(void*);
|
||||
|
||||
// QModelIndex
|
||||
void dos_qmodelindex_create(ref void* index);
|
||||
void dos_qmodelindex_delete(void* index);
|
||||
void dos_qmodelindex_row(void*, ref int result);
|
||||
void dos_qmodelindex_column(void*, ref int result);
|
||||
void dos_qmodelindex_isValid(void* index, ref bool result);
|
||||
void dos_qmodelindex_data(void* index, int role, void* variant);
|
||||
void dos_qmodelindex_parent(void* index, void* parent);
|
||||
void dos_qmodelindex_child(void* index, int r, int c, void* child);
|
||||
void dos_qmodelindex_sibling(void* index, int r, int c, void* sibling);
|
||||
|
||||
// QHashIntByteArray
|
||||
void dos_qhash_int_qbytearray_create(ref void*);
|
||||
void dos_qhash_int_qbytearray_delete(void*);
|
||||
void dos_qhash_int_qbytearray_insert(void*, int, immutable(char)*);
|
||||
void dos_qhash_int_qbytearray_value(void*, int, ref char*);
|
||||
|
||||
// QAbstractListModel
|
||||
void dos_qabstractlistmodel_create(ref void*,
|
||||
void*,
|
||||
void function (void*, void*, int, void**),
|
||||
void function (void*, void*, ref int),
|
||||
void function (void*, void*, ref int),
|
||||
void function (void*, void*, int, void*),
|
||||
void function (void*, void*, void*, int, ref bool),
|
||||
void function (void*, void*),
|
||||
void function (void*, void*, ref int),
|
||||
void function (void*, int, int, int, void*));
|
||||
void dos_qabstractlistmodel_beginInsertRows(void* vptr, void* parent, int first, int last);
|
||||
void dos_qabstractlistmodel_endInsertRows(void* vptr);
|
||||
void dos_qabstractlistmodel_beginRemoveRows(void* vptr, void* parent, int first, int last);
|
||||
void dos_qabstractlistmodel_endRemoveRows(void* vptr);
|
||||
void dos_qabstractlistmodel_beginResetModel(void* vptr);
|
||||
void dos_qabstractlistmodel_endResetModel(void* vptr);
|
||||
void dos_qabstractlistmodel_dataChanged(void* vptr, void* topLeft, void* bottomRight, int* rolesPtr, int rolesLength);
|
||||
void dos_qabstractlistmodel_delete(void*);
|
||||
}
|
||||
|
|
@ -1,14 +0,0 @@
|
|||
public import qvariant;
|
||||
public import qguiapplication;
|
||||
public import qapplication;
|
||||
public import qqmlcontext;
|
||||
public import qobject;
|
||||
public import qqmlapplicationengine;
|
||||
public import qquickview;
|
||||
public import qmetatype;
|
||||
public import qmodelindex;
|
||||
public import qabstractlistmodel;
|
||||
public import qobjectgenerators;
|
||||
public import std.traits;
|
||||
public import std.algorithm;
|
||||
public import std.stdio;
|
|
@ -1,184 +0,0 @@
|
|||
import dothersideinterface;
|
||||
import qobject;
|
||||
import qmodelindex;
|
||||
import qvariant;
|
||||
import std.string;
|
||||
|
||||
class QAbstractListModel : QObject
|
||||
{
|
||||
this()
|
||||
{
|
||||
super(true);
|
||||
dos_qabstractlistmodel_create(this.vptr,
|
||||
cast(void*)this,
|
||||
&staticSlotCallback,
|
||||
&rowCountCallback,
|
||||
&columnCountCallback,
|
||||
&dataCallback,
|
||||
&setDataCallback,
|
||||
&roleNamesCallback,
|
||||
&flagsCallback,
|
||||
&headerDataCallback);
|
||||
qobjectInit();
|
||||
}
|
||||
|
||||
~this()
|
||||
{
|
||||
dos_qabstractlistmodel_delete(this.vptr);
|
||||
}
|
||||
|
||||
public int rowCount(QModelIndex parentIndex)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
public int columnCount(QModelIndex parentIndex)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
public QVariant data(QModelIndex index, int role)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
public bool setData(QModelIndex index, QVariant value, int role)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
public string[int] roleNames()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
public int flags(QModelIndex index)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
public QVariant headerData(int section, int orienation, int role)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
protected final void beginInsertRows(QModelIndex parent, int first, int last)
|
||||
{
|
||||
dos_qabstractlistmodel_beginInsertRows(this.vptr,
|
||||
parent.voidPointer(),
|
||||
first,
|
||||
last);
|
||||
}
|
||||
|
||||
protected final void endInsertRows()
|
||||
{
|
||||
dos_qabstractlistmodel_endInsertRows(this.vptr);
|
||||
}
|
||||
|
||||
protected final void beginRemoveRows(QModelIndex parent, int first, int last)
|
||||
{
|
||||
dos_qabstractlistmodel_beginRemoveRows(this.vptr,
|
||||
parent.voidPointer(),
|
||||
first,
|
||||
last);
|
||||
}
|
||||
|
||||
protected final void endRemoveRows()
|
||||
{
|
||||
dos_qabstractlistmodel_endRemoveRows(this.vptr);
|
||||
}
|
||||
|
||||
protected final void beginResetModel()
|
||||
{
|
||||
dos_qabstractlistmodel_beginResetModel(this.vptr);
|
||||
}
|
||||
|
||||
protected final void endResetModel()
|
||||
{
|
||||
dos_qabstractlistmodel_endResetModel(this.vptr);
|
||||
}
|
||||
|
||||
protected final void dataChanged(QModelIndex topLeft, QModelIndex bottomRight, int[] roles)
|
||||
{
|
||||
dos_qabstractlistmodel_dataChanged(this.vptr,
|
||||
topLeft.voidPointer(),
|
||||
bottomRight.voidPointer(),
|
||||
roles.ptr,
|
||||
cast(int)(roles.length));
|
||||
}
|
||||
|
||||
private extern (C) static void rowCountCallback(void* modelPtr,
|
||||
void* indexPtr,
|
||||
ref int result)
|
||||
{
|
||||
auto model = cast(QAbstractListModel)(modelPtr);
|
||||
auto index = new QModelIndex(indexPtr);
|
||||
result = model.rowCount(index);
|
||||
}
|
||||
|
||||
private extern (C) static void columnCountCallback(void* modelPtr,
|
||||
void* indexPtr,
|
||||
ref int result)
|
||||
{
|
||||
auto model = cast(QAbstractListModel)(modelPtr);
|
||||
auto index = new QModelIndex(indexPtr);
|
||||
result = model.columnCount(index);
|
||||
}
|
||||
|
||||
private extern (C) static void dataCallback(void* modelPtr,
|
||||
void* indexPtr,
|
||||
int role,
|
||||
void* result)
|
||||
{
|
||||
auto model = cast(QAbstractListModel)(modelPtr);
|
||||
auto index = new QModelIndex(indexPtr);
|
||||
auto value = model.data(index, role);
|
||||
if (value is null)
|
||||
return;
|
||||
dos_qvariant_assign(result, value.voidPointer());
|
||||
}
|
||||
|
||||
private extern (C) static void setDataCallback(void* modelPtr,
|
||||
void* indexPtr,
|
||||
void* valuePtr,
|
||||
int role,
|
||||
ref bool result)
|
||||
{
|
||||
auto model = cast(QAbstractListModel)(modelPtr);
|
||||
auto index = new QModelIndex(indexPtr);
|
||||
auto value = new QVariant(valuePtr);
|
||||
result = model.setData(index, value, role);
|
||||
}
|
||||
|
||||
private extern (C) static void roleNamesCallback(void* modelPtr,
|
||||
void* result)
|
||||
{
|
||||
auto model = cast(QAbstractListModel)(modelPtr);
|
||||
auto roles = model.roleNames();
|
||||
foreach(int key; roles.keys) {
|
||||
dos_qhash_int_qbytearray_insert(result, key, roles[key].toStringz());
|
||||
}
|
||||
}
|
||||
|
||||
private extern (C) static void flagsCallback(void* modelPtr,
|
||||
void* indexPtr,
|
||||
ref int result)
|
||||
{
|
||||
auto model = cast(QAbstractListModel)(modelPtr);
|
||||
auto index = new QModelIndex(indexPtr);
|
||||
result = model.flags(index);
|
||||
}
|
||||
|
||||
private extern (C) static void headerDataCallback(void* modelPtr,
|
||||
int section,
|
||||
int orientation,
|
||||
int role,
|
||||
void* result)
|
||||
{
|
||||
auto model = cast(QAbstractListModel)(modelPtr);
|
||||
QVariant value = model.headerData(section, orientation, role);
|
||||
if (value is null)
|
||||
return;
|
||||
dos_qvariant_assign(result, value.voidPointer());
|
||||
}
|
||||
}
|
|
@ -1,24 +0,0 @@
|
|||
import dothersideinterface;
|
||||
|
||||
class QApplication
|
||||
{
|
||||
this()
|
||||
{
|
||||
dos_qapplication_create();
|
||||
}
|
||||
|
||||
~this()
|
||||
{
|
||||
dos_qapplication_delete();
|
||||
}
|
||||
|
||||
void exec()
|
||||
{
|
||||
dos_qapplication_exec();
|
||||
}
|
||||
|
||||
void quit()
|
||||
{
|
||||
dos_qapplication_quit();
|
||||
}
|
||||
}
|
|
@ -1,24 +0,0 @@
|
|||
import dothersideinterface;
|
||||
|
||||
class QGuiApplication
|
||||
{
|
||||
this()
|
||||
{
|
||||
dos_qguiapplication_create();
|
||||
}
|
||||
|
||||
~this()
|
||||
{
|
||||
dos_qguiapplication_delete();
|
||||
}
|
||||
|
||||
void exec()
|
||||
{
|
||||
dos_qguiapplication_exec();
|
||||
}
|
||||
|
||||
void quit()
|
||||
{
|
||||
dos_qguiapplication_quit();
|
||||
}
|
||||
}
|
|
@ -1,42 +0,0 @@
|
|||
import dothersideinterface;
|
||||
import qvariant;
|
||||
import std.string;
|
||||
|
||||
class QHashIntByteArray
|
||||
{
|
||||
this()
|
||||
{
|
||||
dos_qhash_int_qbytearray_create(this.vptr);
|
||||
}
|
||||
|
||||
this(void* vptr)
|
||||
{
|
||||
this.vptr = vptr;
|
||||
}
|
||||
|
||||
~this()
|
||||
{
|
||||
dos_qhash_int_qbytearray_delete(this.vptr);
|
||||
}
|
||||
|
||||
public void* voidPointer()
|
||||
{
|
||||
return vptr;
|
||||
}
|
||||
|
||||
public void insert(int key, string value)
|
||||
{
|
||||
dos_qhash_int_qbytearray_insert(this.vptr, key, value.toStringz());
|
||||
}
|
||||
|
||||
public string value(int key)
|
||||
{
|
||||
char* array;
|
||||
dos_qhash_int_qbytearray_value(this.vptr, key, array);
|
||||
string result = fromStringz(array).dup;
|
||||
dos_chararray_delete(array);
|
||||
return result;
|
||||
}
|
||||
|
||||
private void* vptr;
|
||||
}
|
|
@ -1,42 +0,0 @@
|
|||
import qobject;
|
||||
import qvariant;
|
||||
|
||||
/*
|
||||
enum Type {
|
||||
UnknownType = 0, Bool = 1, Int = 2, UInt = 3, LongLong = 4, ULongLong = 5,
|
||||
Double = 6, Long = 32, Short = 33, Char = 34, ULong = 35, UShort = 36,
|
||||
UChar = 37, Float = 38,
|
||||
VoidStar = 31,
|
||||
QChar = 7, QString = 10, QStringList = 11, QByteArray = 12,
|
||||
QBitArray = 13, QDate = 14, QTime = 15, QDateTime = 16, QUrl = 17,
|
||||
QLocale = 18, QRect = 19, QRectF = 20, QSize = 21, QSizeF = 22,
|
||||
QLine = 23, QLineF = 24, QPoint = 25, QPointF = 26, QRegExp = 27,
|
||||
QEasingCurve = 29, QUuid = 30, QVariant = 41, QModelIndex = 42,
|
||||
QRegularExpression = 44,
|
||||
QJsonValue = 45, QJsonObject = 46, QJsonArray = 47, QJsonDocument = 48,
|
||||
QObjectStar = 39, SChar = 40,
|
||||
Void = 43,
|
||||
QVariantMap = 8, QVariantList = 9, QVariantHash = 28,
|
||||
QFont = 64, QPixmap = 65, QBrush = 66, QColor = 67, QPalette = 68,
|
||||
QIcon = 69, QImage = 70, QPolygon = 71, QRegion = 72, QBitmap = 73,
|
||||
QCursor = 74, QKeySequence = 75, QPen = 76, QTextLength = 77, QTextFormat = 78,
|
||||
QMatrix = 79, QTransform = 80, QMatrix4x4 = 81, QVector2D = 82,
|
||||
QVector3D = 83, QVector4D = 84, QQuaternion = 85, QPolygonF = 86,
|
||||
QSizePolicy = 121,
|
||||
User = 1024
|
||||
};
|
||||
*/
|
||||
|
||||
public enum QMetaType
|
||||
{
|
||||
Unknown = 0,
|
||||
Bool = 1,
|
||||
Int = 2,
|
||||
Double = 6,
|
||||
String = 10,
|
||||
VoidStr = 31,
|
||||
Float = 38,
|
||||
QObject = 39,
|
||||
QVariant = 41,
|
||||
Void = 43
|
||||
}
|
|
@ -1,77 +0,0 @@
|
|||
import dothersideinterface;
|
||||
import qvariant;
|
||||
|
||||
class QModelIndex
|
||||
{
|
||||
this()
|
||||
{
|
||||
dos_qmodelindex_create(this.ptr);
|
||||
}
|
||||
|
||||
this(void* ptr)
|
||||
{
|
||||
this.ptr = ptr;
|
||||
}
|
||||
|
||||
~this()
|
||||
{
|
||||
dos_qmodelindex_delete(this.ptr);
|
||||
ptr = null;
|
||||
}
|
||||
|
||||
public void* voidPointer()
|
||||
{
|
||||
return this.ptr;
|
||||
}
|
||||
|
||||
public int row()
|
||||
{
|
||||
int result = -1;
|
||||
dos_qmodelindex_row(this.ptr, result);
|
||||
return result;
|
||||
}
|
||||
|
||||
public int column()
|
||||
{
|
||||
int result = -1;
|
||||
dos_qmodelindex_column(this.ptr, result);
|
||||
return result;
|
||||
}
|
||||
|
||||
public bool isValid()
|
||||
{
|
||||
bool result = false;
|
||||
dos_qmodelindex_isValid(this.ptr, result);
|
||||
return result;
|
||||
}
|
||||
|
||||
public QVariant data(int role)
|
||||
{
|
||||
auto result = new QVariant();
|
||||
dos_qmodelindex_data(this.ptr, role, result.voidPointer());
|
||||
return result;
|
||||
}
|
||||
|
||||
public QModelIndex parent()
|
||||
{
|
||||
auto result = new QModelIndex();
|
||||
dos_qmodelindex_parent(this.ptr, result.ptr);
|
||||
return result;
|
||||
}
|
||||
|
||||
public QModelIndex child(int row, int column)
|
||||
{
|
||||
auto result = new QModelIndex();
|
||||
dos_qmodelindex_child(this.ptr, row, column, result.ptr);
|
||||
return result;
|
||||
}
|
||||
|
||||
public QModelIndex sibling(int row, int column)
|
||||
{
|
||||
auto result = new QModelIndex();
|
||||
dos_qmodelindex_sibling(this.ptr, row, column, result.ptr);
|
||||
return result;
|
||||
}
|
||||
|
||||
private void* ptr;
|
||||
}
|
129
D/DQml/qobject.d
129
D/DQml/qobject.d
|
@ -1,129 +0,0 @@
|
|||
import std.stdio;
|
||||
import std.format;
|
||||
import std.conv;
|
||||
import std.container;
|
||||
import std.traits;
|
||||
import std.string;
|
||||
import std.algorithm;
|
||||
import dothersideinterface;
|
||||
import qmetatype;
|
||||
import qvariant;
|
||||
|
||||
public class QObject
|
||||
{
|
||||
public this()
|
||||
{
|
||||
this(false);
|
||||
}
|
||||
|
||||
protected this(bool disableDosCalls)
|
||||
{
|
||||
this.disableDosCalls = disableDosCalls;
|
||||
if (!this.disableDosCalls)
|
||||
{
|
||||
dos_qobject_create(this.vptr, cast(void*)this, &staticSlotCallback);
|
||||
qobjectInit();
|
||||
}
|
||||
}
|
||||
|
||||
~this()
|
||||
{
|
||||
if (!this.disableDosCalls)
|
||||
{
|
||||
dos_qobject_delete(this.vptr);
|
||||
this.vptr = null;
|
||||
}
|
||||
}
|
||||
|
||||
public void* voidPointer()
|
||||
{
|
||||
return this.vptr;
|
||||
}
|
||||
|
||||
protected void qobjectInit()
|
||||
{}
|
||||
|
||||
protected void onSlotCalled(QVariant slotName, QVariant[] parameters)
|
||||
{
|
||||
}
|
||||
|
||||
protected void registerSlot(string name, QMetaType[] types)
|
||||
{
|
||||
int index = -1;
|
||||
int length = cast(int)types.length;
|
||||
int[] array = to!(int[])(types);
|
||||
dos_qobject_slot_create(this.vptr,
|
||||
name.toStringz(),
|
||||
length,
|
||||
array.ptr,
|
||||
index);
|
||||
}
|
||||
|
||||
protected void registerSignal(string name, QMetaType[] types)
|
||||
{
|
||||
int index = -1;
|
||||
int length = cast(int)types.length;
|
||||
int[] array = length > 0 ? to!(int[])(types) : null;
|
||||
dos_qobject_signal_create(this.vptr,
|
||||
name.toStringz(),
|
||||
length,
|
||||
array.ptr,
|
||||
index);
|
||||
}
|
||||
|
||||
protected void registerProperty(string name,
|
||||
QMetaType type,
|
||||
string readSlotName,
|
||||
string writeSlotName,
|
||||
string notifySignalName)
|
||||
{
|
||||
dos_qobject_property_create(this.vptr,
|
||||
name.toStringz(),
|
||||
type,
|
||||
readSlotName.toStringz(),
|
||||
writeSlotName.toStringz(),
|
||||
notifySignalName.toStringz());
|
||||
}
|
||||
|
||||
protected void emit(T)(string signalName, T t)
|
||||
{
|
||||
emit(signalName, new QVariant(t));
|
||||
}
|
||||
|
||||
protected void emit(string signalName, QVariant value)
|
||||
{
|
||||
QVariant[] array = [value];
|
||||
emit(signalName, array);
|
||||
}
|
||||
|
||||
protected void emit(string signalName, QVariant[] arguments = null)
|
||||
{
|
||||
int length = cast(int)arguments.length;
|
||||
void*[] array = null;
|
||||
if (length > 0) {
|
||||
array = new void*[length];
|
||||
foreach (int i, QVariant v; arguments)
|
||||
array[i] = v.voidPointer();
|
||||
}
|
||||
dos_qobject_signal_emit(this.vptr,
|
||||
signalName.toStringz(),
|
||||
length,
|
||||
array.ptr);
|
||||
}
|
||||
|
||||
protected extern (C) static void staticSlotCallback(void* qObjectPtr,
|
||||
void* rawSlotName,
|
||||
int numParameters,
|
||||
void** parametersArray)
|
||||
{
|
||||
QVariant[] parameters = new QVariant[numParameters];
|
||||
for (int i = 0; i < numParameters; ++i)
|
||||
parameters[i] = new QVariant(parametersArray[i]);
|
||||
QObject qObject = cast(QObject) qObjectPtr;
|
||||
QVariant slotName = new QVariant(rawSlotName);
|
||||
qObject.onSlotCalled(slotName, parameters);
|
||||
}
|
||||
|
||||
protected void* vptr;
|
||||
protected bool disableDosCalls;
|
||||
}
|
|
@ -1,265 +0,0 @@
|
|||
import std.traits;
|
||||
import std.algorithm;
|
||||
import std.string;
|
||||
import std.stdio;
|
||||
|
||||
struct QtProperty
|
||||
{
|
||||
public string type;
|
||||
public string name;
|
||||
public string read;
|
||||
public string write;
|
||||
public string notify;
|
||||
|
||||
this(string type, string name, string read, string write, string notify)
|
||||
{
|
||||
this.type = type;
|
||||
this.name = name;
|
||||
this.read = read;
|
||||
this.write = write;
|
||||
this.notify = notify;
|
||||
}
|
||||
}
|
||||
struct QtSlot {};
|
||||
struct QtSignal {};
|
||||
|
||||
|
||||
string GenerateVariantConversionCall(string typeName)
|
||||
{
|
||||
switch (typeName)
|
||||
{
|
||||
case "string":
|
||||
return ".toString()";
|
||||
case "int":
|
||||
return ".toInt()";
|
||||
case "bool":
|
||||
return ".toBool()";
|
||||
case "float":
|
||||
return ".toFloat()";
|
||||
case "double":
|
||||
return ".toDouble()";
|
||||
case "QVariant":
|
||||
return "";
|
||||
default:
|
||||
throw new Exception("Unknown conversion function from Qvariant to " ~ typeName);
|
||||
}
|
||||
}
|
||||
|
||||
string GenerateArgumentList(string[] typeNames)
|
||||
{
|
||||
string result = "";
|
||||
for (int i = 0; i < typeNames.length; ++i)
|
||||
{
|
||||
auto typeName = typeNames[i];
|
||||
auto variantCall = GenerateVariantConversionCall(typeName);
|
||||
result ~= i > 0 ? "," : "";
|
||||
result ~= format("arguments[%d]%s", i+1, variantCall);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
string GenerateSlotCall(FunctionInfo info)
|
||||
{
|
||||
auto args = GenerateArgumentList(info.parameterTypes);
|
||||
auto call = format("%s(%s)", info.name, args);
|
||||
auto formatStr = info.returnType != "void" ? "arguments[0].setValue(%s)" : "%s";
|
||||
return format(formatStr, call);
|
||||
}
|
||||
|
||||
string GenerateCaseBlock(FunctionInfo info)
|
||||
{
|
||||
string result = "";
|
||||
result ~= format("case \"%s\":\n", info.name);
|
||||
result ~= format("%s;\n", GenerateSlotCall(info));
|
||||
result ~= "break;\n";
|
||||
return result;
|
||||
}
|
||||
|
||||
string GenerateOnSlotCalled(QtInfo info)
|
||||
{
|
||||
string result = "protected override void onSlotCalled(QVariant slotName, QVariant[] arguments)\n";
|
||||
result ~= "{\n";
|
||||
result ~= "switch(slotName.toString())\n";
|
||||
result ~= "{\n";
|
||||
foreach (slot; info.slots)
|
||||
result ~= GenerateCaseBlock(slot);
|
||||
result ~= "default: super.onSlotCalled(slotName, arguments);\n";
|
||||
result ~= "}\n"; //
|
||||
result ~= "}";
|
||||
return result;
|
||||
}
|
||||
|
||||
string GenerateSignalCall(FunctionInfo info)
|
||||
{
|
||||
string args = "";
|
||||
string vars = "";
|
||||
for (int i = 0; i < info.parameterTypes.length; ++i) {
|
||||
if (i > 0) {
|
||||
args ~= ",";
|
||||
vars ~= ",";
|
||||
}
|
||||
args ~= format("%s val%d", info.parameterTypes[i], i);
|
||||
vars ~= format("val%d", i);
|
||||
}
|
||||
|
||||
auto result = format("public %s %s(%s) { emit(\"%s\", %s); }", info.returnType, info.name, args, info.name, vars);
|
||||
return result;
|
||||
}
|
||||
|
||||
string GenerateQtSignals(QtInfo info)
|
||||
{
|
||||
string result = "";
|
||||
foreach (signal; info.signals)
|
||||
result ~= GenerateSignalCall(signal) ~ "\n";
|
||||
return result;
|
||||
}
|
||||
|
||||
string GenerateMetaType(string typeName)
|
||||
{
|
||||
switch(typeName)
|
||||
{
|
||||
case "void":
|
||||
return "QMetaType.Void";
|
||||
case "int":
|
||||
return "QMetaType.Int";
|
||||
case "string":
|
||||
return "QMetaType.String";
|
||||
case "QObject":
|
||||
return "QMetaType.QObject";
|
||||
case "QVariant":
|
||||
return "QMetaType.QVariant";
|
||||
case "bool":
|
||||
return "QMetaType.Bool";
|
||||
case "float":
|
||||
return "QMetaType.Float";
|
||||
case "double":
|
||||
return "QMetaType.Double";
|
||||
default:
|
||||
throw new Exception(format("Unknown conversion from %s to QMetaType", typeName));
|
||||
}
|
||||
}
|
||||
|
||||
string GenerateMetaTypesListForSlot(FunctionInfo info)
|
||||
{
|
||||
string result = GenerateMetaType(info.returnType);
|
||||
result ~= ", ";
|
||||
result ~= GenerateMetaTypesListForSignal(info);
|
||||
return result;
|
||||
}
|
||||
|
||||
string GenerateMetaTypesListForSignal(FunctionInfo info)
|
||||
{
|
||||
string result = "";
|
||||
for (int i = 0; i < info.parameterTypes.length; ++i)
|
||||
{
|
||||
if (i > 0)
|
||||
result ~= ", ";
|
||||
result ~= GenerateMetaType(info.parameterTypes[i]);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
string GenerateQObjectInit(QtInfo info)
|
||||
{
|
||||
string result = "";
|
||||
result ~= "protected override void qobjectInit()\n";
|
||||
result ~= "{\n";
|
||||
foreach (slot; info.slots)
|
||||
{
|
||||
auto metaTypes = GenerateMetaTypesListForSlot(slot);
|
||||
result ~= format("registerSlot(\"%s\", [%s]);\n", slot.name, metaTypes);
|
||||
}
|
||||
|
||||
foreach (signal; info.signals)
|
||||
{
|
||||
auto metaTypes = GenerateMetaTypesListForSignal(signal);
|
||||
result ~= format("registerSignal(\"%s\", [%s]);\n", signal.name, metaTypes);
|
||||
}
|
||||
|
||||
foreach (property; info.properties)
|
||||
{
|
||||
result ~= format("registerProperty(\"%s\", %s, \"%s\", \"%s\", \"%s\");\n", property.name, GenerateMetaType(property.type), property.read, property.write, property.notify);
|
||||
}
|
||||
|
||||
result ~= "super.qobjectInit();\n";
|
||||
|
||||
result ~= "}";
|
||||
return result;
|
||||
}
|
||||
|
||||
struct FunctionInfo
|
||||
{
|
||||
string name;
|
||||
string returnType;
|
||||
string[] parameterTypes;
|
||||
}
|
||||
|
||||
struct QtInfo
|
||||
{
|
||||
FunctionInfo[] slots;
|
||||
FunctionInfo[] signals;
|
||||
QtProperty[] properties;
|
||||
}
|
||||
|
||||
mixin template InjectQObjectMacro()
|
||||
{
|
||||
private static QtInfo GetQtUDA(T)()
|
||||
{
|
||||
QtInfo result;
|
||||
|
||||
foreach (attribute; __traits(getAttributes, T)) {
|
||||
static if (is (typeof(attribute) == QtProperty)) {
|
||||
result.properties ~= attribute;
|
||||
}
|
||||
}
|
||||
|
||||
foreach (member; __traits(allMembers, T))
|
||||
{
|
||||
static if (__traits(compiles, __traits(getMember, T, member))
|
||||
&& isSomeFunction!(__traits(getMember, T, member)))
|
||||
{
|
||||
// Retrieve the UDA
|
||||
auto attributes = __traits(getAttributes, __traits(getMember, T, member));
|
||||
|
||||
// Turn the tuple in an array of strings
|
||||
string[] attributeNames;
|
||||
foreach (attribute; attributes)
|
||||
attributeNames ~= typeof(attribute).stringof;
|
||||
|
||||
bool isSlot = attributeNames.canFind("QtSlot");
|
||||
bool isSignal = attributeNames.canFind("QtSignal");
|
||||
|
||||
// Extract the Function Return Type and Arguments
|
||||
if (isSlot || isSignal)
|
||||
{
|
||||
FunctionInfo info;
|
||||
info.name = member;
|
||||
info.returnType = ReturnType!(__traits(getMember, T, member)).stringof;
|
||||
|
||||
foreach (param; ParameterTypeTuple!(__traits(getMember, T, member)))
|
||||
info.parameterTypes ~= param.stringof;
|
||||
|
||||
if (isSlot)
|
||||
result.slots ~= info;
|
||||
|
||||
if (isSignal)
|
||||
result.signals ~= info;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private static string Q_OBJECT(T)()
|
||||
{
|
||||
string result = "";
|
||||
auto info = T.GetQtUDA!(T);
|
||||
result ~= GenerateOnSlotCalled(info) ~ "\n";
|
||||
result ~= GenerateQObjectInit(info) ~ "\n";
|
||||
result ~= GenerateQtSignals(info) ~ "\n";
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1,35 +0,0 @@
|
|||
import dothersideinterface;
|
||||
import qqmlcontext;
|
||||
import std.string;
|
||||
|
||||
class QQmlApplicationEngine
|
||||
{
|
||||
this()
|
||||
{
|
||||
dos_qqmlapplicationengine_create(this.vptr);
|
||||
}
|
||||
|
||||
~this()
|
||||
{
|
||||
dos_qqmlapplicationengine_delete(this.vptr);
|
||||
}
|
||||
|
||||
public void* voidPointer()
|
||||
{
|
||||
return this.vptr;
|
||||
}
|
||||
|
||||
public QQmlContext rootContext()
|
||||
{
|
||||
void* contextVPtr;
|
||||
dos_qqmlapplicationengine_context(this.vptr, contextVPtr);
|
||||
return new QQmlContext(contextVPtr);
|
||||
}
|
||||
|
||||
public void load(string filename)
|
||||
{
|
||||
dos_qqmlapplicationengine_load(this.vptr, filename.toStringz());
|
||||
}
|
||||
|
||||
private void* vptr;
|
||||
}
|
|
@ -1,32 +0,0 @@
|
|||
import dothersideinterface;
|
||||
import qvariant;
|
||||
import std.string;
|
||||
|
||||
class QQmlContext
|
||||
{
|
||||
this(void* vptr)
|
||||
{
|
||||
this.vptr = vptr;
|
||||
}
|
||||
|
||||
public void* voidPointer()
|
||||
{
|
||||
return vptr;
|
||||
}
|
||||
|
||||
public string baseUrl()
|
||||
{
|
||||
char* array;
|
||||
dos_qqmlcontext_baseUrl(this.vptr, array);
|
||||
string result = fromStringz(array).dup;
|
||||
dos_chararray_delete(array);
|
||||
return result;
|
||||
}
|
||||
|
||||
public void setContextProperty(string name, QVariant value)
|
||||
{
|
||||
dos_qqmlcontext_setcontextproperty(this.vptr, name.ptr, value.voidPointer());
|
||||
}
|
||||
|
||||
private void* vptr;
|
||||
}
|
|
@ -1,50 +0,0 @@
|
|||
import dothersideinterface;
|
||||
import qqmlcontext;
|
||||
import std.string;
|
||||
|
||||
class QQuickView
|
||||
{
|
||||
this()
|
||||
{
|
||||
dos_qquickview_create(this.vptr);
|
||||
}
|
||||
|
||||
~this()
|
||||
{
|
||||
dos_qquickview_delete(this.vptr);
|
||||
}
|
||||
|
||||
public void* voidPointer()
|
||||
{
|
||||
return this.vptr;
|
||||
}
|
||||
|
||||
public void show()
|
||||
{
|
||||
dos_qquickview_show(this.vptr);
|
||||
}
|
||||
|
||||
public QQmlContext rootContext()
|
||||
{
|
||||
void* contextData;
|
||||
dos_qquickview_rootContext(this.vptr, contextData);
|
||||
return new QQmlContext(contextData);
|
||||
}
|
||||
|
||||
public string source()
|
||||
{
|
||||
char* array;
|
||||
dos_qquickview_source(this.vptr, array);
|
||||
string result = fromStringz(array).dup;
|
||||
dos_chararray_delete(array);
|
||||
return result;
|
||||
}
|
||||
|
||||
public void setSource(string filename)
|
||||
{
|
||||
immutable(char)* filenameAsCString = filename.toStringz();
|
||||
dos_qquickview_set_source(this.vptr, filenameAsCString);
|
||||
}
|
||||
|
||||
private void* vptr;
|
||||
}
|
|
@ -1,160 +0,0 @@
|
|||
import dothersideinterface;
|
||||
import qobject;
|
||||
import std.string;
|
||||
|
||||
class QVariant
|
||||
{
|
||||
public this()
|
||||
{
|
||||
dos_qvariant_create(this.vptr);
|
||||
}
|
||||
|
||||
public this(int value)
|
||||
{
|
||||
dos_qvariant_create_int(this.vptr, value);
|
||||
}
|
||||
|
||||
public this(bool value)
|
||||
{
|
||||
dos_qvariant_create_bool(this.vptr, value);
|
||||
}
|
||||
|
||||
public this(string value)
|
||||
{
|
||||
dos_qvariant_create_string(this.vptr, value.toStringz());
|
||||
}
|
||||
|
||||
public this(float value)
|
||||
{
|
||||
dos_qvariant_create_float(this.vptr, value);
|
||||
}
|
||||
|
||||
public this(double value)
|
||||
{
|
||||
dos_qvariant_create_double(this.vptr, value);
|
||||
}
|
||||
|
||||
public this(QObject value)
|
||||
{
|
||||
dos_qvariant_create_qobject(this.vptr, value.voidPointer());
|
||||
}
|
||||
|
||||
public this(void* vptr, bool hasOwnership = false)
|
||||
{
|
||||
this.vptr = vptr;
|
||||
this.hasOwnership = hasOwnership;
|
||||
}
|
||||
|
||||
~this()
|
||||
{
|
||||
if (this.hasOwnership)
|
||||
dos_qvariant_delete(this.vptr);
|
||||
}
|
||||
|
||||
public void* voidPointer()
|
||||
{
|
||||
return this.vptr;
|
||||
}
|
||||
|
||||
public void setValue(int value)
|
||||
{
|
||||
dos_qvariant_setInt(this.vptr, value);
|
||||
}
|
||||
|
||||
public void setValue(bool value)
|
||||
{
|
||||
dos_qvariant_setBool(this.vptr, value);
|
||||
}
|
||||
|
||||
public void setValue(string value)
|
||||
{
|
||||
dos_qvariant_setString(this.vptr, value.toStringz());
|
||||
}
|
||||
|
||||
public void setValue(QObject value)
|
||||
{
|
||||
dos_qvariant_setQObject(this.vptr, value.voidPointer());
|
||||
}
|
||||
|
||||
public void setValue(float value)
|
||||
{
|
||||
dos_qvariant_setFloat(this.vptr, value);
|
||||
}
|
||||
|
||||
public void setValue(double value)
|
||||
{
|
||||
dos_qvariant_setDouble(this.vptr, value);
|
||||
}
|
||||
|
||||
public void getValue(ref int value)
|
||||
{
|
||||
value = toInt();
|
||||
}
|
||||
|
||||
public void getValue(ref bool value)
|
||||
{
|
||||
value = toBool();
|
||||
}
|
||||
|
||||
public void getValue(ref string value)
|
||||
{
|
||||
value = toString();
|
||||
}
|
||||
|
||||
public void getValue(ref float value)
|
||||
{
|
||||
value = toFloat();
|
||||
}
|
||||
|
||||
public void getValue(ref double value)
|
||||
{
|
||||
value = toDouble();
|
||||
}
|
||||
|
||||
public bool isNull()
|
||||
{
|
||||
bool result;
|
||||
dos_qvariant_isnull(this.vptr, result);
|
||||
return result;
|
||||
}
|
||||
|
||||
public bool toBool()
|
||||
{
|
||||
bool result;
|
||||
dos_qvariant_toBool(this.vptr, result);
|
||||
return result;
|
||||
}
|
||||
|
||||
public int toInt()
|
||||
{
|
||||
int result;
|
||||
dos_qvariant_toInt(this.vptr, result);
|
||||
return result;
|
||||
}
|
||||
|
||||
public float toFloat()
|
||||
{
|
||||
float result;
|
||||
dos_qvariant_toFloat(this.vptr, result);
|
||||
return result;
|
||||
}
|
||||
|
||||
public double toDouble()
|
||||
{
|
||||
double result;
|
||||
dos_qvariant_toDouble(this.vptr, result);
|
||||
return result;
|
||||
}
|
||||
|
||||
public override string toString()
|
||||
{
|
||||
char* array;
|
||||
dos_qvariant_toString(this.vptr, array);
|
||||
string result = fromStringz(array).dup;
|
||||
dos_chararray_delete(array);
|
||||
return result;
|
||||
}
|
||||
|
||||
private void* vptr = null;
|
||||
private bool hasOwnership = true;
|
||||
}
|
|
@ -1,11 +0,0 @@
|
|||
cmake_minimum_required(VERSION 3.0)
|
||||
project (DQmlAbstractItemModel C D )
|
||||
add_executable(${PROJECT_NAME} main.d model.d)
|
||||
target_include_directories(${PROJECT_NAME} PUBLIC
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/../../DQml"
|
||||
${CMAKE_CURRENT_SOURCE_DIR})
|
||||
target_link_libraries(${PROJECT_NAME} PRIVATE
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/../../../DOtherSide/libDOtherSide.so"
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/../../DQml/libDQml.a"
|
||||
)
|
||||
file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/main.qml DESTINATION ${CMAKE_CURRENT_BINARY_DIR})
|
|
@ -1,26 +0,0 @@
|
|||
import dqml;
|
||||
import model;
|
||||
|
||||
void main()
|
||||
{
|
||||
try
|
||||
{
|
||||
auto app = new QGuiApplication();
|
||||
scope(exit) destroy(app);
|
||||
|
||||
auto model = new ListModel();
|
||||
scope(exit) destroy(model);
|
||||
|
||||
auto variant = new QVariant();
|
||||
variant.setValue(model);
|
||||
|
||||
auto engine = new QQmlApplicationEngine();
|
||||
scope(exit) destroy(engine);
|
||||
|
||||
engine.rootContext().setContextProperty("myListModel", variant);
|
||||
engine.load("main.qml");
|
||||
app.exec();
|
||||
}
|
||||
catch
|
||||
{}
|
||||
}
|
|
@ -1,25 +0,0 @@
|
|||
import QtQuick 2.2
|
||||
import QtQuick.Controls 1.2
|
||||
import QtQuick.Layouts 1.1
|
||||
import QtQuick.Window 2.1
|
||||
|
||||
ApplicationWindow
|
||||
{
|
||||
width: 400
|
||||
height: 300
|
||||
title: "AbstractItemModel"
|
||||
Component.onCompleted: visible = true
|
||||
|
||||
Component
|
||||
{
|
||||
id: myListModelDelegate
|
||||
Label { text: "Name:" + name }
|
||||
}
|
||||
|
||||
ListView
|
||||
{
|
||||
anchors.fill: parent
|
||||
model: myListModel
|
||||
delegate: myListModelDelegate
|
||||
}
|
||||
}
|
|
@ -1,48 +0,0 @@
|
|||
import dqml;
|
||||
import std.stdio;
|
||||
|
||||
|
||||
class ListModel : QAbstractListModel
|
||||
{
|
||||
this()
|
||||
{
|
||||
this.names = ["John", "Max", "Paul", "Anna"];
|
||||
this.roles[Roles.Name] = "name";
|
||||
}
|
||||
|
||||
public override int rowCount(QModelIndex parent = null)
|
||||
{
|
||||
if (parent && parent.isValid())
|
||||
return 0;
|
||||
return cast(int)(names.length);
|
||||
}
|
||||
|
||||
public override QVariant data(QModelIndex index, int role)
|
||||
{
|
||||
if (index is null)
|
||||
return null;
|
||||
|
||||
if (!index.isValid())
|
||||
return null;
|
||||
|
||||
if (index.row() < 0 || index.row() >= rowCount())
|
||||
return null;
|
||||
|
||||
switch(role)
|
||||
{
|
||||
case Roles.Name:
|
||||
return new QVariant(names[index.row]);
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public override string[int] roleNames()
|
||||
{
|
||||
return roles;
|
||||
}
|
||||
|
||||
private string[] names;
|
||||
private string[int] roles;
|
||||
private enum Roles : int { Name = 0 };
|
||||
}
|
|
@ -1,5 +0,0 @@
|
|||
add_subdirectory(HelloWorld)
|
||||
add_subdirectory(SimpleData)
|
||||
add_subdirectory(SlotsAndProperties)
|
||||
add_subdirectory(AbstractItemModel)
|
||||
add_subdirectory(ContactApp)
|
|
@ -1,11 +0,0 @@
|
|||
cmake_minimum_required(VERSION 3.0)
|
||||
project (DQmlContactApp C D )
|
||||
add_executable(${PROJECT_NAME} main.d applicationlogic.d contact.d contactlist.d)
|
||||
target_include_directories(${PROJECT_NAME} PUBLIC
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/../../DQml"
|
||||
${CMAKE_CURRENT_SOURCE_DIR})
|
||||
target_link_libraries(${PROJECT_NAME} PRIVATE
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/../../../DOtherSide/libDOtherSide.so"
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/../../DQml/libDQml.a"
|
||||
)
|
||||
file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/main.qml DESTINATION ${CMAKE_CURRENT_BINARY_DIR})
|
|
@ -1,44 +0,0 @@
|
|||
import dqml;
|
||||
import contactlist;
|
||||
import std.stdio;
|
||||
|
||||
@QtProperty(QObject.stringof, "contactList", "contactList", null, null)
|
||||
class ApplicationLogic : QObject
|
||||
{
|
||||
mixin InjectQObjectMacro;
|
||||
mixin(Q_OBJECT!(ApplicationLogic));
|
||||
|
||||
this(QApplication app)
|
||||
{
|
||||
this.m_app = app;
|
||||
this.m_contactList = new ContactList();
|
||||
}
|
||||
|
||||
|
||||
@QtSlot()
|
||||
public QObject contactList()
|
||||
{
|
||||
return this.m_contactList;
|
||||
}
|
||||
|
||||
@QtSlot()
|
||||
public void onLoadTriggered()
|
||||
{
|
||||
writefln("Load Triggered");
|
||||
}
|
||||
|
||||
@QtSlot()
|
||||
public void onSaveTriggered()
|
||||
{
|
||||
writefln("Save Triggered");
|
||||
}
|
||||
|
||||
@QtSlot()
|
||||
public void onExitTriggered()
|
||||
{
|
||||
this.m_app.quit();
|
||||
}
|
||||
|
||||
private QApplication m_app;
|
||||
private ContactList m_contactList;
|
||||
}
|
|
@ -1,56 +0,0 @@
|
|||
import dqml;
|
||||
|
||||
@QtProperty(string.stringof, "firstName", "firstName", "setFirstName", "firstNameChanged")
|
||||
@QtProperty(string.stringof, "lastName", "lastName", "setLastName", "lastNameChanged")
|
||||
class Contact : QObject
|
||||
{
|
||||
mixin InjectQObjectMacro;
|
||||
mixin(Q_OBJECT!(Contact));
|
||||
|
||||
this(string firstName = "", string lastName = "")
|
||||
{
|
||||
this.m_firstName = firstName;
|
||||
this.m_lastName = lastName;
|
||||
}
|
||||
|
||||
@QtSlot()
|
||||
public string firstName()
|
||||
{
|
||||
return this.m_firstName;
|
||||
}
|
||||
|
||||
@QtSlot()
|
||||
public void setFirstName(string firstName)
|
||||
{
|
||||
if (this.m_firstName != firstName)
|
||||
{
|
||||
this.m_firstName = firstName;
|
||||
firstNameChanged(firstName);
|
||||
}
|
||||
}
|
||||
|
||||
@QtSignal()
|
||||
public void firstNameChanged(string);
|
||||
|
||||
@QtSlot()
|
||||
public string lastName()
|
||||
{
|
||||
return this.m_lastName;
|
||||
}
|
||||
|
||||
@QtSlot()
|
||||
public void setLastName(string lastName)
|
||||
{
|
||||
if (this.m_lastName != lastName)
|
||||
{
|
||||
this.m_lastName = lastName;
|
||||
lastNameChanged(lastName);
|
||||
}
|
||||
}
|
||||
|
||||
@QtSignal()
|
||||
public void lastNameChanged(string);
|
||||
|
||||
private string m_firstName;
|
||||
private string m_lastName;
|
||||
}
|
|
@ -1,80 +0,0 @@
|
|||
import dqml;
|
||||
import contact;
|
||||
import std.stdio;
|
||||
import std.algorithm;
|
||||
|
||||
class ContactList : QAbstractListModel
|
||||
{
|
||||
mixin InjectQObjectMacro;
|
||||
mixin(Q_OBJECT!(ContactList));
|
||||
|
||||
this()
|
||||
{
|
||||
this.m_contacts = [];
|
||||
this.m_roleNames[Roles.FirstName] = "firstName";
|
||||
this.m_roleNames[Roles.LastName] = "lastName";
|
||||
}
|
||||
|
||||
public override int rowCount(QModelIndex parent = null)
|
||||
{
|
||||
if (parent && parent.isValid())
|
||||
return 0;
|
||||
return cast(int)(this.m_contacts.length);
|
||||
}
|
||||
|
||||
public override QVariant data(QModelIndex index, int role)
|
||||
{
|
||||
if (index is null)
|
||||
return null;
|
||||
|
||||
if (!index.isValid())
|
||||
return null;
|
||||
|
||||
if (index.row() < 0 || index.row() >= rowCount())
|
||||
return null;
|
||||
|
||||
auto contact = this.m_contacts[index.row];
|
||||
|
||||
switch(role)
|
||||
{
|
||||
case Roles.FirstName:
|
||||
return new QVariant(contact.firstName());
|
||||
case Roles.LastName:
|
||||
return new QVariant(contact.lastName());
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public override string[int] roleNames()
|
||||
{
|
||||
return this.m_roleNames;
|
||||
}
|
||||
|
||||
@QtSlot()
|
||||
public void add(string firstName, string lastName)
|
||||
{
|
||||
auto index = new QModelIndex();
|
||||
auto pos = rowCount();
|
||||
writefln("Adding %s %s in pos %d", firstName, lastName, pos);
|
||||
beginInsertRows(index, pos, pos);
|
||||
this.m_contacts ~= new Contact(firstName, lastName);
|
||||
endInsertRows();
|
||||
}
|
||||
|
||||
@QtSlot()
|
||||
public void del(int pos)
|
||||
{
|
||||
if (pos < 0 || pos >= rowCount())
|
||||
return;
|
||||
auto index = new QModelIndex();
|
||||
writefln("Removing at pos %d", pos);
|
||||
beginRemoveRows(index, pos, pos);
|
||||
this.m_contacts = remove(this.m_contacts, pos);
|
||||
endRemoveRows();
|
||||
}
|
||||
|
||||
private Contact[] m_contacts;
|
||||
private string[int] m_roleNames;
|
||||
private enum Roles : int { FirstName = 0, LastName};
|
||||
}
|
|
@ -1,26 +0,0 @@
|
|||
import dqml;
|
||||
import applicationlogic;
|
||||
|
||||
void main()
|
||||
{
|
||||
try
|
||||
{
|
||||
auto app = new QApplication();
|
||||
scope(exit) destroy(app);
|
||||
|
||||
auto logic = new ApplicationLogic(app);
|
||||
scope(exit) destroy(logic);
|
||||
|
||||
auto variant = new QVariant();
|
||||
variant.setValue(logic);
|
||||
|
||||
auto engine = new QQmlApplicationEngine();
|
||||
scope(exit) destroy(engine);
|
||||
|
||||
engine.rootContext().setContextProperty("logic", variant);
|
||||
engine.load("main.qml");
|
||||
app.exec();
|
||||
}
|
||||
catch
|
||||
{}
|
||||
}
|
|
@ -1,93 +0,0 @@
|
|||
import QtQuick 2.2
|
||||
import QtQuick.Controls 1.2
|
||||
import QtQuick.Layouts 1.1
|
||||
import QtQuick.Window 2.1
|
||||
|
||||
ApplicationWindow {
|
||||
|
||||
width: 500
|
||||
height: 300
|
||||
title: "ContactApp"
|
||||
visible: true
|
||||
|
||||
menuBar: MenuBar {
|
||||
Menu {
|
||||
title: "&File"
|
||||
MenuItem { text: "&Load"; onTriggered: logic.onLoadTriggered() }
|
||||
MenuItem { text: "&Save"; onTriggered: logic.onSaveTriggered() }
|
||||
MenuItem { text: "&Exit"; onTriggered: logic.onExitTriggered() }
|
||||
}
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
anchors.fill: parent
|
||||
|
||||
Component {
|
||||
id: tableTextDelegate
|
||||
Label {
|
||||
id: tableTextDelegateInstance
|
||||
property var styleData: undefined
|
||||
states: State {
|
||||
when: styleData !== undefined
|
||||
PropertyChanges {
|
||||
target: tableTextDelegateInstance;
|
||||
text: styleData.value;
|
||||
color: styleData.textColor
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Component {
|
||||
id: tableButtonDelegate
|
||||
Button {
|
||||
id: tableButtonDelegateInstance
|
||||
property var styleData: undefined
|
||||
text: "Delete"
|
||||
onClicked: logic.contactList.del(styleData.row)
|
||||
}
|
||||
}
|
||||
|
||||
Component {
|
||||
id: tableItemDelegate
|
||||
Loader {
|
||||
id: tableItemDelegateInstance
|
||||
sourceComponent: {
|
||||
if (styleData.column === 0 || styleData.column === 1)
|
||||
return tableTextDelegate
|
||||
else if (styleData.column === 2)
|
||||
return tableButtonDelegate
|
||||
else
|
||||
return tableTextDelegate
|
||||
}
|
||||
Binding {
|
||||
target: tableItemDelegateInstance.item
|
||||
property: "styleData"
|
||||
value: styleData
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TableView {
|
||||
model: logic.contactList
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
TableViewColumn { role: "firstName"; title: "FirstName"; width: 200 }
|
||||
TableViewColumn { role: "lastName"; title: "LastName"; width: 200}
|
||||
TableViewColumn { width: 100; }
|
||||
itemDelegate: tableItemDelegate
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
Label { text: "FirstName" }
|
||||
TextField { id: nameTextField; Layout.fillWidth: true; text: "" }
|
||||
Label { text: "LastName" }
|
||||
TextField { id: surnameTextField; Layout.fillWidth: true; text: "" }
|
||||
Button {
|
||||
text: "Add"
|
||||
onClicked: logic.contactList.add(nameTextField.text, surnameTextField.text)
|
||||
enabled: nameTextField.text !== "" && surnameTextField.text !== ""
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,12 +0,0 @@
|
|||
cmake_minimum_required(VERSION 3.0)
|
||||
project (DQmlHelloWorld C D )
|
||||
add_executable(${PROJECT_NAME} main.d)
|
||||
target_include_directories(${PROJECT_NAME} PUBLIC
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/../../DQml"
|
||||
${CMAKE_CURRENT_SOURCE_DIR})
|
||||
target_link_libraries(${PROJECT_NAME} PRIVATE
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/../../../DOtherSide/libDOtherSide.so"
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/../../DQml/libDQml.a"
|
||||
)
|
||||
file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/main.qml DESTINATION ${CMAKE_CURRENT_BINARY_DIR})
|
||||
|
|
@ -1,19 +0,0 @@
|
|||
import std.stdio;
|
||||
import dqml;
|
||||
|
||||
void main()
|
||||
{
|
||||
try
|
||||
{
|
||||
auto app = new QGuiApplication();
|
||||
scope(exit) destroy(app);
|
||||
|
||||
auto engine = new QQmlApplicationEngine();
|
||||
scope(exit) destroy(engine);
|
||||
engine.load("main.qml");
|
||||
|
||||
app.exec();
|
||||
}
|
||||
catch
|
||||
{}
|
||||
}
|
|
@ -1,12 +0,0 @@
|
|||
import QtQuick 2.2
|
||||
import QtQuick.Controls 1.2
|
||||
import QtQuick.Layouts 1.1
|
||||
import QtQuick.Window 2.1
|
||||
|
||||
ApplicationWindow
|
||||
{
|
||||
width: 400
|
||||
height: 300
|
||||
title: "Hello World"
|
||||
Component.onCompleted: visible = true
|
||||
}
|
|
@ -1,12 +0,0 @@
|
|||
cmake_minimum_required(VERSION 3.0)
|
||||
project (DQmlSimpleData C D )
|
||||
add_executable(${PROJECT_NAME} main.d)
|
||||
target_include_directories(${PROJECT_NAME} PUBLIC
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/../../DQml"
|
||||
${CMAKE_CURRENT_SOURCE_DIR})
|
||||
target_link_libraries(${PROJECT_NAME} PRIVATE
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/../../../DOtherSide/libDOtherSide.so"
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/../../DQml/libDQml.a"
|
||||
)
|
||||
file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/main.qml DESTINATION ${CMAKE_CURRENT_BINARY_DIR})
|
||||
|
|
@ -1,36 +0,0 @@
|
|||
import std.stdio;
|
||||
import dqml;
|
||||
|
||||
void main()
|
||||
{
|
||||
try
|
||||
{
|
||||
auto app = new QGuiApplication();
|
||||
scope(exit) destroy(app);
|
||||
|
||||
auto engine = new QQmlApplicationEngine();
|
||||
scope(exit) destroy(engine);
|
||||
|
||||
auto qVar1 = new QVariant(10);
|
||||
scope(exit) destroy(qVar1);
|
||||
|
||||
auto qVar2 = new QVariant("Hello World");
|
||||
scope(exit) destroy(qVar1);
|
||||
|
||||
auto qVar3 = new QVariant(false);
|
||||
scope(exit) destroy(qVar1);
|
||||
|
||||
auto qVar4 = new QVariant(3.5f);
|
||||
scope(exit) destroy(qVar1);
|
||||
|
||||
engine.rootContext().setContextProperty("qVar1", qVar1);
|
||||
engine.rootContext().setContextProperty("qVar2", qVar2);
|
||||
engine.rootContext().setContextProperty("qVar3", qVar3);
|
||||
engine.rootContext().setContextProperty("qVar4", qVar4);
|
||||
engine.load("main.qml");
|
||||
|
||||
app.exec();
|
||||
}
|
||||
catch
|
||||
{}
|
||||
}
|
|
@ -1,21 +0,0 @@
|
|||
import QtQuick 2.2
|
||||
import QtQuick.Controls 1.2
|
||||
import QtQuick.Layouts 1.1
|
||||
import QtQuick.Window 2.1
|
||||
|
||||
ApplicationWindow
|
||||
{
|
||||
width: 400
|
||||
height: 300
|
||||
title: "SimpleData"
|
||||
Component.onCompleted: visible = true
|
||||
|
||||
ColumnLayout
|
||||
{
|
||||
anchors.fill: parent
|
||||
SpinBox { value: qVar1}
|
||||
TextField { text: qVar2}
|
||||
CheckBox { checked: qVar3}
|
||||
SpinBox { value: qVar4; decimals: 1 }
|
||||
}
|
||||
}
|
|
@ -1,12 +0,0 @@
|
|||
cmake_minimum_required(VERSION 3.0)
|
||||
project (DQmlSlotsAndProperties C D )
|
||||
add_executable(${PROJECT_NAME} main.d contact.d)
|
||||
target_include_directories(${PROJECT_NAME} PUBLIC
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/../../DQml"
|
||||
${CMAKE_CURRENT_SOURCE_DIR})
|
||||
target_link_libraries(${PROJECT_NAME} PRIVATE
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/../../../DOtherSide/libDOtherSide.so"
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/../../DQml/libDQml.a"
|
||||
)
|
||||
file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/main.qml DESTINATION ${CMAKE_CURRENT_BINARY_DIR})
|
||||
|
|
@ -1,52 +0,0 @@
|
|||
import dqml;
|
||||
|
||||
@QtProperty(string.stringof, "name", "getName", "setName", "nameChanged")
|
||||
@QtProperty(string.stringof, "surname", "getSurname", "setSurname", "surnameChanged")
|
||||
class Contact : QObject
|
||||
{
|
||||
mixin InjectQObjectMacro;
|
||||
mixin(Q_OBJECT!(Contact));
|
||||
|
||||
this()
|
||||
{}
|
||||
|
||||
~this()
|
||||
{}
|
||||
|
||||
@QtSlot()
|
||||
public string getName()
|
||||
{
|
||||
return m_name;
|
||||
}
|
||||
|
||||
@QtSlot()
|
||||
public void setName(string name)
|
||||
{
|
||||
if (m_name != name)
|
||||
{
|
||||
m_name = name;
|
||||
emit("nameChanged", name);
|
||||
}
|
||||
}
|
||||
|
||||
@QtSignal()
|
||||
public void nameChanged(string name);
|
||||
|
||||
@QtSlot()
|
||||
public string getSurname()
|
||||
{
|
||||
return m_surname;
|
||||
}
|
||||
|
||||
@QtSlot()
|
||||
public void setSurname(string surname)
|
||||
{
|
||||
m_surname = surname;
|
||||
}
|
||||
|
||||
@QtSignal()
|
||||
void surnameChanged(string surname);
|
||||
|
||||
private string m_name;
|
||||
private string m_surname;
|
||||
}
|
|
@ -1,27 +0,0 @@
|
|||
import std.stdio;
|
||||
import dqml;
|
||||
import contact;
|
||||
|
||||
void main()
|
||||
{
|
||||
try
|
||||
{
|
||||
auto app = new QApplication();
|
||||
scope(exit) destroy(app);
|
||||
|
||||
auto contact = new Contact();
|
||||
scope(exit) destroy(contact);
|
||||
|
||||
auto variant = new QVariant(contact);
|
||||
scope(exit) destroy(variant);
|
||||
|
||||
auto engine = new QQmlApplicationEngine();
|
||||
scope(exit) destroy(engine);
|
||||
|
||||
engine.rootContext().setContextProperty("contact", variant);
|
||||
engine.load("main.qml");
|
||||
app.exec();
|
||||
}
|
||||
catch
|
||||
{}
|
||||
}
|
|
@ -1,24 +0,0 @@
|
|||
import QtQuick 2.2
|
||||
import QtQuick.Controls 1.2
|
||||
import QtQuick.Layouts 1.1
|
||||
import QtQuick.Window 2.1
|
||||
|
||||
ApplicationWindow {
|
||||
width: 400
|
||||
height: 300
|
||||
visible: true
|
||||
|
||||
|
||||
ColumnLayout {
|
||||
anchors.fill: parent
|
||||
|
||||
Label { text: "Current name is:" + contact.name }
|
||||
|
||||
TextField { id: textField }
|
||||
|
||||
Button{
|
||||
text: "Change Name"
|
||||
onClicked: contact.name = textField.text
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,51 +0,0 @@
|
|||
# < 2.8.10 backward compatibility
|
||||
if(NOT CMAKE_PLATFORM_INFO_DIR)
|
||||
set(CMAKE_PLATFORM_INFO_DIR ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY})
|
||||
endif(NOT CMAKE_PLATFORM_INFO_DIR)
|
||||
|
||||
set(CMAKE_D_COMPILER "@CMAKE_D_COMPILER@")
|
||||
set(CMAKE_D_COMPILER_ARG1 "@CMAKE_D_COMPILER_ARG1@")
|
||||
set(CMAKE_D_COMPILER_ID "@CMAKE_D_COMPILER_ID@")
|
||||
set(CMAKE_D_PLATFORM_ID "@CMAKE_D_PLATFORM_ID@")
|
||||
@SET_MSVC_D_ARCHITECTURE_ID@
|
||||
set(CMAKE_AR "@CMAKE_AR@")
|
||||
set(CMAKE_RANLIB "@CMAKE_RANLIB@")
|
||||
set(CMAKE_LINKER "@CMAKE_LINKER@")
|
||||
set(CMAKE_COMPILER_IS_GDC @CMAKE_COMPILER_IS_GDC@)
|
||||
set(CMAKE_COMPILER_IS_DMD @CMAKE_COMPILER_IS_DMD@)
|
||||
set(CMAKE_D_COMPILER_LOADED 1)
|
||||
set(CMAKE_COMPILER_IS_MINGW @CMAKE_COMPILER_IS_MINGW@)
|
||||
set(CMAKE_COMPILER_IS_CYGWIN @CMAKE_COMPILER_IS_CYGWIN@)
|
||||
if(CMAKE_COMPILER_IS_CYGWIN)
|
||||
set(CYGWIN 1)
|
||||
set(UNIX 1)
|
||||
endif(CMAKE_COMPILER_IS_CYGWIN)
|
||||
|
||||
set(CMAKE_D_COMPILER_ENV_VAR "DC")
|
||||
|
||||
if(CMAKE_COMPILER_IS_MINGW)
|
||||
set(MINGW 1)
|
||||
endif(CMAKE_COMPILER_IS_MINGW)
|
||||
set(CMAKE_D_SOURCE_FILE_EXTENSIONS d;di)
|
||||
set(CMAKE_D_IGNORE_EXTENSIONS h;H;o;O;obj;OBJ;def;DEF;rc;RC)
|
||||
# Prefer to use D's linker.
|
||||
# The D value 40 beats CXX value of 30 and C value of 10
|
||||
set(CMAKE_D_LINKER_PREFERENCE 40 )
|
||||
set(CMAKE_D_LINKER_PREFERENCE_PROPOGATES 1 )
|
||||
# Save compiler ABI information.
|
||||
set(CMAKE_D_SIZEOF_DATA_PTR "@CMAKE_D_SIZEOF_DATA_PTR@")
|
||||
set(CMAKE_D_COMPILER_ABI "@CMAKE_D_COMPILER_ABI@")
|
||||
|
||||
if(CMAKE_D_SIZEOF_DATA_PTR)
|
||||
set(CMAKE_SIZEOF_VOID_P "${CMAKE_D_SIZEOF_DATA_PTR}")
|
||||
endif(CMAKE_D_SIZEOF_DATA_PTR)
|
||||
|
||||
if(CMAKE_D_COMPILER_ABI)
|
||||
set(CMAKE_INTERNAL_PLATFORM_ABI "${CMAKE_D_COMPILER_ABI}")
|
||||
endif(CMAKE_D_COMPILER_ABI)
|
||||
|
||||
set(CMAKE_D_HAS_ISYSROOT "@CMAKE_D_HAS_ISYSROOT@")
|
||||
@CMAKE_D_OSX_DEPLOYMENT_TARGET_FLAG_CODE@
|
||||
|
||||
set(CMAKE_D_IMPLICIT_LINK_LIBRARIES "@CMAKE_D_IMPLICIT_LINK_LIBRARIES@")
|
||||
set(CMAKE_D_IMPLICIT_LINK_DIRECTORIES "@CMAKE_D_IMPLICIT_LINK_DIRECTORIES@")
|
|
@ -1,5 +0,0 @@
|
|||
int main(string[] args)
|
||||
{
|
||||
int require = 0;
|
||||
return require;
|
||||
}
|
|
@ -1,39 +0,0 @@
|
|||
version(DigitalMars)
|
||||
{
|
||||
const string COMPILER_ID = "DigitalMars";
|
||||
}
|
||||
else version(GNU)
|
||||
{
|
||||
const string COMPILER_ID = "GNU";
|
||||
}
|
||||
else version(LDC)
|
||||
{
|
||||
const string COMPILER_ID = "LDC";
|
||||
}
|
||||
else version(SDC)
|
||||
{
|
||||
const string COMPILER_ID = "SDC";
|
||||
}
|
||||
else
|
||||
{
|
||||
const string COMPILER_ID = "";
|
||||
}
|
||||
|
||||
/* Construct the string literal in pieces to prevent the source from
|
||||
getting matched. Store it in a pointer rather than an array
|
||||
because some compilers will just produce instructions to fill the
|
||||
array rather than assigning a pointer to a static array. */
|
||||
string info_compiler = "INFO" ":" "compiler[" ~ COMPILER_ID ~ "]";
|
||||
|
||||
@CMAKE_D_COMPILER_ID_PLATFORM_CONTENT@
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
|
||||
int main(string[] args)
|
||||
{
|
||||
int require = 0;
|
||||
require += info_compiler[args.length];
|
||||
require += info_platform[args.length];
|
||||
require += info_arch[args.length];
|
||||
return require;
|
||||
}
|
|
@ -1,280 +0,0 @@
|
|||
#
|
||||
# CMakeD - CMake module for D Language
|
||||
#
|
||||
# Copyright (c) 2013, Selman Ulug <selman.ulug@gmail.com>
|
||||
# Tim Burrell <tim.burrell@gmail.com>
|
||||
# Steve King <sk@metrokings.com>
|
||||
# Dragos Carp <dragos.carp@gmail.com>
|
||||
# Konstantin Oblaukhov <oblaukhov.konstantin@gmail.com>
|
||||
#
|
||||
# All rights reserved.
|
||||
#
|
||||
# See LICENSE for details.
|
||||
#
|
||||
# Modified from CMake 2.6.5 CMakeCInformation.cmake
|
||||
# See http://www.cmake.org/HTML/Copyright.html for details
|
||||
#
|
||||
|
||||
# This file sets the basic flags for the D language in CMake.
|
||||
# It also loads the available platform file for the system-compiler
|
||||
# if it exists.
|
||||
# It also loads a system - compiler - processor (or target hardware)
|
||||
# specific file, which is mainly useful for crosscompiling and embedded systems.
|
||||
|
||||
# Load compiler-specific information.
|
||||
|
||||
set(_INCLUDED_FILE 0) # reset the indicator if an include occurred.
|
||||
|
||||
if(CMAKE_D_COMPILER_ID)
|
||||
include(Compiler/${CMAKE_D_COMPILER_ID}-D OPTIONAL)
|
||||
endif(CMAKE_D_COMPILER_ID)
|
||||
|
||||
# set(CMAKE_D_OUTPUT_EXTENSION .o)
|
||||
set(CMAKE_C_OUTPUT_EXTENSION_REPLACE TRUE )
|
||||
set(CMAKE_D_OUTPUT_EXTENSION_REPLACE TRUE )
|
||||
|
||||
set(CMAKE_BASE_NAME)
|
||||
get_filename_component(CMAKE_BASE_NAME ${CMAKE_D_COMPILER} NAME_WE)
|
||||
|
||||
set(_INCLUDED_FILE 0) # reset the indicator if an include occurred.
|
||||
|
||||
# load a hardware specific file, mostly useful for embedded compilers
|
||||
if(CMAKE_SYSTEM_PROCESSOR)
|
||||
if(CMAKE_D_COMPILER_ID)
|
||||
include(Platform/${CMAKE_SYSTEM_NAME}-${CMAKE_D_COMPILER_ID}-D-${CMAKE_SYSTEM_PROCESSOR} OPTIONAL RESULT_VARIABLE _INCLUDED_FILE)
|
||||
endif(CMAKE_D_COMPILER_ID)
|
||||
if(NOT _INCLUDED_FILE)
|
||||
include(Platform/${CMAKE_SYSTEM_NAME}-${CMAKE_BASE_NAME}-${CMAKE_SYSTEM_PROCESSOR} OPTIONAL)
|
||||
endif(NOT _INCLUDED_FILE)
|
||||
endif(CMAKE_SYSTEM_PROCESSOR)
|
||||
|
||||
set(_INCLUDED_FILE 0) # reset the indicator if an include occurred.
|
||||
|
||||
# load the system- and compiler specific files
|
||||
if(CMAKE_D_COMPILER_ID)
|
||||
include(Platform/${CMAKE_SYSTEM_NAME}-${CMAKE_D_COMPILER_ID}-D
|
||||
OPTIONAL RESULT_VARIABLE _INCLUDED_FILE)
|
||||
endif(CMAKE_D_COMPILER_ID)
|
||||
|
||||
# if no high specificity file was included, then try a more general one
|
||||
if(NOT _INCLUDED_FILE)
|
||||
include(Platform/${CMAKE_SYSTEM_NAME}-${CMAKE_BASE_NAME}
|
||||
OPTIONAL RESULT_VARIABLE _INCLUDED_FILE)
|
||||
endif(NOT _INCLUDED_FILE)
|
||||
|
||||
# We specify the compiler information in the system file for some
|
||||
# platforms, but this language may not have been enabled when the file
|
||||
# was first included. Include it again to get the language info.
|
||||
# Remove this when all compiler info is removed from system files.
|
||||
if(NOT _INCLUDED_FILE)
|
||||
include(Platform/${CMAKE_SYSTEM_NAME} OPTIONAL)
|
||||
endif(NOT _INCLUDED_FILE)
|
||||
|
||||
|
||||
# This should be included before the _INIT variables are
|
||||
# used to initialize the cache. Since the rule variables
|
||||
# have if blocks on them, users can still define them here.
|
||||
# But, it should still be after the platform file so changes can
|
||||
# be made to those values.
|
||||
|
||||
if(CMAKE_USER_MAKE_RULES_OVERRIDE)
|
||||
include(${CMAKE_USER_MAKE_RULES_OVERRIDE})
|
||||
endif(CMAKE_USER_MAKE_RULES_OVERRIDE)
|
||||
|
||||
if(CMAKE_USER_MAKE_RULES_OVERRIDE_D)
|
||||
include(${CMAKE_USER_MAKE_RULES_OVERRIDE_D})
|
||||
endif(CMAKE_USER_MAKE_RULES_OVERRIDE_D)
|
||||
|
||||
# Lines below was taken from CMakeCXXInformation.cmake
|
||||
# Not all of this flags are available on D compilers for now, but some as OPTIONS_PIC are.
|
||||
|
||||
if(NOT CMAKE_SHARED_LIBRARY_CREATE_D_FLAGS)
|
||||
set(CMAKE_SHARED_LIBRARY_CREATE_D_FLAGS ${CMAKE_SHARED_LIBRARY_CREATE_D_FLAGS})
|
||||
endif()
|
||||
|
||||
if(NOT CMAKE_D_COMPILE_OPTIONS_PIC)
|
||||
set(CMAKE_DCOMPILE_OPTIONS_PIC ${CMAKE_D_COMPILE_OPTIONS_PIC})
|
||||
endif()
|
||||
|
||||
if(NOT CMAKE_D_COMPILE_OPTIONS_PIE)
|
||||
set(CMAKE_D_COMPILE_OPTIONS_PIE ${CMAKE_D_COMPILE_OPTIONS_PIE})
|
||||
endif()
|
||||
|
||||
if(NOT CMAKE_D_COMPILE_OPTIONS_DLL)
|
||||
set(CMAKE_D_COMPILE_OPTIONS_DLL ${CMAKE_D_COMPILE_OPTIONS_DLL})
|
||||
endif()
|
||||
|
||||
if(NOT CMAKE_SHARED_LIBRARY_D_FLAGS)
|
||||
set(CMAKE_SHARED_LIBRARY_D_FLAGS ${CMAKE_SHARED_LIBRARY_D_FLAGS})
|
||||
endif()
|
||||
|
||||
if(NOT DEFINED CMAKE_SHARED_LIBRARY_LINK_D_FLAGS)
|
||||
set(CMAKE_SHARED_LIBRARY_LINK_D_FLAGS ${CMAKE_SHARED_LIBRARY_LINK_D_FLAGS})
|
||||
endif()
|
||||
|
||||
if(NOT CMAKE_SHARED_LIBRARY_RUNTIME_D_FLAG)
|
||||
set(CMAKE_SHARED_LIBRARY_RUNTIME_D_FLAG ${CMAKE_SHARED_LIBRARY_RUNTIME_D_FLAG})
|
||||
endif()
|
||||
|
||||
if(NOT CMAKE_SHARED_LIBRARY_RUNTIME_D_FLAG_SEP)
|
||||
set(CMAKE_SHARED_LIBRARY_RUNTIME_D_FLAG_SEP ${CMAKE_SHARED_LIBRARY_RUNTIME_D_FLAG_SEP})
|
||||
endif()
|
||||
|
||||
if(NOT CMAKE_SHARED_LIBRARY_RPATH_LINK_D_FLAG)
|
||||
set(CMAKE_SHARED_LIBRARY_RPATH_LINK_D_FLAG ${CMAKE_SHARED_LIBRARY_RPATH_LINK_D_FLAG})
|
||||
endif()
|
||||
|
||||
if(NOT DEFINED CMAKE_EXE_EXPORTS_D_FLAG)
|
||||
set(CMAKE_EXE_EXPORTS_D_FLAG ${CMAKE_EXE_EXPORTS_D_FLAG})
|
||||
endif()
|
||||
|
||||
if(NOT DEFINED CMAKE_SHARED_LIBRARY_SONAME_D_FLAG)
|
||||
set(CMAKE_SHARED_LIBRARY_SONAME_D_FLAG ${CMAKE_SHARED_LIBRARY_SONAME_D_FLAG})
|
||||
endif()
|
||||
|
||||
if(NOT CMAKE_EXECUTABLE_RUNTIME_D_FLAG)
|
||||
set(CMAKE_EXECUTABLE_RUNTIME_D_FLAG ${CMAKE_SHARED_LIBRARY_RUNTIME_D_FLAG})
|
||||
endif()
|
||||
|
||||
if(NOT CMAKE_EXECUTABLE_RUNTIME_D_FLAG_SEP)
|
||||
set(CMAKE_EXECUTABLE_RUNTIME_D_FLAG_SEP ${CMAKE_SHARED_LIBRARY_RUNTIME_D_FLAG_SEP})
|
||||
endif()
|
||||
|
||||
if(NOT CMAKE_EXECUTABLE_RPATH_LINK_D_FLAG)
|
||||
set(CMAKE_EXECUTABLE_RPATH_LINK_D_FLAG ${CMAKE_SHARED_LIBRARY_RPATH_LINK_D_FLAG})
|
||||
endif()
|
||||
|
||||
if(NOT DEFINED CMAKE_SHARED_LIBRARY_LINK_D_WITH_RUNTIME_PATH)
|
||||
set(CMAKE_SHARED_LIBRARY_LINK_D_WITH_RUNTIME_PATH ${CMAKE_SHARED_LIBRARY_LINK_D_WITH_RUNTIME_PATH})
|
||||
endif()
|
||||
|
||||
if(NOT CMAKE_INCLUDE_FLAG_D)
|
||||
set(CMAKE_INCLUDE_FLAG_D ${CMAKE_INCLUDE_FLAG_D})
|
||||
endif()
|
||||
|
||||
if(NOT CMAKE_INCLUDE_FLAG_SEP_D)
|
||||
set(CMAKE_INCLUDE_FLAG_SEP_D ${CMAKE_INCLUDE_FLAG_SEP_D})
|
||||
endif()
|
||||
|
||||
# for most systems a module is the same as a shared library
|
||||
# so unless the variable CMAKE_MODULE_EXISTS is set just
|
||||
# copy the values from the LIBRARY variables
|
||||
if(NOT CMAKE_MODULE_EXISTS)
|
||||
set(CMAKE_SHARED_MODULE_D_FLAGS ${CMAKE_SHARED_LIBRARY_D_FLAGS})
|
||||
set(CMAKE_SHARED_MODULE_CREATE_D_FLAGS ${CMAKE_SHARED_LIBRARY_CREATE_D_FLAGS})
|
||||
endif(NOT CMAKE_MODULE_EXISTS)
|
||||
|
||||
# repeat for modules
|
||||
if(NOT CMAKE_SHARED_MODULE_CREATE_D_FLAGS)
|
||||
set(CMAKE_SHARED_MODULE_CREATE_D_FLAGS ${CMAKE_SHARED_MODULE_CREATE_D_FLAGS})
|
||||
endif()
|
||||
|
||||
if(NOT CMAKE_SHARED_MODULE_D_FLAGS)
|
||||
set(CMAKE_SHARED_MODULE_D_FLAGS ${CMAKE_SHARED_MODULE_D_FLAGS})
|
||||
endif()
|
||||
|
||||
set(CMAKE_D_FLAGS_INIT "$ENV{DFLAGS} ${CMAKE_D_FLAGS_INIT}")
|
||||
# avoid just having a space as the initial value for the cache
|
||||
if(CMAKE_D_FLAGS_INIT STREQUAL " ")
|
||||
set(CMAKE_D_FLAGS_INIT)
|
||||
endif(CMAKE_D_FLAGS_INIT STREQUAL " ")
|
||||
set(CMAKE_D_FLAGS "${CMAKE_D_FLAGS_INIT}" CACHE STRING
|
||||
"Flags used by the D compiler during all build types.")
|
||||
|
||||
if(NOT CMAKE_NOT_USING_CONFIG_FLAGS)
|
||||
# default build type is none
|
||||
if(NOT CMAKE_NO_BUILD_TYPE)
|
||||
set(CMAKE_BUILD_TYPE ${CMAKE_BUILD_TYPE_INIT} CACHE STRING
|
||||
"Choose the type of build, options are: None(CMAKE_D_FLAGS used) Debug Release RelWithDebInfo MinSizeRel.")
|
||||
endif(NOT CMAKE_NO_BUILD_TYPE)
|
||||
set(CMAKE_D_FLAGS_DEBUG "${CMAKE_D_FLAGS_DEBUG_INIT}" CACHE STRING
|
||||
"Flags used by the compiler during debug builds.")
|
||||
set(CMAKE_D_FLAGS_MINSIZEREL "${CMAKE_D_FLAGS_MINSIZEREL_INIT}" CACHE STRING
|
||||
"Flags used by the compiler during release minsize builds.")
|
||||
set(CMAKE_D_FLAGS_RELEASE "${CMAKE_D_FLAGS_RELEASE_INIT}" CACHE STRING
|
||||
"Flags used by the compiler during release builds (/MD /Ob1 /Oi /Ot /Oy /Gs will produce slightly less optimized but smaller files).")
|
||||
set(CMAKE_D_FLAGS_RELWITHDEBINFO "${CMAKE_D_FLAGS_RELWITHDEBINFO_INIT}" CACHE STRING
|
||||
"Flags used by the compiler during Release with Debug Info builds.")
|
||||
endif(NOT CMAKE_NOT_USING_CONFIG_FLAGS)
|
||||
|
||||
if(CMAKE_D_STANDARD_LIBRARIES_INIT)
|
||||
set(CMAKE_D_STANDARD_LIBRARIES "${CMAKE_D_STANDARD_LIBRARIES_INIT}"
|
||||
CACHE STRING "Libraries linked by default with all D applications.")
|
||||
mark_as_advanced(CMAKE_D_STANDARD_LIBRARIES)
|
||||
endif(CMAKE_D_STANDARD_LIBRARIES_INIT)
|
||||
|
||||
include(CMakeCommonLanguageInclude)
|
||||
|
||||
# now define the following rule variables
|
||||
|
||||
# CMAKE_D_CREATE_SHARED_LIBRARY
|
||||
# CMAKE_D_CREATE_SHARED_MODULE
|
||||
# CMAKE_D_CREATE_STATIC_LIBRARY
|
||||
# CMAKE_D_COMPILE_OBJECT
|
||||
# CMAKE_D_LINK_EXECUTABLE
|
||||
|
||||
# variables supplied by the generator at use time
|
||||
# <TARGET>
|
||||
# <TARGET_BASE> the target without the suffix
|
||||
# <OBJECTS>
|
||||
# <OBJECT>
|
||||
# <LINK_LIBRARIES>
|
||||
# <FLAGS>
|
||||
# <LINK_FLAGS>
|
||||
|
||||
# D compiler information
|
||||
# <CMAKE_D_COMPILER>
|
||||
# <CMAKE_SHARED_LIBRARY_CREATE_D_FLAGS>
|
||||
# <CMAKE_SHARED_MODULE_CREATE_D_FLAGS>
|
||||
# <CMAKE_D_LINK_FLAGS>
|
||||
|
||||
# Static library tools
|
||||
# <CMAKE_AR>
|
||||
# <CMAKE_RANLIB>
|
||||
|
||||
# < 2.8.10 backward compatibility
|
||||
if(NOT CMAKE_PLATFORM_INFO_DIR)
|
||||
set(CMAKE_PLATFORM_INFO_DIR ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY})
|
||||
endif(NOT CMAKE_PLATFORM_INFO_DIR)
|
||||
|
||||
# create a D shared library
|
||||
if(NOT CMAKE_D_CREATE_SHARED_LIBRARY)
|
||||
set(CMAKE_D_CREATE_SHARED_LIBRARY
|
||||
"<CMAKE_D_COMPILER> <CMAKE_SHARED_LIBRARY_D_FLAGS> <LANGUAGE_COMPILE_FLAGS> <LINK_FLAGS> <CMAKE_SHARED_LIBRARY_CREATE_D_FLAGS> <CMAKE_SHARED_LIBRARY_SONAME_D_FLAG><TARGET_SONAME> ${CMAKE_D_DASH_O}<TARGET> <OBJECTS> <LINK_LIBRARIES> ${DSTDLIB_FLAGS} ${CMAKE_D_STDLIBS}")
|
||||
endif(NOT CMAKE_D_CREATE_SHARED_LIBRARY)
|
||||
|
||||
# create a D shared module just copy the shared library rule
|
||||
if(NOT CMAKE_D_CREATE_SHARED_MODULE)
|
||||
set(CMAKE_D_CREATE_SHARED_MODULE "${CMAKE_D_CREATE_SHARED_LIBRARY}")
|
||||
endif(NOT CMAKE_D_CREATE_SHARED_MODULE)
|
||||
|
||||
if(NOT CMAKE_D_CREATE_STATIC_LIBRARY AND CMAKE_STATIC_LIBRARY_CREATE_D_FLAGS)
|
||||
set(CMAKE_D_CREATE_STATIC_LIBRARY
|
||||
"<CMAKE_D_COMPILER> ${CMAKE_STATIC_LIBRARY_CREATE_D_FLAGS} <OBJECTS> ${CMAKE_D_DASH_O}<TARGET>")
|
||||
endif(NOT CMAKE_D_CREATE_STATIC_LIBRARY AND CMAKE_STATIC_LIBRARY_CREATE_D_FLAGS)
|
||||
|
||||
# Create a static archive incrementally for large object file counts.
|
||||
# If CMAKE_D_CREATE_STATIC_LIBRARY is set it will override these.
|
||||
set(CMAKE_D_ARCHIVE_CREATE "<CMAKE_AR> cr <TARGET> <LINK_FLAGS> <OBJECTS>")
|
||||
set(CMAKE_D_ARCHIVE_APPEND "<CMAKE_AR> r <TARGET> <LINK_FLAGS> <OBJECTS>")
|
||||
set(CMAKE_D_ARCHIVE_FINISH "<CMAKE_RANLIB> <TARGET>")
|
||||
|
||||
# compile a D file into an object file
|
||||
if(NOT CMAKE_D_COMPILE_OBJECT)
|
||||
set(CMAKE_D_COMPILE_OBJECT
|
||||
"<CMAKE_D_COMPILER> <FLAGS> ${CMAKE_D_DASH_O}<OBJECT> -c <SOURCE>")
|
||||
endif(NOT CMAKE_D_COMPILE_OBJECT)
|
||||
|
||||
if(NOT CMAKE_D_LINK_EXECUTABLE)
|
||||
set(CMAKE_D_LINK_EXECUTABLE
|
||||
"<CMAKE_D_COMPILER> <FLAGS> <CMAKE_D_LINK_FLAGS> <LINK_FLAGS> <OBJECTS> ${CMAKE_D_DASH_O}<TARGET> <LINK_LIBRARIES> ${CMAKE_D_STDLIBS}")
|
||||
endif(NOT CMAKE_D_LINK_EXECUTABLE)
|
||||
|
||||
mark_as_advanced(
|
||||
CMAKE_D_FLAGS
|
||||
CMAKE_D_FLAGS_DEBUG
|
||||
CMAKE_D_FLAGS_MINSIZEREL
|
||||
CMAKE_D_FLAGS_RELEASE
|
||||
CMAKE_D_FLAGS_RELWITHDEBINFO
|
||||
)
|
||||
set(CMAKE_D_INFORMATION_LOADED 1)
|
|
@ -1,163 +0,0 @@
|
|||
#
|
||||
# CMakeD - CMake module for D Language
|
||||
#
|
||||
# Copyright (c) 2013, Selman Ulug <selman.ulug@gmail.com>
|
||||
# Tim Burrell <tim.burrell@gmail.com>
|
||||
# Dragos Carp <dragos.carp@gmail.com>
|
||||
#
|
||||
# All rights reserved.
|
||||
#
|
||||
# See LICENSE for details.
|
||||
#
|
||||
# Modified from CMake 2.6.5 CMakeDetermineCCompiler.cmake
|
||||
# See http://www.cmake.org/HTML/Copyright.html for details
|
||||
#
|
||||
|
||||
# determine the compiler to use for D programs
|
||||
# NOTE, a generator may set CMAKE_D_COMPILER before
|
||||
# loading this file to force a compiler.
|
||||
# use environment variable DC first if defined by user, next use
|
||||
# the cmake variable CMAKE_GENERATOR_D which can be defined by a generator
|
||||
# as a default compiler
|
||||
|
||||
if(NOT CMAKE_D_COMPILER)
|
||||
set(CMAKE_D_COMPILER_INIT NOTFOUND)
|
||||
# prefer the environment variable DC
|
||||
if($ENV{DC} MATCHES ".+")
|
||||
get_filename_component(CMAKE_D_COMPILER_INIT $ENV{DC} PROGRAM PROGRAM_ARGS CMAKE_D_FLAGS_ENV_INIT)
|
||||
if(CMAKE_D_FLAGS_ENV_INIT)
|
||||
set(CMAKE_D_COMPILER_ARG1 "${CMAKE_D_FLAGS_ENV_INIT}" CACHE STRING "First argument to D compiler")
|
||||
endif(CMAKE_D_FLAGS_ENV_INIT)
|
||||
if(NOT EXISTS ${CMAKE_D_COMPILER_INIT})
|
||||
MESSAGE(FATAL_ERROR "Could not find compiler set in environment variable C:\n$ENV{DC}.")
|
||||
endif(NOT EXISTS ${CMAKE_D_COMPILER_INIT})
|
||||
endif($ENV{DC} MATCHES ".+")
|
||||
|
||||
# next try prefer the compiler specified by the generator
|
||||
if(CMAKE_GENERATOR_D)
|
||||
if(NOT CMAKE_D_COMPILER_INIT)
|
||||
set(CMAKE_D_COMPILER_INIT ${CMAKE_GENERATOR_D})
|
||||
endif(NOT CMAKE_D_COMPILER_INIT)
|
||||
endif(CMAKE_GENERATOR_D)
|
||||
|
||||
# finally list compilers to try
|
||||
if(CMAKE_D_COMPILER_INIT)
|
||||
set(CMAKE_D_COMPILER_LIST ${CMAKE_D_COMPILER_INIT})
|
||||
else(CMAKE_D_COMPILER_INIT)
|
||||
set(CMAKE_D_COMPILER_LIST ${_CMAKE_TOOLCHAIN_PREFIX}gdc ${_CMAKE_TOOLCHAIN_PREFIX}dmd)
|
||||
endif(CMAKE_D_COMPILER_INIT)
|
||||
|
||||
# Find the compiler.
|
||||
if(_CMAKE_USER_D_COMPILER_PATH)
|
||||
find_program(CMAKE_D_COMPILER NAMES ${CMAKE_D_COMPILER_LIST} PATHS ${_CMAKE_USER_D_COMPILER_PATH} DOC "D compiler" NO_DEFAULT_PATH)
|
||||
endif(_CMAKE_USER_D_COMPILER_PATH)
|
||||
find_program(CMAKE_D_COMPILER NAMES ${CMAKE_D_COMPILER_LIST} DOC "D compiler")
|
||||
|
||||
if(CMAKE_D_COMPILER_INIT AND NOT CMAKE_D_COMPILER)
|
||||
set(CMAKE_D_COMPILER "${CMAKE_D_COMPILER_INIT}" CACHE FILEPATH "D compiler" FORCE)
|
||||
endif(CMAKE_D_COMPILER_INIT AND NOT CMAKE_D_COMPILER)
|
||||
else(NOT CMAKE_D_COMPILER)
|
||||
|
||||
# we only get here if CMAKE_D_COMPILER was specified using -D or a pre-made CMakeCache.txt
|
||||
# (e.g. via ctest) or set in CMAKE_TOOLCHAIN_FILE
|
||||
# if CMAKE_D_COMPILER is a list of length 2, use the first item as
|
||||
# CMAKE_D_COMPILER and the 2nd one as CMAKE_D_COMPILER_ARG1
|
||||
|
||||
list(LENGTH CMAKE_D_COMPILER _CMAKE_D_COMPILER_LIST_LENGTH)
|
||||
if("${_CMAKE_D_COMPILER_LIST_LENGTH}" EQUAL 2)
|
||||
list(GET CMAKE_D_COMPILER 1 CMAKE_D_COMPILER_ARG1)
|
||||
list(GET CMAKE_D_COMPILER 0 CMAKE_D_COMPILER)
|
||||
endif("${_CMAKE_D_COMPILER_LIST_LENGTH}" EQUAL 2)
|
||||
|
||||
# if a compiler was specified by the user but without path,
|
||||
# now try to find it with the full path
|
||||
# if it is found, force it into the cache,
|
||||
# if not, don't overwrite the setting (which was given by the user) with "NOTFOUND"
|
||||
# if the C compiler already had a path, reuse it for searching the CXX compiler
|
||||
get_filename_component(_CMAKE_USER_D_COMPILER_PATH "${CMAKE_D_COMPILER}" PATH)
|
||||
if(NOT _CMAKE_USER_D_COMPILER_PATH)
|
||||
find_program(CMAKE_D_COMPILER_WITH_PATH NAMES ${CMAKE_D_COMPILER})
|
||||
mark_as_advanced(CMAKE_D_COMPILER_WITH_PATH)
|
||||
if(CMAKE_D_COMPILER_WITH_PATH)
|
||||
set(CMAKE_D_COMPILER ${CMAKE_D_COMPILER_WITH_PATH} CACHE STRING "D compiler" FORCE)
|
||||
endif(CMAKE_D_COMPILER_WITH_PATH)
|
||||
endif(NOT _CMAKE_USER_D_COMPILER_PATH)
|
||||
endif(NOT CMAKE_D_COMPILER)
|
||||
mark_as_advanced(CMAKE_D_COMPILER)
|
||||
|
||||
if(NOT _CMAKE_TOOLCHAIN_LOCATION)
|
||||
get_filename_component(_CMAKE_TOOLCHAIN_LOCATION "${CMAKE_D_COMPILER}" PATH)
|
||||
endif(NOT _CMAKE_TOOLCHAIN_LOCATION)
|
||||
|
||||
# Build a small source file to identify the compiler.
|
||||
if(${CMAKE_GENERATOR} MATCHES "Visual Studio")
|
||||
set(CMAKE_D_COMPILER_ID_RUN 1)
|
||||
set(CMAKE_D_PLATFORM_ID "Windows")
|
||||
|
||||
# TODO: Set the compiler id. It is probably MSVC but
|
||||
# the user may be using an integrated Intel compiler.
|
||||
# set(CMAKE_D_COMPILER_ID "MSVC")
|
||||
endif(${CMAKE_GENERATOR} MATCHES "Visual Studio")
|
||||
|
||||
if(NOT CMAKE_D_COMPILER_ID_RUN)
|
||||
set(CMAKE_D_COMPILER_ID_RUN 1)
|
||||
|
||||
# Each entry in this list is a set of extra flags to try
|
||||
# adding to the compile line to see if it helps produce
|
||||
# a valid identification file.
|
||||
set(CMAKE_D_COMPILER_ID_TEST_FLAGS
|
||||
# Try compiling to an object file only.
|
||||
"-c"
|
||||
)
|
||||
|
||||
# Try to identify the compiler.
|
||||
set(CMAKE_D_COMPILER_ID)
|
||||
find_file(CMAKE_PLATFORM_ID_CONTENT_FILE CMakePlatformId.di.in PATHS ${CMAKE_ROOT}/Modules
|
||||
${CMAKE_MODULE_PATH} NO_DEFAULT_PATH)
|
||||
file(READ ${CMAKE_PLATFORM_ID_CONTENT_FILE} CMAKE_D_COMPILER_ID_PLATFORM_CONTENT)
|
||||
find_file(CMAKE_D_COMPILER_ID_FILE_IN CMakeDCompilerId.d.in PATHS ${CMAKE_ROOT}/Modules
|
||||
${CMAKE_MODULE_PATH} NO_DEFAULT_PATH)
|
||||
# Workaround for bug http://public.kitware.com/Bug/view.php?id=14481
|
||||
# if CMAKE_MODULE_PATH is used, then patch ${CMAKE_ROOT}/Modules/CMakeDetermineCompilerId.cmake
|
||||
get_filename_component(CMAKE_D_COMPILER_ID_FILE_IN_PATH ${CMAKE_D_COMPILER_ID_FILE_IN} PATH)
|
||||
if(CMAKE_MAJOR_VERSION GREATER 2 OR CMAKE_D_COMPILER_ID_FILE_IN_PATH STREQUAL ${CMAKE_ROOT}/Modules)
|
||||
include(${CMAKE_ROOT}/Modules/CMakeDetermineCompilerId.cmake)
|
||||
else(CMAKE_D_COMPILER_ID_FILE_IN_PATH STREQUAL ${CMAKE_ROOT}/Modules)
|
||||
file(READ ${CMAKE_ROOT}/Modules/CMakeDetermineCompilerId.cmake CMAKE_DETERMINE_COMPILER_ID_CMAKE_CONTENT)
|
||||
STRING(REPLACE "file(READ \${CMAKE_ROOT}/Modules/\${src}.in ID_CONTENT_IN)"
|
||||
"find_file(src_in \${src}.in PATHS \${CMAKE_ROOT}/Modules \${CMAKE_MODULE_PATH} NO_DEFAULT_PATH)
|
||||
file(READ \${src_in} ID_CONTENT_IN)
|
||||
unset(src_in CACHE)"
|
||||
CMAKE_DETERMINE_COMPILER_ID_CMAKE_CONTENT_PATCHED ${CMAKE_DETERMINE_COMPILER_ID_CMAKE_CONTENT})
|
||||
file(WRITE ${CMAKE_PLATFORM_INFO_DIR}/CMakeDetermineCompilerId.cmake
|
||||
${CMAKE_DETERMINE_COMPILER_ID_CMAKE_CONTENT_PATCHED})
|
||||
include(${CMAKE_PLATFORM_INFO_DIR}/CMakeDetermineCompilerId.cmake)
|
||||
endif(CMAKE_MAJOR_VERSION GREATER 2 OR CMAKE_D_COMPILER_ID_FILE_IN_PATH STREQUAL ${CMAKE_ROOT}/Modules)
|
||||
CMAKE_DETERMINE_COMPILER_ID(D DFLAGS CMakeDCompilerId.d)
|
||||
unset(CMAKE_D_COMPILER_ID_FILE_IN CACHE)
|
||||
unset(CMAKE_PLATFORM_ID_CONTENT_FILE CACHE)
|
||||
|
||||
# Set old compiler and platform id variables.
|
||||
if("${CMAKE_D_COMPILER_ID}" MATCHES "GNU")
|
||||
set(CMAKE_COMPILER_IS_GDC 1)
|
||||
endif("${CMAKE_D_COMPILER_ID}" MATCHES "GNU")
|
||||
if("${CMAKE_D_PLATFORM_ID}" MATCHES "MinGW")
|
||||
set(CMAKE_COMPILER_IS_MINGW 1)
|
||||
elseif("${CMAKE_D_PLATFORM_ID}" MATCHES "Cygwin")
|
||||
set(CMAKE_COMPILER_IS_CYGWIN 1)
|
||||
endif("${CMAKE_D_PLATFORM_ID}" MATCHES "MinGW")
|
||||
endif(NOT CMAKE_D_COMPILER_ID_RUN)
|
||||
|
||||
include(CMakeFindBinUtils)
|
||||
if(MSVC_D_ARCHITECTURE_ID)
|
||||
set(SET_MSVC_D_ARCHITECTURE_ID
|
||||
"set(MSVC_D_ARCHITECTURE_ID ${MSVC_D_ARCHITECTURE_ID})")
|
||||
endif(MSVC_D_ARCHITECTURE_ID)
|
||||
# configure variables set in this file for fast reload later on
|
||||
find_file(CMAKE_D_COMPILER_CMAKE_IN CMakeDCompiler.cmake.in PATHS ${CMAKE_ROOT}/Modules
|
||||
${CMAKE_MODULE_PATH} NO_DEFAULT_PATH)
|
||||
configure_file(${CMAKE_D_COMPILER_CMAKE_IN}
|
||||
${CMAKE_PLATFORM_INFO_DIR}/CMakeDCompiler.cmake
|
||||
@ONLY IMMEDIATE # IMMEDIATE must be here for compatibility mode <= 2.0
|
||||
)
|
||||
set(CMAKE_D_COMPILER_ENV_VAR "DC")
|
|
@ -1,41 +0,0 @@
|
|||
#
|
||||
# CMakeD - CMake module for D Language
|
||||
#
|
||||
# Copyright (c) 2013, Selman Ulug <selman.ulug@gmail.com>
|
||||
# Tim Burrell <tim.burrell@gmail.com>
|
||||
# Dragos Carp <dragos.carp@gmail.com>
|
||||
#
|
||||
# All rights reserved.
|
||||
#
|
||||
# See LICENSE for details.
|
||||
#
|
||||
CMAKE_MINIMUM_REQUIRED(VERSION 2.8.1)
|
||||
PROJECT (cmake-d NONE)
|
||||
|
||||
SET (MOD_SRCS
|
||||
CMakeDCompiler.cmake.in
|
||||
CMakeDCompilerId.d.in
|
||||
CMakeDInformation.cmake
|
||||
CMakeDCompilerABI.d
|
||||
CMakeTestDCompiler.cmake
|
||||
CMakeDetermineDCompiler.cmake
|
||||
FindGDCPath.cmake
|
||||
UseDDoc.cmake
|
||||
UseDDeps.cmake
|
||||
UseDub.cmake
|
||||
dependencies.cmake
|
||||
UseDUnittest.cmake
|
||||
FindPhobos.cmake
|
||||
CMakePlatformId.di.in
|
||||
)
|
||||
|
||||
SET (PLAT_SRCS
|
||||
Platform/Linux-dmd.cmake
|
||||
Platform/Linux-gdc.cmake
|
||||
Platform/Linux-ldc2.cmake
|
||||
Platform/Windows-dmd.cmake
|
||||
Platform/Windows-gdc.cmake
|
||||
)
|
||||
|
||||
INSTALL (FILES ${MOD_SRCS} DESTINATION ${CMAKE_ROOT}/Modules)
|
||||
INSTALL (FILES ${PLAT_SRCS} DESTINATION ${CMAKE_ROOT}/Modules/Platform)
|
|
@ -1,118 +0,0 @@
|
|||
/* Identify known platforms by name. */
|
||||
version(linux)
|
||||
{
|
||||
const string PLATFORM_ID = "Linux";
|
||||
}
|
||||
else version(Cygwin)
|
||||
{
|
||||
const string PLATFORM_ID = "Cygwin";
|
||||
}
|
||||
else version(MinGW)
|
||||
{
|
||||
const string PLATFORM_ID = "MinGW";
|
||||
}
|
||||
else version(OSX)
|
||||
{
|
||||
const string PLATFORM_ID = "Darwin";
|
||||
}
|
||||
else version(Windows)
|
||||
{
|
||||
const string PLATFORM_ID = "Windows";
|
||||
}
|
||||
else version(FreeBSD)
|
||||
{
|
||||
const string PLATFORM_ID = "FreeBSD";
|
||||
}
|
||||
else version(NetBSD)
|
||||
{
|
||||
const string PLATFORM_ID = "NetBSD";
|
||||
}
|
||||
else version(OpenBSD)
|
||||
{
|
||||
const string PLATFORM_ID = "OpenBSD";
|
||||
}
|
||||
else version(NetBSD)
|
||||
{
|
||||
const string PLATFORM_ID = "NetBSD";
|
||||
}
|
||||
else version(Solaris)
|
||||
{
|
||||
const string PLATFORM_ID = "SunOS";
|
||||
}
|
||||
else version(AIX)
|
||||
{
|
||||
const string PLATFORM_ID = "AIX";
|
||||
}
|
||||
else version(Haiku)
|
||||
{
|
||||
const string PLATFORM_ID = "Haiku";
|
||||
}
|
||||
else version(AIX)
|
||||
{
|
||||
const string PLATFORM_ID = "BeOS";
|
||||
}
|
||||
else version(AIX)
|
||||
{
|
||||
const string PLATFORM_ID = "QNX";
|
||||
}
|
||||
else version(AIX)
|
||||
{
|
||||
const string PLATFORM_ID = "Tru64";
|
||||
}
|
||||
else version(AIX)
|
||||
{
|
||||
const string PLATFORM_ID = "RISCos";
|
||||
}
|
||||
else
|
||||
{
|
||||
const string PLATFORM_ID = "";
|
||||
}
|
||||
|
||||
/* For windows compilers MSVC and Intel we can determine
|
||||
the architecture of the compiler being used. This is because
|
||||
the compilers do not have flags that can change the architecture,
|
||||
but rather depend on which compiler is being used
|
||||
*/
|
||||
version(IA64)
|
||||
{
|
||||
const string ARCHITECTURE_ID = "IA64";
|
||||
}
|
||||
else version(X86_64)
|
||||
{
|
||||
const string ARCHITECTURE_ID = "x64";
|
||||
}
|
||||
else version(X86)
|
||||
{
|
||||
const string ARCHITECTURE_ID = "X86";
|
||||
}
|
||||
else version(ARM)
|
||||
{
|
||||
const string ARCHITECTURE_ID = "ARM";
|
||||
}
|
||||
else version(MIPS32)
|
||||
{
|
||||
const string ARCHITECTURE_ID = "MIPS";
|
||||
}
|
||||
else version(MIPS64)
|
||||
{
|
||||
const string ARCHITECTURE_ID = "MIPS";
|
||||
}
|
||||
else version(SH)
|
||||
{
|
||||
const string ARCHITECTURE_ID = "SHx";
|
||||
}
|
||||
else version(SH64)
|
||||
{
|
||||
const string ARCHITECTURE_ID = "SHx";
|
||||
}
|
||||
else
|
||||
{
|
||||
const string ARCHITECTURE_ID = "";
|
||||
}
|
||||
|
||||
/* Construct the string literal in pieces to prevent the source from
|
||||
getting matched. Store it in a pointer rather than an array
|
||||
because some compilers will just produce instructions to fill the
|
||||
array rather than assigning a pointer to a static array. */
|
||||
string info_platform = "INFO" ":" "platform[" ~ PLATFORM_ID ~ "]";
|
||||
string info_arch = "INFO" ":" "arch[" ~ ARCHITECTURE_ID ~"]";
|
|
@ -1,78 +0,0 @@
|
|||
#
|
||||
# CMakeD - CMake module for D Language
|
||||
#
|
||||
# Copyright (c) 2007, Selman Ulug <selman.ulug@gmail.com>
|
||||
# Tim Burrell <tim.burrell@gmail.com>
|
||||
# Dragos Carp <dragos.carp@gmail.com>
|
||||
#
|
||||
# All rights reserved.
|
||||
#
|
||||
# See LICENSE for details.
|
||||
#
|
||||
# Modified from CMake 2.6.5 CMakeTestCCompiler.cmake
|
||||
# See http://www.cmake.org/HTML/Copyright.html for details
|
||||
#
|
||||
|
||||
include(CMakeTestCompilerCommon)
|
||||
|
||||
# This file is used by EnableLanguage in cmGlobalGenerator to
|
||||
# determine that that selected D compiler can actually compile
|
||||
# and link the most basic of programs. If not, a fatal error
|
||||
# is set and cmake stops processing commands and will not generate
|
||||
# any makefiles or projects.
|
||||
if(NOT CMAKE_D_COMPILER_WORKS)
|
||||
PrintTestCompilerStatus("D" "")
|
||||
file(WRITE ${CMAKE_PLATFORM_INFO_DIR}/CMakeTmp/testDCompiler.d
|
||||
"int main(char[][] args)\n"
|
||||
"{return args.sizeof-1;}\n")
|
||||
try_compile(CMAKE_D_COMPILER_WORKS ${CMAKE_BINARY_DIR}
|
||||
${CMAKE_PLATFORM_INFO_DIR}/CMakeTmp/testDCompiler.d
|
||||
OUTPUT_VARIABLE OUTPUT)
|
||||
set(D_TEST_WAS_RUN 1)
|
||||
endif(NOT CMAKE_D_COMPILER_WORKS)
|
||||
|
||||
if(NOT CMAKE_D_COMPILER_WORKS)
|
||||
PrintTestCompilerStatus("D" " -- broken")
|
||||
message(STATUS "To force a specific D compiler set the DC environment variable")
|
||||
message(STATUS " ie - export DC=\"/usr/bin/dmd\"")
|
||||
file(APPEND ${CMAKE_PLATFORM_INFO_DIR}/CMakeError.log
|
||||
"Determining if the D compiler works failed with "
|
||||
"the following output:\n${OUTPUT}\n\n")
|
||||
# if the compiler is broken make sure to remove the platform file
|
||||
# since Windows-cl configures both c/cxx files both need to be removed
|
||||
# when c or c++ fails
|
||||
file(REMOVE ${CMAKE_PLATFORM_INFO_DIR}/CMakeDPlatform.cmake)
|
||||
message(FATAL_ERROR "The D compiler \"${CMAKE_D_COMPILER}\" "
|
||||
"is not able to compile a simple test program.\nIt fails "
|
||||
"with the following output:\n ${OUTPUT}\n\n"
|
||||
"CMake will not be able to correctly generate this project.")
|
||||
else(NOT CMAKE_D_COMPILER_WORKS)
|
||||
if(D_TEST_WAS_RUN)
|
||||
message(STATUS "Check for working D compiler: ${CMAKE_D_COMPILER} -- works")
|
||||
file(APPEND ${CMAKE_PLATFORM_INFO_DIR}/CMakeOutput.log
|
||||
"Determining if the D compiler works passed with "
|
||||
"the following output:\n${OUTPUT}\n\n")
|
||||
endif(D_TEST_WAS_RUN)
|
||||
set(CMAKE_D_COMPILER_WORKS 1 CACHE INTERNAL "")
|
||||
|
||||
if(CMAKE_D_COMPILER_FORCED)
|
||||
# The compiler configuration was forced by the user.
|
||||
# Assume the user has configured all compiler information.
|
||||
else(CMAKE_D_COMPILER_FORCED)
|
||||
# Try to identify the ABI and configure it into CMakeDCompiler.cmake
|
||||
include(${CMAKE_ROOT}/Modules/CMakeDetermineCompilerABI.cmake)
|
||||
find_file(CMAKE_D_COMPILER_ABI_SRC CMakeDCompilerABI.d PATHS ${CMAKE_ROOT}/Modules
|
||||
${CMAKE_MODULE_PATH} NO_DEFAULT_PATH)
|
||||
CMAKE_DETERMINE_COMPILER_ABI(D ${CMAKE_D_COMPILER_ABI_SRC})
|
||||
find_file(CMAKE_D_COMPILER_CMAKE_IN CMakeDCompiler.cmake.in PATHS ${CMAKE_ROOT}/Modules
|
||||
${CMAKE_MODULE_PATH} NO_DEFAULT_PATH)
|
||||
configure_file(
|
||||
${CMAKE_D_COMPILER_CMAKE_IN}
|
||||
${CMAKE_PLATFORM_INFO_DIR}/CMakeDCompiler.cmake
|
||||
@ONLY IMMEDIATE # IMMEDIATE must be here for compatibility mode <= 2.0
|
||||
)
|
||||
include(${CMAKE_PLATFORM_INFO_DIR}/CMakeDCompiler.cmake)
|
||||
unset(CMAKE_D_COMPILER_ABI_SRC CACHE)
|
||||
unset(CMAKE_D_COMPILER_CMAKE_IN CACHE)
|
||||
endif(CMAKE_D_COMPILER_FORCED)
|
||||
endif(NOT CMAKE_D_COMPILER_WORKS)
|
|
@ -1,49 +0,0 @@
|
|||
#
|
||||
# CMakeD - CMake module for D Language
|
||||
#
|
||||
# Copyright (c) 2013, Selman Ulug <selman.ulug@gmail.com>
|
||||
# Tim Burrell <tim.burrell@gmail.com>
|
||||
# Dragos Carp <dragos.carp@gmail.com>
|
||||
#
|
||||
# All rights reserved.
|
||||
#
|
||||
# See LICENSE for details.
|
||||
#
|
||||
# - Find GDC Include Path
|
||||
#
|
||||
# GDC_INCLUDE_PATH = path to where object.d is found
|
||||
#
|
||||
|
||||
set(GDC_POSSIBLE_INCLUDE_PATHS
|
||||
/usr/include/d/4.8.2
|
||||
/usr/include/d/4.8.1
|
||||
/usr/include/d/4.8.0
|
||||
/usr/include/d/4.7.3
|
||||
/usr/include/d/4.7.2
|
||||
/usr/include/d/4.7.1
|
||||
/usr/include/d/4.7.0
|
||||
/usr/include/d/4.2.1
|
||||
/usr/include/d/4.2.0
|
||||
/usr/include/d/4.1.2
|
||||
/usr/include/d/4.1.1
|
||||
/usr/include/d/4.1.0
|
||||
/usr/include/d/4.0.4
|
||||
/usr/include/d/4.0.3
|
||||
/usr/include/d/4.0.2
|
||||
/usr/include/d/4.0.1
|
||||
/usr/include/d/4.0.0
|
||||
/usr/include/d/4.0.6
|
||||
/usr/include/d/4.0.5
|
||||
/usr/include/d/3.4.4
|
||||
/usr/include/d/3.4.3
|
||||
/usr/include/d/3.4.2
|
||||
/usr/include/d/3.4.1
|
||||
/usr/include/d/3.4.0
|
||||
)
|
||||
|
||||
find_path(GDC_INCLUDE_PATH object.d
|
||||
${GDC_POSSIBLE_INCLUDE_PATHS})
|
||||
|
||||
mark_as_advanced(
|
||||
GDC_INCLUDE_PATH
|
||||
)
|
|
@ -1,5 +0,0 @@
|
|||
find_path(PHOBOS_INCLUDE_DIR std/file.d)
|
||||
find_library(PHOBOS_LIBRARY phobos2)
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
find_package_handle_standard_args(Phobos DEFAULT_MSG PHOBOS_LIBRARY PHOBOS_INCLUDE_DIR)
|
|
@ -1,67 +0,0 @@
|
|||
#
|
||||
# CMakeD - CMake module for D Language
|
||||
#
|
||||
# Copyright (c) 2007, Selman Ulug <selman.ulug@gmail.com>
|
||||
# Tim Burrell <tim.burrell@gmail.com>
|
||||
#
|
||||
# All rights reserved.
|
||||
#
|
||||
# See LICENSE for details.
|
||||
#
|
||||
# Modified from CMake 2.6.5 gcc.cmake
|
||||
# See http://www.cmake.org/HTML/Copyright.html for details
|
||||
#
|
||||
|
||||
#SET(DSTDLIB_FLAGS "-version=Phobos")
|
||||
IF(CMAKE_D_BUILD_DOCS)
|
||||
SET(DDOC_FLAGS "-D -Dddocumentation")
|
||||
#FOREACH(item ${CMAKE_D_DDOC_FILES})
|
||||
# SET(DDOC_FLAGS "${DDOC_FLAGS} ${item}")
|
||||
#ENDFOREACH(item)
|
||||
ENDIF(CMAKE_D_BUILD_DOCS)
|
||||
|
||||
SET(CMAKE_D_OUTPUT_EXTENSION .o)
|
||||
SET(CMAKE_D_DASH_O "-of")
|
||||
SET(CMAKE_BASE_NAME dmd)
|
||||
|
||||
SET(CMAKE_STATIC_LIBRARY_CREATE_D_FLAGS "-lib")
|
||||
|
||||
SET(CMAKE_SHARED_LIBRARY_D_FLAGS "") # -pic
|
||||
SET(CMAKE_SHARED_LIBRARY_CREATE_D_FLAGS "-shared -defaultlib=libphobos2.so") # -shared
|
||||
SET(CMAKE_SHARED_LIBRARY_LINK_D_FLAGS "") # +s, flag for exe link to use shared lib
|
||||
SET(CMAKE_SHARED_LIBRARY_RUNTIME_D_FLAG "") # -rpath
|
||||
SET(CMAKE_SHARED_LIBRARY_RUNTIME_D_FLAG_SEP "") # : or empty
|
||||
SET(CMAKE_SHARED_LIBRARY_SONAME_D_FLAG "-L-soname=")
|
||||
SET(CMAKE_SHARED_LIBRARY_RPATH_LINK_D_FLAG "-L-rpath=")
|
||||
SET(CMAKE_INCLUDE_FLAG_D "-I") # -I
|
||||
SET(CMAKE_INCLUDE_FLAG_D_SEP "") # , or empty
|
||||
SET(CMAKE_LIBRARY_PATH_FLAG "-L-L")
|
||||
SET(CMAKE_LIBRARY_PATH_TERMINATOR "") # for the Digital Mars D compiler the link paths have to be terminated with a "/"
|
||||
SET(CMAKE_LINK_LIBRARY_FLAG "-L-l")
|
||||
|
||||
SET(CMAKE_D_COMPILE_OPTIONS_PIC "-fPIC")
|
||||
|
||||
SET(CMAKE_LINK_LIBRARY_SUFFIX "")
|
||||
SET(CMAKE_STATIC_LIBRARY_PREFIX "lib")
|
||||
SET(CMAKE_STATIC_LIBRARY_SUFFIX ".a")
|
||||
SET(CMAKE_SHARED_LIBRARY_PREFIX "lib") # lib
|
||||
SET(CMAKE_SHARED_LIBRARY_SUFFIX ".so") # .so
|
||||
SET(CMAKE_EXECUTABLE_SUFFIX "") # .exe
|
||||
SET(CMAKE_DL_LIBS "dl")
|
||||
|
||||
SET(CMAKE_FIND_LIBRARY_PREFIXES "lib")
|
||||
SET(CMAKE_FIND_LIBRARY_SUFFIXES ".so" ".a")
|
||||
|
||||
#SET(CMAKE_D_STDLIBS "-L-lphobos2 -L-lpthread -L-lm -defaultlib=libphobos2.so")
|
||||
|
||||
#SET (CMAKE_D_FLAGS_INIT "-version=${CMAKE_BUILD_TYPE}Build ${DSTDLIB_FLAGS} ${DSTDLIB_TYPE} -I$ENV{D_PATH}/include -I$ENV{D_PATH}/import -I${CMAKE_PROJECT_SOURCE_DIR}")
|
||||
SET (CMAKE_D_FLAGS_INIT "")
|
||||
|
||||
SET (CMAKE_D_LINK_FLAGS "")
|
||||
SET (CMAKE_D_FLAGS_DEBUG_INIT "-g -debug -L--export-dynamic ${DDOC_FLAGS}")
|
||||
# SET (CMAKE_D_FLAGS_MINSIZEREL_INIT "-Os ${DDOC_FLAGS}")
|
||||
SET (CMAKE_D_FLAGS_RELEASE_INIT "-O ${DDOC_FLAGS}")
|
||||
SET (CMAKE_D_FLAGS_RELWITHDEBINFO_INIT "-O -g -L--export-dynamic ${DDOC_FLAGS}")
|
||||
# SET (CMAKE_D_CREATE_PREPROCESSED_SOURCE "<CMAKE_D_COMPILER> <FLAGS> -E <SOURCE> > <PREPROCESSED_SOURCE>")
|
||||
SET (CMAKE_D_CREATE_ASSEMBLY_SOURCE "<CMAKE_D_COMPILER> <FLAGS> -S <SOURCE> -of<ASSEMBLY_SOURCE>")
|
||||
# SET (CMAKE_INCLUDE_SYSTEM_FLAG_D "-isystem ")
|
|
@ -1,41 +0,0 @@
|
|||
#
|
||||
# CMakeD - CMake module for D Language
|
||||
#
|
||||
# Copyright (c) 2007, Selman Ulug <selman.ulug@gmail.com>
|
||||
# Tim Burrell <tim.burrell@gmail.com>
|
||||
#
|
||||
# All rights reserved.
|
||||
#
|
||||
# See LICENSE for details.
|
||||
#
|
||||
# Modified from CMake 2.6.5 gcc.cmake
|
||||
# See http://www.cmake.org/HTML/Copyright.html for details
|
||||
#
|
||||
|
||||
SET(CMAKE_D_DASH_O "-o")
|
||||
SET(CMAKE_BASE_NAME gdc)
|
||||
|
||||
IF(CMAKE_D_USE_TANGO)
|
||||
SET(DSTDLIB_FLAGS "-fversion=Tango")
|
||||
ENDIF(CMAKE_D_USE_TANGO)
|
||||
IF(CMAKE_D_USE_PHOBOS)
|
||||
SET(DSTDLIB_FLAGS "-fversion=Phobos")
|
||||
ENDIF(CMAKE_D_USE_PHOBOS)
|
||||
IF(CMAKE_D_BUILD_DOCS)
|
||||
SET(DDOC_FLAGS "-fdoc -fdoc-dir=documentation")
|
||||
FOREACH(item ${CMAKE_D_DDOC_FILES})
|
||||
SET(DDOC_FLAGS "${DDOC_FLAGS} -fdoc-inc=${item}")
|
||||
ENDFOREACH(item)
|
||||
ENDIF(CMAKE_D_BUILD_DOCS)
|
||||
|
||||
#SET (CMAKE_D_FLAGS_INIT "-fversion=Posix -fversion=${CMAKE_BUILD_TYPE}Build ${DSTDLIB_FLAGS}")
|
||||
SET (CMAKE_D_FLAGS_INIT "")
|
||||
SET (CMAKE_D_FLAGS_DEBUG_INIT "-g ${DDOC_FLAGS}")
|
||||
SET (CMAKE_D_FLAGS_MINSIZEREL_INIT "-Os ${DDOC_FLAGS}")
|
||||
SET (CMAKE_D_FLAGS_RELEASE_INIT "-O3 -fomit-frame-pointer -fweb -frelease -finline-functions ${DDOC_FLAGS}")
|
||||
SET (CMAKE_D_FLAGS_RELWITHDEBINFO_INIT "-O2 -g ${DDOC_FLAGS}")
|
||||
# SET (CMAKE_D_CREATE_PREPROCESSED_SOURCE "<CMAKE_D_COMPILER> <FLAGS> -E <SOURCE> > <PREPROCESSED_SOURCE>")
|
||||
SET (CMAKE_D_CREATE_ASSEMBLY_SOURCE "<CMAKE_D_COMPILER> <FLAGS> -S <SOURCE> -o <ASSEMBLY_SOURCE>")
|
||||
#SET (CMAKE_INCLUDE_SYSTEM_FLAG_D "-isystem ")
|
||||
|
||||
SET(CMAKE_INCLUDE_FLAG_D "-I") # -I
|
|
@ -1,63 +0,0 @@
|
|||
#
|
||||
# CMakeD - CMake module for D Language
|
||||
#
|
||||
# Copyright (c) 2007, Selman Ulug <selman.ulug@gmail.com>
|
||||
# Tim Burrell <tim.burrell@gmail.com>
|
||||
#
|
||||
# All rights reserved.
|
||||
#
|
||||
# See LICENSE for details.
|
||||
#
|
||||
# Modified from CMake 2.6.5 gcc.cmake
|
||||
# See http://www.cmake.org/HTML/Copyright.html for details
|
||||
#
|
||||
|
||||
#SET(DSTDLIB_FLAGS "-version=Phobos")
|
||||
IF(CMAKE_D_BUILD_DOCS)
|
||||
SET(DDOC_FLAGS "-D -Dddocumentation")
|
||||
#FOREACH(item ${CMAKE_D_DDOC_FILES})
|
||||
# SET(DDOC_FLAGS "${DDOC_FLAGS} ${item}")
|
||||
#ENDFOREACH(item)
|
||||
ENDIF(CMAKE_D_BUILD_DOCS)
|
||||
|
||||
SET(CMAKE_D_OUTPUT_EXTENSION .o)
|
||||
SET(CMAKE_D_DASH_O "-of")
|
||||
SET(CMAKE_BASE_NAME ldc2)
|
||||
|
||||
SET(CMAKE_STATIC_LIBRARY_CREATE_D_FLAGS "-lib")
|
||||
|
||||
SET(CMAKE_SHARED_LIBRARY_D_FLAGS "") # -pic
|
||||
SET(CMAKE_SHARED_LIBRARY_CREATE_D_FLAGS "-shared") # -shared
|
||||
SET(CMAKE_SHARED_LIBRARY_LINK_D_FLAGS "") # +s, flag for exe link to use shared lib
|
||||
SET(CMAKE_SHARED_LIBRARY_RUNTIME_D_FLAG "") # -rpath
|
||||
SET(CMAKE_SHARED_LIBRARY_RUNTIME_D_FLAG_SEP "") # : or empty
|
||||
SET(CMAKE_INCLUDE_FLAG_D "-I") # -I
|
||||
SET(CMAKE_INCLUDE_FLAG_D_SEP "") # , or empty
|
||||
SET(CMAKE_LIBRARY_PATH_FLAG "-L-L")
|
||||
SET(CMAKE_LIBRARY_PATH_TERMINATOR "") # for the Digital Mars D compiler the link paths have to be terminated with a "/"
|
||||
SET(CMAKE_LINK_LIBRARY_FLAG "-L-l")
|
||||
|
||||
SET(CMAKE_LINK_LIBRARY_SUFFIX "")
|
||||
SET(CMAKE_STATIC_LIBRARY_PREFIX "lib")
|
||||
SET(CMAKE_STATIC_LIBRARY_SUFFIX ".a")
|
||||
SET(CMAKE_SHARED_LIBRARY_PREFIX "lib") # lib
|
||||
SET(CMAKE_SHARED_LIBRARY_SUFFIX ".so") # .so
|
||||
SET(CMAKE_EXECUTABLE_SUFFIX "") # .exe
|
||||
SET(CMAKE_DL_LIBS "dl")
|
||||
|
||||
SET(CMAKE_FIND_LIBRARY_PREFIXES "lib")
|
||||
SET(CMAKE_FIND_LIBRARY_SUFFIXES ".so" ".a")
|
||||
|
||||
#SET(CMAKE_D_STDLIBS "-L-lphobos2 -L-lpthread -L-lm" )
|
||||
|
||||
#SET (CMAKE_D_FLAGS_INIT "-version=${CMAKE_BUILD_TYPE}Build ${DSTDLIB_FLAGS} ${DSTDLIB_TYPE} -I$ENV{D_PATH}/include -I$ENV{D_PATH}/import -I${CMAKE_PROJECT_SOURCE_DIR}")
|
||||
SET (CMAKE_D_FLAGS_INIT "")
|
||||
# DMD can only produce 32-bit binaries for now
|
||||
SET (CMAKE_D_LINK_FLAGS "")
|
||||
SET (CMAKE_D_FLAGS_DEBUG_INIT "-g -debug -L--export-dynamic ${DDOC_FLAGS}")
|
||||
SET (CMAKE_D_FLAGS_MINSIZEREL_INIT "-Os ${DDOC_FLAGS}")
|
||||
SET (CMAKE_D_FLAGS_RELEASE_INIT "-O -release -inline ${DDOC_FLAGS}")
|
||||
SET (CMAKE_D_FLAGS_RELWITHDEBINFO_INIT "-O -g -L--export-dynamic ${DDOC_FLAGS}")
|
||||
# SET (CMAKE_D_CREATE_PREPROCESSED_SOURCE "<CMAKE_D_COMPILER> <FLAGS> -E <SOURCE> > <PREPROCESSED_SOURCE>")
|
||||
SET (CMAKE_D_CREATE_ASSEMBLY_SOURCE "<CMAKE_D_COMPILER> <FLAGS> -S <SOURCE> -of<ASSEMBLY_SOURCE>")
|
||||
# SET (CMAKE_INCLUDE_SYSTEM_FLAG_D "-isystem ")
|
|
@ -1,56 +0,0 @@
|
|||
#
|
||||
# CMakeD - CMake module for D Language
|
||||
#
|
||||
# Copyright (c) 2007, Selman Ulug <selman.ulug@gmail.com>
|
||||
# Tim Burrell <tim.burrell@gmail.com>
|
||||
#
|
||||
# All rights reserved.
|
||||
#
|
||||
# See LICENSE for details.
|
||||
#
|
||||
# Modified from CMake 2.6.5 gcc.cmake
|
||||
# See http://www.cmake.org/HTML/Copyright.html for details
|
||||
#
|
||||
|
||||
#SET(DSTDLIB_FLAGS "-version=Phobos")
|
||||
IF(CMAKE_D_BUILD_DOCS)
|
||||
SET(DDOC_FLAGS "-D -Dddocumentation")
|
||||
#FOREACH(item ${CMAKE_D_DDOC_FILES})
|
||||
# SET(DDOC_FLAGS "${DDOC_FLAGS} ${item}")
|
||||
#ENDFOREACH(item)
|
||||
ENDIF(CMAKE_D_BUILD_DOCS)
|
||||
|
||||
SET(CMAKE_D_OUTPUT_EXTENSION .obj)
|
||||
SET(CMAKE_D_DASH_O "-of")
|
||||
SET(CMAKE_BASE_NAME dmd)
|
||||
|
||||
SET(CMAKE_STATIC_LIBRARY_CREATE_D_FLAGS "-lib")
|
||||
|
||||
SET(CMAKE_SHARED_LIBRARY_D_FLAGS "") # -pic
|
||||
SET(CMAKE_SHARED_LIBRARY_CREATE_D_FLAGS "-shared") # -shared
|
||||
SET(CMAKE_SHARED_LIBRARY_LINK_D_FLAGS "") # +s, flag for exe link to use shared lib
|
||||
SET(CMAKE_SHARED_LIBRARY_RUNTIME_D_FLAG "") # -rpath
|
||||
SET(CMAKE_SHARED_LIBRARY_RUNTIME_D_FLAG_SEP "") # : or empty
|
||||
SET(CMAKE_INCLUDE_FLAG_D "-I") # -I
|
||||
SET(CMAKE_INCLUDE_FLAG_D_SEP "") # , or empty
|
||||
SET(CMAKE_LIBRARY_PATH_FLAG "-L-L")
|
||||
SET(CMAKE_LIBRARY_PATH_TERMINATOR "") # for the Digital Mars D compiler the link paths have to be terminated with a "/"
|
||||
|
||||
SET(CMAKE_LINK_LIBRARY_FLAG "-L-l")
|
||||
SET(CMAKE_STATIC_LIBRARY_PREFIX "") #
|
||||
SET(CMAKE_STATIC_LIBRARY_SUFFIX ".lib") # lib
|
||||
SET(CMAKE_SHARED_LIBRARY_PREFIX "") #
|
||||
SET(CMAKE_SHARED_LIBRARY_SUFFIX ".dll") # .dll
|
||||
SET(CMAKE_EXECUTABLE_SUFFIX ".exe") # .exe
|
||||
SET(CMAKE_DL_LIBS "dl")
|
||||
|
||||
SET(CMAKE_FIND_LIBRARY_PREFIXES "")
|
||||
SET(CMAKE_FIND_LIBRARY_SUFFIXES ".lib" ".dll")
|
||||
|
||||
SET (CMAKE_D_FLAGS_INIT "")
|
||||
# DMD can only produce 32-bit binaries for now
|
||||
SET (CMAKE_D_LINK_FLAGS "")
|
||||
SET (CMAKE_D_FLAGS_DEBUG_INIT "-g -debug ${DDOC_FLAGS}")
|
||||
SET (CMAKE_D_FLAGS_RELEASE_INIT "-O -release -inline ${DDOC_FLAGS}")
|
||||
SET (CMAKE_D_FLAGS_RELWITHDEBINFO_INIT "-O -g ${DDOC_FLAGS}")
|
||||
SET (CMAKE_D_CREATE_ASSEMBLY_SOURCE "<CMAKE_D_COMPILER> <FLAGS> -S <SOURCE> -of<ASSEMBLY_SOURCE>")
|
|
@ -1,35 +0,0 @@
|
|||
#
|
||||
# CMakeD - CMake module for D Language
|
||||
#
|
||||
# Copyright (c) 2007, Selman Ulug <selman.ulug@gmail.com>
|
||||
# Tim Burrell <tim.burrell@gmail.com>
|
||||
#
|
||||
# All rights reserved.
|
||||
#
|
||||
# See LICENSE for details.
|
||||
#
|
||||
# Modified from CMake 2.6.5 gcc.cmake
|
||||
# See http://www.cmake.org/HTML/Copyright.html for details
|
||||
#
|
||||
|
||||
IF(CMAKE_D_USE_TANGO)
|
||||
SET(DSTDLIB_FLAGS "-fversion=Tango")
|
||||
ENDIF(CMAKE_D_USE_TANGO)
|
||||
IF(CMAKE_D_USE_PHOBOS)
|
||||
SET(DSTDLIB_FLAGS "-fversion=Phobos")
|
||||
ENDIF(CMAKE_D_USE_PHOBOS)
|
||||
IF(CMAKE_D_BUILD_DOCS)
|
||||
SET(DDOC_FLAGS "-fdoc -fdoc-dir=documentation")
|
||||
FOREACH(item ${CMAKE_D_DDOC_FILES})
|
||||
SET(DDOC_FLAGS "${DDOC_FLAGS} -fdoc-inc=${item}")
|
||||
ENDFOREACH(item)
|
||||
ENDIF(CMAKE_D_BUILD_DOCS)
|
||||
|
||||
SET (CMAKE_D_FLAGS_INIT "-fversion=Win -fversion=${CMAKE_BUILD_TYPE}Build ${DSTDLIB_FLAGS}")
|
||||
SET (CMAKE_D_FLAGS_DEBUG_INIT "-g ${DDOC_FLAGS}")
|
||||
SET (CMAKE_D_FLAGS_MINSIZEREL_INIT "-Os ${DDOC_FLAGS}")
|
||||
SET (CMAKE_D_FLAGS_RELEASE_INIT "-O3 -fomit-frame-pointer -fweb -frelease -finline-functions ${DDOC_FLAGS}")
|
||||
SET (CMAKE_D_FLAGS_RELWITHDEBINFO_INIT "-O2 -g ${DDOC_FLAGS}")
|
||||
# SET (CMAKE_D_CREATE_PREPROCESSED_SOURCE "<CMAKE_D_COMPILER> <FLAGS> -E <SOURCE> > <PREPROCESSED_SOURCE>")
|
||||
SET (CMAKE_D_CREATE_ASSEMBLY_SOURCE "<CMAKE_D_COMPILER> <FLAGS> -S <SOURCE> -o <ASSEMBLY_SOURCE>")
|
||||
#SET (CMAKE_INCLUDE_SYSTEM_FLAG_D "-isystem ")
|
|
@ -1,64 +0,0 @@
|
|||
# Dependency tracking for D
|
||||
#
|
||||
# Copyright (c) 2010 Jens Mueller <jens.k.mueller@gmx.de>
|
||||
#
|
||||
# All rights reserved.
|
||||
#
|
||||
# See LICENSE for details.
|
||||
#
|
||||
|
||||
macro(add_executable_with_dependencies _target)
|
||||
# extract D source files from arguments
|
||||
foreach(file ${ARGV})
|
||||
if(${file} MATCHES "\\.d$")
|
||||
list(APPEND d_source_files ${file})
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
#message("D files in arguments: ${d_source_files}")
|
||||
|
||||
foreach(file IN LISTS d_source_files)
|
||||
set(source_file "${CMAKE_CURRENT_SOURCE_DIR}/${file}")
|
||||
set(dependency_file "${CMAKE_CURRENT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/${file}-depend.cmake")
|
||||
set(dependency_files ${dependency_files} ${dependency_file})
|
||||
|
||||
#message("Checking dependencies for ${source_file}")
|
||||
#message("Put into ${dependency_file}")
|
||||
# TODO
|
||||
# better way to get the included directories
|
||||
get_directory_property(include_dirs INCLUDE_DIRECTORIES)
|
||||
set(INCLUDES )
|
||||
foreach(include_dir IN LISTS include_dirs)
|
||||
list(APPEND INCLUDES "${CMAKE_INCLUDE_FLAG_D}${include_dir}")
|
||||
endforeach()
|
||||
|
||||
execute_process(
|
||||
COMMAND ${CMAKE_COMMAND}
|
||||
-D "CMAKE_D_COMPILER:STRING=${CMAKE_D_COMPILER}"
|
||||
-D "CMAKE_D_FLAGS:STRING=${CMAKE_D_FLAGS}"
|
||||
-D "include_directories:STRING=${INCLUDES}"
|
||||
-D "source_file:STRING=${source_file}"
|
||||
-D "dependency_file:STRING=${dependency_file}"
|
||||
-P "${CMAKE_ROOT}/Modules/dependencies.cmake" # TODO hard coded path
|
||||
)
|
||||
|
||||
# load dependencies from file
|
||||
include(${dependency_file})
|
||||
#message("DEPENDENCIES ${D_DMD_DEPEND}")
|
||||
|
||||
add_custom_command(
|
||||
OUTPUT ${dependency_file}
|
||||
DEPENDS ${D_DMD_DEPEND}
|
||||
COMMAND ${CMAKE_COMMAND}
|
||||
-D "CMAKE_D_COMPILER:STRING=${CMAKE_D_COMPILER}"
|
||||
-D "CMAKE_D_FLAGS:STRING=${CMAKE_D_FLAGS}"
|
||||
-D "include_directories:STRING=${INCLUDES}"
|
||||
-D "source_file:STRING=${source_file}"
|
||||
-D "dependency_file:STRING=${dependency_file}"
|
||||
-P "${CMAKE_ROOT}/Modules/dependencies.cmake" # TODO hard coded path
|
||||
COMMENT "Scanning for dependencies"
|
||||
)
|
||||
endforeach()
|
||||
|
||||
add_executable(${ARGV} ${dependency_files})
|
||||
endmacro(add_executable_with_dependencies)
|
|
@ -1,73 +0,0 @@
|
|||
# check if the user wants to build ddocs
|
||||
#
|
||||
# Copyright (c) 2007 Tim Burrell <tim.burrell@gmail.com>
|
||||
#
|
||||
# All rights reserved.
|
||||
#
|
||||
# See LICENSE for details.
|
||||
#
|
||||
|
||||
# Do not build documentation by default
|
||||
if (NOT CMAKE_D_BUILD_DOCS)
|
||||
set(CMAKE_D_BUILD_DOCS False CACHE BOOLEAN TRUE FORCE)
|
||||
else (NOT CMAKE_D_BUILD_DOCS)
|
||||
# check for specified ddoc files
|
||||
# default to the candydoc usual
|
||||
set(CMAKE_D_BUILD_DOCS True CACHE BOOLEAN FALSE FORCE)
|
||||
if (NOT CMAKE_D_DDOC_FILES)
|
||||
set(CMAKE_D_DDOC_FILES "documentation/candydoc/candy.ddoc;documentation/candydoc/modules.ddoc" CACHE STRING FALSE FORCE)
|
||||
else (NOT CMAKE_D_DDOC_FILES)
|
||||
set(CMAKE_D_DDOC_FILES "${CMAKE_D_DDOC_FILES}" CACHE STRING FALSE FORCE)
|
||||
endif (NOT CMAKE_D_DDOC_FILES)
|
||||
|
||||
# copy the candydoc files
|
||||
file(GLOB_RECURSE CANDY_DOC_FILES "${CMAKE_CURRENT_SOURCE_DIR}/candydoc/*")
|
||||
foreach(item ${CANDY_DOC_FILES})
|
||||
string(REGEX REPLACE "${CMAKE_CURRENT_SOURCE_DIR}/" "" item ${item})
|
||||
configure_file(${item} ${CMAKE_CURRENT_BINARY_DIR}/documentation/${item} COPYONLY)
|
||||
endforeach(item)
|
||||
|
||||
# create modules.ddoc
|
||||
file(GLOB_RECURSE sources "${CMAKE_CURRENT_SOURCE_DIR}/*.d")
|
||||
set(first True)
|
||||
foreach(item ${sources})
|
||||
# first make sure we're not config.d
|
||||
string(REGEX MATCH "config\\.d" ignore ${item})
|
||||
if (NOT ${ignore} MATCHES "")
|
||||
# fix up the output
|
||||
string(REGEX REPLACE "${CMAKE_CURRENT_SOURCE_DIR}/" "" item ${item})
|
||||
string(REGEX REPLACE "\\.d" ".html" htmlFile ${item})
|
||||
string(REGEX REPLACE "^.*/" "" htmlFile ${htmlFile})
|
||||
string(REGEX REPLACE "\\.d" "" item ${item})
|
||||
string(REGEX REPLACE "/" "." item ${item})
|
||||
if (first)
|
||||
set(modules "${item}")
|
||||
set(first False)
|
||||
set(CMAKE_D_DDOC_CLEAN_FILES "${CMAKE_CURRENT_BINARY_DIR}/documentation/${htmlFile}" CACHE STRING FALSE FORCE)
|
||||
else (first)
|
||||
set(modules "${modules};${item}")
|
||||
set(CMAKE_D_DDOC_CLEAN_FILES "${CMAKE_D_DDOC_CLEAN_FILES}" "${CMAKE_CURRENT_BINARY_DIR}/documentation/${htmlFile}" CACHE STRING FALSE FORCE)
|
||||
endif (first)
|
||||
endif (NOT ${ignore} MATCHES "")
|
||||
endforeach(item)
|
||||
|
||||
# create formatted modules string
|
||||
set(modString "MODULES = \n")
|
||||
foreach(item ${modules})
|
||||
set(modString "${modString}\t$(MODULE ${item})\n")
|
||||
endforeach(item)
|
||||
file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/documentation/candydoc/modules.ddoc" ${modString})
|
||||
|
||||
# create index.html
|
||||
set(modString "<html><head><title>${PROJECT_NAME} API Documentation</title></head><body>\n")
|
||||
set(modString "<h>${PROJECT_NAME} API Documentation:<br /></h>\n")
|
||||
set(modString "${modString}<ul>\n")
|
||||
foreach(item ${modules})
|
||||
string(REGEX REPLACE "[a-z0-9]*\\." "" filename ${item})
|
||||
set(modString "${modString}\t<li> <a href=\"${filename}.html\">${item}</a> </li>\n")
|
||||
endforeach(item)
|
||||
set(modString "${modString}</ul>\n")
|
||||
set(modString "${modString}</body></html>\n")
|
||||
file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/documentation/index.html" ${modString})
|
||||
endif (NOT CMAKE_D_BUILD_DOCS)
|
||||
|
|
@ -1,37 +0,0 @@
|
|||
# Adding D unittests
|
||||
#
|
||||
# Copyright (c) 2010 Jens Mueller <jens.k.mueller@gmx.de>
|
||||
#
|
||||
# All rights reserved.
|
||||
#
|
||||
# See LICENSE for details.
|
||||
#
|
||||
|
||||
macro(add_unittests _sourcefile)
|
||||
|
||||
set(_testname "${_sourcefile}")
|
||||
set(main_unittest "${CMAKE_CURRENT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/unittest.d")
|
||||
set(_source_file "${CMAKE_CURRENT_SOURCE_DIR}/${_sourcefile}")
|
||||
|
||||
#message("main_unittest ${main_unittest}")
|
||||
#message("testname ${_testname}")
|
||||
#message("_sourcefile ${_source_file}")
|
||||
|
||||
if(NOT EXISTS ${main_unittest})
|
||||
file(WRITE ${main_unittest} "// Generated by UseDUnittest.cmake\nint main() { return 0; }")
|
||||
endif()
|
||||
|
||||
# TODO
|
||||
# better way to get the included directories
|
||||
get_directory_property(include_dirs INCLUDE_DIRECTORIES)
|
||||
set(INCLUDES )
|
||||
foreach(include_dir IN LISTS include_dirs)
|
||||
list(APPEND INCLUDES "${CMAKE_INCLUDE_FLAG_D}${include_dir}")
|
||||
endforeach()
|
||||
|
||||
separate_arguments(CMAKE_D_FLAGS)
|
||||
|
||||
add_test(NAME ${_testname}
|
||||
COMMAND ${CMAKE_D_COMPILER} ${CMAKE_D_FLAGS} ${INCLUDES} ${main_unittest} -unittest -run ${_source_file})
|
||||
|
||||
endmacro(add_unittests)
|
|
@ -1,84 +0,0 @@
|
|||
# This modules add functions for downloading and building dub dependencies.
|
||||
# This code sets the following variables and functions:
|
||||
#
|
||||
# DUB_DIRECTORY = the full path to Dub pacakges
|
||||
#
|
||||
# DubProject_Add(<dub_package> [version])
|
||||
#
|
||||
#============================================================================
|
||||
# Copyright (c) 2014 Dragos Carp <dragos.carp@gmail.com>
|
||||
#
|
||||
# All rights reserved.
|
||||
#
|
||||
# See LICENSE for details.
|
||||
#
|
||||
|
||||
if(NOT DUB_DIRECTORY)
|
||||
set(DUB_DIRECTORY ${CMAKE_BINARY_DIR}/UseDub CACHE PATH "Dub packages directory")
|
||||
endif(NOT DUB_DIRECTORY)
|
||||
|
||||
set(DUB_REGISTRY "http://code.dlang.org/packages")
|
||||
file(MAKE_DIRECTORY ${DUB_DIRECTORY}/CMakeTmp)
|
||||
|
||||
if(NOT CMAKE_D_COMPILER)
|
||||
message(FATAL_ERROR "UseDub needs a D compiler or use it in a D project.")
|
||||
endif(NOT CMAKE_D_COMPILER)
|
||||
|
||||
#compile json parsers
|
||||
if(NOT EXISTS ${DUB_DIRECTORY}/CMakeTmp/DubUrl)
|
||||
find_file(DUB_GET_PACKAGE_URL_D_SRC "DubUrl.d"
|
||||
PATHS ${CMAKE_ROOT}/Modules ${CMAKE_MODULE_PATH} NO_DEFAULT_PATH
|
||||
PATH_SUFFIXES "UseDub")
|
||||
find_file(SEMVER_SRC "semver.d"
|
||||
PATHS ${CMAKE_ROOT}/Modules ${CMAKE_MODULE_PATH} NO_DEFAULT_PATH
|
||||
PATH_SUFFIXES "UseDub")
|
||||
get_filename_component(SEMVER_PATH ${SEMVER_SRC} PATH)
|
||||
execute_process(COMMAND ${CMAKE_D_COMPILER} -I${SEMVER_PATH} ${DUB_GET_PACKAGE_URL_D_SRC} ${SEMVER_SRC}
|
||||
WORKING_DIRECTORY ${DUB_DIRECTORY}/CMakeTmp)
|
||||
unset(DUB_GET_PACKAGE_URL_D_SRC CACHE)
|
||||
endif(NOT EXISTS ${DUB_DIRECTORY}/CMakeTmp/DubUrl)
|
||||
if(NOT EXISTS ${DUB_DIRECTORY}/CMakeTmp/DubToCMake)
|
||||
find_file(DUB_PACKAGE_TO_CMAKE_D_SRC "DubToCMake.d"
|
||||
PATHS ${CMAKE_ROOT}/Modules ${CMAKE_MODULE_PATH} NO_DEFAULT_PATH
|
||||
PATH_SUFFIXES "UseDub")
|
||||
execute_process(COMMAND ${CMAKE_D_COMPILER} ${DUB_PACKAGE_TO_CMAKE_D_SRC}
|
||||
WORKING_DIRECTORY ${DUB_DIRECTORY}/CMakeTmp)
|
||||
unset(DUB_PACKAGE_TO_CMAKE_D_SRC CACHE)
|
||||
endif(NOT EXISTS ${DUB_DIRECTORY}/CMakeTmp/DubToCMake)
|
||||
|
||||
include(ExternalProject)
|
||||
|
||||
function(DubProject_Add name)
|
||||
if(NOT EXISTS ${DUB_DIRECTORY}/${name}.json)
|
||||
file(DOWNLOAD ${DUB_REGISTRY}/${name}.json ${DUB_DIRECTORY}/${name}.json STATUS status)
|
||||
list(GET status 0 statusCode)
|
||||
|
||||
if(NOT statusCode EQUAL 0)
|
||||
file(REMOVE ${DUB_DIRECTORY}/${name}.json)
|
||||
message(FATAL_ERROR "Failed to download ${DUB_REGISTRY}/${name}.json")
|
||||
endif(NOT statusCode EQUAL 0)
|
||||
endif(NOT EXISTS ${DUB_DIRECTORY}/${name}.json)
|
||||
|
||||
if(${ARGC} GREATER 1)
|
||||
execute_process(COMMAND ${DUB_DIRECTORY}/CMakeTmp/DubUrl -p ${name}.json -t ${ARGN}
|
||||
WORKING_DIRECTORY ${DUB_DIRECTORY})
|
||||
else(${ARGC} GREATER 1)
|
||||
execute_process(COMMAND ${DUB_DIRECTORY}/CMakeTmp/DubUrl -p ${name}.json
|
||||
WORKING_DIRECTORY ${DUB_DIRECTORY})
|
||||
endif(${ARGC} GREATER 1)
|
||||
|
||||
include(${DUB_DIRECTORY}/${name}.cmake)
|
||||
|
||||
ExternalProject_Add(${name}
|
||||
DOWNLOAD_DIR ${DUB_DIRECTORY}/archive/${name}
|
||||
SOURCE_DIR ${DUB_DIRECTORY}/source/${name}
|
||||
URL ${DUB_PACKAGE_URL}
|
||||
PATCH_COMMAND ${DUB_DIRECTORY}/CMakeTmp/DubToCMake -p package.json
|
||||
INSTALL_DIR ${DUB_DIRECTORY}/export
|
||||
CMAKE_CACHE_ARGS
|
||||
-DCMAKE_MODULE_PATH:PATH=${CMAKE_MODULE_PATH}
|
||||
-DCMAKE_INSTALL_PREFIX:PATH=<INSTALL_DIR>
|
||||
-DDUB_DIRECTORY:PATH=${DUB_DIRECTORY})
|
||||
|
||||
include_directories(${DUB_DIRECTORY}/source/${name}/source ${DUB_DIRECTORY}/source/${name}/src)
|
||||
endfunction()
|
|
@ -1,103 +0,0 @@
|
|||
import std.file;
|
||||
import std.getopt;
|
||||
import std.json;
|
||||
import std.stdio;
|
||||
import std.string;
|
||||
|
||||
int main(string[] args)
|
||||
{
|
||||
string dubFile = "dub.json";
|
||||
string cmakeFile = "CMakeLists.txt";
|
||||
|
||||
getopt(args,
|
||||
"package|p", &dubFile,
|
||||
"output|o", &cmakeFile);
|
||||
|
||||
if (!exists(dubFile))
|
||||
{
|
||||
stderr.writefln("Cannot find file: '%s'", dubFile);
|
||||
return -1;
|
||||
}
|
||||
|
||||
string json = readText(dubFile);
|
||||
JSONValue root = parseJSON(json);
|
||||
string target = root["targetName"].str;
|
||||
|
||||
string cmake = q"<
|
||||
cmake_minimum_required(VERSION 2.8)
|
||||
|
||||
project(%1$s D)
|
||||
|
||||
find_file(APP_MAIN_FILE
|
||||
NAMES app.d main.d %1$s/main.d %1$s/app.d
|
||||
PATHS source src NO_DEFAULT_PATH)
|
||||
|
||||
file(GLOB_RECURSE SRC_FILES source/*.d src/*.d)
|
||||
if(APP_MAIN_FILE)
|
||||
list(REMOVE_ITEM SRC_FILES ${APP_MAIN_FILE})
|
||||
endif(APP_MAIN_FILE)
|
||||
|
||||
include_directories(source src)
|
||||
>".format(root["name"].str);
|
||||
|
||||
switch ("targetType" in root.object ? root["targetType"].str : "autodetect")
|
||||
{
|
||||
case "autodetect":
|
||||
cmake ~= q"<
|
||||
if(APP_MAIN_FILE)
|
||||
add_executable(%1$s ${SRC_FILES} ${APP_MAIN_FILE})
|
||||
else(APP_MAIN_FILE)
|
||||
add_library(%1$s ${SRC_FILES})
|
||||
endif(APP_MAIN_FILE)
|
||||
>".format(target);
|
||||
break;
|
||||
case "none":
|
||||
break;
|
||||
case "executable":
|
||||
cmake ~= q"<
|
||||
add_executable(%s ${SRC_FILES} ${APP_MAIN_FILE})
|
||||
>".format(target);
|
||||
break;
|
||||
case "library":
|
||||
cmake ~= q"<
|
||||
add_library(%s ${SRC_FILES})
|
||||
>".format(target);
|
||||
break;
|
||||
case "sourceLibrary":
|
||||
break;
|
||||
case "staticLibrary":
|
||||
cmake ~= q"<
|
||||
add_library(%s STATIC ${SRC_FILES})
|
||||
>".format(target);
|
||||
break;
|
||||
case "dynamicLibrary":
|
||||
cmake ~= q"<
|
||||
add_library(%s SHARED ${SRC_FILES})
|
||||
>".format(target);
|
||||
break;
|
||||
default:
|
||||
assert(false, "Unknown targetType");
|
||||
break;
|
||||
}
|
||||
|
||||
cmake ~= q"<
|
||||
install(TARGETS %s
|
||||
RUNTIME DESTINATION bin
|
||||
LIBRARY DESTINATION lib
|
||||
ARCHIVE DESTINATION lib)
|
||||
>".format(target);
|
||||
|
||||
if ("dependencies" in root.object)
|
||||
{
|
||||
cmake ~= "\ninclude(UseDub)\n";
|
||||
foreach (dependency, version_; root["dependencies"].object)
|
||||
{
|
||||
cmake ~= "DubProject_Add(%s %s)\n".format(dependency, version_.str);
|
||||
}
|
||||
cmake ~= "\nadd_dependencies(%s %-(%s %))\n".format(target, root["dependencies"].object.keys);
|
||||
}
|
||||
|
||||
std.file.write(cmakeFile, cmake);
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -1,158 +0,0 @@
|
|||
import std.algorithm;
|
||||
import std.array;
|
||||
import std.file;
|
||||
import std.getopt;
|
||||
import std.json;
|
||||
import std.stdio;
|
||||
import std.string;
|
||||
import semver;
|
||||
|
||||
/**
|
||||
* Finds the best match of $(D range) in $(D choices) versions list.
|
||||
*
|
||||
* Params:
|
||||
* range = Match criteria.
|
||||
* choices = Versions list it is matched against.
|
||||
*
|
||||
* Returns:
|
||||
* Best match in $(D choices) or empty string if no match is found.
|
||||
*
|
||||
* See_Also:
|
||||
* $(WEB https://github.com/npm/npm/blob/master/doc/misc/semver.md#ranges Ranges definition)
|
||||
*/
|
||||
string matchVersion(string range, string[] choices)
|
||||
{
|
||||
foreach (ref choice; choices)
|
||||
{
|
||||
choice.skipOver('~');
|
||||
}
|
||||
|
||||
if (range.skipOver('~'))
|
||||
{
|
||||
foreach (choice; choices)
|
||||
{
|
||||
if (choice.startsWith(range))
|
||||
return choice;
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
unittest
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
int main(string[] args)
|
||||
{
|
||||
string registryFile = "";
|
||||
string packageVersion = "";
|
||||
bool listVersions;
|
||||
string outputPath = ".";
|
||||
|
||||
getopt(args,
|
||||
"package|p", ®istryFile,
|
||||
"tag|t", &packageVersion,
|
||||
"list|l", &listVersions,
|
||||
"output|o", &outputPath);
|
||||
|
||||
if (registryFile.empty)
|
||||
{
|
||||
stderr.writeln("Package registry file (<package_name>.json) need to be specified.");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!exists(registryFile) && !registryFile.endsWith(".json"))
|
||||
registryFile ~= ".json";
|
||||
|
||||
if (!exists(registryFile))
|
||||
{
|
||||
stderr.writefln("Package registry file '%s' not found.", registryFile);
|
||||
return -1;
|
||||
}
|
||||
|
||||
string json = readText(registryFile);
|
||||
JSONValue node;
|
||||
JSONValue root = parseJSON(json);
|
||||
|
||||
if (packageVersion.empty)
|
||||
{
|
||||
packageVersion = "*";
|
||||
}
|
||||
|
||||
auto versionRange = SemVerRange(packageVersion);
|
||||
|
||||
if (!versionRange.valid)
|
||||
{
|
||||
// try exact string match
|
||||
auto range = root["versions"].array.find!`a["version"].str == b`(packageVersion);
|
||||
if (!range.empty)
|
||||
{
|
||||
node = range[0];
|
||||
}
|
||||
else
|
||||
{
|
||||
stderr.writefln("%s has no version tagged %s.", root["name"].str, packageVersion);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
string nodeVersionString(JSONValue node)
|
||||
{
|
||||
auto ver = node["version"].str;
|
||||
ver.skipOver('~');
|
||||
return ver;
|
||||
}
|
||||
|
||||
auto nodes = root["versions"].array.filter!(a => SemVer(nodeVersionString(a)).valid).array;
|
||||
auto maxVersion = nodes.map!(a => SemVer(nodeVersionString(a))).array.maxSatisfying(versionRange);
|
||||
|
||||
if (maxVersion.valid)
|
||||
{
|
||||
auto range = nodes.find!((a, b) => SemVer(nodeVersionString(a)) == b)(maxVersion);
|
||||
assert(!range.empty);
|
||||
node = range[0];
|
||||
}
|
||||
else
|
||||
{
|
||||
stderr.writefln("%s has no version %s.", root["name"].str, versionRange);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (registryFile.endsWith(".json"))
|
||||
{
|
||||
registryFile = registryFile[0..$-5];
|
||||
}
|
||||
|
||||
if (listVersions)
|
||||
{
|
||||
writefln("Package '%s'", registryFile);
|
||||
|
||||
foreach(n; root["versions"].array)
|
||||
{
|
||||
writefln(" %s => %s", n["version"].str, n["downloadUrl"].str);
|
||||
}
|
||||
}
|
||||
|
||||
packageVersion = node["version"].str;
|
||||
auto packageUrl = node["downloadUrl"].str;
|
||||
auto packageName = root["name"].str;
|
||||
|
||||
if (!outputPath.isDir)
|
||||
{
|
||||
stderr.writefln("Output path '%s' need to be a directory.", outputPath);
|
||||
return -1;
|
||||
}
|
||||
|
||||
string output = "set(DUB_PACKAGE_NAME, \"%s\")\n".format(packageName) ~
|
||||
"set(DUB_PACKAGE_VERSION \"%s\")\n".format(packageVersion) ~
|
||||
"set(DUB_PACKAGE_URL \"%s\")\n".format(packageUrl);
|
||||
|
||||
std.file.write(outputPath ~ "/" ~ packageName ~ ".cmake", output);
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -1,612 +0,0 @@
|
|||
import std.algorithm;
|
||||
import std.array;
|
||||
import std.conv;
|
||||
import std.range;
|
||||
import std.regex;
|
||||
import std.stdio;
|
||||
import std.string;
|
||||
|
||||
enum ReleaseType
|
||||
{
|
||||
MAJOR,
|
||||
MINOR,
|
||||
PATCH,
|
||||
PRERELEASE,
|
||||
};
|
||||
|
||||
struct SemVer
|
||||
{
|
||||
uint[3] ids;
|
||||
string[] prerelease;
|
||||
string[] build;
|
||||
|
||||
bool isValid;
|
||||
|
||||
@disable this();
|
||||
|
||||
this(string semVer)
|
||||
{
|
||||
isValid = false;
|
||||
if (semVer.empty)
|
||||
return;
|
||||
if (!semVer.skipOver('v'))
|
||||
semVer.skipOver('=');
|
||||
|
||||
auto re = regex(`^(\d+)(?:\.(\d+))?(?:\.(\d+))?(?:-([a-zA-Z\d-.]+))?(?:\+([a-zA-Z\d-.]+))?$`);
|
||||
auto m = semVer.matchAll(re);
|
||||
if (m.empty)
|
||||
return;
|
||||
|
||||
foreach (i, ref id; ids)
|
||||
{
|
||||
if (!m.captures[i+1].empty)
|
||||
id = m.captures[i+1].to!uint;
|
||||
}
|
||||
|
||||
if (!m.captures[4].empty)
|
||||
{
|
||||
prerelease = m.captures[4].splitter('.').array;
|
||||
if (prerelease.any!empty)
|
||||
return;
|
||||
}
|
||||
|
||||
if (!m.captures[5].empty)
|
||||
{
|
||||
build = m.captures[5].splitter('.').array;
|
||||
if (build.any!empty)
|
||||
return;
|
||||
}
|
||||
|
||||
isValid = true;
|
||||
}
|
||||
|
||||
string toString() const
|
||||
{
|
||||
if (!isValid)
|
||||
return "<invalid_semver>";
|
||||
|
||||
string semVer = "%(%s.%)".format(ids);
|
||||
if (!prerelease.empty)
|
||||
semVer ~= "-" ~ "%-(%s.%)".format(prerelease);
|
||||
if (!build.empty)
|
||||
semVer ~= "+" ~ "%-(%s.%)".format(build);
|
||||
return semVer;
|
||||
}
|
||||
|
||||
@property bool valid() const
|
||||
{
|
||||
return isValid;
|
||||
}
|
||||
|
||||
SemVer inc(ReleaseType releaseType) const
|
||||
in
|
||||
{
|
||||
assert(this.valid);
|
||||
}
|
||||
out(result)
|
||||
{
|
||||
assert(result.valid);
|
||||
}
|
||||
body
|
||||
{
|
||||
SemVer result = "0";
|
||||
foreach (i; 0..releaseType)
|
||||
result.ids[i] = this.ids[i];
|
||||
if (releaseType != ReleaseType.PRERELEASE)
|
||||
result.ids[releaseType] = this.ids[releaseType]+1;
|
||||
return result;
|
||||
}
|
||||
|
||||
SemVer appendPrerelease0()
|
||||
{
|
||||
if (prerelease.empty)
|
||||
prerelease ~= "0";
|
||||
return this;
|
||||
}
|
||||
|
||||
unittest
|
||||
{
|
||||
assert(SemVer("1.2.3").inc(ReleaseType.MAJOR) == SemVer("2.0.0"));
|
||||
assert(SemVer("1.2.3").inc(ReleaseType.MINOR) == SemVer("1.3.0"));
|
||||
assert(SemVer("1.2.3-alpha").inc(ReleaseType.MINOR) == SemVer("1.3.0"));
|
||||
assert(SemVer("1.2.3").inc(ReleaseType.PATCH) == SemVer("1.2.4"));
|
||||
assert(SemVer("1.2.3-alpha").inc(ReleaseType.PATCH) == SemVer("1.2.4"));
|
||||
assert(SemVer("1.2.3").inc(ReleaseType.PRERELEASE) == SemVer("1.2.3"));
|
||||
assert(SemVer("1.2.3-alpha").inc(ReleaseType.PRERELEASE) == SemVer("1.2.3"));
|
||||
}
|
||||
|
||||
int opCmp(ref const SemVer v) const
|
||||
in
|
||||
{
|
||||
assert(this.valid);
|
||||
assert(v.valid);
|
||||
}
|
||||
body
|
||||
{
|
||||
foreach (i; 0..ids.length)
|
||||
{
|
||||
if (ids[i] != v.ids[i])
|
||||
return ids[i] < v.ids[i] ? -1 : 1;
|
||||
}
|
||||
|
||||
if (!prerelease.empty && v.prerelease.empty)
|
||||
return -1;
|
||||
if (prerelease.empty && !v.prerelease.empty)
|
||||
return 1;
|
||||
|
||||
foreach (a, b; lockstep(prerelease, v.prerelease))
|
||||
{
|
||||
if (a.isNumeric && b.isNumeric)
|
||||
{
|
||||
if (a.to!uint != b.to!uint)
|
||||
return a.to!uint < b.to!uint ? -1 : 1;
|
||||
else
|
||||
continue;
|
||||
}
|
||||
if (a != b)
|
||||
return a < b ? -1 : 1;
|
||||
}
|
||||
if (prerelease.length != v.prerelease.length)
|
||||
return prerelease.length < v.prerelease.length ? -1 : 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int opCmp(const SemVer v) const
|
||||
{
|
||||
return this.opCmp(v);
|
||||
}
|
||||
|
||||
bool opEquals(ref const SemVer v) const
|
||||
{
|
||||
return this.opCmp(v) == 0;
|
||||
}
|
||||
|
||||
bool opEquals(const SemVer v) const
|
||||
{
|
||||
return this.opEquals(v);
|
||||
}
|
||||
}
|
||||
|
||||
unittest
|
||||
{
|
||||
assert(!SemVer("1.2-.alpha.32").valid);
|
||||
assert(!SemVer("1.2-alpha+").valid);
|
||||
assert(!SemVer("1.2-alpha_").valid);
|
||||
assert(!SemVer("1.2+32.").valid);
|
||||
assert(!SemVer("1.2.5.6").valid);
|
||||
assert(!SemVer("").valid);
|
||||
assert(SemVer("1.0.0-alpha") < SemVer("1.0.0-alpha.1"));
|
||||
assert(SemVer("1.0.0-alpha.1") < SemVer("1.0.0-alpha.beta"));
|
||||
assert(SemVer("1.0.0-alpha.beta") < SemVer("1.0.0-beta"));
|
||||
assert(SemVer("1.0.0-beta") < SemVer("1.0.0-beta.2"));
|
||||
assert(SemVer("1.0.0-beta.2") < SemVer("1.0.0-beta.11"));
|
||||
assert(SemVer("1.0.0-beta.11") < SemVer("1.0.0-rc.1"));
|
||||
assert(SemVer("1.0.0-rc.1") < SemVer("1.0.0"));
|
||||
assert(SemVer("1.0.0-rc.1") == SemVer("1.0.0-rc.1+build.5"));
|
||||
}
|
||||
|
||||
struct SemVerRange
|
||||
{
|
||||
struct SimpleRange
|
||||
{
|
||||
string op;
|
||||
SemVer semVer;
|
||||
|
||||
string toString() const
|
||||
{
|
||||
return op ~ semVer.toString;
|
||||
}
|
||||
}
|
||||
|
||||
SimpleRange[][] ranges;
|
||||
|
||||
invariant()
|
||||
{
|
||||
assert(ranges.all!(r => r.all!(r => ["<", "<=", "=", ">=", ">"].canFind(r.op))));
|
||||
}
|
||||
|
||||
bool isValid;
|
||||
|
||||
@disable this();
|
||||
|
||||
this(string semVerRange)
|
||||
{
|
||||
isValid = false;
|
||||
auto re = regex(`(~|~>|\^|<|<=|=|>=|>)?[v]?(\d+|\*|X|x)(?:\.(\d+|\*|X|x))?(?:\.(\d+|\*|X|x))?([\S]*)`);
|
||||
|
||||
ranges = [SimpleRange[].init];
|
||||
|
||||
while (!semVerRange.stripLeft.empty)
|
||||
{
|
||||
auto m = semVerRange.matchFirst(re);
|
||||
if (m.empty)
|
||||
return;
|
||||
|
||||
auto operator = m.captures[1];
|
||||
auto wildcard = wildcardAt([m.captures[2], m.captures[3], m.captures[4]]);
|
||||
auto expanded = expand([m.captures[2], m.captures[3], m.captures[4], m.captures[5]]);
|
||||
if (expanded.empty)
|
||||
return;
|
||||
|
||||
auto semVer = SemVer(expanded);
|
||||
if (!semVer.valid)
|
||||
return;
|
||||
|
||||
switch (m.captures.pre.strip)
|
||||
{
|
||||
case "":
|
||||
break;
|
||||
case "-":
|
||||
if (ranges[$-1].empty || ranges[$-1][$-1].op != "=" ||
|
||||
operator != "" || wildcard != ReleaseType.PRERELEASE)
|
||||
return;
|
||||
ranges[$-1][$-1].op = ">=";
|
||||
operator = "<=";
|
||||
break;
|
||||
case "||":
|
||||
ranges ~= SimpleRange[].init;
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
switch (operator)
|
||||
{
|
||||
case "":
|
||||
case "=":
|
||||
final switch (wildcard)
|
||||
{
|
||||
case ReleaseType.MAJOR:
|
||||
assert(semVer == SemVer("0.0.0"));
|
||||
ranges[$-1] ~= SimpleRange(">=", semVer.appendPrerelease0);
|
||||
break;
|
||||
case ReleaseType.MINOR:
|
||||
case ReleaseType.PATCH:
|
||||
ranges[$-1] ~= SimpleRange(">=", semVer.appendPrerelease0);
|
||||
ranges[$-1] ~= SimpleRange("<", semVer.inc(--wildcard).appendPrerelease0);
|
||||
break;
|
||||
case ReleaseType.PRERELEASE:
|
||||
ranges[$-1] ~= SimpleRange("=", semVer);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case "<":
|
||||
ranges[$-1] ~= SimpleRange(operator, semVer.appendPrerelease0);
|
||||
break;
|
||||
case "<=":
|
||||
case ">=":
|
||||
case ">":
|
||||
if (wildcard < ReleaseType.PRERELEASE)
|
||||
semVer.appendPrerelease0;
|
||||
ranges[$-1] ~= SimpleRange(operator, semVer);
|
||||
break;
|
||||
case "~":
|
||||
final switch (wildcard)
|
||||
{
|
||||
case ReleaseType.MAJOR:
|
||||
return;
|
||||
case ReleaseType.MINOR:
|
||||
case ReleaseType.PATCH:
|
||||
--wildcard;
|
||||
break;
|
||||
case ReleaseType.PRERELEASE:
|
||||
--wildcard;
|
||||
--wildcard;
|
||||
break;
|
||||
}
|
||||
ranges[$-1] ~= SimpleRange(">=", semVer.appendPrerelease0);
|
||||
ranges[$-1] ~= SimpleRange("<", semVer.inc(wildcard).appendPrerelease0);
|
||||
break;
|
||||
case "~>":
|
||||
final switch (wildcard)
|
||||
{
|
||||
case ReleaseType.MAJOR:
|
||||
return;
|
||||
case ReleaseType.MINOR:
|
||||
--wildcard;
|
||||
break;
|
||||
case ReleaseType.PATCH:
|
||||
case ReleaseType.PRERELEASE:
|
||||
--wildcard;
|
||||
--wildcard;
|
||||
break;
|
||||
}
|
||||
ranges[$-1] ~= SimpleRange(">=", semVer.appendPrerelease0);
|
||||
ranges[$-1] ~= SimpleRange("<", semVer.inc(wildcard).appendPrerelease0);
|
||||
break;
|
||||
case "^":
|
||||
if (wildcard == ReleaseType.MAJOR || !semVer.prerelease.empty)
|
||||
return;
|
||||
if (semVer.ids[ReleaseType.MAJOR] != 0)
|
||||
{
|
||||
ranges[$-1] ~= SimpleRange(">=", semVer.appendPrerelease0);
|
||||
ranges[$-1] ~= SimpleRange("<", semVer.inc(ReleaseType.MAJOR).appendPrerelease0);
|
||||
}
|
||||
else if (semVer.ids[ReleaseType.MINOR] != 0)
|
||||
{
|
||||
ranges[$-1] ~= SimpleRange(">=", semVer.appendPrerelease0);
|
||||
ranges[$-1] ~= SimpleRange("<", semVer.inc(ReleaseType.MINOR).appendPrerelease0);
|
||||
}
|
||||
else
|
||||
{
|
||||
ranges[$-1] ~= SimpleRange(">=", semVer.appendPrerelease0);
|
||||
ranges[$-1] ~= SimpleRange("<", semVer.inc(ReleaseType.PATCH).appendPrerelease0);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
assert(0);
|
||||
break;
|
||||
}
|
||||
semVerRange = m.captures.post;
|
||||
}
|
||||
isValid = true;
|
||||
}
|
||||
|
||||
private static ReleaseType wildcardAt(string[3] semVer)
|
||||
{
|
||||
foreach (i; ReleaseType.MAJOR..ReleaseType.PRERELEASE)
|
||||
{
|
||||
if (["", "*", "X", "x"].canFind(semVer[i]))
|
||||
return i;
|
||||
}
|
||||
return ReleaseType.PRERELEASE;
|
||||
}
|
||||
|
||||
unittest
|
||||
{
|
||||
assert(wildcardAt(["*", "", ""]) == ReleaseType.MAJOR);
|
||||
assert(wildcardAt(["X", "", ""]) == ReleaseType.MAJOR);
|
||||
assert(wildcardAt(["1", "", ""]) == ReleaseType.MINOR);
|
||||
assert(wildcardAt(["1", "x", ""]) == ReleaseType.MINOR);
|
||||
assert(wildcardAt(["1", "2", ""]) == ReleaseType.PATCH);
|
||||
assert(wildcardAt(["1", "2", "x"]) == ReleaseType.PATCH);
|
||||
assert(wildcardAt(["1", "2", "3"]) == ReleaseType.PRERELEASE);
|
||||
}
|
||||
|
||||
private static string expand(string[4] semVer)
|
||||
{
|
||||
ReleaseType wildcard = wildcardAt(semVer[0..3]);
|
||||
if (wildcard != ReleaseType.PRERELEASE)
|
||||
{
|
||||
if (semVer[wildcard+1..$].any!`!["", "*", "X", "x"].canFind(a)`)
|
||||
return "";
|
||||
foreach (j; wildcard..ReleaseType.PRERELEASE)
|
||||
semVer[j] = "0";
|
||||
}
|
||||
string result = "%-(%s.%)".format(semVer[0..3]);
|
||||
if (!semVer[3].empty)
|
||||
result ~= semVer[3];
|
||||
return result;
|
||||
}
|
||||
|
||||
unittest
|
||||
{
|
||||
assert(expand(["*", "", "", ""]) == "0.0.0");
|
||||
assert(expand(["X", "", "", ""]) == "0.0.0");
|
||||
assert(expand(["1", "2", "3", ""]) == "1.2.3");
|
||||
assert(expand(["1", "2", "3", "-abc"]) == "1.2.3-abc");
|
||||
assert(expand(["1", "2", "", ""]) == "1.2.0");
|
||||
assert(expand(["1", "2", "", "-abc"]) == "");
|
||||
assert(expand(["1", "2", "x", ""]) == "1.2.0");
|
||||
assert(expand(["1", "", "", ""]) == "1.0.0");
|
||||
assert(expand(["1", "x", "", ""]) == "1.0.0");
|
||||
}
|
||||
|
||||
string toString() const
|
||||
{
|
||||
if (!isValid)
|
||||
return "<invalid_semver_range>";
|
||||
|
||||
return "%(%(%s %) || %)".format(ranges);
|
||||
}
|
||||
|
||||
@property bool valid() const
|
||||
{
|
||||
return isValid;
|
||||
}
|
||||
|
||||
private static bool simpleRangeSatisfiedBy(SimpleRange simpleRange, SemVer semVer)
|
||||
in
|
||||
{
|
||||
assert(semVer.valid);
|
||||
assert(["<", "<=", "=", ">=", ">"].canFind(simpleRange.op));
|
||||
assert(simpleRange.semVer.valid);
|
||||
}
|
||||
body
|
||||
{
|
||||
switch (simpleRange.op)
|
||||
{
|
||||
case "<":
|
||||
return semVer < simpleRange.semVer;
|
||||
case "<=":
|
||||
return semVer <= simpleRange.semVer;
|
||||
case "=":
|
||||
return semVer == simpleRange.semVer;
|
||||
case ">=":
|
||||
return semVer >= simpleRange.semVer;
|
||||
case ">":
|
||||
return semVer > simpleRange.semVer;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool satisfiedBy(SemVer semVer)
|
||||
in
|
||||
{
|
||||
assert(semVer.valid);
|
||||
assert(valid);
|
||||
}
|
||||
body
|
||||
{
|
||||
return ranges.any!(r => r.all!(s => simpleRangeSatisfiedBy(s, semVer)));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
bool satisfies(SemVer semVer, SemVerRange semVerRange)
|
||||
{
|
||||
return semVerRange.satisfiedBy(semVer);
|
||||
}
|
||||
|
||||
SemVer maxSatisfying(SemVer[] semVers, SemVerRange semVerRange)
|
||||
in
|
||||
{
|
||||
assert(semVers.all!"a.valid");
|
||||
assert(semVerRange.valid);
|
||||
}
|
||||
body
|
||||
{
|
||||
auto found = semVers.sort!"a > b".find!(a => satisfies(a, semVerRange));
|
||||
return found.empty ? SemVer("invalid") : found[0];
|
||||
}
|
||||
|
||||
unittest
|
||||
{
|
||||
assert(SemVerRange("1.x || >=2.5.0 || 5.0.0 - 7.2.3").valid);
|
||||
assert(!SemVerRange("blerg").valid);
|
||||
assert(!SemVerRange("git+https://user:password0123@github.com/foo").valid);
|
||||
|
||||
assert(SemVer("1.2.3").satisfies(SemVerRange("1.x || >=2.5.0 || 5.0.0 - 7.2.3")));
|
||||
|
||||
assert(SemVer("1.2.3").satisfies(SemVerRange("1.0.0 - 2.0.0")));
|
||||
assert(SemVer("1.0.0").satisfies(SemVerRange("1.0.0")));
|
||||
assert(SemVer("0.2.4").satisfies(SemVerRange(">=*")));
|
||||
assert(SemVer("1.2.3").satisfies(SemVerRange("*")));
|
||||
assert(SemVer("v1.2.3-foo").satisfies(SemVerRange("*")));
|
||||
assert(SemVer("1.0.0").satisfies(SemVerRange(">=1.0.0")));
|
||||
assert(SemVer("1.0.1").satisfies(SemVerRange(">=1.0.0")));
|
||||
assert(SemVer("1.1.0").satisfies(SemVerRange(">=1.0.0")));
|
||||
assert(SemVer("1.0.1").satisfies(SemVerRange(">1.0.0")));
|
||||
assert(SemVer("1.1.0").satisfies(SemVerRange(">1.0.0")));
|
||||
assert(SemVer("2.0.0").satisfies(SemVerRange("<=2.0.0")));
|
||||
assert(SemVer("1.9999.9999").satisfies(SemVerRange("<=2.0.0")));
|
||||
assert(SemVer("0.2.9").satisfies(SemVerRange("<=2.0.0")));
|
||||
assert(SemVer("1.9999.9999").satisfies(SemVerRange("<2.0.0")));
|
||||
assert(SemVer("0.2.9").satisfies(SemVerRange("<2.0.0")));
|
||||
assert(SemVer("1.0.0").satisfies(SemVerRange(">=1.0.0")));
|
||||
assert(SemVer("1.0.1").satisfies(SemVerRange(">=1.0.0")));
|
||||
assert(SemVer("1.1.0").satisfies(SemVerRange(">=1.0.0")));
|
||||
assert(SemVer("1.0.1").satisfies(SemVerRange(">1.0.0")));
|
||||
assert(SemVer("1.1.0").satisfies(SemVerRange(">1.0.0")));
|
||||
assert(SemVer("2.0.0").satisfies(SemVerRange("<=2.0.0")));
|
||||
assert(SemVer("1.9999.9999").satisfies(SemVerRange("<=2.0.0")));
|
||||
assert(SemVer("0.2.9").satisfies(SemVerRange("<=2.0.0")));
|
||||
assert(SemVer("1.9999.9999").satisfies(SemVerRange("<2.0.0")));
|
||||
assert(SemVer("0.2.9").satisfies(SemVerRange("<2.0.0")));
|
||||
assert(SemVer("v0.1.97").satisfies(SemVerRange(">=0.1.97")));
|
||||
assert(SemVer("0.1.97").satisfies(SemVerRange(">=0.1.97")));
|
||||
assert(SemVer("1.2.4").satisfies(SemVerRange("0.1.20 || 1.2.4")));
|
||||
assert(SemVer("0.0.0").satisfies(SemVerRange(">=0.2.3 || <0.0.1")));
|
||||
assert(SemVer("0.2.3").satisfies(SemVerRange(">=0.2.3 || <0.0.1")));
|
||||
assert(SemVer("0.2.4").satisfies(SemVerRange(">=0.2.3 || <0.0.1")));
|
||||
assert(SemVer("2.1.3").satisfies(SemVerRange("2.x.x")));
|
||||
assert(SemVer("1.2.3").satisfies(SemVerRange("1.2.x")));
|
||||
assert(SemVer("2.1.3").satisfies(SemVerRange("1.2.x || 2.x")));
|
||||
assert(SemVer("1.2.3").satisfies(SemVerRange("1.2.x || 2.x")));
|
||||
assert(SemVer("1.2.3").satisfies(SemVerRange("x")));
|
||||
assert(SemVer("2.1.3").satisfies(SemVerRange("2.*.*")));
|
||||
assert(SemVer("1.2.3").satisfies(SemVerRange("1.2.*")));
|
||||
assert(SemVer("2.1.3").satisfies(SemVerRange("1.2.* || 2.*")));
|
||||
assert(SemVer("1.2.3").satisfies(SemVerRange("1.2.* || 2.*")));
|
||||
assert(SemVer("1.2.3").satisfies(SemVerRange("*")));
|
||||
assert(SemVer("2.1.2").satisfies(SemVerRange("2")));
|
||||
assert(SemVer("2.3.1").satisfies(SemVerRange("2.3")));
|
||||
assert(SemVer("2.4.0").satisfies(SemVerRange("~2.4")));
|
||||
assert(SemVer("2.4.5").satisfies(SemVerRange("~2.4")));
|
||||
assert(SemVer("3.2.2").satisfies(SemVerRange("~>3.2.1")));
|
||||
assert(SemVer("1.2.3").satisfies(SemVerRange("~1")));
|
||||
assert(SemVer("1.2.3").satisfies(SemVerRange("~>1")));
|
||||
assert(SemVer("1.0.2").satisfies(SemVerRange("~1.0")));
|
||||
assert(SemVer("1.0.12").satisfies(SemVerRange("~1.0.3")));
|
||||
assert(SemVer("1.0.0").satisfies(SemVerRange(">=1")));
|
||||
assert(SemVer("1.1.1").satisfies(SemVerRange("<1.2")));
|
||||
assert(SemVer("1.1.9").satisfies(SemVerRange("<=1.2")));
|
||||
assert(SemVer("1.0.0-bet").satisfies(SemVerRange("1")));
|
||||
assert(SemVer("0.5.5").satisfies(SemVerRange("~v0.5.4-pre")));
|
||||
assert(SemVer("0.5.4").satisfies(SemVerRange("~v0.5.4-pre")));
|
||||
assert(SemVer("0.7.2").satisfies(SemVerRange("=0.7.x")));
|
||||
assert(SemVer("0.7.2").satisfies(SemVerRange(">=0.7.x")));
|
||||
assert(SemVer("0.7.0-asdf").satisfies(SemVerRange("=0.7.x")));
|
||||
assert(SemVer("0.7.0-asdf").satisfies(SemVerRange(">=0.7.x")));
|
||||
assert(SemVer("0.6.2").satisfies(SemVerRange("<=0.7.x")));
|
||||
assert(SemVer("1.2.3").satisfies(SemVerRange("~1.2.1 >=1.2.3")));
|
||||
assert(SemVer("1.2.3").satisfies(SemVerRange("~1.2.1 =1.2.3")));
|
||||
assert(SemVer("1.2.3").satisfies(SemVerRange("~1.2.1 1.2.3")));
|
||||
assert(SemVer("1.2.3").satisfies(SemVerRange("~1.2.1 >=1.2.3 1.2.3")));
|
||||
assert(SemVer("1.2.3").satisfies(SemVerRange("~1.2.1 1.2.3 >=1.2.3")));
|
||||
assert(SemVer("1.2.3").satisfies(SemVerRange("~1.2.1 1.2.3")));
|
||||
assert(SemVer("1.2.3").satisfies(SemVerRange(">=1.2.1 1.2.3")));
|
||||
assert(SemVer("1.2.3").satisfies(SemVerRange("1.2.3 >=1.2.1")));
|
||||
assert(SemVer("1.2.3").satisfies(SemVerRange(">=1.2.3 >=1.2.1")));
|
||||
assert(SemVer("1.2.3").satisfies(SemVerRange(">=1.2.1 >=1.2.3")));
|
||||
assert(SemVer("1.2.3-beta").satisfies(SemVerRange("<=1.2.3")));
|
||||
assert(SemVer("1.3.0-beta").satisfies(SemVerRange(">1.2")));
|
||||
assert(SemVer("1.2.8").satisfies(SemVerRange(">=1.2")));
|
||||
assert(SemVer("1.8.1").satisfies(SemVerRange("^1.2.3")));
|
||||
assert(SemVer("1.2.3-beta").satisfies(SemVerRange("^1.2.3")));
|
||||
assert(SemVer("0.1.2").satisfies(SemVerRange("^0.1.2")));
|
||||
assert(SemVer("0.1.2").satisfies(SemVerRange("^0.1")));
|
||||
assert(SemVer("1.4.2").satisfies(SemVerRange("^1.2")));
|
||||
assert(SemVer("1.4.2").satisfies(SemVerRange("^1.2 ^1")));
|
||||
assert(SemVer("1.2.0-pre").satisfies(SemVerRange("^1.2")));
|
||||
assert(SemVer("1.2.3-pre").satisfies(SemVerRange("^1.2.3")));
|
||||
|
||||
assert(!SemVer("2.2.3").satisfies(SemVerRange("1.0.0 - 2.0.0")));
|
||||
assert(!SemVer("1.0.1").satisfies(SemVerRange("1.0.0")));
|
||||
assert(!SemVer("0.0.0").satisfies(SemVerRange(">=1.0.0")));
|
||||
assert(!SemVer("0.0.1").satisfies(SemVerRange(">=1.0.0")));
|
||||
assert(!SemVer("0.1.0").satisfies(SemVerRange(">=1.0.0")));
|
||||
assert(!SemVer("0.0.1").satisfies(SemVerRange(">1.0.0")));
|
||||
assert(!SemVer("0.1.0").satisfies(SemVerRange(">1.0.0")));
|
||||
assert(!SemVer("3.0.0").satisfies(SemVerRange("<=2.0.0")));
|
||||
assert(!SemVer("2.9999.9999").satisfies(SemVerRange("<=2.0.0")));
|
||||
assert(!SemVer("2.2.9").satisfies(SemVerRange("<=2.0.0")));
|
||||
assert(!SemVer("2.9999.9999").satisfies(SemVerRange("<2.0.0")));
|
||||
assert(!SemVer("2.2.9").satisfies(SemVerRange("<2.0.0")));
|
||||
assert(!SemVer("v0.1.93").satisfies(SemVerRange(">=0.1.97")));
|
||||
assert(!SemVer("0.1.93").satisfies(SemVerRange(">=0.1.97")));
|
||||
assert(!SemVer("1.2.3").satisfies(SemVerRange("0.1.20 || 1.2.4")));
|
||||
assert(!SemVer("0.0.3").satisfies(SemVerRange(">=0.2.3 || <0.0.1")));
|
||||
assert(!SemVer("0.2.2").satisfies(SemVerRange(">=0.2.3 || <0.0.1")));
|
||||
assert(!SemVer("1.1.3").satisfies(SemVerRange("2.x.x")));
|
||||
assert(!SemVer("3.1.3").satisfies(SemVerRange("2.x.x")));
|
||||
assert(!SemVer("1.3.3").satisfies(SemVerRange("1.2.x")));
|
||||
assert(!SemVer("3.1.3").satisfies(SemVerRange("1.2.x || 2.x")));
|
||||
assert(!SemVer("1.1.3").satisfies(SemVerRange("1.2.x || 2.x")));
|
||||
assert(!SemVer("1.1.3").satisfies(SemVerRange("2.*.*")));
|
||||
assert(!SemVer("3.1.3").satisfies(SemVerRange("2.*.*")));
|
||||
assert(!SemVer("1.3.3").satisfies(SemVerRange("1.2.*")));
|
||||
assert(!SemVer("3.1.3").satisfies(SemVerRange("1.2.* || 2.*")));
|
||||
assert(!SemVer("1.1.3").satisfies(SemVerRange("1.2.* || 2.*")));
|
||||
assert(!SemVer("1.1.2").satisfies(SemVerRange("2")));
|
||||
assert(!SemVer("2.4.1").satisfies(SemVerRange("2.3")));
|
||||
assert(!SemVer("2.5.0").satisfies(SemVerRange("~2.4")));
|
||||
assert(!SemVer("2.3.9").satisfies(SemVerRange("~2.4")));
|
||||
assert(!SemVer("3.3.2").satisfies(SemVerRange("~>3.2.1")));
|
||||
assert(!SemVer("3.2.0").satisfies(SemVerRange("~>3.2.1")));
|
||||
assert(!SemVer("0.2.3").satisfies(SemVerRange("~1")));
|
||||
assert(!SemVer("2.2.3").satisfies(SemVerRange("~>1")));
|
||||
assert(!SemVer("1.1.0").satisfies(SemVerRange("~1.0")));
|
||||
assert(!SemVer("1.0.0").satisfies(SemVerRange("<1")));
|
||||
assert(!SemVer("1.1.1").satisfies(SemVerRange(">=1.2")));
|
||||
assert(!SemVer("1.3.0").satisfies(SemVerRange("<=1.2")));
|
||||
assert(!SemVer("2.0.0-beta").satisfies(SemVerRange("1")));
|
||||
assert(!SemVer("0.5.4-alpha").satisfies(SemVerRange("~v0.5.4-beta")));
|
||||
assert(!SemVer("1.0.0-beta").satisfies(SemVerRange("<1")));
|
||||
assert(!SemVer("0.8.2").satisfies(SemVerRange("=0.7.x")));
|
||||
assert(!SemVer("0.6.2").satisfies(SemVerRange(">=0.7.x")));
|
||||
assert(!SemVer("0.7.2").satisfies(SemVerRange("<=0.7.x")));
|
||||
assert(!SemVer("1.2.3-beta").satisfies(SemVerRange("<1.2.3")));
|
||||
assert(!SemVer("1.2.3-beta").satisfies(SemVerRange("=1.2.3")));
|
||||
assert(!SemVer("1.2.8").satisfies(SemVerRange(">1.3")));
|
||||
assert(!SemVer("2.0.0-alpha").satisfies(SemVerRange("^1.2.3")));
|
||||
assert(!SemVer("1.2.2").satisfies(SemVerRange("^1.2.3")));
|
||||
assert(!SemVer("1.1.9").satisfies(SemVerRange("^1.2")));
|
||||
assert(!SemVer("2.0.0-pre").satisfies(SemVerRange("^1.2.3")));
|
||||
|
||||
auto semVers = [SemVer("0.8.0"), SemVer("1.0.0"), SemVer("1.1.0")];
|
||||
assert(semVers.maxSatisfying(SemVerRange("<=1.0.0")) == SemVer("1.0.0"));
|
||||
assert(semVers.maxSatisfying(SemVerRange(">=1.0")) == SemVer("1.1.0"));
|
||||
}
|
|
@ -1,52 +0,0 @@
|
|||
#message("Adding dependencies")
|
||||
|
||||
#message("CMAKE_D_FLAGS: ${CMAKE_D_FLAGS} ")
|
||||
#message("CMAKE_D_COMPILER: ${CMAKE_D_COMPILER} ")
|
||||
#message("include_directories: ${include_directories} ")
|
||||
#message("source file ${source_file}")
|
||||
#message("dependency file ${dependency_file}")
|
||||
|
||||
separate_arguments(CMAKE_D_FLAGS)
|
||||
|
||||
# TODO
|
||||
# need to pass all arguments that are used for building
|
||||
# can't I use the build rule somehow
|
||||
execute_process(COMMAND ${CMAKE_D_COMPILER} ${CMAKE_D_FLAGS} ${include_directories} -deps=${dependency_file}.tmp -o- ${source_file})
|
||||
#message("executing: ${CMAKE_D_COMPILER} ${CMAKE_D_FLAGS} ${include_directories} -deps=${dependency_file}.tmp -o- ${source_file}")
|
||||
|
||||
if(NOT EXISTS ${dependency_file})
|
||||
file(WRITE ${dependency_file} "# Generated by: ${CMAKE_CURRENT_LIST_FILE}\nSET(D_DMD_DEPEND\n)\n\n")
|
||||
endif()
|
||||
|
||||
file(READ ${dependency_file}.tmp depend_text)
|
||||
#message("DEPENDENCIES: ${depend_text}")
|
||||
|
||||
# extract dependencies
|
||||
string(REGEX MATCHALL "\\([^)]*\\)" out ${depend_text})
|
||||
string(REGEX MATCHALL "[^()]+" out ${out})
|
||||
list(REMOVE_DUPLICATES out)
|
||||
list(SORT out)
|
||||
|
||||
foreach(file ${out})
|
||||
set(dependencies "${dependencies} \"${file}\"\n")
|
||||
endforeach()
|
||||
|
||||
# write new dependencies to temporary file
|
||||
file(WRITE ${dependency_file}.tmp "# Generated by: ${CMAKE_CURRENT_LIST_FILE}\nSET(D_DMD_DEPEND\n ${dependencies})\n\n")
|
||||
|
||||
# get old dependencies
|
||||
include(${dependency_file})
|
||||
set(old_dependencies ${D_DMD_DEPEND})
|
||||
# and the new dependencies from temporary file
|
||||
include(${dependency_file}.tmp)
|
||||
|
||||
# did the dependencies change?
|
||||
if(NOT "${D_DMD_DEPEND}" STREQUAL "${old_dependencies}")
|
||||
message("Dependencies changed. Need to build.")
|
||||
execute_process(COMMAND ${CMAKE_COMMAND} -E touch ${source_file})
|
||||
endif()
|
||||
|
||||
execute_process(COMMAND ${CMAKE_COMMAND} -E copy ${dependency_file}.tmp ${dependency_file})
|
||||
execute_process(COMMAND ${CMAKE_COMMAND} -E remove ${dependency_file}.tmp)
|
||||
|
||||
#message("Finished dependencies")
|
|
@ -1,5 +0,0 @@
|
|||
cmake_minimum_required(VERSION 3.0)
|
||||
list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake/Nim)
|
||||
include(${CMAKE_CURRENT_SOURCE_DIR}/cmake/Nim/UseNim.cmake)
|
||||
find_package(Nim)
|
||||
add_subdirectory(Examples)
|
|
@ -1,304 +0,0 @@
|
|||
:Authors:
|
||||
Filippo Cucchetto <filippocucchetto@gmail.com>
|
||||
|
||||
Will Szumski <will@cowboycoders.org>
|
||||
:Version: 0.3.0
|
||||
:Date: 2015/02/15
|
||||
|
||||
Introduction
|
||||
-----------
|
||||
The NimQml module adds Qt Qml bindings to the Nim programming language
|
||||
allowing you to create new modern UI by mixing the Qml declarative syntax
|
||||
and the Nim imperative language.
|
||||
|
||||
The NimQml is made by two components:
|
||||
* The DOtherSide C++ shared library
|
||||
* The NimQml Nim module
|
||||
|
||||
This first component implements the glue code necessary for
|
||||
communicating with the Qt C++ library, the latter module wraps
|
||||
the libDOtherSide exported symbols in Nim
|
||||
|
||||
Building
|
||||
--------
|
||||
At the time of writing the DOtherSide C++ library must be compiled
|
||||
and installed manually from source.
|
||||
|
||||
First clone the DOtherSide git repo
|
||||
::
|
||||
git clone https://github.com/filcuc/DOtherSide
|
||||
|
||||
than you can proceed with the common CMake build steps
|
||||
|
||||
::
|
||||
mkdir build
|
||||
cd build
|
||||
cmake ..
|
||||
make
|
||||
|
||||
If everything goes correctly, you'll have built both
|
||||
the DOtherSide C++ library and the Nim examples
|
||||
|
||||
Installation
|
||||
----------
|
||||
The installation is not mandatory, in fact you could try
|
||||
the built Nim example in the following way
|
||||
::
|
||||
cd path/to/build/dir
|
||||
cd Nim/Examples/HelloWorld
|
||||
export LD_LIBRARY_PATH=path/to/libDOtherSide.so
|
||||
./HelloWorld
|
||||
|
||||
The DOtherSide project is made of two components
|
||||
1. The DOtherSide C++ lib
|
||||
2. The NimQml module
|
||||
|
||||
You can procede with the installation of the C++ library
|
||||
in the following way
|
||||
::
|
||||
cd to/build/dir
|
||||
make install
|
||||
or by manually copying the library in your system lib directory
|
||||
::
|
||||
sudo cp build/dir/path/DOtherSide/libDOtherSide.so /usr/lib
|
||||
|
||||
For the NimQml module you can use the ``nimble`` package manager
|
||||
::
|
||||
nimble install NimQml
|
||||
|
||||
or
|
||||
::
|
||||
cd to/build/dir/Nim/NimQml
|
||||
nimble install
|
||||
|
||||
|
||||
Example 1: HelloWorld
|
||||
----------
|
||||
As usual lets start with an HelloWorld example.
|
||||
Most of the NimQml projects are made by one or more nim and qml
|
||||
files. Usually the .nim files contains your app logic and data
|
||||
layer. The qml files contain the presentation layer and expose
|
||||
the data in your nim files.
|
||||
|
||||
``Examples/HelloWorld/main.nim``
|
||||
|
||||
.. code-block:: nim
|
||||
:file: ../Examples/HelloWorld/main.nim
|
||||
|
||||
``Examples/HelloWorld/main.qml``
|
||||
|
||||
.. code-block:: qml
|
||||
:file: ../Examples/HelloWorld/main.qml
|
||||
|
||||
The following example shows the basic steps of each NimQml app
|
||||
1. Create the QApplication for initializing the Qt runtime
|
||||
2. Create the QQmlApplicationEngine and load your main .qml file
|
||||
3. Call the ``exec`` proc of the QApplication instance for starting
|
||||
the Qt event loop
|
||||
|
||||
Example 2: exposing data to Qml
|
||||
------------------------------------
|
||||
The previous example shown you how to create a simple application
|
||||
window and how to startup the Qt event loop.
|
||||
|
||||
It's time to explore how to pass data to Qml, but lets see the
|
||||
example code first:
|
||||
|
||||
``Examples/SimpleData/main.nim``
|
||||
|
||||
.. code-block:: nim
|
||||
:file: ../Examples/SimpleData/main.nim
|
||||
|
||||
``Examples/SimpleData/main.qml``
|
||||
|
||||
.. code-block:: qml
|
||||
:file: ../Examples/SimpleData/main.qml
|
||||
|
||||
The following example shows how to expose simple data types to Qml:
|
||||
1. Create a QVariant and set its internal value.
|
||||
2. Create a property in the Qml root context with a given name.
|
||||
|
||||
Once a property is set through the ``setContextProperty`` proc, it's available
|
||||
globally in all the Qml script loaded by the current engine (see the official Qt
|
||||
documentation for more details about the engine and context objects)
|
||||
|
||||
At the time of writing the QVariant class support the following types:
|
||||
* int
|
||||
* string
|
||||
* bool
|
||||
* float
|
||||
* QObject derived classes
|
||||
|
||||
Example 3: exposing complex data and procedures to Qml
|
||||
----------------------------------------------------------
|
||||
As seen by the second example, simple data is fine. However most
|
||||
applications need to expose complex data, functions and
|
||||
update the view when something changes in the data layer.
|
||||
This is achieved by creating an object that derives from QObject.
|
||||
|
||||
A QObject is made of :
|
||||
1. ``Slots``: slots are functions that could be called from the qml engine and/or connected to Qt signals
|
||||
2. ``Signals``: signals allow the sending of events and be connected to slots
|
||||
3. ``Properties``: properties allow the passing of data to
|
||||
the Qml view and make it aware of changes in the data layer
|
||||
|
||||
A QObject property is made of three things:
|
||||
* a read slot: a method that returns the current value of the property
|
||||
* a write slot: a method that sets the value of the property
|
||||
* a notify signal: emitted when the current value of the property is changed
|
||||
|
||||
We'll start by looking at the main.nim file
|
||||
|
||||
``Examples/SlotsAndProperties/main.nim``
|
||||
|
||||
.. code-block:: nim
|
||||
:file: ../Examples/SlotsAndProperties/main.nim
|
||||
|
||||
Here, nothing special happens except:
|
||||
1. The creation of Contact object
|
||||
2. The injection of the Contact object to the Qml root context
|
||||
using the ``setContextProperty`` as seen in the previous
|
||||
example
|
||||
|
||||
The Qml file is as follows:
|
||||
|
||||
``Examples/SlotsAndProperties/main.qml``
|
||||
|
||||
.. code-block:: qml
|
||||
:file: ../Examples/SlotsAndProperties/main.qml
|
||||
|
||||
The qml is made up of: a Label, a TextInput widget, and a button.
|
||||
The label displays the contact name - this automatically updates when
|
||||
the contact name changes.
|
||||
|
||||
When clicked, the button updates the contact name with the text from
|
||||
the TextInput widget.
|
||||
|
||||
So where's the magic?
|
||||
|
||||
The magic is in the Contact.nim file
|
||||
|
||||
``Examples/SlotsAndProperties/Contact.nim``
|
||||
|
||||
.. code-block:: nim
|
||||
:file: ../Examples/SlotsAndProperties/Contact.nim
|
||||
|
||||
First we declare a QObject subclass and provide a simple
|
||||
new method where we:
|
||||
1. invoke the ``create()`` procedure. This invoke the C++ bridge and allocate
|
||||
a QObject instance
|
||||
2. register a slot ``getName`` for reading the Contact name field
|
||||
3. register a slot ``setName`` for writing the Contact name
|
||||
4. register a signal ``nameChanged`` for notify the contact name changes
|
||||
5. register a property called ``name`` of type ``QString`` with the given
|
||||
read, write slots and notify signal
|
||||
|
||||
Looking at the ``getName`` and ``setName`` methods, you can see that slots, as defined in Nim,
|
||||
are nothing more than standard methods. The method corresponding to the ``setName`` slot
|
||||
demonstrates how to use the ``emit`` method to emit a signal.
|
||||
|
||||
The last thing to consider is the override of the ``onSlotCalled`` method.
|
||||
This method is called by the NimQml library when an invocation occurs from
|
||||
the Qml side for one of the slots belonging to the QObject.
|
||||
The usual implementation for the onSlotCalled method consists of a
|
||||
switch statement that forwards the arguments to the correct slot.
|
||||
If the invoked slot has a return value, this is always in the index position
|
||||
0 of the args array.
|
||||
|
||||
|
||||
Example 4: QtObject macro
|
||||
-------------------------
|
||||
The previous example shows how to create a simple QObject, however writing
|
||||
all those ``register`` procs and writing the ``onSlotCalled`` method
|
||||
becomes boring pretty soon.
|
||||
|
||||
Furthermore all this information can be automatically generated.
|
||||
For this purpose you can import the NimQmlMacros module that provides
|
||||
the QtObject macro.
|
||||
|
||||
Let's begin as usual with both the main.nim and main.qml files
|
||||
|
||||
``Examples/QtObjectMacro/main.nim``
|
||||
|
||||
.. code-block:: nim
|
||||
:file: ../Examples/QtObjectMacro/main.nim
|
||||
|
||||
|
||||
``Examples/QtObjectMacro/main.qml``
|
||||
|
||||
.. code-block:: qml
|
||||
:file: ../Examples/QtObjectMacro/main.qml
|
||||
|
||||
Nothing is new in both the ``main.nim`` and ``main.qml`` with respect to
|
||||
the previous example. What changed is the Contact object:
|
||||
|
||||
``Examples/QtObjectMacro/Contact.nim``
|
||||
|
||||
.. code-block:: nim
|
||||
:file: ../Examples/QtObjectMacro/Contact.nim
|
||||
|
||||
In details:
|
||||
1. Each QObject is defined inside the QtObject macro
|
||||
2. Each slot is annotated with the ``{.slot.}`` pragma
|
||||
3. Each signal is annotated with the ``{.signal.}`` pragma
|
||||
4. Each property is created with the ``QtProperty`` macro
|
||||
|
||||
The ``QtProperty`` macro has the following syntax
|
||||
|
||||
.. code-block:: nim
|
||||
QtProperty[typeOfProperty] nameOfProperty
|
||||
|
||||
Example 5: ContactApp
|
||||
-------------------------
|
||||
The last example tries to show you all the stuff presented
|
||||
in the previous chapters and gives you an introduction to how
|
||||
to expose lists to qml.
|
||||
|
||||
Qt models are a huge topic and explaining how they work is
|
||||
out of scope. For further information please read the official
|
||||
Qt documentation.
|
||||
|
||||
The main file follows the basic logic of creating a qml
|
||||
engine and exposing a QObject derived object "ApplicationLogic"
|
||||
through a global "logic" property
|
||||
|
||||
``Examples/ContactApp/main.nim``
|
||||
|
||||
.. code-block:: nim
|
||||
:file: ../Examples/ContactApp/main.nim
|
||||
|
||||
The qml file shows a simple app with a central tableview
|
||||
|
||||
``Examples/ContactApp/main.qml``
|
||||
|
||||
.. code-block:: qml
|
||||
:file: ../Examples/ContactApp/main.qml
|
||||
|
||||
The important things to notice are:
|
||||
1. The menubar load, save and exit items handlers call the logic load, save and exit slots
|
||||
2. The TableView model is retrieved by the logic.contactList property
|
||||
3. The delete and add buttons call the del and add slots of the logic.contactList model
|
||||
|
||||
The ApplicationLogic object is as follows:
|
||||
|
||||
``Examples/ContactApp/ApplicationLogic.nim``
|
||||
|
||||
.. code-block:: nim
|
||||
:file: ../Examples/ContactApp/ApplicationLogic.nim
|
||||
|
||||
The ApplicationLogic object,
|
||||
1. expose some slots for handling the qml menubar triggered signals
|
||||
2. expose a contactList property that return a QAbstractListModel derived object that manage the list of contacts
|
||||
|
||||
The ContactList object is as follows:
|
||||
|
||||
``Examples/ContactApp/ContactList.nim``
|
||||
|
||||
.. code-block:: nim
|
||||
:file: ../Examples/ContactApp/ContactList.nim
|
||||
|
||||
The ContactList object:
|
||||
1. overrides the ``rowCount`` method for returning the number of rows stored in the model
|
||||
2. overrides the ``data`` method for returning the value for the exported roles
|
||||
3. overrides the ``roleNames`` method for returning the names of the roles of the model. This name are then available in the qml item delegates
|
||||
4. defines two slots ``add`` and ``del`` that add or delete a Contact. During this operations the model execute the ``beginInsertRows`` and ``beginRemoveRows`` for notifing the view of an upcoming change. Once the add or delete operations are done the model execute the ``endInsertRows`` and ``endRemoveRows``.
|
|
@ -1,2 +0,0 @@
|
|||
file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/main.qml DESTINATION ${CMAKE_CURRENT_BINARY_DIR})
|
||||
add_nim_executable(TARGET NimQmlAbstractItemModel SOURCES main.nim PATHS ../../NimQml)
|
|
@ -1,37 +0,0 @@
|
|||
import NimQml, NimQmlMacros, Tables
|
||||
|
||||
QtObject:
|
||||
type
|
||||
MyListModel* = ref object of QAbstractListModel
|
||||
names*: seq[string]
|
||||
RoleNames {.pure.} = enum
|
||||
Name = 0,
|
||||
|
||||
converter toCInt(value: RoleNames): cint = return value.cint
|
||||
converter toCInt(value: int): cint = return value.cint
|
||||
converter toInt(value: RoleNames): int = return value.int
|
||||
converter toInt(value: cint): int = return value.int
|
||||
converter toQVariant(value: string): QVariant = return value.newQVariant
|
||||
|
||||
proc delete(self: MyListModel) =
|
||||
let model = self.QAbstractListModel
|
||||
model.delete
|
||||
|
||||
proc newMyListModel*(): MyListModel =
|
||||
new(result, delete)
|
||||
result.names = @["John", "Max", "Paul", "Anna"]
|
||||
result.create
|
||||
|
||||
method rowCount(self: MyListModel, index: QModelIndex = nil): cint =
|
||||
return self.names.len
|
||||
|
||||
method data(self: MyListModel, index: QModelIndex, role: cint): QVariant =
|
||||
if not index.isValid:
|
||||
return
|
||||
if index.row < 0 or index.row >= self.names.len:
|
||||
return
|
||||
return self.names[index.row]
|
||||
|
||||
method roleNames(self: MyListModel): Table[cint, cstring] =
|
||||
result = initTable[cint, cstring]()
|
||||
result[RoleNames.Name] = "name"
|
|
@ -1,26 +0,0 @@
|
|||
import NimQml
|
||||
import MyListModel
|
||||
|
||||
proc mainProc() =
|
||||
echo "Starting"
|
||||
var app = newQApplication()
|
||||
defer: app.delete
|
||||
|
||||
var myListModel = newMyListModel();
|
||||
defer: myListModel.delete
|
||||
|
||||
var engine = newQQmlApplicationEngine()
|
||||
defer: engine.delete
|
||||
|
||||
var variant = newQVariant(myListModel)
|
||||
defer: variant.delete
|
||||
|
||||
engine.rootContext.setContextProperty("myListModel", variant)
|
||||
engine.load("main.qml")
|
||||
|
||||
app.exec()
|
||||
|
||||
when isMainModule:
|
||||
mainProc()
|
||||
GC_fullcollect()
|
||||
|
|
@ -1,25 +0,0 @@
|
|||
import QtQuick 2.2
|
||||
import QtQuick.Controls 1.2
|
||||
import QtQuick.Layouts 1.1
|
||||
import QtQuick.Window 2.1
|
||||
|
||||
ApplicationWindow
|
||||
{
|
||||
width: 400
|
||||
height: 300
|
||||
title: "AbstractItemModel"
|
||||
Component.onCompleted: visible = true
|
||||
|
||||
Component
|
||||
{
|
||||
id: myListModelDelegate
|
||||
Label { text: "Name:" + name }
|
||||
}
|
||||
|
||||
ListView
|
||||
{
|
||||
anchors.fill: parent
|
||||
model: myListModel
|
||||
delegate: myListModelDelegate
|
||||
}
|
||||
}
|
|
@ -1,6 +0,0 @@
|
|||
add_subdirectory(HelloWorld)
|
||||
add_subdirectory(SimpleData)
|
||||
add_subdirectory(SlotsAndProperties)
|
||||
add_subdirectory(QtObjectMacro)
|
||||
add_subdirectory(ContactApp)
|
||||
add_subdirectory(AbstractItemModel)
|
|
@ -1,33 +0,0 @@
|
|||
import NimQml, NimQmlMacros, ContactList
|
||||
|
||||
QtObject:
|
||||
type ApplicationLogic* = ref object of QObject
|
||||
contactList: ContactList
|
||||
app: QApplication
|
||||
|
||||
proc delete*(self: ApplicationLogic) =
|
||||
let qobject = self.QObject
|
||||
qobject.delete
|
||||
self.contactList.delete
|
||||
|
||||
proc newApplicationLogic*(app: QApplication): ApplicationLogic =
|
||||
new(result)
|
||||
result.contactList = newContactList()
|
||||
result.app = app
|
||||
result.create()
|
||||
|
||||
method getContactList(self: ApplicationLogic): QVariant {.slot.} =
|
||||
return newQVariant(self.contactList)
|
||||
|
||||
method onLoadTriggered(self: ApplicationLogic) {.slot.} =
|
||||
echo "Load Triggered"
|
||||
self.contactList.add("John", "Doo")
|
||||
|
||||
method onSaveTriggered(self: ApplicationLogic) {.slot.} =
|
||||
echo "Save Triggered"
|
||||
|
||||
method onExitTriggered(self: ApplicationLogic) {.slot.} =
|
||||
self.app.quit
|
||||
|
||||
QtProperty[QVariant] contactList:
|
||||
read = getContactList
|
|
@ -1,2 +0,0 @@
|
|||
file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/main.qml DESTINATION ${CMAKE_CURRENT_BINARY_DIR})
|
||||
add_nim_executable(TARGET NimQmlContactApp SOURCES main.nim PATHS ../../NimQml)
|
|
@ -1,51 +0,0 @@
|
|||
## Please note we are using templates where ordinarily we would like to use procedures
|
||||
## due to bug: https://github.com/Araq/Nim/issues/1821
|
||||
import NimQml, NimQmlMacros
|
||||
|
||||
QtObject:
|
||||
type Contact* = ref object of QObject
|
||||
name: string
|
||||
surname: string
|
||||
|
||||
proc delete*(self: Contact) =
|
||||
let qobject = self.QObject
|
||||
qobject.delete
|
||||
|
||||
proc newContact*(): Contact =
|
||||
new(result)
|
||||
result.name = ""
|
||||
result.create
|
||||
|
||||
method firstName*(self: Contact): string {.slot.} =
|
||||
result = self.name
|
||||
|
||||
method firstNameChanged*(self: Contact) {.signal.}
|
||||
|
||||
method setFirstName(self: Contact, name: string) {.slot.} =
|
||||
if self.name != name:
|
||||
self.name = name
|
||||
self.firstNameChanged()
|
||||
|
||||
proc `firstName=`*(self: Contact, name: string) = self.setFirstName(name)
|
||||
|
||||
QtProperty[string] firstName:
|
||||
read = firstName
|
||||
write = setFirstName
|
||||
notify = firstNameChanged
|
||||
|
||||
method surname*(self: Contact): string {.slot.} =
|
||||
result = self.surname
|
||||
|
||||
method surnameChanged*(self: Contact) {.signal.}
|
||||
|
||||
method setSurname(self: Contact, surname: string) {.slot.} =
|
||||
if self.surname != surname:
|
||||
self.surname = surname
|
||||
self.surnameChanged()
|
||||
|
||||
proc `surname=`*(self: Contact, surname: string) = self.setSurname(surname)
|
||||
|
||||
QtProperty[string] surname:
|
||||
read = surname
|
||||
write = setSurname
|
||||
notify = surnameChanged
|
|
@ -1,62 +0,0 @@
|
|||
import NimQml, NimQmlMacros, Contact, Tables
|
||||
|
||||
QtObject:
|
||||
type
|
||||
ContactList* = ref object of QAbstractListModel
|
||||
contacts*: seq[Contact]
|
||||
ContactRoles {.pure.} = enum
|
||||
FirstName = 0
|
||||
Surname = 1
|
||||
|
||||
converter toCInt(value: ContactRoles): cint = return value.cint
|
||||
converter toCInt(value: int): cint = return value.cint
|
||||
converter toInt(value: ContactRoles): int = return value.int
|
||||
converter toInt(value: cint): int = return value.int
|
||||
converter toQVariant(value: string): QVariant = return value.newQVariant
|
||||
|
||||
proc delete(self: ContactList) =
|
||||
let model = self.QAbstractListModel
|
||||
model.delete
|
||||
for contact in self.contacts:
|
||||
contact.delete
|
||||
self.contacts = @[]
|
||||
|
||||
proc newContactList*(): ContactList =
|
||||
new(result, delete)
|
||||
result.contacts = @[]
|
||||
result.create
|
||||
|
||||
method rowCount(self: ContactList, index: QModelIndex = nil): cint =
|
||||
return self.contacts.len
|
||||
|
||||
method data(self: ContactList, index: QModelIndex, role: cint): QVariant =
|
||||
if not index.isValid:
|
||||
return
|
||||
if index.row < 0 or index.row >= self.contacts.len:
|
||||
return
|
||||
let contact = self.contacts[index.row]
|
||||
let contactRole = role.ContactRoles
|
||||
case contactRole:
|
||||
of ContactRoles.FirstName: return contact.firstName
|
||||
of ContactRoles.Surname: return contact.surname
|
||||
else: return
|
||||
|
||||
method roleNames(self: ContactList): Table[cint, cstring] =
|
||||
result = initTable[cint, cstring]()
|
||||
result[ContactRoles.FirstName] = "firstName"
|
||||
result[ContactRoles.Surname] = "surname"
|
||||
|
||||
method add*(self: ContactList, name: string, surname: string) {.slot.} =
|
||||
let contact = newContact()
|
||||
contact.firstName = name
|
||||
contact.surname = surname
|
||||
self.beginInsertRows(newQModelIndex(), self.contacts.len, self.contacts.len)
|
||||
self.contacts.add(contact)
|
||||
self.endInsertRows()
|
||||
|
||||
method del*(self: ContactList, pos: int) {.slot.} =
|
||||
if pos < 0 or pos >= self.contacts.len:
|
||||
return
|
||||
self.beginRemoveRows(newQModelIndex(), pos, pos)
|
||||
self.contacts.del(pos)
|
||||
self.endRemoveRows
|
|
@ -1,17 +0,0 @@
|
|||
import NimQml, ApplicationLogic
|
||||
|
||||
proc mainProc() =
|
||||
let app = newQApplication()
|
||||
defer: app.delete
|
||||
let logic = newApplicationLogic(app)
|
||||
defer: logic.delete
|
||||
let engine = newQQmlApplicationEngine()
|
||||
defer: engine.delete
|
||||
let logicVariant = newQVariant(logic)
|
||||
defer: logicVariant.delete
|
||||
engine.rootContext.setContextProperty("logic", logicVariant)
|
||||
engine.load("main.qml")
|
||||
app.exec()
|
||||
|
||||
when isMainModule:
|
||||
mainProc()
|
|
@ -1,93 +0,0 @@
|
|||
import QtQuick 2.2
|
||||
import QtQuick.Controls 1.2
|
||||
import QtQuick.Layouts 1.1
|
||||
import QtQuick.Window 2.1
|
||||
|
||||
ApplicationWindow {
|
||||
|
||||
width: 500
|
||||
height: 300
|
||||
title: "ContactApp"
|
||||
visible: true
|
||||
|
||||
menuBar: MenuBar {
|
||||
Menu {
|
||||
title: "&File"
|
||||
MenuItem { text: "&Load"; onTriggered: logic.onLoadTriggered() }
|
||||
MenuItem { text: "&Save"; onTriggered: logic.onSaveTriggered() }
|
||||
MenuItem { text: "&Exit"; onTriggered: logic.onExitTriggered() }
|
||||
}
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
anchors.fill: parent
|
||||
|
||||
Component {
|
||||
id: tableTextDelegate
|
||||
Label {
|
||||
id: tableTextDelegateInstance
|
||||
property var styleData: undefined
|
||||
states: State {
|
||||
when: styleData !== undefined
|
||||
PropertyChanges {
|
||||
target: tableTextDelegateInstance;
|
||||
text: styleData.value;
|
||||
color: styleData.textColor
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Component {
|
||||
id: tableButtonDelegate
|
||||
Button {
|
||||
id: tableButtonDelegateInstance
|
||||
property var styleData: undefined
|
||||
text: "Delete"
|
||||
onClicked: logic.contactList.del(styleData.row)
|
||||
}
|
||||
}
|
||||
|
||||
Component {
|
||||
id: tableItemDelegate
|
||||
Loader {
|
||||
id: tableItemDelegateInstance
|
||||
sourceComponent: {
|
||||
if (styleData.column === 0 || styleData.column === 1)
|
||||
return tableTextDelegate
|
||||
else if (styleData.column === 2)
|
||||
return tableButtonDelegate
|
||||
else
|
||||
return tableTextDelegate
|
||||
}
|
||||
Binding {
|
||||
target: tableItemDelegateInstance.item
|
||||
property: "styleData"
|
||||
value: styleData
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TableView {
|
||||
model: logic.contactList
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
TableViewColumn { role: "firstName"; title: "FirstName"; width: 200 }
|
||||
TableViewColumn { role: "surname"; title: "Surname"; width: 200}
|
||||
TableViewColumn { width: 100; }
|
||||
itemDelegate: tableItemDelegate
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
Label { text: "Name" }
|
||||
TextField { id: nameTextField; Layout.fillWidth: true; text: "" }
|
||||
Label { text: "Surname" }
|
||||
TextField { id: surnameTextField; Layout.fillWidth: true; text: "" }
|
||||
Button {
|
||||
text: "Add"
|
||||
onClicked: logic.contactList.add(nameTextField.text, surnameTextField.text)
|
||||
enabled: nameTextField.text !== "" && surnameTextField.text !== ""
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,2 +0,0 @@
|
|||
file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/main.qml DESTINATION ${CMAKE_CURRENT_BINARY_DIR})
|
||||
add_nim_executable(TARGET NimQmlHelloWorld SOURCES main.nim PATHS ../../NimQml)
|
|
@ -1,18 +0,0 @@
|
|||
import NimQml
|
||||
import macros
|
||||
import typeinfo
|
||||
|
||||
proc mainProc() =
|
||||
var app = newQApplication()
|
||||
defer: app.delete()
|
||||
|
||||
var engine = newQQmlApplicationEngine()
|
||||
defer: engine.delete()
|
||||
|
||||
engine.load("main.qml")
|
||||
app.exec()
|
||||
|
||||
when isMainModule:
|
||||
mainProc()
|
||||
GC_fullcollect()
|
||||
|
|
@ -1,12 +0,0 @@
|
|||
import QtQuick 2.2
|
||||
import QtQuick.Controls 1.2
|
||||
import QtQuick.Layouts 1.1
|
||||
import QtQuick.Window 2.1
|
||||
|
||||
ApplicationWindow
|
||||
{
|
||||
width: 400
|
||||
height: 300
|
||||
title: "Hello World"
|
||||
Component.onCompleted: visible = true
|
||||
}
|
|
@ -1,2 +0,0 @@
|
|||
file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/main.qml DESTINATION ${CMAKE_CURRENT_BINARY_DIR})
|
||||
add_nim_executable(TARGET NimQmlQtObjectMacro SOURCES main.nim PATHS ../../NimQml)
|
|
@ -1,31 +0,0 @@
|
|||
## Please note we are using templates where ordinarily we would like to use procedures
|
||||
## due to bug: https://github.com/Araq/Nim/issues/1821
|
||||
import NimQml, NimQmlMacros
|
||||
|
||||
QtObject:
|
||||
type Contact* = ref object of QObject
|
||||
m_name: string
|
||||
|
||||
proc delete*(self: Contact) =
|
||||
var qobject = self.QObject
|
||||
qobject.delete()
|
||||
|
||||
proc newContact*(): Contact =
|
||||
new(result, delete)
|
||||
result.m_name = "InitialName"
|
||||
result.create
|
||||
|
||||
method getName*(self: Contact): string {.slot.} =
|
||||
result = self.m_name
|
||||
|
||||
method nameChanged*(self: Contact) {.signal.}
|
||||
|
||||
method setName*(self: Contact, name: string) {.slot.} =
|
||||
if self.m_name != name:
|
||||
self.m_name = name
|
||||
self.nameChanged()
|
||||
|
||||
QtProperty[string] name:
|
||||
read = getName
|
||||
write = setName
|
||||
notify = nameChanged
|
|
@ -1,23 +0,0 @@
|
|||
import NimQml
|
||||
import Contact
|
||||
|
||||
proc mainProc() =
|
||||
var app = newQApplication()
|
||||
defer: app.delete()
|
||||
|
||||
var contact = newContact()
|
||||
defer: contact.delete()
|
||||
|
||||
var engine = newQQmlApplicationEngine()
|
||||
defer: engine.delete()
|
||||
|
||||
var variant = newQVariant(contact)
|
||||
defer: variant.delete()
|
||||
|
||||
engine.rootContext.setContextProperty("contact", variant)
|
||||
engine.load("main.qml")
|
||||
app.exec()
|
||||
|
||||
when isMainModule:
|
||||
mainProc()
|
||||
GC_fullcollect()
|
|
@ -1,33 +0,0 @@
|
|||
import QtQuick 2.2
|
||||
import QtQuick.Controls 1.2
|
||||
import QtQuick.Layouts 1.1
|
||||
import QtQuick.Window 2.1
|
||||
|
||||
ApplicationWindow
|
||||
{
|
||||
width: 400
|
||||
height: 300
|
||||
|
||||
Component.onCompleted: visible = true
|
||||
|
||||
ColumnLayout
|
||||
{
|
||||
anchors.fill: parent
|
||||
|
||||
Label
|
||||
{
|
||||
text: "Current name is:" + contact.name
|
||||
}
|
||||
|
||||
TextField
|
||||
{
|
||||
id: textField
|
||||
}
|
||||
|
||||
Button
|
||||
{
|
||||
text: "Change Name"
|
||||
onClicked: contact.name = textField.text
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,2 +0,0 @@
|
|||
file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/main.qml DESTINATION ${CMAKE_CURRENT_BINARY_DIR})
|
||||
add_nim_executable(TARGET NimQmlSimpleData SOURCES main.nim PATHS ../../NimQml)
|
|
@ -1,34 +0,0 @@
|
|||
import NimQml
|
||||
import macros
|
||||
import typeinfo
|
||||
|
||||
proc mainProc() =
|
||||
var app = newQApplication()
|
||||
defer: app.delete()
|
||||
|
||||
var engine = newQQmlApplicationEngine()
|
||||
defer: engine.delete()
|
||||
|
||||
var qVar1 = newQVariant(10)
|
||||
defer: qVar1.delete()
|
||||
|
||||
var qVar2 = newQVariant("Hello World")
|
||||
defer: qVar2.delete()
|
||||
|
||||
var qVar3 = newQVariant(false)
|
||||
defer: qVar3.delete()
|
||||
|
||||
var qVar4 = newQVariant(3.5.float)
|
||||
defer: qVar4.delete()
|
||||
|
||||
engine.rootContext.setContextProperty("qVar1", qVar1)
|
||||
engine.rootContext.setContextProperty("qVar2", qVar2)
|
||||
engine.rootContext.setContextProperty("qVar3", qVar3)
|
||||
engine.rootContext.setContextProperty("qVar4", qVar4)
|
||||
engine.load("main.qml")
|
||||
app.exec()
|
||||
|
||||
when isMainModule:
|
||||
mainProc()
|
||||
GC_fullcollect()
|
||||
|
|
@ -1,21 +0,0 @@
|
|||
import QtQuick 2.2
|
||||
import QtQuick.Controls 1.2
|
||||
import QtQuick.Layouts 1.1
|
||||
import QtQuick.Window 2.1
|
||||
|
||||
ApplicationWindow
|
||||
{
|
||||
width: 400
|
||||
height: 300
|
||||
title: "SimpleData"
|
||||
Component.onCompleted: visible = true
|
||||
|
||||
ColumnLayout
|
||||
{
|
||||
anchors.fill: parent
|
||||
SpinBox { value: qVar1}
|
||||
TextField { text: qVar2}
|
||||
CheckBox { checked: qVar3}
|
||||
SpinBox { value: qVar4; decimals: 1 }
|
||||
}
|
||||
}
|
|
@ -1,2 +0,0 @@
|
|||
file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/main.qml DESTINATION ${CMAKE_CURRENT_BINARY_DIR})
|
||||
add_nim_executable(TARGET NimQmlSlotsAndProperties SOURCES main.nim PATHS ../../NimQml)
|
|
@ -1,40 +0,0 @@
|
|||
## Please note we are using templates where ordinarily we would like to use procedures
|
||||
## due to bug: https://github.com/Araq/Nim/issues/1821
|
||||
import NimQml
|
||||
|
||||
type Contact = ref object of QObject
|
||||
m_name: string
|
||||
|
||||
proc delete*(self: Contact) =
|
||||
var qobject = self.QObject
|
||||
qobject.delete()
|
||||
|
||||
proc create*(self: Contact) =
|
||||
var qobject = self.QObject
|
||||
qobject.create()
|
||||
self.m_name = "InitialName"
|
||||
self.registerSlot("getName", [QMetaType.QString])
|
||||
self.registerSlot("setName", [QMetaType.Void, QMetaType.QString])
|
||||
self.registerSignal("nameChanged", [QMetaType.Void])
|
||||
self.registerProperty("name", QMetaType.QString, "getName", "setName", "nameChanged")
|
||||
|
||||
proc newContact*(): Contact =
|
||||
new(result, delete)
|
||||
result.create()
|
||||
|
||||
method getName*(self: Contact): string =
|
||||
result = self.m_name
|
||||
|
||||
method setName*(self: Contact, name: string) =
|
||||
if self.m_name != name:
|
||||
self.m_name = name
|
||||
self.emit("nameChanged")
|
||||
|
||||
method onSlotCalled(self: Contact, slotName: string, args: openarray[QVariant]) =
|
||||
case slotName:
|
||||
of "getName":
|
||||
args[0].stringVal = self.getName()
|
||||
of "setName":
|
||||
self.setName(args[1].stringVal)
|
||||
else:
|
||||
discard()
|
|
@ -1,24 +0,0 @@
|
|||
import NimQml
|
||||
import Contact
|
||||
|
||||
proc mainProc() =
|
||||
var app = newQApplication()
|
||||
defer: app.delete()
|
||||
|
||||
var contact = newContact()
|
||||
defer: contact.delete()
|
||||
|
||||
var engine = newQQmlApplicationEngine()
|
||||
defer: engine.delete()
|
||||
|
||||
var variant = newQVariant(contact)
|
||||
defer: variant.delete()
|
||||
|
||||
engine.rootContext.setContextProperty("contact", variant)
|
||||
engine.load("main.qml")
|
||||
app.exec()
|
||||
|
||||
when isMainModule:
|
||||
mainProc()
|
||||
GC_fullcollect()
|
||||
|
|
@ -1,33 +0,0 @@
|
|||
import QtQuick 2.2
|
||||
import QtQuick.Controls 1.2
|
||||
import QtQuick.Layouts 1.1
|
||||
import QtQuick.Window 2.1
|
||||
|
||||
ApplicationWindow
|
||||
{
|
||||
width: 400
|
||||
height: 300
|
||||
|
||||
Component.onCompleted: visible = true
|
||||
|
||||
ColumnLayout
|
||||
{
|
||||
anchors.fill: parent
|
||||
|
||||
Label
|
||||
{
|
||||
text: "Current name is:" + contact.name
|
||||
}
|
||||
|
||||
TextField
|
||||
{
|
||||
id: textField
|
||||
}
|
||||
|
||||
Button
|
||||
{
|
||||
text: "Change Name"
|
||||
onClicked: contact.name = textField.text
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,795 +0,0 @@
|
|||
include NimQmlTypes
|
||||
|
||||
when defined(windows):
|
||||
const dOtherSideDll* = "libDOtherSide.dll"
|
||||
elif defined(macosx):
|
||||
const dOtherSideDll* = "libDOtherSide.dylib"
|
||||
else:
|
||||
const dOtherSideDll* = "libDOtherSide.so"
|
||||
|
||||
## NimQml aims to provide binding to the QML for the Nim programming language
|
||||
##
|
||||
## Optional finalizers
|
||||
## -------------------
|
||||
## To enable finalizers you must define ``nimqml_use_finalizers`` by passing
|
||||
## the option, ``-d:nimqml_use_finalizers``, to the Nim compiler. The relevant
|
||||
## delete method will then be called automatically by the garbage collector.
|
||||
## Care should be taken when using this approach as there are no guarantees
|
||||
## when a finalzier will be run, or if, indeed, it will run at all.
|
||||
|
||||
type QMetaType* {.pure.} = enum ## \
|
||||
## Qt metatypes values used for specifing the
|
||||
## signals and slots argument and return types.
|
||||
##
|
||||
## This enum mimic the QMetaType::Type C++ enum
|
||||
UnknownType = cint(0),
|
||||
Bool = cint(1),
|
||||
Int = cint(2),
|
||||
QString = cint(10),
|
||||
VoidStar = cint(31),
|
||||
QObjectStar = cint(39),
|
||||
QVariant = cint(41),
|
||||
Void = cint(43),
|
||||
|
||||
var qobjectRegistry = initTable[ptr QObjectObj, bool]()
|
||||
|
||||
template debugMsg(message: string) =
|
||||
{.push warning[user]: off.} # workaround to remove warnings; this won't be needed soon
|
||||
when defined(debug):
|
||||
{.pop.}
|
||||
echo "NimQml: ", message
|
||||
else:
|
||||
{.pop.}
|
||||
|
||||
template debugMsg(typeName: string, procName: string) =
|
||||
{.push warning[user]: off.} # workaround to remove warnings; this won't be needed soon
|
||||
when defined(debug):
|
||||
{.pop.}
|
||||
var message = typeName
|
||||
message &= ": "
|
||||
message &= procName
|
||||
debugMsg(message)
|
||||
else:
|
||||
{.pop.}
|
||||
|
||||
template debugMsg(typeName: string, procName: string, userMessage: string) =
|
||||
{.push warning[user]: off.} # workaround to remove warnings; this won't be needed soon
|
||||
when defined(debug):
|
||||
{.pop.}
|
||||
var message = typeName
|
||||
message &= ": "
|
||||
message &= procName
|
||||
message &= " "
|
||||
message &= userMessage
|
||||
debugMsg(message)
|
||||
else:
|
||||
{.pop.}
|
||||
|
||||
template newWithCondFinalizer(variable: expr, finalizer: expr) =
|
||||
## calls ``new`` but only setting a finalizer when ``nimqml_use_finalizers``
|
||||
## is defined
|
||||
{.push warning[user]: off.} # workaround to remove warnings; this won't be needed soon
|
||||
when defined(nimqml_use_finalizers):
|
||||
{.pop.}
|
||||
new(variable, finalizer)
|
||||
else:
|
||||
{.pop.}
|
||||
new(variable)
|
||||
|
||||
# QVariant
|
||||
proc dos_qvariant_create(variant: var RawQVariant) {.cdecl, dynlib:dOtherSideDll, importc.}
|
||||
proc dos_qvariant_create_int(variant: var RawQVariant, value: cint) {.cdecl, dynlib:dOtherSideDll, importc.}
|
||||
proc dos_qvariant_create_bool(variant: var RawQVariant, value: bool) {.cdecl, dynlib:dOtherSideDll, importc.}
|
||||
proc dos_qvariant_create_string(variant: var RawQVariant, value: cstring) {.cdecl, dynlib:dOtherSideDll, importc.}
|
||||
proc dos_qvariant_create_qobject(variant: var RawQVariant, value: RawQObject) {.cdecl, dynlib:dOtherSideDll, importc.}
|
||||
proc dos_qvariant_create_qvariant(variant: var RawQVariant, value: RawQVariant) {.cdecl, dynlib:dOtherSideDll, importc.}
|
||||
proc dos_qvariant_create_float(variant: var RawQVariant, value: cfloat) {.cdecl, dynlib:dOtherSideDll, importc.}
|
||||
proc dos_qvariant_create_double(variant: var RawQVariant, value: cdouble) {.cdecl, dynlib:dOtherSideDll, importc.}
|
||||
proc dos_qvariant_delete(variant: RawQVariant) {.cdecl, dynlib:dOtherSideDll, importc.}
|
||||
proc dos_qvariant_isnull(variant: RawQVariant, isNull: var bool) {.cdecl, dynlib:dOtherSideDll, importc.}
|
||||
proc dos_qvariant_toInt(variant: RawQVariant, value: var cint) {.cdecl, dynlib:dOtherSideDll, importc.}
|
||||
proc dos_qvariant_toBool(variant: RawQVariant, value: var bool) {.cdecl, dynlib:dOtherSideDll, importc.}
|
||||
proc dos_qvariant_toString(variant: RawQVariant, value: var cstring) {.cdecl, dynlib:dOtherSideDll, importc.}
|
||||
proc dos_qvariant_setInt(variant: RawQVariant, value: cint) {.cdecl, dynlib:dOtherSideDll, importc.}
|
||||
proc dos_qvariant_setBool(variant: RawQVariant, value: bool) {.cdecl, dynlib:dOtherSideDll, importc.}
|
||||
proc dos_qvariant_setString(variant: RawQVariant, value: cstring) {.cdecl, dynlib:dOtherSideDll, importc.}
|
||||
proc dos_qvariant_assign(leftValue: RawQVariant, rightValue: RawQVariant) {.cdecl, dynlib:dOtherSideDll, importc.}
|
||||
proc dos_qvariant_toFloat(variant: RawQVariant, value: var cfloat) {.cdecl, dynlib:dOtherSideDll, importc.}
|
||||
proc dos_qvariant_setFloat(variant: RawQVariant, value: float) {.cdecl, dynlib:dOtherSideDll, importc.}
|
||||
proc dos_qvariant_toDouble(variant: RawQVariant, value: var cdouble) {.cdecl, dynlib:dOtherSideDll, importc.}
|
||||
proc dos_qvariant_setDouble(variant: RawQVariant, value: cdouble) {.cdecl, dynlib:dOtherSideDll, importc.}
|
||||
proc dos_qvariant_setQObject(variant: RawQVariant, value: RawQObject) {.cdecl, dynlib:dOtherSideDll, importc.}
|
||||
proc dos_chararray_delete(rawCString: cstring) {.cdecl, dynlib:dOtherSideDll, importc.}
|
||||
|
||||
proc create*(variant: QVariant) =
|
||||
## Create a new QVariant
|
||||
dos_qvariant_create(variant.data)
|
||||
variant.deleted = false
|
||||
|
||||
proc create*(variant: QVariant, value: cint) =
|
||||
## Create a new QVariant given a cint value
|
||||
dos_qvariant_create_int(variant.data, value)
|
||||
variant.deleted = false
|
||||
|
||||
proc create*(variant: QVariant, value: bool) =
|
||||
## Create a new QVariant given a bool value
|
||||
dos_qvariant_create_bool(variant.data, value)
|
||||
variant.deleted = false
|
||||
|
||||
proc create*(variant: QVariant, value: string) =
|
||||
## Create a new QVariant given a string value
|
||||
dos_qvariant_create_string(variant.data, value)
|
||||
variant.deleted = false
|
||||
|
||||
proc create*(variant: QVariant, value: QObject) =
|
||||
## Create a new QVariant given a QObject
|
||||
dos_qvariant_create_qobject(variant.data, value.data.RawQObject)
|
||||
variant.deleted = false
|
||||
|
||||
proc create*(variant: QVariant, value: RawQVariant) =
|
||||
## Create a new QVariant given another QVariant.
|
||||
## The inner value of the QVariant is copied
|
||||
dos_qvariant_create_qvariant(variant.data, value)
|
||||
variant.deleted = false
|
||||
|
||||
proc create*(variant: QVariant, value: cfloat) =
|
||||
## Create a new QVariant given a cfloat value
|
||||
dos_qvariant_create_float(variant.data, value)
|
||||
variant.deleted = false
|
||||
|
||||
proc create*(variant: QVariant, value: QVariant) =
|
||||
## Create a new QVariant given another QVariant.
|
||||
## The inner value of the QVariant is copied
|
||||
create(variant, value.data)
|
||||
|
||||
proc delete*(variant: QVariant) =
|
||||
## Delete a QVariant
|
||||
if not variant.deleted:
|
||||
debugMsg("QVariant", "delete")
|
||||
dos_qvariant_delete(variant.data)
|
||||
variant.data = nil.RawQVariant
|
||||
variant.deleted = true
|
||||
|
||||
proc newQVariant*(): QVariant =
|
||||
## Return a new QVariant
|
||||
newWithCondFinalizer(result, delete)
|
||||
result.create()
|
||||
|
||||
proc newQVariant*(value: cint): QVariant =
|
||||
## Return a new QVariant given a cint
|
||||
newWithCondFinalizer(result, delete)
|
||||
result.create(value)
|
||||
|
||||
proc newQVariant*(value: bool): QVariant =
|
||||
## Return a new QVariant given a bool
|
||||
newWithCondFinalizer(result, delete)
|
||||
result.create(value)
|
||||
|
||||
proc newQVariant*(value: string): QVariant =
|
||||
## Return a new QVariant given a string
|
||||
newWithCondFinalizer(result, delete)
|
||||
result.create(value)
|
||||
|
||||
proc newQVariant*(value: QObject): QVariant =
|
||||
## Return a new QVariant given a QObject
|
||||
newWithCondFinalizer(result, delete)
|
||||
result.create(value)
|
||||
|
||||
proc newQVariant*(value: RawQVariant): QVariant =
|
||||
## Return a new QVariant given a raw QVariant pointer
|
||||
newWithCondFinalizer(result, delete)
|
||||
result.create(value)
|
||||
|
||||
proc newQVariant*(value: QVariant): QVariant =
|
||||
## Return a new QVariant given another QVariant
|
||||
newWithCondFinalizer(result, delete)
|
||||
result.create(value)
|
||||
|
||||
proc newQVariant*(value: float): QVariant =
|
||||
## Return a new QVariant given a float
|
||||
newWithCondFinalizer(result, delete)
|
||||
result.create(value)
|
||||
|
||||
proc isNull*(variant: QVariant): bool =
|
||||
## Return true if the QVariant value is null, false otherwise
|
||||
dos_qvariant_isnull(variant.data, result)
|
||||
|
||||
proc intVal*(variant: QVariant): int =
|
||||
## Return the QVariant value as int
|
||||
var rawValue: cint
|
||||
dos_qvariant_toInt(variant.data, rawValue)
|
||||
result = rawValue.cint
|
||||
|
||||
proc `intVal=`*(variant: QVariant, value: int) =
|
||||
## Sets the QVariant value int value
|
||||
var rawValue = value.cint
|
||||
dos_qvariant_setInt(variant.data, rawValue)
|
||||
|
||||
proc boolVal*(variant: QVariant): bool =
|
||||
## Return the QVariant value as bool
|
||||
dos_qvariant_toBool(variant.data, result)
|
||||
|
||||
proc `boolVal=`*(variant: QVariant, value: bool) =
|
||||
## Sets the QVariant bool value
|
||||
dos_qvariant_setBool(variant.data, value)
|
||||
|
||||
proc floatVal*(variant: QVariant): float =
|
||||
## Return the QVariant value as float
|
||||
var rawValue: cfloat
|
||||
dos_qvariant_toFloat(variant.data, rawValue)
|
||||
result = rawValue.cfloat
|
||||
|
||||
proc `floatVal=`*(variant: QVariant, value: float) =
|
||||
## Sets the QVariant float value
|
||||
dos_qvariant_setFloat(variant.data, value.cfloat)
|
||||
|
||||
proc doubleVal*(variant: QVariant): cdouble =
|
||||
## Return the QVariant value as double
|
||||
var rawValue: cdouble
|
||||
dos_qvariant_toDouble(variant.data, rawValue)
|
||||
result = rawValue
|
||||
|
||||
proc `doubleVal=`*(variant: QVariant, value: cdouble) =
|
||||
## Sets the QVariant double value
|
||||
dos_qvariant_setDouble(variant.data, value)
|
||||
|
||||
proc stringVal*(variant: QVariant): string =
|
||||
## Return the QVariant value as string
|
||||
var rawCString: cstring
|
||||
dos_qvariant_toString(variant.data, rawCString)
|
||||
result = $rawCString
|
||||
dos_chararray_delete(rawCString)
|
||||
|
||||
proc `stringVal=`*(variant: QVariant, value: string) =
|
||||
## Sets the QVariant string value
|
||||
dos_qvariant_setString(variant.data, value)
|
||||
|
||||
proc `qobjectVal=`*(variant: QVariant, value: QObject) =
|
||||
## Sets the QVariant qobject value
|
||||
dos_qvariant_setQObject(variant.data, value.data.RawQObject)
|
||||
|
||||
proc assign*(leftValue: QVariant, rightValue: QVariant) =
|
||||
## Assign a QVariant with another. The inner value of the QVariant is copied
|
||||
dos_qvariant_assign(leftValue.data, rightValue.data)
|
||||
|
||||
# QQmlApplicationEngine
|
||||
proc dos_qqmlapplicationengine_create(engine: var RawQQmlApplicationEngine) {.cdecl, dynlib:dOtherSideDll, importc.}
|
||||
proc dos_qqmlapplicationengine_load(engine: RawQQmlApplicationEngine, filename: cstring) {.cdecl, dynlib:dOtherSideDll, importc.}
|
||||
proc dos_qqmlapplicationengine_context(engine: RawQQmlApplicationEngine, context: var QQmlContext) {.cdecl, dynlib:dOtherSideDll, importc.}
|
||||
proc dos_qqmlapplicationengine_delete(engine: RawQQmlApplicationEngine) {.cdecl, dynlib:dOtherSideDll, importc.}
|
||||
|
||||
proc create*(engine: QQmlApplicationEngine) =
|
||||
## Create an new QQmlApplicationEngine
|
||||
dos_qqmlapplicationengine_create(engine.data)
|
||||
engine.deleted = false
|
||||
|
||||
proc load*(engine: QQmlApplicationEngine, filename: cstring) =
|
||||
## Load the given Qml file
|
||||
dos_qqmlapplicationengine_load(engine.data, filename)
|
||||
|
||||
proc rootContext*(engine: QQmlApplicationEngine): QQmlContext =
|
||||
## Return the engine root context
|
||||
dos_qqmlapplicationengine_context(engine.data, result)
|
||||
|
||||
proc delete*(engine: QQmlApplicationEngine) =
|
||||
## Delete the given QQmlApplicationEngine
|
||||
if not engine.deleted:
|
||||
debugMsg("QQmlApplicationEngine", "delete")
|
||||
dos_qqmlapplicationengine_delete(engine.data)
|
||||
engine.data = nil.RawQQmlApplicationEngine
|
||||
engine.deleted = true
|
||||
|
||||
proc newQQmlApplicationEngine*(): QQmlApplicationEngine =
|
||||
## Return a new QQmlApplicationEngine
|
||||
newWithCondFinalizer(result, delete)
|
||||
result.create()
|
||||
|
||||
# QQmlContext
|
||||
proc dos_qqmlcontext_setcontextproperty(context: QQmlContext, propertyName: cstring, propertyValue: RawQVariant) {.cdecl, dynlib:dOtherSideDll, importc.}
|
||||
|
||||
proc setContextProperty*(context: QQmlContext, propertyName: string, propertyValue: QVariant) =
|
||||
## Sets a new property with the given value
|
||||
dos_qqmlcontext_setcontextproperty(context, propertyName, propertyValue.data)
|
||||
|
||||
# QApplication
|
||||
proc dos_qapplication_create() {.cdecl, dynlib: dOtherSideDll, importc.}
|
||||
proc dos_qapplication_exec() {.cdecl, dynlib:dOtherSideDll, importc.}
|
||||
proc dos_qapplication_quit() {.cdecl, dynlib:dOtherSideDll, importc.}
|
||||
proc dos_qapplication_delete() {.cdecl, dynlib:dOtherSideDll, importc.}
|
||||
|
||||
proc create*(application: QApplication) =
|
||||
## Create a new QApplication
|
||||
dos_qapplication_create()
|
||||
application.deleted = false
|
||||
|
||||
proc exec*(application: QApplication) =
|
||||
## Start the Qt event loop
|
||||
dos_qapplication_exec()
|
||||
|
||||
proc quit*(application: QApplication) =
|
||||
## Quit the Qt event loop
|
||||
dos_qapplication_quit()
|
||||
|
||||
proc delete*(application: QApplication) =
|
||||
## Delete the given QApplication
|
||||
if not application.deleted:
|
||||
debugMsg("QApplication", "delete")
|
||||
dos_qapplication_delete()
|
||||
application.deleted = true
|
||||
|
||||
proc newQApplication*(): QApplication =
|
||||
## Return a new QApplication
|
||||
newWithCondFinalizer(result, delete)
|
||||
result.create()
|
||||
|
||||
# QGuiApplication
|
||||
proc dos_qguiapplication_create() {.cdecl, dynlib: dOtherSideDll, importc.}
|
||||
proc dos_qguiapplication_exec() {.cdecl, dynlib:dOtherSideDll, importc.}
|
||||
proc dos_qguiapplication_quit() {.cdecl, dynlib:dOtherSideDll, importc.}
|
||||
proc dos_qguiapplication_delete() {.cdecl, dynlib:dOtherSideDll, importc.}
|
||||
|
||||
proc create*(application: QGuiApplication) =
|
||||
## Create a new QApplication
|
||||
dos_qguiapplication_create()
|
||||
application.deleted = false
|
||||
|
||||
proc exec*(application: QGuiApplication) =
|
||||
## Start the Qt event loop
|
||||
dos_qguiapplication_exec()
|
||||
|
||||
proc quit*(application: QGuiApplication) =
|
||||
## Quit the Qt event loop
|
||||
dos_qguiapplication_quit()
|
||||
|
||||
proc delete*(application: QGuiApplication) =
|
||||
## Delete the given QApplication
|
||||
if not application.deleted:
|
||||
debugMsg("QApplication", "delete")
|
||||
dos_qguiapplication_delete()
|
||||
application.deleted = true
|
||||
|
||||
proc newQGuiApplication*(): QGuiApplication =
|
||||
## Return a new QApplication
|
||||
newWithCondFinalizer(result, delete)
|
||||
result.create()
|
||||
|
||||
# QObject
|
||||
type RawQVariantArray {.unchecked.} = array[0..0, RawQVariant]
|
||||
type RawQVariantArrayPtr = ptr RawQVariantArray
|
||||
type RawQVariantSeq = seq[RawQVariant]
|
||||
|
||||
proc toVariantSeq(args: RawQVariantArrayPtr, numArgs: cint): seq[QVariant] =
|
||||
result = @[]
|
||||
for i in 0..numArgs-1:
|
||||
result.add(newQVariant(args[i]))
|
||||
|
||||
proc toRawVariantSeq(args: openarray[QVariant]): RawQVariantSeq =
|
||||
result = @[]
|
||||
for variant in args:
|
||||
result.add(variant.data)
|
||||
|
||||
proc delete(sequence: seq[QVariant]) =
|
||||
for variant in sequence:
|
||||
variant.delete
|
||||
|
||||
proc toCIntSeq(metaTypes: openarray[QMetaType]): seq[cint] =
|
||||
result = @[]
|
||||
for metaType in metaTypes:
|
||||
result.add(cint(metaType))
|
||||
|
||||
type QObjectCallBack = proc(nimobject: ptr QObjectObj, slotName: RawQVariant, numArguments: cint, arguments: RawQVariantArrayPtr) {.cdecl.}
|
||||
|
||||
proc dos_qobject_create(qobject: var RawQObject, nimobject: ptr QObjectObj, qobjectCallback: QObjectCallBack) {.cdecl, dynlib:dOtherSideDll, importc.}
|
||||
proc dos_qobject_delete(qobject: RawQObject) {.cdecl, dynlib:dOtherSideDll, importc.}
|
||||
proc dos_qobject_slot_create(qobject: RawQObject, slotName: cstring, argumentsCount: cint, argumentsMetaTypes: ptr cint, slotIndex: var cint) {.cdecl, dynlib:dOtherSideDll, importc.}
|
||||
proc dos_qobject_signal_create(qobject: RawQObject, signalName: cstring, argumentsCount: cint, argumentsMetaTypes: ptr cint, signalIndex: var cint) {.cdecl, dynlib:dOtherSideDll, importc.}
|
||||
proc dos_qobject_signal_emit(qobject: RawQObject, signalName: cstring, argumentsCount: cint, arguments: ptr RawQVariant) {.cdecl, dynlib:dOtherSideDll, importc.}
|
||||
proc dos_qobject_property_create(qobject: RawQObject, propertyName: cstring, propertyType: cint, readSlot: cstring, writeSlot: cstring, notifySignal: cstring) {.cdecl, dynlib:dOtherSideDll, importc.}
|
||||
|
||||
method onSlotCalled*(nimobject: QObject, slotName: string, args: openarray[QVariant]) =
|
||||
## Called from the NimQml bridge when a slot is called from Qml.
|
||||
## Subclasses can override the given method for handling the slot call
|
||||
discard()
|
||||
|
||||
proc qobjectCallback(nimObject: ptr QObjectObj, slotName: RawQVariant, numArguments: cint, arguments: RawQVariantArrayPtr) {.cdecl, exportc.} =
|
||||
if qobjectRegistry[nimObject]:
|
||||
let qobject = cast[QObject](nimObject)
|
||||
GC_ref(qobject)
|
||||
let slotNameAsQVariant = newQVariant(slotName)
|
||||
defer: slotNameAsQVariant.delete
|
||||
let argumentsAsQVariant = arguments.toVariantSeq(numArguments)
|
||||
defer: argumentsAsQVariant.delete
|
||||
# Forward to args to the slot
|
||||
qobject.onSlotCalled(slotNameAsQVariant.stringVal, argumentsAsQVariant)
|
||||
# Update the slot return value
|
||||
dos_qvariant_assign(arguments[0], argumentsAsQVariant[0].data)
|
||||
GC_unref(qobject)
|
||||
|
||||
proc create*(qobject: QObject) =
|
||||
## Create a new QObject
|
||||
debugMsg("QObject", "create")
|
||||
qobject.deleted = false
|
||||
qobject.slots = initTable[string,cint]()
|
||||
qobject.signals = initTable[string, cint]()
|
||||
qobject.properties = initTable[string, cint]()
|
||||
let qobjectPtr = addr(qobject[])
|
||||
dos_qobject_create(qobject.data, qobjectPtr, qobjectCallback)
|
||||
qobjectRegistry[qobjectPtr] = true
|
||||
|
||||
proc delete*(qobject: QObject) =
|
||||
## Delete the given QObject
|
||||
if not qobject.deleted:
|
||||
debugMsg("QObject", "delete")
|
||||
let qobjectPtr = addr(qobject[])
|
||||
qobjectRegistry.del qobjectPtr
|
||||
dos_qobject_delete(qobject.data)
|
||||
qobject.data = nil.RawQObject
|
||||
qobject.deleted = true
|
||||
|
||||
proc newQObject*(): QObject =
|
||||
## Return a new QObject
|
||||
newWithCondFinalizer(result, delete)
|
||||
result.create()
|
||||
|
||||
proc registerSlot*(qobject: QObject,
|
||||
slotName: string,
|
||||
metaTypes: openarray[QMetaType]) =
|
||||
## Register a slot in the QObject with the given name and signature
|
||||
# Copy the metatypes array
|
||||
var copy = toCIntSeq(metatypes)
|
||||
var index: cint
|
||||
dos_qobject_slot_create(qobject.data, slotName, cint(copy.len), addr(copy[0].cint), index)
|
||||
qobject.slots[slotName] = index
|
||||
|
||||
proc registerSignal*(qobject: QObject,
|
||||
signalName: string,
|
||||
metatypes: openarray[QMetaType]) =
|
||||
## Register a signal in the QObject with the given name and signature
|
||||
var index: cint
|
||||
if metatypes.len > 0:
|
||||
var copy = toCIntSeq(metatypes)
|
||||
dos_qobject_signal_create(qobject.data, signalName, copy.len.cint, addr(copy[0].cint), index)
|
||||
else:
|
||||
dos_qobject_signal_create(qobject.data, signalName, 0, nil, index)
|
||||
qobject.signals[signalName] = index
|
||||
|
||||
proc registerProperty*(qobject: QObject,
|
||||
propertyName: string,
|
||||
propertyType: QMetaType,
|
||||
readSlot: string,
|
||||
writeSlot: string,
|
||||
notifySignal: string) =
|
||||
## Register a property in the QObject with the given name and type.
|
||||
assert propertyName != nil, "property name cannot be nil"
|
||||
# don't convert a nil string, else we get a strange memory address
|
||||
let cReadSlot: cstring = if readSlot == nil: cast[cstring](nil) else: readSlot
|
||||
let cWriteSlot: cstring = if writeSlot == nil: cast[cstring](nil) else: writeSlot
|
||||
let cNotifySignal: cstring = if notifySignal == nil: cast[cstring](nil) else: notifySignal
|
||||
dos_qobject_property_create(qobject.data, propertyName, propertyType.cint, cReadSlot, cWriteSlot, cNotifySignal)
|
||||
|
||||
proc emit*(qobject: QObject, signalName: string, args: openarray[QVariant] = []) =
|
||||
## Emit the signal with the given name and values
|
||||
if args.len > 0:
|
||||
var copy = args.toRawVariantSeq
|
||||
dos_qobject_signal_emit(qobject.data, signalName, copy.len.cint, addr(copy[0]))
|
||||
else:
|
||||
dos_qobject_signal_emit(qobject.data, signalName, 0, nil)
|
||||
|
||||
# QQuickView
|
||||
proc dos_qquickview_create(view: var RawQQuickView) {.cdecl, dynlib:dOtherSideDll, importc.}
|
||||
proc dos_qquickview_delete(view: RawQQuickView) {.cdecl, dynlib:dOtherSideDll, importc.}
|
||||
proc dos_qquickview_show(view: RawQQuickView) {.cdecl, dynlib:dOtherSideDll, importc.}
|
||||
proc dos_qquickview_source(view: RawQQuickView, filename: var cstring, length: var int) {.cdecl, dynlib:dOtherSideDll, importc.}
|
||||
proc dos_qquickview_set_source(view: RawQQuickView, filename: cstring) {.cdecl, dynlib:dOtherSideDll, importc.}
|
||||
|
||||
proc create(view: var QQuickView) =
|
||||
## Create a new QQuickView
|
||||
dos_qquickview_create(view.data)
|
||||
view.deleted = false
|
||||
|
||||
proc source(view: QQuickView): cstring =
|
||||
## Return the source Qml file loaded by the view
|
||||
var length: int
|
||||
dos_qquickview_source(view.data, result, length)
|
||||
|
||||
proc `source=`(view: QQuickView, filename: cstring) =
|
||||
## Sets the source Qml file laoded by the view
|
||||
dos_qquickview_set_source(view.data, filename)
|
||||
|
||||
proc show(view: QQuickView) =
|
||||
## Sets the view visible
|
||||
dos_qquickview_show(view.data)
|
||||
|
||||
proc delete(view: QQuickView) =
|
||||
## Delete the given QQuickView
|
||||
if not view.deleted:
|
||||
debugMsg("QQuickView", "delete")
|
||||
dos_qquickview_delete(view.data)
|
||||
view.data = nil.RawQQuickView
|
||||
view.deleted = true
|
||||
|
||||
proc newQQuickView*(): QQuickView =
|
||||
## Return a new QQuickView
|
||||
newWithCondFinalizer(result, delete)
|
||||
result.create()
|
||||
|
||||
# QModelIndex
|
||||
proc dos_qmodelindex_create(modelIndex: var RawQModelIndex) {.cdecl, dynlib:dOtherSideDll, importc.}
|
||||
proc dos_qmodelindex_delete(modelIndex: RawQModelIndex) {.cdecl, dynlib:dOtherSideDll, importc.}
|
||||
proc dos_qmodelindex_row(modelIndex: RawQModelIndex, row: var cint) {.cdecl, dynlib:dOtherSideDll, importc.}
|
||||
proc dos_qmodelindex_column(modelIndex: RawQModelIndex, column: var cint) {.cdecl, dynlib:dOtherSideDll, importc.}
|
||||
proc dos_qmodelindex_isValid(modelIndex: RawQModelIndex, column: var bool) {.cdecl, dynlib:dOtherSideDll, importc.}
|
||||
proc dos_qmodelindex_data(modelIndex: RawQModelIndex, role: cint, data: RawQVariant) {.cdecl, dynlib:dOtherSideDll, importc.}
|
||||
proc dos_qmodelindex_parent(modelIndex: RawQModelIndex, parent: RawQModelIndex) {.cdecl, dynlib:dOtherSideDll, importc.}
|
||||
proc dos_qmodelindex_child(modelIndex: RawQModelIndex, row: cint, column: cint, parent: RawQModelIndex) {.cdecl, dynlib:dOtherSideDll, importc.}
|
||||
proc dos_qmodelindex_sibling(modelIndex: RawQModelIndex, row: cint, column: cint, sibling: RawQModelIndex) {.cdecl, dynlib:dOtherSideDll, importc.}
|
||||
|
||||
proc create*(modelIndex: var QModelIndex) =
|
||||
## Create a new QModelIndex
|
||||
dos_qmodelindex_create(modelIndex.data)
|
||||
modelIndex.deleted = false
|
||||
|
||||
proc create*(modelIndex: var QModelIndex, rawQModelIndex: RawQModelIndex) =
|
||||
## Create a new QModelIndex
|
||||
modelIndex.data = rawQModelIndex
|
||||
modelIndex.deleted = false
|
||||
|
||||
proc delete*(modelIndex: QModelIndex) =
|
||||
## Delete the given QModelIndex
|
||||
if not modelIndex.deleted:
|
||||
debugMsg("QModelIndex", "delete")
|
||||
dos_qmodelindex_delete(modelIndex.data)
|
||||
modelIndex.data = nil.RawQModelIndex
|
||||
modelIndex.deleted = true
|
||||
|
||||
proc newQModelIndex*(): QModelIndex =
|
||||
## Return a new QModelIndex
|
||||
newWithCondFinalizer(result, delete)
|
||||
result.create()
|
||||
|
||||
proc newQModelIndex*(rawQModelIndex: RawQModelIndex): QModelIndex =
|
||||
## Return a new QModelIndex given a raw index
|
||||
newWithCondFinalizer(result, delete)
|
||||
result.create(rawQModelIndex)
|
||||
|
||||
proc row*(modelIndex: QModelIndex): cint =
|
||||
## Return the index row
|
||||
dos_qmodelindex_row(modelIndex.data, result)
|
||||
|
||||
proc column*(modelIndex: QModelIndex): cint =
|
||||
## Return the index column
|
||||
dos_qmodelindex_column(modelIndex.data, result)
|
||||
|
||||
proc isValid*(modelIndex: QModelIndex): bool =
|
||||
## Return true if the index is valid, false otherwise
|
||||
dos_qmodelindex_isValid(modelIndex.data, result)
|
||||
|
||||
proc data*(modelIndex: QModelIndex, role: cint): QVariant =
|
||||
## Return the model data associated to the given role
|
||||
result = newQVariant()
|
||||
dos_qmodelindex_data(modelIndex.data, role, result.data)
|
||||
|
||||
proc parent*(modelIndex: QModelIndex): QModelIndex =
|
||||
## Return the parent index
|
||||
result = newQModelIndex()
|
||||
dos_qmodelindex_parent(modelIndex.data, result.data)
|
||||
|
||||
proc child*(modelIndex: QModelIndex, row: cint, column: cint): QModelIndex =
|
||||
## Return the child index associated to the given row and column
|
||||
result = newQModelIndex()
|
||||
dos_qmodelindex_child(modelIndex.data, row, column, result.data)
|
||||
|
||||
proc sibling*(modelIndex: QModelIndex, row: cint, column: cint): QModelIndex =
|
||||
## Return the sibling index associated to the given row and column
|
||||
result = newQModelIndex()
|
||||
dos_qmodelindex_sibling(modelIndex.data, row, column, result.data)
|
||||
|
||||
# QHashIntByteArray
|
||||
proc dos_qhash_int_qbytearray_create(qHash: var RawQHashIntByteArray) {.cdecl, dynlib:dOtherSideDll, importc.}
|
||||
proc dos_qhash_int_qbytearray_delete(qHash: RawQHashIntByteArray) {.cdecl, dynlib:dOtherSideDll, importc.}
|
||||
proc dos_qhash_int_qbytearray_insert(qHash: RawQHashIntByteArray, key: int, value: cstring) {.cdecl, dynlib:dOtherSideDll, importc.}
|
||||
proc dos_qhash_int_qbytearray_value(qHash: RawQHashIntByteArray, key: int, value: var cstring) {.cdecl, dynlib:dOtherSideDll, importc.}
|
||||
|
||||
proc create*(qHash: var QHashIntByteArray) =
|
||||
## Create the QHash
|
||||
debugMsg("QHashIntByteArray", "create")
|
||||
dos_qhash_int_qbytearray_create(qHash.data)
|
||||
qHash.deleted = false
|
||||
|
||||
proc delete*(qHash: QHashIntByteArray) =
|
||||
## Delete the QHash
|
||||
if not qHash.deleted:
|
||||
debugMsg("QHashIntByteArray", "delete")
|
||||
dos_qhash_int_qbytearray_delete(qHash.data)
|
||||
qHash.deleted = true
|
||||
|
||||
proc insert*(qHash: QHashIntByteArray, key: int, value: cstring) =
|
||||
## Insert the value at the given key
|
||||
dos_qhash_int_qbytearray_insert(qHash.data, key, value)
|
||||
|
||||
proc value*(qHash: QHashIntByteArray, key: int): string =
|
||||
## Return the value associated at the given key
|
||||
var rawString: cstring
|
||||
dos_qhash_int_qbytearray_value(qHash.data, key, rawString)
|
||||
result = $rawString
|
||||
dos_chararray_delete(rawString)
|
||||
|
||||
proc newQHashIntQByteArray*(): QHashIntByteArray =
|
||||
## Create a new QHashIntQByteArray
|
||||
newWithCondFinalizer(result, delete)
|
||||
result.create()
|
||||
|
||||
# QAbstractListModel
|
||||
type
|
||||
RowCountCallback = proc(modelObject: ptr QAbstractListModelObj, rawIndex: RawQModelIndex, result: var cint) {.cdecl.}
|
||||
ColumnCountCallback = proc(modelObject: ptr QAbstractListModelObj, rawIndex: RawQModelIndex, result: var cint) {.cdecl.}
|
||||
DataCallback = proc(modelObject: ptr QAbstractListModelObj, rawIndex: RawQModelIndex, role: cint, result: RawQVariant) {.cdecl.}
|
||||
SetDataCallback = proc(modelObject: ptr QAbstractListModelObj, rawIndex: RawQModelIndex, value: RawQVariant, role: cint, result: var bool) {.cdecl.}
|
||||
RoleNamesCallback = proc(modelObject: ptr QAbstractListModelObj, result: RawQHashIntByteArray) {.cdecl.}
|
||||
FlagsCallback = proc(modelObject: ptr QAbstractListModelObj, index: RawQModelIndex, result: var cint) {.cdecl.}
|
||||
HeaderDataCallback = proc(modelObject: ptr QAbstractListModelObj, section: cint, orientation: cint, role: cint, result: RawQVariant) {.cdecl.}
|
||||
|
||||
proc dos_qabstractlistmodel_create(model: var RawQAbstractListModel,
|
||||
modelPtr: ptr QAbstractListModelObj,
|
||||
qobjectCallback: QObjectCallBack,
|
||||
rowCountCallback: RowCountCallback,
|
||||
columnCountCallback: ColumnCountCallback,
|
||||
dataCallback: DataCallback,
|
||||
setDataCallback: SetDataCallBack,
|
||||
roleNamesCallback: RoleNamesCallback,
|
||||
flagsCallback: FlagsCallback,
|
||||
headerDataCallback: HeaderDataCallback) {.cdecl, dynlib:dOtherSideDll, importc.}
|
||||
proc dos_qabstractlistmodel_delete(model: RawQAbstractListModel) {.cdecl, dynlib:dOtherSideDll, importc.}
|
||||
proc dos_qabstractlistmodel_beginInsertRows(model: RawQAbstractListModel,
|
||||
parentIndex: RawQModelIndex,
|
||||
first: cint,
|
||||
last: cint) {.cdecl, dynlib:dOtherSideDll, importc.}
|
||||
proc dos_qabstractlistmodel_endInsertRows(model: RawQAbstractListModel) {.cdecl, dynlib:dOtherSideDll, importc.}
|
||||
proc dos_qabstractlistmodel_beginRemoveRows(model: RawQAbstractListModel,
|
||||
parentIndex: RawQModelIndex,
|
||||
first: cint,
|
||||
last: cint) {.cdecl, dynlib:dOtherSideDll, importc.}
|
||||
proc dos_qabstractlistmodel_endRemoveRows(model: RawQAbstractListModel) {.cdecl, dynlib:dOtherSideDll, importc.}
|
||||
proc dos_qabstractlistmodel_beginResetModel(model: RawQAbstractListModel) {.cdecl, dynlib:dOtherSideDll, importc.}
|
||||
proc dos_qabstractlistmodel_endResetModel(model: RawQAbstractListModel) {.cdecl, dynlib:dOtherSideDll, importc.}
|
||||
proc dos_qabstractlistmodel_dataChanged(model: RawQAbstractListModel,
|
||||
parentLeft: RawQModelIndex,
|
||||
bottomRight: RawQModelIndex,
|
||||
rolesArrayPtr: ptr cint,
|
||||
rolesArrayLength: cint) {.cdecl, dynlib:dOtherSideDll, importc.}
|
||||
|
||||
method rowCount*(model: QAbstractListModel, index: QModelIndex): cint =
|
||||
## Return the model's row count
|
||||
return 0
|
||||
|
||||
proc rowCountCallback(modelObject: ptr QAbstractListModelObj, rawIndex: RawQModelIndex, result: var cint) {.cdecl, exportc.} =
|
||||
debugMsg("QAbstractListModel", "rowCountCallback")
|
||||
let model = cast[QAbstractListModel](modelObject)
|
||||
let index = newQModelIndex(rawIndex)
|
||||
result = model.rowCount(index)
|
||||
|
||||
method columnCount*(model: QAbstractListModel, index: QModelIndex): cint =
|
||||
## Return the model's column count
|
||||
return 1
|
||||
|
||||
proc columnCountCallback(modelObject: ptr QAbstractListModelObj, rawIndex: RawQModelIndex, result: var cint) {.cdecl, exportc.} =
|
||||
debugMsg("QAbstractListModel", "columnCountCallback")
|
||||
let model = cast[QAbstractListModel](modelObject)
|
||||
let index = newQModelIndex(rawIndex)
|
||||
result = model.columnCount(index)
|
||||
|
||||
method data*(model: QAbstractListModel, index: QModelIndex, role: cint): QVariant =
|
||||
## Return the data at the given model index and role
|
||||
return nil
|
||||
|
||||
proc dataCallback(modelObject: ptr QAbstractListModelObj, rawIndex: RawQModelIndex, role: cint, result: RawQVariant) {.cdecl, exportc.} =
|
||||
debugMsg("QAbstractListModel", "dataCallback")
|
||||
let model = cast[QAbstractListModel](modelObject)
|
||||
let index = newQModelIndex(rawIndex)
|
||||
let variant = data(model, index, role)
|
||||
if variant != nil:
|
||||
dos_qvariant_assign(result, variant.data)
|
||||
variant.delete
|
||||
|
||||
method setData*(model: QAbstractListModel, index: QModelIndex, value: QVariant, role: cint): bool =
|
||||
## Sets the data at the given index and role. Return true on success, false otherwise
|
||||
return false
|
||||
|
||||
proc setDataCallback(modelObject: ptr QAbstractListModelObj, rawIndex: RawQModelIndex, rawQVariant: RawQVariant, role: cint, result: var bool) {.cdecl, exportc.} =
|
||||
debugMsg("QAbstractListModel", "setDataCallback")
|
||||
let model = cast[QAbstractListModel](modelObject)
|
||||
let index = newQModelIndex(rawIndex)
|
||||
let variant = newQVariant(rawQVariant)
|
||||
result = model.setData(index, variant, role)
|
||||
|
||||
method roleNames*(model: QAbstractListModel): Table[cint, cstring] =
|
||||
## Return the model role names
|
||||
result = initTable[cint, cstring]()
|
||||
|
||||
proc roleNamesCallback(modelObject: ptr QAbstractListModelObj, hash: RawQHashIntByteArray) {.cdecl, exportc.} =
|
||||
debugMsg("QAbstractListModel", "roleNamesCallback")
|
||||
let model = cast[QAbstractListModel](modelObject)
|
||||
let table = model.roleNames()
|
||||
for key, val in table.pairs:
|
||||
dos_qhash_int_qbytearray_insert(hash, key, val)
|
||||
|
||||
method flags*(model: QAbstractListModel, index: QModelIndex): QtItemFlag =
|
||||
## Return the item flags and the given index
|
||||
return QtItemFlag.None
|
||||
|
||||
proc flagsCallback(modelObject: ptr QAbstractListModelObj, rawIndex: RawQModelIndex, result: var cint) {.cdecl, exportc.} =
|
||||
debugMsg("QAbstractListModel", "flagsCallback")
|
||||
let model = cast[QAbstractListModel](modelObject)
|
||||
let index = newQModelIndex(rawIndex)
|
||||
result = model.flags(index).cint
|
||||
|
||||
method headerData*(model: QAbstractListModel, section: cint, orientation: QtOrientation, role: cint): QVariant =
|
||||
## Returns the data for the given role and section in the header with the specified orientation
|
||||
return nil
|
||||
|
||||
proc headerDataCallback(modelObject: ptr QAbstractListModelObj, section: cint, orientation: cint, role: cint, result: RawQVariant) {.cdecl, exportc.} =
|
||||
debugMsg("QAbstractListModel", "headerDataCallback")
|
||||
let model = cast[QAbstractListModel](modelObject)
|
||||
let variant = model.headerData(section, orientation.QtOrientation, role)
|
||||
if variant != nil:
|
||||
dos_qvariant_assign(result, variant.data)
|
||||
variant.delete
|
||||
|
||||
proc create*(model: var QAbstractListModel) =
|
||||
## Create a new QAbstractListModel
|
||||
debugMsg("QAbstractListModel", "create")
|
||||
model.slots = initTable[string,cint]()
|
||||
model.signals = initTable[string, cint]()
|
||||
model.properties = initTable[string, cint]()
|
||||
model.deleted = false
|
||||
let modelPtr = addr(model[])
|
||||
dos_qabstractlistmodel_create(model.data.RawQAbstractListModel, modelPtr, qobjectCallback, rowCountCallback, columnCountCallback, dataCallback, setDataCallback, roleNamesCallback, flagsCallback, headerDataCallback)
|
||||
qobjectRegistry[modelPtr] = true
|
||||
|
||||
proc delete*(model: QAbstractListModel) =
|
||||
## Delete the given QAbstractListModel
|
||||
if not model.deleted:
|
||||
debugMsg("QAbstractListModel", "delete")
|
||||
let modelPtr = addr(model[])
|
||||
qobjectRegistry.del modelPtr
|
||||
dos_qabstractlistmodel_delete(model.data.RawQAbstractListModel)
|
||||
model.data = nil.RawQObject
|
||||
model.deleted = true
|
||||
|
||||
proc newQAbstractListModel*(): QAbstractListModel =
|
||||
## Return a new QAbstractListModel
|
||||
newWithCondFinalizer(result, delete)
|
||||
result.create()
|
||||
|
||||
proc beginInsertRows*(model: QAbstractListModel, parentIndex: QModelIndex, first: int, last: int) =
|
||||
## Notify the view that the model is about to inserting the given number of rows
|
||||
dos_qabstractlistmodel_beginInsertRows(model.data.RawQAbstractListModel, parentIndex.data, first.cint, last.cint)
|
||||
|
||||
proc endInsertRows*(model: QAbstractListModel) =
|
||||
## Notify the view that the rows have been inserted
|
||||
dos_qabstractlistmodel_endInsertRows(model.data.RawQAbstractListModel)
|
||||
|
||||
proc beginRemoveRows*(model: QAbstractListModel, parentIndex: QModelIndex, first: int, last: int) =
|
||||
## Notify the view that the model is about to remove the given number of rows
|
||||
dos_qabstractlistmodel_beginRemoveRows(model.data.RawQAbstractListModel, parentIndex.data, first.cint, last.cint)
|
||||
|
||||
proc endRemoveRows*(model: QAbstractListModel) =
|
||||
## Notify the view that the rows have been removed
|
||||
dos_qabstractlistmodel_endRemoveRows(model.data.RawQAbstractListModel)
|
||||
|
||||
proc beginResetModel*(model: QAbstractListModel) =
|
||||
## Notify the view that the model is about to resetting
|
||||
dos_qabstractlistmodel_beginResetModel(model.data.RawQAbstractListModel)
|
||||
|
||||
proc endResetModel*(model: QAbstractListModel) =
|
||||
## Notify the view that model has finished resetting
|
||||
dos_qabstractlistmodel_endResetModel(model.data.RawQAbstractListModel)
|
||||
|
||||
proc dataChanged*(model: QAbstractListModel,
|
||||
topLeft: QModelIndex,
|
||||
bottomRight: QModelIndex,
|
||||
roles: seq[cint]) =
|
||||
## Notify the view that the model data changed
|
||||
var copy = roles
|
||||
dos_qabstractlistmodel_dataChanged(model.data.RawQAbstractListModel, topLeft.data, bottomRight.data, copy[0].addr, copy.len.cint)
|
||||
|
|
@ -1,9 +0,0 @@
|
|||
[Package]
|
||||
name = "NimQml"
|
||||
version = "0.3.0"
|
||||
author = "Filippo Cucchetto, Will Szumski"
|
||||
description = "QML bindings for Nimrod"
|
||||
license = "GPLv3"
|
||||
|
||||
[Deps]
|
||||
Requires: "nimrod >= 0.10.2"
|
|
@ -1,502 +0,0 @@
|
|||
## Contains helper macros for NimQml
|
||||
|
||||
import macros
|
||||
import strutils
|
||||
import typetraits
|
||||
import tables
|
||||
|
||||
template debug(body: stmt): stmt =
|
||||
{.push warning[user]: off.}
|
||||
when defined(debug):
|
||||
{.pop.}
|
||||
body
|
||||
else:
|
||||
{.pop.}
|
||||
|
||||
let nimFromQtVariant {.compileTime.} = {
|
||||
"int" : "intVal",
|
||||
"string" : "stringVal",
|
||||
"bool" : "boolVal",
|
||||
"float" : "floatVal",
|
||||
"QObject" : "qobjectVal",
|
||||
}.toTable
|
||||
|
||||
let nim2QtMeta {.compileTime.} = {
|
||||
"bool": "Bool",
|
||||
"int" : "Int",
|
||||
"string" : "QString",
|
||||
"pointer" : "VoidStar",
|
||||
"QObject" : "QObjectStar",
|
||||
"QVariant": "QVariant",
|
||||
"" : "Void", # no return, which is represented by an nnkEmpty node
|
||||
}.toTable
|
||||
|
||||
proc getNodeOf*(tree: NimNode, kind: NimNodeKind): NimNode {.compileTime.} =
|
||||
## recursively looks for a node of kind, ``kind``, in the tree provided as ``tree``
|
||||
## Returns the first node that satisfies this condition
|
||||
for i in 0.. <tree.len:
|
||||
var child = tree[i]
|
||||
if child.kind == kind:
|
||||
return child
|
||||
var candidate = getNodeOf(child, kind)
|
||||
if not candidate.isNil:
|
||||
return candidate
|
||||
|
||||
static:
|
||||
type Context* = ref object of RootObj
|
||||
type NullContext* = ref object of Context
|
||||
|
||||
type NodeModifier*[T] = proc(context: T, a: var NimNode): NimNode
|
||||
|
||||
# had to remove type bound on hook due to recent regression with generics
|
||||
proc hookOnNode*[T](context: T, code: NimNode, hook: NodeModifier,
|
||||
recursive: bool = false): NimNode {.compileTime.} =
|
||||
## Iterates over the tree, ``code``, calling ``hook`` on each ``NimNode``
|
||||
## encountered. If ``recursive`` is true, it will recurse over the tree, otherwise
|
||||
## it will only visit ``code``'s children. ``hook`` should return a replacement for
|
||||
## the node that was passed in via it's return value. `hook` may return nil to remove
|
||||
## the node from the tree.
|
||||
if code.len == 0:
|
||||
return code
|
||||
var newCode = newNimNode(code.kind)
|
||||
for i in 0.. <code.len:
|
||||
var child = code[i].copy()
|
||||
child = hook(context, child)
|
||||
if recursive:
|
||||
child = hookOnNode(context,child,hook,true)
|
||||
if child != nil:
|
||||
newCode.add child
|
||||
return newCode
|
||||
|
||||
proc removeOpenSym*(context: NullContext,
|
||||
a: var NimNode): NimNode {.compileTime.} =
|
||||
## replaces: ``nnkOpenSymChoice`` and ``nnkSym`` nodes with idents
|
||||
## corresponding to the symbols string representation.
|
||||
if a.kind == nnkOpenSymChoice:
|
||||
return ident($a[0].symbol)
|
||||
elif a.kind == nnkSym:
|
||||
return ident($a.symbol)
|
||||
return a
|
||||
|
||||
proc newTemplate*(name = newEmptyNode();
|
||||
params: openArray[NimNode] = [newEmptyNode()];
|
||||
body: NimNode = newStmtList()): NimNode {.compileTime.} =
|
||||
## shortcut for creating a new template
|
||||
##
|
||||
## The ``params`` array must start with the return type of the template,
|
||||
## followed by a list of IdentDefs which specify the params.
|
||||
result = newNimNode(nnkTemplateDef).add(
|
||||
name,
|
||||
newEmptyNode(),
|
||||
newEmptyNode(),
|
||||
newNimNode(nnkFormalParams).add(params), ##params
|
||||
newEmptyNode(), ## pragmas
|
||||
newEmptyNode(),
|
||||
body)
|
||||
|
||||
#FIXME: changed parent, typ from typedesc to expr to workaround Nim issue #1874
|
||||
template declareSuperTemplate*(parent: expr, typ: expr): stmt =
|
||||
template superType*(ofType: typedesc[typ]): typedesc[parent] =
|
||||
parent
|
||||
|
||||
proc getTypeName*(a: NimNode): NimNode {.compileTime.} =
|
||||
## returns the node containing the name of an object in a
|
||||
## given type definition block
|
||||
expectMinLen a, 1
|
||||
expectKind a, nnkTypeDef
|
||||
var testee = a
|
||||
if testee[0].kind == nnkPragmaExpr:
|
||||
testee = testee[0]
|
||||
if testee[0].kind in {nnkIdent}:
|
||||
return testee[0]
|
||||
elif testee[0].kind in {nnkPostfix}:
|
||||
return testee[0][1]
|
||||
|
||||
proc isExported(def: NimNode): bool {.compileTime.} =
|
||||
## given a type definition, ``typedef``, determines whether or
|
||||
## not the type is exported with a '*'
|
||||
assert def.kind in {nnkTypeDef, nnkProcDef, nnkMethodDef, nnkTemplateDef},
|
||||
"unsupported type: " & $def.kind
|
||||
if def[0].kind == nnkPostfix:
|
||||
return true
|
||||
|
||||
proc exportDef(def: NimNode) {.compileTime.} =
|
||||
## Exports exportable definitions. Currently only supports
|
||||
## templates, methods and procedures and types.
|
||||
if def.kind in {nnkProcDef, nnkMethodDef, nnkTemplateDef, nnkTypeDef}:
|
||||
if def.isExported:
|
||||
return
|
||||
def[0] = postfix(def[0], "*")
|
||||
else:
|
||||
error("node: " & $def.kind & " not supported")
|
||||
|
||||
proc unexportDef(def: NimNode) {.compileTime.} =
|
||||
## unexports exportable definitions. Currently only supports
|
||||
## templates, methods and procedures and types.
|
||||
if def.kind in {nnkProcDef, nnkMethodDef, nnkTemplateDef, nnkTypeDef}:
|
||||
if not def.isExported:
|
||||
return
|
||||
def[0] = ident unpackPostfix(def[0])[1]
|
||||
else:
|
||||
error("node: " & $def.kind & " not supported")
|
||||
|
||||
proc genSuperTemplate*(typeDecl: NimNode): NimNode {.compileTime.} =
|
||||
## generates a template, with name: superType, that returns the super type
|
||||
## of the object defined in the type defintion, ``typeDecl``. ``typeDecl``
|
||||
## must contain an object inheriting from a base type.
|
||||
expectKind typeDecl, nnkTypeDef
|
||||
let inheritStmt = typeDecl.getNodeOf(nnkOfInherit)
|
||||
let typeName = getTypeName(typeDecl)
|
||||
if inheritStmt == nil: error("you must declare a super type for " & $typeName)
|
||||
# ident of superType (have to deal with generics)
|
||||
let superType = if inheritStmt[0].kind == nnkIdent: inheritStmt[0]
|
||||
else: inheritStmt[0].getNodeOf(nnkIdent)
|
||||
let superTemplate = getAst declareSuperTemplate(superType, typeName)
|
||||
result = superTemplate[0]
|
||||
if typeDecl.isExported():
|
||||
result.exportDef()
|
||||
else:
|
||||
result.unexportDef()
|
||||
|
||||
proc getSuperType*(typeDecl: NimNode): NimNode {.compileTime.} =
|
||||
## returns ast containing superType info, may not be an ident if generic
|
||||
let inheritStmt = typeDecl.getNodeOf(nnkOfInherit)
|
||||
if inheritStmt.isNil: return newEmptyNode()
|
||||
return inheritStmt[0]
|
||||
|
||||
proc getPragmaName*(child: NimNode): NimNode {.compileTime.} =
|
||||
## name of child in a nnkPragma section
|
||||
if child.kind == nnkIdent:
|
||||
return child
|
||||
# assumes first ident is name of pragma
|
||||
let ident = child.getNodeOf(nnkIdent)
|
||||
result = ident
|
||||
|
||||
proc removePragma*(pragma: NimNode, toRemove: string): NimNode {.compileTime.} =
|
||||
## removes a pragma from pragma definition, `pragma`, with name `toRemove`
|
||||
expectKind pragma, nnkPragma
|
||||
result = newNimNode(nnkPragma)
|
||||
for i in 0.. <pragma.len:
|
||||
let child = pragma[i]
|
||||
if $child.getPragmaName == toRemove:
|
||||
continue
|
||||
result.add child
|
||||
if result.len == 0:
|
||||
return newEmptyNode()
|
||||
|
||||
proc hasPragma*(node: NimNode, pragmaName: string): bool {.compileTime.} =
|
||||
## Returns ``true`` iff the method, or proc definition: ``node``, has a pragma
|
||||
## ``pragmaName``
|
||||
doAssert node.kind in {nnkMethodDef, nnkProcDef}
|
||||
result = false
|
||||
let pragma = node.pragma
|
||||
if pragma.kind == nnkEmpty:
|
||||
# denotes no pragma set
|
||||
return false
|
||||
for child in pragma.children():
|
||||
if $child.getPragmaName() == pragmaName:
|
||||
return true
|
||||
|
||||
proc getArgType*(arg: NimNode): NimNode {.compileTime.} =
|
||||
## returns the ``NimNode`` representing a parameters type
|
||||
if arg[1].kind == nnkIdent:
|
||||
arg[1]
|
||||
else:
|
||||
arg[1].getNodeOf(nnkIdent)
|
||||
|
||||
proc getArgName*(arg: NimNode): NimNode {.compileTime.} =
|
||||
## returns the ``NimNode`` representing a parameters name
|
||||
if arg[0].kind == nnkIdent:
|
||||
arg[0]
|
||||
else:
|
||||
arg[0].getNodeOf(nnkIdent)
|
||||
|
||||
proc addSignalBody(signal: NimNode): NimNode {.compileTime.} =
|
||||
# e.g: produces: emit(MyQObject, "nameChanged")
|
||||
assert signal.kind in {nnkMethodDef, nnkProcDef}
|
||||
result = newStmtList()
|
||||
# if exported, will use postfix
|
||||
let name = if signal.name.kind == nnkIdent: signal.name else: signal.name[1]
|
||||
let params = signal.params
|
||||
# type signal defined on is the 1st arg
|
||||
let self = getArgName(params[1])
|
||||
var args = newSeq[NimNode]()
|
||||
args.add(self)
|
||||
args.add newLit($name)
|
||||
if params.len > 2: # more args than just type
|
||||
for i in 2.. <params.len:
|
||||
args.add getArgName params[i]
|
||||
result.add newCall("emit", args)
|
||||
|
||||
#FIXME: changed typ from typedesc to expr to workaround Nim issue #1874
|
||||
# This is declared dirty so that identifers are not bound to symbols.
|
||||
# The alternative is to use `removeOpenSym` as we did for `prototypeCreate`.
|
||||
# We should decide which method is preferable.
|
||||
template prototypeOnSlotCalled(typ: expr): stmt {.dirty.} =
|
||||
method onSlotCalled(myQObject: typ, slotName: string, args: openarray[QVariant]) =
|
||||
var super = (typ.superType())(myQObject)
|
||||
procCall onSlotCalled(super, slotName, args)
|
||||
|
||||
#FIXME: changed parent, typ from typedesc to expr to workaround Nim issue #1874
|
||||
template prototypeCreate(typ: expr): stmt {.dirty.}=
|
||||
proc create*(myQObject: var typ) =
|
||||
var super = (typ.superType())(myQObject)
|
||||
procCall create(super)
|
||||
|
||||
proc doRemoveOpenSym(a: var NimNode): NimNode {.compileTime.} =
|
||||
hookOnNode(NullContext(),a, removeOpenSym, true)
|
||||
|
||||
proc templateBody*(a: NimNode): NimNode {.compileTime.} =
|
||||
expectKind a, nnkTemplateDef
|
||||
result = a[6]
|
||||
|
||||
proc genArgTypeArray(params: NimNode): NimNode {.compileTime.} =
|
||||
expectKind params, nnkFormalParams
|
||||
result = newNimNode(nnkBracket)
|
||||
for i in 0 .. <params.len:
|
||||
if i == 1:
|
||||
# skip "self" param eg: myQObject: MyQObject
|
||||
continue
|
||||
let pType = if i != 0: getArgType params[i] else: params[i]
|
||||
let pTypeString = if pType.kind == nnkEmpty: "" else: $pType
|
||||
# function that maps Qvariant type to nim type
|
||||
let qtMeta = nim2QtMeta[pTypeString]
|
||||
if qtMeta == nil: error(pTypeString & " not supported yet")
|
||||
let metaDot = newDotExpr(ident "QMetaType", ident qtMeta)
|
||||
result.add metaDot
|
||||
|
||||
proc getIdentDefName*(a: NimNode): NimNode {.compileTime.} =
|
||||
## returns object field name from ident def
|
||||
expectKind a, nnkIdentDefs
|
||||
if a[0].kind == nnkIdent:
|
||||
return a[0]
|
||||
elif a[0].kind == nnkPostFix:
|
||||
return a[0][1]
|
||||
|
||||
proc tryHandleSigSlot(def: NimNode, signals: var seq[NimNode], slots: var seq[NimNode],
|
||||
generatedCode: var NimNode): bool {.compileTime.} =
|
||||
## Checks a method/proc definition for signals and slots. On finding a method/proc with
|
||||
## a {.signal.} or {.slot.} pragma, it will strip the pragma, add the definition to the
|
||||
## appropriate seq, append the stripped version to the generated code block and return true
|
||||
## indicating the definition was a signal or a slot. If the method/proc is not a slot
|
||||
## or a slot it will return false.
|
||||
expectKind generatedCode, nnkStmtList
|
||||
assert (not signals.isNil)
|
||||
assert (not slots.isNil)
|
||||
assert def.kind in {nnkMethodDef, nnkProcDef}
|
||||
result = false
|
||||
if def.hasPragma("slot"):
|
||||
let pragma = def.pragma()
|
||||
def.pragma = pragma.removePragma("slot")
|
||||
slots.add def # we need to gensome code later
|
||||
generatedCode.add def
|
||||
result = true
|
||||
elif def.hasPragma("signal"):
|
||||
let pragma = def.pragma()
|
||||
def.pragma = pragma.removePragma("signal")
|
||||
def.body = addSignalBody(def)
|
||||
generatedCode.add def
|
||||
signals.add def
|
||||
result = true
|
||||
|
||||
proc genCreateDecl(typ: NimNode): NimNode {.compileTime.} =
|
||||
## generates forward declaration for ``create`` procedure
|
||||
expectKind typ, nnkTypeDef
|
||||
let typeName = typ.getTypeName()
|
||||
result = (getAst prototypeCreate(typeName))[0]
|
||||
result.body = newEmptyNode()
|
||||
if typ.isExported:
|
||||
result.exportDef()
|
||||
else:
|
||||
result.unexportDef()
|
||||
|
||||
proc genCreate(typ: NimNode, signals: seq[NimNode], slots: seq[NimNode],
|
||||
properties: seq[NimNode]): NimNode {.compileTime.} =
|
||||
expectKind typ, nnkTypeDef
|
||||
let typeName = typ.getTypeName()
|
||||
result = (getAst prototypeCreate(typeName))[0]
|
||||
# the template creates loads of openSyms - replace these with idents
|
||||
result = doRemoveOpenSym(result)
|
||||
if typ.isExported:
|
||||
result.exportDef()
|
||||
else:
|
||||
result.unexportDef()
|
||||
var createBody = result.body
|
||||
for slot in slots:
|
||||
let params = slot.params
|
||||
let regSlotDot = newDotExpr(ident "myQObject", ident "registerSlot")
|
||||
let name = ($slot.name).replace("*","")
|
||||
let argTypesArray = genArgTypeArray(params)
|
||||
let call = newCall(regSlotDot, newLit name, argTypesArray)
|
||||
createBody.add call
|
||||
for signal in signals:
|
||||
let params = signal.params
|
||||
let regSigDot = newDotExpr(ident "myQObject", ident "registerSignal")
|
||||
let name = ($signal.name).replace("*","")
|
||||
let argTypesArray = genArgTypeArray(params)
|
||||
let call = newCall(regSigDot, newLit name, argTypesArray)
|
||||
createBody.add call
|
||||
for property in properties:
|
||||
let bracket = property[0]
|
||||
expectKind bracket, nnkBracketExpr
|
||||
#Command
|
||||
# BracketExpr
|
||||
# Ident !"QtProperty"
|
||||
# Ident !"string"
|
||||
# Ident !"name"
|
||||
# StmtList
|
||||
let nimPropType = bracket[1]
|
||||
let qtPropMeta = nim2QtMeta[$nimPropType]
|
||||
if qtPropMeta == nil: error($nimPropType & " not supported")
|
||||
let metaDot = newDotExpr(ident "QMetaType", ident qtPropMeta)
|
||||
let propertyName = property[1]
|
||||
var read, write, notify: NimNode
|
||||
let stmtList = property[2]
|
||||
# fields
|
||||
# StmtList
|
||||
# Asgn
|
||||
# Ident !"read"
|
||||
# Ident !"getName
|
||||
for asgn in stmtList.children:
|
||||
let name = asgn[0]
|
||||
case $name
|
||||
of "read":
|
||||
read = asgn[1]
|
||||
of "write":
|
||||
write = asgn[1]
|
||||
of "notify":
|
||||
notify = asgn[1]
|
||||
else:
|
||||
error("unknown property field: " & $name)
|
||||
let regPropDot = newDotExpr(ident "myQObject", ident "registerProperty")
|
||||
let readArg = if read == nil: newNilLit() else: newLit($read)
|
||||
let writeArg = if write == nil: newNilLit() else: newLit($write)
|
||||
let notifyArg = if notify == nil: newNilLit() else: newLit($notify)
|
||||
let call = newCall(regPropDot, newLit($propertyName), metaDot, readArg, writeArg, notifyArg)
|
||||
createBody.add call
|
||||
|
||||
proc genOnSlotCalled(typ: NimNode, slots: seq[NimNode]): NimNode {.compileTime.} =
|
||||
expectKind typ, nnkTypeDef
|
||||
let typeName = typ.getTypeName()
|
||||
result = (getAst prototypeOnSlotCalled(typeName))[0]
|
||||
var caseStmt = newNimNode(nnkCaseStmt)
|
||||
caseStmt.add ident("slotName")
|
||||
for slot in slots:
|
||||
var ofBranch = newNimNode(nnkOfBranch)
|
||||
# for exported procedures - strip * marker
|
||||
let slotName = ($slot.name).replace("*","")
|
||||
ofBranch.add newLit slotName
|
||||
let params = slot.params
|
||||
let hasReturn = not (params[0].kind == nnkEmpty)
|
||||
var branchStmts = newStmtList()
|
||||
var args = newSeq[NimNode]()
|
||||
# first params always the object
|
||||
args.add ident "myQObject"
|
||||
for i in 2.. <params.len:
|
||||
let pType = getArgType params[i]
|
||||
let argAccess = newNimNode(nnkBracketExpr)
|
||||
.add (ident "args")
|
||||
.add newIntLitNode(i-1)
|
||||
if $pType == "QVariant":
|
||||
args.add argAccess
|
||||
else:
|
||||
# function that maps QVariant type to nim type
|
||||
let mapper = nimFromQtVariant[$pType]
|
||||
let dot = newDotExpr(argAccess, ident mapper)
|
||||
args.add dot
|
||||
var call = newCall(ident slotName, args)
|
||||
if hasReturn:
|
||||
let retType = params[0]
|
||||
let argAccess = newNimNode(nnkBracketExpr)
|
||||
.add (ident "args")
|
||||
.add newIntLitNode(0)
|
||||
if $retType == "QVariant":
|
||||
# eg: args[0].assign(getName(myQObject))
|
||||
let dot = newDotExpr(argAccess, ident "assign")
|
||||
call = newCall(dot, call)
|
||||
else:
|
||||
# eg: args[0].strVal = getName(myQObject)
|
||||
let mapper = nimFromQtVariant[$retType]
|
||||
let dot = newDotExpr(argAccess, ident mapper)
|
||||
call = newAssignment(dot, call)
|
||||
branchStmts.add call
|
||||
ofBranch.add branchStmts
|
||||
caseStmt.add ofBranch
|
||||
# add else: discard
|
||||
caseStmt.add newNimNode(nnkElse)
|
||||
.add newStmtList().add newNimNode(nnkDiscardStmt).add newNimNode(nnkEmpty)
|
||||
result.body.add caseStmt
|
||||
|
||||
macro QtObject*(qtDecl: stmt): stmt {.immediate.} =
|
||||
## Generates boiler plate code for registering signals, slots
|
||||
## and properties.
|
||||
##
|
||||
## Currently generates:
|
||||
## - create: a method to register signal, slots and properties
|
||||
## - superType: a template that returns the super type of the
|
||||
## object defined within the macro body
|
||||
## - onSlotCalled: a method to dispatch an on slot call to the
|
||||
## appropiate method.
|
||||
##
|
||||
## Current limitations:
|
||||
## - only one type can be defined within the body of code sent to the
|
||||
## the macro. It is assumed, but not checked, that somewhere in the
|
||||
## inheritance hierarchy this object derives from ``QObject``.
|
||||
## - generics are not currently supported
|
||||
expectKind(qtDecl, nnkStmtList)
|
||||
#echo treeRepr qtDecl
|
||||
result = newStmtList()
|
||||
var slots = newSeq[NimNode]()
|
||||
var properties = newSeq[NimNode]()
|
||||
var signals = newSeq[NimNode]()
|
||||
# assume only one type per section for now
|
||||
var typ: NimNode
|
||||
for it in qtDecl.children():
|
||||
if it.kind == nnkTypeSection:
|
||||
let typeDecl = it.findChild(it.kind == nnkTypeDef)
|
||||
let superType = typeDecl.getSuperType()
|
||||
if superType.kind == nnkEmpty:
|
||||
# allow simple types and type aliases
|
||||
result.add it
|
||||
else:
|
||||
# may come in useful if we want to check objects inherit from QObject
|
||||
#let superName = if superType.kind == nnkIdent: superType
|
||||
# else: superType.getNodeOf(nnkIdent)
|
||||
if typ != nil:
|
||||
error("you may not define more than one type " &
|
||||
"within the code block passed to this macro")
|
||||
else: # without this else, it fails to compile
|
||||
typ = typeDecl
|
||||
result.add it
|
||||
result.add genSuperTemplate(typeDecl)
|
||||
result.add genCreateDecl(typeDecl)
|
||||
elif it.kind == nnkMethodDef:
|
||||
if tryHandleSigSlot(it, signals, slots, result): continue
|
||||
result.add it
|
||||
elif it.kind == nnkProcDef:
|
||||
if tryHandleSigSlot(it, signals, slots, result): continue
|
||||
result.add it
|
||||
elif it.kind == nnkCommand:
|
||||
let bracket = it[0]
|
||||
if bracket.kind != nnkBracketExpr:
|
||||
error("do not know how to handle: \n" & repr(it))
|
||||
# BracketExpr
|
||||
# Ident !"QtProperty"
|
||||
# Ident !"string"
|
||||
let cmdIdent = bracket[0]
|
||||
if cmdIdent == nil or cmdIdent.kind != nnkIdent or
|
||||
($cmdIdent).toLower() != "qtproperty":
|
||||
error("do not know how to handle: \n" & repr(it))
|
||||
properties.add it
|
||||
else:
|
||||
# everything else should pass through unchanged
|
||||
result.add it
|
||||
if typ == nil:
|
||||
error("you must declare an object that inherits from QObject")
|
||||
|
||||
result.add genOnSlotCalled(typ, slots)
|
||||
|
||||
result.add genCreate(typ, signals, slots, properties)
|
||||
|
||||
debug:
|
||||
echo repr result
|
|
@ -1,68 +0,0 @@
|
|||
import tables
|
||||
|
||||
type
|
||||
RawQVariant = distinct pointer
|
||||
QVariant* = ref object of RootObj ## A QVariant
|
||||
data: RawQVariant
|
||||
deleted: bool
|
||||
|
||||
RawQQmlApplicationEngine = distinct pointer
|
||||
QQmlApplicationEngine* = ref object of RootObj ## A QQmlApplicationEngine
|
||||
data: RawQQmlApplicationEngine
|
||||
deleted: bool
|
||||
|
||||
QApplication* = ref object of RootObj ## A QApplication
|
||||
deleted: bool
|
||||
|
||||
QGuiApplication* = ref object of RootObj ## A QGuiApplication
|
||||
deleted: bool
|
||||
|
||||
RawQObject = distinct pointer
|
||||
QObjectObj = object of RootObj
|
||||
data: RawQObject
|
||||
slots: Table[string, cint]
|
||||
signals: Table[string, cint]
|
||||
properties: Table[string, cint]
|
||||
deleted: bool
|
||||
QObject* = ref QObjectObj
|
||||
|
||||
RawBaseQObjectObj = distinct pointer
|
||||
BaseQObjectObj = object of QObjectObj
|
||||
BaseQObject* = ref BaseQObjectObj ## A QObject
|
||||
|
||||
RawQAbstractListModel = distinct pointer
|
||||
QAbstractListModelObj = object of QObjectObj
|
||||
QAbstractListModel* = ref QAbstractListModelObj ## A QAbstractListModel
|
||||
|
||||
RawQQuickView = distinct pointer
|
||||
QQuickView = ref object of RootObj ## A QQuickView
|
||||
data: RawQQuickView
|
||||
deleted: bool
|
||||
|
||||
QQmlContext* = distinct pointer ## A QQmlContext
|
||||
|
||||
RawQModelIndex = distinct pointer
|
||||
QModelIndex* = ref object of RootObj ## A QModelIndex
|
||||
data: RawQModelIndex
|
||||
deleted: bool
|
||||
|
||||
RawQHashIntByteArray = distinct pointer
|
||||
QHashIntByteArrayObj = object of RootObj
|
||||
data: RawQHashIntByteArray
|
||||
deleted: bool
|
||||
QHashIntByteArray* = ref QHashIntByteArrayObj ## A QHash<int,QByteArray>
|
||||
|
||||
QtItemFlag* {.pure.} = enum
|
||||
None = 0.cint,
|
||||
IsSelectable = 1.cint,
|
||||
IsEditable = 2.cint,
|
||||
IsDragEnabled = 4.cint,
|
||||
IsDropEnabled = 8.cint,
|
||||
IsUserCheckable = 16.cint,
|
||||
IsEnabled = 32.cint,
|
||||
IsTristate = 64.cint,
|
||||
NeverHasChildren = 128.cint
|
||||
|
||||
QtOrientation {.pure.} = enum
|
||||
Horizontal = 1.cint,
|
||||
Vertical = 2.cint
|
|
@ -1,22 +0,0 @@
|
|||
include(CMakeParseArguments)
|
||||
|
||||
find_program(NIM_EXECUTABLE nim PATHS ENV PATH)
|
||||
mark_as_advanced(NIM_EXECUTABLE)
|
||||
|
||||
# Determine the nimrod version
|
||||
if(NIM_EXECUTABLE)
|
||||
execute_process(COMMAND ${NIM_EXECUTABLE} "--version"
|
||||
OUTPUT_VARIABLE NIM_VERSION
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE)
|
||||
STRING(REGEX MATCH "[0-9]+\\.[0-9]+\\.[0-9]+" NIM_VERSION ${NIM_VERSION})
|
||||
endif(NIM_EXECUTABLE)
|
||||
|
||||
# Handle the QUIETLY and REQUIRED arguments, which may be given to the find call.
|
||||
# set NIM_FOUND to TRUE if Nimrod has been found
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
find_package_handle_standard_args(Nim
|
||||
REQUIRED_VARS NIM_EXECUTABLE
|
||||
VERSION_VAR NIM_VERSION)
|
||||
|
||||
set(NIM_USE_FILE "${CMAKE_CURRENT_LIST_DIR}/UseNim.cmake")
|
|
@ -1,49 +0,0 @@
|
|||
include(CMakeParseArguments)
|
||||
|
||||
function(add_nim_executable )
|
||||
set(options )
|
||||
set(oneValueArgs TARGET)
|
||||
set(multiValueArgs SOURCES PATHS)
|
||||
cmake_parse_arguments(ARGS "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
|
||||
|
||||
# collect set of input source files
|
||||
set(in_files "")
|
||||
foreach(src ${ARGS_SOURCES} ${ARGS_UNPARSED_ARGUMENTS})
|
||||
list(APPEND in_files "${CMAKE_CURRENT_SOURCE_DIR}/${src}")
|
||||
endforeach(src ${ARGS_SOURCES} ${ARGS_UNPARSED_ARGUMENTS})
|
||||
|
||||
set(in_paths "")
|
||||
foreach(path ${ARGS_PATHS} ${ARGS_UNPARSED_ARGUMENTS})
|
||||
list(APPEND in_paths "--path:${CMAKE_CURRENT_SOURCE_DIR}/${path}")
|
||||
endforeach(path ${ARGS_PATHS} ${ARGS_UNPARSED_ARGUMENTS})
|
||||
|
||||
# set the target binary and nim cache directory
|
||||
set(nim_target "${CMAKE_CURRENT_BINARY_DIR}/${ARGS_TARGET}")
|
||||
set(nim_cache_dir "${CMAKE_CURRENT_BINARY_DIR}/nimcache")
|
||||
|
||||
# compiler
|
||||
set(nim_compiler "c")
|
||||
|
||||
# compiler options
|
||||
set(nim_compiler_options "")
|
||||
if (WIN32)
|
||||
if (MSVC OR MSVC_IDE)
|
||||
set(nim_compiler_options "--cc:vcc")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# thread options
|
||||
set(nim_thread_options "")
|
||||
if(UNIX)
|
||||
set(nim_thread_options "--passL:-lpthread")
|
||||
endif()
|
||||
|
||||
# add target to trigger the nimrod compiler
|
||||
add_custom_target(
|
||||
${ARGS_TARGET} ALL
|
||||
COMMAND
|
||||
${NIM_EXECUTABLE} ${nim_compiler} ${nim_compiler_options} ${nim_thread_options} ${in_paths} "--nimcache:" ${nim_cache_dir} "--out:" ${nim_target} ${in_files}
|
||||
DEPENDS
|
||||
${in_files}
|
||||
)
|
||||
endfunction(add_nim_executable)
|
48
README.md
48
README.md
|
@ -1,57 +1,33 @@
|
|||
# DOtherSide
|
||||
|
||||
[![License](https://img.shields.io/badge/license-LGPL-green.svg)](https://github.com/filcuc/DOtherSide/blob/master/LICENSE)
|
||||
[![Build Status](https://travis-ci.org/filcuc/DOtherSide.svg?branch=master)](https://travis-ci.org/filcuc/DOtherSide)
|
||||
|
||||
## Description
|
||||
C language library for creating bindings for the Qt QML language.
|
||||
|
||||
Qml bindings for both D and Nim programming languages
|
||||
Currently the DOtherSide library is used by the following bindings:
|
||||
* [nimqml](https://github.com/filcuc/nimqml), QML bindings for the Nim programming language
|
||||
* [dqml](https://github.com/filcuc/dqml), QML bindings for the D programming language
|
||||
|
||||
## Change log
|
||||
The project change log can be read [here](./CHANGELOG.md).
|
||||
|
||||
## Documentation
|
||||
The documentation for the Nim programming language can be
|
||||
read [here](http://filcuc.github.io/DOtherSide/ "").
|
||||
|
||||
For the D programming language is an on going project
|
||||
and pull request are accepted.
|
||||
|
||||
## Supported Platforms and Requirements
|
||||
## Supported platforms
|
||||
Currently we support the following platforms/compilers:
|
||||
- Linux both 32/64bit with gcc
|
||||
- Windows 32/64bit with Visual Studio 2013 Community Edition
|
||||
|
||||
## Change log
|
||||
The project change log can be read [here](./CHANGELOG.md).
|
||||
|
||||
## Build requirements
|
||||
You need the following software:
|
||||
* Qt 5.3 or higher
|
||||
* dmd 2.065 or higher
|
||||
* Linux: gcc 4.8 or later with c++11 support or higher
|
||||
* Windows: Visual Studio 2013 Community Edition (Windows) or higher
|
||||
* Windows: MingGW 4.9.2 or higher
|
||||
* nim 0.10.3 or higher
|
||||
|
||||
## Build Instructions
|
||||
## Build instructions:
|
||||
1. Open a shell terminal inside the cloned repo
|
||||
2. mkdir build && cd build
|
||||
3. cmake ..
|
||||
4. make
|
||||
|
||||
## Install Instructions
|
||||
For the DOtherSide C++ bridge:
|
||||
|
||||
1. Copy the libDOtherSide.so from the build dir to your system lib i.e /usr/lib
|
||||
|
||||
For NimQml use the Nimble package manager:
|
||||
|
||||
1. Open a shell and navigate to the NimQml subdirectory
|
||||
2. Type: nimble install
|
||||
3. Now you can use it in your .nim files
|
||||
|
||||
## Supported features:
|
||||
* Creation of custom QObject and inject in a qml QtQuick view (both Nim and D)
|
||||
* Slot and Signal creation for the following types int, bool, string (both Nim and D)
|
||||
* Creation of properties for databinding (both Nim and D)
|
||||
* Subclassing of QAbstractListModels
|
||||
|
||||
|
||||
|
||||
|
||||
Copy the libDOtherSide.so from the build dir to your system lib i.e /usr/lib
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue