comparison frontends/sortilege/editbox.py @ 0:c4bc297b82f0

sat: - first public release, initial commit
author goffi@necton2
date Sat, 29 Aug 2009 13:34:59 +0200
parents
children a5b5fb5fc9fd
comparison
equal deleted inserted replaced
-1:000000000000 0:c4bc297b82f0
1 #!/usr/bin/python
2 # -*- coding: utf-8 -*-
3
4 """
5 sortilege: a SAT frontend
6 Copyright (C) 2009 Jérôme Poisson (goffi@goffi.org)
7
8 This program is free software: you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation, either version 3 of the License, or
11 (at your option) any later version.
12
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with this program. If not, see <http://www.gnu.org/licenses/>.
20 """
21
22
23 import curses
24 from curses import ascii
25 from window import Window
26
27 def C(k):
28 """return the value of Ctrl+key"""
29 return ord(ascii.ctrl(k))
30
31 def A(k):
32 """return the value of Alt+key"""
33 return ord(ascii.alt(k))
34
35 class EditBox(Window):
36 """This class manage the edition of text"""
37
38 def __init__(self, parent, header, code="utf-8"):
39 self.__header=header
40 self.__text = unicode()
41 self.__curs_pos=0
42 self.__buffer=str()
43 self.__replace_mode=False
44 self.__parent=parent
45 self.__code=code
46
47 Window.__init__(self, self.__parent, 1, self.__parent.getmaxyx()[1], self.__parent.getmaxyx()[0]-1,0, code=code)
48 self.update()
49
50 def registerEnterCB(self, CB):
51 self.__enterCB=CB
52
53 def resizeAdapt(self):
54 """Adapt window size to self.__parent size.
55 Must be called when self.__parent is resized."""
56 self.resize(1, self.__parent.getmaxyx()[1], self.__parent.getmaxyx()[0]-1,0)
57 self.update()
58
59 def __getTextToPrint(self):
60 """return the text printed on the edit line"""
61 width = self.rWidth - len(self.__header) -1
62 if self.__curs_pos<width:
63 begin = 0
64 end = width
65 else:
66 begin = self.__curs_pos-width
67 end = self.__curs_pos
68 return self.__header+self.__text[begin:end]
69
70 def update(self):
71 Window.update(self)
72 text = self.__getTextToPrint()
73 self.addYXStr(0, 0, text, limit=self.rWidth)
74
75 self.noutrefresh()
76
77 def __dec_cur(self):
78 """move cursor on the left"""
79 if self.__curs_pos>0:
80 self.__curs_pos = self.__curs_pos - 1
81
82 def __inc_cur(self):
83 """move cursor on the right"""
84 if self.__curs_pos<len(self.__text):
85 self.__curs_pos = self.__curs_pos + 1
86
87 def move_cur(self, x):
88 pos = x+len(self.__header)
89 if pos>=self.rWidth:
90 pos=self.rWidth-1
91 self.move(0, pos)
92
93 def clear_text(self):
94 """Clear the text of the edit box"""
95 self.__text=""
96 self.__curs_pos=0
97
98 def replace_cur(self):
99 """must be called earch time the cursor is moved"""
100 self.move_cur(self.__curs_pos)
101 self.noutrefresh()
102
103 def activate(self, state=True):
104 cursor_mode = 1 if state else 0
105 curses.curs_set(cursor_mode)
106 Window.activate(self,state)
107
108 def handleKey(self, k):
109 if ascii.isgraph(k) or ascii.isblank(k):
110 pacman = 0 if not self.__replace_mode else 1
111 self.__text = self.__text[:self.__curs_pos] + chr(k) + self.__text[self.__curs_pos + pacman:]
112 self.__curs_pos = self.__curs_pos + 1
113
114 elif k==ascii.NL:
115 try:
116 self.__enterCB(self.__text)
117 except NameError:
118 pass # TODO: thrown an error here
119 self.clear_text()
120
121 elif k==curses.KEY_BACKSPACE:
122 self.__text = self.__text[:self.__curs_pos-1]+self.__text[self.__curs_pos:]
123 self.__dec_cur()
124
125 elif k==curses.KEY_DC:
126 self.__text = self.__text[:self.__curs_pos]+self.__text[self.__curs_pos+1:]
127
128 elif k==curses.KEY_IC:
129 self.__replace_mode = not self.__replace_mode
130
131 elif k==curses.KEY_LEFT:
132 self.__dec_cur()
133
134 elif k==curses.KEY_RIGHT:
135 self.__inc_cur()
136
137 elif k==curses.KEY_HOME or k==C('a'):
138 self.__curs_pos=0
139
140 elif k==curses.KEY_END or k==C('e'):
141 self.__curs_pos=len(self.__text)
142
143 elif k==C('k'):
144 self.__text = self.__text[:self.__curs_pos]
145
146 elif k==C('w'):
147 before = self.__text[:self.__curs_pos]
148 pos = before.rstrip().rfind(" ")+1
149 self.__text = before[:pos] + self.__text[self.__curs_pos:]
150 self.__curs_pos = pos
151
152 elif k>255:
153 self.__buffer=""
154
155 else: ## FIXME: dangerous code, must be checked ! (specialy buffer overflow) ##
156 #We now manage unicode
157 self.__buffer = self.__buffer+chr(k)
158 decoded=unicode()
159 if len(self.__buffer)>4:
160 self.__buffer=""
161 return
162 try:
163 decoded = self.__buffer.decode(self.__code)
164 except UnicodeDecodeError, e:
165 if e.reason!="unexpected end of data":
166 self.__buffer=""
167 return
168 if len(self.__buffer)==1: ## FIXME: awful ! only for test !
169 self.__buffer=""
170 return
171 self.__text = self.__text + decoded
172 self.__curs_pos = self.__curs_pos + 1
173 self.__buffer=""
174
175 self.update()
176