diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 20ee828..9478b9b 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -10,12 +10,10 @@ jobs: - uses: actions/setup-go@v4 with: go-version: '1.25' - - uses: jurplel/install-qt-action@v4 - run: | sudo apt-get update - sudo apt-get -y install build-essential libglu1-mesa-dev libpulse-dev libglib2.0-dev - go get -v github.com/therecipe/qt && go install -v -tags=no_env github.com/therecipe/qt/cmd/... && go mod vendor && rm -rf vendor/github.com/therecipe/env_linux_amd64_513 && git clone https://github.com/therecipe/env_linux_amd64_513.git vendor/github.com/therecipe/env_linux_amd64_513 && $(go env GOPATH)/bin/qtsetup - - run: qtdeploy build desktop + sudo apt-get -y install build-essential libglu1-mesa-dev libpulse-dev libglib2.0-dev pkg-config qtbase5-dev + - run: go build -ldflags '-s -w' build-windows: runs-on: windows-latest steps: @@ -27,12 +25,11 @@ jobs: with: msystem: MINGW64 update: true - install: mingw-w64-x86_64-qt-creator mingw-w64-x86_64-qt5-static + install: mingw-w64-x86_64-qt5-static - shell: msys2 {0} run: | - export QT_MSYS2=true - export QT_MSYS2_ARCH=amd64 - export QT_MSYS2_STATIC=true - git clone https://github.com/therecipe/examples.git && cd ./examples && go install -v -tags=no_env github.com/therecipe/qt/cmd/... && go mod vendor && git clone https://github.com/therecipe/env_windows_amd64_513.git vendor/github.com/therecipe/env_windows_amd64_513 && for /f %v in ('go env GOPATH') do %v\bin\qtdeploy test desktop ./basic/widgets - - shell: msys2 {0} - run: qtdeploy build desktop + export PKG_CONFIG_PATH=/ucrt64/qt5-static/lib/pkgconfig + export CGO_LDFLAGS='-LC:/msys64/ucrt64/qt5-static/share/qt5/plugins/platforms -lqwindows -lQt5FontDatabaseSupport -lQt5EventDispatcherSupport -lQt5ThemeSupport -lQt5PlatformCompositorSupport -lQt5AccessibilitySupport -lQt5WindowsUIAutomationSupport -lwtsapi32 -LC:/msys64/ucrt64/qt5-static/share/qt5/plugins/styles -lqwindowsvistastyle -lQt5VulkanSupport -lqtfreetype -static -static-libgcc -static-libstdc++' + cp -vn /ucrt64/lib/libzstd.a /ucrt64/qt5-static/lib/libzstd + cp -vn /ucrt64/lib/libz.a /ucrt64/qt5-static/lib/libz + go build -ldflags "-s -w -H windowsgui" --tags=windowsqtstatic diff --git a/.gitignore b/.gitignore index 4966360..7a83d52 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,5 @@ dist -view +vnak *.json deploy qtbox diff --git a/event.go b/event.go index ceea758..0a05d98 100644 --- a/event.go +++ b/event.go @@ -6,17 +6,138 @@ import ( "strings" "fiatjaf.com/nostr" - "github.com/therecipe/qt/core" - "github.com/therecipe/qt/widgets" + qt "github.com/mappu/miqt/qt6" ) var event struct { - kindSpin *widgets.QSpinBox - kindNameLabel *widgets.QLabel - tagRows [][]*widgets.QLineEdit - contentEdit *widgets.QTextEdit - createdAtEdit *widgets.QDateTimeEdit - outputEdit *widgets.QTextEdit + kindSpin *qt.QSpinBox + kindNameLabel *qt.QLabel + tagRows [][]*qt.QLineEdit + contentEdit *qt.QTextEdit + createdAtEdit *qt.QDateTimeEdit + outputEdit *qt.QTextEdit +} + +func setupEventTab() *qt.QWidget { + tab := qt.NewQWidget(window.QWidget) + + // set up event tab + layout := qt.NewQVBoxLayout2() + tab.SetLayout(layout.QLayout) + + // kind input + kindHBox := qt.NewQHBoxLayout2() + layout.AddLayout(kindHBox.QLayout) + kindLabel := qt.NewQLabel2() + kindLabel.SetText("kind:") + kindHBox.AddWidget(kindLabel.QWidget) + event.kindSpin = qt.NewQSpinBox(tab) + event.kindSpin.SetValue(1) + event.kindSpin.SetMinimum(0) + event.kindSpin.SetMaximum(1<<16 - 1) + kindHBox.AddWidget(event.kindSpin.QWidget) + event.kindSpin.OnValueChanged(func(int) { + updateEvent() + }) + event.kindNameLabel = qt.NewQLabel2() + kindHBox.AddWidget(event.kindNameLabel.QWidget) + + // content input + contentLabel := qt.NewQLabel2() + contentLabel.SetText("content:") + layout.AddWidget(contentLabel.QWidget) + event.contentEdit = qt.NewQTextEdit(tab) + layout.AddWidget(event.contentEdit.QWidget) + event.contentEdit.OnTextChanged(updateEvent) + + // created_at input + createdAtLabel := qt.NewQLabel2() + createdAtLabel.SetText("created at:") + layout.AddWidget(createdAtLabel.QWidget) + event.createdAtEdit = qt.NewQDateTimeEdit(tab) + event.createdAtEdit.SetDateTime(qt.QDateTime_CurrentDateTime()) + layout.AddWidget(event.createdAtEdit.QWidget) + event.createdAtEdit.OnDateTimeChanged(func(*qt.QDateTime) { + updateEvent() + }) + + // tags input + tagsLabel := qt.NewQLabel2() + tagsLabel.SetText("tags:") + layout.AddWidget(tagsLabel.QWidget) + tagsLayout := qt.NewQVBoxLayout2() + tagRowHBoxes := make([]*qt.QHBoxLayout, 0, 2) + event.tagRows = make([][]*qt.QLineEdit, 0, 2) + layout.AddLayout(tagsLayout.QLayout) + + var addTagRow func() + addTagRow = func() { + hbox := qt.NewQHBoxLayout2() + tagRowHBoxes = append(tagRowHBoxes, hbox) + tagsLayout.AddLayout(hbox.QLayout) + tagItems := []*qt.QLineEdit{} + y := len(event.tagRows) + event.tagRows = append(event.tagRows, tagItems) + + var addItem func() + addItem = func() { + edit := qt.NewQLineEdit(tab) + hbox.AddWidget(edit.QWidget) + x := len(tagItems) + tagItems = append(tagItems, edit) + event.tagRows[y] = tagItems + edit.OnTextChanged(func(text string) { + if strings.TrimSpace(text) != "" { + // when an item input has been filled check if we have to show more + if y == len(event.tagRows)-1 { + addTagRow() + } + if x == len(tagItems)-1 { + addItem() + } + } else { + // do this when an item input has been emptied: check if we need to remove an item from this row + nItems := len(tagItems) + if nItems >= 2 && strings.TrimSpace(tagItems[nItems-1].Text()) == "" && strings.TrimSpace(tagItems[nItems-2].Text()) == "" { + // remove last item if the last 2 are empty + hbox.RemoveWidget(tagItems[nItems-1].QWidget) + tagItems[nItems-1].DeleteLater() + tagItems = tagItems[0 : nItems-1] + event.tagRows[y] = tagItems + } + + // check if we need to remove rows + nRows := len(event.tagRows) + itemIsFilled := func(edit *qt.QLineEdit) bool { return strings.TrimSpace(edit.Text()) != "" } + if nRows >= 2 && !slices.ContainsFunc(event.tagRows[nRows-1], itemIsFilled) && !slices.ContainsFunc(event.tagRows[nRows-2], itemIsFilled) { + // remove the last row if the last 2 are empty + tagsLayout.RemoveItem(tagRowHBoxes[nRows-1].QLayoutItem) + for _, tagItem := range event.tagRows[nRows-1] { + tagItem.DeleteLater() + } + tagRowHBoxes[nRows-1].DeleteLater() + event.tagRows = event.tagRows[0 : nRows-1] + tagRowHBoxes = tagRowHBoxes[0 : nRows-1] + } + } + updateEvent() + }) + } + addItem() + } + + // first + addTagRow() + + // output JSON + outputLabel := qt.NewQLabel2() + outputLabel.SetText("event:") + layout.AddWidget(outputLabel.QWidget) + event.outputEdit = qt.NewQTextEdit(tab) + event.outputEdit.SetReadOnly(true) + layout.AddWidget(event.outputEdit.QWidget) + + return tab } func updateEvent() { @@ -82,120 +203,3 @@ func updateEvent() { finalize() } - -func setupEventTab() *widgets.QWidget { - tab := widgets.NewQWidget(nil, 0) - - // set up event tab - layout := widgets.NewQVBoxLayout() - tab.SetLayout(layout) - - // kind input - kindHBox := widgets.NewQHBoxLayout() - layout.AddLayout(kindHBox, 0) - kindLabel := widgets.NewQLabel2("kind:", nil, 0) - kindHBox.AddWidget(kindLabel, 0, 0) - event.kindSpin = widgets.NewQSpinBox(nil) - event.kindSpin.SetValue(1) - event.kindSpin.SetMinimum(0) - event.kindSpin.SetMaximum(1<<16 - 1) - kindHBox.AddWidget(event.kindSpin, 0, 0) - event.kindSpin.ConnectValueChanged(func(int) { - updateEvent() - }) - event.kindNameLabel = widgets.NewQLabel2("", nil, 0) - kindHBox.AddWidget(event.kindNameLabel, 0, 0) - - // content input - contentLabel := widgets.NewQLabel2("content:", nil, 0) - layout.AddWidget(contentLabel, 0, 0) - event.contentEdit = widgets.NewQTextEdit(nil) - layout.AddWidget(event.contentEdit, 0, 0) - event.contentEdit.ConnectTextChanged(updateEvent) - - // created_at input - createdAtLabel := widgets.NewQLabel2("created at:", nil, 0) - layout.AddWidget(createdAtLabel, 0, 0) - event.createdAtEdit = widgets.NewQDateTimeEdit(nil) - event.createdAtEdit.SetDateTime(core.QDateTime_CurrentDateTime()) - layout.AddWidget(event.createdAtEdit, 0, 0) - event.createdAtEdit.ConnectDateTimeChanged(func(*core.QDateTime) { - updateEvent() - }) - - // tags input - tagsLabel := widgets.NewQLabel2("tags:", nil, 0) - layout.AddWidget(tagsLabel, 0, 0) - tagsLayout := widgets.NewQVBoxLayout() - tagRowHBoxes := make([]widgets.QLayout_ITF, 0, 2) - event.tagRows = make([][]*widgets.QLineEdit, 0, 2) - layout.AddLayout(tagsLayout, 0) - - var addTagRow func() - addTagRow = func() { - hbox := widgets.NewQHBoxLayout() - tagRowHBoxes = append(tagRowHBoxes, hbox) - tagsLayout.AddLayout(hbox, 0) - tagItems := []*widgets.QLineEdit{} - y := len(event.tagRows) - event.tagRows = append(event.tagRows, tagItems) - - var addItem func() - addItem = func() { - edit := widgets.NewQLineEdit(nil) - hbox.AddWidget(edit, 0, 0) - x := len(tagItems) - tagItems = append(tagItems, edit) - event.tagRows[y] = tagItems - edit.ConnectTextChanged(func(text string) { - if strings.TrimSpace(text) != "" { - // when an item input has been filled check if we have to show more - if y == len(event.tagRows)-1 { - addTagRow() - } - if x == len(tagItems)-1 { - addItem() - } - } else { - // do this when an item input has been emptied: check if we need to remove an item from this row - nItems := len(tagItems) - if nItems >= 2 && strings.TrimSpace(tagItems[nItems-1].Text()) == "" && strings.TrimSpace(tagItems[nItems-2].Text()) == "" { - // remove last item if the last 2 are empty - hbox.Layout().RemoveWidget(tagItems[nItems-1]) - tagItems[nItems-1].DeleteLater() - tagItems = tagItems[0 : nItems-1] - event.tagRows[y] = tagItems - } - - // check if we need to remove rows - nRows := len(event.tagRows) - itemIsFilled := func(edit *widgets.QLineEdit) bool { return strings.TrimSpace(edit.Text()) != "" } - if nRows >= 2 && !slices.ContainsFunc(event.tagRows[nRows-1], itemIsFilled) && !slices.ContainsFunc(event.tagRows[nRows-2], itemIsFilled) { - // remove the last row if the last 2 are empty - tagsLayout.RemoveItem(tagRowHBoxes[nRows-1]) - for _, tagItem := range event.tagRows[nRows-1] { - tagItem.DeleteLater() - } - tagRowHBoxes[nRows-1].QLayout_PTR().DeleteLater() - event.tagRows = event.tagRows[0 : nRows-1] - tagRowHBoxes = tagRowHBoxes[0 : nRows-1] - } - } - updateEvent() - }) - } - addItem() - } - - // first - addTagRow() - - // output JSON - outputLabel := widgets.NewQLabel2("event:", nil, 0) - layout.AddWidget(outputLabel, 0, 0) - event.outputEdit = widgets.NewQTextEdit(nil) - event.outputEdit.SetReadOnly(true) - layout.AddWidget(event.outputEdit, 0, 0) - - return tab -} diff --git a/go.mod b/go.mod index f231536..ebd3b44 100644 --- a/go.mod +++ b/go.mod @@ -5,7 +5,8 @@ go 1.25.4 require ( fiatjaf.com/lib v0.3.2 fiatjaf.com/nostr v0.0.0-20251126120447-7261a4b515ed - github.com/therecipe/qt v0.0.0-20200904063919-c0c124a5770d + github.com/itchyny/gojq v0.12.17 + github.com/mappu/miqt v0.12.0 ) require ( @@ -23,7 +24,7 @@ require ( github.com/dustin/go-humanize v1.0.1 // indirect github.com/elnosh/gonuts v0.4.2 // indirect github.com/fxamacker/cbor/v2 v2.7.0 // indirect - github.com/gopherjs/gopherjs v0.0.0-20190411002643-bd77b112433e // indirect + github.com/itchyny/timefmt-go v0.1.6 // indirect github.com/josharian/intern v1.0.0 // indirect github.com/json-iterator/go v1.1.12 // indirect github.com/mailru/easyjson v0.9.0 // indirect diff --git a/go.sum b/go.sum index 3a96eb6..61ec00d 100644 --- a/go.sum +++ b/go.sum @@ -81,10 +81,12 @@ github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMyw github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= -github.com/gopherjs/gopherjs v0.0.0-20190411002643-bd77b112433e h1:XWcjeEtTFTOVA9Fs1w7n2XBftk5ib4oZrhzWk0B+3eA= -github.com/gopherjs/gopherjs v0.0.0-20190411002643-bd77b112433e/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= +github.com/itchyny/gojq v0.12.17 h1:8av8eGduDb5+rvEdaOO+zQUjA04MS0m3Ps8HiD+fceg= +github.com/itchyny/gojq v0.12.17/go.mod h1:WBrEMkgAfAGO1LUcGOckBl5O726KPp+OlkKug0I/FEY= +github.com/itchyny/timefmt-go v0.1.6 h1:ia3s54iciXDdzWzwaVKXZPbiXzxxnv1SPGFfM/myJ5Q= +github.com/itchyny/timefmt-go v0.1.6/go.mod h1:RRDZYC5s9ErkjQvTvvU7keJjxUYzIISJGxm9/mAERQg= github.com/jessevdk/go-flags v0.0.0-20141203071132-1679536dcc89/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= @@ -95,10 +97,10 @@ github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHm github.com/kkdai/bstream v0.0.0-20161212061736-f391b8402d23/go.mod h1:J+Gs4SYgM6CZQHDETBtE9HaSEkGmuNXF86RwHhHUvq4= github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo= github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ= -github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= -github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/mailru/easyjson v0.9.0 h1:PrnmzHw7262yW8sTBwxi1PdJA3Iw/EKBa8psRf7d9a4= github.com/mailru/easyjson v0.9.0/go.mod h1:1+xMtQp2MRNVL/V1bOzuP3aP8VNwRW55fQUto+XFtTU= +github.com/mappu/miqt v0.12.0 h1:bBMBDeACmV8TbdLfoN51la7kF6QT3sNAcG+ZdRDgmxU= +github.com/mappu/miqt v0.12.0/go.mod h1:xFg7ADaO1QSkmXPsPODoKe/bydJpRG9fgCYyIDl/h1U= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= @@ -121,11 +123,7 @@ github.com/rs/cors v1.11.1 h1:eU3gRzXLRK57F5rKMGMZURNdIG4EoAmX8k94r9wXWHA= github.com/rs/cors v1.11.1/go.mod h1:XyqrcTp5zjWr1wsJ8PIRZssZ8b/WMcMf71DJnit4EMU= github.com/savsgio/gotils v0.0.0-20240704082632-aef3928b8a38 h1:D0vL7YNisV2yqE55+q0lFuGse6U8lxlg7fYTctlT5Gc= github.com/savsgio/gotils v0.0.0-20240704082632-aef3928b8a38/go.mod h1:sM7Mt7uEoCeFSCBM+qBrqvEo+/9vdmj19wzp3yzUhmg= -github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= -github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= @@ -136,8 +134,6 @@ github.com/templexxx/cpu v0.0.1 h1:hY4WdLOgKdc8y13EYklu9OUTXik80BkxHoWvTO6MQQY= github.com/templexxx/cpu v0.0.1/go.mod h1:w7Tb+7qgcAlIyX4NhLuDKt78AHA5SzPmq0Wj6HiEnnk= github.com/templexxx/xhex v0.0.0-20200614015412-aed53437177b h1:XeDLE6c9mzHpdv3Wb1+pWBaWv/BlHK0ZYIu/KaL6eHg= github.com/templexxx/xhex v0.0.0-20200614015412-aed53437177b/go.mod h1:7rwmCH0wC2fQvNEvPZ3sKXukhyCTyiaZ5VTZMQYpZKQ= -github.com/therecipe/qt v0.0.0-20200904063919-c0c124a5770d h1:T+d8FnaLSvM/1BdlDXhW4d5dr2F07bAbB+LpgzMxx+o= -github.com/therecipe/qt v0.0.0-20200904063919-c0c124a5770d/go.mod h1:SUUR2j3aE1z6/g76SdD6NwACEpvCxb3fvG82eKbD6us= github.com/tidwall/gjson v1.18.0 h1:FIDeeyB800efLX89e5a8Y0BNH+LOngJyGrIWxG2FKQY= github.com/tidwall/gjson v1.18.0/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA= @@ -155,7 +151,6 @@ github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM= github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg= golang.org/x/crypto v0.0.0-20170930174604-9419663f5a44/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20190418165655-df01cb2cc480/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.39.0 h1:SHs+kF4LP+f+p14esP5jAoDpHU8Gu/v9lFRK6IT5imM= golang.org/x/crypto v0.39.0/go.mod h1:L+Xg3Wf6HoL4Bn4238Z6ft6KfEpN0tJGo53AAPC632U= @@ -163,9 +158,7 @@ golang.org/x/exp v0.0.0-20250305212735-054e65f0b394 h1:nDVHiLt8aIbd/VzvPWN6kSOPE golang.org/x/exp v0.0.0-20250305212735-054e65f0b394/go.mod h1:sIifuuw/Yco/y6yb6+bDNfyeQ/MdPUy/hKEMYQV17cM= golang.org/x/net v0.0.0-20180719180050-a680a1efc54d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190420063019-afa5a82059c6/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200813134508-3edf25e44fcc/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.41.0 h1:vBTly1HeNPEn3wtREYfy4GZ/NECgw2Cnl+nK6Nz3uvw= @@ -173,12 +166,9 @@ golang.org/x/net v0.41.0/go.mod h1:B/K4NNqkfmg07DQYrbwvSluqCJOOXwUjeb/5lOisjbA= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.15.0 h1:KWH3jNZsfyT6xfAfKiz6MRNmd46ByHDYaZ7KSkCtdW8= golang.org/x/sync v0.15.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= -golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190419153524-e8e3143a4f4a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -193,7 +183,6 @@ golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.26.0 h1:P42AVeLghgTYr4+xUnTRKDMqpar+PtX7KWuNQL21L8M= golang.org/x/text v0.26.0/go.mod h1:QK15LZJUUQVJxhz7wXgxSy/CJaTFjd0G+YLonydOVQA= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20190420181800-aa740d480789/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= diff --git a/justfile b/justfile new file mode 100644 index 0000000..38c50dd --- /dev/null +++ b/justfile @@ -0,0 +1,13 @@ +dist: deploy_linux deploy_windows + mkdir -p dist + cd deploy/linux && tar -czvf vnak_linux.tar.gz vnak + mv deploy/linux/vnak_linux.tar.gz dist/ + rm -f deploy/windows/vnak_windows.zip + cd deploy/windows && zip vnak_windows *.exe + mv deploy/windows/vnak_windows.zip dist/ + +deploy_linux: + go build -ldflags="-s -w" + +deploy_windows: + go build -ldflags="-s -w -H windowsgui" --tags=windowsqtstatic diff --git a/main.go b/main.go index 43a3364..52bd8a2 100644 --- a/main.go +++ b/main.go @@ -12,53 +12,58 @@ import ( "fiatjaf.com/nostr/nip19" "fiatjaf.com/nostr/nip49" "fiatjaf.com/nostr/sdk" - "github.com/therecipe/qt/widgets" + qt "github.com/mappu/miqt/qt6" ) var ( + window *qt.QMainWindow + currentSec nostr.SecretKey currentKeyer nostr.Keyer - statusLabel *widgets.QLabel + statusLabel *qt.QLabel debounced = debouncer.New(800 * time.Millisecond) sys = sdk.NewSystem() ctx = context.Background() ) func main() { - app := widgets.NewQApplication(len(os.Args), os.Args) + qt.NewQApplication(os.Args) + + window = qt.NewQMainWindow2() - window := widgets.NewQMainWindow(nil, 0) window.SetMinimumSize2(800, 600) window.SetWindowTitle("nakv") - centralWidget := widgets.NewQWidget(nil, 0) + centralWidget := qt.NewQWidget(window.QWidget) window.SetCentralWidget(centralWidget) - mainLayout := widgets.NewQVBoxLayout() - centralWidget.SetLayout(mainLayout) + mainLayout := qt.NewQVBoxLayout2() + centralWidget.SetLayout(mainLayout.QLayout) // private key input - secLabel := widgets.NewQLabel2("private key (hex or nsec):", nil, 0) - mainLayout.AddWidget(secLabel, 0, 0) + secLabel := qt.NewQLabel2() + secLabel.SetText("private key (hex or nsec):") + mainLayout.AddWidget(secLabel.QWidget) - secHBox := widgets.NewQHBoxLayout() - mainLayout.AddLayout(secHBox, 0) - secEdit := widgets.NewQLineEdit(nil) - secHBox.AddWidget(secEdit, 0, 0) - generateButton := widgets.NewQPushButton2("generate", nil) - secHBox.AddWidget(generateButton, 0, 0) + secHBox := qt.NewQHBoxLayout2() + mainLayout.AddLayout(secHBox.QLayout) + secEdit := qt.NewQLineEdit(centralWidget) + secHBox.AddWidget(secEdit.QWidget) + generateButton := qt.NewQPushButton5("generate", centralWidget) + secHBox.AddWidget(generateButton.QWidget) // password input - passwordHBox := widgets.NewQHBoxLayout() - passwordWidget := widgets.NewQWidget(nil, 0) - passwordWidget.SetLayout(passwordHBox) + passwordHBox := qt.NewQHBoxLayout2() + passwordWidget := qt.NewQWidget(centralWidget) + passwordWidget.SetLayout(passwordHBox.QLayout) passwordWidget.SetVisible(false) - mainLayout.AddWidget(passwordWidget, 0, 0) - passwordLabel := widgets.NewQLabel2("password:", nil, 0) - passwordHBox.AddWidget(passwordLabel, 0, 0) - secPasswordEdit := widgets.NewQLineEdit(nil) - secPasswordEdit.SetEchoMode(widgets.QLineEdit__Password) - passwordHBox.AddWidget(secPasswordEdit, 0, 0) + mainLayout.AddWidget(passwordWidget) + passwordLabel := qt.NewQLabel2() + passwordLabel.SetText("password:") + passwordHBox.AddWidget(passwordLabel.QWidget) + secPasswordEdit := qt.NewQLineEdit(passwordWidget) + secPasswordEdit.SetEchoMode(qt.QLineEdit__Password) + passwordHBox.AddWidget(secPasswordEdit.QWidget) keyChanged := func(text string) { text = strings.TrimSpace(text) @@ -108,16 +113,16 @@ func main() { statusLabel.SetText("") return } - secEdit.ConnectTextChanged(keyChanged) - secPasswordEdit.ConnectTextChanged(keyChanged) - generateButton.ConnectClicked(func(bool) { + secEdit.OnTextChanged(keyChanged) + secPasswordEdit.OnTextChanged(keyChanged) + generateButton.OnClicked(func() { sk := nostr.Generate() nsec := nip19.EncodeNsec(sk) secEdit.SetText(nsec) keyChanged(nsec) }) - tabWidget := widgets.NewQTabWidget(nil) + tabWidget := qt.NewQTabWidget(centralWidget) eventTab := setupEventTab() reqTab := setupReqTab() @@ -125,15 +130,15 @@ func main() { tabWidget.AddTab(eventTab, "event") tabWidget.AddTab(reqTab, "req") - mainLayout.AddWidget(tabWidget, 0, 0) + mainLayout.AddWidget(tabWidget.QWidget) - statusLabel = widgets.NewQLabel2("", nil, 0) - mainLayout.AddWidget(statusLabel, 0, 0) + statusLabel = qt.NewQLabel2() + mainLayout.AddWidget(statusLabel.QWidget) // initial render updateEvent() updateReq() window.Show() - app.Exec() + qt.QApplication_Exec() } diff --git a/req.go b/req.go index dda53b0..a839004 100644 --- a/req.go +++ b/req.go @@ -6,45 +6,45 @@ import ( "strings" "fiatjaf.com/nostr" - "github.com/therecipe/qt/core" - "github.com/therecipe/qt/widgets" + qt "github.com/mappu/miqt/qt6" ) type reqVars struct { - authorsEdits []*widgets.QLineEdit - idsEdits []*widgets.QLineEdit - kindsEdits []*widgets.QLineEdit - kindsLabels []*widgets.QLabel - relaysEdits []*widgets.QLineEdit - sinceEdit *widgets.QDateTimeEdit - untilEdit *widgets.QDateTimeEdit - limitSpin *widgets.QSpinBox + authorsEdits []*qt.QLineEdit + idsEdits []*qt.QLineEdit + kindsEdits []*qt.QLineEdit + kindsLabels []*qt.QLabel + relaysEdits []*qt.QLineEdit + sinceEdit *qt.QDateTimeEdit + untilEdit *qt.QDateTimeEdit + limitSpin *qt.QSpinBox filter nostr.Filter - outputEdit *widgets.QTextEdit - resultsEdit *widgets.QTextEdit + outputEdit *qt.QTextEdit + resultsEdit *qt.QTextEdit } var req = reqVars{} -func setupReqTab() *widgets.QWidget { - tab := widgets.NewQWidget(nil, 0) - layout := widgets.NewQVBoxLayout() - tab.SetLayout(layout) +func setupReqTab() *qt.QWidget { + tab := qt.NewQWidget(window.QWidget) + layout := qt.NewQVBoxLayout2() + tab.SetLayout(layout.QLayout) // authors - authorsLabel := widgets.NewQLabel2("authors:", nil, 0) - layout.AddWidget(authorsLabel, 0, 0) - authorsVBox := widgets.NewQVBoxLayout() - layout.AddLayout(authorsVBox, 0) - req.authorsEdits = []*widgets.QLineEdit{} + authorsLabel := qt.NewQLabel2() + authorsLabel.SetText("authors:") + layout.AddWidget(authorsLabel.QWidget) + authorsVBox := qt.NewQVBoxLayout2() + layout.AddLayout(authorsVBox.QLayout) + req.authorsEdits = []*qt.QLineEdit{} var addAuthorEdit func() addAuthorEdit = func() { - edit := widgets.NewQLineEdit(nil) + edit := qt.NewQLineEdit(tab) req.authorsEdits = append(req.authorsEdits, edit) - authorsVBox.AddWidget(edit, 0, 0) - edit.ConnectTextChanged(func(text string) { + authorsVBox.AddWidget(edit.QWidget) + edit.OnTextChanged(func(text string) { if strings.TrimSpace(text) != "" { if edit == req.authorsEdits[len(req.authorsEdits)-1] { addAuthorEdit() @@ -52,7 +52,7 @@ func setupReqTab() *widgets.QWidget { } else { n := len(req.authorsEdits) if n >= 2 && strings.TrimSpace(req.authorsEdits[n-1].Text()) == "" && strings.TrimSpace(req.authorsEdits[n-2].Text()) == "" { - authorsVBox.Layout().RemoveWidget(req.authorsEdits[n-1]) + authorsVBox.RemoveWidget(req.authorsEdits[n-1].QWidget) req.authorsEdits[n-1].DeleteLater() req.authorsEdits = req.authorsEdits[0 : n-1] } @@ -63,17 +63,18 @@ func setupReqTab() *widgets.QWidget { addAuthorEdit() // ids - idsLabel := widgets.NewQLabel2("ids:", nil, 0) - layout.AddWidget(idsLabel, 0, 0) - idsVBox := widgets.NewQVBoxLayout() - layout.AddLayout(idsVBox, 0) - req.idsEdits = []*widgets.QLineEdit{} + idsLabel := qt.NewQLabel2() + idsLabel.SetText("ids:") + layout.AddWidget(idsLabel.QWidget) + idsVBox := qt.NewQVBoxLayout2() + layout.AddLayout(idsVBox.QLayout) + req.idsEdits = []*qt.QLineEdit{} var addIdEdit func() addIdEdit = func() { - edit := widgets.NewQLineEdit(nil) + edit := qt.NewQLineEdit(tab) req.idsEdits = append(req.idsEdits, edit) - idsVBox.AddWidget(edit, 0, 0) - edit.ConnectTextChanged(func(text string) { + idsVBox.AddWidget(edit.QWidget) + edit.OnTextChanged(func(text string) { if strings.TrimSpace(text) != "" { if edit == req.idsEdits[len(req.idsEdits)-1] { addIdEdit() @@ -81,7 +82,7 @@ func setupReqTab() *widgets.QWidget { } else { n := len(req.idsEdits) if n >= 2 && strings.TrimSpace(req.idsEdits[n-1].Text()) == "" && strings.TrimSpace(req.idsEdits[n-2].Text()) == "" { - idsVBox.Layout().RemoveWidget(req.idsEdits[n-1]) + idsVBox.RemoveWidget(req.idsEdits[n-1].QWidget) req.idsEdits[n-1].DeleteLater() req.idsEdits = req.idsEdits[0 : n-1] } @@ -92,23 +93,24 @@ func setupReqTab() *widgets.QWidget { addIdEdit() // kinds - kindsLabel := widgets.NewQLabel2("kinds:", nil, 0) - layout.AddWidget(kindsLabel, 0, 0) - kindsVBox := widgets.NewQVBoxLayout() - layout.AddLayout(kindsVBox, 0) - req.kindsEdits = []*widgets.QLineEdit{} - req.kindsLabels = []*widgets.QLabel{} + kindsLabel := qt.NewQLabel2() + kindsLabel.SetText("kinds:") + layout.AddWidget(kindsLabel.QWidget) + kindsVBox := qt.NewQVBoxLayout2() + layout.AddLayout(kindsVBox.QLayout) + req.kindsEdits = []*qt.QLineEdit{} + req.kindsLabels = []*qt.QLabel{} var addKindEdit func() addKindEdit = func() { - hbox := widgets.NewQHBoxLayout() - kindsVBox.AddLayout(hbox, 0) - edit := widgets.NewQLineEdit(nil) + hbox := qt.NewQHBoxLayout2() + kindsVBox.AddLayout(hbox.QLayout) + edit := qt.NewQLineEdit(tab) req.kindsEdits = append(req.kindsEdits, edit) - hbox.AddWidget(edit, 0, 0) - label := widgets.NewQLabel2("", nil, 0) + hbox.AddWidget(edit.QWidget) + label := qt.NewQLabel2() req.kindsLabels = append(req.kindsLabels, label) - hbox.AddWidget(label, 0, 0) - edit.ConnectTextChanged(func(text string) { + hbox.AddWidget(label.QWidget) + edit.OnTextChanged(func(text string) { if strings.TrimSpace(text) != "" { if edit == req.kindsEdits[len(req.kindsEdits)-1] { addKindEdit() @@ -119,8 +121,8 @@ func setupReqTab() *widgets.QWidget { lastItem := kindsVBox.ItemAt(kindsVBox.Count() - 1) kindsVBox.RemoveItem(lastItem) lastHBox := lastItem.Layout() - lastHBox.RemoveWidget(req.kindsEdits[n-1]) - lastHBox.RemoveWidget(req.kindsLabels[n-1]) + lastHBox.RemoveWidget(req.kindsEdits[n-1].QWidget) + lastHBox.RemoveWidget(req.kindsLabels[n-1].QWidget) req.kindsEdits[n-1].DeleteLater() req.kindsLabels[n-1].DeleteLater() lastHBox.DeleteLater() @@ -134,69 +136,74 @@ func setupReqTab() *widgets.QWidget { addKindEdit() // since - sinceHBox := widgets.NewQHBoxLayout() - layout.AddLayout(sinceHBox, 0) - sinceLabel := widgets.NewQLabel2("since:", nil, 0) - sinceHBox.AddWidget(sinceLabel, 0, 0) - req.sinceEdit = widgets.NewQDateTimeEdit(nil) + sinceHBox := qt.NewQHBoxLayout2() + layout.AddLayout(sinceHBox.QLayout) + sinceLabel := qt.NewQLabel2() + sinceLabel.SetText("since:") + sinceHBox.AddWidget(sinceLabel.QWidget) + req.sinceEdit = qt.NewQDateTimeEdit(tab) { - time := core.NewQDateTime3(core.NewQDate3(0, 0, 0), core.NewQTime3(0, 0, 0, 0), 0) + time := qt.NewQDateTime() time.SetMSecsSinceEpoch(0) req.sinceEdit.SetDateTime(time) } - sinceHBox.AddWidget(req.sinceEdit, 0, 0) - req.sinceEdit.ConnectDateTimeChanged(func(*core.QDateTime) { + sinceHBox.AddWidget(req.sinceEdit.QWidget) + req.sinceEdit.OnDateTimeChanged(func(*qt.QDateTime) { updateReq() }) // until - untilHBox := widgets.NewQHBoxLayout() - layout.AddLayout(untilHBox, 0) - untilLabel := widgets.NewQLabel2("until:", nil, 0) - untilHBox.AddWidget(untilLabel, 0, 0) - req.untilEdit = widgets.NewQDateTimeEdit(nil) + untilHBox := qt.NewQHBoxLayout2() + layout.AddLayout(untilHBox.QLayout) + untilLabel := qt.NewQLabel2() + untilLabel.SetText("until:") + untilHBox.AddWidget(untilLabel.QWidget) + req.untilEdit = qt.NewQDateTimeEdit(tab) { - time := core.NewQDateTime3(core.NewQDate3(0, 0, 0), core.NewQTime3(0, 0, 0, 0), 0) + time := qt.NewQDateTime() time.SetMSecsSinceEpoch(0) req.untilEdit.SetDateTime(time) } - untilHBox.AddWidget(req.untilEdit, 0, 0) - req.untilEdit.ConnectDateTimeChanged(func(*core.QDateTime) { + untilHBox.AddWidget(req.untilEdit.QWidget) + req.untilEdit.OnDateTimeChanged(func(*qt.QDateTime) { updateReq() }) // limit - limitHBox := widgets.NewQHBoxLayout() - layout.AddLayout(limitHBox, 0) - limitLabel := widgets.NewQLabel2("limit:", nil, 0) - limitHBox.AddWidget(limitLabel, 0, 0) - req.limitSpin = widgets.NewQSpinBox(nil) + limitHBox := qt.NewQHBoxLayout2() + layout.AddLayout(limitHBox.QLayout) + limitLabel := qt.NewQLabel2() + limitLabel.SetText("limit:") + limitHBox.AddWidget(limitLabel.QWidget) + req.limitSpin = qt.NewQSpinBox(tab) req.limitSpin.SetMinimum(0) req.limitSpin.SetMaximum(1000) - limitHBox.AddWidget(req.limitSpin, 0, 0) - req.limitSpin.ConnectValueChanged(func(int) { + limitHBox.AddWidget(req.limitSpin.QWidget) + req.limitSpin.OnValueChanged(func(int) { updateReq() }) // output - outputLabel := widgets.NewQLabel2("filter:", nil, 0) - layout.AddWidget(outputLabel, 0, 0) - req.outputEdit = widgets.NewQTextEdit(nil) + outputLabel := qt.NewQLabel2() + outputLabel.SetText("filter:") + layout.AddWidget(outputLabel.QWidget) + req.outputEdit = qt.NewQTextEdit(tab) req.outputEdit.SetReadOnly(true) - layout.AddWidget(req.outputEdit, 0, 0) + layout.AddWidget(req.outputEdit.QWidget) // relays - relaysLabel := widgets.NewQLabel2("relays:", nil, 0) - layout.AddWidget(relaysLabel, 0, 0) - relaysVBox := widgets.NewQVBoxLayout() - layout.AddLayout(relaysVBox, 0) - req.relaysEdits = []*widgets.QLineEdit{} + relaysLabel := qt.NewQLabel2() + relaysLabel.SetText("relays:") + layout.AddWidget(relaysLabel.QWidget) + relaysVBox := qt.NewQVBoxLayout2() + layout.AddLayout(relaysVBox.QLayout) + req.relaysEdits = []*qt.QLineEdit{} var addRelayEdit func() addRelayEdit = func() { - edit := widgets.NewQLineEdit(nil) + edit := qt.NewQLineEdit(tab) req.relaysEdits = append(req.relaysEdits, edit) - relaysVBox.AddWidget(edit, 0, 0) - edit.ConnectTextChanged(func(text string) { + relaysVBox.AddWidget(edit.QWidget) + edit.OnTextChanged(func(text string) { if strings.TrimSpace(text) != "" { if edit == req.relaysEdits[len(req.relaysEdits)-1] { addRelayEdit() @@ -204,7 +211,7 @@ func setupReqTab() *widgets.QWidget { } else { n := len(req.relaysEdits) if n >= 2 && strings.TrimSpace(req.relaysEdits[n-1].Text()) == "" && strings.TrimSpace(req.relaysEdits[n-2].Text()) == "" { - relaysVBox.Layout().RemoveWidget(req.relaysEdits[n-1]) + relaysVBox.RemoveWidget(req.relaysEdits[n-1].QWidget) req.relaysEdits[n-1].DeleteLater() req.relaysEdits = req.relaysEdits[0 : n-1] } @@ -214,20 +221,21 @@ func setupReqTab() *widgets.QWidget { addRelayEdit() // send button - buttonHBox := widgets.NewQHBoxLayout() - layout.AddLayout(buttonHBox, 0) - sendButton := widgets.NewQPushButton2("send request", nil) - buttonHBox.AddWidget(sendButton, 0, 0) - buttonHBox.AddStretch(1) + buttonHBox := qt.NewQHBoxLayout2() + layout.AddLayout(buttonHBox.QLayout) + sendButton := qt.NewQPushButton5("send request", tab) + buttonHBox.AddWidget(sendButton.QWidget) + buttonHBox.AddStretch() // results - resultsLabel := widgets.NewQLabel2("results:", nil, 0) - layout.AddWidget(resultsLabel, 0, 0) - req.resultsEdit = widgets.NewQTextEdit(nil) + resultsLabel := qt.NewQLabel2() + resultsLabel.SetText("results:") + layout.AddWidget(resultsLabel.QWidget) + req.resultsEdit = qt.NewQTextEdit(tab) req.resultsEdit.SetReadOnly(true) - layout.AddWidget(req.resultsEdit, 0, 0) + layout.AddWidget(req.resultsEdit.QWidget) - sendButton.ConnectClicked(func(checked bool) { + sendButton.OnClicked(func() { req.subscribe() })