From 4b658477ea3dd594fd0af849d35cf01832f1bbeb Mon Sep 17 00:00:00 2001 From: John Ladan Date: Fri, 25 Oct 2013 15:33:49 -0400 Subject: [PATCH] Text entry allows wider strings, and fixed code --- browser.py | 22 ++--- gui.py | 262 +++++++++++++++++++++++++++++---------------------- librarian.py | 6 +- 3 files changed, 161 insertions(+), 129 deletions(-) diff --git a/browser.py b/browser.py index 2db9e49..8251157 100644 --- a/browser.py +++ b/browser.py @@ -1,7 +1,7 @@ import sys import curses import db_layer as db -from form import bookForm,categoryForm +from gui import BookForm,CategoryForm class browserWindow: hl=0 @@ -259,11 +259,11 @@ class trashBrowser(browserWindow): def viewSelection(self,book): bookid = book['id'] w=curses.newwin(1,1,20,20) - bf = bookForm(w,self.hb,book) + bf = BookForm(w,self.hb,book) self.centreChild(w) bf.caption='Viewing Book '+str(bookid) bf.blabel='done' - bf.eventLoop() + bf.event_loop() bf.clear() def restoreSelected(self): @@ -325,11 +325,11 @@ class bookBrowser(browserWindow): bookid = book['id'] w=curses.newwin(1,1) - bf=bookForm(w,self.hb,book) + bf=BookForm(w,self.hb,book) self.centreChild(w) bf.caption='Update Book '+str(bookid) bf.blabel='update' - newbook = bf.eventLoop() + newbook = bf.event_loop() if len(newbook)!=0: db.updateBook(newbook,bookid) bf.clear() @@ -337,11 +337,11 @@ class bookBrowser(browserWindow): def viewSelection(self,book): bookid = book['id'] w=curses.newwin(1,1,20,20) - bf = bookForm(w,self.hb,book) + bf = BookForm(w,self.hb,book) self.centreChild(w) bf.caption='Viewing Book '+str(bookid) bf.blabel='done' - bf.eventLoop() + bf.event_loop() bf.clear() def categorizeSelection(self,book): @@ -407,9 +407,9 @@ class categoryBrowser(browserWindow): def addCategory(self): w = curses.newwin(1,1,10,10) - cf = categoryForm(w,self.hb) + cf = CategoryForm(w,self.hb) self.centreChild(w) - cats = cf.eventLoop() + cats = cf.event_loop() for c in cats: db.addCategory(c) cf.clear() @@ -481,9 +481,9 @@ class categorySelector(browserWindow): def addCategory(self): w = curses.newwin(1,1,10,10) - cf = categoryForm(w,self.hb) + cf = CategoryForm(w,self.hb) self.centreChild(w) - cats = cf.eventLoop() + cats = cf.event_loop() for c in cats: db.addCategory(c) cf.clear() diff --git a/gui.py b/gui.py index 0e35764..4be00a6 100644 --- a/gui.py +++ b/gui.py @@ -1,90 +1,120 @@ import curses import sys -class textEntry: + +class TextEntry: + + """A part of a window that handles text entry. + Properties: + value holds the string that was entered + + Public Methods: + set_geom(row,column,width) Sets the geometry in the window + set_value(string) Set the value and redraw + gain_focus() Gives it focus, moving cursor and changing the drawing + lose_focus() Takes focus, moving cursor to start, changing drawing + handle_input(ch) Pass this the ncurses key, and it manages input + redraw() Redraw the text entry (should never need to do this + """ + + # Public + value = "" # Use the set_value function to set, but retrieve with value + + # Should be Private cursor = 0 start = 0 focus = False x = 0 y = 0 width = 10 - value = "" def __init__(self, parent_window, value=""): self.w = parent_window self.value = value - def setGeom(self,y,x,width): + def set_geom(self,y,x,width): self.x = x self.y = y self.width = width + def set_value(self,v): + self.value=v + self.cursor=len(v) + self.redraw() + + def gain_focus(self): + #sys.stderr.write('I have focus!\n') + self.focus = True + self._mv_cursor(+len(self.value)) + self.start = max(0,self.cursor-self.width) + self.redraw() + + def lose_focus(self): + self.focus = False + self.cursor = 0 + self.start = 0 + self.redraw() + + def handle_input(self,ch): + if ch==curses.KEY_LEFT: + self._mv_cursor(-1) + elif ch==curses.KEY_HOME: + self._set_cursor(0) + elif ch==curses.KEY_RIGHT: + self._mv_cursor(+1) + elif ch==curses.KEY_END: + self._set_cursor(len(self.value)) + elif ch>=32 and ch<=126: + self._insert(curses.keyname(ch).decode('utf-8')) + elif ch==curses.KEY_BACKSPACE: + self._backspace() + elif ch==curses.KEY_DC: + self._delete() + def redraw(self): self.w.addnstr(self.y,self.x, self.value[self.start:]+" "*self.width, self.width) if self.focus: self.w.chgat(self.y, self.x, self.width, curses.A_UNDERLINE) curses.curs_set(1) - def gainFocus(self): - sys.stderr.write('I have focus!\n') - self.focus = True - self.mvCursor(+len(self.value)) - self.start = max(0,self.cursor-self.width) - self.redraw() - - def loseFocus(self): - self.focus = False - self.cursor = 0 - self.start = 0 - self.redraw() + # Private functions + def _mv_cursor(self,delta): + self._set_cursor(self.cursor + delta) - def mvCursor(self,delta): - n = self.cursor + delta - # make sure new position is legal - n = max(n,0) - n = min(n,len(self.value)) - self.cursor = n + def _set_cursor(self, new_c): + self.cursor = max(0, min(len(self.value), new_c)) self.start = max(0,self.cursor-self.width+1) self.redraw() + # Place the drawn cursor in the correct spot col = self.x + self.cursor - self.start self.w.move(self.y,col) - def insert(self,ch): + def _insert(self,ch): c = self.cursor self.value = self.value[:c] +ch+ self.value[c:] - self.mvCursor(+1) + self._mv_cursor(+1) - def backspace(self): + def _backspace(self): if self.cursor>0: c = self.cursor self.value=self.value[:c-1] + self.value[c:] - self.mvCursor(-1) + self._mv_cursor(-1) - def delete(self): + def _delete(self): c = self.cursor self.value = self.value[:c] + self.value[c+1:] - self.mvCursor(0) - - def handle_input(self,ch): - if ch==curses.KEY_LEFT: - self.mvCursor(-1) - elif ch==curses.KEY_HOME: - self.mvCursor(-len(self.value)) - elif ch==curses.KEY_RIGHT: - self.mvCursor(+1) - elif ch==curses.KEY_END: - self.mvCursor(+len(self.value)) - - elif ch>=32 and ch<=126: - self.insert(curses.keyname(ch)) - elif ch==curses.KEY_BACKSPACE: - self.backspace() - elif ch==curses.KEY_DC: - self.delete() + self._mv_cursor(0) -class formWindow: +class FormWindow: + + """General class for a Form Window. + + To use, make the window for it, call the constructor, then call event_loop. + """ + + # Private variables mx = my = 0 hl = 0 bt = -1 @@ -94,27 +124,51 @@ class formWindow: caption = "Form" blabel = "Done" labels = ["label1"] - entries=[] commands = [('pU', 'top'),('pD', 'bottom'),('Es', 'cancel')] + + # Public functions + def __init__(self,window,helpbar,book={}): + self.w = window + self.w.resize(len(self.labels)+6,50) + self.hb = helpbar + self._make_entries() + self._update_geometry() + self._set_entries(book) + def clear(self): self.w.erase() self.w.refresh() - def __init__(self,window,helpbar,book={}): - self.w = window - self.w.resize(len(self.labels)+6,50) - self.hb = helpbar - self.makeEntries() - self.updateGeometry() - self.updateEntries(book) + def event_loop(self): + self.w.keypad(1) + self.refresh() + self.hl=0; + self.entries[self.hl].gain_focus() - def makeEntries(self): + ch = self.w.getch() + while ch != 27: + #sys.stderr.write(curses.keyname(ch).decode('utf-8')) + self.handle_input(ch) + if ch==10 or ch==curses.KEY_ENTER: + if self.bt==0: + return {} + elif self.bt==1: + return self.return_values() + else: + self._mv_focus(+1) + self.w.refresh() + ch = self.w.getch() + curses.curs_set(0) + return {} + + def _make_entries(self): + self.entries = [] for e in range(len(self.labels)): - self.entries.append(textEntry(self.w)) + self.entries.append(TextEntry(self.w)) - def updateGeometry(self): + def _update_geometry(self): (self.my, self.mx) = self.w.getmaxyx() self.left=0 for l in self.labels: @@ -123,21 +177,21 @@ class formWindow: width = self.mx-self.left-2 self.top = 2 for r in range(len(self.entries)): - self.entries[r].setGeom(r+self.top, self.left, width) + self.entries[r].set_geom(r+self.top, self.left, width) # next, the buttons self.brow = self.top+len(self.labels)+1 self.bcol = [self.mx-len(self.blabel)-14, self.mx-len(self.blabel)-4] self.bwidth = [8,len(self.blabel)+2] - def updateEntries(self,book): + def _set_entries(self,book): e = 0 for l in self.labels: - sys.stderr.write('updating label: '+l+'\n') + #sys.stderr.write('updating label: '+l+'\n') if l.lower() in book: - sys.stderr.write(' '+l+' found\n') + #sys.stderr.write(' '+l+' found\n') self.entries[e].value = str(book[l.lower()]) else: - sys.stderr.write(' '+l+' notfound\n') + #sys.stderr.write(' '+l+' notfound\n') self.entries[e].value = "" e += 1 @@ -156,89 +210,67 @@ class formWindow: def refresh(self): self.hb.commands = self.commands self.hb.refresh() - self.updateGeometry() + self._update_geometry() self.redraw() - def highlightButton(self): + def _highlight_button(self): self.w.chgat(self.brow, self.bcol[self.bt], self.bwidth[self.bt], curses.A_REVERSE) curses.curs_set(0) - def unHighlightButton(self): + def _unhighlight_button(self): self.w.chgat(self.brow,1,self.mx-2,curses.A_NORMAL) - def mvFocus(self,delta): + def _mv_focus(self,delta): if self.bt==-1: - self.entries[self.hl].loseFocus() + self.entries[self.hl].lose_focus() else: - self.unHighlightButton() + self._unhighlight_button() new = self.hl+delta - new = max(new,0) - new = min(new,len(self.labels)) # the extra is for the buttons + new = max(0, min(len(self.labels), new)) # the extra is for the buttons self.hl = new if new == len(self.labels): self.bt = 1 self.bt = min(self.bt,1) - self.highlightButton() + self._highlight_button() else: self.bt=-1 - self.entries[self.hl].gainFocus() + self.entries[self.hl].gain_focus() - def returnValues(self): + def _return_values(self): book = {} for k,e in zip(self.labels, self.entries): if v!="" and k.lower()!="publish date": book[k.lower()]=e.value return book - def eventLoop(self): - self.w.keypad(1) - self.refresh() - self.hl=0; - self.entries[self.hl].gainFocus() - ch = self.w.getch() - while ch != 27: - self.handleInput(ch) - if ch==10 or ch==curses.KEY_ENTER: - if self.bt==0: - return {} - elif self.bt==1: - return self.returnValues() - else: - self.mvFocus(+1) - self.w.refresh() - ch = self.w.getch() - curses.curs_set(0) - return {} - - - def handleInput(self,ch): + def handle_input(self,ch): if ch==curses.KEY_UP: - self.mvFocus(-1) + self._mv_focus(-1) elif ch==curses.KEY_PPAGE: - self.mvFocus(-len(self.labels)) + self._mv_focus(-len(self.labels)) elif ch==curses.KEY_DOWN: - self.mvFocus(+1) + self._mv_focus(+1) elif ch==curses.KEY_NPAGE: - self.mvFocus(+len(self.labels)) + self._mv_focus(+len(self.labels)) elif ch==curses.KEY_LEFT: if self.bt==-1: self.entries[self.hl].handle_input(ch) else: - self.unHighlightButton() + self._unhighlight_button() self.bt=0 - self.highlightButton() + self._highlight_button() elif ch==curses.KEY_HOME: if self.bt==-1: - self.mvCursor(-len(self.entries[self.hl])) + self._mv_cursor(-len(self.entries[self.hl])) elif ch==curses.KEY_RIGHT: if self.bt==-1: self.entries[self.hl].handle_input(ch) else: - self.unHighlightButton() + self._unhighlight_button() self.bt=1 - self.highlightButton() + self._highlight_button() else: if self.bt==-1: self.entries[self.hl].handle_input(ch) @@ -246,7 +278,7 @@ class formWindow: -class bookForm(formWindow): +class BookForm(FormWindow): caption = "Add a Book" blabel = "Add" labels = ["ISBN", "LCCN", "Title", "Subtitle", "Authors", "Edition", @@ -262,31 +294,31 @@ class bookForm(formWindow): def lookup_lccn(self,lccn): return {'lccn':lccn} - def returnBook(self): - return self.returnValues() + def return_book(self): + return self.return_values() - def handleInput(self,ch): + def handle_input(self,ch): if ch==10 or ch==curses.KEY_ENTER: if self.hl==0: # lookup by isbn book = self.lookup_isbn(self.entries[0].value) if book != {}: - sys.stderr.write('updating entries\n') - self.updateEntries(book) + #sys.stderr.write('updating entries\n') + self._set_entries(book) self.refresh() - self.mvFocus(+7) + self._mv_focus(+7) if self.hl==1: # lookup by lccn book = self.lookup_lccn(self.entries[1].value) if book != {}: - self.updateEntries(book) + self._set_entries(book) self.refresh() - self.mvFocus(+6) + self._mv_focus(+6) else: - formWindow.handleInput(self,ch) + FormWindow.handle_input(self,ch) -class categoryForm(formWindow): +class CategoryForm(FormWindow): caption = "Add a Category" blabel = "Add" labels = ["Category"] - def returnValues(self): + def return_values(self): return self.entries diff --git a/librarian.py b/librarian.py index 4677065..c4dc884 100755 --- a/librarian.py +++ b/librarian.py @@ -3,7 +3,7 @@ import curses import db_layer as db import browser -import form as form +import gui as form import help_bar as helpBar import book_data @@ -82,14 +82,14 @@ def redrawMenu(w,items,highlight): def addForm(): w=curses.newwin(1,1) (my,mx)=stdscr.getmaxyx() - bf = form.bookForm(w,hb) + bf = form.BookForm(w,hb) (r,c)=w.getmaxyx() w.mvwin((my-r)//2,(mx-c)//2) bf.lookup_isbn=book_data.openLibrary_isbn bf.lookup_lccn=book_data.openLibrary_lccn bf.caption='Add a Book' bf.blabel = 'Add' - book = bf.eventLoop() + book = bf.event_loop() bf.clear() if len(book)!=0: db.addBook(book)