Added home and end to browser window.
[public/library.git] / form.py
1 import curses
2 import sys
3
4 class formWindow:
5     mx = my = 0
6     hl = 0
7     bt = -1
8     cursor = 0
9     textStart = 0
10     left = 0
11     top = 2
12     row = 2
13     caption = "Form"
14     blabel = "Done"
15     labels = ["label1"]
16     entries = []
17
18     commands = [('pU', 'top'),('pD', 'bottom'),('Es', 'cancel')]
19
20     def clear(self):
21         self.w.erase()
22         self.w.refresh()
23
24     def __init__(self,window,helpbar,book={}):
25         self.w = window
26         self.w.resize(len(self.labels)+6,50)
27         self.hb = helpbar
28         self.updateEntries(book)
29         self.updateGeometry()
30
31     def updateGeometry(self):
32         (self.my, self.mx) = self.w.getmaxyx()
33         self.left=0
34         for l in self.labels:
35             self.left = max(len(l),self.left)
36         self.left += 4
37         self.width = self.mx-self.left-2
38         self.top = 2
39         # next, the buttons
40         self.bcol = [self.mx-len(self.blabel)-14, self.mx-len(self.blabel)-4]
41         self.bwidth = [8,len(self.blabel)+2]
42
43     def updateEntries(self,book):
44         self.entries=[]
45         for l in self.labels:
46             if l.lower() in book:
47                 self.entries.append(str(book[l.lower()]))
48             else:
49                 self.entries.append("")
50
51     def refresh(self):
52         self.hb.commands = self.commands
53         self.hb.refresh()
54         self.updateGeometry()
55         self.w.box()
56         self.w.addstr(0,(self.mx-len(self.caption))//2,self.caption)
57         r=self.top
58         for l in self.labels:
59             c = self.left-len(l)-2
60             self.w.addstr(r,c,l+":")
61             self.drawRow(r-self.top)
62             r+=1
63         self.w.addstr(r+1,self.bcol[0], "<cancel>  <"+self.blabel+">")
64         self.w.refresh()
65
66     def drawRow(self,row):
67         r = self.top + row
68         self.w.addnstr(r,self.left, self.entries[row]+" "*self.width, self.width)
69
70     def highlight(self):
71         if self.bt == -1:
72             self.w.chgat(self.row, self.left, self.width, curses.A_UNDERLINE)
73             self.mvCursor(0)
74             curses.curs_set(1)
75         else:
76             self.w.chgat(self.row, self.bcol[self.bt], self.bwidth[self.bt], curses.A_REVERSE)
77             curses.curs_set(0)
78
79     def unHighlight(self):
80         self.w.chgat(self.row,1,self.mx-2,curses.A_NORMAL)
81
82     def mvHighlight(self,delta):
83         self.unHighlight()
84         new = self.hl+delta
85         new = max(new,0)
86         new = min(new,len(self.labels))   # the extra is for the buttons
87         self.hl = new
88         self.row = self.hl + self.top
89         if new == len(self.labels):
90             self.bt =1
91             self.bt = min(self.bt,1)
92             self.row+=1
93         else:
94             self.mvCursor(+len(self.entries[self.hl]))
95             self.bt=-1
96         self.highlight()
97
98     def mvCursor(self,delta):
99         n = self.cursor + delta
100         n = max(n,0)
101         n = min(n,len(self.entries[self.hl]))
102         self.cursor = n
103         col = self.left + self.cursor - self.textStart
104         if col >= self.left and col < self.left+self.width:
105             self.w.move(self.row,col)
106
107     def insert(self,ch):
108         c = self.cursor
109         #sys.stderr.write(str(type(ch)))
110         self.entries[self.hl]=self.entries[self.hl][:c] +ch.decode('utf-8')+  self.entries[self.hl][c:]
111         self.drawRow(self.hl)
112         self.mvCursor(+1)
113         self.highlight()
114
115     def backspace(self):
116         if self.cursor>0:
117             self.entries[self.hl]=self.entries[self.hl][:self.cursor-1] + self.entries[self.hl][self.cursor:]
118             self.drawRow(self.hl)
119             self.mvCursor(-1)
120             self.highlight()
121
122     def delete(self):
123         c = self.cursor
124         self.entries[self.hl]=self.entries[self.hl][:c] + self.entries[self.hl][c+1:]
125         self.drawRow(self.hl)
126         self.highlight()
127
128     def returnValues(self):
129         book = {}
130         for k,v in zip(self.labels, self.entries):
131             if v!="" and k.lower()!="publish date":
132                 book[k.lower()]=v
133         return book
134
135     def eventLoop(self):
136         self.w.keypad(1)
137         self.refresh()
138         self.mvCursor(+len(self.entries[self.hl]))
139         self.highlight()
140
141         ch = self.w.getch()
142         while ch != 27:
143             self.handleInput(ch)
144             if ch==10 or ch==curses.KEY_ENTER:
145                 if self.bt==0:
146                     return {}
147                 elif self.bt==1:
148                     return self.returnValues()
149                 self.mvHighlight(+1)
150             self.w.refresh()
151             ch = self.w.getch()
152         curses.curs_set(0)
153         return {}
154
155
156     def handleInput(self,ch):
157         if ch==curses.KEY_UP:
158             self.mvHighlight(-1)
159         elif ch==curses.KEY_PPAGE:
160             self.mvHighlight(-len(self.labels))
161         elif ch==curses.KEY_DOWN:
162             self.mvHighlight(+1)
163         elif ch==curses.KEY_NPAGE:
164             self.mvHighlight(+len(self.labels))
165
166         elif ch==curses.KEY_LEFT:
167             if self.bt==-1:
168                 self.mvCursor(-1)
169             else:
170                 self.unHighlight()
171                 self.bt=0
172                 self.highlight()
173         elif ch==curses.KEY_HOME:
174             if self.bt==-1:
175                 self.mvCursor(-len(self.entries[self.hl]))
176         elif ch==curses.KEY_RIGHT:
177             if self.bt==-1:
178                 self.mvCursor(+1)
179             else:
180                 self.unHighlight()
181                 self.bt=1
182                 self.highlight()
183         elif ch==curses.KEY_END:
184             if self.bt==-1:
185                 self.mvCursor(+len(self.entries[self.hl]))
186
187         elif ch>=32 and ch<=126:
188             if self.bt==-1:
189                 self.insert(curses.keyname(ch))
190         elif ch==curses.KEY_BACKSPACE:
191             if self.bt==-1:
192                 self.backspace()
193         elif ch==curses.KEY_DC:
194             if self.bt==-1:
195                 self.delete()
196         
197         
198
199 class bookForm(formWindow):
200     caption = "Add a Book"
201     blabel = "Add"
202     labels = ["ISBN", "LCCN", "Title", "Subtitle", "Authors", "Edition",
203               "Publisher", "Publish Date", "Publish Year", "Publish Month", "Publish location",
204               "Pages", "Pagination", "Weight"]
205     
206
207     # redefineable functions lookup is called when 'enter' is pressed on ISBN
208     # and returns the looked-up book. Default returns nothing
209     def lookup_isbn(self,isbn):
210         return {'isbn':isbn}
211     
212     def lookup_lccn(self,lccn):
213         return {'lccn':lccn}
214
215     def returnBook(self):
216         return self.returnValues()
217
218     def handleInput(self,ch):
219         if ch==10 or ch==curses.KEY_ENTER:
220             if self.hl==0:          # lookup by isbn
221                 book = self.lookup_isbn(self.entries[0])
222                 if book != {}:
223                     self.updateEntries(book)
224                 self.refresh()
225                 self.mvHighlight(+7)
226             if self.hl==1:          # lookup by lccn
227                 book = self.lookup_lccn(self.entries[1])
228                 if book != {}:
229                     self.updateEntries(book)
230                 self.refresh()
231                 self.mvHighlight(+6)
232         else:
233             formWindow.handleInput(self,ch)
234
235 class categoryForm(formWindow):
236     caption = "Add a Category"
237     blabel = "Add"
238     labels = ["Category"]
239
240     def returnValues(self):
241         return self.entries