ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/dclient/src/backend/ndk/edit.cpp
Revision: 1.7
Committed: Fri Jan 21 21:49:37 2011 UTC (13 years, 5 months ago) by sf-pippijn
Branch: MAIN
Changes since 1.6: +6 -3 lines
Log Message:
ndk/edit: prevent an out-of-range exception

patch by Jonathan Neuschäfer (j.neuschaefer@gmx.net)

File Contents

# Content
1 /* edit.cc
2 * This file is part of NDK++ library
3 * Copyright (c) 2003,2004 by Stanislav Ievlev
4 *
5 * This file is covered by the GNU Library General Public License,
6 * which should be included with libndk as the file COPYING.
7 */
8 #include <ndk/application.hh>
9 #include <ndk/edit.hh>
10 #include <ndk/packer.hh>
11 #include <ndk/palette.hh>
12
13 #include <ndk/pen.hh>
14
15 #include <cctype>
16
17
18 using ndk::edit;
19
20 edit::edit (std::string const &str, panel *parent, bool accept)
21 : button (str, parent, accept)
22 , current_ (0)
23 , begin_ (0)
24 , mode_ (normal)
25 {
26 events ()->on_keyboard (slot (&edit::at_keyboard, this));
27 events ()->on_system (slot (&edit::at_system, this));
28 }
29
30 void
31 edit::resize (int size)
32 {
33 button::resize (size, 1);
34 }
35
36 void
37 edit::set_text (std::string const &str)
38 {
39 label::set_text (str);
40 current_ = text_.length ();
41 draw ();
42 }
43
44 void
45 edit::set_mode (echo_mode mode)
46 {
47 mode_ = mode;
48 }
49
50 void
51 edit::change_color ()
52 {
53 pen (*this).set_color (palette::instance ().find (
54 state_ == engine::enter_focus
55 ? colors::edit_active
56 : colors::edit_inactive
57 )->second);
58 }
59
60 void
61 edit::draw ()
62 {
63 /* first process flags */
64 std::string out;
65
66 switch (mode_)
67 {
68 case normal:
69 out.assign (text ());
70 break;
71 case no_echo:
72 out.assign ("");
73 break;
74 case password:
75 out.assign (std::string (text ().size (), '*'));
76 break;
77 default:
78 break;
79 }
80
81 if (begin_ > out.length ())
82 begin_ = out.length ();
83
84 label::draw (out, begin_); /* and draw */
85 set_cursor (); /* and finally update cursor position */
86 pen (*this).commit (); /* commit changes to the screen */
87 }
88
89 ndk::event::result
90 edit::at_system (event const &ev)
91 {
92 event::result res = event::ignored;
93
94 if (!ev.sender_)
95 {
96 if (engine::enter_focus == ev.type_)
97 {
98 app->cursor_on ();
99 set_cursor (); /* only set cursor position, don't need full redraw */
100 res = event::accepted;
101 }
102 else if (engine::leave_focus == ev.type_)
103 {
104 app->cursor_off ();
105 res = event::accepted;
106 }
107 }
108 return res;
109 }
110
111 ndk::event::result
112 edit::at_keyboard (keyboard const &ev)
113 {
114 event::result res = event::ignored;
115 unsigned int pos = current_;
116
117 switch (ev.code ())
118 {
119 case key::right:
120 (scroll_right ()) ? draw () : set_cursor ();
121 res = event::accepted;
122 break;
123 case key::left:
124 (scroll_left ()) ? draw () : set_cursor ();
125 res = event::accepted;
126 break;
127 case key::backspace:
128 --pos; /* try to go to previous position */
129 if (pos < text_.length ())
130 {
131 erase (pos);
132 scroll_left (); /* scroll all view to the left */
133 draw (); /* we always need full redraw */
134 res = event::accepted;
135 }
136 break;
137 case key::dc:
138 if (pos < text_.length ())
139 {
140 erase (pos);
141 draw (); /* we always need full redraw */
142 res = event::accepted;
143 }
144 break;
145 case key::home:
146 begin_ = 0;
147 current_ = 0;
148 draw ();
149 res = event::accepted;
150 break;
151 case key::end:
152 current_ = text_.length ();
153 (recalibrate ()) ? draw () : set_cursor ();
154 res = event::accepted;
155 break;
156 case '\r':
157 on_commit_ (text_);
158 break;
159 case '\t': /* don't beep on tab */
160 break;
161 default: /* enter key to the string */
162 if (std::isprint (int (ev.code ())))
163 {
164 insert (pos, char (ev.code ()));
165 scroll_right ();
166 draw (); /* we always need full redraw */
167 res = event::accepted;
168 }
169 #if 0
170 else
171 throw ev.code ();
172 #endif
173 break;
174 }
175
176 return res;
177 }
178
179 bool
180 edit::scroll_right ()
181 {
182 if (current_ < int (text_.length ()))
183 ++current_; /* increase current */
184 /* recalibrate begin, decide are we need to redraw */
185 return recalibrate ();
186 }
187
188 bool
189 edit::scroll_left ()
190 {
191 if (current_ > 0)
192 --current_; /* decrease current */
193 /* recalibrate begin, decide are we need to redraw */
194 return recalibrate ();
195 }
196
197 bool
198 edit::recalibrate ()
199 {
200 bool res = false;
201
202 if ((begin_ < current_) && ((current_ - begin_) > (width () - 1)))
203 {
204 /* may be cursor is over(after) edit screen? */
205 begin_ = current_ - width () + 1;
206 res = true;
207 }
208 else if (begin_ > current_)
209 {
210 /* may be cursor is over(before) edit screen? */
211 begin_ = current_;
212 res = true;
213 }
214 return res;
215 }
216
217 void
218 edit::set_cursor ()
219 {
220 /* always move to zero position in no_echo mode */
221 return_unless (pen (*this).move (mode_ != no_echo ? current_ - begin_ : 0, 0));
222 pen (*this).commit ();
223 }
224
225 void
226 edit::insert (int pos, char sym)
227 {
228 text_.insert (text_.begin () + pos, sym); /* default mode is insert mode */
229 }
230
231 void
232 edit::erase (int pos)
233 {
234 text_.erase (text_.begin () + pos);
235 }