gui.go 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807
  1. package core
  2. import (
  3. "fmt"
  4. "errors"
  5. "kumachan/standalone/qt"
  6. "kumachan/standalone/ctn"
  7. "kumachan/standalone/util/pseudounion"
  8. )
  9. type guiObjectGuard struct {
  10. ptr *qt.Object
  11. }
  12. func makeGuiObjectGuard(Q qt.Object, dispose func()) (guiObjectGuard, func()) {
  13. var g = guiObjectGuard { &Q }
  14. // var class = Q.ClassName()
  15. // println("new", g.ptr, class)
  16. return g, func() {
  17. // println("delete", g.ptr, class)
  18. if *(g.ptr) != (qt.Object{}) {
  19. *(g.ptr) = (qt.Object{})
  20. dispose()
  21. } else {
  22. panic("double-free of GuiObject")
  23. }
  24. }
  25. }
  26. func (g guiObjectGuard) deref(h RuntimeHandle) qt.Object {
  27. if *(g.ptr) != (qt.Object{}) {
  28. return *(g.ptr)
  29. } else {
  30. return Crash1[qt.Object](h, UseAfterFree, "GuiObject already deleted")
  31. }
  32. }
  33. type GuiObject[T any] struct {
  34. g guiObjectGuard
  35. f func(qt.Object)(T)
  36. }
  37. func makeGuiObject[T any] (Q qt.Object, dispose func(), f func(qt.Object)(T)) (GuiObject[T], func()) {
  38. var g, delete_ = makeGuiObjectGuard(Q, dispose)
  39. return GuiObject[T] { g, f }, delete_
  40. }
  41. func (q GuiObject[T]) Deref(h RuntimeHandle) T {
  42. return q.f(q.g.deref(h))
  43. }
  44. func q_Widget(Q qt.Object) qt.Widget { return qt.Widget{Object:Q} }
  45. func q_Action(Q qt.Object) qt.Action { return qt.Action{Object:Q} }
  46. func q_ActionGroup(Q qt.Object) qt.ActionGroup { return qt.ActionGroup{Object:Q} }
  47. type Action struct {
  48. GuiObject[qt.Action]
  49. }
  50. func WrapAction(k func(qt.Pkg)(qt.Action)) (Action, func()) {
  51. var pkg, dispose = qt.CreatePkg()
  52. var Q = k(pkg).Object
  53. var q, delete_ = makeGuiObject(Q, dispose, q_Action)
  54. return Action{q}, delete_
  55. }
  56. type Widget struct {
  57. GuiObject[qt.Widget]
  58. }
  59. func WrapWidget(k func(qt.Pkg)(qt.Widget)) (Widget, func()) {
  60. var pkg, dispose = qt.CreatePkg()
  61. var Q = k(pkg).Object
  62. var q, delete_ = makeGuiObject(Q, dispose, q_Widget)
  63. return Widget{q}, delete_
  64. }
  65. func WrapWidget2[X any] (k func(qt.Pkg)(X,qt.Widget)) (X, Widget, func()) {
  66. var pkg, dispose = qt.CreatePkg()
  67. var x, W = k(pkg)
  68. var Q = W.Object
  69. var q, delete_ = makeGuiObject(Q, dispose, q_Widget)
  70. var w = Widget{q}
  71. return x, w, delete_
  72. }
  73. type Signal struct {
  74. signature string
  75. getValue func(qt.Widget) Object
  76. getOnConnect bool
  77. }
  78. //go:noinline
  79. func MakeSignal(sig string) Signal {
  80. return Signal { sig, nil, false }
  81. }
  82. func MakeSignalWithValueGetter(sig string, v0 bool, f func(qt.Widget)(Object)) Signal {
  83. return Signal { sig, f, v0 }
  84. }
  85. func (s Signal) withPropGetter(f func(qt.Widget)(Object)) Signal {
  86. return Signal { s.signature, f, true }
  87. }
  88. func (s Signal) Connect(w Widget, h RuntimeHandle) Observable {
  89. return Observable(func(pub DataPublisher) {
  90. var pkg, dispose = qt.CreatePkg()
  91. if ((s.getValue != nil) && s.getOnConnect) {
  92. var current = s.getValue(w.Deref(h))
  93. pub.observer.value(current)
  94. }
  95. qt.Connect(w.Deref(h).Object, s.signature, pkg, func() {
  96. if s.getValue != nil {
  97. pub.observer.value(s.getValue(w.Deref(h)))
  98. } else {
  99. pub.observer.value(nil)
  100. }
  101. })
  102. pub.context.registerCleaner(dispose)
  103. })
  104. }
  105. type Events struct {
  106. kind qt.EventKind
  107. prevent bool
  108. }
  109. //go:noinline
  110. func MakeEvents(kind qt.EventKind, prevent bool) Events {
  111. return Events { kind, prevent }
  112. }
  113. func (e Events) Listen(w Widget, h RuntimeHandle) Observable {
  114. return Observable(func(pub DataPublisher) {
  115. var pkg, dispose = qt.CreatePkg()
  116. var callback = eventTransformer(e.kind, pub.observer.value)
  117. qt.Listen(w.Deref(h).Object, e.kind, e.prevent, pkg, callback)
  118. pub.context.registerCleaner(dispose)
  119. })
  120. }
  121. func eventTransformer(kind qt.EventKind, yield func(Object)) func(qt.Event) {
  122. return func(ev qt.Event) {
  123. for _, k := range trivialEventKinds {
  124. if kind == k {
  125. yield(nil)
  126. return
  127. }
  128. }
  129. switch kind {
  130. // ...
  131. default:
  132. panic("unsupported event kind")
  133. }
  134. }
  135. }
  136. var trivialEventKinds = [] qt.EventKind {
  137. qt.EventShow(), qt.EventClose(),
  138. }
  139. type Prop struct {
  140. name string
  141. type_ PropType
  142. }
  143. type PropType int
  144. const ( PropString PropType = iota; PropBool; PropInt )
  145. //go:noinline
  146. func MakeProp(type_ PropType, name string) Prop {
  147. return Prop { name, type_ }
  148. }
  149. func (p Prop) get(w qt.Widget) Object {
  150. switch p.type_ {
  151. case PropString:
  152. return ObjString(w.GetPropString(p.name))
  153. case PropBool:
  154. return ObjBool(w.GetPropBool(p.name))
  155. case PropInt:
  156. return ObjInt(w.GetPropInt(p.name))
  157. default:
  158. panic("unsupported prop type")
  159. }
  160. }
  161. func (p Prop) set(v Object, w qt.Widget) {
  162. switch p.type_ {
  163. case PropString:
  164. w.SetPropString(p.name, GetString(v))
  165. case PropBool:
  166. w.SetPropBool(p.name, GetBool(v))
  167. case PropInt:
  168. w.SetPropInt(p.name, GetInt(v))
  169. default:
  170. panic("unsupported prop type")
  171. }
  172. }
  173. func (p Prop) Read(s Signal) Signal {
  174. return s.withPropGetter(p.get)
  175. }
  176. func (p Prop) Bind(o Observable, w Widget, h RuntimeHandle) Observable {
  177. return o.ConcatMap(func(v Object) Observable {
  178. return Observable(func(pub DataPublisher) {
  179. p.set(v, w.Deref(h))
  180. pub.observer.complete()
  181. })
  182. })
  183. }
  184. func DialogGenerate(pub DataPublisher) (func(Object), func()) {
  185. return pub.observer.value, pub.observer.complete
  186. }
  187. func ConnectActionTrigger(a Action, h RuntimeHandle) Observable {
  188. return onSync(func() func(qt.Pkg, func()) {
  189. return a.Deref(h).OnTrigger
  190. })
  191. }
  192. func SetActionEnabled(a Action, p bool, h RuntimeHandle) Observable {
  193. return doSync(func() {
  194. a.Deref(h).SetEnabled(p)
  195. })
  196. }
  197. func ActionCheckBox(a Action, initial bool, h RuntimeHandle, k func(Observable)(Object)) Hook {
  198. return MakeHook(func() (Object, func()) {
  199. if a.Deref(h).Checkable() {
  200. Crash(h, InvariantViolation, "action already checkable")
  201. }
  202. a.Deref(h).SetCheckable(true)
  203. var set_uncheckable = func() {
  204. a.Deref(h).SetCheckable(false)
  205. }
  206. a.Deref(h).SetChecked(initial)
  207. var checked = onSync1(func() func(qt.Pkg, func(bool)) {
  208. return a.Deref(h).OnCheck
  209. })
  210. return k(checked), set_uncheckable
  211. })
  212. }
  213. type ActionComboBoxItem struct { Action Action; Selected bool }
  214. func ActionComboBox(items ([] ActionComboBoxItem), h RuntimeHandle, k func(Observable)(Object)) Hook {
  215. if len(items) == 0 {
  216. panic("invalid argument")
  217. }
  218. return MakeHook(func() (Object, func()) {
  219. for _, item := range items {
  220. if item.Action.Deref(h).Checkable() {
  221. Crash(h, InvariantViolation, "some action already checkable")
  222. }
  223. item.Action.Deref(h).SetCheckable(true)
  224. }
  225. var set_uncheckable = func() {
  226. for _, item := range items {
  227. item.Action.Deref(h).SetCheckable(false)
  228. }
  229. }
  230. var items = ctn.MapEach(items, func(item ActionComboBoxItem) qt.ActionGroupItem {
  231. return qt.ActionGroupItem {
  232. Action: item.Action.Deref(h),
  233. Selected: item.Selected,
  234. }
  235. })
  236. var pkg, dispose = qt.CreatePkg()
  237. var ok bool
  238. var G = qt.CreateActionGroup(pkg, items, &ok)
  239. if !(ok) {
  240. Crash(h, InvariantViolation, "some action already grouped")
  241. }
  242. var Q = G.Object
  243. var g, delete_ = makeGuiObject(Q, dispose, q_ActionGroup)
  244. var index_on_trigger = onSync1(func() func(qt.Pkg, func(int)) {
  245. return g.Deref(h).OnCheck
  246. })
  247. var index = index_on_trigger.DistinctUntilChanged(func(a Object, b Object) bool {
  248. return (GetInt(a) == GetInt(b))
  249. })
  250. return k(index), func() {
  251. delete_()
  252. set_uncheckable()
  253. }
  254. })
  255. }
  256. func BindInlineStyleSheet(w Widget, o Observable, h RuntimeHandle) Observable {
  257. return ObservableFlattenLast(doSync2(func() (Observable, func()) {
  258. var id, initial = addInlineStyleSheet(w, h)
  259. var selector = fmt.Sprintf(`[%s="%s"]`, qt.DP_InlineStyleSheetId, id)
  260. var value = o.Map(func(obj Object) Object {
  261. var decls = GetString(obj)
  262. var ruleset = fmt.Sprintf("%s { %s }\n", selector, decls)
  263. return ObjString(ruleset + initial)
  264. })
  265. var prop = MakeProp(PropString, qt.P_StyleSheet)
  266. return prop.Bind(value, w, h), func() {
  267. removeInlineStyleSheet(initial, w, h)
  268. }
  269. }))
  270. }
  271. func addInlineStyleSheet(w Widget, h RuntimeHandle) (string, string) {
  272. var W = w.Deref(h)
  273. if W.GetPropString(qt.DP_InlineStyleSheetId) != "" {
  274. Crash(h, InvariantViolation, "duplicate styling")
  275. }
  276. var id = fmt.Sprintf("%x", w.Deref(h).PointerNumber())
  277. W.SetPropString(qt.DP_InlineStyleSheetId, id)
  278. return id, W.GetPropString(qt.P_StyleSheet)
  279. }
  280. func removeInlineStyleSheet(initial string, w Widget, h RuntimeHandle) {
  281. var W = w.Deref(h)
  282. W.SetPropString(qt.P_StyleSheet, initial)
  283. W.SetPropString(qt.DP_InlineStyleSheetId, "")
  284. }
  285. func BindContextMenu(w Widget, m_ qt.Menu, h RuntimeHandle) Observable {
  286. return Observable(func(pub DataPublisher) {
  287. var pkg, dispose = qt.CreatePkg()
  288. var m = qt.CreateContextMenu(m_, pkg)
  289. var ok = m.Bind(w.Deref(h), pkg)
  290. if !(ok) {
  291. Crash(h, InvariantViolation, "duplicate context menu")
  292. }
  293. pub.context.registerCleaner(dispose)
  294. })
  295. }
  296. func CreateDynamicWidget(widgets Observable, h RuntimeHandle) Hook {
  297. return Hook { Observable(func(pub DataPublisher) {
  298. var ctx, ob = pub.useInheritedContext()
  299. var W, w, w_dispose = WrapWidget2(func(ctx qt.Pkg) (qt.DynamicWidget, qt.Widget) {
  300. var W = qt.CreateDynamicWidget(ctx)
  301. return W, W.Widget
  302. })
  303. ctx.registerCleaner(w_dispose)
  304. pub.run(widgets, ctx, &observer {
  305. value: func(obj Object) {
  306. W.SetWidget(GetWidget(obj).Deref(h))
  307. },
  308. error: ErrorLogger(h),
  309. complete: func() {},
  310. })
  311. ob.value(Obj(w))
  312. ob.complete()
  313. })}
  314. }
  315. type ListViewConfig struct {
  316. CreateInterface func(ctx qt.Pkg) qt.Lwi
  317. ReturnObject func(w Widget, e Observable, c Observable, s Observable) Object
  318. }
  319. func ListView(config ListViewConfig, data Observable, getKey func(Object)(string), p ItemViewProvider, h RuntimeHandle) Hook {
  320. return Hook { Observable(func(pub DataPublisher) {
  321. var ctx, ob = pub.useInheritedContext()
  322. var lg = MakeLogger(h)
  323. var I, w, w_dispose = WrapWidget2(func(ctx qt.Pkg) (qt.Lwi, qt.Widget) {
  324. var I = config.CreateInterface(ctx)
  325. return I, I.CastToWidget()
  326. })
  327. ctx.registerCleaner(w_dispose)
  328. var m = make(map[string] *listViewItem)
  329. var update = withLwiLatestKeys(data, I, h, func(obj Object, old_keys_ ([] string)) Observable {
  330. var new_keys_ = make([] string, 0)
  331. var new_keys = make(map[string] struct{})
  332. var mapping = make(map[string] listViewItemValueWithPos)
  333. var list = GetList(obj)
  334. var total = list.Length()
  335. list.ForEachWithIndex(func(index int, value Object) {
  336. var key = getKey(value)
  337. var _, dup = new_keys[key]
  338. if !(dup) {
  339. new_keys_ = append(new_keys_, key)
  340. new_keys[key] = struct{}{}
  341. mapping[key] = listViewItemValueWithPos {
  342. Value: value,
  343. Pos: ItemPos { index, total },
  344. }
  345. } else {
  346. lg.LogError(errors.New("duplicate key ignored: " + key))
  347. }
  348. })
  349. var tasks = make([] Observable, 0)
  350. var old_keys = make(map[string] struct{})
  351. for _, K := range old_keys_ {
  352. var old_key = K
  353. old_keys[old_key] = struct{}{}
  354. var _, exists = new_keys[old_key]
  355. if removed := !(exists); removed {
  356. var remove = doSync(func() {
  357. m[old_key].Dispose()
  358. })
  359. tasks = append(tasks, remove)
  360. }
  361. }
  362. for _, K := range new_keys_ {
  363. var new_key = K
  364. var new_value = mapping[new_key]
  365. if _, exists := old_keys[new_key]; exists {
  366. var item_update = doSync(func() {
  367. m[new_key].Buffer.value(ToObject(new_value))
  368. I.Update(new_key)
  369. })
  370. tasks = append(tasks, item_update)
  371. } else {
  372. var add = retrieveBufAndHook(new_key, p, h, func(buf Subject, hook Hook) Observable {
  373. return retrieveObjectInChildContext(ctx, hook.Job, h, func(view ItemView, ctx *context, dispose func()) Observable {
  374. return doSync(func() {
  375. var widgets = view.Widgets.Deref(h)
  376. var extension = view.Extension
  377. I.Append(new_key, widgets)
  378. ctx.registerCleaner(func() {
  379. I.Delete(new_key)
  380. })
  381. var item = &listViewItem {
  382. Context: ctx,
  383. Dispose: dispose,
  384. Buffer: buf,
  385. Extension: extension,
  386. }
  387. m[new_key] = item
  388. ctx.registerCleaner(func() {
  389. delete(m, new_key)
  390. })
  391. buf.value(ToObject(new_value))
  392. I.Update(new_key)
  393. })
  394. })})
  395. tasks = append(tasks, add)
  396. }
  397. }
  398. var reorder = doSync(func() {
  399. I.Reorder(new_keys_)
  400. })
  401. tasks = append(tasks, reorder)
  402. return Concat(func(yield func(Observable)) {
  403. for _, task := range tasks {
  404. yield(task)
  405. }
  406. })
  407. })
  408. var watch = func(name string, k func(Object)(Observable)) Observable {
  409. return MakeSignal(name).Connect(w, h).StartWith(nil).ConcatMap(k)
  410. }
  411. var e = watch(qt.DefaultListWidget_CurrentChanged, func(_ Object) Observable {
  412. return doSync1(func() ctn.Maybe[Widget] {
  413. if cur, ok := I.Current(); ok {
  414. if item, ok := m[cur]; ok {
  415. return item.Extension
  416. }}
  417. return nil
  418. })
  419. })
  420. var c = watch(qt.DefaultListWidget_CurrentChanged, func(_ Object) Observable {
  421. return doSync1(func() ctn.Maybe[string] {
  422. return ctn.MakeMaybe(I.Current())
  423. })
  424. })
  425. var s = watch(qt.DefaultListWidget_SelectionChanged, func(_ Object) Observable {
  426. return doSync1(func() ([] string) {
  427. return I.Selection()
  428. })
  429. })
  430. pub.run(update, ctx, &observer {
  431. value: func(Object) {},
  432. error: lg.LogError,
  433. complete: func() {},
  434. })
  435. ob.value(config.ReturnObject(w, e, c, s))
  436. ob.complete()
  437. })}
  438. }
  439. func withLwiLatestKeys(data Observable, I qt.Lwi, h RuntimeHandle, k func(Object,[]string)(Observable)) Observable {
  440. return data.ConcatMap(func(obj Object) Observable {
  441. var get_keys = doSync1(func() ([] string) { return I.All() })
  442. return retrieveObject(get_keys, h, func(keys ([] string)) Observable {
  443. return k(obj, keys)
  444. })
  445. })
  446. }
  447. func retrieveBufAndHook(key string, p ItemViewProvider, h RuntimeHandle, k func(Subject,Hook)(Observable)) Observable {
  448. var create_buf = doSync1(func() Subject {
  449. return CreateSubject(h, 1)
  450. })
  451. return retrieveObject(create_buf, h, func(buf Subject) Observable {
  452. var o = listViewItemValue(buf.Observe())
  453. var pos = listViewItemPos(buf.Observe())
  454. var info = ItemInfo {
  455. Key: key,
  456. Pos: pos,
  457. }
  458. var hook = p(o, info)
  459. return k(buf, hook)
  460. })
  461. }
  462. type listViewItem struct {
  463. Context *context
  464. Dispose func()
  465. Buffer Subject
  466. Extension ctn.Maybe[Widget]
  467. }
  468. type listViewItemValueWithPos struct {
  469. Value Object
  470. Pos ItemPos
  471. }
  472. func listViewItemValue(o Observable) Observable {
  473. var raw = o.Map(func(obj Object) Object {
  474. return FromObject[listViewItemValueWithPos](obj).Value
  475. })
  476. return raw.DistinctUntilObjectChanged()
  477. }
  478. func listViewItemPos(o Observable) Observable {
  479. var raw = o.Map(func(obj Object) Object {
  480. return ToObject(FromObject[listViewItemValueWithPos](obj).Pos)
  481. })
  482. return DistinctUntilItemPosChanged(raw)
  483. }
  484. type ListEditViewConfig struct {
  485. CreateInterface func(ctx qt.Pkg) qt.Lwi
  486. ReturnObject func(w Widget, o Observable, e Observable, O Subject) Object
  487. }
  488. func ListEditView(config ListEditViewConfig, initial List, p ItemEditViewProvider, h RuntimeHandle) Hook {
  489. return Hook { Observable(func(pub DataPublisher) {
  490. var ctx, ob = pub.useInheritedContext()
  491. var lg = MakeLogger(h)
  492. var I, w, w_dispose = WrapWidget2(func(ctx qt.Pkg) (qt.Lwi, qt.Widget) {
  493. var I = config.CreateInterface(ctx)
  494. return I, I.CastToWidget()
  495. })
  496. ctx.registerCleaner(w_dispose)
  497. var O = CreateSubject(h, 0)
  498. var store = createItemEditDataStore(h)
  499. var update = O.Observe().ConcatMap(func(op__ Object) Observable {
  500. var op_ = FromObject[ListEditOperation](op__)
  501. switch op := pseudounion.Load(op_).(type) {
  502. case Prepend, Append, InsertAbove, InsertBelow:
  503. var v, i = listEditViewMatchInsertionOperation(op)
  504. return retrieveKeyAndHook(v, p, store, h, func(key string, hook Hook) Observable {
  505. return retrieveObjectInChildContext(ctx, hook.Job, h, func(view ItemEditView, ctx *context, dispose func()) Observable {
  506. var ext = view.Extension
  507. var ops = view.EditOps(key)
  508. var enable_ops = O.Plug(SkipSync(ops))
  509. var insert = doSync(func() {
  510. var widgets = view.Widgets.Deref(h)
  511. store.insert(key, I, i, widgets, ctx, dispose, v, ext)
  512. })
  513. return insert.And(enable_ops, lg.LogError)
  514. })})
  515. case Update:
  516. return doSync(func() {
  517. store.update(op.Key, I, op.Value)
  518. })
  519. case Delete:
  520. return doSync(func() {
  521. store.delete(op.Key, I)
  522. })
  523. case MoveUp:
  524. return doSync(func() {
  525. store.moveUp(op.Key, I)
  526. })
  527. case MoveDown:
  528. return doSync(func() {
  529. store.moveDown(op.Key, I)
  530. })
  531. case MoveTop:
  532. return doSync(func() {
  533. store.moveTop(op.Key, I)
  534. })
  535. case MoveBottom:
  536. return doSync(func() {
  537. store.moveBottom(op.Key, I)
  538. })
  539. case Reorder:
  540. return doSync(func() {
  541. store.reorder(I, op.Reorder, lg)
  542. })
  543. default:
  544. panic("impossible branch")
  545. }
  546. })
  547. var o = store.output()
  548. var watch = func(name string, k func(Object)(Observable)) Observable {
  549. return MakeSignal(name).Connect(w, h).StartWith(nil).ConcatMap(k)
  550. }
  551. var e = watch(qt.DefaultListWidget_CurrentChanged, func(_ Object) Observable {
  552. return doSync1(func() ctn.Maybe[Widget] {
  553. return store.getCurrentExtension(I)
  554. })
  555. })
  556. pub.run(update, ctx, &observer {
  557. value: func(Object) {},
  558. error: lg.LogError,
  559. complete: func() {},
  560. })
  561. initial.ForEach(func(v Object) {
  562. O.value(ToObject(pseudounion.Store[ListEditOperation] (
  563. Append { v },
  564. )))
  565. })
  566. ob.value(config.ReturnObject(w, o, e, O))
  567. ob.complete()
  568. })}
  569. }
  570. var listEditKeyCounter = uint64(0)
  571. func generateListEditKey() string {
  572. var i = listEditKeyCounter
  573. listEditKeyCounter++
  574. var key = fmt.Sprint(i)
  575. return key
  576. }
  577. func retrieveKeyAndHook(value Object, p ItemEditViewProvider, store *listEditViewDataStore, h RuntimeHandle, k func(string,Hook)(Observable)) Observable {
  578. var gen_key = doSync1(generateListEditKey)
  579. return retrieveObject(gen_key, h, func(key string) Observable {
  580. return k(key, p(value, store.info(key)))
  581. })
  582. }
  583. type listEditViewDataStore struct {
  584. ItemsMap map[string] *listEditItem
  585. PositionMap map[string] ItemPos
  586. OutputBuffer Subject
  587. }
  588. type listEditItem struct {
  589. Context *context
  590. Dispose func()
  591. Value Object
  592. Extension ctn.Maybe[Widget]
  593. }
  594. func createItemEditDataStore(h RuntimeHandle) *listEditViewDataStore {
  595. return &listEditViewDataStore {
  596. ItemsMap: make(map[string] *listEditItem),
  597. PositionMap: make(map[string] ItemPos),
  598. OutputBuffer: CreateSubject(h, 1),
  599. }
  600. }
  601. func (s *listEditViewDataStore) getCurrentExtension(I qt.Lwi) ctn.Maybe[Widget] {
  602. if cur, ok := I.Current(); ok {
  603. if item, ok := s.ItemsMap[cur]; ok {
  604. return item.Extension
  605. }}
  606. return nil
  607. }
  608. func (s *listEditViewDataStore) output() Observable {
  609. return s.OutputBuffer.Observe()
  610. }
  611. func (s *listEditViewDataStore) info(key string) ItemInfo {
  612. return ItemInfo {
  613. Key: key,
  614. Pos: s.pos(key),
  615. }
  616. }
  617. func (s *listEditViewDataStore) pos(key string) Observable {
  618. var raw = Observable(func(pub DataPublisher) {
  619. var ctx, ob = pub.useInheritedContext()
  620. pub.run(s.output(), ctx, &observer {
  621. value: func(_ Object) {
  622. if pos, ok := s.PositionMap[key]; ok {
  623. ob.value(ToObject(pos))
  624. }
  625. },
  626. error: ob.error,
  627. complete: ob.complete,
  628. })
  629. })
  630. return DistinctUntilItemPosChanged(raw)
  631. }
  632. func (s *listEditViewDataStore) __updateOutput(I qt.Lwi) {
  633. var keys = I.All()
  634. var L = len(keys)
  635. var pm = make(map[string] ItemPos)
  636. var nodes = make([] ListNode, len(keys))
  637. for i, key := range keys {
  638. pm[key] = ItemPos { i, L }
  639. nodes[i].Value = s.ItemsMap[key].Value
  640. }
  641. var list = NodesToList(nodes)
  642. s.PositionMap = pm
  643. s.OutputBuffer.value(Obj(list))
  644. }
  645. type listEditViewInsertion func(I qt.Lwi, key string, widgets ([] qt.Widget))
  646. func listEditViewPrepend() listEditViewInsertion {
  647. return func(I qt.Lwi, key string, widgets ([] qt.Widget)) {
  648. I.Prepend(key, widgets)
  649. }
  650. }
  651. func listEditViewAppend() listEditViewInsertion {
  652. return func(I qt.Lwi, key string, widgets ([] qt.Widget)) {
  653. I.Append(key, widgets)
  654. }
  655. }
  656. func listEditViewInsertAbove(pivot string) listEditViewInsertion {
  657. return func(I qt.Lwi, key string, widgets []qt.Widget) {
  658. I.InsertAbove(pivot, key, widgets)
  659. }
  660. }
  661. func listEditViewInsertBelow(pivot string) listEditViewInsertion {
  662. return func(I qt.Lwi, key string, widgets []qt.Widget) {
  663. I.InsertBelow(pivot, key, widgets)
  664. }
  665. }
  666. func listEditViewMatchInsertionOperation(op_ interface{}) (Object,listEditViewInsertion) {
  667. switch op := op_.(type) {
  668. case Prepend:
  669. return op.Value, listEditViewPrepend()
  670. case Append:
  671. return op.Value, listEditViewAppend()
  672. case InsertAbove:
  673. return op.Value, listEditViewInsertAbove(op.PivotKey)
  674. case InsertBelow:
  675. return op.Value, listEditViewInsertBelow(op.PivotKey)
  676. default:
  677. panic("invalid argument")
  678. }
  679. }
  680. func (s *listEditViewDataStore) insert(key string, I qt.Lwi, i listEditViewInsertion, widgets ([] qt.Widget), ctx *context, dispose func(), val Object, ext ctn.Maybe[Widget]) {
  681. var _, exists = s.ItemsMap[key]
  682. if exists { panic("something went wrong") }
  683. var add, remove = i, func() {
  684. I.Delete(key)
  685. }
  686. add(I, key, widgets)
  687. ctx.registerCleaner(remove)
  688. var item = &listEditItem {
  689. Context: ctx,
  690. Dispose: dispose,
  691. Value: val,
  692. Extension: ext,
  693. }
  694. s.ItemsMap[key] = item
  695. ctx.registerCleaner(func() {
  696. delete(s.ItemsMap, key)
  697. })
  698. s.__updateOutput(I)
  699. I.Update(key)
  700. }
  701. func (s *listEditViewDataStore) update(key string, I qt.Lwi, val Object) {
  702. if val != s.ItemsMap[key].Value {
  703. s.ItemsMap[key].Value = val
  704. s.__updateOutput(I)
  705. I.Update(key)
  706. }
  707. }
  708. func (s *listEditViewDataStore) delete(key_ ctn.Maybe[string], I qt.Lwi) {
  709. for _, key := range getListEditOperandKeys(false, key_, I) {
  710. s.ItemsMap[key].Dispose()
  711. s.__updateOutput(I)
  712. }
  713. }
  714. func (s *listEditViewDataStore) moveUp(key_ ctn.Maybe[string], I qt.Lwi) bool {
  715. var keys = getListEditOperandKeys(true, key_, I)
  716. if len(keys) == 0 {
  717. return false
  718. }
  719. for i, key := range keys {
  720. var ok = I.MoveUp(key)
  721. if ((i == 0) && !(ok)) {
  722. return false
  723. }
  724. s.__updateOutput(I)
  725. }
  726. return true
  727. }
  728. func (s *listEditViewDataStore) moveDown(key_ ctn.Maybe[string], I qt.Lwi) bool {
  729. var keys = ctn.Reverse(getListEditOperandKeys(true, key_, I))
  730. if len(keys) == 0 {
  731. return false
  732. }
  733. for i, key := range keys {
  734. var ok = I.MoveDown(key)
  735. if ((i == 0) && !(ok)) {
  736. return false
  737. }
  738. s.__updateOutput(I)
  739. }
  740. return true
  741. }
  742. func (s *listEditViewDataStore) moveTop(key_ ctn.Maybe[string], I qt.Lwi) {
  743. for s.moveUp(key_, I) {}
  744. }
  745. func (s *listEditViewDataStore) moveBottom(key_ ctn.Maybe[string], I qt.Lwi) {
  746. for s.moveDown(key_, I) {}
  747. }
  748. func (s *listEditViewDataStore) reorder(I qt.Lwi, f func(List)(List), lg Logger) {
  749. var buf ListBuilder
  750. var rev = make(map[Object] string)
  751. for key, item := range s.ItemsMap {
  752. var value = Object(new(ObjectImpl))
  753. *value = *(item.Value)
  754. buf.Append(value)
  755. rev[value] = key
  756. }
  757. var L = len(rev)
  758. var order = make([] string, L)
  759. var reordered = make([] Object, 0)
  760. var reordered_ = f(buf.Collect())
  761. reordered_.ForEach(func(value Object) {
  762. reordered = append(reordered, value)
  763. })
  764. if len(reordered) == L {
  765. for i, value := range reordered {
  766. if key, ok := rev[value]; ok {
  767. delete(rev, value)
  768. order[i] = key
  769. } else {
  770. goto NG
  771. }
  772. }
  773. I.Reorder(order)
  774. return
  775. }
  776. NG:
  777. lg.LogError(errors.New("invalid reorder, ignored"))
  778. }
  779. func getListEditOperandKeys(contiguous bool, key_ ctn.Maybe[string], I qt.Lwi) ([] string) {
  780. if key, ok := key_.Value(); ok {
  781. return [] string { key }
  782. } else {
  783. if contiguous {
  784. return I.ContiguousSelection()
  785. } else {
  786. return I.Selection()
  787. }
  788. }
  789. }