/* text.cc * This file is part of NDK++ library * Copyright (c) 2003,2004 by Stanislav Ievlev * * This file is covered by the GNU Library General Public License, * which should be included with libndk++ as the file COPYING. */ #include #include #include #include #include using ndk::text; using ndk::text_view; text::text (const std::string &str, ndk::panel *parent, wrap_type wrapping) : ndk::panel (parent) , x_ (0) , y_ (0) , wrapping_ (wrapping) { ncurses::pen pen (pad_); if (!str.empty ()) { int h = string_height (str); if (*(str.end () - 1) != '\n') ++h; /* extra hack only for the first time */ int const w = string_width (str); resize (w, h); pen.write (str); /* add next text to the pad */ } pen.fill (palette::instance ()[colors::label]); events ()->on_keyboard (slot (&text::at_keyboard, this)); } void text::add_text (const std::string &str) { bool at_bottom = y_ + height () >= pad_.height (); /* calculate new height */ pad_.resize ( wrapping_ == wrap ? width () : std::max (pad_.width (), string_width (str) + 1) , std::max (height (), ncurses::pen (pad_).y () + string_height (str)) ); ncurses::pen (pad_).write (str); /* add next text to the pad */ if (at_bottom) while (down ()) ; } void text::draw () /**< draw frame on the panel */ { pad_.draw (*this, x_, y_); /* draw pad content in the viewport */ } bool text::right () { if (x_ + width () < pad_.width () - 1) { ++x_; draw (); return true; } return false; } bool text::left () { if (x_ > 0) { --x_; draw (); return true; } return false; } bool text::down () { if (y_ + height () < pad_.height ()) { ++y_; draw (); return true; } return false; } bool text::up () { if (y_ > 0) { --y_; draw (); return true; } return false; } ndk::event::result text::at_keyboard (const keyboard &ev) { event::result res = event::ignored; switch (ev.code ()) { case key::right: right (); res = event::accepted; break; case key::left: left (); res = event::accepted; break; case key::up: up (); res = event::accepted; break; case key::down: down (); res = event::accepted; break; default: break; } if (event::accepted == res) { ncurses::pen (*this).commit (); emit (changed); } return res; } int text::string_height (const std::string &str) /**< @return number of strings */ { int count = 0; if (wrapping_ == wrap) /* in wrap mode we need additional recalculations of the string height */ count = str.length () / width () + (str.length () % width () != 0 ? 1 : 0); else /* not wrap mode: only calculate number of '\n' */ count = std::count (str.begin (), str.end (), '\n'); /* we also need an additional space below if line have '\n' at the end */ if (*(str.end () - 1) == '\n') ++count; /* grow width if nesessary */ return count; } int text::string_width (const std::string &str) /**< @return maximum string length */ { std::string::const_iterator beg = str.begin (); const std::string::const_iterator end = str.end (); ptrdiff_t max_len = 0; bool need_fix = true; do { std::string::const_iterator curr (std::find (beg, str.end (), '\n')); max_len = std::max (max_len, std::distance (beg, curr) + ((need_fix) ? ncurses::pen (pad_).x () : 0)); beg = (curr == end) ? curr : (curr + 1); need_fix = false; } while (beg != end); return max_len; } void text::resize (int w, int h) { panel::resize (w, h); /* grow size of the text if we need it */ pad_.resize (std::max (pad_.width (), w + 1), std::max (pad_.height (), h)); } void text::clear () { ncurses::pen (pad_).clear (); x_ = 0; y_ = 0; /* truncate buffer to viewport size */ pad_.resize (this->width (), this->height ()); draw (); } void text::set_text (const std::string &str) { clear (); add_text (str); draw (); } int text::length () const { return pad_.height (); } int text::last_line () const { return y_ + height (); } text_view::text_view (const std::string &title, ndk::panel *parent) : frame (title, parent) , text_ ("", this, text::no_wrap) , title_ (title) { events ()->on_system (slot (&text_view::at_system, this)); in_focus (text_); } void text_view::add_text (const std::string &str) { text_.add_text (str); } void text_view::set_text (const std::string &str) { text_.set_text (str); } void text_view::draw () { /* pack widgets */ packer pack (this, align::center); pack.add (&text_); pack.pack (); frame::draw (); ncurses::pen pen (*this); if (!title_.empty ()) { std::string out (title_); /* if we have enough width made title more beautiful */ const int len = title_.length (); const int wid = width (); if (len < wid) { if (len + 6 < wid) out = " " + out + " "; return_unless (pen.move (align::pos (out.size (), wid, align::center), 0)); } else { out = out.substr (0, wid); return_unless (pen.move (0, 0)); } pen.write (out); } } int text_view::padding () const { /* save frame during packing */ return 1; } void text_view::resize (int w, int h) { panel::resize (w, h); if ((w > 2) && (h > 2)) { w -= 2; h -= 2; text_.resize (w, h); } } ndk::event::result text_view::at_system (const event &ev) { event::result res = event::ignored; if (text_.events () == ev.sender_ && text::changed == ev.type_) res = event::accepted; return res; }