// Copyright (C) 2002-2012 Nikolaus Gebhardt / Gaz Davidson // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h // Thanks to Midnight for all his testing, bug fixes and patches :) #include "CGUIEditWorkspace.h" #include "IGUIEnvironment.h" #include "IVideoDriver.h" #include "IOSOperator.h" #include "IReadFile.h" #include "IFileSystem.h" #include "IXMLWriter.h" #include "IGUISkin.h" #include "IGUIElementFactory.h" #include "CGUIEditWindow.h" #include "IGUIContextMenu.h" #include "IGUIFileOpenDialog.h" #include "IGUITreeView.h" #include "CGUIAttribute.h" #include "CMemoryReadWriteFile.h" namespace irr { namespace gui { //! constructor CGUIEditWorkspace::CGUIEditWorkspace(IGUIEnvironment* environment, s32 id, IGUIElement *parent) : IGUIElement(EGUIET_ELEMENT, environment, parent ? parent : environment->getRootGUIElement(), id, environment->getRootGUIElement()->getAbsolutePosition()), CurrentMode(EGUIEDM_SELECT), MouseOverMode(EGUIEDM_SELECT), GridSize(10,10), MenuCommandStart(0x3D17), DrawGrid(false), UseGrid(true), MouseOverElement(0), SelectedElement(0), EditorWindow(0) { #ifdef _DEBUG setDebugName("CGUIEditWorkspace"); #endif // this element is never saved. setSubElement(true); // it resizes to fit a resizing window setAlignment(EGUIA_UPPERLEFT, EGUIA_LOWERRIGHT, EGUIA_UPPERLEFT, EGUIA_LOWERRIGHT); // Types which we currently can't handle in editor // Most of them also just don't make sense in here (like Dialogs) // TODO: We should have a way to create context-menus UnusableElementTypeFilter.push_back(EGUIET_CONTEXT_MENU); UnusableElementTypeFilter.push_back(EGUIET_FILE_OPEN_DIALOG); UnusableElementTypeFilter.push_back(EGUIET_COLOR_SELECT_DIALOG); UnusableElementTypeFilter.push_back(EGUIET_MESSAGE_BOX); UnusableElementTypeFilter.push_back(EGUIET_MODAL_SCREEN); UnusableElementTypeFilter.push_back(EGUIET_ELEMENT); // wouldn't do anything, so don't show in menu UnusableElementTypeFilter.push_back(EGUIET_ROOT); // wouldn't do anything, so don't show in menu EditorWindow = (CGUIEditWindow*) Environment->addGUIElement("GUIEditWindow", this); if (EditorWindow) { EditorWindow->grab(); EditorWindow->setSubElement(true); Environment->setFocus(EditorWindow); serializeAttributes(EditorWindow->getOptionEditor()->getAttribs()); EditorWindow->getOptionEditor()->refreshAttribs(); if (EditorWindow->getEnvironmentEditor()) { Environment->serializeAttributes(EditorWindow->getEnvironmentEditor()->getAttribs()); EditorWindow->getEnvironmentEditor()->refreshAttribs(); } } } //! destructor CGUIEditWorkspace::~CGUIEditWorkspace() { if (EditorWindow) EditorWindow->drop(); } void CGUIEditWorkspace::setMenuCommandIDStart(s32 id) { MenuCommandStart = id; } CGUIEditWorkspace::EGUIEDIT_MODE CGUIEditWorkspace::getModeFromPos(core::position2di p) { if (SelectedElement) { core::rect r = SelectedElement->getAbsolutePosition(); if (TLRect.isPointInside(p)) return EGUIEDM_RESIZE_TL; else if (TRRect.isPointInside(p)) return EGUIEDM_RESIZE_TR; else if (BLRect.isPointInside(p) ) return EGUIEDM_RESIZE_BL; else if (BRRect.isPointInside(p)) return EGUIEDM_RESIZE_BR; else if (TopRect.isPointInside(p)) return EGUIEDM_RESIZE_T; else if (BRect.isPointInside(p)) return EGUIEDM_RESIZE_B; else if (LRect.isPointInside(p)) return EGUIEDM_RESIZE_L; else if (RRect.isPointInside(p)) return EGUIEDM_RESIZE_R; else if (getEditableElementFromPoint(SelectedElement, p) == SelectedElement) return EGUIEDM_MOVE; else return EGUIEDM_SELECT; } return EGUIEDM_SELECT; } IGUIElement* CGUIEditWorkspace::getEditableElementFromPoint(IGUIElement *start, const core::position2di &point, s32 index ) { IGUIElement* target = 0; // we have to search from back to front. core::list::ConstIterator it = start->getChildren().getLast(); s32 count=0; while(it != start->getChildren().end()) { target = getEditableElementFromPoint((*it),point); if (target) { if (!target->isSubElement() && !isMyChild(target) && target != this) { if (index == count) return target; else count++; } else target = 0; } --it; } if (start->getAbsolutePosition().isPointInside(point)) target = start; return target; } void CGUIEditWorkspace::setSelectedElement(IGUIElement *sel) { IGUIElement* focus = Environment->getFocus(); // we only give focus back to children if (!isMyChild(focus)) focus = 0; if (SelectedElement != Parent) { if (SelectedElement != sel && EditorWindow) { EditorWindow->setSelectedElement(sel); SelectedElement = sel; } } else SelectedElement = 0; if (focus) Environment->setFocus(focus); else Environment->setFocus(this); } IGUIElement* CGUIEditWorkspace::getSelectedElement() { return SelectedElement; } void CGUIEditWorkspace::selectNextSibling() { IGUIElement* p=0; if (SelectedElement && SelectedElement->getParent()) p = SelectedElement->getParent(); else p = Parent; core::list::ConstIterator it = p->getChildren().begin(); // find selected element if (SelectedElement) while (*it != SelectedElement) ++it; if (it !=p->getChildren().end()) ++it; // find next non sub-element while (it != p->getChildren().end() && (*it)->isSubElement()) ++it; if (it != p->getChildren().end()) setSelectedElement(*it); } void CGUIEditWorkspace::selectPreviousSibling() { IGUIElement* p=0; if (SelectedElement && SelectedElement->getParent()) p = SelectedElement->getParent(); else p = Parent; core::list::ConstIterator it = p->getChildren().getLast(); // find selected element if (SelectedElement) while (*it != SelectedElement) --it; if (it != p->getChildren().end()) --it; // find next non sub-element while (it != p->getChildren().end() && (*it)->isSubElement()) --it; if (it != p->getChildren().end()) setSelectedElement(*it); } //! called if an event happened. bool CGUIEditWorkspace::OnEvent(const SEvent &e) { IGUIFileOpenDialog* dialog=0; switch(e.EventType) { case ATTRIBEDIT_ATTRIB_CHANGED: { switch (e.UserEvent.UserData1) { case EGUIEDCE_ATTRIB_EDITOR: { // update selected items attributes if (SelectedElement) { SelectedElement->deserializeAttributes(EditorWindow->getAttributeEditor()->getAttribs()); EditorWindow->updateTree(); } return true; } case EGUIEDCE_OPTION_EDITOR: { // update editor options deserializeAttributes(EditorWindow->getOptionEditor()->getAttribs()); return true; } case EGUIEDCE_ENV_EDITOR: { // update environment Environment->deserializeAttributes(EditorWindow->getEnvironmentEditor()->getAttribs()); return true; } } } break; case EET_KEY_INPUT_EVENT: if (!e.KeyInput.PressedDown) { switch (e.KeyInput.Key) { case KEY_DELETE: if (SelectedElement) { IGUIElement* el = SelectedElement; setSelectedElement(0); MouseOverElement = 0; el->remove(); EditorWindow->updateTree(); } break; case KEY_KEY_X: if (e.KeyInput.Control && SelectedElement) { // cut CopySelectedElementXML(); // delete element IGUIElement *el = SelectedElement; setSelectedElement(0); MouseOverElement = 0; el->remove(); } break; case KEY_KEY_C: // copy if (e.KeyInput.Control && SelectedElement) { CopySelectedElementXML(); } break; case KEY_KEY_V: // paste if (e.KeyInput.Control) { PasteXMLToSelectedElement(); } break; default: break; } return true; } break; case EET_MOUSE_INPUT_EVENT: switch(e.MouseInput.Event) { case EMIE_MOUSE_WHEEL: { f32 wheel = e.MouseInput.Wheel; if (wheel > 0) selectPreviousSibling(); else selectNextSibling(); } break; case EMIE_LMOUSE_PRESSED_DOWN: { core::position2di p = core::position2di(e.MouseInput.X,e.MouseInput.Y); IGUIElement* newSelection = getElementFromPoint(p); if (newSelection != this && isMyChild(newSelection) ) // redirect event { Environment->setFocus(newSelection); return true; } // hide the gui editor if (EditorWindow) EditorWindow->setVisible(false); if (CurrentMode == EGUIEDM_SELECT) { if (SelectedElement) { // start moving or dragging CurrentMode = getModeFromPos(p); if (CurrentMode == EGUIEDM_MOVE) StartMovePos = SelectedElement->getAbsolutePosition().UpperLeftCorner; DragStart = p; SelectedArea = SelectedElement->getAbsolutePosition(); } if (CurrentMode < EGUIEDM_MOVE) { // selecting an element... MouseOverElement = getEditableElementFromPoint(Parent, p); if (MouseOverElement == Parent) MouseOverElement = 0; setSelectedElement(MouseOverElement); } } break; } case EMIE_RMOUSE_PRESSED_DOWN: if (CurrentMode == EGUIEDM_SELECT_NEW_PARENT || CurrentMode >= EGUIEDM_MOVE) { // cancel dragging CurrentMode = EGUIEDM_SELECT; } else { DragStart = core::position2di(e.MouseInput.X,e.MouseInput.Y); // root menu IGUIContextMenu* mnu = Environment->addContextMenu( core::rect(e.MouseInput.X, e.MouseInput.Y, e.MouseInput.Y+100, e.MouseInput.Y+100),this); mnu->addItem(L"File",-1,true,true); mnu->addItem(L"Edit",-1,true,true); mnu->addItem(L"View",-1,true,true); mnu->addItem(SelectedElement ? L"Add child" : L"Add" ,-1,true,true); // file menu IGUIContextMenu* sub = mnu->getSubMenu(0); IGUIContextMenu* sub2 =0; sub->addItem(L"New", MenuCommandStart + EGUIEDMC_FILE_NEW ); sub->addItem(L"Load...",MenuCommandStart + EGUIEDMC_FILE_LOAD); sub->addItem(L"Save...",MenuCommandStart + EGUIEDMC_FILE_SAVE); // edit menu sub = mnu->getSubMenu(1); sub->addItem(L"Cut (ctrl+x)", MenuCommandStart + EGUIEDMC_CUT_ELEMENT, (SelectedElement != 0)); sub->addItem(L"Copy (ctrl+c)", MenuCommandStart + EGUIEDMC_COPY_ELEMENT, (SelectedElement != 0)); sub->addItem(L"Paste (ctrl+v)", MenuCommandStart + EGUIEDMC_PASTE_ELEMENT, (core::stringc(Environment->getOSOperator()->getTextFromClipboard()) != "")); sub->addItem(L"Delete (del)", MenuCommandStart + EGUIEDMC_DELETE_ELEMENT, (SelectedElement != 0)); sub->addSeparator(); sub->addItem(L"Set parent", MenuCommandStart + EGUIEDMC_SET_PARENT, (SelectedElement != 0)); sub->addItem(L"Bring to front", MenuCommandStart + EGUIEDMC_BRING_TO_FRONT, (SelectedElement != 0)); sub->addSeparator(); sub->addItem(L"Save to XML...", MenuCommandStart + EGUIEDMC_SAVE_ELEMENT, (SelectedElement != 0)); sub = mnu->getSubMenu(2); // view menu if (EditorWindow) sub->addItem(EditorWindow->isVisible() ? L"Hide window" : L"Show window", MenuCommandStart + EGUIEDMC_TOGGLE_EDITOR); sub = mnu->getSubMenu(3); s32 i,j,c=0; sub->addItem(L"Default factory",-1,true, true); // add elements from each factory for (i=0; u32(i) < Environment->getRegisteredGUIElementFactoryCount(); ++i) { sub2 = sub->getSubMenu(i); IGUIElementFactory *f = Environment->getGUIElementFactory(i); for (j=0; j< f->getCreatableGUIElementTypeCount(); ++j) { EGUI_ELEMENT_TYPE type = f->getCreateableGUIElementType(j); if ( UnusableElementTypeFilter.linear_search(type) < 0 ) sub2->addItem(core::stringw(f->getCreateableGUIElementTypeName(j)).c_str(), MenuCommandStart + EGUIEDMC_COUNT + c); c++; } if (u32(i+1) < Environment->getRegisteredGUIElementFactoryCount()) { core::stringw strFact; strFact = L"Factory "; strFact += i+1; sub->addItem(strFact.c_str(),-1, true, true); } } sub->addSeparator(); sub->addItem(L"From XML...", MenuCommandStart + EGUIEDMC_INSERT_XML); // set focus to menu Environment->setFocus(mnu); } break; case EMIE_LMOUSE_LEFT_UP: // make window visible again if (EditorWindow) EditorWindow->setVisible(true); if (CurrentMode == EGUIEDM_SELECT_NEW_PARENT) { if (SelectedElement) { MouseOverElement = getEditableElementFromPoint(Parent, core::position2di(e.MouseInput.X,e.MouseInput.Y)); if (MouseOverElement) { MouseOverElement->addChild(SelectedElement); setSelectedElement(0); setSelectedElement(SelectedElement); } } CurrentMode = EGUIEDM_SELECT; } else if (CurrentMode >= EGUIEDM_MOVE) { IGUIElement *sel = SelectedElement; // unselect setSelectedElement(0); // move core::position2d p(0,0); if (sel->getParent()) p = sel->getParent()->getAbsolutePosition().UpperLeftCorner; sel->setRelativePosition(SelectedArea - p); // select setSelectedElement(sel); // reset selection mode... CurrentMode = EGUIEDM_SELECT; } break; case EMIE_MOUSE_MOVED: // always on top Parent->bringToFront(this); // if selecting if (CurrentMode == EGUIEDM_SELECT || CurrentMode == EGUIEDM_SELECT_NEW_PARENT) { core::position2di p = core::position2di(e.MouseInput.X,e.MouseInput.Y); // highlight the element that the mouse is over MouseOverElement = getEditableElementFromPoint(Parent, p); if (MouseOverElement == Parent) { MouseOverElement = 0; } if (CurrentMode == EGUIEDM_SELECT) { MouseOverMode = getModeFromPos(p); if (MouseOverMode > EGUIEDM_MOVE) { MouseOverElement = SelectedElement; } } } else if (CurrentMode == EGUIEDM_MOVE) { // get difference core::position2di p = core::position2di(e.MouseInput.X,e.MouseInput.Y); p -= DragStart; // apply to top corner p = StartMovePos + p; if (UseGrid) { p.X = (p.X/GridSize.Width)*GridSize.Width; p.Y = (p.Y/GridSize.Height)*GridSize.Height; } SelectedArea += p - SelectedArea.UpperLeftCorner; } else if (CurrentMode > EGUIEDM_MOVE) { // get difference from start position core::position2di p = core::position2di(e.MouseInput.X,e.MouseInput.Y); if (UseGrid) { p.X = (p.X/GridSize.Width)*GridSize.Width; p.Y = (p.Y/GridSize.Height)*GridSize.Height; } switch(CurrentMode) { case EGUIEDM_RESIZE_T: SelectedArea.UpperLeftCorner.Y = p.Y; break; case EGUIEDM_RESIZE_B: SelectedArea.LowerRightCorner.Y = p.Y; break; case EGUIEDM_RESIZE_L: SelectedArea.UpperLeftCorner.X = p.X; break; case EGUIEDM_RESIZE_R: SelectedArea.LowerRightCorner.X = p.X; break; case EGUIEDM_RESIZE_TL: SelectedArea.UpperLeftCorner = p; break; case EGUIEDM_RESIZE_TR: SelectedArea.UpperLeftCorner.Y = p.Y; SelectedArea.LowerRightCorner.X = p.X; break; case EGUIEDM_RESIZE_BL: SelectedArea.UpperLeftCorner.X = p.X; SelectedArea.LowerRightCorner.Y = p.Y; break; case EGUIEDM_RESIZE_BR: SelectedArea.LowerRightCorner = p; break; default: break; } } break; default: break; } break; case EET_GUI_EVENT: switch(e.GUIEvent.EventType) { case EGET_TREEVIEW_NODE_SELECT: { IGUITreeViewNode* eventnode = ((IGUITreeView*)e.GUIEvent.Caller)->getLastEventNode(); if(!eventnode->isRoot()) setSelectedElement((IGUIElement*)(eventnode->getData())); break; } // load a gui file case EGET_FILE_SELECTED: { dialog = (IGUIFileOpenDialog*)e.GUIEvent.Caller; core::stringc guiFilename(core::stringc(dialog->getFileName()).c_str()); clearParentElements(); Environment->loadGUI(guiFilename, Parent); EditorWindow->updateTree(); break; } case EGET_MENU_ITEM_SELECTED: { IGUIContextMenu *menu = (IGUIContextMenu*)e.GUIEvent.Caller; s32 cmdID = menu->getItemCommandId(menu->getSelectedItem()) - MenuCommandStart; IGUIElement* el; switch(cmdID) { //! file commands case EGUIEDMC_FILE_NEW: clearParentElements(); break; case EGUIEDMC_FILE_LOAD: Environment->addFileOpenDialog(L"Please select a GUI file to open", false, this); break; case EGUIEDMC_FILE_SAVE: Environment->saveGUI("guiTest.xml"); break; //! edit menu case EGUIEDMC_CUT_ELEMENT: { CopySelectedElementXML(); // delete element el = SelectedElement; setSelectedElement(0); MouseOverElement = 0; el->remove(); break; } case EGUIEDMC_COPY_ELEMENT: CopySelectedElementXML(); break; case EGUIEDMC_PASTE_ELEMENT: PasteXMLToSelectedElement(); break; case EGUIEDMC_DELETE_ELEMENT: el = SelectedElement; setSelectedElement(0); MouseOverElement = 0; el->remove(); break; case EGUIEDMC_SET_PARENT: CurrentMode = EGUIEDM_SELECT_NEW_PARENT; break; case EGUIEDMC_BRING_TO_FRONT: if (SelectedElement->getParent()) SelectedElement->getParent()->bringToFront(SelectedElement); break; case EGUIEDMC_SAVE_ELEMENT: //TODO: add 'save' dialog. Environment->saveGUI("guiTest.xml", SelectedElement ? SelectedElement : Environment->getRootGUIElement() ); break; //! toggle edit window case EGUIEDMC_TOGGLE_EDITOR: break; case EGUIEDMC_INSERT_XML: Environment->loadGUI("guiTest.xml", SelectedElement ? SelectedElement : Environment->getRootGUIElement() ); break; default: // create element from factory? if (cmdID >= EGUIEDMC_COUNT) { s32 num = cmdID - EGUIEDMC_COUNT; // get index // loop through all factories s32 i, c=Environment->getRegisteredGUIElementFactoryCount(); for (i=0; i Environment->getGUIElementFactory(i)->getCreatableGUIElementTypeCount(); ++i) { num -= Environment->getGUIElementFactory(i)->getCreatableGUIElementTypeCount(); } if (num < Environment->getGUIElementFactory(i)->getCreatableGUIElementTypeCount() ) { core::stringc name = Environment->getGUIElementFactory(i)->getCreateableGUIElementTypeName(num); IGUIElement *parentElement = SelectedElement ? SelectedElement : Environment->getRootGUIElement(); // add it IGUIElement *newElement = Environment->getGUIElementFactory(i)->addGUIElement(name.c_str(),parentElement); if (newElement) { core::position2di p = DragStart - parentElement->getAbsolutePosition().UpperLeftCorner; newElement->setRelativePosition(core::rect(p,p+core::position2di(100,100))); //Environment->removeFocus(newElement); } } } break; } EditorWindow->updateTree(); } return true; default: break; } break; default: break; } // even if we didn't absorb the event, // we never pass events back to the GUI we're editing! return false; } //! draws the element and its children void CGUIEditWorkspace::draw() { video::IVideoDriver *driver = Environment->getVideoDriver(); if (DrawGrid) { // draw the grid core::rect r = getAbsolutePosition(); s32 cy = r.UpperLeftCorner.Y; while (cy < r.LowerRightCorner.Y) { s32 cx = r.UpperLeftCorner.X; while (cx < r.LowerRightCorner.X) { driver->draw2DRectangle(video::SColor(40,0,0,90),core::rect(cx+1,cy+1,GridSize.Width+cx,GridSize.Height+cy)); cx += GridSize.Width; } cy += GridSize.Height; } } if (MouseOverElement && MouseOverElement != SelectedElement && MouseOverElement != Parent) { core::rect r = MouseOverElement->getAbsolutePosition(); driver->draw2DRectangle(video::SColor(100,0,0,255), r); } if (SelectedElement && CurrentMode == EGUIEDM_SELECT) { driver->draw2DRectangle(video::SColor(100,0,255,0),SelectedElement->getAbsolutePosition()); } if (CurrentMode >= EGUIEDM_MOVE) { driver->draw2DRectangle(video::SColor(100,255,0,0),SelectedArea); } if ( (SelectedElement && CurrentMode >= EGUIEDM_MOVE) || (SelectedElement && MouseOverElement == SelectedElement && MouseOverMode >= EGUIEDM_MOVE) ) { // draw handles for moving EGUIEDIT_MODE m = CurrentMode; core::rect r = SelectedArea; if (m < EGUIEDM_MOVE) { m = MouseOverMode; r = SelectedElement->getAbsolutePosition(); } core::position2di d = core::position2di(4,4); TLRect = core::rect(r.UpperLeftCorner, r.UpperLeftCorner + d ); TRRect = core::rect(r.LowerRightCorner.X-4, r.UpperLeftCorner.Y, r.LowerRightCorner.X, r.UpperLeftCorner.Y+4); TopRect = core::rect(r.getCenter().X-2, r.UpperLeftCorner.Y,r.getCenter().X+2, r.UpperLeftCorner.Y+4 ); BLRect = core::rect(r.UpperLeftCorner.X, r.LowerRightCorner.Y-4, r.UpperLeftCorner.X+4, r.LowerRightCorner.Y); LRect = core::rect(r.UpperLeftCorner.X,r.getCenter().Y-2, r.UpperLeftCorner.X+4, r.getCenter().Y+2 ); RRect = core::rect(r.LowerRightCorner.X-4,r.getCenter().Y-2, r.LowerRightCorner.X, r.getCenter().Y+2 ); BRRect = core::rect(r.LowerRightCorner-d, r.LowerRightCorner); BRect = core::rect(r.getCenter().X-2, r.LowerRightCorner.Y-4,r.getCenter().X+2, r.LowerRightCorner.Y ); // top left if (m == EGUIEDM_RESIZE_T || m == EGUIEDM_RESIZE_L || m == EGUIEDM_RESIZE_TL || m == EGUIEDM_MOVE ) driver->draw2DRectangle(video::SColor(100,255,255,255), TLRect); if (m == EGUIEDM_RESIZE_T || m == EGUIEDM_RESIZE_R || m == EGUIEDM_RESIZE_TR || m == EGUIEDM_MOVE ) driver->draw2DRectangle(video::SColor(100,255,255,255), TRRect); if (m == EGUIEDM_RESIZE_T || m == EGUIEDM_MOVE ) driver->draw2DRectangle(video::SColor(100,255,255,255), TopRect); if (m == EGUIEDM_RESIZE_L || m == EGUIEDM_RESIZE_BL || m == EGUIEDM_RESIZE_B || m == EGUIEDM_MOVE ) driver->draw2DRectangle(video::SColor(100,255,255,255), BLRect); if (m == EGUIEDM_RESIZE_L || m == EGUIEDM_MOVE ) driver->draw2DRectangle(video::SColor(100,255,255,255), LRect); if (m == EGUIEDM_RESIZE_R || m == EGUIEDM_MOVE ) driver->draw2DRectangle(video::SColor(100,255,255,255), RRect); if (m == EGUIEDM_RESIZE_R || m == EGUIEDM_RESIZE_BR || m == EGUIEDM_RESIZE_B || m == EGUIEDM_MOVE ) driver->draw2DRectangle(video::SColor(100,255,255,255), BRRect ); if (m == EGUIEDM_RESIZE_B || m == EGUIEDM_MOVE ) driver->draw2DRectangle(video::SColor(100,255,255,255), BRect); } IGUIElement::draw(); } void CGUIEditWorkspace::setDrawGrid(bool drawGrid) { DrawGrid = drawGrid; } void CGUIEditWorkspace::setGridSize(const core::dimension2di& gridSize) { GridSize = gridSize; if (GridSize.Width < 2) GridSize.Width = 2; if (GridSize.Height < 2) GridSize.Height = 2; } void CGUIEditWorkspace::setUseGrid(bool useGrid) { UseGrid = useGrid; } //! Removes a child. void CGUIEditWorkspace::removeChild(IGUIElement* child) { IGUIElement::removeChild(child); // TODO: Can anyone find out why the workspace removes itself when it has no more children // and document it here? if (Children.empty()) remove(); } void CGUIEditWorkspace::clearParentElements() { setSelectedElement(0); MouseOverElement = 0; IGUIElement * el = Parent; grab(); if ( el->isMyChild(Environment->getFocus()) ) Environment->setFocus(0); // remove all children except first one (EditorWindow) while (!el->getChildren().empty()) { el->removeChild(*(el->getChildren().begin())); } el->addChild(this); drop(); } void CGUIEditWorkspace::updateAbsolutePosition() { core::rect parentRect(0,0,0,0); if (Parent) { parentRect = Parent->getAbsolutePosition(); RelativeRect.UpperLeftCorner.X = 0; RelativeRect.UpperLeftCorner.Y = 0; RelativeRect.LowerRightCorner.X = parentRect.getWidth(); RelativeRect.LowerRightCorner.Y = parentRect.getHeight(); } IGUIElement::updateAbsolutePosition(); } void CGUIEditWorkspace::CopySelectedElementXML() { core::stringc XMLText; core::stringw wXMLText; // create memory write file io::CMemoryReadWriteFile* memWrite = new io::CMemoryReadWriteFile("#Clipboard#"); // save gui to mem file io::IXMLWriter* xml = Environment->getFileSystem()->createXMLWriter(memWrite); Environment->writeGUIElement(xml, SelectedElement); // copy to clipboard- wide chars not supported yet :( wXMLText = (wchar_t*)&memWrite->getData()[0]; u32 i = memWrite->getData().size()/sizeof(wchar_t); if (wXMLText.size() > i) wXMLText[i] = L'\0'; XMLText = wXMLText.c_str(); memWrite->drop(); xml->drop(); Environment->getOSOperator()->copyToClipboard(XMLText.c_str()); } void CGUIEditWorkspace::PasteXMLToSelectedElement() { // get clipboard data const char * p = Environment->getOSOperator()->getTextFromClipboard(); irr::core::stringw wXMLText; core::multibyteToWString(wXMLText, p); io::CMemoryReadWriteFile* memWrite = new io::CMemoryReadWriteFile("#Clipboard#"); io::IXMLWriter* xmlw = Environment->getFileSystem()->createXMLWriter(memWrite); xmlw->writeXMLHeader(); // it needs one of those xmlw->drop(); // write clipboard data memWrite->write((void*)&wXMLText[0], wXMLText.size() * sizeof(wchar_t)); // rewind file memWrite->seek(0, false); // read xml Environment->loadGUI(memWrite, SelectedElement); // reset focus Environment->setFocus(this); // drop the read file memWrite->drop(); } void CGUIEditWorkspace::serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options) { out->addBool("DrawGrid", DrawGrid); out->addBool("UseGrid", UseGrid); out->addPosition2d("GridSize", core::position2di(GridSize.Width, GridSize.Height)); out->addInt("MenuCommandStart", MenuCommandStart); } void CGUIEditWorkspace::deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options) { setDrawGrid(in->getAttributeAsBool("DrawGrid")); setUseGrid(in->getAttributeAsBool("UseGrid")); core::position2di tmpp = in->getAttributeAsPosition2d("GridSize"); core::dimension2di tmpd(tmpp.X, tmpp.Y); setGridSize(tmpd); setMenuCommandIDStart(in->getAttributeAsInt("MenuCommandStart")); } } // end namespace gui } // end namespace irr