pgup, pgdn support, and returns a book thing
[public/library.git] / librarian.py
1 #!/usr/bin/env python
2
3 import curses
4
5 stdscr=0
6
7 def menutest(s, l):
8     global stdscr
9     stdscr=s
10     curses.curs_set(0)
11     (rows,cols)=stdscr.getmaxyx()
12     w = curses.newwin(10,40,(rows-10)/2, (cols-40)/2)
13
14     menu(w, l)
15     
16     curses.curs_set(1)
17
18 # item is a list of (string, callable) tuples
19 def menu(w, items):
20     w.keypad(1)
21     highlight=0
22     redrawMenu(w,items,highlight)
23
24     w.refresh()
25     ch=w.getch()
26     while (ch!=113 and ch!=27): # leave on q or ESC
27         if ch==curses.KEY_UP:
28             if highlight!=0:
29                 w.chgat(highlight,0, 0)
30                 highlight -= 1
31                 while(items[highlight][0]==""):
32                     highlight -=1
33                 w.chgat(highlight,0, curses.A_REVERSE)
34         if ch==curses.KEY_DOWN:
35             if highlight!=len(items)-1:
36                 w.chgat(highlight,0, 0)
37                 highlight += 1
38                 while(items[highlight][0]==""):
39                     highlight +=1
40                 w.chgat(highlight,0, curses.A_REVERSE)
41         if ch==curses.KEY_PPAGE:
42             w.chgat(highlight,0, 0)
43             highlight = 0
44             w.chgat(highlight,0, curses.A_REVERSE)
45         if ch==curses.KEY_NPAGE:
46             w.chgat(highlight,0, 0)
47             highlight = len(items)-1
48             w.chgat(highlight,0, curses.A_REVERSE)
49         if ch==114 or ch==10:
50             (s,f)=items[highlight]
51             f()
52             redrawMenu(w,items,highlight)
53         w.refresh()
54         ch = w.getch()
55
56 def redrawMenu(w,items,highlight):
57     i=0
58     for (mitem,fun) in items:
59         w.addstr(i,0, mitem)
60         i +=1
61     w.chgat(highlight, 0, curses.A_REVERSE)
62     w.refresh()
63
64 # items is a list of (label, value) pairs
65 def redrawForm(w, caption, items, buttonlabel, m):
66     (y,x)=w.getmaxyx()
67     w.border()
68     curses.curs_set(1)
69     w.addstr(1,1,caption)
70     r=3
71     for l,v in items:
72         c = m-len(l)-2
73         w.addstr(r,c,l+":")
74         w.addstr(r,m,v)
75         r+=2
76     w.addstr(r,x-len(buttonlabel)-len("<cancel>")-6, "<cancel>  <"+buttonlabel+">")
77     w.refresh()
78
79 def lists_to_dict(l1, l2):
80     book = {}
81     for k,v in zip(l1,l2):
82         if v!="":
83             book[k.lower()]=v
84     return book
85
86
87 #the final form for book data entry - takes caption and book info.
88 def bookForm(caption, book, buttonlabel):
89     labels = ["ISBN", "LCCN", "Title", "Subtitle", "Authors", "Edition",
90               "Publisher", "Publish Date", "Publish Year", "Publish Month", "Publish location",
91               "Pages", "Pagination", "Weight"]
92     entries = []
93     m = 0
94     for l in labels:
95         m = max(len(l),m)
96         if l.lower() in book:
97             entries.append(book[l.lower()])
98         else:
99             entries.append("")
100     m+=4
101
102     w=curses.newwin(34,70,1,10)
103     (y,x)=w.getmaxyx()
104     w.keypad(1)
105     redrawForm(w,caption,zip(labels,entries),buttonlabel,m)
106     bcol = [x-len(buttonlabel)-len("<cancel>")-6, x-len(buttonlabel)-4]
107     bwidth = [8,len(buttonlabel)+2]
108     
109     highlight=0
110     b = -1
111     r=3
112     w.chgat(r,m,x-m-2,curses.A_UNDERLINE)
113     w.move(r,m+len(entries[highlight]))
114     cursor = len(entries[highlight])
115     ch = w.getch()
116     while (1==1):
117         if ch==27: #escape key
118             curses.curs_set(0)
119             w.clear()
120             w.refresh()
121             return {}
122         if ch==curses.KEY_UP:
123             if highlight == len(labels):
124                 w.chgat(r,bcol[b],bwidth[b],curses.A_NORMAL)
125                 highlight = len(labels)-1
126                 b = -1
127                 r=3+2*highlight
128                 w.chgat(r,m,x-m-2,curses.A_UNDERLINE)
129                 cursor = len(entries[highlight])
130                 w.move(r,m+cursor)
131                 curses.curs_set(1)
132             elif highlight!=0:
133                 w.chgat(r,m,x-m-2,curses.A_NORMAL)
134                 highlight -= 1
135                 r=3+2*highlight
136                 w.chgat(r,m,x-m-2,curses.A_UNDERLINE)
137                 cursor = len(entries[highlight])
138                 w.move(r,m+cursor)
139         elif ch==curses.KEY_PPAGE:
140             w.chgat(r,m,x-m-2,curses.A_NORMAL)
141             highlight=0
142             b=-1
143             r=3+2*highlight
144             w.chgat(r,m,x-m-2,curses.A_UNDERLINE)
145             cursor = len(entries[highlight])
146             w.move(r,m+cursor)
147             curses.curs_set(1)
148         elif ch==curses.KEY_DOWN:
149             if highlight >= len(labels) -1:
150                 highlight = len(labels)
151                 b += 1
152                 b = min(b,1)
153                 curses.curs_set(0)
154                 w.chgat(r,m,x-m-2,curses.A_NORMAL)
155                 r = y-3
156                 w.chgat(r,bcol[b],bwidth[b],curses.A_REVERSE)
157             else:
158                 w.chgat(r,m,x-m-2,curses.A_NORMAL)
159                 highlight += 1
160                 r=3+2*highlight
161                 w.chgat(r,m,x-m-2,curses.A_UNDERLINE)
162                 cursor = len(entries[highlight])
163                 w.move(r,m+cursor)
164         elif ch==curses.KEY_NPAGE:
165             if highlight!=len(labels):
166                 highlight = len(labels)
167                 b += 1
168                 b = min(b,1)
169                 curses.curs_set(0)
170                 w.chgat(r,m,x-m-2,curses.A_NORMAL)
171                 r = y-3
172                 w.chgat(r,bcol[b],bwidth[b],curses.A_REVERSE)
173         elif ch==curses.KEY_LEFT:
174             if highlight == len(labels):
175                 w.chgat(r,bcol[b],bwidth[b],curses.A_NORMAL)
176                 b=0
177                 w.chgat(r,bcol[b],bwidth[b],curses.A_REVERSE)
178             else:
179                 if cursor>0:
180                     cursor-=1
181                     w.move(r,m+cursor)
182         elif ch==curses.KEY_RIGHT:
183             if highlight == len(labels):
184                 w.chgat(r,bcol[b],bwidth[b],curses.A_NORMAL)
185                 b=1
186                 w.chgat(r,bcol[b],bwidth[b],curses.A_REVERSE)
187             else:
188                 if cursor < len(entries[highlight]):
189                     cursor+=1
190                     w.move(r,m+cursor)
191         elif ch>31 and ch<127:
192             if highlight != len(labels):
193                 entries[highlight]=entries[highlight][:cursor] + curses.keyname(ch) + entries[highlight][cursor:]
194                 cursor+=1
195                 w.addnstr(r,m, entries[highlight]+(" "*40), x-m-2)
196                 w.chgat(r,m,x-m-2,curses.A_UNDERLINE)
197                 w.move(r,m+cursor)
198         elif ch==curses.KEY_BACKSPACE:
199             if highlight != len(labels) and cursor!=0:
200                 cursor-=1
201                 entries[highlight]=entries[highlight][:cursor] + entries[highlight][cursor+1:]
202                 w.addnstr(r,m, entries[highlight]+(" "*40), x-m-2)
203                 w.chgat(r,m,x-m-2,curses.A_UNDERLINE)
204                 w.move(r,m+cursor)
205         elif ch==curses.KEY_DC:
206             if highlight != len(labels):
207                 entries[highlight]=entries[highlight][:cursor] + entries[highlight][cursor+1:]
208                 w.addnstr(r,m, entries[highlight]+(" "*40), x-m-2)
209                 w.chgat(r,m,x-m-2,curses.A_UNDERLINE)
210                 w.move(r,m+cursor)
211         elif ch==curses.KEY_HOME:
212             if highlight != len(labels):
213                 cursor=0
214                 w.move(r,m+cursor)
215         elif ch==curses.KEY_END:
216             if highlight != len(labels):
217                 cursor=len(entries[highlight])
218                 w.move(r,m+cursor)
219         elif ch==10:
220             if b != -1:
221                 if b == 0:
222                     w.clear()
223                     w.refresh()
224                     return {}
225                 elif b == 1:
226                     w.clear()
227                     w.refresh()
228                     return lists_to_dict(labels,entries)
229             elif highlight == len(labels)-1:
230                 highlight = len(labels)
231                 b=0
232                 curses.curs_set(0)
233                 w.chgat(r,m,x-m-2,curses.A_NORMAL)
234                 r = y-3
235                 w.chgat(r,bcol[b],bwidth[b],curses.A_REVERSE)
236             else:
237                 w.chgat(r,m,x-m-2,curses.A_NORMAL)
238                 highlight += 1
239                 r=3+2*highlight
240                 w.chgat(r,m,x-m-2,curses.A_UNDERLINE)
241                 cursor = len(entries[highlight])
242                 w.move(r,m+cursor)
243
244
245         w.refresh()
246         ch = w.getch()
247
248     curses.curs_set(0)
249     w.clear()
250     w.refresh()
251     return {}
252
253
254 def addForm():
255     book = {"title":"A Book of Tests", "pages":"123"}
256     book = bookForm("Add a book", book, "add")
257     bookForm("View the book", book, "done")
258
259
260 def updateMenu():
261     w=curses.newwin(1,50,10,10)
262     w.addstr("I will be used to update or modify book records")
263     w.refresh()
264
265 def deleteMenu():
266     w=curses.newwin(1,50,10,10)
267     w.addstr("I will be used to delete book records")
268     w.refresh()
269
270 def browseMenu():
271     w=curses.newwin(1,50,10,10)
272     w.addstr("I will be used to browse book records")
273     w.refresh()
274
275 m = [("Browse Library", browseMenu),
276      ("Add Book or other item", addForm),
277      ("Modify/Update record", updateMenu),
278      ("Remove book from catalogue", deleteMenu),
279      ("",exit),
280      ("Exit", exit)]
281 curses.wrapper(menutest, m)