]> icculus.org git repositories - dana/openbox.git/blob - otk/label.cc
signed ints instead of unsigned ints again. less pain. pain bad.
[dana/openbox.git] / otk / label.cc
1 // -*- mode: C++; indent-tabs-mode: nil; c-basic-offset: 2; -*-
2
3 #ifdef HAVE_CONFIG_H
4 # include "../config.h"
5 #endif
6
7 #include "label.hh"
8 #include "display.hh"
9 #include "rendercontrol.hh"
10
11 #include <string>
12
13 namespace otk {
14
15 Label::Label(Widget *parent)
16   : Widget(parent),
17     _text(""),
18     _justify_horz(RenderStyle::LeftTopJustify),
19     _justify_vert(RenderStyle::LeftTopJustify),
20     _highlight(false)
21 {
22   styleChanged(*RenderStyle::style(screen()));
23 }
24
25 Label::~Label()
26 {
27 }
28
29 void Label::setHorizontalJustify(RenderStyle::Justify j)
30 {
31   _justify_horz = j;
32   refresh();
33 }
34
35 void Label::setVerticalJustify(RenderStyle::Justify j)
36 {
37   _justify_vert = j;
38   refresh();
39 }
40
41 void Label::setHighlighted(bool h)
42 {
43   _highlight = h;
44   styleChanged(*RenderStyle::style(screen()));
45   refresh();
46 }
47
48 void Label::setText(const ustring &text)
49 {
50   bool utf = text.utf8();
51   std::string s = text.c_str(); // use a normal string, for its functionality
52
53   _parsedtext.clear();
54   
55   // parse it into multiple lines
56   std::string::size_type p = 0;
57   while (p != std::string::npos) {
58     std::string::size_type p2 = s.find('\n', p);
59     _parsedtext.push_back(s.substr(p, (p2==std::string::npos?p2:p2-p)));
60     _parsedtext.back().setUtf8(utf);
61     p = (p2==std::string::npos?p2:p2+1);
62   }
63   calcDefaultSizes();
64 }
65
66 void Label::setFont(const Font *f)
67 {
68   _font = f;
69   calcDefaultSizes();
70 }
71
72 void Label::calcDefaultSizes()
73 {
74   int longest = 0;
75   // find the longest line
76   std::vector<ustring>::iterator it, end = _parsedtext.end();
77   for (it = _parsedtext.begin(); it != end; ++it) {
78     int length = _font->measureString(*it);
79     if (length < 0) continue; // lines too long get skipped
80     if (length > longest) longest = length;
81   }
82   setMinSize(Size(longest + borderWidth() * 2 + bevel() * 4,
83                   _parsedtext.size() * _font->height() + borderWidth() * 2 +
84                   bevel() * 2));
85 }
86   
87 void Label::styleChanged(const RenderStyle &style)
88 {
89   if (_highlight) {
90     _texture = style.labelFocusBackground();
91     _forecolor = style.textFocusColor();
92   } else {
93     _texture = style.labelUnfocusBackground();
94     _forecolor = style.textUnfocusColor();
95   }
96   if (_font != style.labelFont()) {
97     _font = style.labelFont();
98     calcDefaultSizes();
99   }
100 }
101
102 void Label::renderForeground(Surface &surface)
103 {
104   const RenderControl *control = display->renderControl(screen());
105   int sidemargin = bevel() * 2;
106   int y = bevel();
107   int w = area().width() - borderWidth() * 2 - sidemargin * 2;
108   int h = area().height() - borderWidth() * 2 - bevel() * 2;
109
110   switch (_justify_vert) {
111   case RenderStyle::RightBottomJustify:
112     y += h - (_parsedtext.size() * _font->height());
113     if (y < bevel()) y = bevel();
114     break;
115   case RenderStyle::CenterJustify:
116     y += (h - (_parsedtext.size() * _font->height())) / 2;
117     if (y < bevel()) y = bevel();
118     break;
119   case RenderStyle::LeftTopJustify:
120     break;
121   }
122   
123   if (w <= 0) return; // can't fit anything
124   
125   std::vector<ustring>::iterator it, end = _parsedtext.end();
126   for (it = _parsedtext.begin(); it != end; ++it, y += _font->height()) {
127     ustring t = *it; // the actual text to draw
128     int x = sidemargin;    // x coord for the text
129
130     // find a string that will fit inside the area for text
131     ustring::size_type text_len = t.size();
132     int length;
133       
134     do {
135       t.resize(text_len);
136       length = _font->measureString(t);
137     } while (length > w && text_len-- > 0);
138     if (length < 0) continue; // lines too long get skipped
139
140     if (text_len <= 0) continue; // won't fit anything
141
142     // justify the text
143     switch (_justify_horz) {
144     case RenderStyle::RightBottomJustify:
145       x += w - length;
146       break;
147     case RenderStyle::CenterJustify:
148       x += (w - length) / 2;
149       break;
150     case RenderStyle::LeftTopJustify:
151       break;
152     }
153  
154     control->drawString(surface, *_font, x, y, *_forecolor, t);
155  }
156 }
157
158 }