widgetproxy.go 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103
  1. // Copyright 2025 The tk9.0-go Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style
  3. // license that can be found in the LICENSE file.
  4. package tk9_0 // import "modernc.org/tk9.0"
  5. import (
  6. "errors"
  7. "fmt"
  8. )
  9. // OperationCallback is the signature for a WidgetProxy operation callback.
  10. type OperationCallback func(args []string)
  11. // widgetProxy wraps a widget window, providing the means to intercept its
  12. // internal operations, and modify their behaviour.
  13. // For example, it can provide access to a TextWidget's internal 'insert' and
  14. // 'delete' operations.
  15. type widgetProxy struct {
  16. window *Window
  17. originalPath string
  18. commandName uintptr
  19. operations map[string]OperationCallback
  20. }
  21. // newWidgetProxy creates a proxy that facilitates hooking in to
  22. // a widget window's internal operations.
  23. func newWidgetProxy(window *Window) widgetProxy {
  24. if !extensionInitialized("eval") {
  25. fail(errors.New("use of WidgetProxy requires the 'eval' extension to be enabled, but it is not"))
  26. }
  27. proxy := widgetProxy{
  28. window: window,
  29. originalPath: window.String() + "_original",
  30. operations: make(map[string]OperationCallback),
  31. }
  32. // Rename the Tcl command within Tcl:
  33. evalErr(fmt.Sprintf("rename %s %s", window, proxy.originalPath))
  34. // Register an event dispatcher for the window.
  35. proxy.registerEventDispatcher()
  36. return proxy
  37. }
  38. // Close undoes the wrapping of its Window.
  39. // All registered operations are unregistered.
  40. func (proxy *widgetProxy) Close() {
  41. // Unregister all registered operations.
  42. for operation := range proxy.operations {
  43. proxy.Unregister(operation)
  44. }
  45. // Restore the original widget Tcl command.
  46. proxy.unregisterEventDispatcher()
  47. // Restore the Tcl command within Tcl:
  48. evalErr(fmt.Sprintf("rename %s %s", proxy.originalPath, proxy.window))
  49. }
  50. // Register registers a callback for an operation supported by the wrapped Window.
  51. //
  52. // The operation name is widget-specific. It is not possible to validate whether
  53. // the operation name is support by the wrapped widget. If an unsupported
  54. // operation name is used it will be silently ignored.
  55. //
  56. // The operation's arguments are passed to the callback. The callback may perform
  57. // the operation on the wrapped widget by calling the EvalWrapped method with the
  58. // arguments. The arguments may be modified if desired.
  59. func (proxy *widgetProxy) Register(operation string, callback OperationCallback) {
  60. proxy.operations[operation] = callback
  61. }
  62. // Unregister unregisters an operation callback.
  63. // If there is no registered callback for the operation, it is silently ignored.
  64. func (proxy *widgetProxy) Unregister(operation string) {
  65. delete(proxy.operations, operation)
  66. }
  67. // EvalWrapped evaluates the arguments as a raw Tcl string against the wrapped Window.
  68. func (proxy *widgetProxy) EvalWrapped(args []string) {
  69. evalErr(fmt.Sprintf("%s %s", proxy.originalPath, tclSafeStrings(args...)))
  70. }
  71. // TextWidgetProxy wraps a TextWidget.
  72. // It provides the ability to intercept the widget's internal operations (such as
  73. // 'insert' and 'delete'), and modify their behaviour.
  74. type TextWidgetProxy struct {
  75. *TextWidget
  76. widgetProxy
  77. }
  78. // NewTextWidgetProxy creates a TextWidgetProxy, wrapping the
  79. // provided TextWidget.
  80. //
  81. // Note that because the EvalWrapped method evaluates raw Tcl, the "eval" extension
  82. // must be enabled in the main package before calling this function.
  83. func NewTextWidgetProxy(widget *TextWidget) TextWidgetProxy {
  84. return TextWidgetProxy{
  85. TextWidget: widget,
  86. widgetProxy: newWidgetProxy(widget.Window),
  87. }
  88. }