diff --git a/all.cpp b/all.cpp index f7f219a8..965867b1 100644 --- a/all.cpp +++ b/all.cpp @@ -2,8 +2,6 @@ #include "cpp/capi.cpp" #include "cpp/govalue.cpp" #include "cpp/govaluetype.cpp" -#include "cpp/goitemmodel.cpp" -#include "cpp/goitemmodel_api.cpp" #include "cpp/idletimer.cpp" #include "cpp/connector.cpp" diff --git a/bridge.go b/bridge.go index a6d95e61..157fedbe 100644 --- a/bridge.go +++ b/bridge.go @@ -1,7 +1,7 @@ package qml // #cgo CPPFLAGS: -I./cpp -// #cgo CXXFLAGS: -std=c++0x -Wall -fno-strict-aliasing +// #cgo CXXFLAGS: -std=c++0x -pedantic-errors -Wall -fno-strict-aliasing // #cgo LDFLAGS: -lstdc++ // #cgo pkg-config: Qt5Core Qt5Widgets Qt5Quick // @@ -16,20 +16,12 @@ import ( "os" "reflect" "runtime" - "runtime/debug" "sync/atomic" "unsafe" "github.com/nanu-c/qml-go/cdata" - "github.com/nanu-c/qml-go/qpainter" - "github.com/nanu-c/qml-go/tools/util" ) -type mainThreadFunc struct { - f func() - done chan struct{} -} - var ( guiFunc = make(chan func()) guiDone = make(chan struct{}) @@ -54,45 +46,19 @@ func init() { // The Run function must necessarily be called from the same goroutine as // the main function or the application may fail when running on Mac OS. func Run(f func() error) error { - return RunArgs(os.Args, f) -} - -// RunArgs runs the main QML event loop, runs f, and then terminates the -// event loop once f returns. -// -// Most functions from the qml package block until RunArgs is called. -// -// The RunArgs function must necessarily be called from the same goroutine as -// the main function or the application may fail when running on Mac OS. -func RunArgs(args []string, f func() error) error { if cdata.Ref() != guiMainRef { - panic("RunArgs must be called on the initial goroutine so apps are portable to Mac OS") + panic("Run must be called on the initial goroutine so apps are portable to Mac OS") } if !atomic.CompareAndSwapInt32(&initialized, 0, 1) { - panic("qml.RunArgs called more than once") - } - - // so, technically we should be freeing the C.CString below, but newGuiApplication - // can really only be called once, and the args are not going to be large - argc := len(args) - argv := make([]*C.char, argc+1) - for i := 0; i < argc; i++ { - argv[i] = C.CString(args[i]) + panic("qml.Run called more than once") } - argv[argc] = nil - - // argvP := unsafe.Pointer(&argv[0]) - - C.newGuiApplication(C.int(argc), &argv[0]) + C.newGuiApplication() C.idleTimerInit((*C.int32_t)(&guiIdleRun)) done := make(chan error, 1) go func() { RunMain(func() {}) // Block until the event loop is running. done <- f() C.applicationExit() - // this is here to keep the argv slice alive while the application is running - // TODO: change this to something without side effects? runtime.KeepAlive? - fmt.Sprintln(argc, argv) }() C.applicationExec() return <-done @@ -112,31 +78,14 @@ func RunMain(f func()) { // Tell Qt we're waiting for the idle hook to be called. if atomic.AddInt32(&guiIdleRun, 1) == 1 { - // C.idleTimerStart() - } - - var doneChan chan struct{} - - select { - case doneChan = <-doneChanBuffer: - // yay - default: - doneChan = make(chan struct{}, 1) + C.idleTimerStart() } // Send f to be executed by the idle hook in the main GUI thread. - guiFunc <- mainThreadFunc{f: f, done: doneChan} - C.idleTimerStart() + guiFunc <- f // Wait until f is done executing. - <-doneChan - - select { - case doneChanBuffer <- doneChan: - return - default: - close(doneChan) - } + <-guiDone } // Lock freezes all QML activity by blocking the main event loop. @@ -227,13 +176,7 @@ func Changed(value, fieldAddr interface{}) { // //export hookIdleTimer func hookIdleTimer() { - ref := cdata.Ref() - if ref != guiMainRef && ref != atomic.LoadUintptr(&guiPaintRef) { - // Not within the GUI or render threads! - fmt.Println("AAARG! hookIdleTimer didn't run on the main thread!") - // return - } - var f mainThreadFunc + var f func() for { select { case f = <-guiFunc: @@ -244,46 +187,12 @@ func hookIdleTimer() { return } } - // fmt.Fprintf(os.Stderr, "hookIdleTimer: %v\n", runtime.FuncForPC(reflect.ValueOf(f).Pointer()).Name()) - // fmt.Fprintf(os.Stderr, "hookIdleTimer: %v\n", reflect.ValueOf(f)) - func() { - defer func() { - if r := recover(); r != nil { - fmt.Printf("Panic in RunMain func: %v\n", r) - debug.PrintStack() - } - }() - - f.f() - }() - - f.done <- struct{}{} + f() + guiDone <- struct{}{} atomic.AddInt32(&guiIdleRun, -1) } } -var valueFoldRefCounter C.GoValueRef = 1 -var valueFoldMap = make(map[C.GoValueRef]*valueFold) - -func getFoldRef(fold *valueFold) C.GoValueRef { - if fold.ref != 0 { - return fold.ref - } - - ref := (C.GoValueRef)(atomic.AddUintptr((*uintptr)(unsafe.Pointer(&valueFoldRefCounter)), 1)) - fold.ref = ref - valueFoldMap[ref] = fold - return ref -} - -func foldFromRef(ref C.GoValueRef) *valueFold { - return valueFoldMap[ref] -} - -func clearFoldRef(ref C.GoValueRef) { - delete(valueFoldMap, ref) -} - type valueFold struct { engine *Engine gvalue interface{} @@ -292,7 +201,6 @@ type valueFold struct { prev *valueFold next *valueFold owner valueOwner - ref C.GoValueRef } // cgoFolds holds all fold values that get reference to on the cgo space. @@ -338,7 +246,7 @@ const ( func wrapGoValue(engine *Engine, gvalue interface{}, owner valueOwner) (cvalue unsafe.Pointer) { gvaluev := reflect.ValueOf(gvalue) gvaluek := gvaluev.Kind() - if gvaluek == reflect.Struct && !util.Hashable(gvalue) { + if gvaluek == reflect.Struct && !hashable(gvalue) { name := gvaluev.Type().Name() if name != "" { name = " (" + name + ")" @@ -351,17 +259,10 @@ func wrapGoValue(engine *Engine, gvalue interface{}, owner valueOwner) (cvalue u painting := cdata.Ref() == atomic.LoadInt64(&guiPaintRef) - hashableGvalue := gvalue - if gvaluev.Kind() == reflect.Slice { - hashableGvalue = *(*reflect.SliceHeader)(unsafe.Pointer(gvaluev.Pointer())) - } else if !util.Hashable(gvalue) { - panic(fmt.Sprintf("gvalue not hashable: %v %v", gvaluev.Type(), gvaluev.Kind())) - } - // Cannot reuse a jsOwner because the QML runtime may choose to destroy // the value _after_ we hand it a new reference to the same value. // See issue #68 for details. - prev, ok := engine.values[hashableGvalue] + prev, ok := engine.values[gvalue] if ok && (prev.owner == cppOwner || painting) { return prev.cvalue } @@ -385,7 +286,7 @@ func wrapGoValue(engine *Engine, gvalue interface{}, owner valueOwner) (cvalue u fold.next = prev prev.prev = fold } - engine.values[hashableGvalue] = fold + engine.values[gvalue] = fold //fmt.Printf("[DEBUG] value alive (wrapped): cvalue=%x gvalue=%x/%#v\n", fold.cvalue, addrOf(fold.gvalue), fold.gvalue) stats.valuesAlive(+1) @@ -451,9 +352,9 @@ func hookGoValueDestroyed(enginep unsafe.Pointer, foldr C.GoRef) { if len(typeNew) == before { panic("destroying value without an associated engine; who created the value?") } - } else if engines[engine.savedAddr] == nil { + } else if engines[engine.addr] == nil { // Must never do that. The engine holds memory references that C++ depends on. - panic(fmt.Sprintf("engine %p was released from global list while its values were still alive", engine.savedAddr)) + panic(fmt.Sprintf("engine %p was released from global list while its values were still alive", engine.addr)) } else { switch { case fold.prev != nil: @@ -475,7 +376,7 @@ func hookGoValueDestroyed(enginep unsafe.Pointer, foldr C.GoRef) { panic("destroying value that knows about the engine, but the engine doesn't know about the value; who cleared the engine?") } if engine.destroyed && len(engine.values) == 0 { - delete(engines, engine.savedAddr) + delete(engines, engine.addr) } } fold.destroyRef() @@ -493,6 +394,7 @@ func deref(value reflect.Value) reflect.Value { } return value } + panic("cannot happen") } //export hookGoValueReadField @@ -503,18 +405,7 @@ func hookGoValueReadField(enginep unsafe.Pointer, foldr C.GoRef, reflectIndex, g if getIndex >= 0 { field = reflect.ValueOf(fold.gvalue).Method(int(getIndex)).Call(nil)[0] } else { - val := deref(reflect.ValueOf(fold.gvalue)) - // defer func() { - // if r := recover(); r != nil { - // fmt.Fprintf(os.Stderr, "panic in hookGoValueReadField %v %v\n", val, reflectIndex) - // } - // }() - if !val.IsValid() { - // panic(fmt.Sprintf("invalid value in hookGoValueReadField %#v\n", fold)) - resultdv.dataType = C.DTInvalid - return - } - field = val.Field(int(reflectIndex)) + field = deref(reflect.ValueOf(fold.gvalue)).Field(int(reflectIndex)) } field = deref(field) @@ -531,7 +422,7 @@ func hookGoValueReadField(enginep unsafe.Pointer, foldr C.GoRef, reflectIndex, g if fieldk == reflect.Slice || fieldk == reflect.Struct && field.Type() != typeRGBA { if field.CanAddr() { field = field.Addr() - } else if !util.Hashable(field.Interface()) { + } else if !hashable(field.Interface()) { t := reflect.ValueOf(fold.gvalue).Type() for t.Kind() == reflect.Ptr { t = t.Elem() @@ -650,11 +541,7 @@ func hookGoValueCallMethod(enginep unsafe.Pointer, foldr C.GoRef, reflectIndex C for i := 0; i < numIn; i++ { paramdv := (*C.DataValue)(unsafe.Pointer(uintptr(unsafe.Pointer(args)) + (uintptr(i)+1)*dataValueSize)) param := reflect.ValueOf(unpackDataValue(paramdv, fold.engine)) - argt := methodt.In(i) - if !param.IsValid() { - fmt.Printf("Warning: %s called with zero parameter\n", methodName) - param = reflect.Zero(argt) - } else if param.Type() != argt { + if argt := methodt.In(i); param.Type() != argt { param, err = convertParam(methodName, i, param, argt) if err != nil { panic(err.Error()) @@ -713,12 +600,10 @@ func hookGoValuePaint(enginep unsafe.Pointer, foldr C.GoRef, reflectIndex C.intp return } - obj := CommonOf(fold.cvalue, fold.engine) - painter := qpainter.FromPtr(qpainterptr) - + painter := &Painter{engine: fold.engine, obj: &Common{fold.cvalue, fold.engine}} v := reflect.ValueOf(fold.gvalue) method := v.Method(int(reflectIndex)) - method.Call([]reflect.Value{reflect.ValueOf(obj), reflect.ValueOf(painter)}) + method.Call([]reflect.Value{reflect.ValueOf(painter)}) } func ensureEngine(enginep unsafe.Pointer, foldr C.GoRef) *valueFold { @@ -770,7 +655,7 @@ func _initGoType(fold *valueFold, schedulePaint bool) { return } // TODO Would be good to preserve identity on the Go side. See unpackDataValue as well. - obj := CommonOf(fold.cvalue, fold.engine) + obj := &Common{engine: fold.engine, addr: fold.cvalue} fold.init.Call([]reflect.Value{reflect.ValueOf(fold.gvalue), reflect.ValueOf(obj)}) fold.init = reflect.Value{} if schedulePaint { diff --git a/cdata/cdata12.c b/cdata/cdata12.c deleted file mode 100644 index 2e60abfa..00000000 --- a/cdata/cdata12.c +++ /dev/null @@ -1,18 +0,0 @@ -// +build !go1.4 - -#include "runtime.h" - -void ·Ref(uintptr ref) { - ref = (uintptr)g->m; - FLUSH(&ref); -} - -void runtime·main(void); -void main·main(void); - -void ·Addrs(uintptr rmain, uintptr mmain) { - rmain = (uintptr)runtime·main; - mmain = (uintptr)main·main; - FLUSH(&rmain); - FLUSH(&mmain); -} diff --git a/cdata/cdata15_386.s b/cdata/cdata15_386.s deleted file mode 100644 index a5c6f402..00000000 --- a/cdata/cdata15_386.s +++ /dev/null @@ -1,17 +0,0 @@ -// +build go1.5 - -#include "textflag.h" - -TEXT ·Ref(SB),NOSPLIT,$4-4 - CALL runtime·acquirem(SB) - MOVL 0(SP), AX - MOVL AX, ret+0(FP) - CALL runtime·releasem(SB) - RET - -TEXT ·Addrs(SB),NOSPLIT,$0-8 - MOVL $runtime·main(SB), AX - MOVL AX, ret+0(FP) - MOVL $main·main(SB), AX - MOVL AX, ret+8(FP) - RET diff --git a/cdata/cdata15_amd64.s b/cdata/cdata15_amd64.s deleted file mode 100644 index db65e062..00000000 --- a/cdata/cdata15_amd64.s +++ /dev/null @@ -1,17 +0,0 @@ -// +build go1.5 - -#include "textflag.h" - -TEXT ·Ref(SB),NOSPLIT,$8-8 - CALL runtime·acquirem(SB) - MOVQ 0(SP), AX - MOVQ AX, ret+0(FP) - CALL runtime·releasem(SB) - RET - -TEXT ·Addrs(SB),NOSPLIT,$0-16 - MOVQ $runtime·main(SB), AX - MOVQ AX, ret+0(FP) - MOVQ $main·main(SB), AX - MOVQ AX, ret+8(FP) - RET diff --git a/cdata/cdata15_arm.s b/cdata/cdata15_arm.s deleted file mode 100644 index 106d2ec9..00000000 --- a/cdata/cdata15_arm.s +++ /dev/null @@ -1,18 +0,0 @@ -// +build go1.5 - -#include "textflag.h" - -TEXT ·Ref(SB),NOSPLIT,$4-4 - BL runtime·acquirem(SB) - MOVW 4(R13), R0 - MOVW R0, ret+0(FP) - MOVW R0, 4(R13) - BL runtime·releasem(SB) - RET - -TEXT ·Addrs(SB),NOSPLIT,$0-8 - MOVW $runtime·main(SB), R0 - MOVW R0, ret+0(FP) - MOVW $main·main(SB), R0 - MOVW R0, ret+4(FP) - RET diff --git a/cdata/cdata14_386.s b/cdata/cdata_386.s similarity index 92% rename from cdata/cdata14_386.s rename to cdata/cdata_386.s index 4e396688..a8a11d9a 100644 --- a/cdata/cdata14_386.s +++ b/cdata/cdata_386.s @@ -1,5 +1,3 @@ -// +build go1.4,!go1.5 - #include "textflag.h" /* diff --git a/cdata/cdata14_amd64.s b/cdata/cdata_amd64.s similarity index 92% rename from cdata/cdata14_amd64.s rename to cdata/cdata_amd64.s index 2d33f2b5..21ffbabd 100644 --- a/cdata/cdata14_amd64.s +++ b/cdata/cdata_amd64.s @@ -1,5 +1,3 @@ -// +build go1.4,!go1.5 - #include "textflag.h" /* diff --git a/cdata/cdata14_arm.s b/cdata/cdata_arm.s similarity index 92% rename from cdata/cdata14_arm.s rename to cdata/cdata_arm.s index a160095c..6d4b1aae 100644 --- a/cdata/cdata14_arm.s +++ b/cdata/cdata_arm.s @@ -1,5 +1,3 @@ -// +build go1.4,!go1.5 - #include "textflag.h" /* diff --git a/cpp/goitemmodel.cpp b/cpp/goitemmodel.cpp deleted file mode 100644 index b07b2298..00000000 --- a/cpp/goitemmodel.cpp +++ /dev/null @@ -1,87 +0,0 @@ - -#include "goitemmodel.h" - -GoItemModel::GoItemModel(QObject* parent, GoValueRef valueref) - : QAbstractItemModel(parent), valueref(valueref) { - -} - -QModelIndex_* miCastTo(const QModelIndex &index) { - return reinterpret_cast(const_cast(&index)); -} -QModelIndex miCastFrom(QModelIndex_ *index) { - if (index == NULL) { - return QModelIndex(); - } - return *reinterpret_cast(index); -} - -// Required functions -int GoItemModel::columnCount(const QModelIndex &parent) const { - return implColumnCount(valueref, miCastTo(parent)); -} - -QVariant GoItemModel::data(const QModelIndex &index, int role) const { - DataValue value; - - implData(valueref, miCastTo(index), role, &value); - - QVariant var; - unpackDataValue(&value, &var); - - return var; -} - -QModelIndex GoItemModel::index(int row, int column, const QModelIndex &parent) const { - return miCastFrom(implIndex(valueref, row, column, miCastTo(parent))); -} - -QModelIndex GoItemModel::parent(const QModelIndex &index) const { - return miCastFrom(implParent(valueref, miCastTo(index))); -} - -int GoItemModel::rowCount(const QModelIndex &parent) const { - return implRowCount(valueref, miCastTo(parent)); -} - - -// Required for editing -Qt::ItemFlags GoItemModel::flags(const QModelIndex &index) const { - return (Qt::ItemFlags)implFlags(valueref, miCastTo(index)); -} - -bool GoItemModel::setData(const QModelIndex &index, const QVariant &value, int role) { - DataValue *dv = (DataValue *) malloc(sizeof(DataValue)); - packDataValue(&value, dv); - return implSetData(valueref, miCastTo(index), dv, role); -} - -// Internal Protected functions - -QModelIndex GoItemModel::protCreateIndex(int row, int column, quintptr id) const { - return createIndex(row, column, id); -} - -void GoItemModel::protBeginInsertColumns(const QModelIndex &parent, int first, int last) { - return beginInsertColumns(parent, first, last); -} - -void GoItemModel::protEndInsertColumns() { - return endInsertColumns(); -} - -void GoItemModel::protBeginInsertRows(const QModelIndex &parent, int first, int last) { - return beginInsertRows(parent, first, last); -} - -void GoItemModel::protEndInsertRows() { - return endInsertRows(); -} - -void GoItemModel::protBeginRemoveRows(const QModelIndex &parent, int first, int last) { - return beginRemoveRows(parent, first, last); -} - -void GoItemModel::protEndRemoveRows() { - return endRemoveRows(); -} diff --git a/cpp/goitemmodel.h b/cpp/goitemmodel.h deleted file mode 100644 index 5bd86f38..00000000 --- a/cpp/goitemmodel.h +++ /dev/null @@ -1,83 +0,0 @@ -#ifndef GOITEMMODEL_H -#define GOITEMMODEL_H - -// #include "capi.h" -#include -#include -#include "goitemmodel_impl.h" - -// QImage_* newQImage(int width, int height, unsigned int format); -// QImage_* loadQImage(const char *filename, int filename_length, const char *format); -// void deleteQImage(QImage_*); - -class GoItemModel : public QAbstractItemModel -{ - Q_OBJECT -public: - // QAbstractItemModel(QObject *parent = Q_NULLPTR) - GoItemModel(QObject *parent, GoValueRef impl); - // virtual ~QAbstractItemModel() - - // Required functions - int columnCount(const QModelIndex &parent = QModelIndex()) const; - QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const; - QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const; - QModelIndex parent(const QModelIndex &index) const; - int rowCount(const QModelIndex &parent = QModelIndex()) const; - - // Required for editing - Qt::ItemFlags flags(const QModelIndex &index) const; - bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole); - - QModelIndex protCreateIndex(int row, int column, quintptr id) const; - void protBeginInsertColumns(const QModelIndex &parent, int first, int last); - void protEndInsertColumns(); - void protBeginInsertRows(const QModelIndex &parent, int first, int last); - void protEndInsertRows(); - void protBeginRemoveRows(const QModelIndex &parent, int first, int last); - void protEndRemoveRows(); - - - - // virtual QModelIndex buddy(const QModelIndex &index) const - // virtual bool canDropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent) const - // virtual bool canFetchMore(const QModelIndex &parent) const - // virtual bool dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent) - // virtual void fetchMore(const QModelIndex &parent) - // virtual Qt::ItemFlags flags(const QModelIndex &index) const - // virtual bool hasChildren(const QModelIndex &parent = QModelIndex()) const - // bool hasIndex(int row, int column, const QModelIndex &parent = QModelIndex()) const - // virtual QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const - // bool insertColumn(int column, const QModelIndex &parent = QModelIndex()) - // virtual bool insertColumns(int column, int count, const QModelIndex &parent = QModelIndex()) - // bool insertRow(int row, const QModelIndex &parent = QModelIndex()) - // virtual bool insertRows(int row, int count, const QModelIndex &parent = QModelIndex()) - // virtual QMap itemData(const QModelIndex &index) const - // virtual QModelIndexList match(const QModelIndex &start, int role, const QVariant &value, int hits = 1, Qt::MatchFlags flags = Qt::MatchFlags( Qt::MatchStartsWith | Qt::MatchWrap )) const - // virtual QMimeData * mimeData(const QModelIndexList &indexes) const - // virtual QStringList mimeTypes() const - // bool moveColumn(const QModelIndex &sourceParent, int sourceColumn, const QModelIndex &destinationParent, int destinationChild) - // virtual bool moveColumns(const QModelIndex &sourceParent, int sourceColumn, int count, const QModelIndex &destinationParent, int destinationChild) - // bool moveRow(const QModelIndex &sourceParent, int sourceRow, const QModelIndex &destinationParent, int destinationChild) - // virtual bool moveRows(const QModelIndex &sourceParent, int sourceRow, int count, const QModelIndex &destinationParent, int destinationChild) - // bool removeColumn(int column, const QModelIndex &parent = QModelIndex()) - // virtual bool removeColumns(int column, int count, const QModelIndex &parent = QModelIndex()) - // bool removeRow(int row, const QModelIndex &parent = QModelIndex()) - // virtual bool removeRows(int row, int count, const QModelIndex &parent = QModelIndex()) - // virtual QHash roleNames() const - // virtual bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole) - // virtual bool setHeaderData(int section, Qt::Orientation orientation, const QVariant &value, int role = Qt::EditRole) - // virtual bool setItemData(const QModelIndex &index, const QMap &roles) - // virtual QModelIndex sibling(int row, int column, const QModelIndex &index) const - // virtual void sort(int column, Qt::SortOrder order = Qt::AscendingOrder) - // virtual QSize span(const QModelIndex &index) const - // virtual Qt::DropActions supportedDragActions() const - // virtual Qt::DropActions supportedDropActions() const - -// private: - GoValueRef valueref; -}; - -#endif // GOITEMMODEL_H - -// vim:ts=4:sw=4:et:ft=cpp diff --git a/cpp/goitemmodel_api.cpp b/cpp/goitemmodel_api.cpp deleted file mode 100644 index 4ed4a2d2..00000000 --- a/cpp/goitemmodel_api.cpp +++ /dev/null @@ -1,143 +0,0 @@ - -#include "goitemmodel.h" -#include "goitemmodel_api.h" -#include "util.cpp" -#include - - -QItemModel_* newGoItemModel(QObject_* parent, GoValueRef impl) { - return reinterpret_cast(new GoItemModel(reinterpret_cast(parent), impl)); -} - -void deleteGoItemModel(QItemModel_* im) { - delete reinterpret_cast(im); -} - - - -QModelIndex_ *modelIndexChild(QModelIndex_ *mi, int row, int col) { - QModelIndex *ret = new QModelIndex; - *ret = reinterpret_cast(mi)->child(row, col); - return (QModelIndex_*)ret; -} - -QModelIndex_ *modelIndexSibling(QModelIndex_ *mi, int row, int col) { - QModelIndex *ret = new QModelIndex; - *ret = reinterpret_cast(mi)->sibling(row, col); - return (QModelIndex_*)ret; -} - -int modelIndexColumn(QModelIndex_ *mi) { - return reinterpret_cast(mi)->column(); -} - -int modelIndexRow(QModelIndex_ *mi) { - return reinterpret_cast(mi)->row(); -} - -void modelIndexData(QModelIndex_ *mi, int role, DataValue *ret) { - QVariant value = reinterpret_cast(mi)->data(role); - packDataValue(&value, ret); -} - -quint32 modelIndexFlags(QModelIndex_ *mi) { - return reinterpret_cast(mi)->flags(); -} - -uintptr_t modelIndexInternalId(QModelIndex_ *mi) { - return reinterpret_cast(mi)->internalId(); -} - -uintptr_t modelIndexInternalPointer(QModelIndex_ *mi) { - return (quintptr)reinterpret_cast(mi)->internalPointer(); -} - -bool modelIndexIsValid(QModelIndex_ *mi) { - return reinterpret_cast(mi)->isValid(); -} - -QItemModel_ *modelIndexModel(QModelIndex_ *mi) { - return (QItemModel_ *)reinterpret_cast(mi)->model(); -} - -QModelIndex_ *modelIndexParent(QModelIndex_ *mi) { - QModelIndex *ret = new QModelIndex; - *ret = reinterpret_cast(mi)->parent(); - return (QModelIndex_*)ret; -} - - -// Protected functions - -QModelIndex_ *itemModelCreateIndex(QItemModel_ *im, int row, int col, uintptr_t id) { - QModelIndex *ret = new QModelIndex; - *ret = reinterpret_cast(im)->protCreateIndex(row, col, id); - return (QModelIndex_*)ret; -} - -void itemModelBeginInsertColumns(QItemModel_ *im, QModelIndex_ *parent, int first, int last) { - reinterpret_cast(im)->protBeginInsertColumns(miCastFrom(parent), first, last); -} - -void itemModelEndInsertColumns(QItemModel_ *im) { - reinterpret_cast(im)->protEndInsertColumns(); -} - -void itemModelBeginInsertRows(QItemModel_ *im, QModelIndex_ *parent, int first, int last) { - reinterpret_cast(im)->protBeginInsertRows(miCastFrom(parent), first, last); -} - -void itemModelEndInsertRows(QItemModel_ *im) { - reinterpret_cast(im)->protEndInsertRows(); -} - -void itemModelBeginRemoveRows(QItemModel_ *im, QModelIndex_ *parent, int first, int last) { - reinterpret_cast(im)->protBeginRemoveRows(miCastFrom(parent), first, last); -} - -void itemModelEndRemoveRows(QItemModel_ *im) { - reinterpret_cast(im)->protEndRemoveRows(); -} - -void itemModelDataChanged(QItemModel_ *im, QModelIndex_ *topLeft, QModelIndex_ *bottomRight) { - reinterpret_cast(im)->dataChanged(miCastFrom(topLeft), miCastFrom(bottomRight)); -} - -// Required functions -int itemModelColumnCount(QItemModel_ *im, QModelIndex_ *parent) { - return reinterpret_cast(im)->columnCount(miCastFrom(parent)); -} - -void itemModelData(QItemModel_ *im, QModelIndex_ *index, int role, DataValue *ret) { - QVariant var = reinterpret_cast(im)->data(miCastFrom(index), role); - - packDataValue(&var, ret); -} - -QModelIndex_ *itemModelIndex(QItemModel_ *im, int row, int column, QModelIndex_ *parent) { - QModelIndex *ret = new QModelIndex; - *ret = reinterpret_cast(im)->index(row, column, miCastFrom(parent)); - return (QModelIndex_*)ret; -} - -QModelIndex_ *itemModelParent(QItemModel_ *im, QModelIndex_ *index) { - QModelIndex *ret = new QModelIndex; - *ret = reinterpret_cast(im)->parent(miCastFrom(index)); - return (QModelIndex_*)ret; -} - -int itemModelRowCount(QItemModel_ *im, QModelIndex_ *parent) { - return reinterpret_cast(im)->rowCount(miCastFrom(parent)); -} - - -// Required for editing -int itemModelFlags(QItemModel_ *im, QModelIndex_ *index) { - return reinterpret_cast(im)->flags(miCastFrom(index)); -} - -bool itemModelSetData(QItemModel_ *im, QModelIndex_ *index, DataValue *value, int role) { - QVariant var; - unpackDataValue(value, &var); - return reinterpret_cast(im)->setData(miCastFrom(index), var, role); -} diff --git a/cpp/goitemmodel_api.h b/cpp/goitemmodel_api.h deleted file mode 100644 index c5cf86a2..00000000 --- a/cpp/goitemmodel_api.h +++ /dev/null @@ -1,103 +0,0 @@ -#ifndef GOITEMMODEL_API_H -#define GOITEMMODEL_API_H - -// #include "capi.h" -#include -#include -#include -#include "capi.h" -#include - -typedef void GoAddr; -typedef void QObject_; -typedef void QItemModel_; -typedef void QModelIndex_; -typedef void QVariant_; - -#ifdef __cplusplus -extern "C" { -#endif - -QItemModel_* newGoItemModel(QObject_*, GoValueRef); -void deleteGoItemModel(QItemModel_*); - -QModelIndex_ *modelIndexChild(QModelIndex_ *mi, int row, int col); -QModelIndex_ *modelIndexSibling(QModelIndex_ *mi, int row, int col); -int modelIndexColumn(QModelIndex_ *mi); -int modelIndexRow(QModelIndex_ *mi); -void modelIndexData(QModelIndex_ *mi, int role, DataValue *ret); -quint32 modelIndexFlags(QModelIndex_ *mi); -uintptr_t modelIndexInternalId(QModelIndex_ *mi); -uintptr_t modelIndexInternalPointer(QModelIndex_ *mi); -bool modelIndexIsValid(QModelIndex_ *mi); -QItemModel_ *modelIndexModel(QModelIndex_ *mi); -QModelIndex_ *modelIndexParent(QModelIndex_ *mi); - - -// Required functions -int itemModelColumnCount(QItemModel_ *im, QModelIndex_ *parent); -void itemModelData(QItemModel_ *im, QModelIndex_ *index, int role, DataValue *ret); -QModelIndex_ *itemModelIndex(QItemModel_ *im, int row, int column, QModelIndex_ *parent); -QModelIndex_ *itemModelParent(QItemModel_ *im, QModelIndex_ *index); -int itemModelRowCount(QItemModel_ *im, QModelIndex_ *parent); - -// Required for editing -int itemModelFlags(QItemModel_ *im, QModelIndex_ *index); -bool itemModelSetData(QItemModel_ *im, QModelIndex_ *index, DataValue *value, int role); - -// Protected functions -QModelIndex_ *itemModelCreateIndex(QItemModel_ *im, int row, int col, uintptr_t id); -void itemModelBeginInsertColumns(QItemModel_ *im, QModelIndex_ *parent, int first, int last); -void itemModelEndInsertColumns(QItemModel_ *im); -void itemModelBeginInsertRows(QItemModel_ *im, QModelIndex_ *parent, int first, int last); -void itemModelEndInsertRows(QItemModel_ *im); -void itemModelBeginRemoveRows(QItemModel_ *im, QModelIndex_ *parent, int first, int last); -void itemModelEndRemoveRows(QItemModel_ *im); - - -void itemModelDataChanged(QItemModel_ *im, QModelIndex_ *topLeft, QModelIndex_ *bottomRight); - - -// virtual QModelIndex buddy(const QModelIndex &index) const -// virtual bool canDropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent) const -// virtual bool canFetchMore(const QModelIndex &parent) const -// virtual bool dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent) -// virtual void fetchMore(const QModelIndex &parent) -// virtual Qt::ItemFlags flags(const QModelIndex &index) const -// virtual bool hasChildren(const QModelIndex &parent = QModelIndex()) const -// bool hasIndex(int row, int column, const QModelIndex &parent = QModelIndex()) const -// virtual QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const -// bool insertColumn(int column, const QModelIndex &parent = QModelIndex()) -// virtual bool insertColumns(int column, int count, const QModelIndex &parent = QModelIndex()) -// bool insertRow(int row, const QModelIndex &parent = QModelIndex()) -// virtual bool insertRows(int row, int count, const QModelIndex &parent = QModelIndex()) -// virtual QMap itemData(const QModelIndex &index) const -// virtual QModelIndexList match(const QModelIndex &start, int role, const QVariant &value, int hits = 1, Qt::MatchFlags flags = Qt::MatchFlags( Qt::MatchStartsWith | Qt::MatchWrap )) const -// virtual QMimeData * mimeData(const QModelIndexList &indexes) const -// virtual QStringList mimeTypes() const -// bool moveColumn(const QModelIndex &sourceParent, int sourceColumn, const QModelIndex &destinationParent, int destinationChild) -// virtual bool moveColumns(const QModelIndex &sourceParent, int sourceColumn, int count, const QModelIndex &destinationParent, int destinationChild) -// bool moveRow(const QModelIndex &sourceParent, int sourceRow, const QModelIndex &destinationParent, int destinationChild) -// virtual bool moveRows(const QModelIndex &sourceParent, int sourceRow, int count, const QModelIndex &destinationParent, int destinationChild) -// bool removeColumn(int column, const QModelIndex &parent = QModelIndex()) -// virtual bool removeColumns(int column, int count, const QModelIndex &parent = QModelIndex()) -// bool removeRow(int row, const QModelIndex &parent = QModelIndex()) -// virtual bool removeRows(int row, int count, const QModelIndex &parent = QModelIndex()) -// virtual QHash roleNames() const -// virtual bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole) -// virtual bool setHeaderData(int section, Qt::Orientation orientation, const QVariant &value, int role = Qt::EditRole) -// virtual bool setItemData(const QModelIndex &index, const QMap &roles) -// virtual QModelIndex sibling(int row, int column, const QModelIndex &index) const -// virtual void sort(int column, Qt::SortOrder order = Qt::AscendingOrder) -// virtual QSize span(const QModelIndex &index) const -// virtual Qt::DropActions supportedDragActions() const -// virtual Qt::DropActions supportedDropActions() const - - -#ifdef __cplusplus -} // extern "C" -#endif - -#endif // GOITEMMODEL_API_H - -// vim:ts=4:sw=4:et:ft=cpp diff --git a/cpp/goitemmodel_impl.h b/cpp/goitemmodel_impl.h deleted file mode 100644 index 56852c1f..00000000 --- a/cpp/goitemmodel_impl.h +++ /dev/null @@ -1,76 +0,0 @@ -#ifndef GOITEMMODEL_IMPL_H -#define GOITEMMODEL_IMPL_H - -// #include "capi.h" -#include -#include -#include - -typedef void GoAddr; -typedef void QObject_; -typedef void QItemModel_; -typedef void QModelIndex_; -typedef void QVariant_; - -#ifdef __cplusplus -extern "C" { -#endif - -// QItemModel_* newGoItemModel(QObject_*, GoValueRef); -// void deleteGoItemModel(QItemModel_*); - -// Required functions -int implColumnCount(GoValueRef impl, QModelIndex_ *parent); -void implData(GoValueRef impl, QModelIndex_ *index, int role, DataValue *ret); -QModelIndex_ *implIndex(GoValueRef impl, int row, int column, QModelIndex_ *parent); -QModelIndex_ *implParent(GoValueRef impl, QModelIndex_ *index); -int implRowCount(GoValueRef impl, QModelIndex_ *parent); - -// Required for editing -int implFlags(GoValueRef impl, QModelIndex_ *index); -bool implSetData(GoValueRef impl, QModelIndex_ *index, DataValue *value, int role); - - -// virtual QModelIndex buddy(const QModelIndex &index) const -// virtual bool canDropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent) const -// virtual bool canFetchMore(const QModelIndex &parent) const -// virtual bool dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent) -// virtual void fetchMore(const QModelIndex &parent) -// virtual Qt::ItemFlags flags(const QModelIndex &index) const -// virtual bool hasChildren(const QModelIndex &parent = QModelIndex()) const -// bool hasIndex(int row, int column, const QModelIndex &parent = QModelIndex()) const -// virtual QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const -// bool insertColumn(int column, const QModelIndex &parent = QModelIndex()) -// virtual bool insertColumns(int column, int count, const QModelIndex &parent = QModelIndex()) -// bool insertRow(int row, const QModelIndex &parent = QModelIndex()) -// virtual bool insertRows(int row, int count, const QModelIndex &parent = QModelIndex()) -// virtual QMap itemData(const QModelIndex &index) const -// virtual QModelIndexList match(const QModelIndex &start, int role, const QVariant &value, int hits = 1, Qt::MatchFlags flags = Qt::MatchFlags( Qt::MatchStartsWith | Qt::MatchWrap )) const -// virtual QMimeData * mimeData(const QModelIndexList &indexes) const -// virtual QStringList mimeTypes() const -// bool moveColumn(const QModelIndex &sourceParent, int sourceColumn, const QModelIndex &destinationParent, int destinationChild) -// virtual bool moveColumns(const QModelIndex &sourceParent, int sourceColumn, int count, const QModelIndex &destinationParent, int destinationChild) -// bool moveRow(const QModelIndex &sourceParent, int sourceRow, const QModelIndex &destinationParent, int destinationChild) -// virtual bool moveRows(const QModelIndex &sourceParent, int sourceRow, int count, const QModelIndex &destinationParent, int destinationChild) -// bool removeColumn(int column, const QModelIndex &parent = QModelIndex()) -// virtual bool removeColumns(int column, int count, const QModelIndex &parent = QModelIndex()) -// bool removeRow(int row, const QModelIndex &parent = QModelIndex()) -// virtual bool removeRows(int row, int count, const QModelIndex &parent = QModelIndex()) -// virtual QHash roleNames() const -// virtual bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole) -// virtual bool setHeaderData(int section, Qt::Orientation orientation, const QVariant &value, int role = Qt::EditRole) -// virtual bool setItemData(const QModelIndex &index, const QMap &roles) -// virtual QModelIndex sibling(int row, int column, const QModelIndex &index) const -// virtual void sort(int column, Qt::SortOrder order = Qt::AscendingOrder) -// virtual QSize span(const QModelIndex &index) const -// virtual Qt::DropActions supportedDragActions() const -// virtual Qt::DropActions supportedDropActions() const - - -#ifdef __cplusplus -} // extern "C" -#endif - -#endif // GOITEMMODEL_IMPL_H - -// vim:ts=4:sw=4:et:ft=cpp diff --git a/cpp/moc_all.cpp b/cpp/moc_all.cpp index c713140d..cff09705 100644 --- a/cpp/moc_all.cpp +++ b/cpp/moc_all.cpp @@ -1,5 +1,4 @@ // This file is automatically generated by cpp/update-moc.sh #include "cpp/moc_connector.cpp" -#include "cpp/moc_goitemmodel.cpp" #include "cpp/moc_govalue.cpp" #include "cpp/moc_idletimer.cpp" diff --git a/cpp/qmodelindex.cpp b/cpp/qmodelindex.cpp deleted file mode 100644 index 80018439..00000000 --- a/cpp/qmodelindex.cpp +++ /dev/null @@ -1,13 +0,0 @@ - -#include "qmodelindex.h" -#include "util.cpp" - - -QModelIndex_* newGoModelIndex(QObject_* parent, GoValueRef impl) { - return reinterpret_cast(new GoModelIndex(reinterpret_cast(parent), impl)); -} - -void deleteGoModelIndex(QModelIndex_* im) { - delete reinterpret_cast(im); -} - diff --git a/cpp/qmodelindex.h b/cpp/qmodelindex.h deleted file mode 100644 index dcc5f5c1..00000000 --- a/cpp/qmodelindex.h +++ /dev/null @@ -1,25 +0,0 @@ -#ifndef MODELINDEX_H -#define MODELINDEX_H - -// #include "capi.h" - -typedef void GoAddr; -typedef void QObject_; -typedef void QItemModel_; -typedef void QModelIndex_; - -#ifdef __cplusplus -extern "C" { -#endif - -QItemModel_* newGoItemModel(QObject_*, GoValueRef); -void deleteGoItemModel(QItemModel_*); - - -#ifdef __cplusplus -} // extern "C" -#endif - -#endif // MODELINDEX_H - -// vim:ts=4:sw=4:et:ft=cpp diff --git a/cpp/util.cpp b/cpp/util.cpp deleted file mode 100644 index 8589215d..00000000 --- a/cpp/util.cpp +++ /dev/null @@ -1,7 +0,0 @@ - -#include "util.h" - -QString QStringFromGoString(const char *str, unsigned int length) { - QByteArray qstrarray(str, length); - return QString::fromUtf8(qstrarray); -} diff --git a/cpp/util.h b/cpp/util.h deleted file mode 100644 index 9b5fd649..00000000 --- a/cpp/util.h +++ /dev/null @@ -1,21 +0,0 @@ -#ifndef UTIL_H -#define UTIL_H - -#include - - -#ifdef __cplusplus -extern "C" { -#endif - - - -QString QStringFromGoString(const char *str, unsigned int length); - - - -#ifdef __cplusplus -} // extern "C" -#endif - -#endif // UTIL_H diff --git a/goitemmodel.go b/goitemmodel.go deleted file mode 100644 index 133edd20..00000000 --- a/goitemmodel.go +++ /dev/null @@ -1,264 +0,0 @@ -package qml - -// #cgo CPPFLAGS: -I../cpp -// #cgo CXXFLAGS: -std=c++0x -Wall -fno-strict-aliasing -// #cgo LDFLAGS: -lstdc++ -// #cgo pkg-config: Qt5Core Qt5Widgets Qt5Quick -// -// #include -// #include "goitemmodel_api.h" -// -import "C" -import ( - "runtime" - "unsafe" -) - -const ( - NoItemFlags ItemFlags = 0 - ItemIsSelectable ItemFlags = 1 - ItemIsEditable ItemFlags = 2 - ItemIsDragEnabled ItemFlags = 4 - ItemIsDropEnabled ItemFlags = 8 - ItemIsUserCheckable ItemFlags = 16 - ItemIsEnabled ItemFlags = 32 - ItemIsAutoTristate ItemFlags = 64 - ItemNeverHasChildren ItemFlags = 128 - ItemIsUserTristate ItemFlags = 256 -) - -type ItemModel interface { - internal_ItemModel() *goItemModel -} - -type ItemModelInternal interface { - CreateIndex(row int, column int, id uintptr) ModelIndex - - BeginInsertColumns(parent ModelIndex, first int, last int) - EndInsertColumns() - BeginInsertRows(parent ModelIndex, first int, last int) - EndInsertRows() - BeginRemoveRows(parent ModelIndex, first int, last int) - EndRemoveRows() - DataChanged(topLeft ModelIndex, bottomRight ModelIndex) -} - -type goItemModel struct { - common *Common - impl ItemModelImpl -} - -func (qim *goItemModel) internal_ItemModel() *goItemModel { return qim } - -func NewItemModel(engine *Engine, parent Object, impl ItemModelImpl) (ItemModel, ItemModelInternal) { - im := mkItemModel() - - var parentPtr unsafe.Pointer - if parent != nil { - parentPtr = unsafe.Pointer(parent.Addr()) - } - - im.impl = impl - - var imptr unsafe.Pointer - - RunMain(func() { - fold := &valueFold{ - gvalue: im, - } - imptr = C.newGoItemModel(parentPtr, getFoldRef(fold)) - }) - - im.common = CommonOf(imptr, engine) - - return im, im -} - -func mkItemModel() *goItemModel { - qimg := &goItemModel{} - - runtime.SetFinalizer(qimg, deleteItemModel) - - return qimg -} - -func deleteItemModel(qim *goItemModel) { - C.deleteGoItemModel(qim.common.addr) - // qim.addr = nil -} - -type ItemModelImpl interface { - // Required functions - ColumnCount(parent ModelIndex) int - Data(index ModelIndex, role Role) interface{} - Index(row int, column int, parent ModelIndex) ModelIndex - Parent(index ModelIndex) ModelIndex - RowCount(parent ModelIndex) int - - // Required for editing - Flags(index ModelIndex) ItemFlags - SetData(index ModelIndex, value interface{}, role Role) bool -} - -type Role int -type ItemFlags int - -type cppItemModelImpl struct { - qim *goItemModel -} - -func itemModelFromCPP(addr uintptr, engine *Engine) ItemModel { - im := mkItemModel() - - im.impl = &cppItemModelImpl{im} - im.common = CommonOf(unsafe.Pointer(addr), engine) - - return im -} - -func passMI(mi ModelIndex) unsafe.Pointer { - if mi == nil { - return nil - } - return unsafe.Pointer(mi.(*qModelIndex).ptr) -} - -// Required functions -func (cim *cppItemModelImpl) ColumnCount(parent ModelIndex) int { - return int(C.itemModelColumnCount(cim.qim.common.addr, passMI(parent))) -} - -func (cim *cppItemModelImpl) Data(index ModelIndex, role Role) interface{} { - var dvalue C.DataValue - C.itemModelData(cim.qim.common.addr, passMI(index), C.int(role), &dvalue) - return unpackDataValue(&dvalue, cim.qim.common.engine) -} - -func (cim *cppItemModelImpl) Index(row int, col int, parent ModelIndex) ModelIndex { - return mkModelIndex(uintptr(C.itemModelIndex(cim.qim.common.addr, C.int(row), C.int(col), passMI(parent))), cim.qim.common.engine) -} - -func (cim *cppItemModelImpl) Parent(index ModelIndex) ModelIndex { - return mkModelIndex(uintptr(C.itemModelParent(cim.qim.common.addr, passMI(index))), cim.qim.common.engine) -} - -func (cim *cppItemModelImpl) RowCount(parent ModelIndex) int { - return int(C.itemModelRowCount(cim.qim.common.addr, passMI(parent))) -} - -// Required for editing -func (cim *cppItemModelImpl) Flags(index ModelIndex) ItemFlags { - return ItemFlags(C.itemModelFlags(cim.qim.common.addr, passMI(index))) -} - -func (cim *cppItemModelImpl) SetData(index ModelIndex, value interface{}, role Role) bool { - var dvalue C.DataValue - packDataValue(value, &dvalue, cim.qim.common.engine, cppOwner) - return bool(C.itemModelSetData(cim.qim.common.addr, passMI(index), &dvalue, C.int(role))) -} - -// Internal (protected) functions - -func (qim *goItemModel) CreateIndex(row int, column int, id uintptr) ModelIndex { - indexPtr := C.itemModelCreateIndex(qim.common.addr, C.int(row), C.int(column), C.uintptr_t(id)) - return mkModelIndex(uintptr(indexPtr), qim.common.engine) -} - -func (qim *goItemModel) BeginInsertColumns(parent ModelIndex, first int, last int) { - C.itemModelBeginInsertColumns(qim.common.addr, passMI(parent), C.int(first), C.int(last)) -} - -func (qim *goItemModel) EndInsertColumns() { - C.itemModelEndInsertColumns(qim.common.addr) -} - -func (qim *goItemModel) BeginInsertRows(parent ModelIndex, first int, last int) { - C.itemModelBeginInsertRows(qim.common.addr, passMI(parent), C.int(first), C.int(last)) -} - -func (qim *goItemModel) EndInsertRows() { - C.itemModelEndInsertRows(qim.common.addr) -} - -func (qim *goItemModel) BeginRemoveRows(parent ModelIndex, first int, last int) { - C.itemModelBeginRemoveRows(qim.common.addr, passMI(parent), C.int(first), C.int(last)) -} - -func (qim *goItemModel) EndRemoveRows() { - C.itemModelEndRemoveRows(qim.common.addr) -} - -func (qim *goItemModel) DataChanged(topLeft ModelIndex, bottomRight ModelIndex) { - C.itemModelDataChanged(qim.common.addr, passMI(topLeft), passMI(bottomRight)) -} - -// Required functions -//export implColumnCount -func implColumnCount(qim C.GoValueRef, parent uintptr) int { - im := foldFromRef(qim).gvalue.(*goItemModel) - parentMi := mkModelIndex(parent, im.common.engine) - - return im.impl.ColumnCount(parentMi) -} - -//export implData -func implData(qim C.GoValueRef, index uintptr, role int, ret *C.DataValue) { - im := foldFromRef(qim).gvalue.(*goItemModel) - indexMi := mkModelIndex(index, im.common.engine) - - v := im.impl.Data(indexMi, Role(role)) - - packDataValue(v, ret, im.common.engine, cppOwner) -} - -//export implIndex -func implIndex(qim C.GoValueRef, row int, column int, parent uintptr) unsafe.Pointer { - im := foldFromRef(qim).gvalue.(*goItemModel) - parentMi := mkModelIndex(parent, im.common.engine) - - ret := im.impl.Index(row, column, parentMi) - if ret != nil { - return ret.(*qModelIndex).ptr - } - - return nil -} - -//export implParent -func implParent(qim C.GoValueRef, index uintptr) unsafe.Pointer { - im := foldFromRef(qim).gvalue.(*goItemModel) - indexMi := mkModelIndex(index, im.common.engine) - parentMi := im.impl.Parent(indexMi) - if parentMi != nil { - return parentMi.(*qModelIndex).ptr - } - - return nil -} - -//export implRowCount -func implRowCount(qim C.GoValueRef, parent uintptr) int { - im := foldFromRef(qim).gvalue.(*goItemModel) - parentMi := mkModelIndex(parent, im.common.engine) - - return im.impl.RowCount(parentMi) -} - -// Required for editing -//export implFlags -func implFlags(qim C.GoValueRef, index uintptr) ItemFlags { - im := foldFromRef(qim).gvalue.(*goItemModel) - indexMi := mkModelIndex(index, im.common.engine) - - return im.impl.Flags(indexMi) -} - -//export implSetData -func implSetData(qim C.GoValueRef, index uintptr, dv *C.DataValue, role int) bool { - im := foldFromRef(qim).gvalue.(*goItemModel) - indexMi := mkModelIndex(index, im.common.engine) - - value := unpackDataValue(dv, im.common.engine) - - return im.impl.SetData(indexMi, value, Role(role)) -} diff --git a/goitemmodelimpls.go b/goitemmodelimpls.go deleted file mode 100644 index f107cd60..00000000 --- a/goitemmodelimpls.go +++ /dev/null @@ -1,37 +0,0 @@ -package qml - -type ItemModelDefaultImpl struct { -} - -func (l *ItemModelDefaultImpl) ColumnCount(parent ModelIndex) int { - return 1 -} - -func (l *ItemModelDefaultImpl) RowCount(parent ModelIndex) int { - return 1 -} - -func (l *ItemModelDefaultImpl) Data(index ModelIndex, role Role) interface{} { - return nil -} - -func (l *ItemModelDefaultImpl) Index(row int, column int, parent ModelIndex) ModelIndex { - // if !parent.IsValid() && column == 0 && row >= 0 && row < len(l.lines) { - // return l.internal.CreateIndex(row, column, 0) - // } - return nil -} - -func (l *ItemModelDefaultImpl) Parent(index ModelIndex) ModelIndex { - return nil -} - -// Editing functions - -func (l *ItemModelDefaultImpl) Flags(index ModelIndex) ItemFlags { - return NoItemFlags -} - -func (l *ItemModelDefaultImpl) SetData(index ModelIndex, value interface{}, role Role) bool { - return false -} diff --git a/gomodelindex.go b/gomodelindex.go deleted file mode 100644 index dface22a..00000000 --- a/gomodelindex.go +++ /dev/null @@ -1,94 +0,0 @@ -package qml - -// #cgo CPPFLAGS: -I../cpp -// #cgo CXXFLAGS: -std=c++0x -Wall -fno-strict-aliasing -// #cgo LDFLAGS: -lstdc++ -// #cgo pkg-config: Qt5Core Qt5Widgets Qt5Quick -// -// #include -// #include "goitemmodel_api.h" -// -import "C" -import "unsafe" - -type qModelIndex struct { - ptr unsafe.Pointer - engine *Engine -} - -func mkModelIndex(ptr uintptr, engine *Engine) ModelIndex { - if ptr == 0 { - return nil - } - return &qModelIndex{ - ptr: unsafe.Pointer(ptr), - engine: engine, - } -} - -type ModelIndex interface { - // ModelIndex can only be created from a ItemModel - internal_ModelIndex() - Child(row, col int) ModelIndex - Sibling(row, col int) ModelIndex - Column() int - Row() int - Data(role Role) interface{} - Flags() ItemFlags - InternalId() uintptr - InternalPointer() uintptr - IsValid() bool - Model() ItemModel - Parent() ModelIndex -} - -func (i *qModelIndex) internal_ModelIndex() {} - -func (i *qModelIndex) Child(row, col int) ModelIndex { - return mkModelIndex(uintptr(C.modelIndexChild(i.ptr, C.int(row), C.int(col))), i.engine) -} - -func (i *qModelIndex) Sibling(row, col int) ModelIndex { - return mkModelIndex(uintptr(C.modelIndexSibling(i.ptr, C.int(row), C.int(col))), i.engine) -} - -func (i *qModelIndex) Column() int { - return int(C.modelIndexColumn(i.ptr)) -} - -func (i *qModelIndex) Row() int { - return int(C.modelIndexRow(i.ptr)) -} - -func (i *qModelIndex) Data(role Role) interface{} { - var dvalue C.DataValue - C.modelIndexData(i.ptr, C.int(role), &dvalue) - return unpackDataValue(&dvalue, i.engine) -} - -func (i *qModelIndex) Flags() ItemFlags { - return ItemFlags(C.modelIndexFlags(i.ptr)) -} - -func (i *qModelIndex) InternalId() uintptr { - return uintptr(C.modelIndexInternalId(i.ptr)) -} - -func (i *qModelIndex) InternalPointer() uintptr { - return uintptr(C.modelIndexInternalPointer(i.ptr)) -} - -func (i *qModelIndex) IsValid() bool { - if i == nil || i.ptr == nil { - return false - } - return bool(C.modelIndexIsValid(i.ptr)) -} - -func (i *qModelIndex) Model() ItemModel { - return itemModelFromCPP(uintptr(C.modelIndexModel(i.ptr)), i.engine) -} - -func (i *qModelIndex) Parent() ModelIndex { - return mkModelIndex(uintptr(C.modelIndexParent(i.ptr)), i.engine) -} diff --git a/qmlcommon.go b/qmlcommon.go deleted file mode 100644 index 0a0e02ee..00000000 --- a/qmlcommon.go +++ /dev/null @@ -1,496 +0,0 @@ -package qml - -// #include -// -// #include "capi.h" -// -import "C" - -import ( - "fmt" - "image/color" - "os" - "reflect" - "runtime" - "unsafe" - - "github.com/nanu-c/qml-go/tools/util" -) - -// Common implements the common behavior of all QML objects. -// It implements the Object interface. -type Common struct { - addr unsafe.Pointer - engine *Engine - destroyed bool - initialized bool -} - -var _ Object = (*Common)(nil) - -// CommonOf returns the Common QML value for the QObject at addr. -// -// This is meant for extensions that integrate directly with the -// underlying QML logic. -func CommonOf(addr unsafe.Pointer, engine *Engine) *Common { - c := &Common{nil, engine, false, false} - c.setAddr(addr) - return c -} - -func (obj *Common) setAddr(addr unsafe.Pointer) { - if obj.initialized || obj.addr != nil || obj.destroyed { - panic("Cannot reuse Common!") - } - obj.addr = addr - obj.initialized = true - - if addr != nil { - obj.On("destroyed", func() { obj.addr = nil; obj.destroyed = true }) - } -} - -func (obj *Common) assertInitialized() { - if !obj.initialized { - panic("Use of uninitialized object") - } - if obj.destroyed { - panic("Use of destroyed object") - } -} - -// Common returns obj itself. -// -// This provides access to the underlying *Common for types that -// embed it, when these are used via the Object interface. -func (obj *Common) Common() *Common { - return obj -} -func (obj *Common) Engine() *Engine { - return obj.engine -} - -// TypeName returns the underlying type name for the held value. -func (obj *Common) TypeName() string { - obj.assertInitialized() - var name string - RunMain(func() { - name = C.GoString(C.objectTypeName(obj.addr)) - }) - return name -} - -// Addr returns the QML object address. -// -// This is meant for extensions that integrate directly with the -// underlying QML logic. -func (obj *Common) Addr() uintptr { - obj.assertInitialized() - return uintptr(obj.addr) -} - -// Interface returns the underlying Go value that is being held by -// the object wrapper. -// -// It is a runtime error to call Interface on values that are not -// backed by a Go value. -func (obj *Common) Interface() interface{} { - obj.assertInitialized() - var result interface{} - var cerr *C.error - RunMain(func() { - var valueref C.GoValueRef - if cerr = C.objectGoAddr(obj.addr, &valueref); cerr == nil { - result = foldFromRef(valueref).gvalue - } - }) - cmust(cerr) - return result -} - -// Set changes the named object property to the given value. -func (obj *Common) Set(property string, value interface{}) { - obj.assertInitialized() - cproperty := C.CString(property) - defer C.free(unsafe.Pointer(cproperty)) - var cerr *C.error - RunMain(func() { - var dvalue C.DataValue - packDataValue(value, &dvalue, obj.engine, cppOwner) - cerr = C.objectSetProperty(obj.addr, cproperty, &dvalue) - }) - cmust(cerr) -} - -// Property returns the current value for a property of the object. -// If the property type is known, type-specific methods such as Int -// and String are more convenient to use. -// Property panics if the property does not exist. -func (obj *Common) Property(name string) interface{} { - obj.assertInitialized() - cname := C.CString(name) - defer C.free(unsafe.Pointer(cname)) - - var dvalue C.DataValue - var found C.int - RunMain(func() { - found = C.objectGetProperty(obj.addr, cname, &dvalue) - }) - if found == 0 { - panic(fmt.Sprintf("object does not have a %q property", name)) - } - return unpackDataValue(&dvalue, obj.engine) -} - -// Int returns the int value of the named property. -// Int panics if the property cannot be represented as an int. -func (obj *Common) Int(property string) int { - switch value := obj.Property(property).(type) { - case int64: - return int(value) - case int: - return value - case uint64: - return int(value) - case uint32: - return int(value) - case uintptr: - return int(value) - case float32: - return int(value) - case float64: - return int(value) - default: - panic(fmt.Sprintf("value of property %q cannot be represented as an int: %#v", property, value)) - } -} - -// Int64 returns the int64 value of the named property. -// Int64 panics if the property cannot be represented as an int64. -func (obj *Common) Int64(property string) int64 { - switch value := obj.Property(property).(type) { - case int64: - return value - case int: - return int64(value) - case uint64: - return int64(value) - case uint32: - return int64(value) - case uintptr: - return int64(value) - case float32: - return int64(value) - case float64: - return int64(value) - default: - panic(fmt.Sprintf("value of property %q cannot be represented as an int64: %#v", property, value)) - } -} - -// Float64 returns the float64 value of the named property. -// Float64 panics if the property cannot be represented as float64. -func (obj *Common) Float64(property string) float64 { - switch value := obj.Property(property).(type) { - case int64: - return float64(value) - case int: - return float64(value) - case uint64: - return float64(value) - case uint32: - return float64(value) - case uintptr: - return float64(value) - case float32: - return float64(value) - case float64: - return value - default: - panic(fmt.Sprintf("value of property %q cannot be represented as a float64: %#v", property, value)) - } -} - -// Bool returns the bool value of the named property. -// Bool panics if the property is not a bool. -func (obj *Common) Bool(property string) bool { - value := obj.Property(property) - if b, ok := value.(bool); ok { - return b - } - panic(fmt.Sprintf("value of property %q is not a bool: %#v", property, value)) -} - -// String returns the string value of the named property. -// String panics if the property is not a string. -func (obj *Common) String(property string) string { - value := obj.Property(property) - if s, ok := value.(string); ok { - return s - } - panic(fmt.Sprintf("value of property %q is not a string: %#v", property, value)) -} - -// Color returns the RGBA value of the named property. -// Color panics if the property is not a color. -func (obj *Common) Color(property string) color.RGBA { - value := obj.Property(property) - c, ok := value.(color.RGBA) - if !ok { - panic(fmt.Sprintf("value of property %q is not a color: %#v", property, value)) - } - return c -} - -// Object returns the object value of the named property. -// Object panics if the property is not a QML object. -func (obj *Common) Object(property string) Object { - value := obj.Property(property) - object, ok := value.(Object) - if !ok { - panic(fmt.Sprintf("value of property %q is not a QML object: %#v", property, value)) - } - return object -} - -// List returns the list value of the named property. -// List panics if the property is not a list. -func (obj *Common) List(property string) *List { - value := obj.Property(property) - m, ok := value.(*List) - if !ok { - panic(fmt.Sprintf("value of property %q is not a QML list: %#v", property, value)) - } - return m -} - -// Map returns the map value of the named property. -// Map panics if the property is not a map. -func (obj *Common) Map(property string) *Map { - value := obj.Property(property) - m, ok := value.(*Map) - if !ok { - panic(fmt.Sprintf("value of property %q is not a QML map: %#v", property, value)) - } - return m -} - -// ObjectByName returns the Object value of the descendant object that -// was defined with the objectName property set to the provided value. -// ObjectByName panics if the object is not found. -func (obj *Common) ObjectByName(objectName string) Object { - obj.assertInitialized() - cname, cnamelen := util.UnsafeStringData(objectName) - var dvalue C.DataValue - var object Object - RunMain(func() { - qname := C.newString((*C.char)(cname), C.int(cnamelen)) - defer C.delString(qname) - C.objectFindChild(obj.addr, qname, &dvalue) - // unpackDataValue will also initialize the Go type, if necessary. - value := unpackDataValue(&dvalue, obj.engine) - if dvalue.dataType == C.DTGoAddr { - datap := unsafe.Pointer(&dvalue.data) - fold := (*(**valueFold)(datap)) - if fold.init.IsValid() { - panic("internal error: custom Go type not initialized") - } - cobject := CommonOf(fold.cvalue, fold.engine) - object = cobject - } else { - object, _ = value.(Object) - } - }) - if object == nil { - panic(fmt.Sprintf("cannot find descendant with objectName == %q", objectName)) - } - return object -} - -// Call calls the given object method with the provided parameters. -// Call panics if the method does not exist. -func (obj *Common) Call(method string, params ...interface{}) interface{} { - obj.assertInitialized() - if len(params) > len(dataValueArray) { - panic("too many parameters") - } - cmethod, cmethodLen := util.UnsafeStringData(method) - var result C.DataValue - var cerr *C.error - RunMain(func() { - for i, param := range params { - packDataValue(param, &dataValueArray[i], obj.engine, jsOwner) - } - defer func() { - if r := recover(); r != nil { - fmt.Fprintf(os.Stderr, "Panic objectInvoke, %v\n", method) - } - }() - // if obj.addr == nil { - // fmt.Fprintf(os.Stderr, "objectInvoke, %v %v %v\n", obj.addr, method, len(params)) - // } - if obj.destroyed { - // object wasn't destroyed before, checked by assertInitialized, so it was - // destroyed while waiting to run on the main thread - // TODO: What to do about this??? - } - cerr = C.objectInvoke(obj.addr, (*C.char)(cmethod), C.int(cmethodLen), &result, &dataValueArray[0], C.int(len(params))) - }) - if cerr != nil { - fmt.Fprintf(os.Stderr, "Common: %#v\n", obj) - } - cmust(cerr) - return unpackDataValue(&result, obj.engine) -} - -// Create creates a new instance of the component held by obj. -// The component instance runs under the ctx context. If ctx is nil, -// it runs under the same context as obj. -// -// The Create method panics if called on an object that does not -// represent a QML component. -func (obj *Common) Create(ctx *Context) Object { - obj.assertInitialized() - if C.objectIsComponent(obj.addr) == 0 { - panic("object is not a component") - } - var root Common - root.engine = obj.engine - RunMain(func() { - ctxaddr := nilPtr - if ctx != nil { - ctxaddr = ctx.addr - } - root.setAddr(C.componentCreate(obj.addr, ctxaddr)) - }) - return &root -} - -// CreateWindow creates a new instance of the component held by obj, -// and creates a new window holding the instance as its root object. -// The component instance runs under the ctx context. If ctx is nil, -// it runs under the same context as obj. -// -// The CreateWindow method panics if called on an object that -// does not represent a QML component. -func (obj *Common) CreateWindow(ctx *Context) *Window { - obj.assertInitialized() - if C.objectIsComponent(obj.addr) == 0 { - panic("object is not a component") - } - var win Window - win.engine = obj.engine - RunMain(func() { - ctxaddr := nilPtr - if ctx != nil { - ctxaddr = ctx.addr - } - win.setAddr(C.componentCreateWindow(obj.addr, ctxaddr)) - }) - return &win -} - -// Destroy finalizes the value and releases any resources used. -// The value must not be used after calling this method. -func (obj *Common) Destroy() { - // TODO We might hook into the destroyed signal, and prevent this object - // from being used in post-destruction crash-prone ways. - RunMain(func() { - if obj.addr != nilPtr { - C.delObjectLater(obj.addr) - obj.addr = nilPtr - } - }) -} - -var connectedFunction = make(map[*interface{}]bool) - -// On connects the named signal from obj with the provided function, so that -// when obj next emits that signal, the function is called with the parameters -// the signal carries. -// -// The provided function must accept a number of parameters that is equal to -// or less than the number of parameters provided by the signal, and the -// resepctive parameter types must match exactly or be conversible according -// to normal Go rules. -// -// For example: -// -// obj.On("clicked", func() { fmt.Println("obj got a click") }) -// -// Note that Go uses the real signal name, rather than the one used when -// defining QML signal handlers ("clicked" rather than "onClicked"). -// -// For more details regarding signals and QML see: -// -// http://qt-project.org/doc/qt-5.0/qtqml/qml-qtquick2-connections.html -// -func (obj *Common) On(signal string, function interface{}) { - obj.assertInitialized() - funcv := reflect.ValueOf(function) - funct := funcv.Type() - if funcv.Kind() != reflect.Func { - panic("function provided to On is not a function or method") - } - if funct.NumIn() > C.MaxParams { - panic("function takes too many arguments") - } - csignal, csignallen := util.UnsafeStringData(signal) - var cerr *C.error - RunMain(func() { - fold := &valueFold{gvalue: &function} - funcref := getFoldRef(fold) - cerr = C.objectConnect(obj.addr, (*C.char)(csignal), C.int(csignallen), obj.engine.addr, funcref, C.int(funcv.Type().NumIn())) - if cerr == nil { - connectedFunction[&function] = true - stats.connectionsAlive(+1) - } - }) - cmust(cerr) -} - -// Disconnect everything connected to an object's signals -func (obj *Common) Clear() { - obj.assertInitialized() - var cerr *C.error - RunMain(func() { - cerr = C.objectDisconnect(obj.addr) - }) - cmust(cerr) -} - -//export hookSignalDisconnect -func hookSignalDisconnect(funcref C.GoValueRef) { - fold := foldFromRef(funcref) - if fold == nil { - panic("disconnecting unknown signal function") - } - delete(connectedFunction, fold.gvalue.(*interface{})) - clearFoldRef(funcref) - stats.connectionsAlive(-1) -} - -//export hookSignalCall -func hookSignalCall(enginep unsafe.Pointer, funcref C.GoValueRef, args *C.DataValue) { - engine := engines[enginep] - fold := foldFromRef(funcref) - funcv := reflect.ValueOf(*fold.gvalue.(*interface{})) - - if engine == nil { - fmt.Println(fmt.Sprintf("signal called after engine was destroyed: %v %v", fold, runtime.FuncForPC(funcv.Pointer()).Name())) - } - - funct := funcv.Type() - numIn := funct.NumIn() - var params [C.MaxParams]reflect.Value - for i := 0; i < numIn; i++ { - arg := (*C.DataValue)(unsafe.Pointer(uintptr(unsafe.Pointer(args)) + uintptr(i)*dataValueSize)) - param := reflect.ValueOf(unpackDataValue(arg, engine)) - if paramt := funct.In(i); param.Type() != paramt { - // TODO Provide a better error message when this fails. - param = param.Convert(paramt) - } - params[i] = param - } - funcv.Call(params[:numIn]) -} diff --git a/qmlcontext.go b/qmlcontext.go deleted file mode 100644 index 5f3474fc..00000000 --- a/qmlcontext.go +++ /dev/null @@ -1,80 +0,0 @@ -package qml - -// #include -// -// #include "capi.h" -// -import "C" -import ( - "github.com/nanu-c/qml-go/tools/util" -) - -// Context represents a QML context that can hold variables visible -// to logic running within it. -type Context struct { - Common -} - -// SetVar makes the provided value available as a variable with the -// given name for QML code executed within the c context. -// -// If value is a struct, its exported fields are also made accessible to -// QML code as attributes of the named object. The attribute name in the -// object has the same name of the Go field name, except for the first -// letter which is lowercased. This is conventional and enforced by -// the QML implementation. -// -// The engine will hold a reference to the provided value, so it will -// not be garbage collected until the engine is destroyed, even if the -// value is unused or changed. -func (ctx *Context) SetVar(name string, value interface{}) { - cname, cnamelen := util.UnsafeStringData(name) - RunMain(func() { - var dvalue C.DataValue - packDataValue(value, &dvalue, ctx.engine, cppOwner) - - qname := C.newString((*C.char)(cname), C.int(cnamelen)) - defer C.delString(qname) - - C.contextSetProperty(ctx.addr, qname, &dvalue) - }) -} - -// SetVars makes the exported fields of the provided value available as -// variables for QML code executed within the c context. The variable names -// will have the same name of the Go field names, except for the first -// letter which is lowercased. This is conventional and enforced by -// the QML implementation. -// -// The engine will hold a reference to the provided value, so it will -// not be garbage collected until the engine is destroyed, even if the -// value is unused or changed. -func (ctx *Context) SetVars(value interface{}) { - RunMain(func() { - C.contextSetObject(ctx.addr, wrapGoValue(ctx.engine, value, cppOwner)) - }) -} - -// Var returns the context variable with the given name. -func (ctx *Context) Var(name string) interface{} { - cname, cnamelen := util.UnsafeStringData(name) - - var dvalue C.DataValue - RunMain(func() { - qname := C.newString((*C.char)(cname), C.int(cnamelen)) - defer C.delString(qname) - - C.contextGetProperty(ctx.addr, qname, &dvalue) - }) - return unpackDataValue(&dvalue, ctx.engine) -} - -// Spawn creates a new context that has ctx as a parent. -func (ctx *Context) Spawn() *Context { - var result Context - result.engine = ctx.engine - RunMain(func() { - result.setAddr(C.contextSpawn(ctx.addr)) - }) - return &result -} diff --git a/qmlengine.go b/qmlengine.go deleted file mode 100644 index e1dcfcc0..00000000 --- a/qmlengine.go +++ /dev/null @@ -1,298 +0,0 @@ -package qml - -// #include -// -// #include "capi.h" -// -import "C" - -import ( - "errors" - "fmt" - "image" - "io" - "io/ioutil" - "os" - "path/filepath" - "reflect" - "strings" - "unsafe" - - "github.com/nanu-c/qml-go/tools/util" -) - -// Engine provides an environment for instantiating QML components. -type Engine struct { - Common - values map[interface{}]*valueFold - destroyed bool - - savedAddr unsafe.Pointer // addr might be cleared when destroyed, use this after destroyed - - imageProviders map[string]*func(imageId string, width, height int) image.Image -} - -var engines = make(map[unsafe.Pointer]*Engine) - -// NewEngine returns a new QML engine. -// -// The Destory method must be called to finalize the engine and -// release any resources used. -func NewEngine() *Engine { - engine := &Engine{values: make(map[interface{}]*valueFold)} - RunMain(func() { - engine.engine = engine - engine.setAddr(C.newEngine(nil)) - engine.savedAddr = engine.addr - engine.imageProviders = make(map[string]*func(imageId string, width, height int) image.Image) - engines[engine.addr] = engine - stats.enginesAlive(+1) - engine.On("destroyed", engine.onDestroyed) - }) - return engine -} - -func (e *Engine) assertValid() { - if e.destroyed { - panic("engine already destroyed") - } -} - -// Destroy finalizes the engine and releases any resources used. -// The engine must not be used after calling this method. -// -// It is safe to call Destroy more than once. -func (e *Engine) Destroy() { - if !e.destroyed { - RunMain(func() { - if !e.destroyed { - e.destroyed = true - C.delObjectLater(e.addr) - } - }) - } -} - -func (e *Engine) onDestroyed() { - if len(e.values) == 0 { - delete(engines, e.addr) - } else { - // The engine reference keeps those values alive. - // The last value destroyed will clear it. - } - stats.enginesAlive(-1) - -} - -// Load loads a new component with the provided location and with the -// content read from r. The location informs the resource name for -// logged messages, and its path is used to locate any other resources -// referenced by the QML content. -// -// Once a component is loaded, component instances may be created from -// the resulting object via its Create and CreateWindow methods. -func (e *Engine) Load(location string, r io.Reader) (Object, error) { - var cdata unsafe.Pointer - var cdatalen int - - qrc := strings.HasPrefix(location, "qrc:") - if qrc { - if r != nil { - return nil, fmt.Errorf("cannot load qrc resource while providing data: %s", location) - } - } else { - data, err := ioutil.ReadAll(r) - if err != nil { - return nil, err - } - if colon, slash := strings.Index(location, ":"), strings.Index(location, "/"); colon == -1 || slash <= colon { - if filepath.IsAbs(location) { - location = "file:///" + filepath.ToSlash(location) - } else { - dir, err := os.Getwd() - if err != nil { - return nil, fmt.Errorf("cannot obtain absolute path: %v", err) - } - location = "file:///" + filepath.ToSlash(filepath.Join(dir, location)) - } - } - - // Workaround issue #84 (QTBUG-41193) by not refering to an existent file. - if s := strings.TrimPrefix(location, "file:///"); s != location { - if _, err := os.Stat(filepath.FromSlash(s)); err == nil { - location = location + "." - } - } - - cdata, cdatalen = util.UnsafeBytesData(data) - } - - var err error - cloc, cloclen := util.UnsafeStringData(location) - comp := &Common{engine: e} - RunMain(func() { - // TODO The component's parent should probably be the engine. - comp.setAddr(C.newComponent(e.addr, nilPtr)) - if qrc { - C.componentLoadURL(comp.addr, (*C.char)(cloc), C.int(cloclen)) - } else { - C.componentSetData(comp.addr, (*C.char)(cdata), C.int(cdatalen), (*C.char)(cloc), C.int(cloclen)) - } - message := C.componentErrorString(comp.addr) - if message != nilCharPtr { - err = errors.New(strings.TrimRight(C.GoString(message), "\n")) - C.free(unsafe.Pointer(message)) - } - }) - if err != nil { - return nil, err - } - return comp, nil -} - -// LoadFile loads a component from the provided QML file. -// Resources referenced by the QML content will be resolved relative to its path. -// -// Once a component is loaded, component instances may be created from -// the resulting object via its Create and CreateWindow methods. -func (e *Engine) LoadFile(path string) (Object, error) { - if strings.HasPrefix(path, "qrc:") { - return e.Load(path, nil) - } - // TODO Test this. - f, err := os.Open(path) - if err != nil { - return nil, err - } - defer f.Close() - return e.Load(path, f) -} - -// LoadString loads a component from the provided QML string. -// The location informs the resource name for logged messages, and its -// path is used to locate any other resources referenced by the QML content. -// -// Once a component is loaded, component instances may be created from -// the resulting object via its Create and CreateWindow methods. -func (e *Engine) LoadString(location, qml string) (Object, error) { - return e.Load(location, strings.NewReader(qml)) -} - -// Context returns the engine's root context. -func (e *Engine) Context() *Context { - e.assertValid() - var ctx Context - ctx.engine = e - RunMain(func() { - ctx.setAddr(C.engineRootContext(e.addr)) - }) - return &ctx -} - -func (e *Engine) ClearImportPaths() { - RunMain(func() { - C.engineClearImportPaths(e.addr) - }) -} - -func (e *Engine) AddImportPath(path string) { - cpath, cpathLen := util.UnsafeStringData(path) - RunMain(func() { - C.engineAddImportPath(e.addr, (*C.char)(cpath), C.int(cpathLen)) - }) -} - -func (e *Engine) ClearPluginPaths() { - RunMain(func() { - C.engineClearPluginPaths(e.addr) - }) -} - -func (e *Engine) AddPluginPath(path string) { - cpath, cpathLen := util.UnsafeStringData(path) - RunMain(func() { - C.engineAddPluginPath(e.addr, (*C.char)(cpath), C.int(cpathLen)) - }) -} - -func (e *Engine) ClearComponentCache() { - RunMain(func() { - C.engineClearComponentCache(e.addr) - }) -} - -// TODO ObjectOf is probably still worth it, but turned out unnecessary -// for GL functionality. Test it properly before introducing it. - -// ObjectOf returns the QML Object representation of the provided Go value -// within the e engine. -//func (e *Engine) ObjectOf(value interface{}) Object { -// // TODO Would be good to preserve identity on the Go side. See unpackDataValue as well. -// return &Common{ -// engine: e, -// addr: wrapGoValue(e, value, cppOwner), -// } -//} - -// AddImageProvider registers f to be called when an image is requested by QML code -// with the specified provider identifier. It is a runtime error to register the same -// provider identifier multiple times. -// -// The imgId provided to f is the requested image source, with the "image:" scheme -// and provider identifier removed. For example, with an image image source of -// "image://myprovider/icons/home.ext", the respective imgId would be "icons/home.ext". -// -// If either the width or the height parameters provided to f are zero, no specific -// size for the image was requested. If non-zero, the returned image should have the -// the provided size, and will be resized if the returned image has a different size. -// -// See the documentation for more details on image providers: -// -// http://qt-project.org/doc/qt-5.0/qtquick/qquickimageprovider.html -// -func (e *Engine) AddImageProvider(prvId string, f func(imgId string, width, height int) image.Image) { - if _, ok := e.imageProviders[prvId]; ok { - panic(fmt.Sprintf("engine already has an image provider with id %q", prvId)) - } - e.imageProviders[prvId] = &f - cprvId, cprvIdLen := util.UnsafeStringData(prvId) - RunMain(func() { - qprvId := C.newString((*C.char)(cprvId), C.int(cprvIdLen)) - defer C.delString(qprvId) - C.engineAddImageProvider(e.addr, qprvId, unsafe.Pointer(&f)) - }) -} - -//export hookRequestImage -func hookRequestImage(imageFunc unsafe.Pointer, cid *C.char, cidLen, cwidth, cheight C.int) unsafe.Pointer { - f := *(*func(imgId string, width, height int) image.Image)(imageFunc) - - id := util.UnsafeString(unsafe.Pointer(cid), int(cidLen)) - width := int(cwidth) - height := int(cheight) - - img := f(id, width, height) - - var cimage unsafe.Pointer - - rect := img.Bounds() - width = rect.Max.X - rect.Min.X - height = rect.Max.Y - rect.Min.Y - cimage = C.newImage(C.int(width), C.int(height)) - - var cbits []byte - cbitsh := (*reflect.SliceHeader)((unsafe.Pointer)(&cbits)) - cbitsh.Data = (uintptr)((unsafe.Pointer)(C.imageBits(cimage))) - cbitsh.Len = width * height * 4 // RGBA - cbitsh.Cap = cbitsh.Len - - i := 0 - for y := 0; y < height; y++ { - for x := 0; x < width; x++ { - r, g, b, a := img.At(x, y).RGBA() - *(*uint32)(unsafe.Pointer(&cbits[i])) = (a>>8)<<24 | (r>>8)<<16 | (g>>8)<<8 | (b >> 8) - i += 4 - } - } - return cimage -} diff --git a/qmllist.go b/qmllist.go deleted file mode 100644 index 1387a352..00000000 --- a/qmllist.go +++ /dev/null @@ -1,38 +0,0 @@ -package qml - -import ( - "fmt" - "reflect" -) - -// List holds a QML list which may be converted to a Go slice of an -// appropriate type via Convert. -// -// In the future this will also be able to hold a reference -// to QML-owned maps, so they can be mutated in place. -type List struct { - // In the future this will be able to hold a reference to QML-owned - // lists, so they can be mutated. - data []interface{} -} - -// Len returns the number of elements in the list. -func (l *List) Len() int { - return len(l.data) -} - -// Convert allocates a new slice and copies the list content into it, -// performing type conversions as possible, and then assigns the result -// to the slice pointed to by sliceAddr. -// Convert panics if the list values are not compatible with the -// provided slice. -func (l *List) Convert(sliceAddr interface{}) { - toPtr := reflect.ValueOf(sliceAddr) - if toPtr.Kind() != reflect.Ptr || toPtr.Type().Elem().Kind() != reflect.Slice { - panic(fmt.Sprintf("List.Convert got a sliceAddr parameter that is not a slice address: %#v", sliceAddr)) - } - err := convertAndSet(toPtr.Elem(), reflect.ValueOf(l), reflect.Value{}) - if err != nil { - panic(err.Error()) - } -} diff --git a/qmlmap.go b/qmlmap.go deleted file mode 100644 index 7e423c23..00000000 --- a/qmlmap.go +++ /dev/null @@ -1,35 +0,0 @@ -package qml - -import ( - "fmt" - "reflect" -) - -// Map holds a QML map which may be converted to a Go map of an -// appropriate type via Convert. -// -// In the future this will also be able to hold a reference -// to QML-owned maps, so they can be mutated in place. -type Map struct { - data []interface{} -} - -// Len returns the number of pairs in the map. -func (m *Map) Len() int { - return len(m.data) / 2 -} - -// Convert allocates a new map and copies the content of m property to it, -// performing type conversions as possible, and then assigns the result to -// the map pointed to by mapAddr. Map panics if m contains values that -// cannot be converted to the type of the map at mapAddr. -func (m *Map) Convert(mapAddr interface{}) { - toPtr := reflect.ValueOf(mapAddr) - if toPtr.Kind() != reflect.Ptr || toPtr.Type().Elem().Kind() != reflect.Map { - panic(fmt.Sprintf("Map.Convert got a mapAddr parameter that is not a map address: %#v", mapAddr)) - } - err := convertAndSet(toPtr.Elem(), reflect.ValueOf(m), reflect.Value{}) - if err != nil { - panic(err.Error()) - } -} diff --git a/qmlobject.go b/qmlobject.go deleted file mode 100644 index 45e10c92..00000000 --- a/qmlobject.go +++ /dev/null @@ -1,31 +0,0 @@ -package qml - -import "image/color" - -// Object is the common interface implemented by all QML types. -// -// See the documentation of Common for details about this interface. -type Object interface { - Common() *Common - Addr() uintptr - TypeName() string - Interface() interface{} - Set(property string, value interface{}) - Property(name string) interface{} - Int(property string) int - Int64(property string) int64 - Float64(property string) float64 - Bool(property string) bool - String(property string) string - Color(property string) color.RGBA - Object(property string) Object - Map(property string) *Map - List(property string) *List - ObjectByName(objectName string) Object - Call(method string, params ...interface{}) interface{} - Create(ctx *Context) Object - CreateWindow(ctx *Context) *Window - Destroy() - On(signal string, function interface{}) - Clear() -} diff --git a/qmltypes.go b/qmltypes.go deleted file mode 100644 index 1ae9972a..00000000 --- a/qmltypes.go +++ /dev/null @@ -1,135 +0,0 @@ -package qml - -// #include -// -// #include "capi.h" -// -import "C" - -import ( - "fmt" - "reflect" - "unsafe" -) - -// TypeSpec holds the specification of a QML type that is backed by Go logic. -// -// The type specification must be registered with the RegisterTypes function -// before it will be visible to QML code, as in: -// -// qml.RegisterTypes("GoExtensions", 1, 0, []qml.TypeSpec{{ -// Init: func(p *Person, obj qml.Object) {}, -// }}) -// -// See the package documentation for more details. -// -type TypeSpec struct { - // Init must be set to a function that is called when QML code requests - // the creation of a new value of this type. The provided function must - // have the following type: - // - // func(value *CustomType, object qml.Object) - // - // Where CustomType is the custom type being registered. The function will - // be called with a newly created *CustomType and its respective qml.Object. - Init interface{} - - // Name optionally holds the identifier the type is known as within QML code, - // when the registered extension module is imported. If not specified, the - // name of the Go type provided as the first argument of Init is used instead. - Name string - - // Singleton defines whether a single instance of the type should be used - // for all accesses, as a singleton value. If true, all properties of the - // singleton value are directly accessible under the type name. - Singleton bool - - private struct{} // Force use of fields by name. -} - -var types []*TypeSpec - -// RegisterTypes registers the provided list of type specifications for use -// by QML code. To access the registered types, they must be imported from the -// provided location and major.minor version numbers. -// -// For example, with a location "GoExtensions", major 4, and minor 2, this statement -// imports all the registered types in the module's namespace: -// -// import GoExtensions 4.2 -// -// See the documentation on QML import statements for details on these: -// -// http://qt-project.org/doc/qt-5.0/qtqml/qtqml-syntax-imports.html -// -func RegisterTypes(location string, major, minor int, types []TypeSpec) { - for i := range types { - err := registerType(location, major, minor, &types[i]) - if err != nil { - panic(err) - } - } -} - -func registerType(location string, major, minor int, spec *TypeSpec) error { - // Copy and hold a reference to the spec data. - localSpec := *spec - - f := reflect.ValueOf(localSpec.Init) - ft := f.Type() - if ft.Kind() != reflect.Func { - return fmt.Errorf("TypeSpec.Init must be a function, got %#v", localSpec.Init) - } - if ft.NumIn() != 2 { - return fmt.Errorf("TypeSpec.Init's function must accept two arguments: %s", ft) - } - firstArg := ft.In(0) - if firstArg.Kind() != reflect.Ptr || firstArg.Elem().Kind() == reflect.Ptr { - return fmt.Errorf("TypeSpec.Init's function must take a pointer type as the second argument: %s", ft) - } - if ft.In(1) != typeObject { - return fmt.Errorf("TypeSpec.Init's function must take qml.Object as the second argument: %s", ft) - } - customType := typeInfo(reflect.New(firstArg.Elem()).Interface()) - if localSpec.Name == "" { - localSpec.Name = firstArg.Elem().Name() - if localSpec.Name == "" { - panic("cannot determine registered type name; please provide one explicitly") - } - } - - var err error - RunMain(func() { - cloc := C.CString(location) - cname := C.CString(localSpec.Name) - cres := C.int(0) - if localSpec.Singleton { - cres = C.registerSingleton(cloc, C.int(major), C.int(minor), cname, customType, unsafe.Pointer(&localSpec)) - } else { - cres = C.registerType(cloc, C.int(major), C.int(minor), cname, customType, unsafe.Pointer(&localSpec)) - } - // It doesn't look like it keeps references to these, but it's undocumented and unclear. - C.free(unsafe.Pointer(cloc)) - C.free(unsafe.Pointer(cname)) - if cres == -1 { - err = fmt.Errorf("QML engine failed to register type; invalid type location or name?") - } else { - types = append(types, &localSpec) - } - }) - - return err -} - -// RegisterConverter registers the convereter function to be called when a -// value with the provided type name is obtained from QML logic. The function -// must return the new value to be used in place of the original value. -func RegisterConverter(typeName string, converter func(engine *Engine, obj Object) interface{}) { - if converter == nil { - delete(converters, typeName) - } else { - converters[typeName] = converter - } -} - -var converters = make(map[string]func(engine *Engine, obj Object) interface{}) diff --git a/qmlwindow.go b/qmlwindow.go deleted file mode 100644 index c53fce2f..00000000 --- a/qmlwindow.go +++ /dev/null @@ -1,115 +0,0 @@ -package qml - -// #include -// -// #include "capi.h" -// -import "C" - -import ( - "image" - "reflect" - "sync" - "unsafe" -) - -// Window represents a QML window where components are rendered. -type Window struct { - Common -} - -// Show exposes the window. -func (win *Window) Show() { - RunMain(func() { - C.windowShow(win.addr) - }) -} - -// Hide hides the window. -func (win *Window) Hide() { - RunMain(func() { - C.windowHide(win.addr) - }) -} - -// PlatformId returns the window's platform id. -// -// For platforms where this id might be useful, the value returned will -// uniquely represent the window inside the corresponding screen. -func (win *Window) PlatformId() uintptr { - var id uintptr - RunMain(func() { - id = uintptr(C.windowPlatformId(win.addr)) - }) - return id -} - -// Root returns the root object being rendered. -// -// If the window was defined in QML code, the root object is the window itself. -func (win *Window) Root() Object { - var obj Common - obj.engine = win.engine - RunMain(func() { - obj.setAddr(C.windowRootObject(win.addr)) - }) - return &obj -} - -// Wait blocks the current goroutine until the window is closed. -func (win *Window) Wait() { - // XXX Test this. - var m sync.Mutex - m.Lock() - RunMain(func() { - // TODO Must be able to wait for the same Window from multiple goroutines. - // TODO If the window is not visible, must return immediately. - waitingWindows[win.addr] = &m - C.windowConnectHidden(win.addr) - }) - m.Lock() -} - -var waitingWindows = make(map[unsafe.Pointer]*sync.Mutex) - -//export hookWindowHidden -func hookWindowHidden(addr unsafe.Pointer) { - m, ok := waitingWindows[addr] - if !ok { - panic("window is not waiting") - } - delete(waitingWindows, addr) - m.Unlock() -} - -// Snapshot returns an image with the visible contents of the window. -// The main GUI thread is paused while the data is being acquired. -func (win *Window) Snapshot() image.Image { - // TODO Test this. - var cimage unsafe.Pointer - RunMain(func() { - cimage = C.windowGrabWindow(win.addr) - }) - defer C.delImage(cimage) - - // This should be safe to be done out of the main GUI thread. - var cwidth, cheight C.int - C.imageSize(cimage, &cwidth, &cheight) - - var cbits []byte - cbitsh := (*reflect.SliceHeader)((unsafe.Pointer)(&cbits)) - cbitsh.Data = (uintptr)((unsafe.Pointer)(C.imageConstBits(cimage))) - cbitsh.Len = int(cwidth * cheight * 8) // ARGB - cbitsh.Cap = cbitsh.Len - - image := image.NewRGBA(image.Rect(0, 0, int(cwidth), int(cheight))) - l := int(cwidth * cheight * 4) - for i := 0; i < l; i += 4 { - var c uint32 = *(*uint32)(unsafe.Pointer(&cbits[i])) - image.Pix[i+0] = byte(c >> 16) - image.Pix[i+1] = byte(c >> 8) - image.Pix[i+2] = byte(c) - image.Pix[i+3] = byte(c >> 24) - } - return image -}