kexi

kexiscrollview.cpp
1/* This file is part of the KDE project
2 Copyright (C) 2004 Cedric Pasteur <cedric.pasteur@free.fr>
3 Copyright (C) 2004 Jaroslaw Staniek <js@iidea.pl>
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Library General Public
7 License as published by the Free Software Foundation; either
8 version 2 of the License, or (at your option) any later version.
9
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Library General Public License for more details.
14
15 You should have received a copy of the GNU Library General Public License
16 along with this library; see the file COPYING.LIB. If not, write to
17 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 * Boston, MA 02110-1301, USA.
19*/
20#include "kexiscrollview.h"
21
22#include <tqcursor.h>
23#include <tqobjectlist.h>
24#include <tqpainter.h>
25#include <tqpixmap.h>
26
27#include <kdebug.h>
28#include <kstaticdeleter.h>
29#include <tdelocale.h>
30
31#include <utils/kexirecordnavigator.h>
32#include <core/kexi.h>
33#include <kexiutils/utils.h>
34
36class KexiScrollViewData
37{
38 public:
39 TQPixmap horizontalOuterAreaPixmapBuffer;
40 TQPixmap verticalOuterAreaPixmapBuffer;
41};
42
43// @todo warning: not reentrant!
44static KStaticDeleter<KexiScrollViewData> KexiScrollView_data_deleter;
45KexiScrollViewData* KexiScrollView_data = 0;
46
47KexiScrollView::KexiScrollView(TQWidget *parent, bool preview)
48 : TQScrollView(parent, "kexiscrollview", WStaticContents)
49 , m_widget(0)
50 , m_helpFont(font())
51 , m_preview(preview)
52 , m_scrollViewNavPanel(0)
53{
54 setFrameStyle(TQFrame::WinPanel | TQFrame::Sunken);
55 viewport()->setPaletteBackgroundColor(colorGroup().mid());
56 TQColor fc = palette().active().foreground(),
57 bc = viewport()->paletteBackgroundColor();
58 m_helpColor = KexiUtils::blendedColors(fc, bc, 1, 2);
59// m_helpColor = TQColor((fc.red()+bc.red()*2)/3, (fc.green()+bc.green()*2)/3,
60// (fc.blue()+bc.blue()*2)/3);
61 m_helpFont.setPointSize( m_helpFont.pointSize() * 3 );
62
63 setFocusPolicy(TQWidget::WheelFocus);
64
65 //initial resize mode is always manual;
66 //will be changed on show(), if needed
67 setResizePolicy(Manual);
68
69 viewport()->setMouseTracking(true);
70 m_resizing = false;
71 m_enableResizing = true;
72 m_snapToGrid = false;
73 m_gridSize = 0;
74 m_outerAreaVisible = true;
75
76 connect(&m_delayedResize, TQ_SIGNAL(timeout()), this, TQ_SLOT(refreshContentsSize()));
77 m_smodeSet = false;
78 if (m_preview) {
79 refreshContentsSizeLater(true, true);
81 updateScrollBars();
82 m_scrollViewNavPanel = new KexiRecordNavigator(this, leftMargin(), "nav");
83 m_scrollViewNavPanel->setSizePolicy(TQSizePolicy::Minimum,TQSizePolicy::Preferred);
84 }
85}
86
87KexiScrollView::~KexiScrollView()
88{
89}
90
91void
92KexiScrollView::setWidget(TQWidget *w)
93{
94 addChild(w);
95 m_widget = w;
96}
97
98void
99KexiScrollView::setRecordNavigatorVisible(bool visible)
100{
101 if(/*m_scrollViewNavPanel->isVisible() &&*/ !visible)
102 m_scrollViewNavPanel->hide();
103 else if(visible) {
104 m_scrollViewNavPanel->show();
105 updateNavPanelGeometry();
106 }
107}
108
109void
110KexiScrollView::setSnapToGrid(bool enable, int gridSize)
111{
112 m_snapToGrid = enable;
113 if(enable) {
114 m_gridSize = gridSize;
115 }
116}
117
118void
119KexiScrollView::refreshContentsSizeLater(bool horizontal, bool vertical)
120{
121 Q_UNUSED( horizontal );
122 Q_UNUSED( vertical );
123
124 if (!m_smodeSet) {
125 m_smodeSet = true;
126 m_vsmode = vScrollBarMode();
127 m_hsmode = hScrollBarMode();
128 }
129// if (vertical)
130 setVScrollBarMode(TQScrollView::AlwaysOff);
131 //if (horizontal)
132 setHScrollBarMode(TQScrollView::AlwaysOff);
133 updateScrollBars();
134 m_delayedResize.start( 100, true );
135}
136
137void
139{
140 if(!m_widget)
141 return;
142 if (m_preview) {
143 resizeContents(m_widget->width(), m_widget->height());
144// kdDebug() << "KexiScrollView::refreshContentsSize(): ( "
145 // << m_widget->width() <<", "<< m_widget->height() << endl;
146 setVScrollBarMode(m_vsmode);
147 setHScrollBarMode(m_hsmode);
148 m_smodeSet = false;
149 updateScrollBars();
150 }
151 else {
152 // Ensure there is always space to resize Form
153 int w = contentsWidth(), h = contentsHeight();
154 bool change = false;
155 const int delta_x = TQMAX( (KexiScrollView_data ?
156 KexiScrollView_data->verticalOuterAreaPixmapBuffer.width() : 0), 300);
157 const int delta_y = TQMAX( (KexiScrollView_data ?
158 KexiScrollView_data->horizontalOuterAreaPixmapBuffer.height() : 0), 300);
159 if((m_widget->width() + delta_x * 2 / 3) > w) {
160 w = m_widget->width() + delta_x;
161 change = true;
162 }
163 else if((w - m_widget->width()) > delta_x) {
164 w = m_widget->width() + delta_x;
165 change = true;
166 }
167 if((m_widget->height() + delta_y * 2 / 3) > h) {
168 h = m_widget->height() + delta_y;
169 change = true;
170 }
171 else if((h - m_widget->height()) > delta_y) {
172 h = m_widget->height() + delta_y;
173 change = true;
174 }
175 if (change) {
176 repaint();
177 viewport()->repaint();
178 repaintContents();
179 updateContents(0, 0, 2000,2000);
180 clipper()->repaint();
181
182 resizeContents(w, h);
183 }
184// kdDebug() << "KexiScrollView::refreshContentsSize(): ( "
185 // << contentsWidth() <<", "<< contentsHeight() << endl;
186 updateScrollBars();
187 setVScrollBarMode(Auto);
188 setHScrollBarMode(Auto);
189 }
190 updateContents();
191 updateScrollBars();
192}
193
194void
195KexiScrollView::updateNavPanelGeometry()
196{
197 if (m_scrollViewNavPanel)
198 m_scrollViewNavPanel->updateGeometry(leftMargin());
199}
200
201void
202KexiScrollView::contentsMousePressEvent(TQMouseEvent *ev)
203{
204 if(!m_widget)
205 return;
206
207 TQRect r3(0, 0, m_widget->width() + 4, m_widget->height() + 4);
208 if(!r3.contains(ev->pos())) // clicked outside form
209 //m_form->resetSelection();
210 emit outerAreaClicked();
211
212 if(!m_enableResizing)
213 return;
214
215 TQRect r(m_widget->width(), 0, 4, m_widget->height() + 4); // right limit
216 TQRect r2(0, m_widget->height(), m_widget->width() + 4, 4); // bottom limit
217 if(r.contains(ev->pos()) || r2.contains(ev->pos()))
218 {
219 m_resizing = true;
220 emit resizingStarted();
221 }
222}
223
224void
225KexiScrollView::contentsMouseReleaseEvent(TQMouseEvent *)
226{
227 if(m_resizing) {
228 m_resizing = false;
229 emit resizingEnded();
230 }
231
232 unsetCursor();
233}
234
235void
236KexiScrollView::contentsMouseMoveEvent(TQMouseEvent *ev)
237{
238 if(!m_widget || !m_enableResizing)
239 return;
240
241 if(m_resizing) // resize widget
242 {
243 int tmpx = ev->x(), tmpy = ev->y();
244 const int exceeds_x = (tmpx - contentsX() + 5) - clipper()->width();
245 const int exceeds_y = (tmpy - contentsY() + 5) - clipper()->height();
246 if (exceeds_x > 0)
247 tmpx -= exceeds_x;
248 if (exceeds_y > 0)
249 tmpy -= exceeds_y;
250 if ((tmpx - contentsX()) < 0)
251 tmpx = contentsX();
252 if ((tmpy - contentsY()) < 0)
253 tmpy = contentsY();
254
255 // we look for the max widget right() (or bottom()), which would be the limit for form resizing (not to hide widgets)
256 TQObjectList *list = m_widget->queryList("TQWidget", 0, true, false /* not recursive*/);
257 for(TQObject *o = list->first(); o; o = list->next())
258 {
259 TQWidget *w = (TQWidget*)o;
260 tmpx = TQMAX(tmpx, (w->geometry().right() + 10));
261 tmpy = TQMAX(tmpy, (w->geometry().bottom() + 10));
262 }
263 delete list;
264
265 int neww = -1, newh;
266 if(cursor().shape() == TQCursor::SizeHorCursor)
267 {
268 if(m_snapToGrid)
269 neww = int( float(tmpx) / float(m_gridSize) + 0.5 ) * m_gridSize;
270 else
271 neww = tmpx;
272 newh = m_widget->height();
273 }
274 else if(cursor().shape() == TQCursor::SizeVerCursor)
275 {
276 neww = m_widget->width();
277 if(m_snapToGrid)
278 newh = int( float(tmpy) / float(m_gridSize) + 0.5 ) * m_gridSize;
279 else
280 newh = tmpy;
281 }
282 else if(cursor().shape() == TQCursor::SizeFDiagCursor)
283 {
284 if(m_snapToGrid) {
285 neww = int( float(tmpx) / float(m_gridSize) + 0.5 ) * m_gridSize;
286 newh = int( float(tmpy) / float(m_gridSize) + 0.5 ) * m_gridSize;
287 } else {
288 neww = tmpx;
289 newh = tmpy;
290 }
291 }
292 //needs update?
293 if (neww!=-1 && m_widget->size() != TQSize(neww, newh)) {
294 m_widget->resize( neww, newh );
296 updateContents();
297 }
298 }
299 else // update mouse cursor
300 {
301 TQPoint p = ev->pos();
302 TQRect r(m_widget->width(), 0, 4, m_widget->height()); // right
303 TQRect r2(0, m_widget->height(), m_widget->width(), 4); // bottom
304 TQRect r3(m_widget->width(), m_widget->height(), 4, 4); // bottom-right corner
305
306 if(r.contains(p))
307 setCursor(TQCursor::SizeHorCursor);
308 else if(r2.contains(p))
309 setCursor(TQCursor::SizeVerCursor);
310 else if(r3.contains(p))
311 setCursor(TQCursor::SizeFDiagCursor);
312 else
313 unsetCursor();
314 }
315}
316
317void
318KexiScrollView::setupPixmapBuffer(TQPixmap& pixmap, const TQString& text, int lines)
319{
320 Q_UNUSED( lines );
321
322 TQFontMetrics fm(m_helpFont);
323 const int flags = TQt::AlignCenter|TQt::AlignTop;
324 TQRect rect(fm.boundingRect(0,0,1000,1000,flags,text));
325 const int txtw = rect.width(), txth = rect.height();//fm.width(text), txth = fm.height()*lines;
326 pixmap = TQPixmap(txtw, txth);
327 if (!pixmap.isNull()) {
328 //create pixmap once
329 pixmap.fill( viewport()->paletteBackgroundColor() );
330 TQPainter pb(&pixmap, this);
331 pb.setPen(m_helpColor);
332 pb.setFont(m_helpFont);
333 pb.drawText(0, 0, txtw, txth, TQt::AlignCenter|TQt::AlignTop, text);
334 }
335}
336
337void
338KexiScrollView::drawContents( TQPainter * p, int clipx, int clipy, int clipw, int cliph )
339{
340 TQScrollView::drawContents(p, clipx, clipy, clipw, cliph);
341 if (m_widget) {
342 if(m_preview || !m_outerAreaVisible)
343 return;
344
345 //draw right and bottom borders
346 const int wx = childX(m_widget);
347 const int wy = childY(m_widget);
348 p->setPen(palette().active().foreground());
349 p->drawLine(wx+m_widget->width(), wy, wx+m_widget->width(), wy+m_widget->height());
350 p->drawLine(wx, wy+m_widget->height(), wx+m_widget->width(), wy+m_widget->height());
351//kdDebug() << "KexiScrollView::drawContents() " << wy+m_widget->height() << endl;
352
353 if (!KexiScrollView_data) {
354 KexiScrollView_data_deleter.setObject( KexiScrollView_data, new KexiScrollViewData() );
355
356 //create flicker-less buffer
357 setupPixmapBuffer( KexiScrollView_data->horizontalOuterAreaPixmapBuffer, i18n("Outer Area"), 1 );
358 setupPixmapBuffer( KexiScrollView_data->verticalOuterAreaPixmapBuffer, i18n("Outer\nArea"), 2 );
359 }
360 if (!KexiScrollView_data->horizontalOuterAreaPixmapBuffer.isNull()
361 && !KexiScrollView_data->verticalOuterAreaPixmapBuffer.isNull()
362 && !m_delayedResize.isActive() /* only draw text if there's not pending delayed resize*/)
363 {
364 if (m_widget->height()>(KexiScrollView_data->verticalOuterAreaPixmapBuffer.height()+20)) {
365 p->drawPixmap(
366 TQMAX( m_widget->width(), KexiScrollView_data->verticalOuterAreaPixmapBuffer.width() + 20 ) + 20,
367 TQMAX( (m_widget->height() - KexiScrollView_data->verticalOuterAreaPixmapBuffer.height())/2, 20 ),
368 KexiScrollView_data->verticalOuterAreaPixmapBuffer
369 );
370 }
371 p->drawPixmap(
372 TQMAX( (m_widget->width() - KexiScrollView_data->horizontalOuterAreaPixmapBuffer.width())/2, 20 ),
373 TQMAX( m_widget->height(), KexiScrollView_data->horizontalOuterAreaPixmapBuffer.height() + 20 ) + 20,
374 KexiScrollView_data->horizontalOuterAreaPixmapBuffer
375 );
376 }
377 }
378}
379
380void
381KexiScrollView::leaveEvent( TQEvent *e )
382{
383 TQWidget::leaveEvent(e);
384 m_widget->update(); //update form elements on too fast mouse move
385}
386
387void
388KexiScrollView::setHBarGeometry( TQScrollBar & hbar, int x, int y, int w, int h )
389{
390/*todo*/
391// kdDebug(44021)<<"KexiScrollView::setHBarGeometry"<<endl;
392 if (m_scrollViewNavPanel && m_scrollViewNavPanel->isVisible()) {
393 m_scrollViewNavPanel->setHBarGeometry( hbar, x, y, w, h );
394 }
395 else {
396 hbar.setGeometry( x, y, w, h );
397 }
398}
399
401KexiScrollView::recordNavigator() const
402{
403 return m_scrollViewNavPanel;
404}
405
406#include "kexiscrollview.moc"
407
KexiRecordNavigator class provides a record navigator.
void setHBarGeometry(TQScrollBar &hbar, int x, int y, int w, int h)
KexiScrollView(TQWidget *parent, bool preview)
virtual void refreshContentsSize()
TQScrollView::ScrollBarMode m_vsmode
for refreshContentsSizeLater()
KEXIUTILS_EXPORT TQColor blendedColors(const TQColor &c1, const TQColor &c2, int factor1=1, int factor2=1)