Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
5 : * This Source Code Form is subject to the terms of the Mozilla Public
6 : * License, v. 2.0. If a copy of the MPL was not distributed with this
7 : * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 : *
9 : * This file incorporates work covered by the following license notice:
10 : *
11 : * Licensed to the Apache Software Foundation (ASF) under one or more
12 : * contributor license agreements. See the NOTICE file distributed
13 : * with this work for additional information regarding copyright
14 : * ownership. The ASF licenses this file to you under the Apache
15 : * License, Version 2.0 (the "License"); you may not use this file
16 : * except in compliance with the License. You may obtain a copy of
17 : * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 : */
19 :
20 : #include "tools/rc.h"
21 :
22 : #include "vcl/event.hxx"
23 : #include "vcl/decoview.hxx"
24 : #include "vcl/spin.h"
25 : #include "vcl/spinfld.hxx"
26 : #include "vcl/settings.hxx"
27 :
28 : #include "controldata.hxx"
29 : #include "svdata.hxx"
30 :
31 : namespace {
32 :
33 697 : void ImplGetSpinbuttonValue(vcl::Window* pWin,
34 : const Rectangle& rUpperRect, const Rectangle& rLowerRect,
35 : bool bUpperIn, bool bLowerIn, bool bUpperEnabled, bool bLowerEnabled,
36 : bool bHorz, SpinbuttonValue& rValue )
37 : {
38 : // convert spinbutton data to a SpinbuttonValue structure for native painting
39 :
40 697 : rValue.maUpperRect = rUpperRect;
41 697 : rValue.maLowerRect = rLowerRect;
42 :
43 697 : Point aPointerPos = pWin->GetPointerPosPixel();
44 :
45 697 : ControlState nState = ControlState::ENABLED;
46 697 : if (bUpperIn)
47 0 : nState |= ControlState::PRESSED;
48 697 : if (!pWin->IsEnabled() || !bUpperEnabled)
49 400 : nState &= ~ControlState::ENABLED;
50 697 : if (pWin->HasFocus())
51 0 : nState |= ControlState::FOCUSED;
52 697 : if (pWin->IsMouseOver() && rUpperRect.IsInside(aPointerPos))
53 0 : nState |= ControlState::ROLLOVER;
54 697 : rValue.mnUpperState = nState;
55 :
56 697 : nState = ControlState::ENABLED;
57 697 : if (bLowerIn)
58 0 : nState |= ControlState::PRESSED;
59 697 : if (!pWin->IsEnabled() || !bLowerEnabled)
60 404 : nState &= ~ControlState::ENABLED;
61 697 : if (pWin->HasFocus())
62 0 : nState |= ControlState::FOCUSED;
63 : // for overlapping spins: highlight only one
64 697 : if (pWin->IsMouseOver() && rLowerRect.IsInside(aPointerPos) && !rUpperRect.IsInside(aPointerPos))
65 0 : nState |= ControlState::ROLLOVER;
66 697 : rValue.mnLowerState = nState;
67 :
68 697 : rValue.mnUpperPart = bHorz ? PART_BUTTON_LEFT : PART_BUTTON_UP;
69 697 : rValue.mnLowerPart = bHorz ? PART_BUTTON_RIGHT : PART_BUTTON_DOWN;
70 697 : }
71 :
72 693 : bool ImplDrawNativeSpinfield(vcl::RenderContext& rRenderContext, vcl::Window* pWin, const SpinbuttonValue& rSpinbuttonValue)
73 : {
74 693 : bool bNativeOK = false;
75 :
76 693 : if (rRenderContext.IsNativeControlSupported(CTRL_SPINBOX, PART_ENTIRE_CONTROL) &&
77 : // there is just no useful native support for spinfields with dropdown
78 0 : !(pWin->GetStyle() & WB_DROPDOWN))
79 : {
80 0 : if (rRenderContext.IsNativeControlSupported(CTRL_SPINBOX, rSpinbuttonValue.mnUpperPart) &&
81 0 : rRenderContext.IsNativeControlSupported(CTRL_SPINBOX, rSpinbuttonValue.mnLowerPart))
82 : {
83 : // only paint the embedded spin buttons, all buttons are painted at once
84 : bNativeOK = rRenderContext.DrawNativeControl(CTRL_SPINBOX, PART_ALL_BUTTONS, Rectangle(),
85 0 : ControlState::ENABLED, rSpinbuttonValue, OUString());
86 : }
87 : else
88 : {
89 : // paint the spinbox as a whole, use borderwindow to have proper clipping
90 0 : vcl::Window* pBorder = pWin->GetWindow(GetWindowType::Border);
91 :
92 : // to not overwrite everything, set the button region as clipregion to the border window
93 0 : Rectangle aClipRect(rSpinbuttonValue.maLowerRect);
94 0 : aClipRect.Union(rSpinbuttonValue.maUpperRect);
95 :
96 : // convert from screen space to borderwin space
97 0 : aClipRect.SetPos(pBorder->ScreenToOutputPixel(pWin->OutputToScreenPixel(aClipRect.TopLeft())));
98 :
99 0 : vcl::Region oldRgn(pBorder->GetClipRegion());
100 0 : pBorder->SetClipRegion(vcl::Region(aClipRect));
101 :
102 0 : Point aPt;
103 0 : Size aSize(pBorder->GetOutputSizePixel()); // the size of the border window, i.e., the whole control
104 0 : Rectangle aBound, aContent;
105 0 : Rectangle aNatRgn(aPt, aSize);
106 0 : if (!ImplGetSVData()->maNWFData.mbCanDrawWidgetAnySize &&
107 : pBorder->GetNativeControlRegion(CTRL_SPINBOX, PART_ENTIRE_CONTROL,
108 : aNatRgn, ControlState::NONE, rSpinbuttonValue,
109 0 : OUString(), aBound, aContent))
110 : {
111 0 : aSize = aContent.GetSize();
112 : }
113 :
114 0 : Rectangle aRgn(aPt, aSize);
115 : bNativeOK = pBorder->DrawNativeControl(CTRL_SPINBOX, PART_ENTIRE_CONTROL, aRgn,
116 0 : ControlState::ENABLED, rSpinbuttonValue, OUString());
117 :
118 0 : pBorder->SetClipRegion(vcl::Region(oldRgn));
119 : }
120 : }
121 693 : return bNativeOK;
122 : }
123 :
124 4 : bool ImplDrawNativeSpinbuttons(vcl::RenderContext& rRenderContext, const SpinbuttonValue& rSpinbuttonValue)
125 : {
126 4 : bool bNativeOK = false;
127 :
128 4 : if (rRenderContext.IsNativeControlSupported(CTRL_SPINBUTTONS, PART_ENTIRE_CONTROL))
129 : {
130 : // only paint the standalone spin buttons, all buttons are painted at once
131 : bNativeOK = rRenderContext.DrawNativeControl(CTRL_SPINBUTTONS, PART_ALL_BUTTONS, Rectangle(),
132 0 : ControlState::ENABLED, rSpinbuttonValue, OUString());
133 : }
134 4 : return bNativeOK;
135 : }
136 :
137 : }
138 :
139 697 : void ImplDrawSpinButton(vcl::RenderContext& rRenderContext, vcl::Window* pWindow,
140 : const Rectangle& rUpperRect, const Rectangle& rLowerRect,
141 : bool bUpperIn, bool bLowerIn, bool bUpperEnabled, bool bLowerEnabled,
142 : bool bHorz, bool bMirrorHorz)
143 : {
144 697 : DecorationView aDecoView(&rRenderContext);
145 :
146 697 : DrawButtonFlags nStyle = DrawButtonFlags::NoLeftLightBorder;
147 697 : DrawSymbolFlags nSymStyle = DrawSymbolFlags::NONE;
148 :
149 : SymbolType eType1, eType2;
150 :
151 697 : const StyleSettings& rStyleSettings = rRenderContext.GetSettings().GetStyleSettings();
152 697 : if ( rStyleSettings.GetOptions() & StyleSettingsOptions::SpinArrow )
153 : {
154 : // arrows are only use in OS/2 look
155 0 : if ( bHorz )
156 : {
157 0 : eType1 = bMirrorHorz ? SymbolType::ARROW_RIGHT : SymbolType::ARROW_LEFT;
158 0 : eType2 = bMirrorHorz ? SymbolType::ARROW_LEFT : SymbolType::ARROW_RIGHT;
159 : }
160 : else
161 : {
162 0 : eType1 = SymbolType::ARROW_UP;
163 0 : eType2 = SymbolType::ARROW_DOWN;
164 : }
165 : }
166 : else
167 : {
168 697 : if ( bHorz )
169 : {
170 4 : eType1 = bMirrorHorz ? SymbolType::SPIN_RIGHT : SymbolType::SPIN_LEFT;
171 4 : eType2 = bMirrorHorz ? SymbolType::SPIN_LEFT : SymbolType::SPIN_RIGHT;
172 : }
173 : else
174 : {
175 693 : eType1 = SymbolType::SPIN_UP;
176 693 : eType2 = SymbolType::SPIN_DOWN;
177 : }
178 : }
179 :
180 : // draw upper/left Button
181 697 : DrawButtonFlags nTempStyle = nStyle;
182 697 : if (bUpperIn)
183 0 : nTempStyle |= DrawButtonFlags::Pressed;
184 :
185 697 : bool bNativeOK = false;
186 697 : Rectangle aUpRect;
187 :
188 697 : if (pWindow)
189 : {
190 : // are we drawing standalone spin buttons or members of a spinfield ?
191 697 : ControlType aControl = CTRL_SPINBUTTONS;
192 697 : switch (pWindow->GetType())
193 : {
194 : case WINDOW_EDIT:
195 : case WINDOW_MULTILINEEDIT:
196 : case WINDOW_PATTERNFIELD:
197 : case WINDOW_METRICFIELD:
198 : case WINDOW_CURRENCYFIELD:
199 : case WINDOW_DATEFIELD:
200 : case WINDOW_TIMEFIELD:
201 : case WINDOW_LONGCURRENCYFIELD:
202 : case WINDOW_NUMERICFIELD:
203 : case WINDOW_SPINFIELD:
204 693 : aControl = CTRL_SPINBOX;
205 693 : break;
206 : default:
207 4 : aControl = CTRL_SPINBUTTONS;
208 4 : break;
209 : }
210 :
211 697 : SpinbuttonValue aValue;
212 : ImplGetSpinbuttonValue(pWindow, rUpperRect, rLowerRect,
213 : bUpperIn, bLowerIn, bUpperEnabled, bLowerEnabled,
214 697 : bHorz, aValue);
215 :
216 697 : if( aControl == CTRL_SPINBOX )
217 693 : bNativeOK = ImplDrawNativeSpinfield(rRenderContext, pWindow, aValue);
218 4 : else if( aControl == CTRL_SPINBUTTONS )
219 4 : bNativeOK = ImplDrawNativeSpinbuttons(rRenderContext, aValue);
220 : }
221 :
222 697 : if (!bNativeOK)
223 697 : aUpRect = aDecoView.DrawButton(rUpperRect, nTempStyle);
224 :
225 : // draw lower/right Button
226 697 : if (bLowerIn)
227 0 : nStyle |= DrawButtonFlags::Pressed;
228 697 : Rectangle aLowRect;
229 697 : if(!bNativeOK)
230 697 : aLowRect = aDecoView.DrawButton(rLowerRect, nStyle);
231 :
232 : // make use of additional default edge
233 697 : aUpRect.Left()--;
234 697 : aUpRect.Top()--;
235 697 : aUpRect.Right()++;
236 697 : aUpRect.Bottom()++;
237 697 : aLowRect.Left()--;
238 697 : aLowRect.Top()--;
239 697 : aLowRect.Right()++;
240 697 : aLowRect.Bottom()++;
241 :
242 : // draw into the edge, so that something is visible if the rectangle is too small
243 697 : if (aUpRect.GetHeight() < 4)
244 : {
245 142 : aUpRect.Right()++;
246 142 : aUpRect.Bottom()++;
247 142 : aLowRect.Right()++;
248 142 : aLowRect.Bottom()++;
249 : }
250 :
251 : // calculate Symbol size
252 697 : long nTempSize1 = aUpRect.GetWidth();
253 697 : long nTempSize2 = aLowRect.GetWidth();
254 697 : if (std::abs( nTempSize1-nTempSize2 ) == 1)
255 : {
256 0 : if (nTempSize1 > nTempSize2)
257 0 : aUpRect.Left()++;
258 : else
259 0 : aLowRect.Left()++;
260 : }
261 697 : nTempSize1 = aUpRect.GetHeight();
262 697 : nTempSize2 = aLowRect.GetHeight();
263 697 : if (std::abs(nTempSize1 - nTempSize2) == 1)
264 : {
265 0 : if (nTempSize1 > nTempSize2)
266 0 : aUpRect.Top()++;
267 : else
268 0 : aLowRect.Top()++;
269 : }
270 :
271 697 : DrawSymbolFlags nTempSymStyle = nSymStyle;
272 697 : if (!bUpperEnabled)
273 400 : nTempSymStyle |= DrawSymbolFlags::Disable;
274 697 : if (!bNativeOK)
275 697 : aDecoView.DrawSymbol(aUpRect, eType1, rStyleSettings.GetButtonTextColor(), nTempSymStyle);
276 :
277 697 : if (!bLowerEnabled)
278 404 : nSymStyle |= DrawSymbolFlags::Disable;
279 697 : if (!bNativeOK)
280 697 : aDecoView.DrawSymbol(aLowRect, eType2, rStyleSettings.GetButtonTextColor(), nSymStyle);
281 697 : }
282 :
283 2319 : void SpinField::ImplInitSpinFieldData()
284 : {
285 2319 : mpEdit.disposeAndClear();
286 2319 : mbSpin = false;
287 2319 : mbRepeat = false;
288 2319 : mbUpperIn = false;
289 2319 : mbLowerIn = false;
290 2319 : mbInitialUp = false;
291 2319 : mbInitialDown = false;
292 2319 : mbNoSelect = false;
293 2319 : mbInDropDown = false;
294 2319 : }
295 :
296 2319 : void SpinField::ImplInit(vcl::Window* pParent, WinBits nWinStyle)
297 : {
298 2319 : Edit::ImplInit( pParent, nWinStyle );
299 :
300 2319 : if (nWinStyle & (WB_SPIN | WB_DROPDOWN))
301 : {
302 2193 : mbSpin = true;
303 :
304 : // Some themes want external spin buttons, therefore the main
305 : // spinfield should not overdraw the border between its encapsulated
306 : // edit field and the spin buttons
307 2193 : if ((nWinStyle & WB_SPIN) && ImplUseNativeBorder(*this, nWinStyle))
308 : {
309 0 : SetBackground();
310 0 : mpEdit.set(VclPtr<Edit>::Create(this, WB_NOBORDER));
311 0 : mpEdit->SetBackground();
312 : }
313 : else
314 2193 : mpEdit.set(VclPtr<Edit>::Create(this, WB_NOBORDER));
315 :
316 2193 : mpEdit->EnableRTL(false);
317 2193 : mpEdit->SetPosPixel(Point());
318 2193 : mpEdit->Show();
319 :
320 2193 : SetSubEdit(mpEdit);
321 :
322 2193 : maRepeatTimer.SetTimeoutHdl(LINK( this, SpinField, ImplTimeout));
323 2193 : maRepeatTimer.SetTimeout(GetSettings().GetMouseSettings().GetButtonStartRepeat());
324 2193 : if (nWinStyle & WB_REPEAT)
325 2157 : mbRepeat = true;
326 :
327 2193 : SetCompoundControl(true);
328 : }
329 2319 : }
330 :
331 8 : SpinField::SpinField(WindowType nTyp) :
332 8 : Edit(nTyp)
333 : {
334 8 : ImplInitSpinFieldData();
335 8 : }
336 :
337 2311 : SpinField::SpinField(vcl::Window* pParent, WinBits nWinStyle) :
338 2311 : Edit(WINDOW_SPINFIELD)
339 : {
340 2311 : ImplInitSpinFieldData();
341 2311 : ImplInit(pParent, nWinStyle);
342 2311 : }
343 :
344 0 : SpinField::SpinField(vcl::Window* pParent, const ResId& rResId) :
345 0 : Edit(WINDOW_SPINFIELD)
346 : {
347 0 : ImplInitSpinFieldData();
348 0 : rResId.SetRT(RSC_SPINFIELD);
349 0 : WinBits nStyle = ImplInitRes(rResId);
350 0 : ImplInit(pParent, nStyle);
351 0 : ImplLoadRes(rResId);
352 :
353 0 : if (!(nStyle & WB_HIDE))
354 0 : Show();
355 0 : }
356 :
357 126 : SpinField::~SpinField()
358 : {
359 63 : disposeOnce();
360 63 : }
361 :
362 2319 : void SpinField::dispose()
363 : {
364 2319 : mpEdit.disposeAndClear();
365 :
366 2319 : Edit::dispose();
367 2319 : }
368 :
369 22 : void SpinField::Up()
370 : {
371 22 : ImplCallEventListenersAndHandler( VCLEVENT_SPINFIELD_UP, maUpHdlLink, this );
372 22 : }
373 :
374 11 : void SpinField::Down()
375 : {
376 11 : ImplCallEventListenersAndHandler( VCLEVENT_SPINFIELD_DOWN, maDownHdlLink, this );
377 11 : }
378 :
379 11 : void SpinField::First()
380 : {
381 11 : ImplCallEventListenersAndHandler( VCLEVENT_SPINFIELD_FIRST, maFirstHdlLink, this );
382 11 : }
383 :
384 11 : void SpinField::Last()
385 : {
386 11 : ImplCallEventListenersAndHandler( VCLEVENT_SPINFIELD_LAST, maLastHdlLink, this );
387 11 : }
388 :
389 0 : void SpinField::MouseButtonDown( const MouseEvent& rMEvt )
390 : {
391 0 : if (!HasFocus() && (!mpEdit || !mpEdit->HasFocus()))
392 : {
393 0 : mbNoSelect = true;
394 0 : GrabFocus();
395 : }
396 :
397 0 : if (!IsReadOnly())
398 : {
399 0 : if (maUpperRect.IsInside(rMEvt.GetPosPixel()))
400 : {
401 0 : mbUpperIn = true;
402 0 : mbInitialUp = true;
403 0 : Invalidate(maUpperRect);
404 : }
405 0 : else if (maLowerRect.IsInside(rMEvt.GetPosPixel()))
406 : {
407 0 : mbLowerIn = true;
408 0 : mbInitialDown = true;
409 0 : Invalidate(maLowerRect);
410 : }
411 0 : else if (maDropDownRect.IsInside(rMEvt.GetPosPixel()))
412 : {
413 : // put DropDownButton to the right
414 0 : mbInDropDown = ShowDropDown( !mbInDropDown );
415 0 : Invalidate(Rectangle(Point(), GetOutputSizePixel()));
416 : }
417 :
418 0 : if (mbUpperIn || mbLowerIn)
419 : {
420 0 : Update();
421 0 : CaptureMouse();
422 0 : if (mbRepeat)
423 0 : maRepeatTimer.Start();
424 0 : return;
425 : }
426 : }
427 :
428 0 : Edit::MouseButtonDown(rMEvt);
429 : }
430 :
431 0 : void SpinField::MouseButtonUp(const MouseEvent& rMEvt)
432 : {
433 0 : ReleaseMouse();
434 0 : mbInitialUp = mbInitialDown = false;
435 0 : maRepeatTimer.Stop();
436 0 : maRepeatTimer.SetTimeout(GetSettings().GetMouseSettings().GetButtonStartRepeat());
437 :
438 0 : if (mbUpperIn)
439 : {
440 0 : mbUpperIn = false;
441 0 : Invalidate(maUpperRect);
442 0 : Update();
443 0 : Up();
444 : }
445 0 : else if (mbLowerIn)
446 : {
447 0 : mbLowerIn = false;
448 0 : Invalidate(maLowerRect);
449 0 : Update();
450 0 : Down();
451 : }
452 :
453 0 : Edit::MouseButtonUp(rMEvt);
454 0 : }
455 :
456 0 : void SpinField::MouseMove(const MouseEvent& rMEvt)
457 : {
458 0 : if (rMEvt.IsLeft())
459 : {
460 0 : if (mbInitialUp)
461 : {
462 0 : bool bNewUpperIn = maUpperRect.IsInside(rMEvt.GetPosPixel());
463 0 : if (bNewUpperIn != mbUpperIn)
464 : {
465 0 : if (bNewUpperIn)
466 : {
467 0 : if (mbRepeat)
468 0 : maRepeatTimer.Start();
469 : }
470 : else
471 0 : maRepeatTimer.Stop();
472 :
473 0 : mbUpperIn = bNewUpperIn;
474 0 : Invalidate(maUpperRect);
475 0 : Update();
476 : }
477 : }
478 0 : else if (mbInitialDown)
479 : {
480 0 : bool bNewLowerIn = maLowerRect.IsInside(rMEvt.GetPosPixel());
481 0 : if (bNewLowerIn != mbLowerIn)
482 : {
483 0 : if (bNewLowerIn)
484 : {
485 0 : if (mbRepeat)
486 0 : maRepeatTimer.Start();
487 : }
488 : else
489 0 : maRepeatTimer.Stop();
490 :
491 0 : mbLowerIn = bNewLowerIn;
492 0 : Invalidate(maLowerRect);
493 0 : Update();
494 : }
495 : }
496 : }
497 :
498 0 : Edit::MouseMove(rMEvt);
499 0 : }
500 :
501 2310 : bool SpinField::Notify(NotifyEvent& rNEvt)
502 : {
503 2310 : bool nDone = false;
504 2310 : if (rNEvt.GetType() == MouseNotifyEvent::KEYINPUT)
505 : {
506 0 : const KeyEvent& rKEvt = *rNEvt.GetKeyEvent();
507 0 : if (!IsReadOnly())
508 : {
509 0 : sal_uInt16 nMod = rKEvt.GetKeyCode().GetModifier();
510 0 : switch (rKEvt.GetKeyCode().GetCode())
511 : {
512 : case KEY_UP:
513 : {
514 0 : if (!nMod)
515 : {
516 0 : Up();
517 0 : nDone = true;
518 : }
519 : }
520 0 : break;
521 : case KEY_DOWN:
522 : {
523 0 : if (!nMod)
524 : {
525 0 : Down();
526 0 : nDone = true;
527 : }
528 0 : else if ((nMod == KEY_MOD2) && !mbInDropDown && (GetStyle() & WB_DROPDOWN))
529 : {
530 0 : mbInDropDown = ShowDropDown(true);
531 0 : Invalidate(Rectangle(Point(), GetOutputSizePixel()));
532 0 : nDone = true;
533 : }
534 : }
535 0 : break;
536 : case KEY_PAGEUP:
537 : {
538 0 : if (!nMod)
539 : {
540 0 : Last();
541 0 : nDone = true;
542 : }
543 : }
544 0 : break;
545 : case KEY_PAGEDOWN:
546 : {
547 0 : if (!nMod)
548 : {
549 0 : First();
550 0 : nDone = true;
551 : }
552 : }
553 0 : break;
554 : }
555 : }
556 : }
557 :
558 2310 : if (rNEvt.GetType() == MouseNotifyEvent::COMMAND)
559 : {
560 0 : if ((rNEvt.GetCommandEvent()->GetCommand() == CommandEventId::Wheel) && !IsReadOnly())
561 : {
562 0 : MouseWheelBehaviour nWheelBehavior(GetSettings().GetMouseSettings().GetWheelBehavior());
563 0 : if (nWheelBehavior == MouseWheelBehaviour::ALWAYS
564 0 : || (nWheelBehavior == MouseWheelBehaviour::FocusOnly && HasChildPathFocus()))
565 : {
566 0 : const CommandWheelData* pData = rNEvt.GetCommandEvent()->GetWheelData();
567 0 : if (pData->GetMode() == CommandWheelMode::SCROLL)
568 : {
569 0 : if (pData->GetDelta() < 0L)
570 0 : Down();
571 : else
572 0 : Up();
573 0 : nDone = true;
574 : }
575 : }
576 : else
577 0 : nDone = false; // don't eat this event, let the default handling happen (i.e. scroll the context)
578 : }
579 : }
580 :
581 2310 : return nDone || Edit::Notify(rNEvt);
582 : }
583 :
584 0 : void SpinField::Command(const CommandEvent& rCEvt)
585 : {
586 0 : Edit::Command(rCEvt);
587 0 : }
588 :
589 0 : void SpinField::FillLayoutData() const
590 : {
591 0 : if (mbSpin)
592 : {
593 0 : mpControlData->mpLayoutData = new vcl::ControlLayoutData();
594 0 : AppendLayoutData(*GetSubEdit());
595 0 : GetSubEdit()->SetLayoutDataParent(this);
596 : }
597 : else
598 0 : Edit::FillLayoutData();
599 0 : }
600 :
601 2097 : void SpinField::Paint(vcl::RenderContext& rRenderContext, const Rectangle& rRect)
602 : {
603 2097 : if (mbSpin)
604 : {
605 693 : bool bEnable = IsEnabled();
606 : ImplDrawSpinButton(rRenderContext, this, maUpperRect, maLowerRect,
607 693 : mbUpperIn, mbLowerIn, bEnable, bEnable);
608 : }
609 :
610 2097 : if (GetStyle() & WB_DROPDOWN)
611 : {
612 189 : DecorationView aView(&rRenderContext);
613 :
614 189 : DrawButtonFlags nStyle = DrawButtonFlags::NoLightBorder;
615 189 : if (mbInDropDown)
616 0 : nStyle |= DrawButtonFlags::Pressed;
617 189 : Rectangle aInnerRect = aView.DrawButton(maDropDownRect, nStyle);
618 :
619 189 : SymbolType eSymbol = SymbolType::SPIN_DOWN;
620 189 : if (rRenderContext.GetSettings().GetStyleSettings().GetOptions() & StyleSettingsOptions::SpinUpDown)
621 0 : eSymbol = SymbolType::SPIN_UPDOWN;
622 :
623 189 : DrawSymbolFlags nSymbolStyle = IsEnabled() ? DrawSymbolFlags::NONE : DrawSymbolFlags::Disable;
624 189 : aView.DrawSymbol(aInnerRect, eSymbol, rRenderContext.GetSettings().GetStyleSettings().GetButtonTextColor(), nSymbolStyle);
625 : }
626 :
627 2097 : Edit::Paint(rRenderContext, rRect);
628 2097 : }
629 :
630 6010 : void SpinField::ImplCalcButtonAreas(OutputDevice* pDev, const Size& rOutSz, Rectangle& rDDArea,
631 : Rectangle& rSpinUpArea, Rectangle& rSpinDownArea)
632 : {
633 6010 : const StyleSettings& rStyleSettings = pDev->GetSettings().GetStyleSettings();
634 :
635 6010 : Size aSize = rOutSz;
636 6010 : Size aDropDownSize;
637 :
638 6010 : if (GetStyle() & WB_DROPDOWN)
639 : {
640 276 : long nW = rStyleSettings.GetScrollBarSize();
641 276 : nW = GetDrawPixel( pDev, nW );
642 276 : aDropDownSize = Size( CalcZoom( nW ), aSize.Height() );
643 276 : aSize.Width() -= aDropDownSize.Width();
644 276 : rDDArea = Rectangle( Point( aSize.Width(), 0 ), aDropDownSize );
645 276 : rDDArea.Top()--;
646 : }
647 : else
648 5734 : rDDArea.SetEmpty();
649 :
650 : // calcuate sizes according to the height
651 6010 : if (GetStyle() & WB_SPIN)
652 : {
653 5828 : long nBottom1 = aSize.Height()/2;
654 5828 : long nBottom2 = aSize.Height()-1;
655 5828 : long nTop2 = nBottom1;
656 5828 : long nTop1 = 0;
657 5828 : if ( !(aSize.Height() & 0x01) )
658 2946 : nBottom1--;
659 :
660 5828 : bool bNativeRegionOK = false;
661 5828 : Rectangle aContentUp, aContentDown;
662 :
663 17484 : if ((pDev->GetOutDevType() == OUTDEV_WINDOW) &&
664 : // there is just no useful native support for spinfields with dropdown
665 11562 : ! (GetStyle() & WB_DROPDOWN) &&
666 5734 : IsNativeControlSupported(CTRL_SPINBOX, PART_ENTIRE_CONTROL))
667 : {
668 0 : vcl::Window *pWin = static_cast<vcl::Window*>(pDev);
669 0 : vcl::Window *pBorder = pWin->GetWindow( GetWindowType::Border );
670 :
671 : // get the system's spin button size
672 0 : ImplControlValue aControlValue;
673 0 : Rectangle aBound;
674 0 : Point aPoint;
675 :
676 : // use the full extent of the control
677 0 : Rectangle aArea( aPoint, pBorder->GetOutputSizePixel() );
678 :
679 : bNativeRegionOK =
680 : pWin->GetNativeControlRegion(CTRL_SPINBOX, PART_BUTTON_UP,
681 0 : aArea, ControlState::NONE, aControlValue, OUString(), aBound, aContentUp) &&
682 : pWin->GetNativeControlRegion(CTRL_SPINBOX, PART_BUTTON_DOWN,
683 0 : aArea, ControlState::NONE, aControlValue, OUString(), aBound, aContentDown);
684 :
685 0 : if (bNativeRegionOK)
686 : {
687 : // convert back from border space to local coordinates
688 0 : aPoint = pBorder->ScreenToOutputPixel( pWin->OutputToScreenPixel( aPoint ) );
689 0 : aContentUp.Move(-aPoint.X(), -aPoint.Y());
690 0 : aContentDown.Move(-aPoint.X(), -aPoint.Y());
691 0 : }
692 : }
693 :
694 5828 : if (bNativeRegionOK)
695 : {
696 0 : rSpinUpArea = aContentUp;
697 0 : rSpinDownArea = aContentDown;
698 : }
699 : else
700 : {
701 5828 : aSize.Width() -= CalcZoom( GetDrawPixel( pDev, rStyleSettings.GetSpinSize() ) );
702 :
703 5828 : rSpinUpArea = Rectangle( aSize.Width(), nTop1, rOutSz.Width()-aDropDownSize.Width()-1, nBottom1 );
704 5828 : rSpinDownArea = Rectangle( rSpinUpArea.Left(), nTop2, rSpinUpArea.Right(), nBottom2 );
705 : }
706 : }
707 : else
708 : {
709 182 : rSpinUpArea.SetEmpty();
710 182 : rSpinDownArea.SetEmpty();
711 : }
712 6010 : }
713 :
714 7431 : void SpinField::Resize()
715 : {
716 7431 : if (mbSpin)
717 : {
718 6010 : Control::Resize();
719 6010 : Size aSize = GetOutputSizePixel();
720 6010 : bool bSubEditPositioned = false;
721 :
722 6010 : if (GetStyle() & (WB_SPIN | WB_DROPDOWN))
723 : {
724 6010 : ImplCalcButtonAreas( this, aSize, maDropDownRect, maUpperRect, maLowerRect );
725 :
726 6010 : ImplControlValue aControlValue;
727 6010 : Point aPoint;
728 6010 : Rectangle aContent, aBound;
729 :
730 : // use the full extent of the control
731 6010 : vcl::Window *pBorder = GetWindow( GetWindowType::Border );
732 6010 : Rectangle aArea( aPoint, pBorder->GetOutputSizePixel() );
733 :
734 : // adjust position and size of the edit field
735 12020 : if (GetNativeControlRegion(CTRL_SPINBOX, PART_SUB_EDIT, aArea, ControlState::NONE,
736 12020 : aControlValue, OUString(), aBound, aContent))
737 : {
738 : // convert back from border space to local coordinates
739 0 : aPoint = pBorder->ScreenToOutputPixel(OutputToScreenPixel(aPoint));
740 0 : aContent.Move(-aPoint.X(), -aPoint.Y());
741 :
742 : // use the themes drop down size
743 0 : mpEdit->SetPosPixel( aContent.TopLeft() );
744 0 : bSubEditPositioned = true;
745 0 : aSize = aContent.GetSize();
746 : }
747 : else
748 : {
749 6010 : if (maUpperRect.IsEmpty())
750 : {
751 : DBG_ASSERT( !maDropDownRect.IsEmpty(), "SpinField::Resize: SPIN && DROPDOWN, but all empty rects?" );
752 182 : aSize.Width() = maDropDownRect.Left();
753 : }
754 : else
755 5828 : aSize.Width() = maUpperRect.Left();
756 6010 : }
757 : }
758 :
759 6010 : if (!bSubEditPositioned)
760 : {
761 : // this moves our sub edit if RTL gets switched
762 6010 : mpEdit->SetPosPixel(Point());
763 : }
764 6010 : mpEdit->SetSizePixel(aSize);
765 :
766 6010 : if (GetStyle() & WB_SPIN)
767 5828 : Invalidate(Rectangle(maUpperRect.TopLeft(), maLowerRect.BottomRight()));
768 6010 : if (GetStyle() & WB_DROPDOWN)
769 276 : Invalidate(maDropDownRect);
770 : }
771 7431 : }
772 :
773 8716 : void SpinField::StateChanged(StateChangedType nType)
774 : {
775 8716 : Edit::StateChanged(nType);
776 :
777 8716 : if (nType == StateChangedType::Enable)
778 : {
779 340 : if (mbSpin || (GetStyle() & WB_DROPDOWN))
780 : {
781 227 : mpEdit->Enable(IsEnabled());
782 :
783 227 : if (mbSpin)
784 : {
785 227 : Invalidate(maLowerRect);
786 227 : Invalidate(maUpperRect);
787 : }
788 227 : if (GetStyle() & WB_DROPDOWN)
789 14 : Invalidate(maDropDownRect);
790 : }
791 : }
792 8376 : else if (nType == StateChangedType::Style)
793 : {
794 357 : if (GetStyle() & WB_REPEAT)
795 101 : mbRepeat = true;
796 : else
797 256 : mbRepeat = false;
798 : }
799 8019 : else if (nType == StateChangedType::Zoom)
800 : {
801 1 : Resize();
802 1 : if (mpEdit)
803 1 : mpEdit->SetZoom(GetZoom());
804 1 : Invalidate();
805 : }
806 8018 : else if (nType == StateChangedType::ControlFont)
807 : {
808 641 : if (mpEdit)
809 284 : mpEdit->SetControlFont(GetControlFont());
810 641 : Invalidate();
811 : }
812 7377 : else if (nType == StateChangedType::ControlForeground)
813 : {
814 0 : if (mpEdit)
815 0 : mpEdit->SetControlForeground(GetControlForeground());
816 0 : Invalidate();
817 : }
818 7377 : else if (nType == StateChangedType::ControlBackground)
819 : {
820 0 : if (mpEdit)
821 0 : mpEdit->SetControlBackground(GetControlBackground());
822 0 : Invalidate();
823 : }
824 7377 : else if( nType == StateChangedType::Mirroring )
825 : {
826 401 : if (mpEdit)
827 89 : mpEdit->CompatStateChanged(StateChangedType::Mirroring);
828 401 : Resize();
829 : }
830 8716 : }
831 :
832 1847 : void SpinField::DataChanged( const DataChangedEvent& rDCEvt )
833 : {
834 1847 : Edit::DataChanged(rDCEvt);
835 :
836 7388 : if ((rDCEvt.GetType() == DataChangedEventType::SETTINGS) &&
837 7388 : (rDCEvt.GetFlags() & AllSettingsFlags::STYLE))
838 : {
839 1847 : Resize();
840 1847 : Invalidate();
841 : }
842 1847 : }
843 :
844 0 : Rectangle* SpinField::ImplFindPartRect(const Point& rPt)
845 : {
846 0 : if (maUpperRect.IsInside(rPt))
847 0 : return &maUpperRect;
848 0 : else if (maLowerRect.IsInside(rPt))
849 0 : return &maLowerRect;
850 : else
851 0 : return NULL;
852 : }
853 :
854 0 : bool SpinField::PreNotify(NotifyEvent& rNEvt)
855 : {
856 0 : const MouseEvent* pMouseEvt = NULL;
857 :
858 0 : if ((rNEvt.GetType() == MouseNotifyEvent::MOUSEMOVE) && (pMouseEvt = rNEvt.GetMouseEvent()) != NULL)
859 : {
860 0 : if (!pMouseEvt->GetButtons() && !pMouseEvt->IsSynthetic() && !pMouseEvt->IsModifierChanged())
861 : {
862 : // trigger redraw if mouse over state has changed
863 0 : if( IsNativeControlSupported(CTRL_SPINBOX, PART_ENTIRE_CONTROL) ||
864 0 : IsNativeControlSupported(CTRL_SPINBOX, PART_ALL_BUTTONS) )
865 : {
866 0 : Rectangle* pRect = ImplFindPartRect( GetPointerPosPixel() );
867 0 : Rectangle* pLastRect = ImplFindPartRect( GetLastPointerPosPixel() );
868 0 : if( pRect != pLastRect || (pMouseEvt->IsLeaveWindow() || pMouseEvt->IsEnterWindow()) )
869 : {
870 : // FIXME: this is currently only on OS X
871 : // check for other platforms that need similar handling
872 0 : if (ImplGetSVData()->maNWFData.mbNoFocusRects && IsNativeWidgetEnabled() &&
873 0 : IsNativeControlSupported(CTRL_EDITBOX, PART_ENTIRE_CONTROL))
874 : {
875 0 : ImplInvalidateOutermostBorder(this);
876 : }
877 : else
878 : {
879 : // paint directly
880 0 : vcl::Region aRgn( GetActiveClipRegion() );
881 0 : if (pLastRect)
882 : {
883 0 : SetClipRegion(vcl::Region(*pLastRect));
884 0 : Invalidate(*pLastRect);
885 0 : SetClipRegion( aRgn );
886 : }
887 0 : if (pRect)
888 : {
889 0 : SetClipRegion(vcl::Region(*pRect));
890 0 : Invalidate(*pRect);
891 0 : SetClipRegion( aRgn );
892 0 : }
893 : }
894 : }
895 : }
896 : }
897 : }
898 :
899 0 : return Edit::PreNotify(rNEvt);
900 : }
901 :
902 0 : void SpinField::EndDropDown()
903 : {
904 0 : mbInDropDown = false;
905 0 : Invalidate(Rectangle(Point(), GetOutputSizePixel()));
906 0 : }
907 :
908 0 : bool SpinField::ShowDropDown( bool )
909 : {
910 0 : return false;
911 : }
912 :
913 11558 : Size SpinField::CalcMinimumSizeForText(const OUString &rString) const
914 : {
915 11558 : Size aSz = Edit::CalcMinimumSizeForText(rString);
916 :
917 11558 : if ( GetStyle() & WB_DROPDOWN )
918 0 : aSz.Width() += GetSettings().GetStyleSettings().GetScrollBarSize();
919 11558 : if ( GetStyle() & WB_SPIN )
920 : {
921 11514 : ImplControlValue aControlValue;
922 11514 : Rectangle aArea( Point(), Size(100, aSz.Height()));
923 11514 : Rectangle aEntireBound, aEntireContent, aEditBound, aEditContent;
924 23028 : if (
925 : GetNativeControlRegion(CTRL_SPINBOX, PART_ENTIRE_CONTROL,
926 34542 : aArea, ControlState::NONE, aControlValue, OUString(), aEntireBound, aEntireContent) &&
927 : GetNativeControlRegion(CTRL_SPINBOX, PART_SUB_EDIT,
928 11514 : aArea, ControlState::NONE, aControlValue, OUString(), aEditBound, aEditContent)
929 : )
930 : {
931 0 : aSz.Width() += (aEntireContent.GetWidth() - aEditContent.GetWidth());
932 : }
933 : else
934 : {
935 11514 : aSz.Width() += maUpperRect.GetWidth();
936 11514 : }
937 : }
938 :
939 11558 : return aSz;
940 : }
941 :
942 44 : Size SpinField::CalcMinimumSize() const
943 : {
944 44 : return CalcMinimumSizeForText(GetText());
945 : }
946 :
947 3838 : Size SpinField::GetOptimalSize() const
948 : {
949 3838 : return CalcMinimumSize();
950 : }
951 :
952 11558 : Size SpinField::CalcSize(sal_Int32 nChars) const
953 : {
954 11558 : Size aSz = Edit::CalcSize( nChars );
955 :
956 11558 : if ( GetStyle() & WB_DROPDOWN )
957 0 : aSz.Width() += GetSettings().GetStyleSettings().GetScrollBarSize();
958 11558 : if ( GetStyle() & WB_SPIN )
959 11514 : aSz.Width() += GetSettings().GetStyleSettings().GetSpinSize();
960 :
961 11558 : return aSz;
962 : }
963 :
964 0 : IMPL_LINK_TYPED( SpinField, ImplTimeout, Timer*, pTimer, void )
965 : {
966 0 : if ( pTimer->GetTimeout() == GetSettings().GetMouseSettings().GetButtonStartRepeat() )
967 : {
968 0 : pTimer->SetTimeout( GetSettings().GetMouseSettings().GetButtonRepeat() );
969 0 : pTimer->Start();
970 : }
971 : else
972 : {
973 0 : if ( mbInitialUp )
974 0 : Up();
975 : else
976 0 : Down();
977 : }
978 0 : }
979 :
980 0 : void SpinField::Draw(OutputDevice* pDev, const Point& rPos, const Size& rSize, DrawFlags nFlags)
981 : {
982 0 : Edit::Draw(pDev, rPos, rSize, nFlags);
983 :
984 0 : WinBits nFieldStyle = GetStyle();
985 0 : if ( !(nFlags & DrawFlags::NoControls ) && ( nFieldStyle & (WB_SPIN|WB_DROPDOWN) ) )
986 : {
987 0 : Point aPos = pDev->LogicToPixel( rPos );
988 0 : Size aSize = pDev->LogicToPixel( rSize );
989 0 : OutDevType eOutDevType = pDev->GetOutDevType();
990 0 : AllSettings aOldSettings = pDev->GetSettings();
991 :
992 0 : pDev->Push();
993 0 : pDev->SetMapMode();
994 :
995 0 : if (eOutDevType == OUTDEV_PRINTER)
996 : {
997 0 : StyleSettings aStyleSettings = aOldSettings.GetStyleSettings();
998 0 : aStyleSettings.SetFaceColor(COL_LIGHTGRAY);
999 0 : aStyleSettings.SetButtonTextColor(COL_BLACK);
1000 0 : AllSettings aSettings(aOldSettings);
1001 0 : aSettings.SetStyleSettings(aStyleSettings);
1002 0 : pDev->SetSettings(aSettings);
1003 : }
1004 :
1005 0 : Rectangle aDD, aUp, aDown;
1006 0 : ImplCalcButtonAreas(pDev, aSize, aDD, aUp, aDown);
1007 0 : aDD.Move(aPos.X(), aPos.Y());
1008 0 : aUp.Move(aPos.X(), aPos.Y());
1009 0 : aUp.Top()++;
1010 0 : aDown.Move(aPos.X(), aPos.Y());
1011 :
1012 0 : Color aButtonTextColor;
1013 0 : if ((nFlags & DrawFlags::Mono) || (eOutDevType == OUTDEV_PRINTER))
1014 0 : aButtonTextColor = Color( COL_BLACK );
1015 : else
1016 0 : aButtonTextColor = GetSettings().GetStyleSettings().GetButtonTextColor();
1017 :
1018 0 : if (GetStyle() & WB_DROPDOWN)
1019 : {
1020 0 : DecorationView aView( pDev );
1021 0 : DrawButtonFlags nStyle = DrawButtonFlags::NoLightBorder;
1022 0 : Rectangle aInnerRect = aView.DrawButton( aDD, nStyle );
1023 0 : SymbolType eSymbol = SymbolType::SPIN_DOWN;
1024 0 : if (GetSettings().GetStyleSettings().GetOptions() & StyleSettingsOptions::SpinUpDown)
1025 0 : eSymbol = SymbolType::SPIN_UPDOWN;
1026 :
1027 0 : DrawSymbolFlags nSymbolStyle = (IsEnabled() || (nFlags & DrawFlags::NoDisable)) ? DrawSymbolFlags::NONE : DrawSymbolFlags::Disable;
1028 0 : aView.DrawSymbol(aInnerRect, eSymbol, aButtonTextColor, nSymbolStyle);
1029 : }
1030 :
1031 0 : if (GetStyle() & WB_SPIN)
1032 : {
1033 0 : ImplDrawSpinButton(*pDev, this, aUp, aDown, false, false, true, true);
1034 : }
1035 :
1036 0 : pDev->Pop();
1037 0 : pDev->SetSettings(aOldSettings);
1038 : }
1039 801 : }
1040 :
1041 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|