-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathquickviewimpl.go
142 lines (123 loc) · 3.37 KB
/
quickviewimpl.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
//go:build impl
package faithtop
import (
"encoding/json"
"fmt"
"github.com/therecipe/qt/core"
"github.com/therecipe/qt/quick"
"github.com/therecipe/qt/widgets"
"path/filepath"
"reflect"
"runtime"
"strconv"
"strings"
)
type (
QuickViewImpl struct {
*WidgetImpl
quickView *quick.QQuickView
bridge *QuickBridge
}
QuickBridge struct {
quick.QQuickItem
_ func() `constructor:"init"`
_ func(funcName string, args []string) `signal:"callGo,auto"`
_ func(funcName string, args []string) `signal:"callQml"`
handlers map[string]reflect.Value
}
)
func init() {
newQuickViewImpl = func(win IWindow) IQuickView {
if win == nil {
panic("the parent window cannot be nil")
}
v := &QuickViewImpl{
quickView: quick.NewQQuickView(nil),
bridge: NewQuickBridge(nil),
}
var widget *widgets.QWidget
widget = widget.CreateWindowContainer(v.quickView, win.(*WindowImpl).window, 0)
v.WidgetImpl = widgetImplFrom(widget)
v.quickView.RootContext().SetContextProperty("bridge", v.bridge)
return v
}
QuickBridge_QmlRegisterType2("QuickBridge", 1, 0, "QuickBridge")
}
func (b *QuickBridge) init() {
b.handlers = make(map[string]reflect.Value)
}
func (b *QuickBridge) callGo(funcName string, args []string) {
if b.handlers == nil {
return
}
if handler, ok := b.handlers[funcName]; ok {
t := handler.Type()
if t.NumIn() > len(args) {
panic("not enough arguments to call Go function: [" + funcName + "], have " + strconv.Itoa(len(args)) + " but want " + strconv.Itoa(t.NumIn()))
}
arguments := []reflect.Value{}
for i := 0; i < t.NumIn(); i++ {
argument, e := convertToGoType(args[i], t.In(i))
if e != nil {
panic(fmt.Errorf("error when calling Go function [%s]: %w", funcName, e))
}
arguments = append(arguments, argument)
}
handler.Call(arguments)
} else {
panic("funcName [" + funcName + "] is not registered on QuickView")
}
}
func convertToGoType(s string, target reflect.Type) (reflect.Value, error) {
switch target.Kind() {
case reflect.String:
return reflect.ValueOf(s), nil
default:
value := reflect.New(target)
e := json.Unmarshal([]byte(s), value.Interface())
if e != nil {
return value, e
}
return value.Elem(), nil
}
}
func convertToQmlArgument(arg interface{}) string {
if v, ok := arg.(string); ok {
return v
}
b, _ := json.Marshal(arg)
return string(b)
}
func (q *QuickViewImpl) Assign(v *IQuickView) IQuickView {
*v = q
return q
}
func (q *QuickViewImpl) Source(qmlFile string) IQuickView {
q.quickView.SetSource(core.NewQUrl3(qmlFile, 0))
return q
}
func (q *QuickViewImpl) Call(funcName string, args ...interface{}) {
strs := []string{}
for _, arg := range args {
strs = append(strs, convertToQmlArgument(arg))
}
q.bridge.CallQml(funcName, strs)
}
func (q *QuickViewImpl) BindFunction(fn interface{}) IQuickView {
funcName := getFunctionName(fn)
t := reflect.TypeOf(fn)
if t.Kind() != reflect.Func {
panic("BindFunction: the input value is not a function, but [" + t.Kind().String() + "]")
}
if _, ok := q.bridge.handlers[funcName]; ok {
panic("BindFunction: function with '" + funcName + "' duplicated")
}
q.bridge.handlers[funcName] = reflect.ValueOf(fn)
return q
}
func getFunctionName(v interface{}) string {
t := reflect.ValueOf(v)
fn := runtime.FuncForPC(t.Pointer()).Name()
n := strings.TrimPrefix(filepath.Ext(fn), ".")
return n
}