Version 7.1.7.1, tag libreoffice-7.1.7.1
[LibreOffice.git] / svx / source / dialog / dlgctl3d.cxx
blob7eb7e07f9f9a99e22852575f895994f27d82775c
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
21 #include <svx/def3d.hxx>
22 #include <svx/dlgctl3d.hxx>
23 #include <svx/strings.hrc>
24 #include <svx/view3d.hxx>
25 #include <svx/fmmodel.hxx>
26 #include <svl/itempool.hxx>
27 #include <svx/fmpage.hxx>
28 #include <svx/sphere3d.hxx>
29 #include <svx/cube3d.hxx>
30 #include <svx/scene3d.hxx>
31 #include <vcl/svapp.hxx>
32 #include <svx/helperhittest3d.hxx>
33 #include <basegfx/polygon/b2dpolygontools.hxx>
34 #include <polygn3d.hxx>
35 #include <svx/xfillit0.hxx>
36 #include <svx/xflclit.hxx>
37 #include <svx/xlineit0.hxx>
38 #include <svx/xlnclit.hxx>
39 #include <svx/xlnwtit.hxx>
40 #include <helpids.h>
41 #include <svx/dialmgr.hxx>
42 #include <tools/helpers.hxx>
43 #include <vcl/settings.hxx>
45 using namespace com::sun::star;
47 Svx3DPreviewControl::Svx3DPreviewControl()
48 : mpFmPage(nullptr)
49 , mpScene(nullptr)
50 , mp3DObj(nullptr)
51 , mnObjectType(SvxPreviewObjectType::SPHERE)
55 void Svx3DPreviewControl::SetDrawingArea(weld::DrawingArea* pDrawingArea)
57 Size aSize(pDrawingArea->get_ref_device().LogicToPixel(Size(80, 100), MapMode(MapUnit::MapAppFont)));
58 pDrawingArea->set_size_request(aSize.Width(), aSize.Height());
59 CustomWidgetController::SetDrawingArea(pDrawingArea);
60 SetOutputSizePixel(aSize);
62 Construct();
65 Svx3DPreviewControl::~Svx3DPreviewControl()
67 mp3DView.reset();
68 mpModel.reset();
71 void Svx3DPreviewControl::Construct()
73 // Do never mirror the preview window. This explicitly includes right
74 // to left writing environments.
75 EnableRTL (false);
76 OutputDevice& rDevice = GetDrawingArea()->get_ref_device();
77 rDevice.SetMapMode(MapMode(MapUnit::Map100thMM));
79 // Model
80 mpModel.reset(new FmFormModel());
81 mpModel->GetItemPool().FreezeIdRanges();
83 // Page
84 mpFmPage = new FmFormPage( *mpModel );
85 mpModel->InsertPage( mpFmPage, 0 );
87 // 3D View
88 mp3DView.reset(new E3dView(*mpModel, &rDevice));
89 mp3DView->SetBufferedOutputAllowed(true);
90 mp3DView->SetBufferedOverlayAllowed(true);
92 // 3D Scene
93 mpScene = new E3dScene(*mpModel);
95 // initially create object
96 SetObjectType(SvxPreviewObjectType::SPHERE);
98 // camera and perspective
99 Camera3D rCamera = mpScene->GetCamera();
100 const basegfx::B3DRange& rVolume = mpScene->GetBoundVolume();
101 double fW = rVolume.getWidth();
102 double fH = rVolume.getHeight();
103 double fCamZ = rVolume.getMaxZ() + ((fW + fH) / 2.0);
105 rCamera.SetAutoAdjustProjection(false);
106 rCamera.SetViewWindow(- fW / 2, - fH / 2, fW, fH);
107 basegfx::B3DPoint aLookAt;
108 double fDefaultCamPosZ = mp3DView->GetDefaultCamPosZ();
109 basegfx::B3DPoint aCamPos(0.0, 0.0, fCamZ < fDefaultCamPosZ ? fDefaultCamPosZ : fCamZ);
110 rCamera.SetPosAndLookAt(aCamPos, aLookAt);
111 double fDefaultCamFocal = mp3DView->GetDefaultCamFocal();
112 rCamera.SetFocalLength(fDefaultCamFocal);
114 mpScene->SetCamera( rCamera );
115 mpFmPage->InsertObject( mpScene );
117 basegfx::B3DHomMatrix aRotation;
118 aRotation.rotate(DEG2RAD( 25 ), 0.0, 0.0);
119 aRotation.rotate(0.0, DEG2RAD( 40 ), 0.0);
120 mpScene->SetTransform(aRotation * mpScene->GetTransform());
122 // invalidate SnapRects of objects
123 mpScene->SetRectsDirty();
125 SfxItemSet aSet( mpModel->GetItemPool(),
126 svl::Items<XATTR_LINESTYLE, XATTR_LINESTYLE,
127 XATTR_FILL_FIRST, XATTR_FILLBITMAP>{} );
128 aSet.Put( XLineStyleItem( drawing::LineStyle_NONE ) );
129 aSet.Put( XFillStyleItem( drawing::FillStyle_SOLID ) );
130 aSet.Put( XFillColorItem( "", COL_WHITE ) );
132 mpScene->SetMergedItemSet(aSet);
134 // PageView
135 SdrPageView* pPageView = mp3DView->ShowSdrPage( mpFmPage );
136 mp3DView->hideMarkHandles();
138 // mark scene
139 mp3DView->MarkObj( mpScene, pPageView );
142 void Svx3DPreviewControl::Resize()
144 // size of page
145 Size aSize(GetOutputSizePixel());
146 aSize = GetDrawingArea()->get_ref_device().PixelToLogic(aSize);
147 mpFmPage->SetSize(aSize);
149 // set size
150 Size aObjSize( aSize.Width()*5/6, aSize.Height()*5/6 );
151 Point aObjPoint( (aSize.Width() - aObjSize.Width()) / 2,
152 (aSize.Height() - aObjSize.Height()) / 2);
153 tools::Rectangle aRect( aObjPoint, aObjSize);
154 mpScene->SetSnapRect( aRect );
157 void Svx3DPreviewControl::Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle& rRect)
159 mp3DView->CompleteRedraw(&rRenderContext, vcl::Region(rRect));
162 bool Svx3DPreviewControl::MouseButtonDown(const MouseEvent& rMEvt)
164 if (rMEvt.IsShift() && rMEvt.IsMod1())
166 if(SvxPreviewObjectType::SPHERE == GetObjectType())
168 SetObjectType(SvxPreviewObjectType::CUBE);
170 else
172 SetObjectType(SvxPreviewObjectType::SPHERE);
175 return false;
178 void Svx3DPreviewControl::SetObjectType(SvxPreviewObjectType nType)
180 if(mnObjectType == nType && mp3DObj)
181 return;
183 SfxItemSet aSet(mpModel->GetItemPool(), svl::Items<SDRATTR_START, SDRATTR_END>{});
184 mnObjectType = nType;
186 if( mp3DObj )
188 aSet.Put(mp3DObj->GetMergedItemSet());
189 mpScene->RemoveObject( mp3DObj->GetOrdNum() );
190 // always use SdrObject::Free(...) for SdrObjects (!)
191 SdrObject* pTemp(mp3DObj);
192 SdrObject::Free(pTemp);
195 switch( nType )
197 case SvxPreviewObjectType::SPHERE:
199 mp3DObj = new E3dSphereObj(
200 *mpModel,
201 mp3DView->Get3DDefaultAttributes(),
202 basegfx::B3DPoint( 0, 0, 0 ),
203 basegfx::B3DVector( 5000, 5000, 5000 ));
205 break;
207 case SvxPreviewObjectType::CUBE:
209 mp3DObj = new E3dCubeObj(
210 *mpModel,
211 mp3DView->Get3DDefaultAttributes(),
212 basegfx::B3DPoint( -2500, -2500, -2500 ),
213 basegfx::B3DVector( 5000, 5000, 5000 ));
215 break;
218 if (mp3DObj)
220 mpScene->InsertObject( mp3DObj );
221 mp3DObj->SetMergedItemSet(aSet);
224 Invalidate();
227 SfxItemSet const & Svx3DPreviewControl::Get3DAttributes() const
229 return mp3DObj->GetMergedItemSet();
232 void Svx3DPreviewControl::Set3DAttributes( const SfxItemSet& rAttr )
234 mp3DObj->SetMergedItemSet(rAttr, true);
235 Resize();
236 Invalidate();
239 #define RADIUS_LAMP_PREVIEW_SIZE (4500.0)
240 #define RADIUS_LAMP_SMALL (600.0)
241 #define RADIUS_LAMP_BIG (1000.0)
242 #define NO_LIGHT_SELECTED (0xffffffff)
243 #define MAX_NUMBER_LIGHTS (8)
245 const sal_Int32 g_nInteractionStartDistance = 5 * 5 * 2;
247 Svx3DLightControl::Svx3DLightControl()
248 : maChangeCallback(),
249 maSelectionChangeCallback(),
250 maSelectedLight(NO_LIGHT_SELECTED),
251 mpExpansionObject(nullptr),
252 mpLampBottomObject(nullptr),
253 mpLampShaftObject(nullptr),
254 maLightObjects(MAX_NUMBER_LIGHTS, nullptr),
255 mfRotateX(-20.0),
256 mfRotateY(45.0),
257 mfRotateZ(0.0),
258 maActionStartPoint(),
259 mfSaveActionStartHor(0.0),
260 mfSaveActionStartVer(0.0),
261 mfSaveActionStartRotZ(0.0),
262 mbMouseMoved(false),
263 mbMouseCaptured(false),
264 mbGeometrySelected(false)
268 void Svx3DLightControl::SetDrawingArea(weld::DrawingArea* pDrawingArea)
270 Svx3DPreviewControl::SetDrawingArea(pDrawingArea);
271 Construct2();
274 void Svx3DLightControl::Construct2()
277 // hide all page stuff, use control background (normally gray)
278 const Color aDialogColor(Application::GetSettings().GetStyleSettings().GetDialogColor());
279 mp3DView->SetPageVisible(false);
280 mp3DView->SetApplicationBackgroundColor(aDialogColor);
281 mp3DView->SetApplicationDocumentColor(aDialogColor);
285 // create invisible expansion object
286 const double fMaxExpansion(RADIUS_LAMP_BIG + RADIUS_LAMP_PREVIEW_SIZE);
287 mpExpansionObject = new E3dCubeObj(
288 *mpModel,
289 mp3DView->Get3DDefaultAttributes(),
290 basegfx::B3DPoint(-fMaxExpansion, -fMaxExpansion, -fMaxExpansion),
291 basegfx::B3DVector(2.0 * fMaxExpansion, 2.0 * fMaxExpansion, 2.0 * fMaxExpansion));
292 mpScene->InsertObject( mpExpansionObject );
293 SfxItemSet aSet(mpModel->GetItemPool());
294 aSet.Put( XLineStyleItem( drawing::LineStyle_NONE ) );
295 aSet.Put( XFillStyleItem( drawing::FillStyle_NONE ) );
296 mpExpansionObject->SetMergedItemSet(aSet);
300 // create lamp control object (Yellow lined object)
301 // base circle
302 const basegfx::B2DPolygon a2DCircle(basegfx::utils::createPolygonFromCircle(basegfx::B2DPoint(0.0, 0.0), RADIUS_LAMP_PREVIEW_SIZE));
303 basegfx::B3DPolygon a3DCircle(basegfx::utils::createB3DPolygonFromB2DPolygon(a2DCircle));
304 basegfx::B3DHomMatrix aTransform;
306 aTransform.rotate(F_PI2, 0.0, 0.0);
307 aTransform.translate(0.0, -RADIUS_LAMP_PREVIEW_SIZE, 0.0);
308 a3DCircle.transform(aTransform);
310 // create object for it
311 mpLampBottomObject = new E3dPolygonObj(
312 *mpModel,
313 basegfx::B3DPolyPolygon(a3DCircle));
314 mpScene->InsertObject( mpLampBottomObject );
316 // half circle with stand
317 basegfx::B2DPolygon a2DHalfCircle;
318 a2DHalfCircle.append(basegfx::B2DPoint(RADIUS_LAMP_PREVIEW_SIZE, 0.0));
319 a2DHalfCircle.append(basegfx::B2DPoint(RADIUS_LAMP_PREVIEW_SIZE, -RADIUS_LAMP_PREVIEW_SIZE));
320 a2DHalfCircle.append(basegfx::utils::createPolygonFromEllipseSegment(
321 basegfx::B2DPoint(0.0, 0.0), RADIUS_LAMP_PREVIEW_SIZE, RADIUS_LAMP_PREVIEW_SIZE, F_2PI - F_PI2, F_PI2));
322 basegfx::B3DPolygon a3DHalfCircle(basegfx::utils::createB3DPolygonFromB2DPolygon(a2DHalfCircle));
324 // create object for it
325 mpLampShaftObject = new E3dPolygonObj(
326 *mpModel,
327 basegfx::B3DPolyPolygon(a3DHalfCircle));
328 mpScene->InsertObject( mpLampShaftObject );
330 // initially invisible
331 SfxItemSet aSet(mpModel->GetItemPool());
332 aSet.Put( XLineStyleItem( drawing::LineStyle_NONE ) );
333 aSet.Put( XFillStyleItem( drawing::FillStyle_NONE ) );
335 mpLampBottomObject->SetMergedItemSet(aSet);
336 mpLampShaftObject->SetMergedItemSet(aSet);
340 // change camera settings
341 Camera3D rCamera = mpScene->GetCamera();
342 const basegfx::B3DRange& rVolume = mpScene->GetBoundVolume();
343 double fW = rVolume.getWidth();
344 double fH = rVolume.getHeight();
345 double fCamZ = rVolume.getMaxZ() + ((fW + fH) / 2.0);
347 rCamera.SetAutoAdjustProjection(false);
348 rCamera.SetViewWindow(- fW / 2, - fH / 2, fW, fH);
349 basegfx::B3DPoint aLookAt;
350 double fDefaultCamPosZ = mp3DView->GetDefaultCamPosZ();
351 basegfx::B3DPoint aCamPos(0.0, 0.0, fCamZ < fDefaultCamPosZ ? fDefaultCamPosZ : fCamZ);
352 rCamera.SetPosAndLookAt(aCamPos, aLookAt);
353 double fDefaultCamFocal = mp3DView->GetDefaultCamFocal();
354 rCamera.SetFocalLength(fDefaultCamFocal);
356 mpScene->SetCamera( rCamera );
358 basegfx::B3DHomMatrix aNeutral;
359 mpScene->SetTransform(aNeutral);
362 // invalidate SnapRects of objects
363 mpScene->SetRectsDirty();
366 void Svx3DLightControl::ConstructLightObjects()
368 for(sal_uInt32 a(0); a < MAX_NUMBER_LIGHTS; a++)
370 // get rid of possible existing light object
371 if(maLightObjects[a])
373 mpScene->RemoveObject(maLightObjects[a]->GetOrdNum());
374 // always use SdrObject::Free(...) for SdrObjects (!)
375 SdrObject* pTemp(maLightObjects[a]);
376 SdrObject::Free(pTemp);
377 maLightObjects[a] = nullptr;
380 if(GetLightOnOff(a))
382 const bool bIsSelectedLight(a == maSelectedLight);
383 basegfx::B3DVector aDirection(GetLightDirection(a));
384 aDirection.normalize();
385 aDirection *= RADIUS_LAMP_PREVIEW_SIZE;
387 const double fLampSize(bIsSelectedLight ? RADIUS_LAMP_BIG : RADIUS_LAMP_SMALL);
388 E3dObject* pNewLight = new E3dSphereObj(
389 *mpModel,
390 mp3DView->Get3DDefaultAttributes(),
391 basegfx::B3DPoint( 0, 0, 0 ),
392 basegfx::B3DVector( fLampSize, fLampSize, fLampSize));
393 mpScene->InsertObject(pNewLight);
395 basegfx::B3DHomMatrix aTransform;
396 aTransform.translate(aDirection.getX(), aDirection.getY(), aDirection.getZ());
397 pNewLight->SetTransform(aTransform);
399 SfxItemSet aSet(mpModel->GetItemPool());
400 aSet.Put( XLineStyleItem( drawing::LineStyle_NONE ) );
401 aSet.Put( XFillStyleItem( drawing::FillStyle_SOLID ) );
402 aSet.Put( XFillColorItem(OUString(), GetLightColor(a)));
403 pNewLight->SetMergedItemSet(aSet);
405 maLightObjects[a] = pNewLight;
410 void Svx3DLightControl::AdaptToSelectedLight()
412 if(NO_LIGHT_SELECTED == maSelectedLight)
414 // make mpLampBottomObject/mpLampShaftObject invisible
415 SfxItemSet aSet(mpModel->GetItemPool());
416 aSet.Put( XLineStyleItem( drawing::LineStyle_NONE ) );
417 aSet.Put( XFillStyleItem( drawing::FillStyle_NONE ) );
418 mpLampBottomObject->SetMergedItemSet(aSet);
419 mpLampShaftObject->SetMergedItemSet(aSet);
421 else
423 basegfx::B3DVector aDirection(GetLightDirection(maSelectedLight));
424 aDirection.normalize();
426 // make mpLampBottomObject/mpLampShaftObject visible (yellow hairline)
427 SfxItemSet aSet(mpModel->GetItemPool());
428 aSet.Put( XLineStyleItem( drawing::LineStyle_SOLID ) );
429 aSet.Put( XLineColorItem(OUString(), COL_YELLOW));
430 aSet.Put( XLineWidthItem(0));
431 aSet.Put( XFillStyleItem( drawing::FillStyle_NONE ) );
432 mpLampBottomObject->SetMergedItemSet(aSet);
433 mpLampShaftObject->SetMergedItemSet(aSet);
435 // adapt transformation of mpLampShaftObject
436 basegfx::B3DHomMatrix aTransform;
437 double fRotateY(0.0);
439 if(!basegfx::fTools::equalZero(aDirection.getZ()) || !basegfx::fTools::equalZero(aDirection.getX()))
441 fRotateY = atan2(-aDirection.getZ(), aDirection.getX());
444 aTransform.rotate(0.0, fRotateY, 0.0);
445 mpLampShaftObject->SetTransform(aTransform);
447 // adapt transformation of selected light
448 E3dObject* pSelectedLight = maLightObjects[sal_Int32(maSelectedLight)];
450 if(pSelectedLight)
452 aTransform.identity();
453 aTransform.translate(
454 aDirection.getX() * RADIUS_LAMP_PREVIEW_SIZE,
455 aDirection.getY() * RADIUS_LAMP_PREVIEW_SIZE,
456 aDirection.getZ() * RADIUS_LAMP_PREVIEW_SIZE);
457 pSelectedLight->SetTransform(aTransform);
462 void Svx3DLightControl::TrySelection(Point aPosPixel)
464 if(!mpScene)
465 return;
467 const Point aPosLogic(GetDrawingArea()->get_ref_device().PixelToLogic(aPosPixel));
468 const basegfx::B2DPoint aPoint(aPosLogic.X(), aPosLogic.Y());
469 std::vector< const E3dCompoundObject* > aResult;
470 getAllHit3DObjectsSortedFrontToBack(aPoint, *mpScene, aResult);
472 if(aResult.empty())
473 return;
475 // exclude expansion object which will be part of
476 // the hits. It's invisible, but for HitTest, it's included
477 const E3dCompoundObject* pResult = nullptr;
479 for(auto const & b: aResult)
481 if(b && b != mpExpansionObject)
483 pResult = b;
484 break;
488 if(pResult == mp3DObj)
490 if(!mbGeometrySelected)
492 mbGeometrySelected = true;
493 maSelectedLight = NO_LIGHT_SELECTED;
494 ConstructLightObjects();
495 AdaptToSelectedLight();
496 Invalidate();
498 if(maSelectionChangeCallback.IsSet())
500 maSelectionChangeCallback.Call(this);
504 else
506 sal_uInt32 aNewSelectedLight(NO_LIGHT_SELECTED);
508 for(sal_uInt32 a(0); a < MAX_NUMBER_LIGHTS; a++)
510 if(maLightObjects[a] && maLightObjects[a] == pResult)
512 aNewSelectedLight = a;
516 if(aNewSelectedLight != maSelectedLight)
518 SelectLight(aNewSelectedLight);
520 if(maSelectionChangeCallback.IsSet())
522 maSelectionChangeCallback.Call(this);
528 void Svx3DLightControl::Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle& rRect)
530 Svx3DPreviewControl::Paint(rRenderContext, rRect);
533 tools::Rectangle Svx3DLightControl::GetFocusRect()
535 if (!HasFocus())
536 return tools::Rectangle();
537 Size aFocusSize = GetOutputSizePixel();
538 aFocusSize.AdjustWidth( -4 );
539 aFocusSize.AdjustHeight( -4 );
540 return tools::Rectangle(Point(2, 2), aFocusSize);
543 bool Svx3DLightControl::MouseButtonDown( const MouseEvent& rMEvt )
545 bool bCallParent(true);
547 // switch state
548 if(rMEvt.IsLeft())
550 if(IsSelectionValid() || mbGeometrySelected)
552 mbMouseMoved = false;
553 bCallParent = false;
554 maActionStartPoint = rMEvt.GetPosPixel();
555 CaptureMouse();
556 mbMouseCaptured = true;
558 else
560 // Single click without moving much trying to do a selection
561 TrySelection(rMEvt.GetPosPixel());
562 bCallParent = false;
566 // call parent
567 if (bCallParent)
568 return Svx3DPreviewControl::MouseButtonDown(rMEvt);
569 return true;
572 bool Svx3DLightControl::MouseMove(const MouseEvent& rMEvt)
574 if (!mbMouseCaptured)
575 return false;
577 Point aDeltaPos = rMEvt.GetPosPixel() - maActionStartPoint;
579 if(!mbMouseMoved)
581 if(sal_Int32(aDeltaPos.X() * aDeltaPos.X() + aDeltaPos.Y() * aDeltaPos.Y()) > g_nInteractionStartDistance)
583 if(mbGeometrySelected)
585 GetRotation(mfSaveActionStartVer, mfSaveActionStartHor, mfSaveActionStartRotZ);
587 else
589 // interaction start, save values
590 GetPosition(mfSaveActionStartHor, mfSaveActionStartVer);
593 mbMouseMoved = true;
597 if(mbMouseMoved)
599 if(mbGeometrySelected)
601 double fNewRotX = mfSaveActionStartVer - basegfx::deg2rad(aDeltaPos.Y());
602 double fNewRotY = mfSaveActionStartHor + basegfx::deg2rad(aDeltaPos.X());
604 // cut horizontal
605 while(fNewRotY < 0.0)
607 fNewRotY += F_2PI;
610 while(fNewRotY >= F_2PI)
612 fNewRotY -= F_2PI;
615 // cut vertical
616 if(fNewRotX < -F_PI2)
618 fNewRotX = -F_PI2;
621 if(fNewRotX > F_PI2)
623 fNewRotX = F_PI2;
626 SetRotation(fNewRotX, fNewRotY, mfSaveActionStartRotZ);
628 if(maChangeCallback.IsSet())
630 maChangeCallback.Call(this);
633 else
635 // interaction in progress
636 double fNewPosHor = mfSaveActionStartHor + static_cast<double>(aDeltaPos.X());
637 double fNewPosVer = mfSaveActionStartVer - static_cast<double>(aDeltaPos.Y());
639 // cut horizontal
640 fNewPosHor = NormAngle360(fNewPosHor);
642 // cut vertical
643 if(fNewPosVer < -90.0)
645 fNewPosVer = -90.0;
648 if(fNewPosVer > 90.0)
650 fNewPosVer = 90.0;
653 SetPosition(fNewPosHor, fNewPosVer);
655 if(maChangeCallback.IsSet())
657 maChangeCallback.Call(this);
661 return true;
664 bool Svx3DLightControl::MouseButtonUp(const MouseEvent& rMEvt)
666 if (!mbMouseCaptured)
667 return false;
668 ReleaseMouse();
669 mbMouseCaptured = false;
671 if (mbMouseMoved)
673 // was change interactively
675 else
677 // simple click without much movement, try selection
678 TrySelection(rMEvt.GetPosPixel());
681 return true;
684 void Svx3DLightControl::Resize()
686 // set size of page
687 const Size aSize(GetDrawingArea()->get_ref_device().PixelToLogic(GetOutputSizePixel()));
688 mpFmPage->SetSize(aSize);
690 // set position and size of scene
691 mpScene->SetSnapRect(tools::Rectangle(Point(0, 0), aSize));
694 void Svx3DLightControl::SetObjectType(SvxPreviewObjectType nType)
696 // call parent
697 Svx3DPreviewControl::SetObjectType(nType);
699 // apply object rotation
700 if(mp3DObj)
702 basegfx::B3DHomMatrix aObjectRotation;
703 aObjectRotation.rotate(mfRotateX, mfRotateY, mfRotateZ);
704 mp3DObj->SetTransform(aObjectRotation);
708 bool Svx3DLightControl::IsSelectionValid()
710 return (NO_LIGHT_SELECTED != maSelectedLight) && GetLightOnOff(maSelectedLight);
713 void Svx3DLightControl::GetPosition(double& rHor, double& rVer)
715 if(IsSelectionValid())
717 basegfx::B3DVector aDirection(GetLightDirection(maSelectedLight));
718 aDirection.normalize();
719 rHor = basegfx::rad2deg(atan2(-aDirection.getX(), -aDirection.getZ()) + F_PI); // 0..360.0
720 rVer = basegfx::rad2deg(atan2(aDirection.getY(), aDirection.getXZLength())); // -90.0..90.0
722 if(IsGeometrySelected())
724 rHor = basegfx::rad2deg(mfRotateY); // 0..360.0
725 rVer = basegfx::rad2deg(mfRotateX); // -90.0..90.0
729 void Svx3DLightControl::SetPosition(double fHor, double fVer)
731 if(IsSelectionValid())
733 // set selected light's direction
734 fHor = basegfx::deg2rad(fHor) - F_PI; // -PI..PI
735 fVer = basegfx::deg2rad(fVer); // -PI2..PI2
736 basegfx::B3DVector aDirection(cos(fVer) * -sin(fHor), sin(fVer), cos(fVer) * -cos(fHor));
737 aDirection.normalize();
739 if(!aDirection.equal(GetLightDirection(maSelectedLight)))
741 // set changed light direction at SdrScene
742 SfxItemSet aSet(mpModel->GetItemPool());
744 switch(maSelectedLight)
746 case 0: aSet.Put(makeSvx3DLightDirection1Item(aDirection)); break;
747 case 1: aSet.Put(makeSvx3DLightDirection2Item(aDirection)); break;
748 case 2: aSet.Put(makeSvx3DLightDirection3Item(aDirection)); break;
749 case 3: aSet.Put(makeSvx3DLightDirection4Item(aDirection)); break;
750 case 4: aSet.Put(makeSvx3DLightDirection5Item(aDirection)); break;
751 case 5: aSet.Put(makeSvx3DLightDirection6Item(aDirection)); break;
752 case 6: aSet.Put(makeSvx3DLightDirection7Item(aDirection)); break;
753 default:
754 case 7: aSet.Put(makeSvx3DLightDirection8Item(aDirection)); break;
757 mpScene->SetMergedItemSet(aSet);
759 // correct 3D light's and LampFrame's geometries
760 AdaptToSelectedLight();
761 Invalidate();
764 if(!IsGeometrySelected())
765 return;
767 if(mfRotateX == fVer && mfRotateY == fHor)
768 return;
770 mfRotateX = basegfx::deg2rad(fVer);
771 mfRotateY = basegfx::deg2rad(fHor);
773 if(mp3DObj)
775 basegfx::B3DHomMatrix aObjectRotation;
776 aObjectRotation.rotate(mfRotateX, mfRotateY, mfRotateZ);
777 mp3DObj->SetTransform(aObjectRotation);
779 Invalidate();
783 void Svx3DLightControl::SetRotation(double fRotX, double fRotY, double fRotZ)
785 if(!IsGeometrySelected())
786 return;
788 if(fRotX == mfRotateX && fRotY == mfRotateY && fRotZ == mfRotateZ)
789 return;
791 mfRotateX = fRotX;
792 mfRotateY = fRotY;
793 mfRotateZ = fRotZ;
795 if(mp3DObj)
797 basegfx::B3DHomMatrix aObjectRotation;
798 aObjectRotation.rotate(mfRotateX, mfRotateY, mfRotateZ);
799 mp3DObj->SetTransform(aObjectRotation);
801 Invalidate();
805 void Svx3DLightControl::GetRotation(double& rRotX, double& rRotY, double& rRotZ)
807 rRotX = mfRotateX;
808 rRotY = mfRotateY;
809 rRotZ = mfRotateZ;
812 void Svx3DLightControl::Set3DAttributes( const SfxItemSet& rAttr )
814 // call parent
815 Svx3DPreviewControl::Set3DAttributes(rAttr);
817 if(maSelectedLight != NO_LIGHT_SELECTED && !GetLightOnOff(maSelectedLight))
819 // selected light is no more active, select new one
820 maSelectedLight = NO_LIGHT_SELECTED;
823 // local updates
824 ConstructLightObjects();
825 AdaptToSelectedLight();
826 Invalidate();
829 void Svx3DLightControl::SelectLight(sal_uInt32 nLightNumber)
831 if(nLightNumber > 7)
833 nLightNumber = NO_LIGHT_SELECTED;
836 if(NO_LIGHT_SELECTED != nLightNumber)
838 if(!GetLightOnOff(nLightNumber))
840 nLightNumber = NO_LIGHT_SELECTED;
844 if(nLightNumber != maSelectedLight)
846 maSelectedLight = nLightNumber;
847 mbGeometrySelected = false;
848 ConstructLightObjects();
849 AdaptToSelectedLight();
850 Invalidate();
854 bool Svx3DLightControl::GetLightOnOff(sal_uInt32 nNum) const
856 if(nNum <= 7)
858 const SfxItemSet aLightItemSet(Get3DAttributes());
860 switch(nNum)
862 case 0 : return aLightItemSet.Get(SDRATTR_3DSCENE_LIGHTON_1).GetValue();
863 case 1 : return aLightItemSet.Get(SDRATTR_3DSCENE_LIGHTON_2).GetValue();
864 case 2 : return aLightItemSet.Get(SDRATTR_3DSCENE_LIGHTON_3).GetValue();
865 case 3 : return aLightItemSet.Get(SDRATTR_3DSCENE_LIGHTON_4).GetValue();
866 case 4 : return aLightItemSet.Get(SDRATTR_3DSCENE_LIGHTON_5).GetValue();
867 case 5 : return aLightItemSet.Get(SDRATTR_3DSCENE_LIGHTON_6).GetValue();
868 case 6 : return aLightItemSet.Get(SDRATTR_3DSCENE_LIGHTON_7).GetValue();
869 case 7 : return aLightItemSet.Get(SDRATTR_3DSCENE_LIGHTON_8).GetValue();
873 return false;
876 Color Svx3DLightControl::GetLightColor(sal_uInt32 nNum) const
878 if(nNum <= 7)
880 const SfxItemSet aLightItemSet(Get3DAttributes());
882 switch(nNum)
884 case 0 : return aLightItemSet.Get(SDRATTR_3DSCENE_LIGHTCOLOR_1).GetValue();
885 case 1 : return aLightItemSet.Get(SDRATTR_3DSCENE_LIGHTCOLOR_2).GetValue();
886 case 2 : return aLightItemSet.Get(SDRATTR_3DSCENE_LIGHTCOLOR_3).GetValue();
887 case 3 : return aLightItemSet.Get(SDRATTR_3DSCENE_LIGHTCOLOR_4).GetValue();
888 case 4 : return aLightItemSet.Get(SDRATTR_3DSCENE_LIGHTCOLOR_5).GetValue();
889 case 5 : return aLightItemSet.Get(SDRATTR_3DSCENE_LIGHTCOLOR_6).GetValue();
890 case 6 : return aLightItemSet.Get(SDRATTR_3DSCENE_LIGHTCOLOR_7).GetValue();
891 case 7 : return aLightItemSet.Get(SDRATTR_3DSCENE_LIGHTCOLOR_8).GetValue();
895 return COL_BLACK;
898 basegfx::B3DVector Svx3DLightControl::GetLightDirection(sal_uInt32 nNum) const
900 if(nNum <= 7)
902 const SfxItemSet aLightItemSet(Get3DAttributes());
904 switch(nNum)
906 case 0 : return aLightItemSet.Get(SDRATTR_3DSCENE_LIGHTDIRECTION_1).GetValue();
907 case 1 : return aLightItemSet.Get(SDRATTR_3DSCENE_LIGHTDIRECTION_2).GetValue();
908 case 2 : return aLightItemSet.Get(SDRATTR_3DSCENE_LIGHTDIRECTION_3).GetValue();
909 case 3 : return aLightItemSet.Get(SDRATTR_3DSCENE_LIGHTDIRECTION_4).GetValue();
910 case 4 : return aLightItemSet.Get(SDRATTR_3DSCENE_LIGHTDIRECTION_5).GetValue();
911 case 5 : return aLightItemSet.Get(SDRATTR_3DSCENE_LIGHTDIRECTION_6).GetValue();
912 case 6 : return aLightItemSet.Get(SDRATTR_3DSCENE_LIGHTDIRECTION_7).GetValue();
913 case 7 : return aLightItemSet.Get(SDRATTR_3DSCENE_LIGHTDIRECTION_8).GetValue();
917 return basegfx::B3DVector();
920 SvxLightCtl3D::SvxLightCtl3D(Svx3DLightControl& rLightControl, weld::Scale& rHori,
921 weld::Scale& rVert, weld::Button& rSwitcher)
922 : mrLightControl(rLightControl)
923 , mrHorScroller(rHori)
924 , mrVerScroller(rVert)
925 , mrSwitcher(rSwitcher)
927 // init members
928 Init();
931 void SvxLightCtl3D::Init()
933 Size aSize(mrLightControl.GetDrawingArea()->get_ref_device().LogicToPixel(Size(80, 100), MapMode(MapUnit::MapAppFont)));
934 mrLightControl.set_size_request(aSize.Width(), aSize.Height());
936 // #i58240# set HelpIDs for scrollbars and switcher
937 mrHorScroller.set_help_id(HID_CTRL3D_HSCROLL);
938 mrVerScroller.set_help_id(HID_CTRL3D_VSCROLL);
939 mrSwitcher.set_help_id(HID_CTRL3D_SWITCHER);
940 mrSwitcher.set_accessible_name(SvxResId(STR_SWITCH));
942 // Light preview
943 mrLightControl.Show();
944 mrLightControl.SetChangeCallback( LINK(this, SvxLightCtl3D, InternalInteractiveChange) );
945 mrLightControl.SetSelectionChangeCallback( LINK(this, SvxLightCtl3D, InternalSelectionChange) );
947 // Horiz Scrollbar
948 mrHorScroller.show();
949 mrHorScroller.set_range(0, 36000);
950 mrHorScroller.connect_value_changed( LINK(this, SvxLightCtl3D, ScrollBarMove) );
952 // Vert Scrollbar
953 mrVerScroller.show();
954 mrVerScroller.set_range(0, 18000);
955 mrVerScroller.connect_value_changed( LINK(this, SvxLightCtl3D, ScrollBarMove) );
957 // Switch Button
958 mrSwitcher.show();
959 mrSwitcher.connect_clicked( LINK(this, SvxLightCtl3D, ButtonPress) );
961 weld::DrawingArea* pArea = mrLightControl.GetDrawingArea();
962 pArea->connect_key_press(Link<const KeyEvent&, bool>()); //acknowledge we first remove the old one
963 pArea->connect_key_press(LINK(this, SvxLightCtl3D, KeyInput));
965 pArea->connect_focus_in(Link<weld::Widget&, void>()); //acknowledge we first remove the old one
966 pArea->connect_focus_in(LINK(this, SvxLightCtl3D, FocusIn));
968 // check selection
969 CheckSelection();
972 SvxLightCtl3D::~SvxLightCtl3D()
976 void SvxLightCtl3D::CheckSelection()
978 const bool bSelectionValid(mrLightControl.IsSelectionValid() || mrLightControl.IsGeometrySelected());
979 mrHorScroller.set_sensitive(bSelectionValid);
980 mrVerScroller.set_sensitive(bSelectionValid);
982 if (bSelectionValid)
984 double fHor(0.0), fVer(0.0);
985 mrLightControl.GetPosition(fHor, fVer);
986 mrHorScroller.set_value( sal_Int32(fHor * 100.0) );
987 mrVerScroller.set_value( 18000 - sal_Int32((fVer + 90.0) * 100.0) );
991 void SvxLightCtl3D::move( double fDeltaHor, double fDeltaVer )
993 double fHor(0.0), fVer(0.0);
995 mrLightControl.GetPosition(fHor, fVer);
996 fHor += fDeltaHor;
997 fVer += fDeltaVer;
999 if( fVer > 90.0 )
1000 return;
1002 if ( fVer < -90.0 )
1003 return;
1005 mrLightControl.SetPosition(fHor, fVer);
1006 mrHorScroller.set_value( sal_Int32(fHor * 100.0) );
1007 mrVerScroller.set_value( 18000 - sal_Int32((fVer + 90.0) * 100.0) );
1009 if(maUserInteractiveChangeCallback.IsSet())
1011 maUserInteractiveChangeCallback.Call(this);
1015 IMPL_LINK(SvxLightCtl3D, KeyInput, const KeyEvent&, rKEvt, bool)
1017 const vcl::KeyCode aCode(rKEvt.GetKeyCode());
1019 if (aCode.GetModifier())
1020 return false;
1022 bool bHandled = true;
1024 switch ( aCode.GetCode() )
1026 case KEY_SPACE:
1028 break;
1030 case KEY_LEFT:
1032 move( -4.0, 0.0 ); // #i58242# changed move direction in X
1033 break;
1035 case KEY_RIGHT:
1037 move( 4.0, 0.0 ); // #i58242# changed move direction in X
1038 break;
1040 case KEY_UP:
1042 move( 0.0, 4.0 );
1043 break;
1045 case KEY_DOWN:
1047 move( 0.0, -4.0 );
1048 break;
1050 case KEY_PAGEUP:
1052 sal_Int32 nLight(mrLightControl.GetSelectedLight() - 1);
1054 while((nLight >= 0) && !mrLightControl.GetLightOnOff(nLight))
1056 nLight--;
1059 if(nLight < 0)
1061 nLight = 7;
1063 while((nLight >= 0) && !mrLightControl.GetLightOnOff(nLight))
1065 nLight--;
1069 if(nLight >= 0)
1071 mrLightControl.SelectLight(nLight);
1072 CheckSelection();
1074 if(maUserSelectionChangeCallback.IsSet())
1076 maUserSelectionChangeCallback.Call(this);
1080 break;
1082 case KEY_PAGEDOWN:
1084 sal_Int32 nLight(mrLightControl.GetSelectedLight() - 1);
1086 while(nLight <= 7 && !mrLightControl.GetLightOnOff(nLight))
1088 nLight++;
1091 if(nLight > 7)
1093 nLight = 0;
1095 while(nLight <= 7 && !mrLightControl.GetLightOnOff(nLight))
1097 nLight++;
1101 if(nLight <= 7)
1103 mrLightControl.SelectLight(nLight);
1104 CheckSelection();
1106 if(maUserSelectionChangeCallback.IsSet())
1108 maUserSelectionChangeCallback.Call(this);
1112 break;
1114 default:
1116 bHandled = false;
1117 break;
1120 return bHandled;
1123 IMPL_LINK_NOARG(SvxLightCtl3D, FocusIn, weld::Widget&, void)
1125 if (mrLightControl.IsEnabled())
1127 CheckSelection();
1131 IMPL_LINK_NOARG(SvxLightCtl3D, ScrollBarMove, weld::Scale&, void)
1133 const sal_Int32 nHor(mrHorScroller.get_value());
1134 const sal_Int32 nVer(mrVerScroller.get_value());
1136 mrLightControl.SetPosition(
1137 static_cast<double>(nHor) / 100.0,
1138 static_cast<double>((18000 - nVer) - 9000) / 100.0);
1140 if (maUserInteractiveChangeCallback.IsSet())
1142 maUserInteractiveChangeCallback.Call(this);
1146 IMPL_LINK_NOARG(SvxLightCtl3D, ButtonPress, weld::Button&, void)
1148 if(SvxPreviewObjectType::SPHERE == GetSvx3DLightControl().GetObjectType())
1150 GetSvx3DLightControl().SetObjectType(SvxPreviewObjectType::CUBE);
1152 else
1154 GetSvx3DLightControl().SetObjectType(SvxPreviewObjectType::SPHERE);
1158 IMPL_LINK_NOARG(SvxLightCtl3D, InternalInteractiveChange, Svx3DLightControl*, void)
1160 double fHor(0.0), fVer(0.0);
1162 mrLightControl.GetPosition(fHor, fVer);
1163 mrHorScroller.set_value( sal_Int32(fHor * 100.0) );
1164 mrVerScroller.set_value( 18000 - sal_Int32((fVer + 90.0) * 100.0) );
1166 if(maUserInteractiveChangeCallback.IsSet())
1168 maUserInteractiveChangeCallback.Call(this);
1172 IMPL_LINK_NOARG(SvxLightCtl3D, InternalSelectionChange, Svx3DLightControl*, void)
1174 CheckSelection();
1176 if(maUserSelectionChangeCallback.IsSet())
1178 maUserSelectionChangeCallback.Call(this);
1182 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */