7 """A part of a window that handles text entry.
9 value holds the string that was entered
12 set_geom(row,column,width) Sets the geometry in the window
13 set_value(string) Set the value and redraw
14 gain_focus() Gives it focus, moving cursor and changing the drawing
15 lose_focus() Takes focus, moving cursor to start, changing drawing
16 handle_input(ch) Pass this the ncurses key, and it manages input
17 redraw() Redraw the text entry (should never need to do this
21 value = "" # Use the set_value function to set, but retrieve with value
32 def __init__(self, parent_window, value=""):
33 self.w = parent_window
36 def set_geom(self,y,x,width):
41 def set_value(self,v):
47 #sys.stderr.write('I have focus!\n')
49 self._mv_cursor(+len(self.value))
50 self.start = max(0,self.cursor-self.width)
59 def handle_input(self,ch):
60 if ch==curses.KEY_LEFT:
62 elif ch==curses.KEY_HOME:
64 elif ch==curses.KEY_RIGHT:
66 elif ch==curses.KEY_END:
67 self._set_cursor(len(self.value))
68 elif ch>=32 and ch<=126:
69 self._insert(curses.keyname(ch).decode('utf-8'))
70 elif ch==curses.KEY_BACKSPACE:
72 elif ch==curses.KEY_DC:
76 self.w.addnstr(self.y,self.x, self.value[self.start:]+" "*self.width, self.width)
78 self.w.chgat(self.y, self.x, self.width, curses.A_UNDERLINE)
82 def _mv_cursor(self,delta):
83 self._set_cursor(self.cursor + delta)
85 def _set_cursor(self, new_c):
86 self.cursor = max(0, min(len(self.value), new_c))
87 self.start = max(0,self.cursor-self.width+1)
89 # Place the drawn cursor in the correct spot
90 col = self.x + self.cursor - self.start
91 self.w.move(self.y,col)
95 self.value = self.value[:c] +ch+ self.value[c:]
101 self.value=self.value[:c-1] + self.value[c:]
106 self.value = self.value[:c] + self.value[c+1:]
113 """General class for a Form Window.
115 To use, make the window for it, call the constructor, then call event_loop.
129 commands = [('pU', 'top'),('pD', 'bottom'),('Es', 'cancel')]
133 def __init__(self,window,helpbar,book={}, width=50):
135 self.w.resize(len(self.labels)+6,width)
138 self._update_geometry()
139 self._set_entries(book)
145 def event_loop(self):
149 self.entries[self.hl].gain_focus()
153 #sys.stderr.write(curses.keyname(ch).decode('utf-8'))
154 self.handle_input(ch)
155 if ch==10 or ch==curses.KEY_ENTER:
159 return self.return_values()
167 def _make_entries(self):
169 for e in range(len(self.labels)):
170 self.entries.append(TextEntry(self.w))
172 def _update_geometry(self):
173 (self.my, self.mx) = self.w.getmaxyx()
175 for l in self.labels:
176 self.left = max(len(l),self.left)
178 width = self.mx-self.left-2
180 for r in range(len(self.entries)):
181 self.entries[r].set_geom(r+self.top, self.left, width)
183 self.brow = self.top+len(self.labels)+1
184 self.bcol = [self.mx-len(self.blabel)-14, self.mx-len(self.blabel)-4]
185 self.bwidth = [8,len(self.blabel)+2]
187 def _set_entries(self,book):
189 for l in self.labels:
190 #sys.stderr.write('updating label: '+l+'\n')
191 if l.lower() in book:
192 #sys.stderr.write(' '+l+' found\n')
193 self.entries[e].value = str(book[l.lower()])
195 #sys.stderr.write(' '+l+' notfound\n')
196 self.entries[e].value = ""
201 self.w.addstr(0,(self.mx-len(self.caption))//2,self.caption)
203 for l in self.labels:
204 c = self.left-len(l)-2
205 self.w.addstr(r+self.top,c,l+":")
206 self.entries[r].redraw()
208 self.w.addstr(self.brow,self.bcol[0], "<cancel> <"+self.blabel+">")
212 self.hb.commands = self.commands
214 self._update_geometry()
217 def _highlight_button(self):
218 self.w.chgat(self.brow, self.bcol[self.bt], self.bwidth[self.bt], curses.A_REVERSE)
221 def _unhighlight_button(self):
222 self.w.chgat(self.brow,1,self.mx-2,curses.A_NORMAL)
224 def _mv_focus(self,delta):
226 self.entries[self.hl].lose_focus()
228 self._unhighlight_button()
230 new = max(0, min(len(self.labels), new)) # the extra is for the buttons
232 if new == len(self.labels):
234 self.bt = min(self.bt,1)
235 self._highlight_button()
238 self.entries[self.hl].gain_focus()
241 def _return_values(self):
243 for k,e in zip(self.labels, self.entries):
244 if v!="" and k.lower()!="publish date":
245 book[k.lower()]=e.value
249 def handle_input(self,ch):
250 if ch==curses.KEY_UP:
252 elif ch==curses.KEY_PPAGE:
253 self._mv_focus(-len(self.labels))
254 elif ch==curses.KEY_DOWN:
256 elif ch==curses.KEY_NPAGE:
257 self._mv_focus(+len(self.labels))
258 elif ch==curses.KEY_LEFT:
260 self.entries[self.hl].handle_input(ch)
262 self._unhighlight_button()
264 self._highlight_button()
265 elif ch==curses.KEY_HOME:
267 self._mv_cursor(-len(self.entries[self.hl]))
268 elif ch==curses.KEY_RIGHT:
270 self.entries[self.hl].handle_input(ch)
272 self._unhighlight_button()
274 self._highlight_button()
277 self.entries[self.hl].handle_input(ch)
282 class BookForm(FormWindow):
283 caption = "Add a Book"
285 labels = ["ISBN", "LCCN", "Title", "Subtitle", "Authors", "Edition",
286 "Publisher", "Publish Date", "Publish Year", "Publish Month", "Publish location",
287 "Pages", "Pagination", "Weight"]
290 # redefineable functions lookup is called when 'enter' is pressed on ISBN
291 # and returns the looked-up book. Default returns nothing
292 def lookup_isbn(self,isbn):
295 def lookup_lccn(self,lccn):
298 def return_book(self):
299 return self.return_values()
301 def handle_input(self,ch):
302 if ch==10 or ch==curses.KEY_ENTER:
303 if self.hl==0: # lookup by isbn
304 book = self.lookup_isbn(self.entries[0].value)
306 #sys.stderr.write('updating entries\n')
307 self._set_entries(book)
310 if self.hl==1: # lookup by lccn
311 book = self.lookup_lccn(self.entries[1].value)
313 self._set_entries(book)
317 FormWindow.handle_input(self,ch)
319 class CategoryForm(FormWindow):
320 caption = "Add a Category"
322 labels = ["Category"]
324 def return_values(self):