xref: /trunk/main/sc/source/ui/view/hdrcont.cxx (revision b3f79822)
1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_sc.hxx"
26 
27 
28 
29 // INCLUDE ---------------------------------------------------------------
30 
31 #include <sfx2/dispatch.hxx>
32 #include <vcl/help.hxx>
33 #include <tools/poly.hxx>
34 #include <svtools/colorcfg.hxx>
35 
36 #include "scresid.hxx"
37 #include "sc.hrc"
38 #include "tabvwsh.hxx"
39 #include "hdrcont.hxx"
40 #include "scmod.hxx"		// Optionen
41 #include "inputopt.hxx"		// Optionen
42 #include "gridmerg.hxx"
43 #include "document.hxx"
44 
45 // -----------------------------------------------------------------------
46 
47 #define SC_DRAG_MIN		2
48 
49 //	passes in paint
50 //	(selection left/right must be first because the continuous lines
51 //	are partly overwritten later)
52 
53 #define SC_HDRPAINT_SEL_RIGHT	0
54 #define SC_HDRPAINT_SEL_LEFT	1
55 #define SC_HDRPAINT_TOP			2
56 #define SC_HDRPAINT_SEL_TOP		3
57 #define SC_HDRPAINT_SEL_BOTTOM	4
58 #define SC_HDRPAINT_BOTTOM		5
59 #define SC_HDRPAINT_TEXT		6
60 #define SC_HDRPAINT_COUNT		7
61 
62 //==================================================================
63 
ScHeaderControl(Window * pParent,SelectionEngine * pSelectionEngine,SCCOLROW nNewSize,sal_uInt16 nNewFlags)64 ScHeaderControl::ScHeaderControl( Window* pParent, SelectionEngine* pSelectionEngine,
65 									SCCOLROW nNewSize, sal_uInt16 nNewFlags ) :
66 			Window		( pParent ),
67 			pSelEngine	( pSelectionEngine ),
68 			nFlags		( nNewFlags ),
69 			bVertical	( (nNewFlags & HDR_VERTICAL) != 0 ),
70 			nSize		( nNewSize ),
71 			nMarkStart	( 0 ),
72 			nMarkEnd	( 0 ),
73 			bMarkRange	( sal_False ),
74 			bDragging	( sal_False ),
75 			bIgnoreMove	( sal_False )
76 {
77     // --- RTL --- no default mirroring for this window, the spreadsheet itself
78     // is also not mirrored
79     // #107811# mirror the vertical window for correct border drawing
80     // #106948# table layout depends on sheet format, not UI setting, so the
81 	// borders of the vertical window have to be handled manually, too.
82     EnableRTL( sal_False );
83 
84 	aNormFont = GetFont();
85 	aNormFont.SetTransparent( sal_True );		//! WEIGHT_NORMAL hart setzen ???
86 	aBoldFont = aNormFont;
87 	aBoldFont.SetWeight( WEIGHT_BOLD );
88 
89 	SetFont(aBoldFont);
90 	bBoldSet = sal_True;
91 
92 	Size aSize = LogicToPixel( Size(
93 		GetTextWidth( String::CreateFromAscii(RTL_CONSTASCII_STRINGPARAM("8888")) ),
94 		GetTextHeight() ) );
95 	aSize.Width()  += 4;	// Platz fuer hervorgehobene Umrandung
96 	aSize.Height() += 3;
97 	SetSizePixel( aSize );
98 
99 	nWidth = nSmallWidth = aSize.Width();
100 	nBigWidth = LogicToPixel( Size( GetTextWidth(
101 		String::CreateFromAscii(RTL_CONSTASCII_STRINGPARAM("8888888")) ), 0 ) ).Width() + 5;
102 
103 	SetBackground();	// sonst Probleme auf OS/2 !?!?!
104 }
105 
SetWidth(long nNew)106 void ScHeaderControl::SetWidth( long nNew )
107 {
108 	DBG_ASSERT( bVertical, "SetDigits nur fuer Zeilenkoepfe erlaubt" );
109 	if ( nNew != nWidth )
110 	{
111 		Size aSize( nNew, GetSizePixel().Height() );	// Hoehe nicht aendern
112 		SetSizePixel( aSize );
113 
114 		nWidth = nNew;
115 
116 		Invalidate();		// neu zentrieren
117 	}
118 }
119 
~ScHeaderControl()120 ScHeaderControl::~ScHeaderControl()
121 {
122 }
123 
DoPaint(SCCOLROW nStart,SCCOLROW nEnd)124 void ScHeaderControl::DoPaint( SCCOLROW nStart, SCCOLROW nEnd )
125 {
126 	sal_Bool bLayoutRTL = IsLayoutRTL();
127 	long nLayoutSign = bLayoutRTL ? -1 : 1;
128 
129 	Rectangle aRect( Point(0,0), GetOutputSizePixel() );
130 	if ( bVertical )
131 	{
132         aRect.Top() = GetScrPos( nStart )-nLayoutSign;      // extra pixel for line at top of selection
133 		aRect.Bottom() = GetScrPos( nEnd+1 )-nLayoutSign;
134 	}
135 	else
136 	{
137         aRect.Left() = GetScrPos( nStart )-nLayoutSign;     // extra pixel for line left of selection
138 		aRect.Right() = GetScrPos( nEnd+1 )-nLayoutSign;
139 	}
140 	Invalidate(aRect);
141 }
142 
SetMark(sal_Bool bNewSet,SCCOLROW nNewStart,SCCOLROW nNewEnd)143 void ScHeaderControl::SetMark( sal_Bool bNewSet, SCCOLROW nNewStart, SCCOLROW nNewEnd )
144 {
145 	sal_Bool bEnabled = SC_MOD()->GetInputOptions().GetMarkHeader();	//! cachen?
146 	if (!bEnabled)
147 		bNewSet = sal_False;
148 
149 	//	Variablen setzen
150 
151 	sal_Bool bOldSet	 = bMarkRange;
152 	SCCOLROW nOldStart = nMarkStart;
153 	SCCOLROW nOldEnd	 = nMarkEnd;
154 	PutInOrder( nNewStart, nNewEnd );
155 	bMarkRange = bNewSet;
156 	nMarkStart = nNewStart;
157 	nMarkEnd   = nNewEnd;
158 
159 	//	Paint
160 
161 	if ( bNewSet )
162 	{
163 		if ( bOldSet )
164 		{
165 			if ( nNewStart == nOldStart )
166 			{
167 				if ( nNewEnd != nOldEnd )
168 					DoPaint( Min( nNewEnd, nOldEnd ) + 1, Max( nNewEnd, nOldEnd ) );
169 				// sonst nix
170 			}
171 			else if ( nNewEnd == nOldEnd )
172 				DoPaint( Min( nNewStart, nOldStart ), Max( nNewStart, nOldStart ) - 1 );
173 			else if ( nNewStart > nOldEnd || nNewEnd < nOldStart )
174 			{
175 				//	zwei Bereiche...
176 				DoPaint( nOldStart, nOldEnd );
177 				DoPaint( nNewStart, nNewEnd );
178 			}
179 			else				//	irgendwie ueberlappend... (kommt eh nicht oft vor)
180 				DoPaint( Min( nNewStart, nOldStart ), Max( nNewEnd, nOldEnd ) );
181 		}
182 		else
183 			DoPaint( nNewStart, nNewEnd );		//	komplett neu
184 	}
185 	else if ( bOldSet )
186 		DoPaint( nOldStart, nOldEnd );			//	komplett aufheben
187 
188 	//	sonst war nix, is nix
189 }
190 
GetScrPos(SCCOLROW nEntryNo)191 long ScHeaderControl::GetScrPos( SCCOLROW nEntryNo )
192 {
193 	long nScrPos;
194 
195 	long nMax = ( bVertical ? GetOutputSizePixel().Height() : GetOutputSizePixel().Width() ) + 1;
196 	if (nEntryNo >= nSize)
197 		nScrPos = nMax;
198 	else
199 	{
200 		nScrPos = 0;
201 		for (SCCOLROW i=GetPos(); i<nEntryNo && nScrPos<nMax; i++)
202 		{
203 			sal_uInt16 nAdd = GetEntrySize(i);
204 			if (nAdd)
205 				nScrPos += nAdd;
206 			else
207 			{
208 				SCCOLROW nHidden = GetHiddenCount(i);
209 				if (nHidden > 0)
210 					i += nHidden - 1;
211 			}
212 		}
213 	}
214 
215 	if ( IsLayoutRTL() )
216 		nScrPos = nMax - nScrPos - 2;
217 
218 	return nScrPos;
219 }
220 
221 // draw a rectangle across the window's width/height, with the outer part in a lighter color
222 
DrawShadedRect(long nStart,long nEnd,const Color & rBaseColor)223 void ScHeaderControl::DrawShadedRect( long nStart, long nEnd, const Color& rBaseColor )
224 {
225     Color aWhite( COL_WHITE );
226 
227     Color aInner( rBaseColor );             // highlight color, unchanged
228     Color aCenter( rBaseColor );
229     aCenter.Merge( aWhite, 0xd0 );          // lighten up a bit
230     Color aOuter( rBaseColor );
231     aOuter.Merge( aWhite, 0xa0 );           // lighten up more
232 
233     if ( IsMirrored() )
234         std::swap( aInner, aOuter );        // just swap colors instead of positions
235 
236     Size aWinSize = GetSizePixel();
237     long nBarSize = bVertical ? aWinSize.Width() : aWinSize.Height();
238     long nCenterPos = (nBarSize / 2) - 1;
239 
240     SetLineColor();
241     SetFillColor( aOuter );
242     if (bVertical)
243         DrawRect( Rectangle( 0, nStart, nCenterPos-1, nEnd ) );
244     else
245         DrawRect( Rectangle( nStart, 0, nEnd, nCenterPos-1 ) );
246     SetFillColor( aCenter );
247     if (bVertical)
248         DrawRect( Rectangle( nCenterPos, nStart, nCenterPos, nEnd ) );
249     else
250         DrawRect( Rectangle( nStart, nCenterPos, nEnd, nCenterPos ) );
251     SetFillColor( aInner );
252     if (bVertical)
253         DrawRect( Rectangle( nCenterPos+1, nStart, nBarSize-1, nEnd ) );
254     else
255         DrawRect( Rectangle( nStart, nCenterPos+1, nEnd, nBarSize-1 ) );
256 }
257 
258 //
259 //		Paint
260 //
261 
Paint(const Rectangle & rRect)262 void ScHeaderControl::Paint( const Rectangle& rRect )
263 {
264 	//	fuer VCL ist es wichtig, wenig Aufrufe zu haben, darum werden die aeusseren
265 	//	Linien zusammengefasst
266 
267 	const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings();
268     sal_Bool bHighContrast = rStyleSettings.GetHighContrastMode();
269 	sal_Bool bDark = rStyleSettings.GetFaceColor().IsDark();
270 	// Use the same distinction for bDark as in Window::DrawSelectionBackground
271 
272 	Color aTextColor = rStyleSettings.GetButtonTextColor();
273 	Color aSelTextColor = rStyleSettings.GetHighlightTextColor();
274 	aNormFont.SetColor( aTextColor );
275     if ( bHighContrast )
276         aBoldFont.SetColor( aTextColor );
277     else
278         aBoldFont.SetColor( aSelTextColor );
279 	SetTextColor( ( bBoldSet && !bHighContrast ) ? aSelTextColor : aTextColor );
280 
281     Color aBlack( COL_BLACK );
282     Color aSelLineColor = rStyleSettings.GetHighlightColor();
283     aSelLineColor.Merge( aBlack, 0xe0 );        // darken just a little bit
284 
285 	sal_Bool bLayoutRTL = IsLayoutRTL();
286 	long nLayoutSign = bLayoutRTL ? -1 : 1;
287 	sal_Bool bMirrored = IsMirrored();
288 
289 //	const FunctionSet*	pFuncSet = pSelEngine->GetFunctionSet();
290 	String				aString;
291 	sal_uInt16				nBarSize;
292 	Point				aScrPos;
293 	Size				aTextSize;
294 //	Size				aSize = GetOutputSizePixel();
295 
296 	if (bVertical)
297 		nBarSize = (sal_uInt16) GetSizePixel().Width();
298 	else
299 		nBarSize = (sal_uInt16) GetSizePixel().Height();
300 
301 	SCCOLROW	nPos = GetPos();
302 
303 	long nPStart = bVertical ? rRect.Top() : rRect.Left();
304 	long nPEnd = bVertical ? rRect.Bottom() : rRect.Right();
305 
306 	long nTransStart = nPEnd + 1;
307 	long nTransEnd = 0;
308 
309 	long nInitScrPos = 0;
310 	if ( bLayoutRTL )
311 	{
312 		long nTemp = nPStart;		// swap nPStart / nPEnd
313 		nPStart = nPEnd;
314 		nPEnd = nTemp;
315 		nTemp = nTransStart;		// swap nTransStart / nTransEnd
316 		nTransStart = nTransEnd;
317 		nTransEnd = nTemp;
318 		if ( bVertical )			// start loops from the end
319 			nInitScrPos = GetSizePixel().Height() - 1;
320 		else
321 			nInitScrPos = GetSizePixel().Width() - 1;
322 	}
323 
324 	//	aeussere Linien komplett durchzeichnen
325 	//	Zuerst Ende der letzten Zelle finden
326 
327 //	long nLineEnd = -1;
328 	long nLineEnd = nInitScrPos - nLayoutSign;
329 
330 	for (SCCOLROW i=nPos; i<nSize; i++)
331 	{
332 		sal_uInt16 nSizePix = GetEntrySize( i );
333 		if (nSizePix)
334 		{
335 			nLineEnd += nSizePix * nLayoutSign;
336 
337 			if ( bMarkRange && i >= nMarkStart && i <= nMarkEnd )
338 			{
339 				long nLineStart = nLineEnd - ( nSizePix - 1 ) * nLayoutSign;
340 				if ( nLineStart * nLayoutSign < nTransStart * nLayoutSign )
341 					nTransStart = nLineStart;
342 				if ( nLineEnd * nLayoutSign > nTransEnd * nLayoutSign )
343 					nTransEnd = nLineEnd;
344 			}
345 
346 			if ( nLineEnd * nLayoutSign > nPEnd * nLayoutSign )
347 			{
348 				nLineEnd = nPEnd;
349 				break;
350 			}
351 		}
352 		else
353 		{
354 			SCCOLROW nHidden = GetHiddenCount(i);
355 			if (nHidden > 0)
356 				i += nHidden - 1;
357 		}
358 	}
359 
360 	//	background is different for entry area and behind the entries
361 
362 	Rectangle aFillRect;
363 	SetLineColor();
364 
365 	if ( nLineEnd * nLayoutSign >= nInitScrPos * nLayoutSign )
366 	{
367         if ( bHighContrast )
368         {
369             // high contrast: single-color background
370             SetFillColor( rStyleSettings.GetFaceColor() );
371             if ( bVertical )
372                 aFillRect = Rectangle( 0, nInitScrPos, nBarSize-1, nLineEnd );
373             else
374                 aFillRect = Rectangle( nInitScrPos, 0, nLineEnd, nBarSize-1 );
375             DrawRect( aFillRect );
376         }
377         else
378         {
379             // normal: 3-part background
380             DrawShadedRect( nInitScrPos, nLineEnd, rStyleSettings.GetFaceColor() );
381         }
382 	}
383 
384 	if ( nLineEnd * nLayoutSign < nPEnd * nLayoutSign )
385 	{
386         SetFillColor( SC_MOD()->GetColorConfig().GetColorValue(svtools::APPBACKGROUND).nColor );
387 		if ( bVertical )
388 			aFillRect = Rectangle( 0, nLineEnd+nLayoutSign, nBarSize-1, nPEnd );
389 		else
390 			aFillRect = Rectangle( nLineEnd+nLayoutSign, 0, nPEnd, nBarSize-1 );
391 		DrawRect( aFillRect );
392 	}
393 
394 	if ( nLineEnd * nLayoutSign >= nPStart * nLayoutSign )
395 	{
396         if ( nTransEnd * nLayoutSign >= nTransStart * nLayoutSign )
397         {
398             if ( bHighContrast )
399             {
400                 if ( bDark )
401                 {
402                     //	solid grey background for dark face color is drawn before lines
403 
404                     SetLineColor();
405                     SetFillColor( COL_LIGHTGRAY );
406                     if (bVertical)
407                         DrawRect( Rectangle( 0, nTransStart, nBarSize-1, nTransEnd ) );
408                     else
409                         DrawRect( Rectangle( nTransStart, 0, nTransEnd, nBarSize-1 ) );
410                 }
411             }
412             else
413             {
414                 // background for selection
415 
416                 DrawShadedRect( nTransStart, nTransEnd, rStyleSettings.GetHighlightColor() );
417             }
418         }
419 
420 #if 0
421 		// 3D border is no longer used
422 		SetLineColor( rStyleSettings.GetLightColor() );
423 		if (bVertical)
424 			DrawLine( Point( 0, nPStart ), Point( 0, nLineEnd ) );
425 		else
426 			DrawLine( Point( nPStart, 0 ), Point( nLineEnd, 0 ) );
427 #endif
428 
429 		SetLineColor( rStyleSettings.GetDarkShadowColor() );
430 		if (bVertical)
431 		{
432 			long nDarkPos = bMirrored ? 0 : nBarSize-1;
433 			DrawLine( Point( nDarkPos, nPStart ), Point( nDarkPos, nLineEnd ) );
434 		}
435 		else
436 			DrawLine( Point( nPStart, nBarSize-1 ), Point( nLineEnd, nBarSize-1 ) );
437 
438         // line in different color for selection
439         if ( nTransEnd * nLayoutSign >= nTransStart * nLayoutSign && !bHighContrast )
440         {
441             SetLineColor( aSelLineColor );
442             if (bVertical)
443             {
444                 long nDarkPos = bMirrored ? 0 : nBarSize-1;
445                 DrawLine( Point( nDarkPos, nTransStart ), Point( nDarkPos, nTransEnd ) );
446             }
447             else
448                 DrawLine( Point( nTransStart, nBarSize-1 ), Point( nTransEnd, nBarSize-1 ) );
449         }
450 	}
451 
452 	//
453 	//	loop through entries several times to avoid changing the line color too often
454 	//	and to allow merging of lines
455 	//
456 
457 	ScGridMerger aGrid( this, 1, 1 );
458 
459 	//	start at SC_HDRPAINT_BOTTOM instead of 0 - selection doesn't get different
460 	//	borders, light border at top isn't used anymore
461     //  use SC_HDRPAINT_SEL_BOTTOM for different color
462 
463     for (sal_uInt16 nPass = SC_HDRPAINT_SEL_BOTTOM; nPass < SC_HDRPAINT_COUNT; nPass++)
464 	{
465 		//	set line color etc. before entry loop
466 		switch ( nPass )
467 		{
468             case SC_HDRPAINT_SEL_BOTTOM:
469                 // same as non-selected for high contrast
470                 SetLineColor( bHighContrast ? rStyleSettings.GetDarkShadowColor() : aSelLineColor );
471                 break;
472 			case SC_HDRPAINT_BOTTOM:
473 				SetLineColor( rStyleSettings.GetDarkShadowColor() );
474 				break;
475 			case SC_HDRPAINT_TEXT:
476                 // DrawSelectionBackground is used only for high contrast on light background
477                 if ( nTransEnd * nLayoutSign >= nTransStart * nLayoutSign && bHighContrast && !bDark )
478 				{
479 					//	Transparent selection background is drawn after lines, before text.
480 					//	#109814# Use DrawSelectionBackground to make sure there is a visible
481 					//	difference. The case of a dark face color, where DrawSelectionBackground
482 					//	would just paint over the lines, is handled separately (bDark).
483 					//	Otherwise, GetHighlightColor is used with 80% transparency.
484 					//	The window's background color (SetBackground) has to be the background
485 					//	of the cell area, for the contrast comparison in DrawSelectionBackground.
486 
487 					Rectangle aTransRect;
488 					if (bVertical)
489 						aTransRect = Rectangle( 0, nTransStart, nBarSize-1, nTransEnd );
490 					else
491 						aTransRect = Rectangle( nTransStart, 0, nTransEnd, nBarSize-1 );
492 					SetBackground( Color( rStyleSettings.GetFaceColor() ) );
493 					DrawSelectionBackground( aTransRect, 0, sal_True, sal_False, sal_False );
494 					SetBackground();
495 				}
496 				break;
497 		}
498 
499 		SCCOLROW	nCount=0;
500 		long	nScrPos=nInitScrPos;
501 		do
502 		{
503 			if (bVertical)
504 				aScrPos = Point( 0, nScrPos );
505 			else
506 				aScrPos = Point( nScrPos, 0 );
507 
508 			SCCOLROW	nEntryNo = nCount + nPos;
509 			if ( nEntryNo >= nSize )				// MAXCOL/MAXROW
510 				nScrPos = nPEnd + nLayoutSign;		//	beyond nPEnd -> stop
511 			else
512 			{
513 				sal_uInt16 nSizePix = GetEntrySize( nEntryNo );
514 
515 				if (nSizePix == 0)
516 				{
517 					SCCOLROW nHidden = GetHiddenCount(nEntryNo);
518 					if (nHidden > 0)
519 						nCount += nHidden - 1;
520 				}
521 				else if ((nScrPos+nSizePix*nLayoutSign)*nLayoutSign >= nPStart*nLayoutSign)
522 				{
523 					Point aEndPos(aScrPos);
524 					if (bVertical)
525 						aEndPos = Point( aScrPos.X()+nBarSize-1, aScrPos.Y()+(nSizePix-1)*nLayoutSign );
526 					else
527 						aEndPos = Point( aScrPos.X()+(nSizePix-1)*nLayoutSign, aScrPos.Y()+nBarSize-1 );
528 
529 					sal_Bool bMark = bMarkRange && nEntryNo >= nMarkStart && nEntryNo <= nMarkEnd;
530                     sal_Bool bNextToMark = bMarkRange && nEntryNo + 1 >= nMarkStart && nEntryNo <= nMarkEnd;
531 
532 					switch ( nPass )
533 					{
534                         case SC_HDRPAINT_SEL_BOTTOM:
535 						case SC_HDRPAINT_BOTTOM:
536                             if ( nPass == ( bNextToMark ? SC_HDRPAINT_SEL_BOTTOM : SC_HDRPAINT_BOTTOM ) )
537                             {
538                                 if (bVertical)
539                                     aGrid.AddHorLine( aScrPos.X(), aEndPos.X(), aEndPos.Y() );
540                                 else
541                                     aGrid.AddVerLine( aEndPos.X(), aScrPos.Y(), aEndPos.Y() );
542 
543                                 //  thick bottom for hidden rows
544                                 //  (drawn directly, without aGrid)
545                                 if ( nEntryNo+1 < nSize )
546                                     if ( GetEntrySize(nEntryNo+1)==0 )
547                                     {
548                                         if (bVertical)
549                                             DrawLine( Point(aScrPos.X(),aEndPos.Y()-nLayoutSign),
550                                                       Point(aEndPos.X(),aEndPos.Y()-nLayoutSign) );
551                                         else
552                                             DrawLine( Point(aEndPos.X()-nLayoutSign,aScrPos.Y()),
553                                                       Point(aEndPos.X()-nLayoutSign,aEndPos.Y()) );
554                                     }
555                             }
556 							break;
557 
558 						case SC_HDRPAINT_TEXT:
559 							if ( nSizePix > 1 )		// minimal check for small columns/rows
560 							{
561 								if ( bMark != bBoldSet )
562 								{
563 									if (bMark)
564 										SetFont(aBoldFont);
565 									else
566 										SetFont(aNormFont);
567 									bBoldSet = bMark;
568 								}
569 								aString = GetEntryText( nEntryNo );
570 								aTextSize.Width() = GetTextWidth( aString );
571 								aTextSize.Height() = GetTextHeight();
572 
573 								Point aTxtPos(aScrPos);
574 								if (bVertical)
575 								{
576 									aTxtPos.X() += (nBarSize-aTextSize.Width())/2;
577 									aTxtPos.Y() += (nSizePix*nLayoutSign-aTextSize.Height())/2;
578 									if ( bMirrored )
579 										aTxtPos.X() += 1;	// dark border is left instead of right
580 								}
581 								else
582 								{
583 									aTxtPos.X() += (nSizePix*nLayoutSign-aTextSize.Width()+1)/2;
584                                     aTxtPos.Y() += (nBarSize-aTextSize.Height())/2;
585 								}
586 								DrawText( aTxtPos, aString );
587 							}
588 							break;
589 					}
590 
591 					//	bei Selektion der ganzen Zeile/Spalte:
592 					//	InvertRect( Rectangle( aScrPos, aEndPos ) );
593 				}
594 				nScrPos += nSizePix * nLayoutSign;		// also if before the visible area
595 			}
596 			++nCount;
597 		}
598 		while ( nScrPos * nLayoutSign <= nPEnd * nLayoutSign );
599 
600 		aGrid.Flush();
601 	}
602 }
603 
604 //
605 //		Maus - Handling
606 //
607 
GetMousePos(const MouseEvent & rMEvt,sal_Bool & rBorder)608 SCCOLROW ScHeaderControl::GetMousePos( const MouseEvent& rMEvt, sal_Bool& rBorder )
609 {
610 	sal_Bool	bFound=sal_False;
611 	SCCOLROW	nCount = 1;
612 	SCCOLROW	nPos = GetPos();
613 	SCCOLROW	nHitNo = nPos;
614 	long	nScrPos;
615 	long	nMousePos = bVertical ? rMEvt.GetPosPixel().Y() : rMEvt.GetPosPixel().X();
616 	long	nDif;
617 	Size	aSize = GetOutputSizePixel();
618 	long	nWinSize = bVertical ? aSize.Height() : aSize.Width();
619 
620 	sal_Bool bLayoutRTL = IsLayoutRTL();
621 	long nLayoutSign = bLayoutRTL ? -1 : 1;
622 	long nEndPos = bLayoutRTL ? -1 : nWinSize;
623 
624 	nScrPos = GetScrPos( nPos ) - nLayoutSign;
625 	do
626 	{
627 		SCCOLROW nEntryNo = nCount + nPos;
628 
629 //		nScrPos = GetScrPos( nEntryNo ) - 1;
630 
631         if (nEntryNo > nSize)
632             nScrPos = nEndPos + nLayoutSign;
633 		else
634 			nScrPos += GetEntrySize( nEntryNo - 1 ) * nLayoutSign;		//! GetHiddenCount() ??
635 
636 		nDif = nMousePos - nScrPos;
637 		if (nDif >= -2 && nDif <= 2 && nCount > 0)
638 		{
639 			bFound=sal_True;
640 			nHitNo=nEntryNo-1;
641 		}
642         else if (nDif * nLayoutSign >= 0 && nEntryNo < nSize)
643 			nHitNo = nEntryNo;
644 		++nCount;
645 	}
646 	while ( nScrPos * nLayoutSign < nEndPos * nLayoutSign && nDif * nLayoutSign > 0 );
647 
648 	rBorder = bFound;
649 	return nHitNo;
650 }
651 
IsSelectionAllowed(SCCOLROW nPos) const652 bool ScHeaderControl::IsSelectionAllowed(SCCOLROW nPos) const
653 {
654     ScTabViewShell* pViewSh = dynamic_cast<ScTabViewShell*>(SfxViewShell::Current());
655     if (!pViewSh)
656         return false;
657 
658     ScViewData* pViewData = pViewSh->GetViewData();
659     sal_uInt16 nTab = pViewData->GetTabNo();
660     ScDocument* pDoc = pViewData->GetDocument();
661     const ScTableProtection* pProtect = pDoc->GetTabProtection(nTab);
662     bool bSelectAllowed = true;
663     if ( pProtect && pProtect->isProtected() )
664     {
665         // This sheet is protected.  Check if a context menu is allowed on this cell.
666         bool bCellsProtected = false;
667         if (bVertical)
668         {
669             // row header
670             SCROW nRPos = static_cast<SCROW>(nPos);
671             bCellsProtected = pDoc->HasAttrib(0, nRPos, nTab, MAXCOL, nRPos, nTab, HASATTR_PROTECTED);
672         }
673         else
674         {
675             // column header
676             SCCOL nCPos = static_cast<SCCOL>(nPos);
677             bCellsProtected = pDoc->HasAttrib(nCPos, 0, nTab, nCPos, MAXROW, nTab, HASATTR_PROTECTED);
678         }
679 
680         bool bSelProtected   = pProtect->isOptionEnabled(ScTableProtection::SELECT_LOCKED_CELLS);
681         bool bSelUnprotected = pProtect->isOptionEnabled(ScTableProtection::SELECT_UNLOCKED_CELLS);
682 
683         if (bCellsProtected)
684             bSelectAllowed = bSelProtected;
685         else
686             bSelectAllowed = bSelUnprotected;
687     }
688     return bSelectAllowed;
689 }
690 
MouseButtonDown(const MouseEvent & rMEvt)691 void ScHeaderControl::MouseButtonDown( const MouseEvent& rMEvt )
692 {
693 	if (IsDisabled())
694 		return;
695 
696 	bIgnoreMove = sal_False;
697 	SelectWindow();
698 
699 	sal_Bool bFound;
700 	SCCOLROW nHitNo = GetMousePos( rMEvt, bFound );
701     if (!IsSelectionAllowed(nHitNo))
702         return;
703 
704 	if ( bFound && rMEvt.IsLeft() && ResizeAllowed() )
705 	{
706 		nDragNo = nHitNo;
707 		sal_uInt16 nClicks = rMEvt.GetClicks();
708 		if ( nClicks && nClicks%2==0 )
709 		{
710 			SetEntrySize( nDragNo, HDR_SIZE_OPTIMUM );
711 			SetPointer( Pointer( POINTER_ARROW ) );
712 		}
713 		else
714 		{
715 			if (bVertical)
716 				nDragStart = rMEvt.GetPosPixel().Y();
717 			else
718 				nDragStart = rMEvt.GetPosPixel().X();
719 			nDragPos = nDragStart;
720 			ShowDragHelp();
721 			DrawInvert( nDragPos );
722 
723 			// CaptureMouse();
724 			StartTracking();
725 			bDragging = sal_True;
726 			bDragMoved = sal_False;
727 		}
728 	}
729 	else if (rMEvt.IsLeft())
730 	{
731 		pSelEngine->SetWindow( this );
732 		Point aPoint;
733 		Rectangle aVis( aPoint,GetOutputSizePixel() );
734 		if (bVertical)
735 			aVis.Left() = LONG_MIN, aVis.Right() = LONG_MAX;
736 		else
737 			aVis.Top() = LONG_MIN, aVis.Bottom() = LONG_MAX;
738 		pSelEngine->SetVisibleArea( aVis );
739 
740 		SetMarking( sal_True );		//	muss vor SelMouseButtonDown sein
741 		pSelEngine->SelMouseButtonDown( rMEvt );
742 
743 		//	#74215# In column/row headers a simple click already is a selection.
744 		//	-> Call SelMouseMove to ensure CreateAnchor is called (and DestroyAnchor
745 		//	if the next click is somewhere else with Control key).
746 		pSelEngine->SelMouseMove( rMEvt );
747 
748 		if (IsMouseCaptured())
749 		{
750 			//	Tracking statt CaptureMouse, damit sauber abgebrochen werden kann
751 			//!	Irgendwann sollte die SelectionEngine selber StartTracking rufen!?!
752 			ReleaseMouse();
753 			StartTracking();
754 		}
755 	}
756 }
757 
MouseButtonUp(const MouseEvent & rMEvt)758 void ScHeaderControl::MouseButtonUp( const MouseEvent& rMEvt )
759 {
760 	if ( IsDisabled() )
761 		return;
762 
763 	SetMarking( sal_False );
764 	bIgnoreMove = sal_False;
765 //    sal_Bool bFound;
766 //    SCCOLROW nHitNo = GetMousePos( rMEvt, bFound );
767 
768 	if ( bDragging )
769 	{
770 		DrawInvert( nDragPos );
771 		ReleaseMouse();
772 		bDragging	= sal_False;
773 
774 		long nScrPos	= GetScrPos( nDragNo );
775 		long nMousePos 	= bVertical ? rMEvt.GetPosPixel().Y() : rMEvt.GetPosPixel().X();
776 		sal_Bool bLayoutRTL = IsLayoutRTL();
777 		long nNewWidth  = bLayoutRTL ? ( nScrPos - nMousePos + 1 )
778 									 : ( nMousePos + 2 - nScrPos );
779 
780 		if ( nNewWidth < 0 /* && !IsSelected(nDragNo) */ )
781 		{
782             SCCOLROW nStart = 0;
783 			SCCOLROW nEnd = nDragNo;
784 			while (nNewWidth < 0)
785 			{
786 				nStart = nDragNo;
787 				if (nDragNo>0)
788 				{
789 					--nDragNo;
790 					nNewWidth += GetEntrySize( nDragNo );	//! GetHiddenCount() ???
791 				}
792 				else
793 					nNewWidth = 0;
794 			}
795 			HideEntries( nStart, nEnd );
796 		}
797 		else
798 		{
799 			if (nNewWidth<0) nNewWidth=0;
800 			if (bDragMoved)
801 				SetEntrySize( nDragNo, (sal_uInt16) nNewWidth );
802 		}
803 	}
804 	else
805 	{
806 		pSelEngine->SelMouseButtonUp( rMEvt );
807 		ReleaseMouse();
808 	}
809 }
810 
MouseMove(const MouseEvent & rMEvt)811 void ScHeaderControl::MouseMove( const MouseEvent& rMEvt )
812 {
813 	if ( IsDisabled() )
814 	{
815 		SetPointer( Pointer( POINTER_ARROW ) );
816 		return;
817 	}
818 
819 	sal_Bool bFound;
820     (void)GetMousePos( rMEvt, bFound );
821 
822 	if ( bDragging )
823 	{
824 		long nNewPos = bVertical ? rMEvt.GetPosPixel().Y() : rMEvt.GetPosPixel().X();
825 		if ( nNewPos != nDragPos )
826 		{
827 			DrawInvert( nDragPos );
828 			nDragPos = nNewPos;
829 			ShowDragHelp();
830 			DrawInvert( nDragPos );
831 
832 			if (nDragPos <= nDragStart-SC_DRAG_MIN || nDragPos >= nDragStart+SC_DRAG_MIN)
833 				bDragMoved = sal_True;
834 		}
835 	}
836 	else
837 	{
838 		if ( bFound && rMEvt.GetButtons()==0 && ResizeAllowed() )
839 			SetPointer( Pointer( bVertical ? POINTER_VSIZEBAR : POINTER_HSIZEBAR ) );
840 		else
841 			SetPointer( Pointer( POINTER_ARROW ) );
842 
843 		if (!bIgnoreMove)
844 			pSelEngine->SelMouseMove( rMEvt );
845 	}
846 }
847 
Tracking(const TrackingEvent & rTEvt)848 void ScHeaderControl::Tracking( const TrackingEvent& rTEvt )
849 {
850 	//	Weil die SelectionEngine kein Tracking kennt, die Events nur auf
851 	//	die verschiedenen MouseHandler verteilen...
852 
853 	if ( rTEvt.IsTrackingCanceled() )
854 		StopMarking();
855 	else if ( rTEvt.IsTrackingEnded() )
856 		MouseButtonUp( rTEvt.GetMouseEvent() );
857 	else
858 		MouseMove( rTEvt.GetMouseEvent() );
859 }
860 
Command(const CommandEvent & rCEvt)861 void ScHeaderControl::Command( const CommandEvent& rCEvt )
862 {
863 	sal_uInt16 nCmd = rCEvt.GetCommand();
864 	if ( nCmd == COMMAND_CONTEXTMENU )
865 	{
866 		StopMarking();		// Selektion / Dragging beenden
867 
868 		//	Popup ausfuehren
869 
870 		ScTabViewShell* pViewSh = PTR_CAST( ScTabViewShell,
871 											SfxViewShell::Current() );
872 		if ( pViewSh )
873 		{
874             if ( rCEvt.IsMouseEvent() )
875             {
876                 // #i18735# select the column/row under the mouse pointer
877                 ScViewData* pViewData = pViewSh->GetViewData();
878 
879                 SelectWindow();     // also deselects drawing objects, stops draw text edit
880                 if ( pViewData->HasEditView( pViewData->GetActivePart() ) )
881                     SC_MOD()->InputEnterHandler();  // always end edit mode
882 
883                 MouseEvent aMEvt( rCEvt.GetMousePosPixel() );
884                 sal_Bool bBorder;
885                 SCCOLROW nPos = GetMousePos( aMEvt, bBorder );
886                 if (!IsSelectionAllowed(nPos))
887                     // Selecting this cell is not allowed, neither is context menu.
888                     return;
889 
890                 SCTAB nTab = pViewData->GetTabNo();
891                 ScRange aNewRange;
892                 if ( bVertical )
893                     aNewRange = ScRange( 0, sal::static_int_cast<SCROW>(nPos), nTab,
894                                          MAXCOL, sal::static_int_cast<SCROW>(nPos), nTab );
895                 else
896                     aNewRange = ScRange( sal::static_int_cast<SCCOL>(nPos), 0, nTab,
897                                          sal::static_int_cast<SCCOL>(nPos), MAXROW, nTab );
898 
899                 // see if any part of the range is already selected
900                 sal_Bool bSelected = sal_False;
901                 ScRangeList aRanges;
902                 pViewData->GetMarkData().FillRangeListWithMarks( &aRanges, sal_False );
903                 sal_uLong nRangeCount = aRanges.Count();
904                 for (sal_uLong i=0; i<nRangeCount && !bSelected; i++)
905                     if ( aRanges.GetObject(i)->Intersects( aNewRange ) )
906                         bSelected = sal_True;
907 
908                 // select the range if no part of it was selected
909                 if ( !bSelected )
910                     pViewSh->MarkRange( aNewRange );
911             }
912 
913 			ScResId aResId( bVertical ? RID_POPUP_ROWHEADER : RID_POPUP_COLHEADER );
914 			pViewSh->GetDispatcher()->ExecutePopup( aResId );
915 		}
916 	}
917 	else if ( nCmd == COMMAND_STARTDRAG )
918 	{
919 		pSelEngine->Command( rCEvt );
920 	}
921 }
922 
StopMarking()923 void ScHeaderControl::StopMarking()
924 {
925 	if ( bDragging )
926 	{
927 		DrawInvert( nDragPos );
928 		bDragging = sal_False;
929 	}
930 
931 	SetMarking( sal_False );
932 	bIgnoreMove = sal_True;
933 
934 	//	#86260# don't call pSelEngine->Reset, so selection across the parts of
935 	//	a split/frozen view is possible
936 
937 	ReleaseMouse();
938 }
939 
ShowDragHelp()940 void ScHeaderControl::ShowDragHelp()
941 {
942 	if (Help::IsQuickHelpEnabled())
943 	{
944 		long nScrPos	= GetScrPos( nDragNo );
945 		sal_Bool bLayoutRTL = IsLayoutRTL();
946 		long nVal = bLayoutRTL ? ( nScrPos - nDragPos + 1 )
947 							   : ( nDragPos + 2 - nScrPos );
948 
949 		String aHelpStr = GetDragHelp( nVal );
950 		Point aPos = OutputToScreenPixel( Point(0,0) );
951 		Size aSize = GetSizePixel();
952 
953 		Point aMousePos = OutputToScreenPixel(GetPointerPosPixel());
954 
955 		Rectangle aRect;
956 		sal_uInt16 nAlign;
957 		if (!bVertical)
958 		{
959 			//	oberhalb
960 			aRect.Left() = aMousePos.X();
961 			aRect.Top()	 = aPos.Y() - 4;
962 			nAlign		 = QUICKHELP_BOTTOM|QUICKHELP_CENTER;
963 		}
964 		else
965 		{
966 			//	rechts oben
967 			aRect.Left() = aPos.X() + aSize.Width() + 8;
968 			aRect.Top()	 = aMousePos.Y() - 2;
969 			nAlign		 = QUICKHELP_LEFT|QUICKHELP_BOTTOM;
970 		}
971 
972 		aRect.Right() 	= aRect.Left();
973 		aRect.Bottom()	= aRect.Top();
974 
975 		Help::ShowQuickHelp(this, aRect, aHelpStr, nAlign);
976 	}
977 }
978 
RequestHelp(const HelpEvent & rHEvt)979 void ScHeaderControl::RequestHelp( const HelpEvent& rHEvt )
980 {
981 	//	Wenn eigene QuickHelp angezeigt wird, nicht durch RequestHelp
982 	//	wieder wegnehmen lassen
983 
984 	sal_Bool bOwn = bDragging && Help::IsQuickHelpEnabled();
985 	if (!bOwn)
986 		Window::RequestHelp(rHEvt);
987 }
988 
989 // -----------------------------------------------------------------------
990 //					Dummys fuer virtuelle Methoden
991 // -----------------------------------------------------------------------
992 
GetHiddenCount(SCCOLROW nEntryNo)993 SCCOLROW ScHeaderControl::GetHiddenCount( SCCOLROW nEntryNo )
994 {
995 	SCCOLROW nHidden = 0;
996 	while ( nEntryNo < nSize && GetEntrySize( nEntryNo ) == 0 )
997 	{
998 		++nEntryNo;
999 		++nHidden;
1000 	}
1001 	return nHidden;
1002 }
1003 
IsLayoutRTL()1004 sal_Bool ScHeaderControl::IsLayoutRTL()
1005 {
1006 	return sal_False;
1007 }
1008 
IsMirrored()1009 sal_Bool ScHeaderControl::IsMirrored()
1010 {
1011 	return sal_False;
1012 }
1013 
IsDisabled()1014 sal_Bool ScHeaderControl::IsDisabled()
1015 {
1016 	return sal_False;
1017 }
1018 
ResizeAllowed()1019 sal_Bool ScHeaderControl::ResizeAllowed()
1020 {
1021 	return sal_True;
1022 }
1023 
SelectWindow()1024 void ScHeaderControl::SelectWindow()
1025 {
1026 }
1027 
DrawInvert(long)1028 void ScHeaderControl::DrawInvert( long /* nDragPos */ )
1029 {
1030 }
1031 
GetDragHelp(long)1032 String ScHeaderControl::GetDragHelp( long /* nVal */ )
1033 {
1034 	return EMPTY_STRING;
1035 }
1036 
SetMarking(sal_Bool)1037 void ScHeaderControl::SetMarking( sal_Bool /* bSet */ )
1038 {
1039 }
1040 
1041 
1042 
1043