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

# User Rev Content
1 sf-pippijn 1.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 sf-pippijn 1.6 * which should be included with libndk as the file COPYING.
7 sf-pippijn 1.1 */
8 sf-pippijn 1.6 #include <ndk/application.hh>
9     #include <ndk/edit.hh>
10     #include <ndk/packer.hh>
11     #include <ndk/palette.hh>
12 sf-pippijn 1.1
13 sf-pippijn 1.6 #include <ndk/pen.hh>
14 sf-pippijn 1.1
15     #include <cctype>
16    
17    
18     using ndk::edit;
19    
20 sf-pippijn 1.3 edit::edit (std::string const &str, panel *parent, bool accept)
21 sf-pippijn 1.1 : 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 sf-pippijn 1.3 edit::set_text (std::string const &str)
38 sf-pippijn 1.1 {
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 sf-pippijn 1.5 pen (*this).set_color (palette::instance ().find (
54     state_ == engine::enter_focus
55     ? colors::edit_active
56     : colors::edit_inactive
57     )->second);
58 sf-pippijn 1.1 }
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 sf-pippijn 1.7 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 sf-pippijn 1.1 }
88    
89     ndk::event::result
90 sf-pippijn 1.3 edit::at_system (event const &ev)
91 sf-pippijn 1.1 {
92     event::result res = event::ignored;
93    
94     if (!ev.sender_)
95     {
96     if (engine::enter_focus == ev.type_)
97     {
98 sf-pippijn 1.5 app->cursor_on ();
99 sf-pippijn 1.1 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 sf-pippijn 1.5 app->cursor_off ();
105 sf-pippijn 1.1 res = event::accepted;
106     }
107     }
108     return res;
109     }
110    
111     ndk::event::result
112 sf-pippijn 1.3 edit::at_keyboard (keyboard const &ev)
113 sf-pippijn 1.1 {
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 sf-pippijn 1.5 return_unless (pen (*this).move (mode_ != no_echo ? current_ - begin_ : 0, 0));
222     pen (*this).commit ();
223 sf-pippijn 1.1 }
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     }