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_rise;
00089         int                     m_border;
00090         bool                    m_haveFocus;
00091         bool                    m_encrypt;
00092         smart_ptr<Drawer>       m_drawer;
00093 };
00094 
00095 
00096 
00097 Textbox::Textbox(void) throw()
00098 {
00099         m_max = 0;
00100         m_haveFocus = false;
00101         m_size = 0;
00102         m_border = 0;
00103         m_value[0] = 0;
00104         m_encrypt = false;
00105 }
00106 
00107 
00108 
00109 void
00110 Textbox::initialize
00111 (
00112 IN const Datahash * hash,
00113 IN smart_ptr<Drawer>& drawer
00114 )
00115 {
00116         ASSERT(hash, "null");
00117         ASSERT(drawer, "null");
00118 
00119         m_drawer = drawer;
00120         m_name = getString(hash, "name");
00121         std::string value = getString(hash, "value");
00122         m_max = getInt(hash, "max");
00123         if (m_max < 1) {
00124                 WAVE_EX(wex);
00125                 wex << "Bad textbox max size: " << m_max;
00126         }
00127         if (m_max > s_max) {
00128                 DPRINTF("Truncating textbox size!  Max is %d", s_max);
00129                 m_max = s_max;
00130         }
00131         std::string enc = getOptionalString(hash, "encrypt", "");
00132         m_encrypt = ("true" == enc);
00133 
00134 //      DPRINTF("name: %s", m_name.c_str());
00135 //      DPRINTF("value: %s", value.c_str());
00136 //      DPRINTF("max: %d", m_max);
00137 //      DPRINTF("encrypt: %s", (m_encrypt ? "true" : "false"));
00138 
00139         m_label = m_name;
00140         m_label += ": ";
00141 
00142         // account for width of label
00143         font_size_t fs =
00144             m_drawer->getFontSizing(eElement_Textbox, m_label.c_str());
00145         m_width = fs.lead + fs.trail + 1;
00146         m_height = fs.rise + fs.drop + 1;
00147         m_rise = fs.rise;
00148 
00149         border_size_t bs = m_drawer->getBorderSizing(eElement_Textbox);
00150         m_border = bs.size;
00151         m_width += bs.size;
00152         m_valueOffset = m_width + bs.size;
00153 
00154         // account for width of (possible) value
00155         for (int i = 0; i < m_max; ++i) {
00156                 m_value[i] = 'M';
00157         }
00158         m_value[m_max] = '|';
00159         m_value[m_max + 1] = 0;
00160 //      DPRINTF("m_value = '%s'", m_value);
00161 
00162         fs = m_drawer->getFontSizing(eElement_Textbox, m_value);
00163         m_width += fs.lead + fs.trail + 1;
00164         m_width += 3 * bs.size;
00165 
00166         // copy in actual value
00167         strncpy(m_value, value.c_str(), m_max);
00168         m_value[m_max] = 0;     // force null-termination
00169         m_size = strlen(m_value);
00170 //      DPRINTF("m_value = '%s'", m_value);
00171         ASSERT(m_size <= m_max, "Bad size?  %d vs max %d", m_size, m_max);
00172 
00173         // use largest height + rise values
00174         int height = fs.rise + fs.drop + 1;
00175         if (height > m_height) {
00176                 m_height = height;
00177         }
00178         if (fs.rise > m_rise) {
00179                 m_rise = fs.rise;
00180         }
00181         m_height += 2 * bs.size;        // account for border size
00182 }
00183 
00184 
00185 
00186 void
00187 Textbox::draw
00188 (
00189 IN const point_t& offset
00190 )
00191 {
00192         ASSERT(m_drawer, "null");
00193 
00194         // draw label
00195         point_t pos(offset.x + m_border, offset.y + m_border + m_rise);
00196         m_drawer->drawString(eElement_Textbox, pos, m_label.c_str());
00197 
00198         // draw textbox
00199         if (m_haveFocus) {
00200                 DPRINTF("TODO: focus?");
00201         }
00202         rect_t r(offset.x + m_valueOffset, offset.y,
00203             offset.x + m_width, offset.y + m_height);
00204         m_drawer->drawRectWithBorder(eElement_Textbox, r);
00205 
00206         // save if encrypted!
00207         // TODO: get rid of this!  Keep a display and actual separate...
00208         char save_val[s_max + 1];
00209         if (m_encrypt) {
00210                 for (int i = 0; i < m_size; ++i) {
00211                         save_val[i] = m_value[i];
00212                         m_value[i] = '*';
00213                 }
00214                 save_val[m_size] = 0;
00215         }
00216 
00217         // draw value
00218         // TODO: blah!  draw caret separately, not by tweaking string
00219         bool showCaret = m_haveFocus && (time(NULL) % 2);
00220         if (showCaret) {
00221                 m_value[m_size] = '|';
00222                 m_value[m_size + 1] = 0;
00223         }
00224 
00225         pos.x = offset.x + m_valueOffset + m_border;
00226         pos.y = offset.y + m_border + m_rise;
00227         m_drawer->drawString(eElement_Textbox, pos, m_value);
00228         if (showCaret) {
00229                 m_value[m_size] = 0;
00230         }
00231 
00232         // restore if encrypted!
00233         if (m_encrypt) {
00234                 for (int i = 0; i < m_size; ++i) {
00235                         m_value[i] = save_val[i];
00236                 }
00237                 m_value[m_size] = 0;
00238         }
00239 }
00240 
00241 
00242 
00243 const char *
00244 Textbox::keyboard
00245 (
00246 IN int key,
00247 IN int mods
00248 )
00249 {
00250         char a = (char) key;
00251 
00252         if (8 == key || 127 == key) {
00253                 // delete or backspace
00254                 if (m_size > 0) {
00255                         m_size--;
00256                         m_value[m_size] = 0;
00257                 }
00258         } else if (isalnum(a) || 32 == a) {
00259                 // regular key
00260                 if (m_size < m_max) {
00261                         m_value[m_size] = a;
00262                         ++m_size;
00263                         m_value[m_size] = 0;
00264                 }
00265         } else if (13 == key) {
00266                 // ENTER key pressed!
00267                 return m_name.c_str();
00268         }
00269 
00270         // nothing submitted
00271         return NULL;
00272 }
00273 
00274 
00275 
00276 void
00277 Textbox::addData
00278 (
00279 IN crypto::DESKey * key,
00280 IN Datahash * data
00281 )
00282 {
00283         // ASSERT(key) -- can be null
00284         ASSERT(data, "null");
00285 
00286         // add our name: value pair
00287         std::string enc;
00288         const char * val = m_value;
00289         if (m_encrypt) {
00290                 if (!key) {
00291                         WAVE_EX(wex);
00292                         wex << "Asked to encrypt, but no encryption key ";
00293                         wex << "provided.  textbox name: " << m_name;
00294                 }
00295                 enc = key->encrypt(m_value, m_max);
00296                 val = enc.c_str();
00297         }
00298         data->insert(m_name, val);
00299 }
00300 
00301 
00302 
00303 ////////////////////////////////////////////////////////////////////////////////
00304 //
00305 //      public API
00306 //
00307 ////////////////////////////////////////////////////////////////////////////////
00308 
00309 smart_ptr<Element>
00310 createTextboxElement
00311 (
00312 IN Manager * mgr,
00313 IN const Datahash * hash
00314 )
00315 {
00316         ASSERT(mgr, "null");
00317         ASSERT(hash, "null");
00318 
00319         smart_ptr<Textbox> local = new Textbox;
00320         ASSERT(local, "out of memory");
00321 
00322         smart_ptr<Drawer> drawer = mgr->getDrawer();
00323         local->initialize(hash, drawer);
00324 
00325         return local;
00326 }
00327 
00328 
00329 
00330 };      // dialog namespace
00331