textbox.cpp

Go to the documentation of this file.
00001 /*
00002  * textbox.cpp
00003  *
00004  * Copyright (C) 2008-2009  Thomas A. Vaughan
00005  * All rights reserved.
00006  *
00007  *
00008  * Redistribution and use in source and binary forms, with or without
00009  * modification, are permitted provided that the following conditions are met:
00010  *     * Redistributions of source code must retain the above copyright
00011  *       notice, this list of conditions and the following disclaimer.
00012  *     * Redistributions in binary form must reproduce the above copyright
00013  *       notice, this list of conditions and the following disclaimer in the
00014  *       documentation and/or other materials provided with the distribution.
00015  *     * Neither the name of the <organization> nor the
00016  *       names of its contributors may be used to endorse or promote products
00017  *       derived from this software without specific prior written permission.
00018  *
00019  * THIS SOFTWARE IS PROVIDED BY THOMAS A. VAUGHAN ''AS IS'' AND ANY
00020  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
00021  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
00022  * DISCLAIMED. IN NO EVENT SHALL THOMAS A. VAUGHAN BE LIABLE FOR ANY
00023  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
00024  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
00025  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
00026  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00027  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
00028  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00029  *
00030  *
00031  * Implementation of a text entry field.
00032  */
00033 
00034 // includes --------------------------------------------------------------------
00035 #include "element.h"                    // always include our own header first!
00036 
00037 #include "dialog.h"
00038 
00039 #include "common/wave_ex.h"
00040 #include "datahash/datahash_util.h"
00041 
00042 
00043 namespace dialog {
00044 
00045 
00046 static const int s_max                          = 126;  // 2^N - 2
00047 
00048 ////////////////////////////////////////////////////////////////////////////////
00049 //
00050 //      Textbox -- class that implements the Element interface for text elements
00051 //
00052 ////////////////////////////////////////////////////////////////////////////////
00053 
00054 class Textbox : public Element {
00055 public:
00056         Textbox(void) throw();
00057         ~Textbox(void) throw() { }
00058 
00059         // public class methods ------------------------------------------------
00060         void initialize(IN const Datahash * hash,
00061                                 IN smart_ptr<Drawer>& drawer);
00062 
00063         // dialog::Element class interface methods -----------------------------
00064         int getWidth(void) { return m_width; }
00065         int getHeight(void) { return m_height; }
00066         void draw(IN const point_t& offset);
00067         void cursor(IN const point_t& pos) { }
00068         const char * keyboard(IN int key, IN int mods);
00069         Element * getFocus(IN const point_t& pos) { return this; }
00070         void notifyFocus(IN bool haveFocus) { m_haveFocus = haveFocus; }
00071         const char * button(IN int button, IN int state,
00072                                 IN const point_t& pos) { return NULL; }
00073         void addData(IN crypto::DESKey * key,
00074                                 IN Datahash * data);
00075 
00076 private:
00077         // private helper methods ----------------------------------------------
00078 
00079         // private member data -------------------------------------------------
00080         std::string             m_name;
00081         char                    m_value[s_max + 2];     // caret + null
00082         std::string             m_label;
00083         int                     m_max;
00084         int                     m_width;
00085         int                     m_height;
00086         int                     m_valueOffset;
00087         int                     m_size;
00088         int                     m_border;
00089         bool                    m_haveFocus;
00090         bool                    m_encrypt;
00091         smart_ptr<Drawer>       m_drawer;
00092 };
00093 
00094 
00095 
00096 Textbox::Textbox(void) throw()
00097 {
00098         m_max = 0;
00099         m_haveFocus = false;
00100         m_size = 0;
00101         m_border = 0;
00102         m_value[0] = 0;
00103         m_encrypt = false;
00104 }
00105 
00106 
00107 
00108 void
00109 Textbox::initialize
00110 (
00111 IN const Datahash * hash,
00112 IN smart_ptr<Drawer>& drawer
00113 )
00114 {
00115         ASSERT(hash, "null");
00116         ASSERT(drawer, "null");
00117 
00118         m_drawer = drawer;
00119         m_name = getString(hash, "name");
00120         std::string value = getString(hash, "value");
00121         m_max = getInt(hash, "max");
00122         if (m_max < 1) {
00123                 WAVE_EX(wex);
00124                 wex << "Bad textbox max size: " << m_max;
00125         }
00126         if (m_max > s_max) {
00127                 DPRINTF("Truncating textbox size!  Max is %d", s_max);
00128                 m_max = s_max;
00129         }
00130         std::string enc = getOptionalString(hash, "encrypt", "");
00131         m_encrypt = ("true" == enc);
00132 
00133         DPRINTF("name: %s", m_name.c_str());
00134         DPRINTF("value: %s", value.c_str());
00135         DPRINTF("max: %d", m_max);
00136         DPRINTF("encrypt: %s", (m_encrypt ? "true" : "false"));
00137 
00138         m_label = m_name;
00139         m_label += ": ";
00140 
00141         // account for width of label
00142         font_size_t fs =
00143             m_drawer->getFontSizing(eElement_Textbox, m_label.c_str());
00144         m_width = fs.width;
00145 
00146         border_size_t bs = m_drawer->getBorderSizing(eElement_Textbox);
00147         m_border = bs.size;
00148         m_width += bs.size;
00149         m_valueOffset = m_width + bs.size;
00150 
00151         // account for width of (possible) value
00152         for (int i = 0; i < m_max; ++i) {
00153                 m_value[i] = 'M';
00154         }
00155         m_value[m_max] = '|';
00156         m_value[m_max + 1] = 0;
00157         DPRINTF("m_value = '%s'", m_value);
00158 
00159         fs = m_drawer->getFontSizing(eElement_Textbox, m_value);
00160         m_width += fs.width;
00161         m_width += 3 * bs.size;
00162 
00163         // copy in actual value
00164         strncpy(m_value, value.c_str(), m_max);
00165         m_value[m_max] = 0;     // force null-termination
00166         m_size = strlen(m_value);
00167         DPRINTF("m_value = '%s'", m_value);
00168         ASSERT(m_size <= m_max, "Bad size?  %d vs max %d", m_size, m_max);
00169 
00170         m_height = fs.height;
00171         m_height += 2 * bs.size;
00172 }
00173 
00174 
00175 
00176 void
00177 Textbox::draw
00178 (
00179 IN const point_t& offset
00180 )
00181 {
00182         ASSERT(m_drawer, "null");
00183 
00184         // draw label
00185         point_t pos(offset.x + m_border, offset.y + m_border);
00186         m_drawer->drawString(eElement_Textbox, pos, m_label.c_str());
00187 
00188         // draw textbox
00189         if (m_haveFocus) {
00190                 DPRINTF("TODO: focus?");
00191         }
00192         rect_t r(offset.x + m_valueOffset, offset.y,
00193             offset.x + m_width, offset.y + m_height);
00194         m_drawer->drawRectWithBorder(eElement_Textbox, r);
00195 
00196         // save if encrypted!
00197         // TODO: get rid of this!  Keep a display and actual separate...
00198         char save_val[s_max + 1];
00199         if (m_encrypt) {
00200                 for (int i = 0; i < m_size; ++i) {
00201                         save_val[i] = m_value[i];
00202                         m_value[i] = '*';
00203                 }
00204                 save_val[m_size] = 0;
00205         }
00206 
00207         // draw value
00208         // TODO: blah!  draw caret separately, not by tweaking string
00209         bool showCaret = m_haveFocus && (time(NULL) % 2);
00210         if (showCaret) {
00211                 m_value[m_size] = '|';
00212                 m_value[m_size + 1] = 0;
00213         }
00214 
00215         pos.x = offset.x + m_valueOffset + m_border;
00216         pos.y = offset.y + m_border;
00217         m_drawer->drawString(eElement_Textbox, pos, m_value);
00218         if (showCaret) {
00219                 m_value[m_size] = 0;
00220         }
00221 
00222         // restore if encrypted!
00223         if (m_encrypt) {
00224                 for (int i = 0; i < m_size; ++i) {
00225                         m_value[i] = save_val[i];
00226                 }
00227                 m_value[m_size] = 0;
00228         }
00229 }
00230 
00231 
00232 
00233 const char *
00234 Textbox::keyboard
00235 (
00236 IN int key,
00237 IN int mods
00238 )
00239 {
00240         char a = (char) key;
00241 
00242         if (8 == key || 127 == key) {
00243                 // delete or backspace
00244                 if (m_size > 0) {
00245                         m_size--;
00246                         m_value[m_size] = 0;
00247                 }
00248         } else if (isalnum(a) || 32 == a) {
00249                 // regular key
00250                 if (m_size < m_max) {
00251                         m_value[m_size] = a;
00252                         ++m_size;
00253                         m_value[m_size] = 0;
00254                 }
00255         } else if (13 == key) {
00256                 // ENTER key pressed!
00257                 return m_name.c_str();
00258         }
00259 
00260         // nothing submitted
00261         return NULL;
00262 }
00263 
00264 
00265 
00266 void
00267 Textbox::addData
00268 (
00269 IN crypto::DESKey * key,
00270 IN Datahash * data
00271 )
00272 {
00273         // ASSERT(key) -- can be null
00274         ASSERT(data, "null");
00275 
00276         // add our name: value pair
00277         std::string enc;
00278         const char * val = m_value;
00279         if (m_encrypt) {
00280                 if (!key) {
00281                         WAVE_EX(wex);
00282                         wex << "Asked to encrypt, but no encryption key ";
00283                         wex << "provided.  textbox name: " << m_name;
00284                 }
00285                 enc = key->encrypt(m_value, m_max);
00286                 val = enc.c_str();
00287         }
00288         data->insert(m_name, val);
00289 }
00290 
00291 
00292 
00293 ////////////////////////////////////////////////////////////////////////////////
00294 //
00295 //      public API
00296 //
00297 ////////////////////////////////////////////////////////////////////////////////
00298 
00299 smart_ptr<Element>
00300 createTextboxElement
00301 (
00302 IN Manager * mgr,
00303 IN const Datahash * hash
00304 )
00305 {
00306         ASSERT(mgr, "null");
00307         ASSERT(hash, "null");
00308 
00309         smart_ptr<Textbox> local = new Textbox;
00310         ASSERT(local, "out of memory");
00311 
00312         smart_ptr<Drawer> drawer = mgr->getDrawer();
00313         local->initialize(hash, drawer);
00314 
00315         return local;
00316 }
00317 
00318 
00319 
00320 };      // dialog namespace
00321