Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
5 : * This Source Code Form is subject to the terms of the Mozilla Public
6 : * License, v. 2.0. If a copy of the MPL was not distributed with this
7 : * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 : *
9 : * This file incorporates work covered by the following license notice:
10 : *
11 : * Licensed to the Apache Software Foundation (ASF) under one or more
12 : * contributor license agreements. See the NOTICE file distributed
13 : * with this work for additional information regarding copyright
14 : * ownership. The ASF licenses this file to you under the Apache
15 : * License, Version 2.0 (the "License"); you may not use this file
16 : * except in compliance with the License. You may obtain a copy of
17 : * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 : */
19 :
20 :
21 : #include <comphelper/processfactory.hxx>
22 :
23 : #include <tools/rc.h>
24 : #include <vcl/svapp.hxx>
25 : #include <vcl/event.hxx>
26 : #include <vcl/ctrl.hxx>
27 : #include <vcl/decoview.hxx>
28 : #include <vcl/salnativewidgets.hxx>
29 :
30 : #include <textlayout.hxx>
31 : #include <svdata.hxx>
32 : #include <controldata.hxx>
33 :
34 :
35 : using namespace vcl;
36 :
37 : // =======================================================================
38 :
39 1968 : void Control::ImplInitControlData()
40 : {
41 1968 : mbHasControlFocus = sal_False;
42 1968 : mpControlData = new ImplControlData;
43 1968 : }
44 :
45 : // -----------------------------------------------------------------------
46 :
47 1962 : Control::Control( WindowType nType ) :
48 1962 : Window( nType )
49 : {
50 1962 : ImplInitControlData();
51 1962 : }
52 :
53 : // -----------------------------------------------------------------------
54 :
55 6 : Control::Control( Window* pParent, WinBits nStyle ) :
56 6 : Window( WINDOW_CONTROL )
57 : {
58 6 : ImplInitControlData();
59 6 : ImplInit( pParent, nStyle, NULL );
60 6 : }
61 :
62 0 : Control::Control( Window* pParent, const ResId& rResId ) :
63 0 : Window( WINDOW_CONTROL )
64 : {
65 0 : ImplInitControlData();
66 0 : rResId.SetRT( RSC_CONTROL );
67 0 : WinBits nStyle = ImplInitRes( rResId );
68 0 : ImplInit( pParent, nStyle, NULL );
69 0 : ImplLoadRes( rResId );
70 :
71 0 : if ( !(nStyle & WB_HIDE) )
72 0 : Show();
73 0 : }
74 :
75 : // -----------------------------------------------------------------------
76 :
77 1074 : Control::~Control()
78 : {
79 537 : delete mpControlData, mpControlData = NULL;
80 537 : }
81 :
82 : // -----------------------------------------------------------------------
83 :
84 0 : void Control::GetFocus()
85 : {
86 0 : Window::GetFocus();
87 0 : }
88 :
89 : // -----------------------------------------------------------------------
90 :
91 0 : void Control::LoseFocus()
92 : {
93 0 : Window::LoseFocus();
94 0 : }
95 :
96 : // -----------------------------------------------------------------------
97 :
98 1679 : void Control::Resize()
99 : {
100 1679 : ImplClearLayoutData();
101 1679 : Window::Resize();
102 1679 : }
103 :
104 : // -----------------------------------------------------------------------
105 :
106 0 : void Control::FillLayoutData() const
107 : {
108 0 : }
109 :
110 : // -----------------------------------------------------------------------
111 :
112 0 : void Control::CreateLayoutData() const
113 : {
114 : DBG_ASSERT( !mpControlData->mpLayoutData, "Control::CreateLayoutData: should be called with non-existent layout data only!" );
115 0 : mpControlData->mpLayoutData = new ::vcl::ControlLayoutData();
116 0 : }
117 :
118 : // -----------------------------------------------------------------------
119 :
120 0 : bool Control::HasLayoutData() const
121 : {
122 0 : return mpControlData->mpLayoutData != NULL;
123 : }
124 :
125 : // -----------------------------------------------------------------------
126 :
127 0 : ::vcl::ControlLayoutData* Control::GetLayoutData() const
128 : {
129 0 : return mpControlData->mpLayoutData;
130 : }
131 :
132 : // -----------------------------------------------------------------------
133 :
134 0 : void Control::SetText( const String& rStr )
135 : {
136 0 : ImplClearLayoutData();
137 0 : Window::SetText( rStr );
138 0 : }
139 :
140 : // -----------------------------------------------------------------------
141 :
142 0 : Rectangle ControlLayoutData::GetCharacterBounds( long nIndex ) const
143 : {
144 0 : return (nIndex >= 0 && nIndex < (long) m_aUnicodeBoundRects.size()) ? m_aUnicodeBoundRects[ nIndex ] : Rectangle();
145 : }
146 :
147 :
148 : // -----------------------------------------------------------------------
149 :
150 0 : Rectangle Control::GetCharacterBounds( long nIndex ) const
151 : {
152 0 : if( !HasLayoutData() )
153 0 : FillLayoutData();
154 0 : return mpControlData->mpLayoutData ? mpControlData->mpLayoutData->GetCharacterBounds( nIndex ) : Rectangle();
155 : }
156 :
157 : // -----------------------------------------------------------------------
158 :
159 0 : long ControlLayoutData::GetIndexForPoint( const Point& rPoint ) const
160 : {
161 0 : long nIndex = -1;
162 0 : for( long i = m_aUnicodeBoundRects.size()-1; i >= 0; i-- )
163 : {
164 0 : Point aTopLeft = m_aUnicodeBoundRects[i].TopLeft();
165 0 : Point aBottomRight = m_aUnicodeBoundRects[i].BottomRight();
166 0 : if (rPoint.X() >= aTopLeft.X() && rPoint.Y() >= aTopLeft.Y() &&
167 0 : rPoint.X() <= aBottomRight.X() && rPoint.Y() <= aBottomRight.Y())
168 : {
169 0 : nIndex = i;
170 : break;
171 : }
172 : }
173 0 : return nIndex;
174 : }
175 :
176 : // -----------------------------------------------------------------------
177 :
178 0 : long Control::GetIndexForPoint( const Point& rPoint ) const
179 : {
180 0 : if( ! HasLayoutData() )
181 0 : FillLayoutData();
182 0 : return mpControlData->mpLayoutData ? mpControlData->mpLayoutData->GetIndexForPoint( rPoint ) : -1;
183 : }
184 :
185 : // -----------------------------------------------------------------------
186 :
187 0 : long ControlLayoutData::GetLineCount() const
188 : {
189 0 : long nLines = m_aLineIndices.size();
190 0 : if( nLines == 0 && m_aDisplayText.Len() )
191 0 : nLines = 1;
192 0 : return nLines;
193 : }
194 :
195 : // -----------------------------------------------------------------------
196 :
197 0 : Pair ControlLayoutData::GetLineStartEnd( long nLine ) const
198 : {
199 0 : Pair aPair( -1, -1 );
200 :
201 0 : int nDisplayLines = m_aLineIndices.size();
202 0 : if( nLine >= 0 && nLine < nDisplayLines )
203 : {
204 0 : aPair.A() = m_aLineIndices[nLine];
205 0 : if( nLine+1 < nDisplayLines )
206 0 : aPair.B() = m_aLineIndices[nLine+1]-1;
207 : else
208 0 : aPair.B() = m_aDisplayText.Len()-1;
209 : }
210 0 : else if( nLine == 0 && nDisplayLines == 0 && m_aDisplayText.Len() )
211 : {
212 : // special case for single line controls so the implementations
213 : // in that case do not have to fill in the line indices
214 0 : aPair.A() = 0;
215 0 : aPair.B() = m_aDisplayText.Len()-1;
216 : }
217 0 : return aPair;
218 : }
219 :
220 : // -----------------------------------------------------------------------
221 :
222 0 : Pair Control::GetLineStartEnd( long nLine ) const
223 : {
224 0 : if( !HasLayoutData() )
225 0 : FillLayoutData();
226 0 : return mpControlData->mpLayoutData ? mpControlData->mpLayoutData->GetLineStartEnd( nLine ) : Pair( -1, -1 );
227 : }
228 :
229 : // -----------------------------------------------------------------------
230 :
231 0 : long ControlLayoutData::ToRelativeLineIndex( long nIndex ) const
232 : {
233 : // is the index sensible at all ?
234 0 : if( nIndex >= 0 && nIndex < m_aDisplayText.Len() )
235 : {
236 0 : int nDisplayLines = m_aLineIndices.size();
237 : // if only 1 line exists, then absolute and relative index are
238 : // identical -> do nothing
239 0 : if( nDisplayLines > 1 )
240 : {
241 : int nLine;
242 0 : for( nLine = nDisplayLines-1; nLine >= 0; nLine-- )
243 : {
244 0 : if( m_aLineIndices[nLine] <= nIndex )
245 : {
246 0 : nIndex -= m_aLineIndices[nLine];
247 0 : break;
248 : }
249 : }
250 0 : if( nLine < 0 )
251 : {
252 : DBG_ASSERT( nLine >= 0, "ToRelativeLineIndex failed" );
253 0 : nIndex = -1;
254 : }
255 : }
256 : }
257 : else
258 0 : nIndex = -1;
259 :
260 0 : return nIndex;
261 : }
262 :
263 : // -----------------------------------------------------------------------
264 :
265 0 : long Control::ToRelativeLineIndex( long nIndex ) const
266 : {
267 0 : if( !HasLayoutData() )
268 0 : FillLayoutData();
269 0 : return mpControlData->mpLayoutData ? mpControlData->mpLayoutData->ToRelativeLineIndex( nIndex ) : -1;
270 : }
271 :
272 : // -----------------------------------------------------------------------
273 :
274 0 : String Control::GetDisplayText() const
275 : {
276 0 : if( !HasLayoutData() )
277 0 : FillLayoutData();
278 0 : return mpControlData->mpLayoutData ? mpControlData->mpLayoutData->m_aDisplayText : GetText();
279 : }
280 :
281 : // -----------------------------------------------------------------------
282 :
283 6 : long Control::Notify( NotifyEvent& rNEvt )
284 : {
285 6 : if ( rNEvt.GetType() == EVENT_GETFOCUS )
286 : {
287 0 : if ( !mbHasControlFocus )
288 : {
289 0 : mbHasControlFocus = sal_True;
290 0 : StateChanged( STATE_CHANGE_CONTROL_FOCUS );
291 0 : if ( ImplCallEventListenersAndHandler( VCLEVENT_CONTROL_GETFOCUS, maGetFocusHdl, this ) )
292 : // been destroyed within the handler
293 0 : return sal_True;
294 : }
295 : }
296 : else
297 : {
298 6 : if ( rNEvt.GetType() == EVENT_LOSEFOCUS )
299 : {
300 0 : Window* pFocusWin = Application::GetFocusWindow();
301 0 : if ( !pFocusWin || !ImplIsWindowOrChild( pFocusWin ) )
302 : {
303 0 : mbHasControlFocus = sal_False;
304 0 : StateChanged( STATE_CHANGE_CONTROL_FOCUS );
305 0 : if ( ImplCallEventListenersAndHandler( VCLEVENT_CONTROL_LOSEFOCUS, maLoseFocusHdl, this ) )
306 : // been destroyed within the handler
307 0 : return sal_True;
308 : }
309 : }
310 : }
311 :
312 6 : return Window::Notify( rNEvt );
313 : }
314 :
315 : // -----------------------------------------------------------------------
316 :
317 6765 : void Control::StateChanged( StateChangedType nStateChange )
318 : {
319 6765 : if( nStateChange == STATE_CHANGE_INITSHOW ||
320 : nStateChange == STATE_CHANGE_VISIBLE ||
321 : nStateChange == STATE_CHANGE_ZOOM ||
322 : nStateChange == STATE_CHANGE_BORDER ||
323 : nStateChange == STATE_CHANGE_CONTROLFONT
324 : )
325 : {
326 2009 : ImplClearLayoutData();
327 : }
328 6765 : Window::StateChanged( nStateChange );
329 6765 : }
330 :
331 : // -----------------------------------------------------------------------
332 :
333 0 : void Control::AppendLayoutData( const Control& rSubControl ) const
334 : {
335 0 : if( !rSubControl.HasLayoutData() )
336 0 : rSubControl.FillLayoutData();
337 0 : if( !rSubControl.HasLayoutData() || !rSubControl.mpControlData->mpLayoutData->m_aDisplayText.Len() )
338 0 : return;
339 :
340 0 : long nCurrentIndex = mpControlData->mpLayoutData->m_aDisplayText.Len();
341 0 : mpControlData->mpLayoutData->m_aDisplayText.Append( rSubControl.mpControlData->mpLayoutData->m_aDisplayText );
342 0 : int nLines = rSubControl.mpControlData->mpLayoutData->m_aLineIndices.size();
343 : int n;
344 0 : mpControlData->mpLayoutData->m_aLineIndices.push_back( nCurrentIndex );
345 0 : for( n = 1; n < nLines; n++ )
346 0 : mpControlData->mpLayoutData->m_aLineIndices.push_back( rSubControl.mpControlData->mpLayoutData->m_aLineIndices[n] + nCurrentIndex );
347 0 : int nRectangles = rSubControl.mpControlData->mpLayoutData->m_aUnicodeBoundRects.size();
348 0 : Rectangle aRel = const_cast<Control&>(rSubControl).GetWindowExtentsRelative( const_cast<Control*>(this) );
349 0 : for( n = 0; n < nRectangles; n++ )
350 : {
351 0 : Rectangle aRect = rSubControl.mpControlData->mpLayoutData->m_aUnicodeBoundRects[n];
352 0 : aRect.Move( aRel.Left(), aRel.Top() );
353 0 : mpControlData->mpLayoutData->m_aUnicodeBoundRects.push_back( aRect );
354 : }
355 : }
356 :
357 : // -----------------------------------------------------------------
358 :
359 0 : sal_Bool Control::ImplCallEventListenersAndHandler( sal_uLong nEvent, const Link& rHandler, void* pCaller )
360 : {
361 0 : ImplDelData aCheckDelete;
362 0 : ImplAddDel( &aCheckDelete );
363 :
364 0 : ImplCallEventListeners( nEvent );
365 0 : if ( !aCheckDelete.IsDead() )
366 : {
367 0 : rHandler.Call( pCaller );
368 :
369 0 : if ( !aCheckDelete.IsDead() )
370 : {
371 0 : ImplRemoveDel( &aCheckDelete );
372 0 : return sal_False;
373 : }
374 : }
375 0 : return sal_True;
376 : }
377 :
378 : // -----------------------------------------------------------------
379 :
380 0 : void Control::SetLayoutDataParent( const Control* pParent ) const
381 : {
382 0 : if( HasLayoutData() )
383 0 : mpControlData->mpLayoutData->m_pParent = pParent;
384 0 : }
385 :
386 : // -----------------------------------------------------------------
387 :
388 3984 : void Control::ImplClearLayoutData() const
389 : {
390 3984 : delete mpControlData->mpLayoutData, mpControlData->mpLayoutData = NULL;
391 3984 : }
392 :
393 : // -----------------------------------------------------------------------
394 :
395 0 : void Control::ImplDrawFrame( OutputDevice* pDev, Rectangle& rRect )
396 : {
397 : // use a deco view to draw the frame
398 : // However, since there happens a lot of magic there, we need to fake some (style) settings
399 : // on the device
400 0 : AllSettings aOriginalSettings( pDev->GetSettings() );
401 :
402 0 : AllSettings aNewSettings( aOriginalSettings );
403 0 : StyleSettings aStyle( aNewSettings.GetStyleSettings() );
404 :
405 : // The *only known* clients of the Draw methods of the various VCL-controls are form controls:
406 : // During print preview, and during printing, Draw is called. Thus, drawing always happens with a
407 : // mono (colored) border
408 0 : aStyle.SetOptions( aStyle.GetOptions() | STYLE_OPTION_MONO );
409 0 : aStyle.SetMonoColor( GetSettings().GetStyleSettings().GetMonoColor() );
410 :
411 0 : aNewSettings.SetStyleSettings( aStyle );
412 : // #i67023# do not call data changed listeners for this fake
413 : // since they may understandably invalidate on settings changed
414 0 : pDev->OutputDevice::SetSettings( aNewSettings );
415 :
416 0 : DecorationView aDecoView( pDev );
417 0 : rRect = aDecoView.DrawFrame( rRect, FRAME_DRAW_WINDOWBORDER );
418 :
419 0 : pDev->OutputDevice::SetSettings( aOriginalSettings );
420 0 : }
421 :
422 : // -----------------------------------------------------------------------
423 :
424 784 : void Control::DataChanged( const DataChangedEvent& rDCEvt)
425 : {
426 : // we don't want to loose some style settings for controls created with the
427 : // toolkit
428 784 : if ( IsCreatedWithToolkit() &&
429 0 : (rDCEvt.GetType() == DATACHANGED_SETTINGS) &&
430 0 : (rDCEvt.GetFlags() & SETTINGS_STYLE) )
431 : {
432 0 : AllSettings aSettings = GetSettings();
433 0 : StyleSettings aStyleSettings = aSettings.GetStyleSettings();
434 0 : sal_uLong nOldOptions = rDCEvt.GetOldSettings()->GetStyleSettings().GetOptions();
435 0 : sal_uLong nNewOptions = aStyleSettings.GetOptions();
436 :
437 0 : if ( !(nNewOptions & STYLE_OPTION_MONO) && ( nOldOptions & STYLE_OPTION_MONO ) )
438 : {
439 0 : nNewOptions |= STYLE_OPTION_MONO;
440 0 : aStyleSettings.SetOptions( nNewOptions );
441 0 : aStyleSettings.SetMonoColor( rDCEvt.GetOldSettings()->GetStyleSettings().GetMonoColor() );
442 0 : aSettings.SetStyleSettings( aStyleSettings );
443 0 : SetSettings( aSettings );
444 0 : }
445 : }
446 784 : }
447 :
448 : // -----------------------------------------------------------------
449 :
450 0 : ControlLayoutData::~ControlLayoutData()
451 : {
452 0 : if( m_pParent )
453 0 : m_pParent->ImplClearLayoutData();
454 0 : }
455 :
456 : // -----------------------------------------------------------------
457 :
458 0 : Size Control::GetOptimalSize(WindowSizeType eType) const
459 : {
460 0 : switch (eType) {
461 : case WINDOWSIZE_MINIMUM:
462 0 : return Size( GetTextWidth( GetText() ) + 2 * 12,
463 0 : GetTextHeight() + 2 * 6 );
464 : case WINDOWSIZE_PREFERRED:
465 0 : return GetOptimalSize( WINDOWSIZE_MINIMUM );
466 : case WINDOWSIZE_MAXIMUM:
467 : default:
468 0 : return Size( LONG_MAX, LONG_MAX );
469 : }
470 : }
471 :
472 : // -----------------------------------------------------------------
473 :
474 0 : void Control::SetReferenceDevice( OutputDevice* _referenceDevice )
475 : {
476 0 : if ( mpControlData->mpReferenceDevice == _referenceDevice )
477 0 : return;
478 :
479 0 : mpControlData->mpReferenceDevice = _referenceDevice;
480 0 : Invalidate();
481 : }
482 :
483 : // -----------------------------------------------------------------
484 :
485 0 : OutputDevice* Control::GetReferenceDevice() const
486 : {
487 0 : return mpControlData->mpReferenceDevice;
488 : }
489 :
490 : // -----------------------------------------------------------------
491 :
492 0 : const Font& Control::GetCanonicalFont( const StyleSettings& _rStyle ) const
493 : {
494 0 : return _rStyle.GetLabelFont();
495 : }
496 :
497 : // -----------------------------------------------------------------
498 0 : const Color& Control::GetCanonicalTextColor( const StyleSettings& _rStyle ) const
499 : {
500 0 : return _rStyle.GetLabelTextColor();
501 : }
502 :
503 : // -----------------------------------------------------------------
504 1212 : void Control::ImplInitSettings( const sal_Bool _bFont, const sal_Bool _bForeground )
505 : {
506 1212 : const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings();
507 :
508 1212 : if ( _bFont )
509 : {
510 1212 : Font aFont( GetCanonicalFont( rStyleSettings ) );
511 1212 : if ( IsControlFont() )
512 0 : aFont.Merge( GetControlFont() );
513 1212 : SetZoomedPointFont( aFont );
514 : }
515 :
516 1212 : if ( _bForeground || _bFont )
517 : {
518 1212 : Color aColor;
519 1212 : if ( IsControlForeground() )
520 0 : aColor = GetControlForeground();
521 : else
522 1212 : aColor = GetCanonicalTextColor( rStyleSettings );
523 1212 : SetTextColor( aColor );
524 1212 : SetTextFillColor();
525 : }
526 1212 : }
527 :
528 : // -----------------------------------------------------------------
529 :
530 0 : void Control::DrawControlText( OutputDevice& _rTargetDevice, Rectangle& _io_rRect, const XubString& _rStr,
531 : sal_uInt16 _nStyle, MetricVector* _pVector, String* _pDisplayText ) const
532 : {
533 : #ifdef FS_DEBUG
534 : if ( !_pVector )
535 : {
536 : static MetricVector aCharRects;
537 : static String sDisplayText;
538 : aCharRects.clear();
539 : sDisplayText = String();
540 : _pVector = &aCharRects;
541 : _pDisplayText = &sDisplayText;
542 : }
543 : #endif
544 :
545 0 : if ( !mpControlData->mpReferenceDevice || ( mpControlData->mpReferenceDevice == &_rTargetDevice ) )
546 : {
547 0 : _io_rRect = _rTargetDevice.GetTextRect( _io_rRect, _rStr, _nStyle );
548 0 : _rTargetDevice.DrawText( _io_rRect, _rStr, _nStyle, _pVector, _pDisplayText );
549 : }
550 : else
551 : {
552 0 : ControlTextRenderer aRenderer( *this, _rTargetDevice, *mpControlData->mpReferenceDevice );
553 0 : _io_rRect = aRenderer.DrawText( _io_rRect, _rStr, _nStyle, _pVector, _pDisplayText );
554 : }
555 :
556 : #ifdef FS_DEBUG
557 : _rTargetDevice.Push( PUSH_LINECOLOR | PUSH_FILLCOLOR );
558 : _rTargetDevice.SetLineColor( COL_LIGHTRED );
559 : _rTargetDevice.SetFillColor();
560 : for ( MetricVector::const_iterator cr = _pVector->begin();
561 : cr != _pVector->end();
562 : ++cr
563 : )
564 : {
565 : _rTargetDevice.DrawRect( *cr );
566 : }
567 : _rTargetDevice.Pop();
568 : #endif
569 0 : }
570 :
571 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|