// -*- mode: C++; indent-tabs-mode: nil; c-basic-offset: 2; -*- #include "config.h" #include "label.hh" #include "display.hh" #include "rendercontrol.hh" #include namespace otk { Label::Label(int screen, EventDispatcher *ed, int bevel) : Widget(screen, ed, Widget::Horizontal, bevel, true), _text(""), _font(0), _justify_horz(RenderStyle::LeftTopJustify), _justify_vert(RenderStyle::LeftTopJustify), _highlight(false) { styleChanged(*RenderStyle::style(screen)); } Label::Label(Widget *parent) : Widget(parent), _text(""), _font(0), _justify_horz(RenderStyle::LeftTopJustify), _justify_vert(RenderStyle::LeftTopJustify), _highlight(false) { styleChanged(*RenderStyle::style(screen())); } Label::~Label() { } void Label::setHorizontalJustify(RenderStyle::Justify j) { _justify_horz = j; refresh(); } void Label::setVerticalJustify(RenderStyle::Justify j) { _justify_vert = j; refresh(); } void Label::setHighlighted(bool h) { _highlight = h; styleChanged(*RenderStyle::style(screen())); refresh(); } void Label::setText(const ustring &text) { bool utf = text.utf8(); std::string s = text.c_str(); // use a normal string, for its functionality _parsedtext.clear(); _text = text; // parse it into multiple lines std::string::size_type p = 0; while (p != std::string::npos) { std::string::size_type p2 = s.find('\n', p); std::string s(s.substr(p, (p2==std::string::npos?p2:p2-p))); // turn tabs into spaces (multiples of 8) std::string::size_type t; while ((t = s.find('\t')) != std::string::npos) s.replace(t, 1, std::string(8 - t % 8, ' ')); _parsedtext.push_back(s); _parsedtext.back().setUtf8(utf); p = (p2==std::string::npos?p2:p2+1); } calcDefaultSizes(); } void Label::setFont(const Font *f) { _font = f; calcDefaultSizes(); } void Label::calcDefaultSizes() { int longest = 0; // find the longest line std::vector::iterator it, end = _parsedtext.end(); for (it = _parsedtext.begin(); it != end; ++it) { int length = _font->measureString(*it); if (length < 0) continue; // lines too long get skipped if (length > longest) longest = length; } setMinSize(Size(longest + borderWidth() * 2 + bevel() * 4, _parsedtext.size() * _font->height() + borderWidth() * 2 + bevel() * 2)); } void Label::styleChanged(const RenderStyle &style) { if (_highlight) { _texture = style.labelFocusBackground(); _forecolor = style.textFocusColor(); } else { _texture = style.labelUnfocusBackground(); _forecolor = style.textUnfocusColor(); } if (_font != style.labelFont()) { _font = style.labelFont(); calcDefaultSizes(); } } void Label::renderForeground(Surface &surface) { const RenderControl *control = display->renderControl(screen()); int sidemargin = bevel() * 2; int y = bevel(); int w = area().width() - borderWidth() * 2 - sidemargin * 2; int h = area().height() - borderWidth() * 2 - bevel() * 2; switch (_justify_vert) { case RenderStyle::RightBottomJustify: y += h - (_parsedtext.size() * _font->height()); if (y < bevel()) y = bevel(); break; case RenderStyle::CenterJustify: y += (h - (_parsedtext.size() * _font->height())) / 2; if (y < bevel()) y = bevel(); break; case RenderStyle::LeftTopJustify: break; } if (w <= 0) return; // can't fit anything std::vector::iterator it, end = _parsedtext.end(); for (it = _parsedtext.begin(); it != end; ++it, y += _font->height()) { ustring t = *it; // the actual text to draw int x = sidemargin; // x coord for the text // find a string that will fit inside the area for text ustring::size_type text_len = t.size(); int length; do { t.resize(text_len); length = _font->measureString(t); } while (length > w && text_len-- > 0); if (length < 0) continue; // lines too long get skipped if (text_len <= 0) continue; // won't fit anything // justify the text switch (_justify_horz) { case RenderStyle::RightBottomJustify: x += w - length; break; case RenderStyle::CenterJustify: x += (w - length) / 2; break; case RenderStyle::LeftTopJustify: break; } control->drawString(surface, *_font, x, y, *_forecolor, t); } } }