new listmodel syntax. Also added code gen support to list models

This commit is contained in:
Roland Singer 2019-01-24 15:36:14 +01:00
parent b78c4fc6b7
commit f5ca35ce27
9 changed files with 145 additions and 58 deletions

View File

@ -89,6 +89,7 @@ func init() {
func (_v *{{$struct.Name}}) GmlInit() {
goPtr := pointer.Save(_v)
_v.GmlObject_SetGoPointer(goPtr)
_v.GmlObject_SetPointer(unsafe.Pointer(C.{{$struct.CBaseName}}_new(goPtr)))
runtime.SetFinalizer(_v, func(_v *{{$struct.Name}}) {
C.{{$struct.CBaseName}}_free((C.{{$struct.CBaseName}})(_v.GmlObject_Pointer()))

View File

@ -50,6 +50,10 @@ func init() {
C.gml_list_model_init()
}
type listModelInitializer interface {
initListModel(handler ListModelHandler)
}
type ListModelHandler interface {
RowCount() int
Data(row int) interface{}
@ -58,75 +62,86 @@ type ListModelHandler interface {
type ListModel struct {
Object
freed bool
lm C.gml_list_model
ptr unsafe.Pointer
ptr C.gml_list_model
handler ListModelHandler
}
func NewListModel(handler ListModelHandler) *ListModel {
lm := &ListModel{handler: handler}
func InitListModel(m interface{}) {
lmi, ok := m.(listModelInitializer)
if !ok {
panic(fmt.Errorf("failed to assert to list model"))
}
lm.ptr = pointer.Save(lm)
lm.lm = C.gml_list_model_new(lm.ptr)
lm.GmlObject_SetPointer(unsafe.Pointer(lm.lm))
handler, ok := m.(ListModelHandler)
if !ok {
panic(fmt.Errorf("failed to assert to list model handler"))
}
// Always free the C++ value.
runtime.SetFinalizer(lm, freeListModel)
lmi.initListModel(handler)
}
func (lm *ListModel) initListModel(handler ListModelHandler) {
lm.handler = handler
// If signals, slots or properties are defined on the model handler,
// then use the generated C++ type by calling GmlInit...
// Otherwise this is a standalone ListModel.
switch ht := lm.handler.(type) {
case objectInitializer:
ht.GmlInit()
lm.ptr = (C.gml_list_model)(lm.GmlObject_Pointer())
default:
handlerGoPtr := pointer.Save(lm.handler)
lm.GmlObject_SetGoPointer(handlerGoPtr)
lm.ptr = C.gml_list_model_new(handlerGoPtr)
lm.GmlObject_SetPointer(unsafe.Pointer(lm.ptr))
// Always cleanup.
runtime.SetFinalizer(lm, func(lm *ListModel) {
C.gml_list_model_free(lm.ptr)
pointer.Unref(handlerGoPtr)
})
}
// Check if something failed.
// This should never happen is signalizes a fatal error.
if lm.lm == nil {
// This should never happen. It signalizes a fatal error.
if lm.ptr == nil {
panic(fmt.Errorf("failed to create gml list model: C pointer is nil"))
}
return lm
}
func (lm *ListModel) Free() {
freeListModel(lm)
}
func freeListModel(lm *ListModel) {
if lm.freed {
return
}
lm.freed = true
C.gml_list_model_free(lm.lm)
pointer.Unref(lm.ptr)
}
func (lm *ListModel) Reset(dataModifier func()) {
RunMain(func() {
// Begin the reset operation.
C.gml_list_model_begin_reset_model(lm.lm)
C.gml_list_model_begin_reset_model(lm.ptr)
// Perform the data modifications.
dataModifier()
// End the reset operation.
C.gml_list_model_end_reset_model(lm.lm)
C.gml_list_model_end_reset_model(lm.ptr)
})
}
func (lm *ListModel) Insert(row, count int, dataModifier func()) {
RunMain(func() {
// Begin the insert operation.
C.gml_list_model_begin_insert_rows(lm.lm, C.int(row), C.int(count))
C.gml_list_model_begin_insert_rows(lm.ptr, C.int(row), C.int(count))
// Perform the data modification.
dataModifier()
// End the insert operation.
C.gml_list_model_end_insert_rows(lm.lm)
C.gml_list_model_end_insert_rows(lm.ptr)
})
}
func (lm *ListModel) Move(row, count, dstRow int, dataModifier func()) {
RunMain(func() {
// Begin the move operation.
C.gml_list_model_begin_move_rows(lm.lm, C.int(row), C.int(count), C.int(dstRow))
C.gml_list_model_begin_move_rows(lm.ptr, C.int(row), C.int(count), C.int(dstRow))
// Perform the data modification.
dataModifier()
// End the move operation.
C.gml_list_model_end_move_rows(lm.lm)
C.gml_list_model_end_move_rows(lm.ptr)
})
}
@ -135,18 +150,18 @@ func (lm *ListModel) Reload(row, count int, dataModifier func()) {
// Perform the data modification.
dataModifier()
// Signal the changed operation.
C.gml_list_model_rows_data_changed(lm.lm, C.int(row), C.int(count))
C.gml_list_model_rows_data_changed(lm.ptr, C.int(row), C.int(count))
})
}
func (lm *ListModel) Remove(row, count int, dataModifier func()) {
RunMain(func() {
// Begin the remove operation.
C.gml_list_model_begin_remove_rows(lm.lm, C.int(row), C.int(count))
C.gml_list_model_begin_remove_rows(lm.ptr, C.int(row), C.int(count))
// Perform the data modification.
dataModifier()
// End the remove operation.
C.gml_list_model_end_remove_rows(lm.lm)
C.gml_list_model_end_remove_rows(lm.ptr)
})
}
@ -156,12 +171,12 @@ func (lm *ListModel) Remove(row, count int, dataModifier func()) {
//export gml_list_model_row_count_go_slot
func gml_list_model_row_count_go_slot(goPtr unsafe.Pointer) C.int {
return C.int((pointer.Restore(goPtr)).(*ListModel).handler.RowCount())
return C.int((pointer.Restore(goPtr)).(ListModelHandler).RowCount())
}
//export gml_list_model_data_go_slot
func gml_list_model_data_go_slot(goPtr unsafe.Pointer, row C.int) C.gml_variant {
data := (pointer.Restore(goPtr)).(*ListModel).handler.Data(int(row))
data := (pointer.Restore(goPtr)).(ListModelHandler).Data(int(row))
v := ToVariant(data)
// Release, because C++ is handling memory.

View File

@ -35,12 +35,17 @@ import (
"unsafe"
)
type objectInitializer interface {
GmlInit()
}
type objectGetter interface {
GmlObject() *Object
}
type Object struct {
ptr unsafe.Pointer
ptr unsafe.Pointer
goPtr unsafe.Pointer
}
func (o *Object) GmlObject_Pointer() unsafe.Pointer {
@ -54,6 +59,17 @@ func (o *Object) GmlObject_SetPointer(ptr unsafe.Pointer) {
o.ptr = ptr
}
func (o *Object) GmlObject_GoPointer() unsafe.Pointer {
if o.goPtr == nil {
panic(fmt.Errorf("gml.Object go pointer is nil: did you call GmlInit()?"))
}
return o.goPtr
}
func (o *Object) GmlObject_SetGoPointer(goPtr unsafe.Pointer) {
o.goPtr = goPtr
}
func (o *Object) GmlObject() *Object {
return o
}

View File

@ -29,7 +29,6 @@ package main
import (
"github.com/desertbit/gml"
_ "github.com/desertbit/gml/samples/hello_world/model"
)
func main() {

View File

@ -15,14 +15,4 @@ ApplicationWindow {
font.pointSize: 24
font.bold: true
}
ListView {
anchors.fill: parent
delegate: Text {
color: "red"
text: display
}
model: m
Component.onCompleted: console.log(m.get(5))
}
}

5
samples/list_model/.gitignore vendored Normal file
View File

@ -0,0 +1,5 @@
/build
/list_model
gml_gen*
*.qrc

View File

@ -0,0 +1,36 @@
/*
* GML - Go QML
*
* The MIT License (MIT)
*
* Copyright (c) 2019 Roland Singer <roland.singer[at]desertbit.com>
* Copyright (c) 2019 Sebastian Borchers <sebastian[at]desertbit.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package main
import (
"github.com/desertbit/gml"
)
func main() {
gml.ExecExit("qrc:/qml/app.qml")
}

View File

@ -25,19 +25,23 @@
* SOFTWARE.
*/
package model
package main
import (
"log"
"strconv"
"github.com/desertbit/gml"
"github.com/rs/zerolog/log"
)
//#############//
//### Slots ###//
//#############//
var M *model
type model struct {
*gml.ListModel
gml.ListModel
_ struct {
get func(row int) string `gml:"slot"`
@ -54,12 +58,11 @@ func (m *model) Data(row int) interface{} {
func init() {
M = &model{}
M.ListModel = gml.NewListModel(M)
M.GmlInit()
gml.InitListModel(M)
err := gml.SetContextProperty("m", M)
if err != nil {
log.Fatal().Err(err).Msg("init")
log.Fatalln("failed to set model context property")
}
}
@ -68,5 +71,5 @@ func init() {
//#############//
func (m *model) get(row int) string {
return "this is a test, lol"
return "slot get called"
}

View File

@ -0,0 +1,22 @@
import QtQuick 2.11
import QtQuick.Layouts 1.3
import QtQuick.Controls 2.4
ApplicationWindow {
id: window
width: 300
height: 300
visible: true
ListView {
anchors.fill: parent
delegate: Text {
color: "red"
text: display
font.pointSize: 24
font.bold: true
}
model: m
Component.onCompleted: console.log(m.get(5))
}
}