File: boxadapter.go

package info (click to toggle)
golang-github-gcla-gowid 1.4.0-1
  • links: PTS, VCS
  • area: main
  • in suites: bookworm, forky, sid, trixie
  • size: 1,456 kB
  • sloc: makefile: 4
file content (135 lines) | stat: -rw-r--r-- 3,843 bytes parent folder | download
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
// Copyright 2019-2022 Graham Clark. All rights reserved.  Use of this source code
// is governed by the MIT license that can be found in the LICENSE file.

// Package boxadapter provides a widget that will allow a box widget to be used
// in a flow context. Based on urwid's BoxAdapter - http://urwid.org/reference/widget.html#boxadapter.
package boxadapter

import (
	"fmt"

	"github.com/gcla/gowid"
	tcell "github.com/gdamore/tcell/v2"
)

//======================================================================

type Widget struct {
	gowid.IWidget
	rows int
	*gowid.Callbacks
	gowid.SubWidgetCallbacks
}

type IBoxAdapter interface {
	Rows() int
}

type IBoxAdapterWidget interface {
	gowid.ICompositeWidget
	IBoxAdapter
}

func New(inner gowid.IWidget, rows int) *Widget {
	res := &Widget{
		IWidget: inner,
		rows:    rows,
	}
	res.SubWidgetCallbacks = gowid.SubWidgetCallbacks{CB: &res.Callbacks}
	var _ gowid.IWidget = res
	var _ gowid.IComposite = res
	var _ IBoxAdapter = res
	return res
}

func (w *Widget) String() string {
	return fmt.Sprintf("boxadapter[%v]", w.SubWidget())
}

func (w *Widget) SubWidget() gowid.IWidget {
	return w.IWidget
}

func (w *Widget) SetSubWidget(wi gowid.IWidget, app gowid.IApp) {
	w.IWidget = wi
	gowid.RunWidgetCallbacks(w, gowid.SubWidgetCB{}, app, w)
}

func (w *Widget) Rows() int {
	return w.rows
}

func (w *Widget) SetRows(rows int, app gowid.IApp) {
	w.rows = rows
}

func (w *Widget) RenderSize(size gowid.IRenderSize, focus gowid.Selector, app gowid.IApp) gowid.IRenderBox {
	return RenderSize(w, size, focus, app)
}

func (w *Widget) Render(size gowid.IRenderSize, focus gowid.Selector, app gowid.IApp) gowid.ICanvas {
	return Render(w, size, focus, app)
}

func (w *Widget) SubWidgetSize(size gowid.IRenderSize, focus gowid.Selector, app gowid.IApp) gowid.IRenderSize {
	return SubWidgetSize(w, size, focus, app)
}

func (w *Widget) UserInput(ev interface{}, size gowid.IRenderSize, focus gowid.Selector, app gowid.IApp) bool {
	return UserInput(w, ev, size, focus, app)
}

//======================================================================

// SubWidgetSize is the same as RenderSize for this widget - the inner widget will
// be rendered as a box with the specified number of columns and the widget's
// set number of rows.
func SubWidgetSize(w IBoxAdapter, size gowid.IRenderSize, focus gowid.Selector, app gowid.IApp) gowid.IRenderSize {
	return RenderSize(w, size, focus, app)
}

func RenderSize(w IBoxAdapter, size gowid.IRenderSize, focus gowid.Selector, app gowid.IApp) gowid.IRenderBox {
	switch sz := size.(type) {
	case gowid.IRenderFlowWith:
		return gowid.RenderBox{
			C: sz.FlowColumns(),
			R: w.Rows(),
		}
	default:
		panic(gowid.WidgetSizeError{Widget: w, Size: size, Required: "gowid.IRenderFlow"})
	}
}

func Render(w IBoxAdapterWidget, size gowid.IRenderSize, focus gowid.Selector, app gowid.IApp) gowid.ICanvas {
	rsize := RenderSize(w, size, focus, app)
	res := w.SubWidget().Render(rsize, focus, app)

	return res
}

// Ensure that a valid mouse interaction with a flow widget will result in a
// mouse interaction with the subwidget
func UserInput(w IBoxAdapterWidget, ev interface{}, size gowid.IRenderSize, focus gowid.Selector, app gowid.IApp) bool {
	if _, ok := size.(gowid.IRenderFlowWith); !ok {
		panic(gowid.WidgetSizeError{Widget: w, Size: size, Required: "gowid.IRenderFlow"})
	}

	box := RenderSize(w, size, focus, app)

	if evm, ok := ev.(*tcell.EventMouse); ok {
		_, my := evm.Position()
		if my < box.BoxRows() && my >= 0 {
			return gowid.UserInputIfSelectable(w.SubWidget(), ev, box, focus, app)
		}
	} else {
		return gowid.UserInputIfSelectable(w.SubWidget(), ev, box, focus, app)
	}

	return false
}

//======================================================================
// Local Variables:
// mode: Go
// fill-column: 110
// End: