~galfy/helenos/bird-port-mainline

« back to all changes in this revision

Viewing changes to tools/xtui.py

  • Committer: Martin Decky
  • Date: 2009-08-04 11:19:19 UTC
  • Revision ID: martin@uranus.dsrg.hide.ms.mff.cuni.cz-20090804111919-evyclddlr3v5lhmp
Initial import

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#
 
2
# Copyright (c) 2009 Martin Decky
 
3
# All rights reserved.
 
4
#
 
5
# Redistribution and use in source and binary forms, with or without
 
6
# modification, are permitted provided that the following conditions
 
7
# are met:
 
8
#
 
9
# - Redistributions of source code must retain the above copyright
 
10
#   notice, this list of conditions and the following disclaimer.
 
11
# - Redistributions in binary form must reproduce the above copyright
 
12
#   notice, this list of conditions and the following disclaimer in the
 
13
#   documentation and/or other materials provided with the distribution.
 
14
# - The name of the author may not be used to endorse or promote products
 
15
#   derived from this software without specific prior written permission.
 
16
#
 
17
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
 
18
# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 
19
# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 
20
# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
 
21
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 
22
# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 
23
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 
24
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 
25
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 
26
# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
27
#
 
28
"""
 
29
Text User Interface wrapper
 
30
"""
 
31
 
 
32
import sys
 
33
import os
 
34
 
 
35
def call_dlg(dlgcmd, *args, **kw):
 
36
        "Wrapper for calling 'dialog' program"
 
37
        
 
38
        indesc, outdesc = os.pipe()
 
39
        pid = os.fork()
 
40
        if (not pid):
 
41
                os.close(2)
 
42
                os.dup(outdesc)
 
43
                os.close(indesc)
 
44
                
 
45
                dlgargs = [dlgcmd]
 
46
                for key, val in kw.items():
 
47
                        dlgargs.append('--' + key)
 
48
                        dlgargs.append(val)
 
49
                
 
50
                dlgargs += args
 
51
                os.execlp(dlgcmd, *dlgargs)
 
52
        
 
53
        os.close(outdesc)
 
54
        
 
55
        try:
 
56
                errout = os.fdopen(indesc, 'r')
 
57
                data = errout.read()
 
58
                errout.close()
 
59
                pid, status = os.wait()
 
60
        except:
 
61
                # Reset terminal
 
62
                os.system('reset')
 
63
                raise
 
64
        
 
65
        if (not os.WIFEXITED(status)):
 
66
                # Reset terminal
 
67
                os.system('reset')
 
68
                raise EOFError
 
69
        
 
70
        status = os.WEXITSTATUS(status)
 
71
        if (status == 255):
 
72
                raise EOFError
 
73
        
 
74
        return (status, data)
 
75
 
 
76
try:
 
77
        import snack
 
78
        newt = True
 
79
        dialog = False
 
80
except ImportError:
 
81
        newt = False
 
82
        
 
83
        dlgcmd = os.environ.get('DIALOG', 'dialog')
 
84
        if (call_dlg(dlgcmd, '--print-maxsize')[0] != 0):
 
85
                dialog = False
 
86
        else:
 
87
                dialog = True
 
88
 
 
89
width_extra = 13
 
90
height_extra = 11
 
91
 
 
92
def width_fix(screen, width):
 
93
        "Correct width to screen size"
 
94
        
 
95
        if (width + width_extra > screen.width):
 
96
                width = screen.width - width_extra
 
97
        
 
98
        if (width <= 0):
 
99
                width = screen.width
 
100
        
 
101
        return width
 
102
 
 
103
def height_fix(screen, height):
 
104
        "Correct height to screen size"
 
105
        
 
106
        if (height + height_extra > screen.height):
 
107
                height = screen.height - height_extra
 
108
        
 
109
        if (height <= 0):
 
110
                height = screen.height
 
111
        
 
112
        return height
 
113
 
 
114
def screen_init():
 
115
        "Initialize the screen"
 
116
        
 
117
        if (newt):
 
118
                return snack.SnackScreen()
 
119
        
 
120
        return None
 
121
 
 
122
def screen_done(screen):
 
123
        "Cleanup the screen"
 
124
        
 
125
        if (newt):
 
126
                screen.finish()
 
127
 
 
128
def choice_window(screen, title, text, options, position):
 
129
        "Create options menu"
 
130
        
 
131
        maxopt = 0
 
132
        for option in options:
 
133
                length = len(option)
 
134
                if (length > maxopt):
 
135
                        maxopt = length
 
136
        
 
137
        width = maxopt
 
138
        height = len(options)
 
139
        
 
140
        if (newt):
 
141
                width = width_fix(screen, width + width_extra)
 
142
                height = height_fix(screen, height)
 
143
                
 
144
                if (height > 3):
 
145
                        large = True
 
146
                else:
 
147
                        large = False
 
148
                
 
149
                buttonbar = snack.ButtonBar(screen, ('Done', 'Cancel'))
 
150
                textbox = snack.TextboxReflowed(width, text)
 
151
                listbox = snack.Listbox(height, scroll = large, returnExit = 1)
 
152
                
 
153
                cnt = 0
 
154
                for option in options:
 
155
                        listbox.append(option, cnt)
 
156
                        cnt += 1
 
157
                
 
158
                if (position != None):
 
159
                        listbox.setCurrent(position)
 
160
                
 
161
                grid = snack.GridForm(screen, title, 1, 3)
 
162
                grid.add(textbox, 0, 0)
 
163
                grid.add(listbox, 0, 1, padding = (0, 1, 0, 1))
 
164
                grid.add(buttonbar, 0, 2, growx = 1)
 
165
                
 
166
                retval = grid.runOnce()
 
167
                
 
168
                return (buttonbar.buttonPressed(retval), listbox.current())
 
169
        elif (dialog):
 
170
                if (width < 35):
 
171
                        width = 35
 
172
                
 
173
                args = []
 
174
                cnt = 0
 
175
                for option in options:
 
176
                        args.append(str(cnt + 1))
 
177
                        args.append(option)
 
178
                        
 
179
                        cnt += 1
 
180
                
 
181
                kw = {}
 
182
                if (position != None):
 
183
                        kw['default-item'] = str(position + 1)
 
184
                
 
185
                status, data = call_dlg(dlgcmd, '--title', title, '--extra-button', '--extra-label', 'Done', '--menu', text, str(height + height_extra), str(width + width_extra), str(cnt), *args, **kw)
 
186
                
 
187
                if (status == 1):
 
188
                        return ('cancel', None)
 
189
                
 
190
                try:
 
191
                        choice = int(data) - 1
 
192
                except ValueError:
 
193
                        return ('cancel', None)
 
194
                
 
195
                if (status == 0):
 
196
                        return (None, choice)
 
197
                
 
198
                return ('done', choice)
 
199
        
 
200
        sys.stdout.write("\n *** %s *** \n%s\n\n" % (title, text))
 
201
        
 
202
        maxcnt = len(str(len(options)))
 
203
        cnt = 0
 
204
        for option in options:
 
205
                sys.stdout.write("%*s. %s\n" % (maxcnt, cnt + 1, option))
 
206
                cnt += 1
 
207
        
 
208
        sys.stdout.write("\n%*s. Done\n" % (maxcnt, '0'))
 
209
        sys.stdout.write("%*s. Quit\n\n" % (maxcnt, 'q'))
 
210
        
 
211
        while True:
 
212
                if (position != None):
 
213
                        sys.stdout.write("Selection[%s]: " % str(position + 1))
 
214
                else:
 
215
                        sys.stdout.write("Selection: ")
 
216
                inp = sys.stdin.readline()
 
217
                
 
218
                if (not inp):
 
219
                        raise EOFError
 
220
                
 
221
                if (not inp.strip()):
 
222
                        if (position != None):
 
223
                                return (None, position)
 
224
                        continue
 
225
                
 
226
                if (inp.strip() == 'q'):
 
227
                        return ('cancel', None)
 
228
                
 
229
                try:
 
230
                        choice = int(inp.strip())
 
231
                except ValueError:
 
232
                        continue
 
233
                
 
234
                if (choice == 0):
 
235
                        return ('done', 0)
 
236
                
 
237
                if (choice < 1) or (choice > len(options)):
 
238
                        continue
 
239
                
 
240
                return (None, choice - 1)
 
241
 
 
242
def error_dialog(screen, title, msg):
 
243
        "Print error dialog"
 
244
        
 
245
        width = len(msg)
 
246
        
 
247
        if (newt):
 
248
                width = width_fix(screen, width)
 
249
                
 
250
                buttonbar = snack.ButtonBar(screen, ['Ok'])
 
251
                textbox = snack.TextboxReflowed(width, msg)
 
252
                
 
253
                grid = snack.GridForm(screen, title, 1, 2)
 
254
                grid.add(textbox, 0, 0, padding = (0, 0, 0, 1))
 
255
                grid.add(buttonbar, 0, 1, growx = 1)
 
256
                grid.runOnce()
 
257
        elif (dialog):
 
258
                call_dlg(dlgcmd, '--title', title, '--msgbox', msg, '6', str(width + width_extra))
 
259
        else:
 
260
                sys.stdout.write("\n%s: %s\n" % (title, msg))