Update ooo320-m1
[ooovba.git] / vcl / aqua / source / gdi / salnativewidgets.cxx
blobbd10356a98976a3c377d6f36262e42979ff46c93
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: salnativewidgets.cxx,v $
10 * $Revision: 1.15 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 #include "salconst.h"
32 #include "salgdi.h"
33 #include "salnativewidgets.h"
34 #include "saldata.hxx"
35 #include "salframe.h"
37 #include "vcl/salnativewidgets.hxx"
38 #include "vcl/decoview.hxx"
39 #include "vcl/svapp.hxx"
40 #include "vcl/timer.hxx"
42 #include "premac.h"
43 #include <Carbon/Carbon.h>
44 #include "postmac.h"
46 class AquaBlinker : public Timer
48 AquaSalFrame* mpFrame;
49 Rectangle maInvalidateRect;
51 AquaBlinker( AquaSalFrame* pFrame, const Rectangle& rRect )
52 : mpFrame( pFrame ), maInvalidateRect( rRect )
54 mpFrame->maBlinkers.push_back( this );
57 public:
59 static void Blink( AquaSalFrame*, const Rectangle&, int nTimeout = 80 );
61 virtual void Timeout()
63 Stop();
64 if( AquaSalFrame::isAlive( mpFrame ) && mpFrame->mbShown )
66 mpFrame->maBlinkers.remove( this );
67 mpFrame->SendPaintEvent( &maInvalidateRect );
69 delete this;
73 void AquaBlinker::Blink( AquaSalFrame* pFrame, const Rectangle& rRect, int nTimeout )
75 // prevent repeated paints from triggering themselves all the time
76 for( std::list< AquaBlinker* >::const_iterator it = pFrame->maBlinkers.begin();
77 it != pFrame->maBlinkers.end(); ++it )
79 if( (*it)->maInvalidateRect == rRect )
80 return;
82 AquaBlinker* pNew = new AquaBlinker( pFrame, rRect );
83 pNew->SetTimeout( nTimeout );
84 pNew->Start();
87 ControlPart ImplgetCounterPart( ControlPart nPart )
89 ControlPart nCounterPart = 0;
90 switch (nPart)
92 case PART_BUTTON_UP:
93 nCounterPart = PART_BUTTON_DOWN;
94 break;
95 case PART_BUTTON_DOWN:
96 nCounterPart = PART_BUTTON_UP;
97 break;
98 case PART_BUTTON_LEFT:
99 nCounterPart = PART_BUTTON_RIGHT;
100 break;
101 case PART_BUTTON_RIGHT:
102 nCounterPart = PART_BUTTON_LEFT;
103 break;
105 return nCounterPart;
109 // Helper returns an HIRect
111 static HIRect ImplGetHIRectFromRectangle(Rectangle aRect)
113 HIRect aHIRect;
114 aHIRect.origin.x = static_cast<float>(aRect.Left());
115 aHIRect.origin.y = static_cast<float>(aRect.Top());
116 aHIRect.size.width = static_cast<float>(aRect.GetWidth());
117 aHIRect.size.height = static_cast<float>(aRect.GetHeight());
118 return aHIRect;
121 static ThemeButtonValue ImplGetButtonValue( ButtonValue aButtonValue )
123 switch( aButtonValue )
125 case BUTTONVALUE_ON:
126 return kThemeButtonOn;
127 break;
129 case BUTTONVALUE_OFF:
130 return kThemeButtonOff;
131 break;
133 case BUTTONVALUE_MIXED:
134 case BUTTONVALUE_DONTKNOW:
135 default:
136 return kThemeButtonMixed;
137 break;
141 static bool AquaGetScrollRect( /* TODO: int nScreen, */ ControlPart nPart,
142 const Rectangle& rControlRect, Rectangle& rResultRect )
144 bool bRetVal = true;
145 rResultRect = rControlRect;
147 switch( nPart )
149 case PART_BUTTON_UP:
150 if( GetSalData()->mbIsScrollbarDoubleMax )
151 rResultRect.Top() = rControlRect.Bottom() - 2*BUTTON_HEIGHT;
152 rResultRect.Bottom() = rResultRect.Top() + BUTTON_HEIGHT;
153 break;
155 case PART_BUTTON_DOWN:
156 rResultRect.Top() = rControlRect.Bottom() - BUTTON_HEIGHT;
157 break;
159 case PART_BUTTON_LEFT:
160 if( GetSalData()->mbIsScrollbarDoubleMax )
161 rResultRect.Left() = rControlRect.Right() - 2*BUTTON_WIDTH;
162 rResultRect.Right() = rResultRect.Left() + BUTTON_WIDTH;
163 break;
165 case PART_BUTTON_RIGHT:
166 rResultRect.Left() = rControlRect.Right() - BUTTON_WIDTH;
167 break;
169 case PART_TRACK_HORZ_AREA:
170 rResultRect.Right() -= BUTTON_WIDTH + 1;
171 if( GetSalData()->mbIsScrollbarDoubleMax )
172 rResultRect.Right() -= BUTTON_WIDTH;
173 else
174 rResultRect.Left() += BUTTON_WIDTH + 1;
175 break;
177 case PART_TRACK_VERT_AREA:
178 rResultRect.Bottom() -= BUTTON_HEIGHT + 1;
179 if( GetSalData()->mbIsScrollbarDoubleMax )
180 rResultRect.Bottom() -= BUTTON_HEIGHT;
181 else
182 rResultRect.Top() += BUTTON_HEIGHT + 1;
183 break;
184 case PART_THUMB_HORZ:
185 if( GetSalData()->mbIsScrollbarDoubleMax )
187 rResultRect.Left() += 8;
188 rResultRect.Right() += 6;
190 else
192 rResultRect.Left() += 4;
193 rResultRect.Right() += 4;
195 break;
196 case PART_THUMB_VERT:
197 if( GetSalData()->mbIsScrollbarDoubleMax )
199 rResultRect.Top() += 8;
200 rResultRect.Bottom() += 8;
202 else
204 rResultRect.Top() += 4;
205 rResultRect.Bottom() += 4;
207 break;
208 case PART_TRACK_HORZ_LEFT:
209 if( GetSalData()->mbIsScrollbarDoubleMax )
210 rResultRect.Right() += 8;
211 else
212 rResultRect.Right() += 4;
213 break;
214 case PART_TRACK_HORZ_RIGHT:
215 if( GetSalData()->mbIsScrollbarDoubleMax )
216 rResultRect.Left() += 6;
217 else
218 rResultRect.Left() += 4;
219 break;
220 case PART_TRACK_VERT_UPPER:
221 if( GetSalData()->mbIsScrollbarDoubleMax )
222 rResultRect.Bottom() += 8;
223 else
224 rResultRect.Bottom() += 4;
225 break;
226 case PART_TRACK_VERT_LOWER:
227 if( GetSalData()->mbIsScrollbarDoubleMax )
228 rResultRect.Top() += 8;
229 else
230 rResultRect.Top() += 4;
231 break;
232 default:
233 bRetVal = false;
236 return bRetVal;
240 * IsNativeControlSupported()
241 * --------------------------
242 * Returns TRUE if the platform supports native
243 * drawing of the control defined by nPart.
246 BOOL AquaSalGraphics::IsNativeControlSupported( ControlType nType, ControlPart nPart )
248 bool bOk = FALSE;
250 // Native controls are now defaults
251 // If you want to disable experimental native controls code,
252 // just set the environment variable SAL_NO_NWF to something
253 // and vcl controls will be used as default again.
255 switch( nType )
257 case CTRL_PUSHBUTTON:
258 case CTRL_RADIOBUTTON:
259 case CTRL_CHECKBOX:
260 case CTRL_LISTNODE:
261 if( nPart == PART_ENTIRE_CONTROL )
262 return true;
263 break;
265 case CTRL_SCROLLBAR:
266 if( nPart == PART_DRAW_BACKGROUND_HORZ ||
267 nPart == PART_DRAW_BACKGROUND_VERT ||
268 nPart == PART_ENTIRE_CONTROL ||
269 nPart == HAS_THREE_BUTTONS )
270 return true;
271 break;
273 case CTRL_EDITBOX:
274 if( nPart == PART_ENTIRE_CONTROL ||
275 nPart == HAS_BACKGROUND_TEXTURE )
276 return true;
277 break;
279 case CTRL_MULTILINE_EDITBOX:
280 if( nPart == PART_ENTIRE_CONTROL ||
281 nPart == HAS_BACKGROUND_TEXTURE )
282 return true;
283 break;
285 case CTRL_SPINBOX:
286 if( nPart == PART_ENTIRE_CONTROL ||
287 nPart == PART_ALL_BUTTONS ||
288 nPart == HAS_BACKGROUND_TEXTURE )
289 return true;
290 break;
292 case CTRL_SPINBUTTONS:
293 return false;
294 break;
296 case CTRL_COMBOBOX:
297 if( nPart == PART_ENTIRE_CONTROL ||
298 nPart == HAS_BACKGROUND_TEXTURE )
299 return true;
300 break;
302 case CTRL_LISTBOX:
303 if( nPart == PART_ENTIRE_CONTROL ||
304 nPart == PART_WINDOW ||
305 nPart == HAS_BACKGROUND_TEXTURE ||
306 nPart == PART_SUB_EDIT
308 return true;
309 break;
311 case CTRL_TAB_ITEM:
312 case CTRL_TAB_PANE:
313 case CTRL_TAB_BODY: // see vcl/source/window/tabpage.cxx
314 case CTRL_FIXEDBORDER:
315 if( nPart == PART_ENTIRE_CONTROL ||
316 nPart == PART_TABS_DRAW_RTL ||
317 nPart == HAS_BACKGROUND_TEXTURE )
318 return true;
319 break;
321 // when PART_BUTTON is used, toolbar icons are not highlighted when mouse rolls over.
322 // More Aqua compliant
323 case CTRL_TOOLBAR:
324 if( nPart == PART_ENTIRE_CONTROL ||
325 nPart == PART_DRAW_BACKGROUND_HORZ ||
326 nPart == PART_DRAW_BACKGROUND_VERT)
327 return true;
328 break;
330 case CTRL_WINDOW_BACKGROUND:
331 if ( nPart == PART_BACKGROUND_WINDOW ||
332 nPart == PART_BACKGROUND_DIALOG )
333 return true;
334 break;
336 case CTRL_MENUBAR:
337 if( nPart == PART_ENTIRE_CONTROL )
338 return true;
339 break;
341 case CTRL_TOOLTIP: // ** TO DO
342 #if 0
343 if( nPart == PART_ENTIRE_CONTROL ) // we don't currently support the tooltip
344 return true;
345 #endif
346 break;
348 case CTRL_MENU_POPUP:
349 if( nPart == PART_ENTIRE_CONTROL ||
350 nPart == PART_MENU_ITEM ||
351 nPart == PART_MENU_ITEM_CHECK_MARK ||
352 nPart == PART_MENU_ITEM_RADIO_MARK)
353 return true;
354 break;
355 case CTRL_PROGRESS:
356 case CTRL_INTROPROGRESS:
357 if( nPart == PART_ENTIRE_CONTROL )
358 return true;
359 break;
360 case CTRL_FRAME:
361 if( nPart == PART_BORDER )
362 return true;
363 break;
364 case CTRL_LISTNET:
365 if( nPart == PART_ENTIRE_CONTROL )
366 return true;
367 break;
370 return bOk;
374 * HitTestNativeControl()
376 * If the return value is TRUE, bIsInside contains information whether
377 * aPos was or was not inside the native widget specified by the
378 * nType/nPart combination.
380 BOOL AquaSalGraphics::hitTestNativeControl( ControlType nType, ControlPart nPart, const Region& rControlRegion,
381 const Point& rPos, SalControlHandle& rControlHandle, BOOL& rIsInside )
383 if ( nType == CTRL_SCROLLBAR )
385 Rectangle aRect;
386 bool bValid = AquaGetScrollRect( /* TODO: m_nScreen */ nPart, rControlRegion.GetBoundRect(), aRect );
387 rIsInside = bValid ? aRect.IsInside( rPos ) : FALSE;
388 if( GetSalData()->mbIsScrollbarDoubleMax )
390 // in double max mode the actual trough is a little smaller than the track
391 // there is some visual filler that is not sensitive
392 if( bValid && rIsInside )
394 if( nPart == PART_TRACK_HORZ_AREA )
396 // the left 4 pixels are not hit sensitive
397 if( rPos.X() - aRect.Left() < 4 )
398 rIsInside = FALSE;
400 else if( nPart == PART_TRACK_VERT_AREA )
402 // the top 4 pixels are not hit sensitive
403 if( rPos.Y() - aRect.Top() < 4 )
404 rIsInside = FALSE;
408 return bValid;
409 } // CTRL_SCROLLBAR
411 return FALSE;
415 kThemeStateInactive = 0,
416 kThemeStateActive = 1,
417 kThemeStatePressed = 2,
418 kThemeStateRollover = 6,
419 kThemeStateUnavailable = 7,
420 kThemeStateUnavailableInactive = 8
421 kThemeStatePressedUp = 2,
422 kThemeStatePressedDown = 3
424 #define CTRL_STATE_ENABLED 0x0001
425 #define CTRL_STATE_FOCUSED 0x0002
426 #define CTRL_STATE_PRESSED 0x0004
427 #define CTRL_STATE_ROLLOVER 0x0008
428 #define CTRL_STATE_HIDDEN 0x0010
429 #define CTRL_STATE_DEFAULT 0x0020
430 #define CTRL_STATE_SELECTED 0x0040
431 #define CTRL_CACHING_ALLOWED 0x8000 // set when the control is completely visible (i.e. not clipped)
433 static ThemeDrawState getState( ControlState nState )
435 if( (nState & CTRL_STATE_ENABLED) == 0 )
437 if( (nState & CTRL_STATE_HIDDEN) == 0 )
438 return kThemeStateInactive;
439 else
440 return kThemeStateUnavailableInactive;
443 if( (nState & CTRL_STATE_HIDDEN) != 0 )
444 return kThemeStateUnavailable;
446 if( (nState & CTRL_STATE_PRESSED) != 0 )
447 return kThemeStatePressed;
449 return kThemeStateActive;
453 * DrawNativeControl()
455 * Draws the requested control described by nPart/nState.
457 * rControlRegion: The bounding region of the complete control in VCL frame coordinates.
458 * aValue: An optional value (tristate/numerical/string)
459 * rControlHandle: Carries platform dependent data and is maintained by the AquaSalGraphics implementation.
460 * aCaption: A caption or title string (like button text etc)
462 BOOL AquaSalGraphics::drawNativeControl(ControlType nType,
463 ControlPart nPart,
464 const Region& rControlRegion,
465 ControlState nState,
466 const ImplControlValue& aValue,
467 SalControlHandle& rControlHandle,
468 const rtl::OUString& aCaption )
470 BOOL bOK = FALSE;
472 if( ! CheckContext() )
473 return false;
475 CGContextSaveGState( mrContext );
477 Rectangle buttonRect = rControlRegion.GetBoundRect();
478 HIRect rc = ImplGetHIRectFromRectangle(buttonRect);
480 /** Scrollbar parts code equivalent **
481 PART_BUTTON_UP 101
482 PART_BUTTON_DOWN 102
483 PART_THUMB_VERT 211
484 PART_TRACK_VERT_UPPER 201
485 PART_TRACK_VERT_LOWER 203
487 PART_DRAW_BACKGROUND_HORZ 1000
488 PART_DRAW_BACKGROUND_VERT 1001
491 switch( nType )
494 case CTRL_COMBOBOX:
495 if ( nPart == HAS_BACKGROUND_TEXTURE ||
496 nPart == PART_ENTIRE_CONTROL )
498 HIThemeButtonDrawInfo aComboInfo;
499 aComboInfo.version = 0;
500 aComboInfo.kind = kThemeComboBox;
501 aComboInfo.state = getState( nState );
502 aComboInfo.value = kThemeButtonOn;
503 aComboInfo.adornment = kThemeAdornmentNone;
505 if( (nState & CTRL_STATE_FOCUSED) != 0 )
506 aComboInfo.adornment |= kThemeAdornmentFocus;
508 HIThemeDrawButton(&rc, &aComboInfo, mrContext, kHIThemeOrientationNormal,&rc);
509 bOK = true;
511 break;
513 case CTRL_FIXEDBORDER:
514 case CTRL_TOOLBAR:
516 HIThemeMenuItemDrawInfo aMenuItemDrawInfo;
517 aMenuItemDrawInfo.version = 0;
518 aMenuItemDrawInfo.state = kThemeMenuActive;
519 aMenuItemDrawInfo.itemType = kThemeMenuItemHierBackground;
520 HIThemeDrawMenuItem(&rc,&rc,&aMenuItemDrawInfo,mrContext,kHIThemeOrientationNormal,NULL);
521 bOK = true;
523 break;
525 case CTRL_WINDOW_BACKGROUND:
527 HIThemeBackgroundDrawInfo aThemeBackgroundInfo;
528 aThemeBackgroundInfo.version = 0;
529 aThemeBackgroundInfo.state = getState( nState );
530 aThemeBackgroundInfo.kind = kThemeBrushDialogBackgroundInactive;
531 // FIXME: without this magical offset there is a 2 pixel black border on the right and bottom
532 rc.size.width += 2;
533 rc.size.height += 2;
535 HIThemeApplyBackground( &rc, &aThemeBackgroundInfo, mrContext, kHIThemeOrientationNormal);
536 CGContextFillRect( mrContext, rc );
537 bOK = true;
539 break;
541 case CTRL_MENUBAR:
542 case CTRL_MENU_POPUP:
544 if ((nPart == PART_ENTIRE_CONTROL) || (nPart == PART_MENU_ITEM )|| (nPart == HAS_BACKGROUND_TEXTURE ))
546 // FIXME: without this magical offset there is a 2 pixel black border on the right
547 rc.size.width += 2;
549 HIThemeMenuDrawInfo aMenuInfo;
550 aMenuInfo.version = 0;
551 aMenuInfo.menuType = kThemeMenuTypePullDown;
553 HIThemeMenuItemDrawInfo aMenuItemDrawInfo;
554 // the Aqua grey theme when the item is selected is drawn here.
555 aMenuItemDrawInfo.itemType = kThemeMenuItemPlain;
557 if ((nPart == PART_MENU_ITEM ))
559 // the blue theme when the item is selected is drawn here.
560 aMenuItemDrawInfo.state = kThemeMenuSelected;
562 else
564 // normal color for non selected item
565 aMenuItemDrawInfo.state = kThemeMenuActive;
568 // repaints the background of the pull down menu
569 HIThemeDrawMenuBackground(&rc,&aMenuInfo,mrContext,kHIThemeOrientationNormal);
571 // repaints the item either blue (selected) and/or Aqua grey (active only)
572 HIThemeDrawMenuItem(&rc,&rc,&aMenuItemDrawInfo,mrContext,kHIThemeOrientationNormal,&rc);
574 bOK = true;
576 else if(( nPart == PART_MENU_ITEM_CHECK_MARK )||( nPart == PART_MENU_ITEM_RADIO_MARK )) {
577 if( nState & CTRL_STATE_PRESSED ) {//checked, else it is not displayed (see vcl/source/window/menu.cxx)
578 HIThemeTextInfo aTextInfo;
579 aTextInfo.version = 0;
580 aTextInfo.state = ((nState & CTRL_STATE_ENABLED)==0) ? kThemeStateInactive: kThemeStateActive;
581 aTextInfo.fontID = kThemeMenuItemMarkFont;
582 aTextInfo.horizontalFlushness=kHIThemeTextHorizontalFlushCenter;
583 aTextInfo.verticalFlushness=kHIThemeTextVerticalFlushTop;
584 aTextInfo.options=kHIThemeTextBoxOptionNone;
585 aTextInfo.truncationPosition=kHIThemeTextTruncationNone;
586 //aTextInfo.truncationMaxLines unused because of kHIThemeTextTruncationNone
588 if( nState & CTRL_STATE_SELECTED) aTextInfo.state = kThemeStatePressed; //item highlighted
590 UniChar mark=( nPart == PART_MENU_ITEM_CHECK_MARK ) ? kCheckUnicode: kBulletUnicode;//0x2713;
591 CFStringRef cfString = CFStringCreateWithCharactersNoCopy(kCFAllocatorDefault, &mark, 1, kCFAllocatorNull);
592 HIThemeDrawTextBox(cfString, &rc, &aTextInfo, mrContext, kHIThemeOrientationNormal);
593 if (cfString)
594 CFRelease(cfString);
596 bOK = true;
600 break;
602 case CTRL_PUSHBUTTON:
604 // [ FIXME] : instead of use a value, vcl can retrieve corect values on the fly (to be implemented)
605 const int PB_Mini_Height = 15;
606 const int PB_Norm_Height = 21;
608 HIThemeButtonDrawInfo aPushInfo;
609 aPushInfo.version = 0;
611 // no animation
612 aPushInfo.animation.time.start = 0;
613 aPushInfo.animation.time.current = 0;
614 PushButtonValue* pPBVal = (PushButtonValue*)aValue.getOptionalVal();
615 int nPaintHeight = static_cast<int>(rc.size.height);
617 if( pPBVal && pPBVal->mbBevelButton )
619 aPushInfo.kind = kThemeRoundedBevelButton;
621 else if( rc.size.height <= PB_Norm_Height )
623 aPushInfo.kind = kThemePushButtonMini;
624 nPaintHeight = PB_Mini_Height;
626 else if( pPBVal->mbSingleLine || rc.size.height < (PB_Norm_Height + PB_Norm_Height/2) )
628 aPushInfo.kind = kThemePushButtonNormal;
629 nPaintHeight = PB_Norm_Height;
631 // avoid clipping when focused
632 rc.origin.x += FOCUS_RING_WIDTH/2;
633 rc.size.width -= FOCUS_RING_WIDTH;
635 if( (nState & CTRL_STATE_DEFAULT) != 0 )
637 AquaBlinker::Blink( mpFrame, buttonRect );
638 // show correct animation phase
639 aPushInfo.animation.time.current = CFAbsoluteTimeGetCurrent();
642 else
643 aPushInfo.kind = kThemeBevelButton;
645 // translate the origin for controls with fixed paint height
646 // so content ends up somewhere sensible
647 int delta_y = static_cast<int>(rc.size.height) - nPaintHeight;
648 rc.origin.y += delta_y/2;
650 aPushInfo.state = getState( nState );
651 aPushInfo.value = ImplGetButtonValue( aValue.getTristateVal() );
653 aPushInfo.adornment = (( nState & CTRL_STATE_DEFAULT ) != 0) ?
654 kThemeAdornmentDefault :
655 kThemeAdornmentNone;
656 if( (nState & CTRL_STATE_FOCUSED) != 0 )
657 aPushInfo.adornment |= kThemeAdornmentFocus;
659 HIThemeDrawButton( &rc, &aPushInfo, mrContext, kHIThemeOrientationNormal, NULL );
660 bOK = true;
662 break;
664 case CTRL_RADIOBUTTON:
665 case CTRL_CHECKBOX:
667 HIThemeButtonDrawInfo aInfo;
668 aInfo.version = 0;
669 switch( nType )
671 case CTRL_RADIOBUTTON: if(rc.size.width >= BUTTON_HEIGHT) aInfo.kind = kThemeRadioButton;
672 else aInfo.kind = kThemeSmallRadioButton;
673 break;
674 case CTRL_CHECKBOX: if(rc.size.width >= BUTTON_HEIGHT) aInfo.kind = kThemeCheckBox;
675 else aInfo.kind = kThemeSmallCheckBox;
676 break;
679 aInfo.state = getState( nState );
681 ButtonValue aButtonValue = aValue.getTristateVal();
682 aInfo.value = ImplGetButtonValue( aButtonValue );
684 aInfo.adornment = (( nState & CTRL_STATE_DEFAULT ) != 0) ?
685 kThemeAdornmentDefault :
686 kThemeAdornmentNone;
687 if( (nState & CTRL_STATE_FOCUSED) != 0 )
688 aInfo.adornment |= kThemeAdornmentFocus;
689 HIThemeDrawButton( &rc, &aInfo, mrContext, kHIThemeOrientationNormal, NULL );
690 bOK = true;
692 break;
694 case CTRL_LISTNODE:
696 ButtonValue aButtonValue = aValue.getTristateVal();
698 if( Application::GetSettings().GetLayoutRTL() && aButtonValue == BUTTONVALUE_OFF )
700 // FIXME: a value of kThemeDisclosureLeft
701 // should draw a theme compliant left disclosure triangle
702 // sadly this does not seem to work, so we'll draw a left
703 // grey equilateral triangle here ourselves.
704 // Perhaps some other HIThemeButtonDrawInfo setting would do the trick ?
706 CGContextSetShouldAntialias( mrContext, true );
707 float aGrey[] = { 0.45, 0.45, 0.45, 1.0 };
708 CGContextSetFillColor( mrContext, aGrey );
709 CGContextBeginPath( mrContext );
710 float x = rc.origin.x + rc.size.width;
711 float y = rc.origin.y;
712 CGContextMoveToPoint( mrContext, x, y );
713 y += rc.size.height;
714 CGContextAddLineToPoint( mrContext, x, y );
715 x -= rc.size.height * 0.866; // cos( 30 degree ) is approx. 0.866
716 y -= rc.size.height/2;
717 CGContextAddLineToPoint( mrContext, x, y );
718 CGContextDrawPath( mrContext, kCGPathEOFill );
720 else
722 HIThemeButtonDrawInfo aInfo;
723 aInfo.version = 0;
724 aInfo.kind = kThemeDisclosureTriangle;
725 aInfo.value = kThemeDisclosureRight;
726 aInfo.state = getState( nState );
728 aInfo.adornment = kThemeAdornmentNone;
730 switch( aButtonValue ) {
731 case BUTTONVALUE_ON: aInfo.value = kThemeDisclosureDown;//expanded
732 break;
733 case BUTTONVALUE_OFF:
734 // FIXME: this should have drawn a theme compliant disclosure triangle
735 // (see above)
736 if( Application::GetSettings().GetLayoutRTL() )
738 aInfo.value = kThemeDisclosureLeft;//collapsed, RTL
740 break;
741 case BUTTONVALUE_DONTKNOW: //what to do?
742 default:
743 break;
746 HIThemeDrawButton( &rc, &aInfo, mrContext, kHIThemeOrientationNormal, NULL );
748 bOK = true;
750 break;
752 case CTRL_PROGRESS:
753 case CTRL_INTROPROGRESS:
755 long nProgressWidth = aValue.getNumericVal();
756 HIThemeTrackDrawInfo aTrackInfo;
757 aTrackInfo.version = 0;
758 aTrackInfo.kind = (rc.size.height > 10) ? kThemeProgressBarLarge : kThemeProgressBarMedium;
759 aTrackInfo.bounds = rc;
760 aTrackInfo.min = 0;
761 aTrackInfo.max = static_cast<SInt32>(rc.size.width);
762 aTrackInfo.value = nProgressWidth;
763 aTrackInfo.reserved = 0;
764 aTrackInfo.bounds.origin.y -= 2; // FIXME: magic for shadow
765 aTrackInfo.bounds.size.width -= 2; // FIXME: magic for shadow
766 aTrackInfo.attributes = kThemeTrackHorizontal;
767 if( Application::GetSettings().GetLayoutRTL() )
768 aTrackInfo.attributes |= kThemeTrackRightToLeft;
769 aTrackInfo.enableState = (nState & CTRL_STATE_ENABLED) ? kThemeTrackActive : kThemeTrackInactive;
770 aTrackInfo.filler1 = 0;
771 aTrackInfo.trackInfo.progress.phase = static_cast<UInt8>(CFAbsoluteTimeGetCurrent()*10.0);
773 HIThemeDrawTrack( &aTrackInfo, NULL, mrContext, kHIThemeOrientationNormal );
774 bOK = true;
776 break;
778 case CTRL_SCROLLBAR:
780 ScrollbarValue* pScrollbarVal = (ScrollbarValue *)(aValue.getOptionalVal());
782 if( nPart == PART_DRAW_BACKGROUND_VERT ||
783 nPart == PART_DRAW_BACKGROUND_HORZ )
785 HIThemeTrackDrawInfo aTrackDraw;
786 aTrackDraw.kind = kThemeMediumScrollBar;
787 // FIXME: the scrollbar length must be adjusted
788 if (nPart == PART_DRAW_BACKGROUND_VERT)
789 rc.size.height += 2;
790 else
791 rc.size.width += 2;
793 aTrackDraw.bounds = rc;
794 aTrackDraw.min = pScrollbarVal->mnMin;
795 aTrackDraw.max = pScrollbarVal->mnMax - pScrollbarVal->mnVisibleSize;
796 aTrackDraw.value = pScrollbarVal->mnCur;
797 aTrackDraw.reserved = 0;
798 aTrackDraw.attributes = kThemeTrackShowThumb;
799 if( nPart == PART_DRAW_BACKGROUND_HORZ )
800 aTrackDraw.attributes |= kThemeTrackHorizontal;
801 aTrackDraw.enableState = kThemeTrackActive;
803 ScrollBarTrackInfo aScrollInfo;
804 aScrollInfo.viewsize = pScrollbarVal->mnVisibleSize;
805 aScrollInfo.pressState = 0;
807 if ( pScrollbarVal->mnButton1State & CTRL_STATE_ENABLED )
809 if ( pScrollbarVal->mnButton1State & CTRL_STATE_PRESSED )
810 aScrollInfo.pressState = kThemeTopOutsideArrowPressed;
813 if ( pScrollbarVal->mnButton2State & CTRL_STATE_ENABLED )
815 if ( pScrollbarVal->mnButton2State & CTRL_STATE_PRESSED )
816 aScrollInfo.pressState = kThemeBottomOutsideArrowPressed;
819 if ( pScrollbarVal->mnThumbState & CTRL_STATE_ENABLED )
821 if ( pScrollbarVal->mnThumbState & CTRL_STATE_PRESSED )
822 aScrollInfo.pressState = kThemeThumbPressed;
825 aTrackDraw.trackInfo.scrollbar = aScrollInfo;
827 HIThemeDrawTrack( &aTrackDraw, NULL, mrContext, kHIThemeOrientationNormal );
828 bOK = true;
831 break;
833 //#define OLD_TAB_STYLE
834 #ifdef OLD_TAB_STYLE
835 case CTRL_TAB_PANE:
837 HIThemeTabPaneDrawInfo aTabPaneDrawInfo;
838 aTabPaneDrawInfo.version = 0;
839 aTabPaneDrawInfo.state = kThemeStateActive;
840 aTabPaneDrawInfo.direction=kThemeTabNorth;
841 aTabPaneDrawInfo.size=kHIThemeTabSizeNormal;
843 //the border is outside the rect rc for Carbon
844 //but for VCL it should be inside
845 rc.origin.x+=1;
846 rc.size.width-=2;
848 HIThemeDrawTabPane(&rc, &aTabPaneDrawInfo, mrContext, kHIThemeOrientationNormal);
849 bOK = true;
851 break;
853 case CTRL_TAB_ITEM:
855 HIThemeTabDrawInfo aTabItemDrawInfo;
856 aTabItemDrawInfo.version=0;
857 aTabItemDrawInfo.style=kThemeTabNonFront;
858 aTabItemDrawInfo.direction=kThemeTabNorth;
859 aTabItemDrawInfo.size=kHIThemeTabSizeNormal;
860 aTabItemDrawInfo.adornment=kHIThemeTabAdornmentNone;
862 if(nState & CTRL_STATE_SELECTED) {
863 aTabItemDrawInfo.style=kThemeTabFront;
865 if(nState & CTRL_STATE_FOCUSED) {
866 aTabItemDrawInfo.adornment=kHIThemeTabAdornmentFocus;
869 /*if(rc.size.height>=TAB_HEIGHT_NORMAL) rc.size.height=TAB_HEIGHT_NORMAL;
870 else if(rc.size.height>=TAB_HEIGHT_SMALL) rc.size.height=TAB_HEIGHT_SMALL;
871 else rc.size.height=TAB_HEIGHT_MINI;*/
872 //now we only use the default size
873 rc.size.height=TAB_HEIGHT_NORMAL;
875 HIThemeDrawTab(&rc, &aTabItemDrawInfo, mrContext, kHIThemeOrientationNormal, &rc );
877 bOK=true;
879 break;
880 #else
881 case CTRL_TAB_PANE:
883 HIThemeTabPaneDrawInfo aTabPaneDrawInfo;
884 aTabPaneDrawInfo.version = 1;
885 aTabPaneDrawInfo.state = kThemeStateActive;
886 aTabPaneDrawInfo.direction=kThemeTabNorth;
887 aTabPaneDrawInfo.size=kHIThemeTabSizeNormal;
888 aTabPaneDrawInfo.kind=kHIThemeTabKindNormal;
890 //the border is outside the rect rc for Carbon
891 //but for VCL it should be inside
892 rc.origin.x+=1;
893 rc.origin.y-=TAB_HEIGHT_NORMAL/2;
894 rc.size.height+=TAB_HEIGHT_NORMAL/2;
895 rc.size.width-=2;
897 HIThemeDrawTabPane(&rc, &aTabPaneDrawInfo, mrContext, kHIThemeOrientationNormal);
899 bOK = true;
901 break;
903 case CTRL_TAB_ITEM:
905 HIThemeTabDrawInfo aTabItemDrawInfo;
906 aTabItemDrawInfo.version=1;
907 aTabItemDrawInfo.style=kThemeTabNonFront;
908 aTabItemDrawInfo.direction=kThemeTabNorth;
909 aTabItemDrawInfo.size=kHIThemeTabSizeNormal;
910 aTabItemDrawInfo.adornment=kHIThemeTabAdornmentTrailingSeparator;
911 //State
912 if(nState & CTRL_STATE_SELECTED) {
913 aTabItemDrawInfo.style=kThemeTabFront;
915 if(nState & CTRL_STATE_FOCUSED) {
916 aTabItemDrawInfo.adornment|=kHIThemeTabAdornmentFocus;
919 //first, last or middle tab
920 aTabItemDrawInfo.position=kHIThemeTabPositionMiddle;
922 TabitemValue *aTabValue=(TabitemValue *) aValue.getOptionalVal();
923 unsigned int nAlignement=aTabValue->mnAlignment;
924 //TABITEM_LEFTALIGNED (and TABITEM_RIGHTALIGNED) for the leftmost (or rightmost) tab
925 //when there are several lines of tabs because there is only one first tab and one
926 //last tab and TABITEM_FIRST_IN_GROUP (and TABITEM_LAST_IN_GROUP) because when the
927 //line width is different from window width, there may not be TABITEM_RIGHTALIGNED
928 if((nAlignement & TABITEM_LEFTALIGNED)&&(nAlignement & TABITEM_RIGHTALIGNED)) //tab alone
929 aTabItemDrawInfo.position=kHIThemeTabPositionOnly;
930 else if((nAlignement & TABITEM_LEFTALIGNED)||(nAlignement & TABITEM_FIRST_IN_GROUP))
931 aTabItemDrawInfo.position=kHIThemeTabPositionFirst;
932 else if((nAlignement & TABITEM_RIGHTALIGNED)||(nAlignement & TABITEM_LAST_IN_GROUP))
933 aTabItemDrawInfo.position=kHIThemeTabPositionLast;
935 //support for RTL
936 //see issue 79748
937 if( Application::GetSettings().GetLayoutRTL() ) {
938 if( aTabItemDrawInfo.position == kHIThemeTabPositionFirst )
939 aTabItemDrawInfo.position = kHIThemeTabPositionLast;
940 else if( aTabItemDrawInfo.position == kHIThemeTabPositionLast )
941 aTabItemDrawInfo.position = kHIThemeTabPositionFirst;
944 rc.size.width+=2;//because VCL has 2 empty pixels between 2 tabs
945 rc.origin.x-=1;
947 HIThemeDrawTab(&rc, &aTabItemDrawInfo, mrContext, kHIThemeOrientationNormal, &rc );
949 bOK=true;
951 break;
952 #endif
954 case CTRL_LISTBOX:
955 switch( nPart)
957 case PART_ENTIRE_CONTROL:
958 case PART_BUTTON_DOWN:
960 HIThemeButtonDrawInfo aListInfo;
961 aListInfo.version = 0;
962 aListInfo.kind = kThemePopupButton;
963 aListInfo.state = getState( nState );//kThemeStateInactive -> greyed
964 aListInfo.value = kThemeButtonOn;
966 aListInfo.adornment = kThemeAdornmentDefault;
967 if( (nState & CTRL_STATE_FOCUSED) != 0 )
968 aListInfo.adornment |= kThemeAdornmentFocus;
970 HIThemeDrawButton(&rc, &aListInfo, mrContext, kHIThemeOrientationNormal,&rc);
971 bOK = true;
972 break;
974 case PART_WINDOW:
976 HIThemeFrameDrawInfo aTextDrawInfo;
977 aTextDrawInfo.version=0;
978 aTextDrawInfo.kind=kHIThemeFrameTextFieldSquare;
979 aTextDrawInfo.state=getState( nState );
980 aTextDrawInfo.isFocused=false;
982 rc.size.width+=1;//else there's a white space because aqua theme hasn't a 3D border
983 rc.size.height+=1;
984 HIThemeDrawFrame(&rc, &aTextDrawInfo, mrContext, kHIThemeOrientationNormal);
986 if(nState & CTRL_STATE_FOCUSED) HIThemeDrawFocusRect(&rc, true, mrContext, kHIThemeOrientationNormal);
988 bOK=true;
989 break;
992 break;
994 case CTRL_EDITBOX:
995 case CTRL_MULTILINE_EDITBOX:
997 HIThemeFrameDrawInfo aTextDrawInfo;
998 aTextDrawInfo.version=0;
999 aTextDrawInfo.kind=kHIThemeFrameTextFieldSquare;
1000 aTextDrawInfo.state=getState( nState );
1001 aTextDrawInfo.isFocused=false;
1003 rc.size.width += 1; // else there may be a white space because aqua theme hasn't a 3D border
1004 // change rc so that the frame will encompass only the content region
1005 // see counterpart in GetNativeControlRegion
1006 rc.size.width += 2;
1007 rc.size.height += 2;
1009 //CGContextSetFillColorWithColor
1010 CGContextFillRect (mrContext, CGRectMake(rc.origin.x, rc.origin.y, rc.size.width, rc.size.height));
1011 //fill a white background, because drawFrame only draws the border
1013 HIThemeDrawFrame(&rc, &aTextDrawInfo, mrContext, kHIThemeOrientationNormal);
1015 if(nState & CTRL_STATE_FOCUSED) HIThemeDrawFocusRect(&rc, true, mrContext, kHIThemeOrientationNormal);
1017 bOK=true;
1019 break;
1021 case CTRL_SPINBOX:
1023 if(nPart == PART_ENTIRE_CONTROL)
1025 //text field:
1026 HIThemeFrameDrawInfo aTextDrawInfo;
1027 aTextDrawInfo.version=0;
1028 aTextDrawInfo.kind=kHIThemeFrameTextFieldSquare;
1029 aTextDrawInfo.state=getState( nState );
1030 aTextDrawInfo.isFocused=false;
1032 //rc.size.width contains the full size of the spinbox ie textfield + button
1033 //so we remove the button width and the space between the button and the textfield
1034 rc.size.width -= SPIN_BUTTON_SPACE + SPIN_BUTTON_WIDTH + 2*FOCUS_RING_WIDTH;
1035 rc.origin.x += FOCUS_RING_WIDTH;
1036 rc.origin.y += FOCUS_RING_WIDTH;
1038 //CGContextSetFillColorWithColor
1039 CGContextFillRect (mrContext, CGRectMake(rc.origin.x, rc.origin.y, rc.size.width, rc.size.height));
1040 //fill a white background, because drawFrame only draws the border
1042 HIThemeDrawFrame(&rc, &aTextDrawInfo, mrContext, kHIThemeOrientationNormal);
1044 if(nState & CTRL_STATE_FOCUSED) HIThemeDrawFocusRect(&rc, true, mrContext, kHIThemeOrientationNormal);
1046 //buttons:
1047 SpinbuttonValue* pSpinButtonVal = (SpinbuttonValue *)(aValue.getOptionalVal());
1048 ControlState nUpperState = CTRL_STATE_ENABLED;//state of the upper button
1049 ControlState nLowerState = CTRL_STATE_ENABLED;//and of the lower button
1050 if(pSpinButtonVal) {//pSpinButtonVal is sometimes null
1051 nUpperState = (ControlState) pSpinButtonVal->mnUpperState;
1052 nLowerState = (ControlState) pSpinButtonVal->mnLowerState;
1055 if( pSpinButtonVal )
1057 HIThemeButtonDrawInfo aSpinInfo;
1058 aSpinInfo.kind = kThemeIncDecButton;
1059 aSpinInfo.state = kThemeStateActive;
1060 if(nUpperState & CTRL_STATE_PRESSED)
1061 aSpinInfo.state = kThemeStatePressedUp;
1062 else if(nLowerState & CTRL_STATE_PRESSED)
1063 aSpinInfo.state = kThemeStatePressedDown;
1064 else if((nUpperState & ~CTRL_STATE_ENABLED)||(nLowerState & ~CTRL_STATE_ENABLED))
1065 aSpinInfo.state = kThemeStateInactive;
1066 else if((nUpperState & CTRL_STATE_ROLLOVER)||(nLowerState & CTRL_STATE_ROLLOVER))
1067 aSpinInfo.state = kThemeStateRollover;
1069 Rectangle aSpinRect( pSpinButtonVal->maUpperRect );
1070 aSpinRect.Union( pSpinButtonVal->maLowerRect );
1071 HIRect buttonRc = ImplGetHIRectFromRectangle(aSpinRect);
1073 // FIXME: without this fuzz factor there is some unwanted clipping
1074 if( Application::GetSettings().GetLayoutRTL() )
1075 buttonRc.origin.x -= FOCUS_RING_WIDTH - CLIP_FUZZ;
1076 else
1077 buttonRc.origin.x += FOCUS_RING_WIDTH + CLIP_FUZZ;
1079 switch( aValue.getTristateVal() )
1081 case BUTTONVALUE_ON: aSpinInfo.value = kThemeButtonOn;
1082 break;
1083 case BUTTONVALUE_OFF: aSpinInfo.value = kThemeButtonOff;
1084 break;
1085 case BUTTONVALUE_MIXED:
1086 case BUTTONVALUE_DONTKNOW:
1087 default: aSpinInfo.value = kThemeButtonMixed;
1088 break;
1091 aSpinInfo.adornment = ( ((nUpperState & CTRL_STATE_DEFAULT) != 0 ) ||
1092 ((nLowerState & CTRL_STATE_DEFAULT) != 0 )) ?
1093 kThemeAdornmentDefault :
1094 kThemeAdornmentNone;
1095 if( ((nUpperState & CTRL_STATE_FOCUSED) != 0 ) || ((nLowerState & CTRL_STATE_FOCUSED) != 0 ))
1096 aSpinInfo.adornment |= kThemeAdornmentFocus;
1098 HIThemeDrawButton( &buttonRc, &aSpinInfo, mrContext, kHIThemeOrientationNormal, NULL );
1101 bOK=true;
1105 break;
1107 case CTRL_FRAME:
1109 USHORT nStyle = aValue.getNumericVal();
1110 if( nPart == PART_BORDER ) {
1111 if(!( nStyle & FRAME_DRAW_MENU ) && !(nStyle & FRAME_DRAW_WINDOWBORDER) )
1113 // #i84756# strange effects start to happen when HIThemeDrawFrame
1114 // meets the border of the window. These can be avoided by clipping
1115 // to the boundary of the frame
1116 if( rc.origin.y + rc.size.height >= mpFrame->maGeometry.nHeight-3 )
1118 CGMutablePathRef rPath = CGPathCreateMutable();
1119 CGPathAddRect( rPath, NULL, CGRectMake( 0, 0, mpFrame->maGeometry.nWidth-1, mpFrame->maGeometry.nHeight-1 ) );
1121 CGContextBeginPath( mrContext );
1122 CGContextAddPath( mrContext, rPath );
1123 CGContextClip( mrContext );
1124 CGPathRelease( rPath );
1127 HIThemeFrameDrawInfo aTextDrawInfo;
1128 aTextDrawInfo.version=0;
1129 aTextDrawInfo.kind=kHIThemeFrameListBox;
1130 aTextDrawInfo.state=kThemeStateActive;
1131 aTextDrawInfo.isFocused=false;
1133 HIThemeDrawFrame(&rc, &aTextDrawInfo, mrContext, kHIThemeOrientationNormal);
1135 bOK=true;
1139 break;
1141 case CTRL_LISTNET:
1143 //do nothing as there isn't net for listviews on macos
1144 bOK=true;
1146 break;
1150 CGContextRestoreGState( mrContext );
1152 /* #i90291# in most cases invalidating the whole control region instead
1153 of just the unclipped part of it is sufficient (and probably faster).
1154 However for the window background we should not unnecessarily enlarge
1155 the really changed rectangle since the difference is usually quite high
1156 (the background is always drawn as a whole since we don't know anything
1157 about its possible contents)
1159 if( nType == CTRL_WINDOW_BACKGROUND )
1161 CGRect aRect = { { 0, 0 }, { 0, 0 } };
1162 if( mxClipPath )
1163 aRect = CGPathGetBoundingBox( mxClipPath );
1164 if( aRect.size.width != 0 && aRect.size.height != 0 )
1165 buttonRect.Intersection( Rectangle( Point( static_cast<long int>(aRect.origin.x),
1166 static_cast<long int>(aRect.origin.y) ),
1167 Size( static_cast<long int>(aRect.size.width),
1168 static_cast<long int>(aRect.size.height) ) ) );
1171 RefreshRect( buttonRect.Left(), buttonRect.Top(), buttonRect.GetWidth(), buttonRect.GetHeight() );
1173 return bOK;
1177 * DrawNativeControlText()
1179 * OPTIONAL. Draws the requested text for the control described by nPart/nState.
1180 * Used if text not drawn by DrawNativeControl().
1182 * rControlRegion: The bounding region of the complete control in VCL frame coordinates.
1183 * aValue: An optional value (tristate/numerical/string)
1184 * rControlHandle: Carries platform dependent data and is maintained by the AquaSalGraphics implementation.
1185 * aCaption: A caption or title string (like button text etc)
1187 BOOL AquaSalGraphics::drawNativeControlText( ControlType nType, ControlPart nPart, const Region& rControlRegion,
1188 ControlState nState, const ImplControlValue& aValue,
1189 SalControlHandle& rControlHandle, const rtl::OUString& aCaption )
1191 return( FALSE );
1196 * GetNativeControlRegion()
1198 * If the return value is TRUE, rNativeBoundingRegion
1199 * contains the true bounding region covered by the control
1200 * including any adornment, while rNativeContentRegion contains the area
1201 * within the control that can be safely drawn into without drawing over
1202 * the borders of the control.
1204 * rControlRegion: The bounding region of the control in VCL frame coordinates.
1205 * aValue: An optional value (tristate/numerical/string)
1206 * rControlHandle: Carries platform dependent data and is maintained by the AquaSalGraphics implementation.
1207 * aCaption: A caption or title string (like button text etc)
1209 BOOL AquaSalGraphics::getNativeControlRegion( ControlType nType, ControlPart nPart, const Region& rControlRegion, ControlState nState,
1210 const ImplControlValue& aValue, SalControlHandle& rControlHandle, const rtl::OUString& aCaption,
1211 Region &rNativeBoundingRegion, Region &rNativeContentRegion )
1214 BOOL toReturn = FALSE;
1216 short x = rControlRegion.GetBoundRect().Left();
1217 short y = rControlRegion.GetBoundRect().Top();
1218 short w, h;
1220 sal_uInt8 nBorderCleanup = 0;
1222 switch (nType)
1224 case CTRL_SCROLLBAR:
1226 Rectangle aRect;
1227 if( AquaGetScrollRect( /* m_nScreen */ nPart, rControlRegion.GetBoundRect(), aRect ) )
1229 toReturn = TRUE;
1230 rNativeBoundingRegion = aRect;
1231 rNativeContentRegion = aRect;
1234 break;
1236 case CTRL_PUSHBUTTON:
1237 case CTRL_RADIOBUTTON:
1238 case CTRL_CHECKBOX:
1240 if ( nType == CTRL_PUSHBUTTON )
1242 w = rControlRegion.GetBoundRect().GetWidth();
1243 h = rControlRegion.GetBoundRect().GetHeight();
1245 else
1247 // checkbox and radio borders need cleanup after unchecking them
1248 nBorderCleanup = 4;
1250 // TEXT_SEPARATOR to respect Aqua HIG
1251 w = BUTTON_WIDTH + TEXT_SEPARATOR;
1252 h = BUTTON_HEIGHT;
1256 rNativeContentRegion = Rectangle( Point( x, y ), Size( w, h + nBorderCleanup) );
1257 rNativeBoundingRegion = Rectangle( Point( x, y ), Size( w, h ) );
1259 toReturn = TRUE;
1261 break;
1262 case CTRL_PROGRESS:
1264 Rectangle aRect( rControlRegion.GetBoundRect() );
1265 if( aRect.GetHeight() < 16 )
1266 aRect.Bottom() = aRect.Top() + 9; // values taken from HIG for medium progress
1267 else
1268 aRect.Bottom() = aRect.Top() + 15; // values taken from HIG for large progress
1269 rNativeBoundingRegion = aRect;
1270 rNativeContentRegion = aRect;
1271 toReturn = TRUE;
1273 break;
1275 case CTRL_INTROPROGRESS:
1277 Rectangle aRect( rControlRegion.GetBoundRect() );
1278 aRect.Bottom() = aRect.Top() + INTRO_PROGRESS_HEIGHT; // values taken from HIG for medium progress
1279 rNativeBoundingRegion = aRect;
1280 rNativeContentRegion = aRect;
1281 toReturn = TRUE;
1283 break;
1285 case CTRL_TAB_ITEM:
1287 w = rControlRegion.GetBoundRect().GetWidth() + 2*TAB_TEXT_OFFSET - 2*VCL_TAB_TEXT_OFFSET;
1289 #ifdef OLD_TAB_STYLE
1290 h = TAB_HEIGHT_NORMAL;
1291 #else
1292 h = TAB_HEIGHT_NORMAL+2;
1293 #endif
1294 rNativeContentRegion = Rectangle( Point( x, y ), Size( w, h ) );
1295 rNativeBoundingRegion = Rectangle( Point( x, y ), Size( w, h ) );
1297 toReturn = TRUE;
1299 break;
1301 case CTRL_EDITBOX:
1303 w = rControlRegion.GetBoundRect().GetWidth();
1304 if( w < 3+2*FOCUS_RING_WIDTH )
1305 w = 3+2*FOCUS_RING_WIDTH;
1306 h = TEXT_EDIT_HEIGHT_NORMAL;
1308 rNativeContentRegion = Rectangle( Point( x+FOCUS_RING_WIDTH, y+FOCUS_RING_WIDTH ), Size( w-2*FOCUS_RING_WIDTH-2, h-2 ) );
1309 rNativeBoundingRegion = Rectangle( Point( x, y ), Size( w, h+2*FOCUS_RING_WIDTH ) );
1311 toReturn = TRUE;
1313 break;
1314 case CTRL_LISTBOX:
1315 case CTRL_COMBOBOX:
1317 if( nPart == PART_ENTIRE_CONTROL )
1319 w = rControlRegion.GetBoundRect().GetWidth();
1320 h = COMBOBOX_HEIGHT_NORMAL;//listboxes and comboxes have the same height
1322 rNativeContentRegion = Rectangle( Point( x+FOCUS_RING_WIDTH, y+FOCUS_RING_WIDTH ), Size( w-2*FOCUS_RING_WIDTH, h ) );
1323 rNativeBoundingRegion = Rectangle( Point( x, y ), Size( w, h+2*FOCUS_RING_WIDTH ) );
1325 toReturn = TRUE;
1327 else if( nPart == PART_BUTTON_DOWN )
1329 w = rControlRegion.GetBoundRect().GetWidth();
1330 if( w < 3+2*FOCUS_RING_WIDTH )
1331 w = 3+2*FOCUS_RING_WIDTH;
1332 h = COMBOBOX_HEIGHT_NORMAL;//listboxes and comboxes have the same height
1334 x += w-DROPDOWN_BUTTON_WIDTH - FOCUS_RING_WIDTH;
1335 y += FOCUS_RING_WIDTH;
1336 w = DROPDOWN_BUTTON_WIDTH;
1338 rNativeContentRegion = Rectangle( Point( x, y ), Size( w, h ) );
1339 rNativeBoundingRegion = Rectangle( Point( x, y ), Size( w+FOCUS_RING_WIDTH, h+2*FOCUS_RING_WIDTH ) );
1341 toReturn = true;
1343 else if( nPart == PART_SUB_EDIT )
1345 w = rControlRegion.GetBoundRect().GetWidth();
1346 h = COMBOBOX_HEIGHT_NORMAL;//listboxes and comboxes have the same height
1348 x += FOCUS_RING_WIDTH;
1349 x += 3; // add an offset for rounded borders
1350 y += 2; // don't draw into upper border
1351 y += FOCUS_RING_WIDTH;
1352 w -= 3 + DROPDOWN_BUTTON_WIDTH + 2*FOCUS_RING_WIDTH;
1353 if( nType == CTRL_LISTBOX )
1354 w -= 9; // HIG specifies 9 units distance between dropdown button area and content
1355 h -= 4; // don't draw into lower border
1357 rNativeContentRegion = Rectangle( Point( x, y ), Size( w, h ) );
1358 rNativeBoundingRegion = Rectangle( Point( x, y ), Size( w+FOCUS_RING_WIDTH, h+2*FOCUS_RING_WIDTH ) );
1360 toReturn = true;
1363 break;
1364 case CTRL_SPINBOX:
1365 if( nPart == PART_ENTIRE_CONTROL ) {
1366 w = rControlRegion.GetBoundRect().GetWidth();
1367 if( w < 3+2*FOCUS_RING_WIDTH+SPIN_BUTTON_SPACE+SPIN_BUTTON_WIDTH )
1368 w = 3+2*FOCUS_RING_WIDTH+SPIN_BUTTON_SPACE+SPIN_BUTTON_WIDTH;
1369 h = TEXT_EDIT_HEIGHT_NORMAL;
1371 rNativeContentRegion = Rectangle( Point( x+FOCUS_RING_WIDTH, y ), Size( w-2*FOCUS_RING_WIDTH, h ) );
1372 rNativeBoundingRegion = Rectangle( Point( x, y ), Size( w, h+2*FOCUS_RING_WIDTH ) );
1374 toReturn = TRUE;
1376 else if( nPart == PART_SUB_EDIT ) {
1377 w = rControlRegion.GetBoundRect().GetWidth() - SPIN_BUTTON_SPACE - SPIN_BUTTON_WIDTH;
1378 h = TEXT_EDIT_HEIGHT_NORMAL;
1379 x += 4; // add an offset for rounded borders
1380 y += 2; // don't draw into upper border
1381 w -= 8; // offset for left and right rounded border
1382 h -= 4; // don't draw into upper or ower border
1384 rNativeContentRegion = Rectangle( Point( x + FOCUS_RING_WIDTH, y + FOCUS_RING_WIDTH ), Size( w - 2* FOCUS_RING_WIDTH, h ) );
1385 rNativeBoundingRegion = Rectangle( Point( x, y ), Size( w, h+2*FOCUS_RING_WIDTH ) );
1387 toReturn = TRUE;
1389 else if( nPart == PART_BUTTON_UP ) {
1390 //rControlRegion.GetBoundRect().GetWidth() contains the width of the full control
1391 //ie the width of the textfield + button
1392 //x is the position of the left corner of the full control
1393 x += rControlRegion.GetBoundRect().GetWidth() - SPIN_BUTTON_WIDTH - SPIN_BUTTON_SPACE - CLIP_FUZZ;
1394 y += FOCUS_RING_WIDTH - CLIP_FUZZ;
1395 w = SPIN_BUTTON_WIDTH + 2*CLIP_FUZZ;
1396 h = SPIN_UPPER_BUTTON_HEIGHT + 2*CLIP_FUZZ;
1398 rNativeContentRegion = Rectangle( Point( x, y ), Size( w, h ) );
1399 rNativeBoundingRegion = Rectangle( Point( x, y ), Size( w, h ) );
1401 toReturn = TRUE;
1403 else if( nPart == PART_BUTTON_DOWN ) {
1404 x += rControlRegion.GetBoundRect().GetWidth() - SPIN_BUTTON_WIDTH - SPIN_BUTTON_SPACE - CLIP_FUZZ;
1405 y += SPIN_UPPER_BUTTON_HEIGHT + FOCUS_RING_WIDTH - CLIP_FUZZ;
1406 w = SPIN_BUTTON_WIDTH + 2*CLIP_FUZZ;
1407 h = SPIN_LOWER_BUTTON_HEIGHT + 2*CLIP_FUZZ;
1409 rNativeContentRegion = Rectangle( Point( x, y ), Size( w, h ) );
1410 rNativeBoundingRegion = Rectangle( Point( x, y ), Size( w, h ) );
1412 toReturn = TRUE;
1414 break;
1415 case CTRL_FRAME:
1417 USHORT nStyle = aValue.getNumericVal();
1418 if( ( nPart == PART_BORDER ) &&
1419 !( nStyle & (FRAME_DRAW_MENU | FRAME_DRAW_WINDOWBORDER | FRAME_DRAW_BORDERWINDOWBORDER) ) )
1421 Rectangle aRect = rControlRegion.GetBoundRect();
1422 if( nStyle & FRAME_DRAW_DOUBLEIN )
1424 aRect.Left() += 1;
1425 aRect.Top() += 1;
1426 //rRect.Right() -= 1;
1427 //rRect.Bottom() -= 1;
1429 else
1431 aRect.Left() += 1;
1432 aRect.Top() += 1;
1433 aRect.Right() -= 1;
1434 aRect.Bottom() -= 1;
1437 rNativeContentRegion = aRect;
1438 rNativeBoundingRegion = aRect;
1440 toReturn = TRUE;
1443 break;
1445 case CTRL_MENUBAR:
1446 case CTRL_MENU_POPUP:
1448 if(( nPart == PART_MENU_ITEM_CHECK_MARK )||( nPart == PART_MENU_ITEM_RADIO_MARK )) {
1450 w=10;
1451 h=10;//dimensions of the mark (10px font)
1453 rNativeContentRegion = Rectangle( Point( x, y ), Size( w, h ) );
1454 rNativeBoundingRegion = Rectangle( Point( x, y ), Size( w, h ) );
1456 toReturn = TRUE;
1459 break;
1463 return toReturn;