1 // Copyright (C) 2002-2012 Nikolaus Gebhardt / Gaz Davidson
2 // This file is part of the "Irrlicht Engine".
3 // For conditions of distribution and use, see copyright notice in irrlicht.h
4
5 // Thanks to Midnight for all his testing, bug fixes and patches :)
6
7 #include "CGUIEditWorkspace.h"
8 #include "IGUIEnvironment.h"
9 #include "IVideoDriver.h"
10 #include "IOSOperator.h"
11 #include "IReadFile.h"
12 #include "IFileSystem.h"
13 #include "IXMLWriter.h"
14 #include "IGUISkin.h"
15 #include "IGUIElementFactory.h"
16 #include "CGUIEditWindow.h"
17 #include "IGUIContextMenu.h"
18 #include "IGUIFileOpenDialog.h"
19 #include "IGUITreeView.h"
20 #include "CGUIAttribute.h"
21 #include "CMemoryReadWriteFile.h"
22
23 namespace irr
24 {
25 namespace gui
26 {
27
28 //! constructor
CGUIEditWorkspace(IGUIEnvironment * environment,s32 id,IGUIElement * parent)29 CGUIEditWorkspace::CGUIEditWorkspace(IGUIEnvironment* environment, s32 id, IGUIElement *parent)
30 : IGUIElement(EGUIET_ELEMENT, environment, parent ? parent : environment->getRootGUIElement(), id, environment->getRootGUIElement()->getAbsolutePosition()),
31 CurrentMode(EGUIEDM_SELECT), MouseOverMode(EGUIEDM_SELECT),
32 GridSize(10,10), MenuCommandStart(0x3D17), DrawGrid(false), UseGrid(true),
33 MouseOverElement(0), SelectedElement(0), EditorWindow(0)
34 {
35 #ifdef _DEBUG
36 setDebugName("CGUIEditWorkspace");
37 #endif
38
39 // this element is never saved.
40 setSubElement(true);
41
42 // it resizes to fit a resizing window
43 setAlignment(EGUIA_UPPERLEFT, EGUIA_LOWERRIGHT, EGUIA_UPPERLEFT, EGUIA_LOWERRIGHT);
44
45 EditorWindow = (CGUIEditWindow*) Environment->addGUIElement("GUIEditWindow", this);
46 if (EditorWindow)
47 {
48 EditorWindow->grab();
49 EditorWindow->setSubElement(true);
50
51 Environment->setFocus(EditorWindow);
52 serializeAttributes(EditorWindow->getOptionEditor()->getAttribs());
53 EditorWindow->getOptionEditor()->refreshAttribs();
54
55 if (EditorWindow->getEnvironmentEditor())
56 {
57 Environment->serializeAttributes(EditorWindow->getEnvironmentEditor()->getAttribs());
58 EditorWindow->getEnvironmentEditor()->refreshAttribs();
59 }
60 }
61 }
62
63
64 //! destructor
~CGUIEditWorkspace()65 CGUIEditWorkspace::~CGUIEditWorkspace()
66 {
67 if (EditorWindow)
68 EditorWindow->drop();
69 }
70
71
setMenuCommandIDStart(s32 id)72 void CGUIEditWorkspace::setMenuCommandIDStart(s32 id)
73 {
74 MenuCommandStart = id;
75 }
76
getModeFromPos(core::position2di p)77 CGUIEditWorkspace::EGUIEDIT_MODE CGUIEditWorkspace::getModeFromPos(core::position2di p)
78 {
79 if (SelectedElement)
80 {
81 core::rect<s32> r = SelectedElement->getAbsolutePosition();
82
83 if (TLRect.isPointInside(p))
84 return EGUIEDM_RESIZE_TL;
85
86 else if (TRRect.isPointInside(p))
87 return EGUIEDM_RESIZE_TR;
88
89 else if (BLRect.isPointInside(p) )
90 return EGUIEDM_RESIZE_BL;
91
92 else if (BRRect.isPointInside(p))
93 return EGUIEDM_RESIZE_BR;
94
95 else if (TopRect.isPointInside(p))
96 return EGUIEDM_RESIZE_T;
97
98 else if (BRect.isPointInside(p))
99 return EGUIEDM_RESIZE_B;
100
101 else if (LRect.isPointInside(p))
102 return EGUIEDM_RESIZE_L;
103
104 else if (RRect.isPointInside(p))
105 return EGUIEDM_RESIZE_R;
106
107 else if (getEditableElementFromPoint(SelectedElement, p) == SelectedElement)
108 return EGUIEDM_MOVE;
109
110 else
111 return EGUIEDM_SELECT;
112 }
113
114 return EGUIEDM_SELECT;
115
116 }
117
getEditableElementFromPoint(IGUIElement * start,const core::position2di & point,s32 index)118 IGUIElement* CGUIEditWorkspace::getEditableElementFromPoint(IGUIElement *start, const core::position2di &point, s32 index )
119 {
120 IGUIElement* target = 0;
121
122 // we have to search from back to front.
123
124 core::list<IGUIElement*>::ConstIterator it = start->getChildren().getLast();
125 s32 count=0;
126 while(it != start->getChildren().end())
127 {
128 target = getEditableElementFromPoint((*it),point);
129 if (target)
130 {
131 if (!target->isSubElement() && !isMyChild(target) && target != this)
132 {
133 if (index == count)
134 return target;
135 else
136 count++;
137 }
138 else
139 target = 0;
140 }
141 --it;
142 }
143
144 if (start->getAbsolutePosition().isPointInside(point))
145 target = start;
146
147 return target;
148 }
149
setSelectedElement(IGUIElement * sel)150 void CGUIEditWorkspace::setSelectedElement(IGUIElement *sel)
151 {
152 IGUIElement* focus = Environment->getFocus();
153 // we only give focus back to children
154 if (!isMyChild(focus))
155 focus = 0;
156
157 if (SelectedElement != Parent)
158 {
159 if (SelectedElement != sel && EditorWindow)
160 {
161 EditorWindow->setSelectedElement(sel);
162 SelectedElement = sel;
163 }
164 }
165 else
166 SelectedElement = 0;
167
168 if (focus)
169 Environment->setFocus(focus);
170 else
171 Environment->setFocus(this);
172 }
173
getSelectedElement()174 IGUIElement* CGUIEditWorkspace::getSelectedElement()
175 {
176 return SelectedElement;
177 }
selectNextSibling()178 void CGUIEditWorkspace::selectNextSibling()
179 {
180 IGUIElement* p=0;
181
182 if (SelectedElement && SelectedElement->getParent())
183 p = SelectedElement->getParent();
184 else
185 p = Parent;
186
187 core::list<IGUIElement*>::ConstIterator it = p->getChildren().begin();
188 // find selected element
189 if (SelectedElement)
190 while (*it != SelectedElement)
191 ++it;
192 if (it !=p->getChildren().end())
193 ++it;
194 // find next non sub-element
195 while (it != p->getChildren().end() && (*it)->isSubElement())
196 ++it;
197
198 if (it != p->getChildren().end())
199 setSelectedElement(*it);
200 }
selectPreviousSibling()201 void CGUIEditWorkspace::selectPreviousSibling()
202 {
203 IGUIElement* p=0;
204
205 if (SelectedElement && SelectedElement->getParent())
206 p = SelectedElement->getParent();
207 else
208 p = Parent;
209
210 core::list<IGUIElement*>::ConstIterator it = p->getChildren().getLast();
211 // find selected element
212 if (SelectedElement)
213 while (*it != SelectedElement)
214 --it;
215 if (it != p->getChildren().end())
216 --it;
217 // find next non sub-element
218 while (it != p->getChildren().end() && (*it)->isSubElement())
219 --it;
220
221 if (it != p->getChildren().end())
222 setSelectedElement(*it);
223 }
224
225 //! called if an event happened.
OnEvent(const SEvent & e)226 bool CGUIEditWorkspace::OnEvent(const SEvent &e)
227 {
228 IGUIFileOpenDialog* dialog=0;
229 switch(e.EventType)
230 {
231 case ATTRIBEDIT_ATTRIB_CHANGED:
232 {
233 switch (e.UserEvent.UserData1)
234 {
235 case EGUIEDCE_ATTRIB_EDITOR:
236 {
237 // update selected items attributes
238 if (SelectedElement)
239 {
240 SelectedElement->deserializeAttributes(EditorWindow->getAttributeEditor()->getAttribs());
241 EditorWindow->updateTree();
242 }
243 return true;
244 }
245 case EGUIEDCE_OPTION_EDITOR:
246 {
247 // update editor options
248 deserializeAttributes(EditorWindow->getOptionEditor()->getAttribs());
249 return true;
250 }
251 case EGUIEDCE_ENV_EDITOR:
252 {
253 // update environment
254 Environment->deserializeAttributes(EditorWindow->getEnvironmentEditor()->getAttribs());
255 return true;
256 }
257 }
258 }
259 break;
260
261 case EET_KEY_INPUT_EVENT:
262 if (!e.KeyInput.PressedDown)
263 {
264 switch (e.KeyInput.Key)
265 {
266 case KEY_DELETE:
267 if (SelectedElement)
268 {
269 IGUIElement* el = SelectedElement;
270 setSelectedElement(0);
271 MouseOverElement = 0;
272 el->remove();
273 EditorWindow->updateTree();
274 }
275 break;
276 case KEY_KEY_X:
277 if (e.KeyInput.Control && SelectedElement)
278 {
279 // cut
280 CopySelectedElementXML();
281 // delete element
282 IGUIElement *el = SelectedElement;
283 setSelectedElement(0);
284 MouseOverElement = 0;
285 el->remove();
286 }
287 break;
288 case KEY_KEY_C:
289 // copy
290 if (e.KeyInput.Control && SelectedElement)
291 {
292 CopySelectedElementXML();
293 }
294 break;
295 case KEY_KEY_V:
296 // paste
297 if (e.KeyInput.Control)
298 {
299 PasteXMLToSelectedElement();
300 }
301 break;
302 default:
303 break;
304 }
305
306 return true;
307 }
308 break;
309
310 case EET_MOUSE_INPUT_EVENT:
311
312 switch(e.MouseInput.Event)
313 {
314 case EMIE_MOUSE_WHEEL:
315 {
316 f32 wheel = e.MouseInput.Wheel;
317
318 if (wheel > 0)
319 selectPreviousSibling();
320 else
321 selectNextSibling();
322 }
323 break;
324 case EMIE_LMOUSE_PRESSED_DOWN:
325 {
326 core::position2di p = core::position2di(e.MouseInput.X,e.MouseInput.Y);
327
328 IGUIElement* newSelection = getElementFromPoint(p);
329
330 if (newSelection != this && isMyChild(newSelection) ) // redirect event
331 {
332 Environment->setFocus(newSelection);
333 return true;
334 }
335
336 // hide the gui editor
337 if (EditorWindow)
338 EditorWindow->setVisible(false);
339
340 if (CurrentMode == EGUIEDM_SELECT)
341 {
342 if (SelectedElement)
343 {
344 // start moving or dragging
345 CurrentMode = getModeFromPos(p);
346
347 if (CurrentMode == EGUIEDM_MOVE)
348 StartMovePos = SelectedElement->getAbsolutePosition().UpperLeftCorner;
349
350 DragStart = p;
351 SelectedArea = SelectedElement->getAbsolutePosition();
352 }
353
354 if (CurrentMode < EGUIEDM_MOVE)
355 {
356 // selecting an element...
357 MouseOverElement = getEditableElementFromPoint(Parent, p);
358
359 if (MouseOverElement == Parent)
360 MouseOverElement = 0;
361
362 setSelectedElement(MouseOverElement);
363 }
364 }
365
366 break;
367 }
368 case EMIE_RMOUSE_PRESSED_DOWN:
369 if (CurrentMode == EGUIEDM_SELECT_NEW_PARENT || CurrentMode >= EGUIEDM_MOVE)
370 {
371 // cancel dragging
372 CurrentMode = EGUIEDM_SELECT;
373 }
374 else
375 {
376 DragStart = core::position2di(e.MouseInput.X,e.MouseInput.Y);
377 // root menu
378 IGUIContextMenu* mnu = Environment->addContextMenu(
379 core::rect<s32>(e.MouseInput.X, e.MouseInput.Y, e.MouseInput.Y+100, e.MouseInput.Y+100),this);
380 mnu->addItem(L"File",-1,true,true);
381 mnu->addItem(L"Edit",-1,true,true);
382 mnu->addItem(L"View",-1,true,true);
383 mnu->addItem(SelectedElement ? L"Add child" : L"Add" ,-1,true,true);
384
385 // file menu
386 IGUIContextMenu* sub = mnu->getSubMenu(0);
387 IGUIContextMenu* sub2 =0;
388
389 sub->addItem(L"New", MenuCommandStart + EGUIEDMC_FILE_NEW );
390 sub->addItem(L"Load...",MenuCommandStart + EGUIEDMC_FILE_LOAD);
391 sub->addItem(L"Save...",MenuCommandStart + EGUIEDMC_FILE_SAVE);
392
393 // edit menu
394 sub = mnu->getSubMenu(1);
395 sub->addItem(L"Cut (ctrl+x)", MenuCommandStart + EGUIEDMC_CUT_ELEMENT, (SelectedElement != 0));
396 sub->addItem(L"Copy (ctrl+c)", MenuCommandStart + EGUIEDMC_COPY_ELEMENT, (SelectedElement != 0));
397 sub->addItem(L"Paste (ctrl+v)", MenuCommandStart + EGUIEDMC_PASTE_ELEMENT,
398 (core::stringc(Environment->getOSOperator()->getTextFromClipboard()) != ""));
399 sub->addItem(L"Delete (del)", MenuCommandStart + EGUIEDMC_DELETE_ELEMENT, (SelectedElement != 0));
400 sub->addSeparator();
401 sub->addItem(L"Set parent", MenuCommandStart + EGUIEDMC_SET_PARENT, (SelectedElement != 0));
402 sub->addItem(L"Bring to front", MenuCommandStart + EGUIEDMC_BRING_TO_FRONT, (SelectedElement != 0));
403 sub->addSeparator();
404 sub->addItem(L"Save to XML...", MenuCommandStart + EGUIEDMC_SAVE_ELEMENT, (SelectedElement != 0));
405
406 sub = mnu->getSubMenu(2);
407 // view menu
408 if (EditorWindow)
409 sub->addItem(EditorWindow->isVisible() ? L"Hide window" : L"Show window", MenuCommandStart + EGUIEDMC_TOGGLE_EDITOR);
410
411 sub = mnu->getSubMenu(3);
412
413 s32 i,j,c=0;
414 sub->addItem(L"Default factory",-1,true, true);
415
416 // add elements from each factory
417 for (i=0; u32(i) < Environment->getRegisteredGUIElementFactoryCount(); ++i)
418 {
419 sub2 = sub->getSubMenu(i);
420
421 IGUIElementFactory *f = Environment->getGUIElementFactory(i);
422
423 for (j=0; j< f->getCreatableGUIElementTypeCount(); ++j)
424 {
425 sub2->addItem(core::stringw(f->getCreateableGUIElementTypeName(j)).c_str(), MenuCommandStart + EGUIEDMC_COUNT + c);
426 c++;
427 }
428
429 if (u32(i+1) < Environment->getRegisteredGUIElementFactoryCount())
430 {
431 core::stringw strFact;
432 strFact = L"Factory ";
433 strFact += i+1;
434 sub->addItem(strFact.c_str(),-1, true, true);
435 }
436 }
437 sub->addSeparator();
438 sub->addItem(L"From XML...", MenuCommandStart + EGUIEDMC_INSERT_XML);
439
440 // set focus to menu
441 Environment->setFocus(mnu);
442
443 }
444 break;
445 case EMIE_LMOUSE_LEFT_UP:
446
447 // make window visible again
448 if (EditorWindow)
449 EditorWindow->setVisible(true);
450 if (CurrentMode == EGUIEDM_SELECT_NEW_PARENT)
451 {
452 if (SelectedElement)
453 {
454 MouseOverElement = getEditableElementFromPoint(Parent,
455 core::position2di(e.MouseInput.X,e.MouseInput.Y));
456 if (MouseOverElement)
457 {
458 MouseOverElement->addChild(SelectedElement);
459 setSelectedElement(0);
460 setSelectedElement(SelectedElement);
461 }
462 }
463 CurrentMode = EGUIEDM_SELECT;
464 }
465 else if (CurrentMode >= EGUIEDM_MOVE)
466 {
467 IGUIElement *sel = SelectedElement;
468 // unselect
469 setSelectedElement(0);
470
471 // move
472 core::position2d<s32> p(0,0);
473 if (sel->getParent())
474 p = sel->getParent()->getAbsolutePosition().UpperLeftCorner;
475
476 sel->setRelativePosition(SelectedArea - p);
477
478 // select
479 setSelectedElement(sel);
480
481 // reset selection mode...
482 CurrentMode = EGUIEDM_SELECT;
483 }
484 break;
485 case EMIE_MOUSE_MOVED:
486 // always on top
487 Parent->bringToFront(this);
488
489 // if selecting
490 if (CurrentMode == EGUIEDM_SELECT || CurrentMode == EGUIEDM_SELECT_NEW_PARENT)
491 {
492
493 core::position2di p = core::position2di(e.MouseInput.X,e.MouseInput.Y);
494
495 // highlight the element that the mouse is over
496 MouseOverElement = getEditableElementFromPoint(Parent, p);
497 if (MouseOverElement == Parent)
498 {
499 MouseOverElement = 0;
500 }
501
502 if (CurrentMode == EGUIEDM_SELECT)
503 {
504 MouseOverMode = getModeFromPos(p);
505 if (MouseOverMode > EGUIEDM_MOVE)
506 {
507 MouseOverElement = SelectedElement;
508 }
509 }
510 }
511 else if (CurrentMode == EGUIEDM_MOVE)
512 {
513 // get difference
514 core::position2di p = core::position2di(e.MouseInput.X,e.MouseInput.Y);
515 p -= DragStart;
516
517 // apply to top corner
518 p = StartMovePos + p;
519 if (UseGrid)
520 {
521 p.X = (p.X/GridSize.Width)*GridSize.Width;
522 p.Y = (p.Y/GridSize.Height)*GridSize.Height;
523 }
524
525 SelectedArea += p - SelectedArea.UpperLeftCorner;
526 }
527 else if (CurrentMode > EGUIEDM_MOVE)
528 {
529 // get difference from start position
530 core::position2di p = core::position2di(e.MouseInput.X,e.MouseInput.Y);
531 if (UseGrid)
532 {
533 p.X = (p.X/GridSize.Width)*GridSize.Width;
534 p.Y = (p.Y/GridSize.Height)*GridSize.Height;
535 }
536
537 switch(CurrentMode)
538 {
539 case EGUIEDM_RESIZE_T:
540 SelectedArea.UpperLeftCorner.Y = p.Y;
541 break;
542 case EGUIEDM_RESIZE_B:
543 SelectedArea.LowerRightCorner.Y = p.Y;
544 break;
545 case EGUIEDM_RESIZE_L:
546 SelectedArea.UpperLeftCorner.X = p.X;
547 break;
548 case EGUIEDM_RESIZE_R:
549 SelectedArea.LowerRightCorner.X = p.X;
550 break;
551 case EGUIEDM_RESIZE_TL:
552 SelectedArea.UpperLeftCorner = p;
553 break;
554 case EGUIEDM_RESIZE_TR:
555 SelectedArea.UpperLeftCorner.Y = p.Y;
556 SelectedArea.LowerRightCorner.X = p.X;
557 break;
558 case EGUIEDM_RESIZE_BL:
559 SelectedArea.UpperLeftCorner.X = p.X;
560 SelectedArea.LowerRightCorner.Y = p.Y;
561 break;
562 case EGUIEDM_RESIZE_BR:
563 SelectedArea.LowerRightCorner = p;
564 break;
565 default:
566 break;
567 }
568 }
569
570 break;
571 default:
572 break;
573 }
574 break;
575
576 case EET_GUI_EVENT:
577 switch(e.GUIEvent.EventType)
578 {
579 case EGET_TREEVIEW_NODE_SELECT:
580 {
581 IGUITreeViewNode* eventnode = ((IGUITreeView*)e.GUIEvent.Caller)->getLastEventNode();
582 if(!eventnode->isRoot())
583 setSelectedElement((IGUIElement*)(eventnode->getData()));
584 break;
585 }
586 // load a gui file
587 case EGET_FILE_SELECTED:
588 dialog = (IGUIFileOpenDialog*)e.GUIEvent.Caller;
589 Environment->loadGUI(core::stringc(dialog->getFileName()).c_str());
590 break;
591
592 case EGET_MENU_ITEM_SELECTED:
593 {
594 IGUIContextMenu *menu = (IGUIContextMenu*)e.GUIEvent.Caller;
595 s32 cmdID = menu->getItemCommandId(menu->getSelectedItem()) - MenuCommandStart;
596
597 IGUIElement* el;
598
599 switch(cmdID)
600 {
601
602 //! file commands
603 case EGUIEDMC_FILE_NEW:
604 // clear all elements belonging to our parent
605 setSelectedElement(0);
606 MouseOverElement = 0;
607 el = Parent;
608 grab();
609 // remove all children
610 while(Children.end() != el->getChildren().begin())
611 el->removeChild(*(el->getChildren().begin()));
612 // attach to parent again
613 el->addChild(this);
614 drop();
615
616 break;
617 case EGUIEDMC_FILE_LOAD:
618 Environment->addFileOpenDialog(L"Please select a GUI file to open", false, this);
619 break;
620 case EGUIEDMC_FILE_SAVE:
621 Environment->saveGUI("guiTest.xml");
622 break;
623
624 //! edit menu
625 case EGUIEDMC_CUT_ELEMENT:
626 {
627 CopySelectedElementXML();
628 // delete element
629 el = SelectedElement;
630 setSelectedElement(0);
631 MouseOverElement = 0;
632 el->remove();
633 break;
634 }
635 case EGUIEDMC_COPY_ELEMENT:
636 CopySelectedElementXML();
637 break;
638 case EGUIEDMC_PASTE_ELEMENT:
639 PasteXMLToSelectedElement();
640 break;
641 case EGUIEDMC_DELETE_ELEMENT:
642 el = SelectedElement;
643 setSelectedElement(0);
644 MouseOverElement = 0;
645 el->remove();
646 break;
647 case EGUIEDMC_SET_PARENT:
648 CurrentMode = EGUIEDM_SELECT_NEW_PARENT;
649 break;
650 case EGUIEDMC_BRING_TO_FRONT:
651 if (SelectedElement->getParent())
652 SelectedElement->getParent()->bringToFront(SelectedElement);
653 break;
654
655 case EGUIEDMC_SAVE_ELEMENT:
656 //TODO: add 'save' dialog.
657 Environment->saveGUI("guiTest.xml", SelectedElement ? SelectedElement : Environment->getRootGUIElement() );
658 break;
659
660 //! toggle edit window
661 case EGUIEDMC_TOGGLE_EDITOR:
662 break;
663
664 case EGUIEDMC_INSERT_XML:
665 Environment->loadGUI("guiTest.xml", SelectedElement ? SelectedElement : Environment->getRootGUIElement() );
666 break;
667
668 default:
669 // create element from factory?
670 if (cmdID >= EGUIEDMC_COUNT)
671 {
672
673 s32 num = cmdID - EGUIEDMC_COUNT; // get index
674 // loop through all factories
675 s32 i, c=Environment->getRegisteredGUIElementFactoryCount();
676 for (i=0; i<c && num > Environment->getGUIElementFactory(i)->getCreatableGUIElementTypeCount(); ++i)
677 {
678 num -= Environment->getGUIElementFactory(i)->getCreatableGUIElementTypeCount();
679 }
680 if (num < Environment->getGUIElementFactory(i)->getCreatableGUIElementTypeCount() )
681 {
682 core::stringc name = Environment->getGUIElementFactory(i)->getCreateableGUIElementTypeName(num);
683 IGUIElement *parentElement = SelectedElement ? SelectedElement : Environment->getRootGUIElement();
684 // add it
685 IGUIElement *newElement = Environment->getGUIElementFactory(i)->addGUIElement(name.c_str(),parentElement);
686 if (newElement)
687 {
688 core::position2di p = DragStart - parentElement->getAbsolutePosition().UpperLeftCorner;
689 newElement->setRelativePosition(core::rect<s32>(p,p+core::position2di(100,100)));
690 //Environment->removeFocus(newElement);
691 }
692 }
693 }
694 break;
695 }
696 EditorWindow->updateTree();
697 }
698 return true;
699 default:
700 break;
701 }
702 break;
703
704 default:
705 break;
706 }
707
708 // even if we didn't absorb the event,
709 // we never pass events back to the GUI we're editing!
710 return false;
711 }
712
713
714 //! draws the element and its children
draw()715 void CGUIEditWorkspace::draw()
716 {
717 video::IVideoDriver *driver = Environment->getVideoDriver();
718
719 if (DrawGrid)
720 {
721 // draw the grid
722
723 core::rect<s32> r = getAbsolutePosition();
724
725 s32 cy = r.UpperLeftCorner.Y;
726 while (cy < r.LowerRightCorner.Y)
727 {
728 s32 cx = r.UpperLeftCorner.X;
729 while (cx < r.LowerRightCorner.X)
730 {
731 driver->draw2DRectangle(video::SColor(40,0,0,90),core::rect<s32>(cx+1,cy+1,GridSize.Width+cx,GridSize.Height+cy));
732 cx += GridSize.Width;
733 }
734 cy += GridSize.Height;
735 }
736 }
737 if (MouseOverElement &&
738 MouseOverElement != SelectedElement &&
739 MouseOverElement != Parent)
740 {
741 core::rect<s32> r = MouseOverElement->getAbsolutePosition();
742 driver->draw2DRectangle(video::SColor(100,0,0,255), r);
743 }
744 if (SelectedElement && CurrentMode == EGUIEDM_SELECT)
745 {
746 driver->draw2DRectangle(video::SColor(100,0,255,0),SelectedElement->getAbsolutePosition());
747 }
748 if (CurrentMode >= EGUIEDM_MOVE)
749 {
750 driver->draw2DRectangle(video::SColor(100,255,0,0),SelectedArea);
751 }
752
753 if ( (SelectedElement && CurrentMode >= EGUIEDM_MOVE) ||
754 (SelectedElement && MouseOverElement == SelectedElement && MouseOverMode >= EGUIEDM_MOVE) )
755 {
756 // draw handles for moving
757 EGUIEDIT_MODE m = CurrentMode;
758 core::rect<s32> r = SelectedArea;
759 if (m < EGUIEDM_MOVE)
760 {
761 m = MouseOverMode;
762 r = SelectedElement->getAbsolutePosition();
763 }
764
765 core::position2di d = core::position2di(4,4);
766
767 TLRect = core::rect<s32>(r.UpperLeftCorner, r.UpperLeftCorner + d );
768 TRRect = core::rect<s32>(r.LowerRightCorner.X-4, r.UpperLeftCorner.Y, r.LowerRightCorner.X, r.UpperLeftCorner.Y+4);
769 TopRect = core::rect<s32>(r.getCenter().X-2, r.UpperLeftCorner.Y,r.getCenter().X+2, r.UpperLeftCorner.Y+4 );
770 BLRect = core::rect<s32>(r.UpperLeftCorner.X, r.LowerRightCorner.Y-4, r.UpperLeftCorner.X+4, r.LowerRightCorner.Y);
771 LRect = core::rect<s32>(r.UpperLeftCorner.X,r.getCenter().Y-2, r.UpperLeftCorner.X+4, r.getCenter().Y+2 );
772 RRect = core::rect<s32>(r.LowerRightCorner.X-4,r.getCenter().Y-2, r.LowerRightCorner.X, r.getCenter().Y+2 );
773 BRRect = core::rect<s32>(r.LowerRightCorner-d, r.LowerRightCorner);
774 BRect = core::rect<s32>(r.getCenter().X-2, r.LowerRightCorner.Y-4,r.getCenter().X+2, r.LowerRightCorner.Y );
775
776 // top left
777 if (m == EGUIEDM_RESIZE_T || m == EGUIEDM_RESIZE_L || m == EGUIEDM_RESIZE_TL || m == EGUIEDM_MOVE )
778 driver->draw2DRectangle(video::SColor(100,255,255,255), TLRect);
779
780 if (m == EGUIEDM_RESIZE_T || m == EGUIEDM_RESIZE_R || m == EGUIEDM_RESIZE_TR || m == EGUIEDM_MOVE )
781 driver->draw2DRectangle(video::SColor(100,255,255,255), TRRect);
782
783 if (m == EGUIEDM_RESIZE_T || m == EGUIEDM_MOVE )
784 driver->draw2DRectangle(video::SColor(100,255,255,255), TopRect);
785
786 if (m == EGUIEDM_RESIZE_L || m == EGUIEDM_RESIZE_BL || m == EGUIEDM_RESIZE_B || m == EGUIEDM_MOVE )
787 driver->draw2DRectangle(video::SColor(100,255,255,255), BLRect);
788
789 if (m == EGUIEDM_RESIZE_L || m == EGUIEDM_MOVE )
790 driver->draw2DRectangle(video::SColor(100,255,255,255), LRect);
791
792 if (m == EGUIEDM_RESIZE_R || m == EGUIEDM_MOVE )
793 driver->draw2DRectangle(video::SColor(100,255,255,255), RRect);
794
795 if (m == EGUIEDM_RESIZE_R || m == EGUIEDM_RESIZE_BR || m == EGUIEDM_RESIZE_B || m == EGUIEDM_MOVE )
796 driver->draw2DRectangle(video::SColor(100,255,255,255), BRRect );
797
798 if (m == EGUIEDM_RESIZE_B || m == EGUIEDM_MOVE )
799 driver->draw2DRectangle(video::SColor(100,255,255,255), BRect);
800
801
802 }
803
804 IGUIElement::draw();
805 }
806
807
setDrawGrid(bool drawGrid)808 void CGUIEditWorkspace::setDrawGrid(bool drawGrid)
809 {
810 DrawGrid = drawGrid;
811 }
812
setGridSize(const core::dimension2di & gridSize)813 void CGUIEditWorkspace::setGridSize(const core::dimension2di& gridSize)
814 {
815 GridSize = gridSize;
816 if (GridSize.Width < 2)
817 GridSize.Width = 2;
818 if (GridSize.Height < 2)
819 GridSize.Height = 2;
820 }
821
setUseGrid(bool useGrid)822 void CGUIEditWorkspace::setUseGrid(bool useGrid)
823 {
824 UseGrid = useGrid;
825 }
826
827
828 //! Removes a child.
removeChild(IGUIElement * child)829 void CGUIEditWorkspace::removeChild(IGUIElement* child)
830 {
831 IGUIElement::removeChild(child);
832
833 if (Children.empty())
834 remove();
835 }
836
837
updateAbsolutePosition()838 void CGUIEditWorkspace::updateAbsolutePosition()
839 {
840 core::rect<s32> parentRect(0,0,0,0);
841
842 if (Parent)
843 {
844 parentRect = Parent->getAbsolutePosition();
845 RelativeRect.UpperLeftCorner.X = 0;
846 RelativeRect.UpperLeftCorner.Y = 0;
847 RelativeRect.LowerRightCorner.X = parentRect.getWidth();
848 RelativeRect.LowerRightCorner.Y = parentRect.getHeight();
849 }
850
851 IGUIElement::updateAbsolutePosition();
852 }
853
CopySelectedElementXML()854 void CGUIEditWorkspace::CopySelectedElementXML()
855 {
856 core::stringc XMLText;
857 core::stringw wXMLText;
858 // create memory write file
859 io::CMemoryReadWriteFile* memWrite = new io::CMemoryReadWriteFile("#Clipboard#");
860 // save gui to mem file
861 io::IXMLWriter* xml = Environment->getFileSystem()->createXMLWriter(memWrite);
862 Environment->writeGUIElement(xml, SelectedElement);
863
864 // copy to clipboard- wide chars not supported yet :(
865 wXMLText = (wchar_t*)&memWrite->getData()[0];
866 u32 i = memWrite->getData().size()/sizeof(wchar_t);
867 if (wXMLText.size() > i)
868 wXMLText[i] = L'\0';
869 XMLText = wXMLText.c_str();
870 memWrite->drop();
871 xml->drop();
872 Environment->getOSOperator()->copyToClipboard(XMLText.c_str());
873 }
874
PasteXMLToSelectedElement()875 void CGUIEditWorkspace::PasteXMLToSelectedElement()
876 {
877 // get clipboard data
878 const char * p = Environment->getOSOperator()->getTextFromClipboard();
879
880 // convert to stringw
881 // TODO: we should have such a function in core::string
882 size_t lenOld = strlen(p);
883 wchar_t *ws = new wchar_t[lenOld + 1];
884 size_t len = mbstowcs(ws,p,lenOld);
885 ws[len] = 0;
886 irr::core::stringw wXMLText(ws);
887 delete[] ws;
888
889 io::CMemoryReadWriteFile* memWrite = new io::CMemoryReadWriteFile("#Clipboard#");
890
891 io::IXMLWriter* xmlw = Environment->getFileSystem()->createXMLWriter(memWrite);
892 xmlw->writeXMLHeader(); // it needs one of those
893 xmlw->drop();
894
895 // write clipboard data
896 memWrite->write((void*)&wXMLText[0], wXMLText.size() * sizeof(wchar_t));
897
898 // rewind file
899 memWrite->seek(0, false);
900
901 // read xml
902 Environment->loadGUI(memWrite, SelectedElement);
903
904 // reset focus
905 Environment->setFocus(this);
906
907 // drop the read file
908 memWrite->drop();
909 }
910
serializeAttributes(io::IAttributes * out,io::SAttributeReadWriteOptions * options)911 void CGUIEditWorkspace::serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options)
912 {
913 out->addBool("DrawGrid", DrawGrid);
914 out->addBool("UseGrid", UseGrid);
915 out->addPosition2d("GridSize", core::position2di(GridSize.Width, GridSize.Height));
916 out->addInt("MenuCommandStart", MenuCommandStart);
917 }
918
deserializeAttributes(io::IAttributes * in,io::SAttributeReadWriteOptions * options)919 void CGUIEditWorkspace::deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options)
920 {
921 setDrawGrid(in->getAttributeAsBool("DrawGrid"));
922 setUseGrid(in->getAttributeAsBool("UseGrid"));
923
924 core::position2di tmpp = in->getAttributeAsPosition2d("GridSize");
925 core::dimension2di tmpd(tmpp.X, tmpp.Y);
926 setGridSize(tmpd);
927 setMenuCommandIDStart(in->getAttributeAsInt("MenuCommandStart"));
928 }
929
930
931 } // end namespace gui
932 } // end namespace irr
933
934
935