-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathwindow.go
189 lines (167 loc) · 4.95 KB
/
window.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
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
// Licensed under the GPL-v3
// Copyright: Sebastian Tilders <[email protected]> (c) 2019
package ncurses
import (
// #cgo LDFLAGS: -lncursesw
// #include <binding.h>
// #include <curses.h>
"C"
"fmt"
"unsafe"
"errors"
)
// Type which holds information about the current cursor position
type Position struct {
X uint16
Y uint16
}
// Alias for position which holds information about terminal size
type Size Position
type winst *C.struct__win_st
func (p1 Position) greater(p2 Position) bool {
return p1.Y > p2.Y|| p1.X > p2.X
}
// Holds information about the currently used Terminal and works as a handle for all ncurses
// related function calls.
type Window struct {
name string
chandle unsafe.Pointer
max Size
begin Position
cursor Position
// Set to true, if you want to automatically refresh the window after it recieved a command
AutoRefresh bool
}
// Creates a new window. Make sure the windows do not overlap.
// Notice: Fields for position and Size are swapped. The first parameter sets the column count, not the line count.
// TODO(sebi2020): Add DelWindow method
func NewWindow(name string, begin Position, end Size) (*Window, error) {
if !initialized {
return nil,errors.New("Ncurses is not initialized")
}
if begin.greater(Position(wins["stdscr"].max)) || Position(end).greater(Position(wins["stdscr"].max)) {
return nil,errors.New(fmt.Sprintf("Window dimensions greater than terminal size\nMain Size: %v, Window start: %v,Window end:%v",wins["stdscr"].max,begin,end))
}
w := &Window{
name:name,
begin:begin,
max:end,
cursor:Position{0,0},
AutoRefresh:false,
}
w.chandle = unsafe.Pointer(C.newwin(C.int(end.Y),C.int(end.X),C.int(begin.Y),C.int(begin.X)))
C.syncok(winst(w.chandle),true)
wins.append(w)
return w,nil
}
// Implementation of the Stringer Interface for type Window
func (w *Window) String() string { // Implements interface Stringer {
return fmt.Sprintf("%T{%s %s}", w,w.max,w.cursor)
}
// Implementation of the Stringer Interface for type Position
func (p Position) String() string {
return fmt.Sprintf("(%d, %d)", p.Y,p.X);
}
// Implementation of the Stringer Interface for type Size
func (s Size) String() string {
return fmt.Sprintf("<%d, %d>", s.Y,s.X)
}
func (w *Window) sendCommand(c Command, refresh bool) {
GetComChannel() <-c
if refresh {
w.Refresh()
}
}
// Retrieves the terminal height and width (gathered through Terminfo & Termcap DB)
func(w *Window) GetMaxYX() (Size,error) {
if !initialized {
return Size{},errors.New("Not initialized");
}
lines,cols := C.int(0),C.int(0)
C.bind_get_maxyx((*C.struct__win_st)(w.chandle),&lines,&cols)
lines_go, cols_go := uint16(lines),uint16(cols)
w.max = Size{cols_go,lines_go}
return w.max,nil
}
// Returns name of the window from which this method is called.
func (w *Window) GetName() string {
return w.name;
}
// Retrieves one Rune from user.
func (w *Window) Getch() rune {
ret := C.wgetch((*C.struct__win_st)(w.chandle));
return rune(ret)
}
// Moves the the cursor relative to the beginning of w *Window.
func (w *Window) Move(y,x uint16) {
com := Command{
Name: MOVE,
Window:w,
Value: Position{x,y},
Scope: LOCAL,
}
w.sendCommand(com,w.AutoRefresh)
}
// Refreshes terminal screen. Outputs all content written since last call to Refresh()
func (w *Window) Refresh() {
com := Command{
Name: REFRESH,
Window:w,
Scope:LOCAL,
}
w.sendCommand(com,false)
}
// Implements the Writer interface.
// Allows you to write strings with fmt.Fprintf(window, format,...args) to the associated window.
func (w *Window) Write(p []byte) (n int, err error) {
if !initialized {
return 0,errors.New("ncurses is not initialized")
}
n = len(p)
com := Command{
Name: ADD,
Window:w,
Value:string(p),
Scope:LOCAL,
}
w.sendCommand(com,w.AutoRefresh)
return n,nil
}
// Inserts a string at the current position.
func (w *Window) Insert(format string, val ...interface{}) {
com := Command{
Name: INSERT,
Window: w,
Value: fmt.Sprintf(format,val...),
Scope: LOCAL,
}
w.sendCommand(com,w.AutoRefresh)
}
// Allow you to enable window scrolling. Must be called before calling Scroll(n int)
func (w *Window) SetScrolling(enable bool) {
com := Command{
Name: SCROLLOK,
Window: w,
Value: enable,
Scope: LOCAL,
}
w.sendCommand(com,false)
}
func (w *Window) Scroll(n int) {
com := Command{
Name: SCROLL,
Window: w,
Value: n,
Scope: LOCAL,
}
w.sendCommand(com,w.AutoRefresh)
}
// Deletes all content of w *Window.
func (w *Window) Clear() {
com := Command{
Name: CLEAR,
Window: w,
Scope: LOCAL,
}
w.sendCommand(com,w.AutoRefresh)
}