c.py 8.08 KB
Newer Older
Fjen Undso's avatar
Fjen Undso committed
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
#!/usr/bin/env python3
import logging
from curses import wrapper
import curses
import time


class CursesHandler(logging.Handler):
    def __init__(self, screen):
        logging.Handler.__init__(self)
        maxy, maxx = screen.getmaxyx()
        win_log_border = screen.subwin(5, maxx, maxy - 5, 0)
        win_log_border.border(0)
        win_log = win_log_border.subwin(3, maxx - 2, maxy - 4, 1)
        win_log.scrollok(True)
        win_log.idlok(True)
        win_log.leaveok(True)
        self.screen = win_log
        formatter = logging.Formatter(
            '%(name) -10s | %(levelname) -5s | %(message)s')
        self.setFormatter(formatter)

    def emit(self, record):
        try:
            msg = self.format(record)
            screen = self.screen
            fs = "\n%s"
            screen.addstr(fs % msg)
            screen.refresh()
        except (KeyboardInterrupt, SystemExit):
            raise
        except BaseException:
            self.handleError(record)


class NumberRange:
37
    def __init__(self, window, *, row=0, col=0, value=0, text='', attr=curses.A_STANDOUT, min_value=0, max_value=255, prev_key=None, next_key=None):
Fjen Undso's avatar
Fjen Undso committed
38
39
40
        self.window = window
        self.row = row
        self.col = col
41
42
43
44
45
        self.value = value
        self.text = text
        self.attr = attr
        self.min = min_value
        self.max = max_value
Fjen Undso's avatar
Fjen Undso committed
46
47
48
49
50
51
52
53
        self.focus = False
        self.prev_key = prev_key
        self.next_key = next_key
        self.draw()

    def draw(self):
        attr = curses.A_NORMAL
        if self.focus:
54
            attr = self.attr
Fjen Undso's avatar
Fjen Undso committed
55
        self.window.move(self.row, self.col)
56
        self.window.addstr(self.text + "<")
Fjen Undso's avatar
Fjen Undso committed
57
        formatter = "{:>" + str(len(str(self.max))) + "}"
58
        self.window.addstr(formatter.format(self.value), attr)
Fjen Undso's avatar
Fjen Undso committed
59
60
61
62
63
64
65
66
67
68
        self.window.addstr(">")
        self.window.refresh()

    def send_key(self, key):
        if self.focus:
            if key == self.prev_key:
                self.decr()
            elif key == self.next_key:
                self.incr()
            elif key.isdigit():
69
                if len(str(self.value)) == len(str(self.max)):
Fjen Undso's avatar
Fjen Undso committed
70
71
72
73
                    # reset number if field is full
                    self.set(int(key))
                else:
                    # add number on right side
74
                    self.set(int(str(self.value) + key))
Fjen Undso's avatar
Fjen Undso committed
75

76
77
    def set(self, value):
        self.value = min(value, self.max)
Fjen Undso's avatar
Fjen Undso committed
78
        self.value = max(self.value, self.min)
Fjen Undso's avatar
Fjen Undso committed
79
80
81
        self.draw()

    def incr(self):
82
        self.set(self.value + 1)
Fjen Undso's avatar
Fjen Undso committed
83
84

    def decr(self):
85
        self.set(self.value - 1)
Fjen Undso's avatar
Fjen Undso committed
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

    def toggle_focus(self):
        self.focus = not self.focus
        self.draw()


class CheckBox:
    def __init__(self, window, *, row=0, col=0, text=None, toggle_key=None):
        self.window = window
        self.row = row
        self.col = col
        self.text = text
        self.toggle_key = toggle_key
        self.focus = False
        self.active = False
        self.draw()

    def draw(self):
        attr = curses.A_NORMAL
        if self.focus:
            attr = curses.A_STANDOUT
        self.window.move(self.row, self.col)
        if self.active:
            self.window.addstr("(X) " + self.text, attr)
        else:
            self.window.addstr("( ) " + self.text, attr)
        self.window.refresh()

    def send_key(self, key):
        if self.focus and key == self.toggle_key:
            self.toggle()

    def toggle(self):
        self.active = not self.active
        self.draw()

    def toggle_focus(self):
        self.focus = not self.focus
        self.draw()


class FocusSwitcher:
    def __init__(self, elements=[], prev_key=None, next_key=None):
        self.elements = elements
        self.prev_key = prev_key
        self.next_key = next_key
        self.focus = False

    def toggle_focus(self):
        if self.focus:
            for e in self.elements:
                if e.focus:
                    e.toggle_focus()
        else:
            self.elements[0].toggle_focus()
        self.focus = not self.focus

    def add(self, element):
        self.elements.append(element)

    def send_key(self, key):
        if self.focus:
            if key == self.prev_key:
                self.prev()
            elif key == self.next_key:
                self.next()
            else:
                for e in self.elements:
                    e.send_key(key)

    def next(self):
        for i in range(len(self.elements)):
            if self.elements[i].focus:
                self.elements[i].toggle_focus()
                if i == len(self.elements) - 1:
                    self.elements[0].toggle_focus()
                else:
                    self.elements[i + 1].toggle_focus()
                break

    def prev(self):
        for i in range(len(self.elements)):
            if self.elements[i].focus:
                self.elements[i].toggle_focus()
                self.elements[i - 1].toggle_focus()
                break


Fjen Undso's avatar
Fjen Undso committed
174
175
176
177
178
179
180
181
class ProgressBar:
    def __init__(self, window, *, row=0, col=0, width=0, height=0, text='',
                 max_value=100, attr=curses.A_STANDOUT, prev_key=None, next_key=None):
        self.row = row
        self.col = col
        self.width = width
        self.height = height
        self.max = max_value
Fjen Undso's avatar
Fjen Undso committed
182
        self.value = 0
Fjen Undso's avatar
Fjen Undso committed
183
        self.attr = attr
Fjen Undso's avatar
Fjen Undso committed
184
185
        self.focus = True
        self.text = text
Fjen Undso's avatar
Fjen Undso committed
186
187
188
        self.prev_key = prev_key
        self.next_key = next_key
        self.window = window.subwin(height, width, row, col)
Fjen Undso's avatar
Fjen Undso committed
189
        self.draw()
Fjen Undso's avatar
Fjen Undso committed
190
191
192
193
194

    def toggle_focus(self):
        pass

    def draw(self):
Fjen Undso's avatar
Fjen Undso committed
195
196
197
198
199
200
201
202
203
        self.window.clear()
        # draw frame
        self.window.border(0)
        if len(self.text) > self.width:
            self.window.addstr(self.text)
        else:
            self.window.addstr(0, (self.width - len(self.text)) // 2, self.text)

        # draw bar
Fjen Undso's avatar
Fjen Undso committed
204
205
206
207
208
209
210
211
        top = self.height - 1 - int(self.value / self.max * (self.height - 2))
        bottom = self.height - 1
        for i in range(top, bottom):
            self.window.addstr(i, 1, '#' * (self.width - 2), self.attr)
        self.window.refresh()

    def set(self, value):
        self.value = min(value, self.max)
Fjen Undso's avatar
Fjen Undso committed
212
        self.value = max(self.value, 0)
Fjen Undso's avatar
Fjen Undso committed
213
214
215
216
217
218
219
220
221
222
223
224
225
        self.draw()

    def incr(self):
        self.set(self.value + 1)

    def decr(self):
        self.set(self.value - 1)

    def send_key(self, key):
        if key == self.prev_key:
            self.decr()
        elif key == self.next_key:
            self.incr()
Fjen Undso's avatar
Fjen Undso committed
226
227
228
229
230
231


def main(stdscr):
    stdscr.clear()
    # hide cursor
    curses.curs_set(0)
Fjen Undso's avatar
Fjen Undso committed
232
233
234
235
236
237
    # init colors
    curses.start_color()
    curses.use_default_colors()
    curses.init_pair(curses.COLOR_RED, curses.COLOR_RED, curses.COLOR_WHITE)
    curses.init_pair(curses.COLOR_GREEN, curses.COLOR_GREEN, curses.COLOR_WHITE)
    curses.init_pair(curses.COLOR_BLUE, curses.COLOR_BLUE, curses.COLOR_WHITE)
Fjen Undso's avatar
Fjen Undso committed
238
239
240
241
242
243

    # logging
    logger = logging.getLogger(__name__)
    logger.addHandler(CursesHandler(stdscr))
    logger.setLevel(logging.INFO)

Fjen Undso's avatar
Fjen Undso committed
244
    numbers_text = ['R', 'G', 'B', 'W']
245
246
247
248
249
250
251
252
253
254
    progress_bars = [
        ProgressBar(stdscr,
            row=0,
            col=i*8,
            width=5,
            height=12,
            max_value=255,
            prev_key='KEY_DOWN',
            next_key='KEY_UP',
            text=numbers_text[i]) for i in range(len(numbers_text))]
Fjen Undso's avatar
Fjen Undso committed
255
256
257
    numbers = [
        NumberRange(
            stdscr,
Fjen Undso's avatar
Fjen Undso committed
258
259
260
261
            col = i*8,
            row=12,
            value=i,
            prev_key='KEY_DOWN',
262
263
264
            next_key='KEY_UP') for i in range(len(numbers_text))]
    fs_pbn = [FocusSwitcher(i) for i in zip(numbers, progress_bars)]
    fs_n = FocusSwitcher(fs_pbn, prev_key='KEY_LEFT', next_key='KEY_RIGHT')
Fjen Undso's avatar
Fjen Undso committed
265

Fjen Undso's avatar
Fjen Undso committed
266
267
268
    checkboxes = [
        CheckBox(
            stdscr,
Fjen Undso's avatar
Fjen Undso committed
269
270
            col=0,
            row=i+13,
Fjen Undso's avatar
Fjen Undso committed
271
            toggle_key=' ',
Fjen Undso's avatar
Fjen Undso committed
272
273
            text='ESP' +
            str(i)) for i in range(1,9)]
Fjen Undso's avatar
Fjen Undso committed
274
    fs_cb = FocusSwitcher(checkboxes, prev_key='KEY_UP', next_key='KEY_DOWN')
275

Fjen Undso's avatar
Fjen Undso committed
276
277
278
279
280
281
282
283
284
285
286
287
    fs_main = FocusSwitcher([fs_n, fs_cb], prev_key='\t')
    fs_main.toggle_focus()

    stdscr.refresh()
    while True:
        k = stdscr.getkey()
        logger.info(k)
        fs_main.send_key(k)


if __name__ == '__main__':
    wrapper(main)