| 178 | | void ToolMorphT::MorphPrims_CommitAndClear() |
| 179 | | { |
| 180 | | // Set the map elements of all morph primitives back to "visible" |
| 181 | | // and remove all unmodified morph primitives from our list. |
| 182 | | |
| 183 | | // TODO: Doing it like this is not particularly efficient, but this is going to be refactored anyway. |
| 184 | | while (m_MorphPrims.Size()>0) |
| 185 | | { |
| 186 | | MorphPrims_TogglePrim(m_MorphPrims[0]->GetMapPrim()); |
| 187 | | } |
| 188 | | } |
| 189 | | |
| 190 | | |
| 191 | | void ToolMorphT::MorphPrims_TogglePrim(const MapPrimitiveT* MapPrim) |
| 192 | | { |
| 193 | | // Only needed for observer message. |
| 194 | | ArrayT<MapElementT*> MapElements; |
| 195 | | MapElements.PushBack(const_cast<MapPrimitiveT*>(MapPrim)); |
| 196 | | |
| 197 | | const int MP_Index=MorphPrims_Find(MapPrim); |
| 198 | | |
| 199 | | if (MP_Index>=0) |
| 200 | | { |
| 201 | | MorphPrimT* MorphPrim=m_MorphPrims[MP_Index]; |
| 202 | | |
| 203 | | m_MorphPrims.RemoveAtAndKeepOrder(MP_Index); |
| 204 | | wxASSERT(MapPrim == MorphPrim->GetMapPrim()); |
| 205 | | |
| 206 | | if (MorphPrim->IsModified()) |
| 207 | | { |
| 208 | | MapPrimitiveT* MorphedMapPrim=MorphPrim->GetMorphedMapPrim(); |
| 209 | | |
| 210 | | if (MorphedMapPrim) |
| 211 | | { |
| 212 | | m_IsRecursiveSelfNotify=true; |
| 213 | | |
| 214 | | ArrayT<CommandT*> Commands; |
| 215 | | Commands.PushBack(new CommandDeleteT(m_MapDoc, const_cast<MapPrimitiveT*>(MorphPrim->GetMapPrim()))); |
| 216 | | Commands.PushBack(new CommandAddPrimT(m_MapDoc, MorphedMapPrim, MorphPrim->GetMapPrim()->GetParent())); |
| 217 | | |
| 218 | | m_MapDoc.GetHistory().SubmitCommand(new CommandMacroT(Commands, "Edit Vertices")); |
| 219 | | |
| 220 | | m_IsRecursiveSelfNotify=false; |
| 221 | | } |
| 222 | | } |
| 223 | | |
| 224 | | delete MorphPrim; |
| 225 | | |
| 226 | | // Elem is now no longer mentioned in the m_MorphPrims list, and thus no longer affected by IsHiddenByTool(). |
| | 175 | void ToolMorphT::MorphPrims_SyncTo(const ArrayT<MapElementT*>& Elems) |
| | 176 | { |
| | 177 | ArrayT<MapElementT*> VisChanged; |
| | 178 | |
| | 179 | // Remove all entries from m_MorphPrims that are not in NewSelection. |
| | 180 | for (unsigned long MPNr=0; MPNr<m_MorphPrims.Size(); MPNr++) |
| | 181 | { |
| | 182 | MapPrimitiveT* MapPrim=const_cast<MapPrimitiveT*>(m_MorphPrims[MPNr]->GetMapPrim()); |
| | 183 | |
| | 184 | if (Elems.Find(MapPrim) < 0) |
| | 185 | { |
| | 186 | delete m_MorphPrims[MPNr]; |
| | 187 | m_MorphPrims.RemoveAt(MPNr); |
| | 188 | MPNr--; |
| | 189 | |
| | 190 | VisChanged.PushBack(MapPrim); |
| | 191 | } |
| | 192 | } |
| | 193 | |
| | 194 | // Add all entries that are in Elems but not yet in m_MorphPrims to m_MorphPrims. |
| | 195 | for (unsigned long ElemNr=0; ElemNr<Elems.Size(); ElemNr++) |
| | 196 | { |
| | 197 | MapPrimitiveT* MapPrim=dynamic_cast<MapPrimitiveT*>(Elems[ElemNr]); |
| | 198 | |
| | 199 | if (!MapPrim) continue; |
| | 200 | if (MapPrim->GetType()!=&MapBrushT::TypeInfo && MapPrim->GetType()!=&MapBezierPatchT::TypeInfo) continue; |
| | 201 | if (MorphPrims_Find(MapPrim) >= 0) continue; |
| | 202 | |
| | 203 | m_MorphPrims.PushBack(new MorphPrimT(MapPrim)); |
| | 204 | VisChanged.PushBack(MapPrim); |
| | 205 | } |
| | 206 | |
| | 207 | // If any changes were made, notify the observers. |
| | 208 | if (VisChanged.Size() > 0) |
| | 209 | { |
| 230 | | return; |
| 231 | | } |
| 232 | | |
| 233 | | if (dynamic_cast<const MapBrushT*>(MapPrim)==NULL && dynamic_cast<const MapBezierPatchT*>(MapPrim)==NULL) return; |
| 234 | | |
| 235 | | MorphPrimT* MorphPrim=new MorphPrimT(MapPrim); |
| 236 | | m_MorphPrims.PushBack(MorphPrim); |
| 237 | | |
| 238 | | // Elem is now mentioned in the m_MorphPrims list, and thus affected by IsHiddenByTool(). |
| 239 | | m_IsRecursiveSelfNotify=true; |
| 240 | | m_MapDoc.UpdateAllObservers_Modified(MapElements, MEMD_VISIBILITY); |
| 241 | | m_IsRecursiveSelfNotify=false; |
| 242 | | } |
| 243 | | |
| 244 | | |
| 245 | | ArrayT<MorphHandleT> ToolMorphT::GetMorphHandlesAt(ViewWindow2DT& ViewWindow, const wxPoint& Point) |
| | 213 | |
| | 214 | m_ToolMan.UpdateAllObservers(this, UPDATE_SOON); |
| | 215 | } |
| | 216 | } |
| | 217 | |
| | 218 | |
| | 219 | ArrayT<MorphHandleT> ToolMorphT::GetMorphHandlesAt(ViewWindow2DT& ViewWindow, const wxPoint& Point) const |
| | 404 | void ToolMorphT::FinishDragMorphHandles() |
| | 405 | { |
| | 406 | ArrayT<CommandT*> Commands; |
| | 407 | |
| | 408 | for (unsigned long MPNr=0; MPNr<m_MorphPrims.Size(); MPNr++) |
| | 409 | { |
| | 410 | if (!m_MorphPrims[MPNr]->IsModified()) continue; |
| | 411 | |
| | 412 | MapPrimitiveT* MapPrim =const_cast<MapPrimitiveT*>(m_MorphPrims[MPNr]->GetMapPrim()); |
| | 413 | MapEntityBaseT* ParentEntity =MapPrim->GetParent(); |
| | 414 | MapPrimitiveT* MorphedMapPrim=m_MorphPrims[MPNr]->GetMorphedMapPrim(); |
| | 415 | |
| | 416 | if (!MorphedMapPrim) continue; |
| | 417 | wxASSERT(MapPrim->IsSelected()); |
| | 418 | |
| | 419 | // The delete command also unselects the MapPrim, calling NotifySubjectChanged_Selection(), |
| | 420 | // followed by NotifySubjectChanged_Deleted(). |
| | 421 | // Thus our m_MorphPrims[MPNr] will be deleted and a new one created for MorphedMapPrim by |
| | 422 | // the implicit calls to the NotifySubjectChanged_*() functions. |
| | 423 | CommandDeleteT* DelCmd=new CommandDeleteT(m_MapDoc, MapPrim); |
| | 424 | DelCmd->Do(); |
| | 425 | Commands.PushBack(DelCmd); |
| | 426 | |
| | 427 | CommandAddPrimT* AddPrimCmd=new CommandAddPrimT(m_MapDoc, MorphedMapPrim, ParentEntity, "new prim", false /*don't set the selection*/); |
| | 428 | AddPrimCmd->Do(); |
| | 429 | Commands.PushBack(AddPrimCmd); |
| | 430 | |
| | 431 | CommandSelectT* SelCmd=CommandSelectT::Add(&m_MapDoc, MorphedMapPrim); |
| | 432 | SelCmd->Do(); |
| | 433 | Commands.PushBack(SelCmd); |
| | 434 | } |
| | 435 | |
| | 436 | m_MapDoc.GetHistory().SubmitCommand(new CommandMacroT(Commands, "Edit Vertices")); |
| | 437 | |
| | 438 | // This is somewhat redundant, but have it anyway here for clarity. |
| | 439 | m_DragState=DragNothing; |
| | 440 | } |
| | 441 | |
| | 442 | |
| 610 | | if (!ME.ControlDown()) MorphPrims_CommitAndClear(); |
| 611 | | MorphPrims_TogglePrim(HitPrim); |
| 612 | | |
| 613 | | m_ToolMan.UpdateAllObservers(this, UPDATE_NOW); |
| | 621 | // The handling of the Control key is not ideal: it would possibly be better to |
| | 622 | // not account for it at all, or to route this through the selection tool somehow. |
| | 623 | // |
| | 624 | // The implied call to NotifySubjectChanged_Selection() will update our tool state. |
| | 625 | m_MapDoc.GetHistory().SubmitCommand(ME.ControlDown() |
| | 626 | ? CommandSelectT::Add(&m_MapDoc, HitPrim) |
| | 627 | : CommandSelectT::Set(&m_MapDoc, HitPrim)); |
| | 628 | |
| 880 | | if (!ME.ControlDown()) MorphPrims_CommitAndClear(); |
| 881 | | MorphPrims_TogglePrim(HitPrim); |
| 882 | | |
| 883 | | m_ToolMan.UpdateAllObservers(this, UPDATE_NOW); |
| | 896 | // The handling of the Control key is not ideal: it would possibly be better to |
| | 897 | // not account for it at all, or to route this through the selection tool somehow. |
| | 898 | // |
| | 899 | // The implied call to NotifySubjectChanged_Selection() will update our tool state. |
| | 900 | m_MapDoc.GetHistory().SubmitCommand(ME.ControlDown() |
| | 901 | ? CommandSelectT::Add(&m_MapDoc, HitPrim) |
| | 902 | : CommandSelectT::Set(&m_MapDoc, HitPrim)); |
| | 903 | |
| 997 | | // An external event caused a selection change, such as the user clicking "Undo". |
| 998 | | // |
| 999 | | // - What we can *not* do is calling MorphPrims_CommitAndClear(), because that |
| 1000 | | // would attempt to submit another command to the command history while the |
| 1001 | | // command history is attempting to run the "Undo". |
| 1002 | | // |
| 1003 | | // - Technically, it would be possible to do nothing: A change in selection |
| 1004 | | // does not require any alterations of our tool state, the user can continue |
| 1005 | | // to morph the objects that he previously begun to morph. |
| 1006 | | // |
| 1007 | | // - Although the user might lose some morph work, probably the least confusion |
| 1008 | | // action is to just discard and clear the tool state. |
| 1009 | | // |
| 1010 | | for (unsigned long MPNr=0; MPNr<m_MorphPrims.Size(); MPNr++) |
| | 1017 | MorphPrims_SyncTo(NewSelection); |
| | 1018 | } |
| | 1019 | |
| | 1020 | |
| | 1021 | void ToolMorphT::NotifySubjectChanged_Deleted(SubjectT* Subject, const ArrayT<MapElementT*>& MapElements) |
| | 1022 | { |
| | 1023 | if (!IsActiveTool() || m_IsRecursiveSelfNotify) return; |
| | 1024 | |
| | 1025 | // Remove all entries that are in MapElements and m_MorphPrims from m_MorphPrims. |
| | 1026 | for (unsigned long ElemNr=0; ElemNr<MapElements.Size(); ElemNr++) |
| | 1027 | { |
| | 1028 | MapPrimitiveT* MapPrim=dynamic_cast<MapPrimitiveT*>(MapElements[ElemNr]); |
| | 1029 | if (!MapPrim) continue; |
| | 1030 | |
| | 1031 | const int MPNr=MorphPrims_Find(MapPrim); |
| | 1032 | if (MPNr < 0) continue; |
| | 1033 | |
| 1023 | | for (unsigned long i=0; i<MapElements.Size(); i++) |
| 1024 | | { |
| 1025 | | MapPrimitiveT* MapPrim=dynamic_cast<MapPrimitiveT*>(MapElements[i]); |
| 1026 | | |
| | 1051 | // If only the visibility changed, do nothing. In all other cases, |
| | 1052 | // don't further examine Detail, but just do the update. |
| | 1053 | if (Detail==MEMD_VISIBILITY) return; |
| | 1054 | |
| | 1055 | // Update all entries that are in MapElements and m_MorphPrims. |
| | 1056 | for (unsigned long ElemNr=0; ElemNr<MapElements.Size(); ElemNr++) |
| | 1057 | { |
| | 1058 | MapPrimitiveT* MapPrim=dynamic_cast<MapPrimitiveT*>(MapElements[ElemNr]); |
| 1047 | | void ToolMorphT::NotifySubjectChanged_Modified(SubjectT* Subject, const ArrayT<MapElementT*>& MapElements, MapElemModDetailE Detail) |
| 1048 | | { |
| 1049 | | if (!IsActiveTool() || m_IsRecursiveSelfNotify) return; |
| 1050 | | if (Detail!=MEMD_GENERIC && Detail!=MEMD_VISIBILITY) return; |
| 1051 | | |
| 1052 | | for (unsigned long i=0; i<MapElements.Size(); i++) |
| 1053 | | { |
| 1054 | | MapPrimitiveT* MapPrim=dynamic_cast<MapPrimitiveT*>(MapElements[i]); |
| 1055 | | |
| 1056 | | if (!MapPrim) continue; |
| 1057 | | |
| 1058 | | for (unsigned long j=0; j<m_MorphPrims.Size(); j++) |
| 1059 | | { |
| 1060 | | if (MapPrim==m_MorphPrims[j]->GetMapPrim()) |
| 1061 | | { |
| 1062 | | // Update the morph primitive of this map element, discarding all prior changes, if any. |
| 1063 | | delete m_MorphPrims[j]; |
| 1064 | | m_MorphPrims[j]=new MorphPrimT(MapPrim); |
| 1065 | | |
| 1066 | | // Object has been found so we can safely break the inner loop and check the next object. |
| 1067 | | break; |
| 1068 | | } |
| 1069 | | } |
| 1070 | | } |
| 1071 | | |
| 1072 | | m_ToolMan.UpdateAllObservers(this, UPDATE_SOON); |
| 1073 | | } |
| 1074 | | |
| 1075 | | |
| 1078 | | if (!IsActiveTool() || m_IsRecursiveSelfNotify) return; |
| 1079 | | if (Detail!=MEMD_GENERIC && Detail!=MEMD_TRANSFORM && Detail!=MEMD_PRIMITIVE_PROPS_CHANGED && Detail!=MEMD_MORPH) return; |
| 1080 | | |
| 1081 | | for (unsigned long i=0; i<MapElements.Size(); i++) |
| 1082 | | { |
| 1083 | | MapPrimitiveT* MapPrim=dynamic_cast<MapPrimitiveT*>(MapElements[i]); |
| 1084 | | |
| 1085 | | if (!MapPrim) continue; |
| 1086 | | |
| 1087 | | for (unsigned long j=0; j<m_MorphPrims.Size(); j++) |
| 1088 | | { |
| 1089 | | if (MapPrim==m_MorphPrims[j]->GetMapPrim()) |
| 1090 | | { |
| 1091 | | // Update the morph primitive of this map element, discarding all prior changes, if any. |
| 1092 | | delete m_MorphPrims[j]; |
| 1093 | | m_MorphPrims[j]=new MorphPrimT(MapPrim); |
| 1094 | | |
| 1095 | | // Object has been found so we can safely break the inner loop and check the next object. |
| 1096 | | break; |
| 1097 | | } |
| 1098 | | } |
| 1099 | | } |
| 1100 | | |
| 1101 | | m_ToolMan.UpdateAllObservers(this, UPDATE_SOON); |
| | 1074 | NotifySubjectChanged_Modified(Subject, MapElements, Detail); |