/src/libreoffice/sc/source/ui/drawfunc/fudraw.cxx
Line | Count | Source |
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 <editeng/editeng.hxx> |
21 | | #include <editeng/outlobj.hxx> |
22 | | #include <svx/svdobj.hxx> |
23 | | #include <svx/svdoole2.hxx> |
24 | | #include <svx/svdouno.hxx> |
25 | | #include <svx/ImageMapInfo.hxx> |
26 | | #include <sfx2/dispatch.hxx> |
27 | | #include <sfx2/viewfrm.hxx> |
28 | | #include <vcl/uitest/logger.hxx> |
29 | | #include <vcl/uitest/eventdescription.hxx> |
30 | | |
31 | | #include <sc.hrc> |
32 | | #include <fudraw.hxx> |
33 | | #include <futext.hxx> |
34 | | #include <tabvwsh.hxx> |
35 | | #include <drwlayer.hxx> |
36 | | #include <userdat.hxx> |
37 | | #include <docsh.hxx> |
38 | | #include <drawview.hxx> |
39 | | #include <comphelper/lok.hxx> |
40 | | #include <com/sun/star/embed/EmbedVerbs.hpp> |
41 | | |
42 | | namespace |
43 | | { |
44 | | |
45 | | void collectUIInformation( const OUString& aevent ) |
46 | 0 | { |
47 | 0 | EventDescription aDescription; |
48 | 0 | aDescription.aID = "grid_window"; |
49 | 0 | aDescription.aParameters = {{ aevent , ""}}; |
50 | 0 | aDescription.aAction = "COMMENT"; |
51 | 0 | aDescription.aParent = "MainWindow"; |
52 | 0 | aDescription.aKeyWord = "ScGridWinUIObject"; |
53 | 0 | UITestLogger::getInstance().logEvent(aDescription); |
54 | 0 | } |
55 | | |
56 | | } |
57 | | |
58 | | // base class for draw module specific functions |
59 | | FuDraw::FuDraw(ScTabViewShell& rViewSh, vcl::Window* pWin, ScDrawView* pViewP, |
60 | | SdrModel& rDoc, const SfxRequest& rReq) |
61 | 0 | : FuPoor(rViewSh, pWin, pViewP, rDoc, rReq) |
62 | 0 | , aNewPointer(PointerStyle::Arrow) |
63 | 0 | , aOldPointer(PointerStyle::Arrow) |
64 | 0 | { |
65 | 0 | } |
66 | | |
67 | | FuDraw::~FuDraw() |
68 | 0 | { |
69 | 0 | } |
70 | | |
71 | | void FuDraw::DoModifiers(const MouseEvent& rMEvt) |
72 | 0 | { |
73 | | // Shift = Ortho and AngleSnap |
74 | | // Control = Snap (Toggle) |
75 | | // Alt = centric |
76 | |
|
77 | 0 | bool bShift = rMEvt.IsShift(); |
78 | 0 | bool bAlt = rMEvt.IsMod2(); |
79 | |
|
80 | 0 | bool bOrtho = bShift; |
81 | 0 | bool bAngleSnap = bShift; |
82 | 0 | bool bCenter = bAlt; |
83 | | |
84 | | // #i33136# |
85 | 0 | if(doConstructOrthogonal()) |
86 | 0 | { |
87 | 0 | bOrtho = !bShift; |
88 | 0 | } |
89 | |
|
90 | 0 | if (pView->IsOrtho() != bOrtho) |
91 | 0 | pView->SetOrtho(bOrtho); |
92 | 0 | if (pView->IsAngleSnapEnabled() != bAngleSnap) |
93 | 0 | pView->SetAngleSnapEnabled(bAngleSnap); |
94 | |
|
95 | 0 | if (pView->IsCreate1stPointAsCenter() != bCenter) |
96 | 0 | pView->SetCreate1stPointAsCenter(bCenter); |
97 | 0 | if (pView->IsResizeAtCenter() != bCenter) |
98 | 0 | pView->SetResizeAtCenter(bCenter); |
99 | |
|
100 | 0 | } |
101 | | |
102 | | void FuDraw::ResetModifiers() |
103 | 0 | { |
104 | 0 | if (!pView) |
105 | 0 | return; |
106 | | |
107 | 0 | ScViewData& rViewData = rViewShell.GetViewData(); |
108 | 0 | const ScViewOptions& rOpt = rViewData.GetOptions(); |
109 | 0 | const ScGridOptions& rGrid = rOpt.GetGridOptions(); |
110 | 0 | bool bGridOpt = rGrid.GetUseGridSnap(); |
111 | |
|
112 | 0 | if (pView->IsOrtho()) |
113 | 0 | pView->SetOrtho(false); |
114 | 0 | if (pView->IsAngleSnapEnabled()) |
115 | 0 | pView->SetAngleSnapEnabled(false); |
116 | |
|
117 | 0 | if (pView->IsGridSnap() != bGridOpt) |
118 | 0 | pView->SetGridSnap(bGridOpt); |
119 | 0 | if (pView->IsSnapEnabled() != bGridOpt) |
120 | 0 | pView->SetSnapEnabled(bGridOpt); |
121 | |
|
122 | 0 | if (pView->IsCreate1stPointAsCenter()) |
123 | 0 | pView->SetCreate1stPointAsCenter(false); |
124 | 0 | if (pView->IsResizeAtCenter()) |
125 | 0 | pView->SetResizeAtCenter(false); |
126 | 0 | } |
127 | | |
128 | | bool FuDraw::MouseButtonDown(const MouseEvent& rMEvt) |
129 | 0 | { |
130 | | // remember button state for creation of own MouseEvents |
131 | 0 | SetMouseButtonCode(rMEvt.GetButtons()); |
132 | |
|
133 | 0 | DoModifiers( rMEvt ); |
134 | 0 | return false; |
135 | 0 | } |
136 | | |
137 | | bool FuDraw::MouseMove(const MouseEvent& rMEvt) |
138 | 0 | { |
139 | 0 | if (SfxViewShell* pSfxViewShell = pView->GetSfxViewShell()) |
140 | 0 | { |
141 | 0 | pSfxViewShell->GetDrawView()->MouseMove(rMEvt, pWindow->GetOutDev()); |
142 | | // evaluate modifiers only if in a drawing layer action |
143 | | // (don't interfere with keyboard shortcut handling) |
144 | 0 | if (pView->IsAction()) |
145 | 0 | DoModifiers( rMEvt ); |
146 | 0 | } |
147 | |
|
148 | 0 | return false; |
149 | 0 | } |
150 | | |
151 | | bool FuDraw::MouseButtonUp(const MouseEvent& rMEvt) |
152 | 0 | { |
153 | | // remember button state for creation of own MouseEvents |
154 | 0 | SetMouseButtonCode(rMEvt.GetButtons()); |
155 | |
|
156 | 0 | ResetModifiers(); |
157 | 0 | return false; |
158 | 0 | } |
159 | | |
160 | | // Process Keyboard events. Return true if an event is being handled |
161 | | static bool lcl_KeyEditMode( SdrObject* pObj, ScTabViewShell& rViewShell, const KeyEvent* pInitialKey ) |
162 | 0 | { |
163 | 0 | bool bReturn = false; |
164 | 0 | if ( DynCastSdrTextObj( pObj) != nullptr && dynamic_cast<const SdrUnoObj*>( pObj) == nullptr ) |
165 | 0 | { |
166 | 0 | assert(pObj); |
167 | | // start text edit - like FuSelection::MouseButtonUp, |
168 | | // but with bCursorToEnd instead of mouse position |
169 | |
|
170 | 0 | OutlinerParaObject* pOPO = pObj->GetOutlinerParaObject(); |
171 | 0 | bool bVertical = ( pOPO && pOPO->IsEffectivelyVertical() ); |
172 | 0 | sal_uInt16 nTextSlotId = bVertical ? SID_DRAW_TEXT_VERTICAL : SID_DRAW_TEXT; |
173 | | |
174 | | // don't switch shells if text shell is already active |
175 | 0 | FuPoor* pPoor = rViewShell.GetViewData().GetView()->GetDrawFuncPtr(); |
176 | 0 | if ( !pPoor || pPoor->GetSlotID() != nTextSlotId ) |
177 | 0 | { |
178 | 0 | rViewShell.GetViewData().GetDispatcher(). |
179 | 0 | Execute(nTextSlotId, SfxCallMode::SYNCHRON | SfxCallMode::RECORD); |
180 | 0 | } |
181 | | |
182 | | // get the resulting FuText and set in edit mode |
183 | 0 | pPoor = rViewShell.GetViewData().GetView()->GetDrawFuncPtr(); |
184 | 0 | if ( pPoor && pPoor->GetSlotID() == nTextSlotId ) // no RTTI |
185 | 0 | { |
186 | 0 | FuText* pText = static_cast<FuText*>(pPoor); |
187 | 0 | pText->SetInEditMode( pObj, nullptr, true, pInitialKey ); |
188 | | //! set cursor to end of text |
189 | 0 | } |
190 | 0 | bReturn = true; |
191 | 0 | } |
192 | 0 | return bReturn; |
193 | 0 | } |
194 | | |
195 | | bool FuDraw::KeyInput(const KeyEvent& rKEvt) |
196 | 0 | { |
197 | 0 | bool bReturn = false; |
198 | 0 | ScViewData& rViewData = rViewShell.GetViewData(); |
199 | |
|
200 | 0 | const SdrMarkList& rMarkList = pView->GetMarkedObjectList(); |
201 | 0 | switch ( rKEvt.GetKeyCode().GetCode() ) |
202 | 0 | { |
203 | 0 | case KEY_ESCAPE: |
204 | 0 | if ( rViewShell.IsDrawTextShell() || aSfxRequest.GetSlot() == SID_DRAW_NOTEEDIT ) |
205 | 0 | { |
206 | 0 | collectUIInformation(u"CLOSE"_ustr); |
207 | | // if object selected -> normal draw-shell, else turn off drawing |
208 | 0 | rViewData.GetDispatcher().Execute(aSfxRequest.GetSlot(), SfxCallMode::SLOT | SfxCallMode::RECORD); |
209 | 0 | bReturn = true; |
210 | 0 | } |
211 | 0 | else if ( rViewShell.IsDrawSelMode() ) |
212 | 0 | { |
213 | 0 | pView->UnmarkAll(); |
214 | 0 | rViewData.GetDispatcher().Execute(SID_OBJECT_SELECT, SfxCallMode::SLOT | SfxCallMode::RECORD); |
215 | 0 | bReturn = true; |
216 | 0 | } |
217 | 0 | else if ( rMarkList.GetMarkCount() != 0 ) |
218 | 0 | { |
219 | | // III |
220 | 0 | SdrHdlList& rHdlList = const_cast< SdrHdlList& >( pView->GetHdlList() ); |
221 | 0 | if( rHdlList.GetFocusHdl() ) |
222 | 0 | rHdlList.ResetFocusHdl(); |
223 | 0 | else |
224 | 0 | pView->UnmarkAll(); |
225 | | |
226 | | // while bezier editing, object is selected |
227 | 0 | if (rMarkList.GetMarkCount() == 0) |
228 | 0 | rViewShell.SetDrawShell( false ); |
229 | |
|
230 | 0 | bReturn = true; |
231 | 0 | } |
232 | 0 | break; |
233 | | |
234 | 0 | case KEY_DELETE: //! via accelerator |
235 | 0 | pView->DeleteMarked(); |
236 | 0 | bReturn = true; |
237 | 0 | break; |
238 | | |
239 | 0 | case KEY_RETURN: |
240 | 0 | { |
241 | 0 | if( rKEvt.GetKeyCode().GetModifier() == 0 ) |
242 | 0 | { |
243 | | // activate OLE object on RETURN for selected object |
244 | | // put selected text object in edit mode |
245 | 0 | if( !pView->IsTextEdit() && 1 == rMarkList.GetMarkCount() ) |
246 | 0 | { |
247 | 0 | bool bOle = rViewShell.GetViewFrame().GetFrame().IsInPlace(); |
248 | 0 | SdrObject* pObj = rMarkList.GetMark( 0 )->GetMarkedSdrObj(); |
249 | 0 | auto pOleObj = dynamic_cast<SdrOle2Obj*>(pObj); |
250 | 0 | if( pOleObj && !bOle ) |
251 | 0 | { |
252 | 0 | rViewShell.ActivateObject(pOleObj, css::embed::EmbedVerbs::MS_OLEVERB_PRIMARY); |
253 | | |
254 | | // consumed |
255 | 0 | bReturn = true; |
256 | 0 | } |
257 | 0 | else if ( lcl_KeyEditMode( pObj, rViewShell, nullptr ) ) // start text edit for suitable object |
258 | 0 | bReturn = true; |
259 | 0 | } |
260 | 0 | } |
261 | 0 | } |
262 | 0 | break; |
263 | | |
264 | 0 | case KEY_F2: |
265 | 0 | { |
266 | 0 | if( rKEvt.GetKeyCode().GetModifier() == 0 ) |
267 | 0 | { |
268 | | // put selected text object in edit mode |
269 | | // (this is not SID_SETINPUTMODE, but F2 hardcoded, like in Writer) |
270 | 0 | if( !pView->IsTextEdit() && 1 == rMarkList.GetMarkCount() ) |
271 | 0 | { |
272 | 0 | SdrObject* pObj = rMarkList.GetMark( 0 )->GetMarkedSdrObj(); |
273 | 0 | bool isMobilePhone = comphelper::LibreOfficeKit::isActive() && rViewShell.isLOKMobilePhone(); |
274 | | // Double tapping on charts on phone may result in activating the edit mode which is not wanted. |
275 | | // It happens due to the delay of selection message of the object from kit to javascript |
276 | | // in that case F2 is sent instead of double click |
277 | 0 | if (isMobilePhone && ScDocument::IsChart(pObj)) |
278 | 0 | { |
279 | 0 | rViewShell.ActivateObject(static_cast<SdrOle2Obj*>(pObj), css::embed::EmbedVerbs::MS_OLEVERB_PRIMARY); |
280 | 0 | break; |
281 | 0 | } |
282 | 0 | if ( lcl_KeyEditMode( pObj, rViewShell, nullptr ) ) // start text edit for suitable object |
283 | 0 | bReturn = true; |
284 | 0 | } |
285 | 0 | } |
286 | 0 | } |
287 | 0 | break; |
288 | | |
289 | 0 | case KEY_TAB: |
290 | 0 | { |
291 | | // in calc do NOT start draw object selection using TAB/SHIFT-TAB when |
292 | | // there is not yet an object selected |
293 | 0 | if(rMarkList.GetMarkCount() != 0) |
294 | 0 | { |
295 | 0 | vcl::KeyCode aCode = rKEvt.GetKeyCode(); |
296 | |
|
297 | 0 | if ( !aCode.IsMod1() && !aCode.IsMod2() ) |
298 | 0 | { |
299 | | // changeover to the next object |
300 | 0 | if(!pView->MarkNextObj( !aCode.IsShift() )) |
301 | 0 | { |
302 | | //If there is only one object, don't do the UnmarkAllObj() & MarkNextObj(). |
303 | 0 | if ( pView->HasMultipleMarkableObjects() && pView->HasMarkableObj() ) |
304 | 0 | { |
305 | | // No next object: go over open end and |
306 | | // get first from the other side |
307 | 0 | pView->UnmarkAllObj(); |
308 | 0 | pView->MarkNextObj(!aCode.IsShift()); |
309 | 0 | } |
310 | 0 | } |
311 | | |
312 | | // II |
313 | 0 | if(rMarkList.GetMarkCount() != 0) |
314 | 0 | pView->MakeVisible(pView->GetAllMarkedRect(), *pWindow); |
315 | |
|
316 | 0 | bReturn = true; |
317 | 0 | } |
318 | | |
319 | | // handle Mod1 and Mod2 to get travelling running on different systems |
320 | 0 | if(rKEvt.GetKeyCode().IsMod1() || rKEvt.GetKeyCode().IsMod2()) |
321 | 0 | { |
322 | | // II do something with a selected handle? |
323 | 0 | const SdrHdlList& rHdlList = pView->GetHdlList(); |
324 | 0 | bool bForward(!rKEvt.GetKeyCode().IsShift()); |
325 | |
|
326 | 0 | const_cast<SdrHdlList&>(rHdlList).TravelFocusHdl(bForward); |
327 | | |
328 | | // guarantee visibility of focused handle |
329 | 0 | SdrHdl* pHdl = rHdlList.GetFocusHdl(); |
330 | |
|
331 | 0 | if(pHdl) |
332 | 0 | { |
333 | 0 | Point aHdlPosition(pHdl->GetPos()); |
334 | 0 | tools::Rectangle aVisRect(aHdlPosition - Point(100, 100), Size(200, 200)); |
335 | 0 | pView->MakeVisible(aVisRect, *pWindow); |
336 | 0 | } |
337 | | |
338 | | // consumed |
339 | 0 | bReturn = true; |
340 | 0 | } |
341 | 0 | } |
342 | 0 | } |
343 | 0 | break; |
344 | | |
345 | 0 | case KEY_END: |
346 | 0 | { |
347 | | // in calc do NOT select the last draw object when |
348 | | // there is not yet an object selected |
349 | 0 | if(rMarkList.GetMarkCount() != 0) |
350 | 0 | { |
351 | 0 | vcl::KeyCode aCode = rKEvt.GetKeyCode(); |
352 | |
|
353 | 0 | if ( aCode.IsMod1() ) |
354 | 0 | { |
355 | | // mark last object |
356 | 0 | pView->UnmarkAllObj(); |
357 | 0 | pView->MarkNextObj(); |
358 | | |
359 | | // II |
360 | 0 | if(rMarkList.GetMarkCount() != 0) |
361 | 0 | pView->MakeVisible(pView->GetAllMarkedRect(), *pWindow); |
362 | |
|
363 | 0 | bReturn = true; |
364 | 0 | } |
365 | 0 | } |
366 | 0 | } |
367 | 0 | break; |
368 | | |
369 | 0 | case KEY_HOME: |
370 | 0 | { |
371 | | // in calc do NOT select the first draw object when |
372 | | // there is not yet an object selected |
373 | 0 | if(rMarkList.GetMarkCount() != 0) |
374 | 0 | { |
375 | 0 | vcl::KeyCode aCode = rKEvt.GetKeyCode(); |
376 | |
|
377 | 0 | if ( aCode.IsMod1() ) |
378 | 0 | { |
379 | | // mark first object |
380 | 0 | pView->UnmarkAllObj(); |
381 | 0 | pView->MarkNextObj(true); |
382 | | |
383 | | // II |
384 | 0 | if(rMarkList.GetMarkCount() != 0) |
385 | 0 | pView->MakeVisible(pView->GetAllMarkedRect(), *pWindow); |
386 | |
|
387 | 0 | bReturn = true; |
388 | 0 | } |
389 | 0 | } |
390 | 0 | } |
391 | 0 | break; |
392 | | |
393 | 0 | case KEY_UP: |
394 | 0 | case KEY_DOWN: |
395 | 0 | case KEY_LEFT: |
396 | 0 | case KEY_RIGHT: |
397 | 0 | { |
398 | | // in calc do cursor travelling of draw objects only when |
399 | | // there is an object selected yet |
400 | 0 | if(rMarkList.GetMarkCount() != 0) |
401 | 0 | { |
402 | |
|
403 | 0 | if(rMarkList.GetMarkCount() == 1) |
404 | 0 | { |
405 | | // disable cursor travelling on note objects as the tail connector position |
406 | | // must not move. |
407 | 0 | SdrObject* pObj = rMarkList.GetMark( 0 )->GetMarkedSdrObj(); |
408 | 0 | if( ScDrawLayer::IsNoteCaption( pObj ) ) |
409 | 0 | break; |
410 | 0 | } |
411 | | |
412 | 0 | tools::Long nX = 0; |
413 | 0 | tools::Long nY = 0; |
414 | 0 | sal_uInt16 nCode = rKEvt.GetKeyCode().GetCode(); |
415 | |
|
416 | 0 | if (nCode == KEY_UP) |
417 | 0 | { |
418 | | // scroll up |
419 | 0 | nX = 0; |
420 | 0 | nY =-1; |
421 | 0 | } |
422 | 0 | else if (nCode == KEY_DOWN) |
423 | 0 | { |
424 | | // scroll down |
425 | 0 | nX = 0; |
426 | 0 | nY = 1; |
427 | 0 | } |
428 | 0 | else if (nCode == KEY_LEFT) |
429 | 0 | { |
430 | | // scroll left |
431 | 0 | nX =-1; |
432 | 0 | nY = 0; |
433 | 0 | } |
434 | 0 | else if (nCode == KEY_RIGHT) |
435 | 0 | { |
436 | | // scroll right |
437 | 0 | nX = 1; |
438 | 0 | nY = 0; |
439 | 0 | } |
440 | |
|
441 | 0 | bool bReadOnly = rViewData.GetDocShell().IsReadOnly(); |
442 | |
|
443 | 0 | if(!rKEvt.GetKeyCode().IsMod1() && !bReadOnly) |
444 | 0 | { |
445 | 0 | if(rKEvt.GetKeyCode().IsMod2()) |
446 | 0 | { |
447 | | // move in 1 pixel distance |
448 | 0 | Size aLogicSizeOnePixel = pWindow ? pWindow->PixelToLogic(Size(1,1)) : Size(100, 100); |
449 | 0 | nX *= aLogicSizeOnePixel.Width(); |
450 | 0 | nY *= aLogicSizeOnePixel.Height(); |
451 | 0 | } |
452 | 0 | else if(rKEvt.GetKeyCode().IsShift()) // #i121236# Support for shift key in calc |
453 | 0 | { |
454 | 0 | nX *= 1000; |
455 | 0 | nY *= 1000; |
456 | 0 | } |
457 | 0 | else |
458 | 0 | { |
459 | | // old, fixed move distance |
460 | 0 | nX *= 100; |
461 | 0 | nY *= 100; |
462 | 0 | } |
463 | | |
464 | | // is there a movement to do? |
465 | 0 | if(0 != nX || 0 != nY) |
466 | 0 | { |
467 | | // II |
468 | 0 | const SdrHdlList& rHdlList = pView->GetHdlList(); |
469 | 0 | SdrHdl* pHdl = rHdlList.GetFocusHdl(); |
470 | |
|
471 | 0 | if(nullptr == pHdl) |
472 | 0 | { |
473 | | // only take action when move is allowed |
474 | 0 | if(pView->IsMoveAllowed()) |
475 | 0 | { |
476 | | // restrict movement to WorkArea |
477 | 0 | const tools::Rectangle& rWorkArea = pView->GetWorkArea(); |
478 | |
|
479 | 0 | if(!rWorkArea.IsEmpty()) |
480 | 0 | { |
481 | 0 | tools::Rectangle aMarkRect(pView->GetMarkedObjRect()); |
482 | 0 | aMarkRect.Move(nX, nY); |
483 | |
|
484 | 0 | if(!aMarkRect.Contains(rWorkArea)) |
485 | 0 | { |
486 | 0 | if(aMarkRect.Left() < rWorkArea.Left()) |
487 | 0 | { |
488 | 0 | nX += rWorkArea.Left() - aMarkRect.Left(); |
489 | 0 | } |
490 | |
|
491 | 0 | if(aMarkRect.Right() > rWorkArea.Right()) |
492 | 0 | { |
493 | 0 | nX -= aMarkRect.Right() - rWorkArea.Right(); |
494 | 0 | } |
495 | |
|
496 | 0 | if(aMarkRect.Top() < rWorkArea.Top()) |
497 | 0 | { |
498 | 0 | nY += rWorkArea.Top() - aMarkRect.Top(); |
499 | 0 | } |
500 | |
|
501 | 0 | if(aMarkRect.Bottom() > rWorkArea.Bottom()) |
502 | 0 | { |
503 | 0 | nY -= aMarkRect.Bottom() - rWorkArea.Bottom(); |
504 | 0 | } |
505 | 0 | } |
506 | 0 | } |
507 | | |
508 | | // now move the selected draw objects |
509 | 0 | pView->MoveAllMarked(Size(nX, nY)); |
510 | | |
511 | | // II |
512 | 0 | pView->MakeVisible(pView->GetAllMarkedRect(), *pWindow); |
513 | |
|
514 | 0 | bReturn = true; |
515 | 0 | } |
516 | 0 | } |
517 | 0 | else |
518 | 0 | { |
519 | | // move handle with index nHandleIndex |
520 | 0 | if (nX || nY) |
521 | 0 | { |
522 | | // now move the Handle (nX, nY) |
523 | 0 | Point aStartPoint(pHdl->GetPos()); |
524 | 0 | Point aEndPoint(pHdl->GetPos() + Point(nX, nY)); |
525 | 0 | const SdrDragStat& rDragStat = pView->GetDragStat(); |
526 | | |
527 | | // start dragging |
528 | 0 | pView->BegDragObj(aStartPoint, nullptr, pHdl, 0); |
529 | |
|
530 | 0 | if(pView->IsDragObj()) |
531 | 0 | { |
532 | 0 | bool bWasNoSnap = rDragStat.IsNoSnap(); |
533 | 0 | bool bWasSnapEnabled = pView->IsSnapEnabled(); |
534 | | |
535 | | // switch snapping off |
536 | 0 | if(!bWasNoSnap) |
537 | 0 | const_cast<SdrDragStat&>(rDragStat).SetNoSnap(); |
538 | 0 | if(bWasSnapEnabled) |
539 | 0 | pView->SetSnapEnabled(false); |
540 | |
|
541 | 0 | pView->MovAction(aEndPoint); |
542 | 0 | pView->EndDragObj(); |
543 | | |
544 | | // restore snap |
545 | 0 | if(!bWasNoSnap) |
546 | 0 | const_cast<SdrDragStat&>(rDragStat).SetNoSnap(bWasNoSnap); |
547 | 0 | if(bWasSnapEnabled) |
548 | 0 | pView->SetSnapEnabled(bWasSnapEnabled); |
549 | 0 | } |
550 | | |
551 | | // make moved handle visible |
552 | 0 | tools::Rectangle aVisRect(aEndPoint - Point(100, 100), Size(200, 200)); |
553 | 0 | pView->MakeVisible(aVisRect, *pWindow); |
554 | |
|
555 | 0 | bReturn = true; |
556 | 0 | } |
557 | 0 | } |
558 | 0 | } |
559 | 0 | } |
560 | 0 | } |
561 | 0 | } |
562 | 0 | break; |
563 | | |
564 | 0 | case KEY_SPACE: |
565 | 0 | { |
566 | | // in calc do only something when draw objects are selected |
567 | 0 | if(rMarkList.GetMarkCount() != 0) |
568 | 0 | { |
569 | 0 | const SdrHdlList& rHdlList = pView->GetHdlList(); |
570 | 0 | SdrHdl* pHdl = rHdlList.GetFocusHdl(); |
571 | |
|
572 | 0 | if(pHdl) |
573 | 0 | { |
574 | 0 | if(pHdl->GetKind() == SdrHdlKind::Poly) |
575 | 0 | { |
576 | | // rescue ID of point with focus |
577 | 0 | sal_uInt32 nPol(pHdl->GetPolyNum()); |
578 | 0 | sal_uInt32 nPnt(pHdl->GetPointNum()); |
579 | |
|
580 | 0 | if(pView->IsPointMarked(*pHdl)) |
581 | 0 | { |
582 | 0 | if(rKEvt.GetKeyCode().IsShift()) |
583 | 0 | { |
584 | 0 | pView->UnmarkPoint(*pHdl); |
585 | 0 | } |
586 | 0 | } |
587 | 0 | else |
588 | 0 | { |
589 | 0 | if(!rKEvt.GetKeyCode().IsShift()) |
590 | 0 | { |
591 | 0 | pView->UnmarkAllPoints(); |
592 | 0 | } |
593 | |
|
594 | 0 | pView->MarkPoint(*pHdl); |
595 | 0 | } |
596 | |
|
597 | 0 | if(nullptr == rHdlList.GetFocusHdl()) |
598 | 0 | { |
599 | | // restore point with focus |
600 | 0 | SdrHdl* pNewOne = nullptr; |
601 | |
|
602 | 0 | for(size_t a = 0; !pNewOne && a < rHdlList.GetHdlCount(); ++a) |
603 | 0 | { |
604 | 0 | SdrHdl* pAct = rHdlList.GetHdl(a); |
605 | |
|
606 | 0 | if(pAct |
607 | 0 | && pAct->GetKind() == SdrHdlKind::Poly |
608 | 0 | && pAct->GetPolyNum() == nPol |
609 | 0 | && pAct->GetPointNum() == nPnt) |
610 | 0 | { |
611 | 0 | pNewOne = pAct; |
612 | 0 | } |
613 | 0 | } |
614 | |
|
615 | 0 | if(pNewOne) |
616 | 0 | { |
617 | 0 | const_cast<SdrHdlList&>(rHdlList).SetFocusHdl(pNewOne); |
618 | 0 | } |
619 | 0 | } |
620 | |
|
621 | 0 | bReturn = true; |
622 | 0 | } |
623 | 0 | } |
624 | 0 | } |
625 | 0 | } |
626 | 0 | break; |
627 | 0 | } |
628 | | |
629 | 0 | if (!bReturn) |
630 | 0 | { |
631 | 0 | bReturn = FuPoor::KeyInput(rKEvt); |
632 | 0 | } |
633 | |
|
634 | 0 | if (!bReturn) |
635 | 0 | { |
636 | | // allow direct typing into a selected text object |
637 | |
|
638 | 0 | if( !pView->IsTextEdit() && 1 == rMarkList.GetMarkCount() && EditEngine::IsSimpleCharInput(rKEvt) ) |
639 | 0 | { |
640 | 0 | SdrObject* pObj = rMarkList.GetMark( 0 )->GetMarkedSdrObj(); |
641 | | |
642 | | // start text edit for suitable object, pass key event to OutlinerView |
643 | 0 | if ( lcl_KeyEditMode( pObj, rViewShell, &rKEvt ) ) |
644 | 0 | bReturn = true; |
645 | 0 | } |
646 | 0 | } |
647 | |
|
648 | 0 | return bReturn; |
649 | 0 | } |
650 | | |
651 | | // toggle mouse-pointer |
652 | | static bool lcl_UrlHit( const SdrView* pView, const Point& rPosPixel, const vcl::Window* pWindow ) |
653 | 0 | { |
654 | 0 | SdrViewEvent aVEvt; |
655 | 0 | MouseEvent aMEvt( rPosPixel, 1, MouseEventModifiers::NONE, MOUSE_LEFT ); |
656 | 0 | SdrHitKind eHit = pView->PickAnything( aMEvt, SdrMouseEventKind::BUTTONDOWN, aVEvt ); |
657 | |
|
658 | 0 | if (eHit != SdrHitKind::NONE && aVEvt.mpObj != nullptr) |
659 | 0 | { |
660 | 0 | if ( SvxIMapInfo::GetIMapInfo(aVEvt.mpObj) && SvxIMapInfo::GetHitIMapObject( |
661 | 0 | aVEvt.mpObj, pWindow->PixelToLogic(rPosPixel), pWindow->GetOutDev() ) ) |
662 | 0 | return true; |
663 | | |
664 | 0 | if (aVEvt.meEvent == SdrEventKind::ExecuteUrl) |
665 | 0 | return true; |
666 | 0 | } |
667 | | |
668 | 0 | return false; |
669 | 0 | } |
670 | | |
671 | | void FuDraw::ForcePointer(const MouseEvent* pMEvt) |
672 | 0 | { |
673 | 0 | if ( pView->IsAction() ) |
674 | 0 | return; |
675 | | |
676 | 0 | Point aPosPixel = pWindow->GetPointerPosPixel(); |
677 | 0 | bool bAlt = pMEvt && pMEvt->IsMod2(); |
678 | 0 | Point aPnt = pWindow->PixelToLogic( aPosPixel ); |
679 | 0 | SdrHdl* pHdl = pView->PickHandle(aPnt); |
680 | 0 | SdrPageView* pPV; |
681 | 0 | SdrObject* pMacroPickObj; |
682 | |
|
683 | 0 | ScMacroInfo* pInfo = nullptr; |
684 | 0 | SdrObject* pObj = pView->PickObj(aPnt, pView->getHitTolLog(), pPV, SdrSearchOptions::ALSOONMASTER); |
685 | 0 | if (pObj) |
686 | 0 | { |
687 | 0 | if ( pObj->IsGroupObject() ) |
688 | 0 | { |
689 | 0 | SdrObject* pHit = pView->PickObj(aMDPos, pView->getHitTolLog(), pPV, SdrSearchOptions::DEEP); |
690 | 0 | if (pHit) |
691 | 0 | pObj = pHit; |
692 | 0 | } |
693 | 0 | pInfo = ScDrawLayer::GetMacroInfo( pObj ); |
694 | 0 | } |
695 | |
|
696 | 0 | if ( pView->IsTextEdit() ) |
697 | 0 | { |
698 | 0 | rViewShell.SetActivePointer(PointerStyle::Text); // can't be ? |
699 | 0 | } |
700 | 0 | else if ( pHdl ) |
701 | 0 | { |
702 | 0 | rViewShell.SetActivePointer( |
703 | 0 | pView->GetPreferredPointer( aPnt, pWindow->GetOutDev() ) ); |
704 | 0 | } |
705 | 0 | else if ( pView->IsMarkedHit(aPnt) ) |
706 | 0 | { |
707 | 0 | rViewShell.SetActivePointer( PointerStyle::Move ); |
708 | 0 | } |
709 | 0 | else if ( !bAlt && ( !pMEvt || !pMEvt->GetButtons() ) |
710 | 0 | && lcl_UrlHit( pView, aPosPixel, pWindow ) ) |
711 | 0 | { |
712 | | // could be suppressed with ALT |
713 | 0 | pWindow->SetPointer( PointerStyle::RefHand ); // Text-URL / ImageMap |
714 | 0 | } |
715 | 0 | else if ( !bAlt && (pMacroPickObj = pView->PickObj(aPnt, pView->getHitTolLog(), pPV, SdrSearchOptions::PICKMACRO)) ) |
716 | 0 | { |
717 | | // could be suppressed with ALT |
718 | 0 | SdrObjMacroHitRec aHitRec; //! something missing ???? |
719 | 0 | rViewShell.SetActivePointer(pMacroPickObj->GetMacroPointer(aHitRec)); |
720 | 0 | } |
721 | 0 | else if ( !bAlt && pInfo && (!pInfo->GetMacro().isEmpty() || !pObj->getHyperlink().isEmpty()) ) |
722 | 0 | pWindow->SetPointer( PointerStyle::RefHand ); |
723 | 0 | else if ( IsDetectiveHit( aPnt ) ) |
724 | 0 | rViewShell.SetActivePointer( PointerStyle::Detective ); |
725 | 0 | else |
726 | 0 | { |
727 | 0 | const bool bIsThemed = rViewShell.GetViewData().IsThemedCursor(); |
728 | 0 | rViewShell.SetActivePointer( bIsThemed ? PointerStyle::FatCross : PointerStyle::Arrow ); //! in Gridwin? |
729 | 0 | } |
730 | 0 | } |
731 | | |
732 | | bool FuDraw::IsEditingANote() const |
733 | 0 | { |
734 | 0 | const SdrMarkList& rMarkList = pView->GetMarkedObjectList(); |
735 | 0 | const size_t backval=rMarkList.GetMarkCount(); |
736 | 0 | for (size_t nlv1=0; nlv1<backval; ++nlv1) |
737 | 0 | { |
738 | 0 | SdrObject* pObj = rMarkList.GetMark( nlv1 )->GetMarkedSdrObj(); |
739 | 0 | if ( ScDrawLayer::IsNoteCaption( pObj ) ) |
740 | 0 | { |
741 | 0 | return true; |
742 | 0 | } |
743 | 0 | } |
744 | 0 | return false; |
745 | 0 | } |
746 | | |
747 | | bool FuDraw::IsSizingOrMovingNote( const MouseEvent& rMEvt ) const |
748 | 0 | { |
749 | 0 | bool bIsSizingOrMoving = false; |
750 | 0 | if ( rMEvt.IsLeft() ) |
751 | 0 | { |
752 | 0 | const SdrMarkList& rMarkList = pView->GetMarkedObjectList(); |
753 | 0 | if(rMarkList.GetMarkCount() == 1) |
754 | 0 | { |
755 | 0 | SdrObject* pObj = rMarkList.GetMark( 0 )->GetMarkedSdrObj(); |
756 | 0 | if ( ScDrawLayer::IsNoteCaption( pObj ) ) |
757 | 0 | { |
758 | 0 | Point aMPos = pWindow->PixelToLogic( rMEvt.GetPosPixel() ); |
759 | 0 | bIsSizingOrMoving = |
760 | 0 | pView->PickHandle( aMPos ) || // handles to resize the note |
761 | 0 | pView->IsTextEditFrameHit( aMPos ); // frame for moving the note |
762 | 0 | } |
763 | 0 | } |
764 | 0 | } |
765 | 0 | return bIsSizingOrMoving; |
766 | 0 | } |
767 | | |
768 | | /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |