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