split up widget and basewidget
[mikachu/openbox.git] / otk / widget.cc
1 // -*- mode: C++; indent-tabs-mode: nil; c-basic-offset: 2; -*-
2
3 #ifdef    HAVE_CONFIG_H
4 #  include "../config.h"
5 #endif // HAVE_CONFIG_H
6
7 #include "widget.hh"
8
9 #include <algorithm>
10
11 namespace otk {
12
13 OtkWidget::OtkWidget(OtkWidget *parent, Direction direction)
14   : OtkBaseWidget(parent),
15     OtkEventHandler(),
16     _direction(direction), _stretchable_vert(false), _stretchable_horz(false),
17     _event_dispatcher(parent->getEventDispatcher())
18 {
19   assert(parent);
20   _event_dispatcher->registerHandler(getWindow(), this);
21 }
22
23 OtkWidget::OtkWidget(OtkEventDispatcher *event_dispatcher, Style *style,
24                      Direction direction, Cursor cursor, int bevel_width)
25   : OtkBaseWidget(style, cursor, bevel_width),
26     OtkEventHandler(),
27     _direction(direction), _stretchable_vert(false), _stretchable_horz(false),
28     _event_dispatcher(event_dispatcher)
29 {
30   assert(event_dispatcher);
31   _event_dispatcher->registerHandler(getWindow(), this);
32 }
33
34 OtkWidget::~OtkWidget()
35 {
36   _event_dispatcher->clearHandler(_window);
37 }
38
39 void OtkWidget::adjust(void)
40 {
41   if (_direction == Horizontal)
42     adjustHorz();
43   else
44     adjustVert();
45 }
46
47 void OtkWidget::adjustHorz(void)
48 {
49   if (_children.size() == 0)
50     return;
51
52   OtkWidget *tmp;
53   OtkBaseWidgetList::iterator it, end = _children.end();
54
55   int tallest = 0;
56   int width = _bevel_width;
57   OtkBaseWidgetList stretchable;
58
59   for (it = _children.begin(); it != end; ++it) {
60     if (!(tmp = dynamic_cast<OtkWidget*>(*it))) continue;
61     if (tmp->isStretchableVert())
62       tmp->setHeight(_rect.height() > _bevel_width * 2 ?
63                      _rect.height() - _bevel_width * 2 : _bevel_width);
64     if (tmp->isStretchableHorz())
65       stretchable.push_back(tmp);
66     else
67       width += tmp->_rect.width() + _bevel_width;
68
69     if (tmp->_rect.height() > tallest)
70       tallest = tmp->_rect.height();
71   }
72
73   if (stretchable.size() > 0) {
74     OtkBaseWidgetList::iterator str_it = stretchable.begin(),
75       str_end = stretchable.end();
76
77     int str_width = _rect.width() - width / stretchable.size();
78
79     for (; str_it != str_end; ++str_it)
80       (*str_it)->setWidth(str_width > _bevel_width ? str_width - _bevel_width
81                           : _bevel_width);
82   }
83
84   OtkWidget *prev_widget = 0;
85
86   for (it = _children.begin(); it != end; ++it) {
87     if (!(tmp = dynamic_cast<OtkWidget*>(*it))) continue;
88     int x, y;
89
90     if (prev_widget)
91       x = prev_widget->_rect.x() + prev_widget->_rect.width() + _bevel_width;
92     else
93       x = _rect.x() + _bevel_width;
94     y = (tallest - tmp->_rect.height()) / 2 + _bevel_width;
95
96     tmp->move(x, y);
97
98     prev_widget = tmp;
99   }
100
101   internalResize(width, tallest + _bevel_width * 2);
102 }
103
104 void OtkWidget::adjustVert(void)
105 {
106   if (_children.size() == 0)
107     return;
108
109   OtkWidget *tmp;
110   OtkBaseWidgetList::iterator it, end = _children.end();
111
112   int widest = 0;
113   int height = _bevel_width;
114   OtkBaseWidgetList stretchable;
115
116   for (it = _children.begin(); it != end; ++it) {
117     if (!(tmp = dynamic_cast<OtkWidget*>(*it))) continue;
118     if (tmp->isStretchableHorz())
119       tmp->setWidth(_rect.width() > _bevel_width * 2 ?
120                     _rect.width() - _bevel_width * 2 : _bevel_width);
121     if (tmp->isStretchableVert())
122       stretchable.push_back(tmp);
123     else
124       height += tmp->_rect.height() + _bevel_width;
125
126     if (tmp->_rect.width() > widest)
127       widest = tmp->_rect.width();
128   }
129
130   if (stretchable.size() > 0) {
131     OtkBaseWidgetList::iterator str_it = stretchable.begin(),
132       str_end = stretchable.end();
133
134     int str_height = _rect.height() - height / stretchable.size();
135
136     for (; str_it != str_end; ++str_it)
137       (*str_it)->setHeight(str_height > _bevel_width ?
138                            str_height - _bevel_width : _bevel_width);
139   }
140
141   OtkWidget *prev_widget = 0;
142
143   for (it = _children.begin(); it != end; ++it) {
144     if (!(tmp = dynamic_cast<OtkWidget*>(*it))) continue;
145     int x, y;
146
147     if (prev_widget)
148       y = prev_widget->_rect.y() + prev_widget->_rect.height() + _bevel_width;
149     else
150       y = _rect.y() + _bevel_width;
151     x = (widest - tmp->_rect.width()) / 2 + _bevel_width;
152
153     tmp->move(x, y);
154
155     prev_widget = tmp;
156   }
157
158   internalResize(widest + _bevel_width * 2, height);
159 }
160
161 void OtkWidget::update(void)
162 {
163   if (_dirty)
164     adjust();
165
166   OtkBaseWidget::update();
167 }
168
169 void OtkWidget::internalResize(int w, int h)
170 {
171   assert(w > 0 && h > 0);
172
173 //  if (! _fixed_width && ! _fixed_height)
174     resize(w, h);
175 //  else if (! _fixed_width)
176 //    resize(w, _rect.height());
177 //  else if (! _fixed_height)
178 //    resize(_rect.width(), h);
179 }
180
181 void OtkWidget::setEventDispatcher(OtkEventDispatcher *disp)
182 {
183   if (_event_dispatcher)
184     _event_dispatcher->clearHandler(_window);
185   _event_dispatcher = disp;
186   _event_dispatcher->registerHandler(_window, this);
187 }
188
189 void OtkWidget::exposeHandler(const XExposeEvent &e)
190 {
191   OtkEventHandler::exposeHandler(e);
192   _dirty = true;
193   update();
194 }
195
196 void OtkWidget::configureHandler(const XConfigureEvent &e)
197 {
198   OtkEventHandler::configureHandler(e);
199   if (_ignore_config) {
200     _ignore_config--;
201   } else {
202     if (!(e.width == _rect.width() && e.height == _rect.height())) {
203       _dirty = true;
204       _rect.setSize(e.width, e.height);
205     }
206     update();
207   }
208 }
209
210 }