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