1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
21 #include <comphelper/processfactory.hxx>
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>
30 #include <textlayout.hxx>
32 #include <controldata.hxx>
37 // =======================================================================
39 void Control::ImplInitControlData()
41 mbHasControlFocus
= sal_False
;
42 mpControlData
= new ImplControlData
;
45 // -----------------------------------------------------------------------
47 Control::Control( WindowType nType
) :
50 ImplInitControlData();
53 // -----------------------------------------------------------------------
55 Control::Control( Window
* pParent
, WinBits nStyle
) :
56 Window( WINDOW_CONTROL
)
58 ImplInitControlData();
59 ImplInit( pParent
, nStyle
, NULL
);
62 Control::Control( Window
* pParent
, const ResId
& rResId
) :
63 Window( WINDOW_CONTROL
)
65 ImplInitControlData();
66 rResId
.SetRT( RSC_CONTROL
);
67 WinBits nStyle
= ImplInitRes( rResId
);
68 ImplInit( pParent
, nStyle
, NULL
);
69 ImplLoadRes( rResId
);
71 if ( !(nStyle
& WB_HIDE
) )
75 // -----------------------------------------------------------------------
79 delete mpControlData
, mpControlData
= NULL
;
82 // -----------------------------------------------------------------------
84 void Control::GetFocus()
89 // -----------------------------------------------------------------------
91 void Control::LoseFocus()
96 // -----------------------------------------------------------------------
98 void Control::Resize()
100 ImplClearLayoutData();
104 // -----------------------------------------------------------------------
106 void Control::FillLayoutData() const
110 // -----------------------------------------------------------------------
112 void Control::CreateLayoutData() const
114 DBG_ASSERT( !mpControlData
->mpLayoutData
, "Control::CreateLayoutData: should be called with non-existent layout data only!" );
115 mpControlData
->mpLayoutData
= new ::vcl::ControlLayoutData();
118 // -----------------------------------------------------------------------
120 bool Control::HasLayoutData() const
122 return mpControlData
->mpLayoutData
!= NULL
;
125 // -----------------------------------------------------------------------
127 ::vcl::ControlLayoutData
* Control::GetLayoutData() const
129 return mpControlData
->mpLayoutData
;
132 // -----------------------------------------------------------------------
134 void Control::SetText( const OUString
& rStr
)
136 ImplClearLayoutData();
137 Window::SetText( rStr
);
140 // -----------------------------------------------------------------------
142 Rectangle
ControlLayoutData::GetCharacterBounds( long nIndex
) const
144 return (nIndex
>= 0 && nIndex
< (long) m_aUnicodeBoundRects
.size()) ? m_aUnicodeBoundRects
[ nIndex
] : Rectangle();
148 // -----------------------------------------------------------------------
150 Rectangle
Control::GetCharacterBounds( long nIndex
) const
152 if( !HasLayoutData() )
154 return mpControlData
->mpLayoutData
? mpControlData
->mpLayoutData
->GetCharacterBounds( nIndex
) : Rectangle();
157 // -----------------------------------------------------------------------
159 long ControlLayoutData::GetIndexForPoint( const Point
& rPoint
) const
162 for( long i
= m_aUnicodeBoundRects
.size()-1; i
>= 0; i
-- )
164 Point aTopLeft
= m_aUnicodeBoundRects
[i
].TopLeft();
165 Point aBottomRight
= m_aUnicodeBoundRects
[i
].BottomRight();
166 if (rPoint
.X() >= aTopLeft
.X() && rPoint
.Y() >= aTopLeft
.Y() &&
167 rPoint
.X() <= aBottomRight
.X() && rPoint
.Y() <= aBottomRight
.Y())
176 // -----------------------------------------------------------------------
178 long Control::GetIndexForPoint( const Point
& rPoint
) const
180 if( ! HasLayoutData() )
182 return mpControlData
->mpLayoutData
? mpControlData
->mpLayoutData
->GetIndexForPoint( rPoint
) : -1;
185 // -----------------------------------------------------------------------
187 long ControlLayoutData::GetLineCount() const
189 long nLines
= m_aLineIndices
.size();
190 if( nLines
== 0 && !m_aDisplayText
.isEmpty() )
195 // -----------------------------------------------------------------------
197 Pair
ControlLayoutData::GetLineStartEnd( long nLine
) const
199 Pair
aPair( -1, -1 );
201 int nDisplayLines
= m_aLineIndices
.size();
202 if( nLine
>= 0 && nLine
< nDisplayLines
)
204 aPair
.A() = m_aLineIndices
[nLine
];
205 if( nLine
+1 < nDisplayLines
)
206 aPair
.B() = m_aLineIndices
[nLine
+1]-1;
208 aPair
.B() = m_aDisplayText
.getLength()-1;
210 else if( nLine
== 0 && nDisplayLines
== 0 && !m_aDisplayText
.isEmpty() )
212 // special case for single line controls so the implementations
213 // in that case do not have to fill in the line indices
215 aPair
.B() = m_aDisplayText
.getLength()-1;
220 // -----------------------------------------------------------------------
222 Pair
Control::GetLineStartEnd( long nLine
) const
224 if( !HasLayoutData() )
226 return mpControlData
->mpLayoutData
? mpControlData
->mpLayoutData
->GetLineStartEnd( nLine
) : Pair( -1, -1 );
229 // -----------------------------------------------------------------------
231 long ControlLayoutData::ToRelativeLineIndex( long nIndex
) const
233 // is the index sensible at all ?
234 if( nIndex
>= 0 && nIndex
< m_aDisplayText
.getLength() )
236 int nDisplayLines
= m_aLineIndices
.size();
237 // if only 1 line exists, then absolute and relative index are
238 // identical -> do nothing
239 if( nDisplayLines
> 1 )
242 for( nLine
= nDisplayLines
-1; nLine
>= 0; nLine
-- )
244 if( m_aLineIndices
[nLine
] <= nIndex
)
246 nIndex
-= m_aLineIndices
[nLine
];
252 DBG_ASSERT( nLine
>= 0, "ToRelativeLineIndex failed" );
263 // -----------------------------------------------------------------------
265 long Control::ToRelativeLineIndex( long nIndex
) const
267 if( !HasLayoutData() )
269 return mpControlData
->mpLayoutData
? mpControlData
->mpLayoutData
->ToRelativeLineIndex( nIndex
) : -1;
272 // -----------------------------------------------------------------------
274 OUString
Control::GetDisplayText() const
276 if( !HasLayoutData() )
278 return mpControlData
->mpLayoutData
? OUString(mpControlData
->mpLayoutData
->m_aDisplayText
) : GetText();
281 // -----------------------------------------------------------------------
283 long Control::Notify( NotifyEvent
& rNEvt
)
285 if ( rNEvt
.GetType() == EVENT_GETFOCUS
)
287 if ( !mbHasControlFocus
)
289 mbHasControlFocus
= sal_True
;
290 StateChanged( STATE_CHANGE_CONTROL_FOCUS
);
291 if ( ImplCallEventListenersAndHandler( VCLEVENT_CONTROL_GETFOCUS
, maGetFocusHdl
, this ) )
292 // been destroyed within the handler
298 if ( rNEvt
.GetType() == EVENT_LOSEFOCUS
)
300 Window
* pFocusWin
= Application::GetFocusWindow();
301 if ( !pFocusWin
|| !ImplIsWindowOrChild( pFocusWin
) )
303 mbHasControlFocus
= sal_False
;
304 StateChanged( STATE_CHANGE_CONTROL_FOCUS
);
305 if ( ImplCallEventListenersAndHandler( VCLEVENT_CONTROL_LOSEFOCUS
, maLoseFocusHdl
, this ) )
306 // been destroyed within the handler
312 return Window::Notify( rNEvt
);
315 // -----------------------------------------------------------------------
317 void Control::StateChanged( StateChangedType nStateChange
)
319 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
326 ImplClearLayoutData();
328 Window::StateChanged( nStateChange
);
331 // -----------------------------------------------------------------------
333 void Control::AppendLayoutData( const Control
& rSubControl
) const
335 if( !rSubControl
.HasLayoutData() )
336 rSubControl
.FillLayoutData();
337 if( !rSubControl
.HasLayoutData() || rSubControl
.mpControlData
->mpLayoutData
->m_aDisplayText
.isEmpty() )
340 long nCurrentIndex
= mpControlData
->mpLayoutData
->m_aDisplayText
.getLength();
341 mpControlData
->mpLayoutData
->m_aDisplayText
+= rSubControl
.mpControlData
->mpLayoutData
->m_aDisplayText
;
342 int nLines
= rSubControl
.mpControlData
->mpLayoutData
->m_aLineIndices
.size();
344 mpControlData
->mpLayoutData
->m_aLineIndices
.push_back( nCurrentIndex
);
345 for( n
= 1; n
< nLines
; n
++ )
346 mpControlData
->mpLayoutData
->m_aLineIndices
.push_back( rSubControl
.mpControlData
->mpLayoutData
->m_aLineIndices
[n
] + nCurrentIndex
);
347 int nRectangles
= rSubControl
.mpControlData
->mpLayoutData
->m_aUnicodeBoundRects
.size();
348 Rectangle aRel
= const_cast<Control
&>(rSubControl
).GetWindowExtentsRelative( const_cast<Control
*>(this) );
349 for( n
= 0; n
< nRectangles
; n
++ )
351 Rectangle aRect
= rSubControl
.mpControlData
->mpLayoutData
->m_aUnicodeBoundRects
[n
];
352 aRect
.Move( aRel
.Left(), aRel
.Top() );
353 mpControlData
->mpLayoutData
->m_aUnicodeBoundRects
.push_back( aRect
);
357 // -----------------------------------------------------------------
359 sal_Bool
Control::ImplCallEventListenersAndHandler( sal_uLong nEvent
, const Link
& rHandler
, void* pCaller
)
361 ImplDelData aCheckDelete
;
362 ImplAddDel( &aCheckDelete
);
364 ImplCallEventListeners( nEvent
);
365 if ( !aCheckDelete
.IsDead() )
367 rHandler
.Call( pCaller
);
369 if ( !aCheckDelete
.IsDead() )
371 ImplRemoveDel( &aCheckDelete
);
378 // -----------------------------------------------------------------
380 void Control::SetLayoutDataParent( const Control
* pParent
) const
382 if( HasLayoutData() )
383 mpControlData
->mpLayoutData
->m_pParent
= pParent
;
386 // -----------------------------------------------------------------
388 void Control::ImplClearLayoutData() const
390 delete mpControlData
->mpLayoutData
, mpControlData
->mpLayoutData
= NULL
;
393 // -----------------------------------------------------------------------
395 void Control::ImplDrawFrame( OutputDevice
* pDev
, Rectangle
& rRect
)
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
400 AllSettings
aOriginalSettings( pDev
->GetSettings() );
402 AllSettings
aNewSettings( aOriginalSettings
);
403 StyleSettings
aStyle( aNewSettings
.GetStyleSettings() );
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 aStyle
.SetOptions( aStyle
.GetOptions() | STYLE_OPTION_MONO
);
409 aStyle
.SetMonoColor( GetSettings().GetStyleSettings().GetMonoColor() );
411 aNewSettings
.SetStyleSettings( aStyle
);
412 // #i67023# do not call data changed listeners for this fake
413 // since they may understandably invalidate on settings changed
414 pDev
->OutputDevice::SetSettings( aNewSettings
);
416 DecorationView
aDecoView( pDev
);
417 rRect
= aDecoView
.DrawFrame( rRect
, FRAME_DRAW_WINDOWBORDER
);
419 pDev
->OutputDevice::SetSettings( aOriginalSettings
);
422 // -----------------------------------------------------------------------
424 void Control::DataChanged( const DataChangedEvent
& rDCEvt
)
426 // we don't want to loose some style settings for controls created with the
428 if ( IsCreatedWithToolkit() &&
429 (rDCEvt
.GetType() == DATACHANGED_SETTINGS
) &&
430 (rDCEvt
.GetFlags() & SETTINGS_STYLE
) )
432 const AllSettings
* pOldSettings
= rDCEvt
.GetOldSettings();
434 AllSettings aSettings
= GetSettings();
435 StyleSettings aStyleSettings
= aSettings
.GetStyleSettings();
436 sal_uLong nNewOptions
= aStyleSettings
.GetOptions();
438 if ( pOldSettings
&& !(nNewOptions
& STYLE_OPTION_MONO
) && ( pOldSettings
->GetStyleSettings().GetOptions() & STYLE_OPTION_MONO
) )
440 nNewOptions
|= STYLE_OPTION_MONO
;
441 aStyleSettings
.SetOptions( nNewOptions
);
442 aStyleSettings
.SetMonoColor( pOldSettings
->GetStyleSettings().GetMonoColor() );
443 aSettings
.SetStyleSettings( aStyleSettings
);
444 SetSettings( aSettings
);
449 // -----------------------------------------------------------------
451 ControlLayoutData::~ControlLayoutData()
454 m_pParent
->ImplClearLayoutData();
457 // -----------------------------------------------------------------
459 Size
Control::GetOptimalSize() const
461 return Size( GetTextWidth( GetText() ) + 2 * 12,
462 GetTextHeight() + 2 * 6 );
465 // -----------------------------------------------------------------
467 void Control::SetReferenceDevice( OutputDevice
* _referenceDevice
)
469 if ( mpControlData
->mpReferenceDevice
== _referenceDevice
)
472 mpControlData
->mpReferenceDevice
= _referenceDevice
;
476 // -----------------------------------------------------------------
478 OutputDevice
* Control::GetReferenceDevice() const
480 return mpControlData
->mpReferenceDevice
;
483 // -----------------------------------------------------------------
485 const Font
& Control::GetCanonicalFont( const StyleSettings
& _rStyle
) const
487 return _rStyle
.GetLabelFont();
490 // -----------------------------------------------------------------
491 const Color
& Control::GetCanonicalTextColor( const StyleSettings
& _rStyle
) const
493 return _rStyle
.GetLabelTextColor();
496 // -----------------------------------------------------------------
497 void Control::ImplInitSettings( const sal_Bool _bFont
, const sal_Bool _bForeground
)
499 const StyleSettings
& rStyleSettings
= GetSettings().GetStyleSettings();
503 Font
aFont( GetCanonicalFont( rStyleSettings
) );
504 if ( IsControlFont() )
505 aFont
.Merge( GetControlFont() );
506 SetZoomedPointFont( aFont
);
509 if ( _bForeground
|| _bFont
)
512 if ( IsControlForeground() )
513 aColor
= GetControlForeground();
515 aColor
= GetCanonicalTextColor( rStyleSettings
);
516 SetTextColor( aColor
);
521 // -----------------------------------------------------------------
523 void Control::DrawControlText( OutputDevice
& _rTargetDevice
, Rectangle
& _io_rRect
, const OUString
& _rStr
,
524 sal_uInt16 _nStyle
, MetricVector
* _pVector
, OUString
* _pDisplayText
) const
529 static MetricVector aCharRects
;
530 static String sDisplayText
;
532 sDisplayText
= String();
533 _pVector
= &aCharRects
;
534 _pDisplayText
= &sDisplayText
;
538 if ( !mpControlData
->mpReferenceDevice
|| ( mpControlData
->mpReferenceDevice
== &_rTargetDevice
) )
540 _io_rRect
= _rTargetDevice
.GetTextRect( _io_rRect
, _rStr
, _nStyle
);
541 _rTargetDevice
.DrawText( _io_rRect
, _rStr
, _nStyle
, _pVector
, _pDisplayText
);
545 ControlTextRenderer
aRenderer( *this, _rTargetDevice
, *mpControlData
->mpReferenceDevice
);
546 _io_rRect
= aRenderer
.DrawText( _io_rRect
, _rStr
, _nStyle
, _pVector
, _pDisplayText
);
550 _rTargetDevice
.Push( PUSH_LINECOLOR
| PUSH_FILLCOLOR
);
551 _rTargetDevice
.SetLineColor( COL_LIGHTRED
);
552 _rTargetDevice
.SetFillColor();
553 for ( MetricVector::const_iterator cr
= _pVector
->begin();
554 cr
!= _pVector
->end();
558 _rTargetDevice
.DrawRect( *cr
);
560 _rTargetDevice
.Pop();
564 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */